diff --git a/.editorconfig b/.editorconfig index c379dffa45..332927531a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -27,4 +27,8 @@ charset = utf-8-bom charset = utf-8-bom [Windows/{aboutbox.rc,version.rc}] -charset = utf-16le +charset = utf-8 + +[libretro/**.{cpp,h}] +indent_style = space +indent_size = 3 diff --git a/.gitignore b/.gitignore index cb1af7b298..2c9994fde5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ Windows/ARM64 Windows/ipch Windows/bin-release Windows/win-version.h +Windows/win-version-*.tmp android/assets ext/_Output android/lint.xml @@ -78,6 +79,7 @@ memstick* Cheats /git-version.cpp +/git-version-*.tmp .pspsh.hist __testoutput.txt @@ -114,3 +116,6 @@ debian/ppsspp/ # RenderDoc *.rdc + +# bad output from libretro. don't want to accidentally add it +nul diff --git a/.gitmodules b/.gitmodules index 04a3791ff2..5d8992a220 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,7 +12,7 @@ url = https://github.com/hrydgard/minidx9.git [submodule "ext/armips"] path = ext/armips - url = https://github.com/Kingcom/armips + url = https://github.com/Kingcom/armips.git [submodule "ext/glslang"] path = ext/glslang url = https://github.com/hrydgard/glslang.git @@ -31,3 +31,6 @@ [submodule "ext/native/tools/prebuilt"] path = ext/native/tools/prebuilt url = https://github.com/hrydgard/ppsspp-freetype.git +[submodule "ext/miniupnp"] + path = ext/miniupnp + url = https://github.com/hrydgard/miniupnp.git diff --git a/.travis.sh b/.travis.sh index 5e6afecd23..bdd4baa01c 100644 --- a/.travis.sh +++ b/.travis.sh @@ -21,64 +21,8 @@ download_extract_zip() { unzip $2 2>&1 | pv > /dev/null } -brew_make_bottle() { - echo "Rebuilding $1 as bottle..." - brew uninstall -f --ignore-dependencies $1 && brew install --ignore-dependencies --build-bottle $1 || true - brew bottle $1 && brew postinstall $1 || true - rm $HOME/Library/Caches/Homebrew/$1-*.bottle.*.tar.gz || true - mv ./$1-*.bottle.*.tar.gz $HOME/Library/Caches/Homebrew/ || true -} - travis_before_install() { git submodule update --init --recursive - - if [ "$TRAVIS_OS_NAME" = osx ]; then - # Depends on Python, wastes time updating... - brew uninstall -f mercurial || true - - # To check version numbers, we want jq. Try to cache this too. - for PKG in automake oniguruma; do - if ! brew info --json $PKG | grep built_as_bottle > /dev/null; then - if [ -f $HOME/Library/Caches/Homebrew/$PKG*.bottle.*.tar.gz ]; then - brew install -f $HOME/Library/Caches/Homebrew/$PKG*.bottle.*.tar.gz || true - else - brew_make_bottle $PKG - fi - fi - done - brew install jq || true - - # Try to install as many at once as possible. - TO_UPGRADE="" - TO_UNINSTALL="" - for PKG in ccache openssl@1.1 pyenv pkg-config readline gdbm sqlite xz python sdl2; do - PKG_VER="`brew info $PKG --json | jq '.[0].versions.stable' | tr -d '"'`" - if [ -f $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz ]; then - TO_UPGRADE="$TO_UPGRADE $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz" - TO_UNINSTALL="$TO_UNINSTALL $PKG" - fi - done - - for PKG in ccache openssl@1.1 pyenv pkg-config readline gdbm sqlite xz python sdl2; do - PKG_VER="`brew info $PKG --json | jq '.[0].versions.stable' | tr -d '"'`" - if [ ! -f $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz ]; then - brew_make_bottle $PKG - fi - done - - if [ "$TO_UPGRADE" != "" ]; then - brew uninstall -f --ignore-dependencies $TO_UNINSTALL - brew install -f --ignore-dependencies $TO_UPGRADE || true - fi - - # In case there were issues with all at once, now let's try installing any others from cache. - for PKG in ccache openssl@1.1 pyenv pkg-config readline gdbm sqlite xz python sdl2; do - PKG_VER="`brew info $PKG --json | jq '.[0].versions.stable' | tr -d '"'`" - if [ -f $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz ]; then - brew upgrade $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz || brew install -f $HOME/Library/Caches/Homebrew/$PKG-*.bottle.*.tar.gz || true - fi - done - fi } travis_install() { @@ -171,7 +115,11 @@ travis_script() { sed -i 's/>ProgramDatabase<\/DebugInformationFormat>/><\/DebugInformationFormat>/g' $f done - msbuild.exe Windows\\PPSSPP.sln -m -p:CLToolExe=clcache.exe -p:Configuration=Release -p:Platform=x64 -p:TrackFileAccess=false + if [ "$UWP" == "TRUE" ]; then + msbuild.exe UWP\\PPSSPP_UWP.sln -m -p:CLToolExe=clcache.exe -p:Configuration=Release -p:Platform=x64 -p:TrackFileAccess=false -p:AppxPackageSigningEnabled=false + else + msbuild.exe Windows\\PPSSPP.sln -m -p:CLToolExe=clcache.exe -p:Configuration=Release -p:Platform=x64 -p:TrackFileAccess=false + fi fi } diff --git a/.travis.yml b/.travis.yml index b5fc79998f..fccd90b7bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,9 @@ addons: - sourceline: 'ppa:ubuntu-sdk-team/ppa' homebrew: update: true + packages: + - ccache + - sdl2 cache: apt: true @@ -86,16 +89,20 @@ jobs: env: PPSSPP_BUILD_TYPE=Linux LIBRETRO=TRUE - os: osx - osx_image: xcode9 + osx_image: xcode9.4 compiler: "clang" env: PPSSPP_BUILD_TYPE=macOS - os: osx - osx_image: xcode9 + osx_image: xcode9.4 compiler: "clang" env: PPSSPP_BUILD_TYPE=iOS - os: windows compiler: "msvc2017" env: PPSSPP_BUILD_TYPE=Windows + - os: windows + compiler: "msvc2017" + env: PPSSPP_BUILD_TYPE=Windows + UWP=TRUE before_install: - travis_retry bash .travis.sh travis_before_install diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index cbda75bb1f..67405088b5 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -41,7 +41,7 @@ flags = [ '-fexceptions', '-DNDEBUG', '-Iext/native', -'-Iext/native/ext', +'-Iext', '-Iext/glew', '-ICommon', # THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bed3ec51a..431ee28228 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,6 @@ if(CMAKE_SYSTEM_PROCESSOR) endif() elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch64") 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_DEVICE ON) set(X86_64_DEVICE ON) @@ -119,6 +118,7 @@ option(LIBRETRO "Set to ON to generate the libretro target" OFF) # :: Options option(USE_FFMPEG "Build with FFMPEG support" ON) option(USE_DISCORD "Build with Discord support" ON) +option(USE_MINIUPNPC "Build with miniUPnPc 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}) @@ -164,11 +164,12 @@ else() set(CoreLinkType STATIC) endif() -include_directories(ext/native) - # Work around for some misfeature of the current glslang build system include_directories(ext/glslang) +# Not sure if this is the best way - what about system glew? +# Anyway, glew will be going away anyway. +include_directories(ext/glew) if(NOT OPENGL_LIBRARIES AND USING_GLES2) set(OPENGL_LIBRARIES GLESv2 EGL) @@ -239,6 +240,18 @@ endif() if(ARM64) message("Generating for ARMv8, ${CMAKE_BUILD_TYPE}") endif() + +# It looks like the flags for the selected build type are written to the cache after each run, which causes some of the operations +# below to keep expanding them with the same flags over and over on every run, leading to a rebuild of the majority of the files. +# To work around this, remember the initial state of the variables from the first run and reset the variables to that. +# TODO: Setting the attributes per target would probably be a better solution. +foreach (LANGUAGE C CXX) + foreach (BUILD_TYPE DEBUG MINSIZEREL RELEASE RELWITHDEBINFO) + set(_CMAKE_${LANGUAGE}_FLAGS_${BUILD_TYPE}_INITIAL ${CMAKE_${LANGUAGE}_FLAGS_${BUILD_TYPE}} CACHE STRING "") + set(CMAKE_${LANGUAGE}_FLAGS_${BUILD_TYPE} ${_CMAKE_${LANGUAGE}_FLAGS_${BUILD_TYPE}_INITIAL}) + endforeach() +endforeach() + if(NOT MSVC) if(ANDROID) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") @@ -287,12 +300,7 @@ if(NOT MSVC) if(IOS) elseif(APPLE AND NOT CMAKE_CROSSCOMPILING) - # We want C++11, so target 10.7+ - if(USING_QT_UI) - set(MACOSX_VERSION_MIN "10.8") - else() - set(MACOSX_VERSION_MIN "10.7") - endif() + set(MACOSX_VERSION_MIN "10.8") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=${MACOSX_VERSION_MIN}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=${MACOSX_VERSION_MIN} -stdlib=libc++ -U__STRICT_ANSI__") set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") @@ -310,7 +318,9 @@ if(NOT MSVC) else() # Disable warnings about MS-specific _s variants of libc functions add_definitions(-D_CRT_SECURE_NO_WARNINGS) - add_definitions(-MP) + if (NOT CLANG) + add_compile_options(-MP) + endif() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -D_NDEBUG") endif() @@ -340,8 +350,13 @@ macro(setup_target_project TargetName ProjectDir) endforeach() endmacro() -# Commented-out files are files that don't compile -# and were disabled in the original MSVC project anyway +add_subdirectory(ext) + +if(WIN32) + include_directories(dx9sdk/Include) + include_directories(dx9sdk/Include/DX11) +endif() + set(CommonX86 Common/ABI.cpp @@ -389,24 +404,19 @@ if(NOT (X86 OR ARM OR MIPS)) source_group(Fake FILES ${CommonFake}) endif() -set(CommonWindows - Common/stdafx.cpp - Common/stdafx.h -) -source_group(Windows FILES ${CommonWindows}) - -set(CommonVulkan ${CommonExtra} - Common/Vulkan/VulkanContext.cpp - Common/Vulkan/VulkanContext.h - Common/Vulkan/VulkanDebug.cpp - Common/Vulkan/VulkanDebug.h - Common/Vulkan/VulkanImage.cpp - Common/Vulkan/VulkanImage.h - Common/Vulkan/VulkanLoader.cpp - Common/Vulkan/VulkanLoader.h - Common/Vulkan/VulkanMemory.cpp - Common/Vulkan/VulkanMemory.h -) +if(WIN32) + set(CommonD3D + Common/GPU/D3D9/D3D9ShaderCompiler.cpp + Common/GPU/D3D9/D3D9ShaderCompiler.h + Common/GPU/D3D9/D3D9StateCache.cpp + Common/GPU/D3D9/D3D9StateCache.h + Common/GPU/D3D9/thin3d_d3d9.cpp + Common/GPU/D3D9/D3DCompilerLoader.cpp + Common/GPU/D3D11/thin3d_d3d11.cpp + Common/GPU/D3D11/D3D11Loader.cpp + Common/GPU/D3D11/D3D11Loader.h + ) +endif() add_library(Common STATIC ${CommonX86} @@ -414,25 +424,200 @@ add_library(Common STATIC ${CommonARM64} ${CommonMIPS} ${CommonFake} - ${CommonWindows} - ${CommonVulkan} - Common/ColorConv.cpp - Common/ColorConv.h - Common/ChunkFile.cpp - Common/ChunkFile.h - Common/ConsoleListener.cpp - Common/ConsoleListener.h + ${CommonD3D} + Common/Serialize/Serializer.cpp + Common/Serialize/Serializer.h + Common/Serialize/SerializeDeque.h + Common/Serialize/SerializeFuncs.h + Common/Serialize/SerializeList.h + Common/Serialize/SerializeMap.h + Common/Serialize/SerializeSet.h Common/Crypto/md5.cpp Common/Crypto/md5.h Common/Crypto/sha1.cpp Common/Crypto/sha1.h Common/Crypto/sha256.cpp Common/Crypto/sha256.h - Common/FileUtil.cpp - Common/FileUtil.h - Common/KeyMap.cpp - Common/KeyMap.h - Common/Hashmaps.h + Common/Data/Collections/ConstMap.h + Common/Data/Collections/FixedSizeQueue.h + Common/Data/Collections/Hashmaps.h + Common/Data/Collections/TinySet.h + Common/Data/Collections/ThreadSafeList.h + Common/Data/Color/RGBAUtil.cpp + Common/Data/Color/RGBAUtil.h + Common/Data/Convert/SmallDataConvert.cpp + Common/Data/Convert/SmallDataConvert.h + Common/Data/Encoding/Base64.cpp + Common/Data/Encoding/Base64.h + Common/Data/Encoding/Compression.cpp + Common/Data/Encoding/Compression.h + Common/Data/Encoding/Shiftjis.h + Common/Data/Encoding/Utf8.cpp + Common/Data/Encoding/Utf8.h + Common/Data/Encoding/Utf16.h + Common/Data/Format/RIFF.cpp + Common/Data/Format/RIFF.h + Common/Data/Format/IniFile.cpp + Common/Data/Format/IniFile.h + Common/Data/Format/JSONReader.h + Common/Data/Format/JSONReader.cpp + Common/Data/Format/JSONWriter.h + Common/Data/Format/JSONWriter.cpp + Common/Data/Format/PNGLoad.cpp + Common/Data/Format/PNGLoad.h + Common/Data/Format/ZIMLoad.cpp + Common/Data/Format/ZIMLoad.h + Common/Data/Format/ZIMSave.cpp + Common/Data/Format/ZIMSave.h + Common/Data/Hash/Hash.cpp + Common/Data/Hash/Hash.h + Common/Data/Text/I18n.cpp + Common/Data/Text/I18n.h + Common/Data/Text/Parsers.cpp + Common/Data/Text/Parsers.h + Common/Data/Text/WrapText.cpp + Common/Data/Text/WrapText.h + Common/Data/Random/Rng.h + Common/File/VFS/VFS.h + Common/File/VFS/VFS.cpp + Common/File/VFS/AssetReader.cpp + Common/File/VFS/AssetReader.h + Common/File/DiskFree.h + Common/File/DiskFree.cpp + Common/File/PathBrowser.h + Common/File/PathBrowser.cpp + Common/File/FileUtil.cpp + Common/File/FileUtil.h + Common/File/DirListing.cpp + Common/File/DirListing.h + Common/File/FileDescriptor.cpp + Common/File/FileDescriptor.h + Common/GPU/DataFormat.h + Common/GPU/thin3d.cpp + Common/GPU/thin3d.h + Common/GPU/thin3d_create.h + Common/GPU/OpenGL/GLCommon.h + Common/GPU/OpenGL/GLDebugLog.cpp + Common/GPU/OpenGL/GLDebugLog.h + Common/GPU/OpenGL/GLSLProgram.cpp + Common/GPU/OpenGL/GLSLProgram.h + Common/GPU/OpenGL/gl3stub.c + Common/GPU/OpenGL/gl3stub.h + Common/GPU/OpenGL/GLFeatures.cpp + Common/GPU/OpenGL/GLFeatures.h + Common/GPU/OpenGL/thin3d_gl.cpp + Common/GPU/OpenGL/GLRenderManager.cpp + Common/GPU/OpenGL/GLRenderManager.h + Common/GPU/OpenGL/GLQueueRunner.cpp + Common/GPU/OpenGL/GLQueueRunner.h + Common/GPU/OpenGL/DataFormatGL.cpp + Common/GPU/OpenGL/DataFormatGL.h + Common/GPU/Vulkan/VulkanDebug.cpp + Common/GPU/Vulkan/VulkanDebug.h + Common/GPU/Vulkan/VulkanContext.cpp + Common/GPU/Vulkan/VulkanContext.h + Common/GPU/Vulkan/VulkanImage.cpp + Common/GPU/Vulkan/VulkanImage.h + Common/GPU/Vulkan/VulkanLoader.cpp + Common/GPU/Vulkan/VulkanLoader.h + Common/GPU/Vulkan/VulkanMemory.cpp + Common/GPU/Vulkan/VulkanMemory.h + Common/GPU/Vulkan/thin3d_vulkan.cpp + Common/GPU/Vulkan/VulkanRenderManager.cpp + Common/GPU/Vulkan/VulkanRenderManager.h + Common/GPU/Vulkan/VulkanQueueRunner.cpp + Common/GPU/Vulkan/VulkanQueueRunner.h + Common/Input/GestureDetector.cpp + Common/Input/GestureDetector.h + Common/Input/KeyCodes.h + Common/Input/InputState.cpp + Common/Input/InputState.h + Common/Math/fast/fast_math.c + Common/Math/fast/fast_matrix.c + Common/Math/fast/fast_matrix_neon.S + Common/Math/fast/fast_matrix_sse.c + Common/Math/curves.cpp + Common/Math/curves.h + Common/Math/expression_parser.cpp + Common/Math/expression_parser.h + Common/Math/lin/matrix4x4.cpp + Common/Math/lin/matrix4x4.h + Common/Math/lin/vec3.cpp + Common/Math/lin/vec3.h + Common/Math/math_util.cpp + Common/Math/math_util.h + Common/Net/HTTPClient.cpp + Common/Net/HTTPClient.h + Common/Net/HTTPHeaders.cpp + Common/Net/HTTPHeaders.h + Common/Net/HTTPServer.cpp + Common/Net/HTTPServer.h + Common/Net/Resolve.cpp + Common/Net/Resolve.h + Common/Net/Sinks.cpp + Common/Net/Sinks.h + Common/Net/URL.cpp + Common/Net/URL.h + Common/Net/WebsocketServer.cpp + Common/Net/WebsocketServer.h + Common/Profiler/Profiler.cpp + Common/Profiler/Profiler.h + Common/Render/TextureAtlas.cpp + Common/Render/TextureAtlas.h + Common/Render/DrawBuffer.cpp + Common/Render/DrawBuffer.h + Common/Render/Text/draw_text.cpp + Common/Render/Text/draw_text.h + Common/Render/Text/draw_text_android.cpp + Common/Render/Text/draw_text_android.h + Common/Render/Text/draw_text_win.cpp + Common/Render/Text/draw_text_win.h + Common/Render/Text/draw_text_uwp.cpp + Common/Render/Text/draw_text_uwp.h + Common/System/Display.cpp + Common/System/Display.h + Common/Thread/Executor.cpp + Common/Thread/Executor.h + Common/Thread/PrioritizedWorkQueue.cpp + Common/Thread/PrioritizedWorkQueue.h + Common/Thread/ThreadUtil.cpp + Common/Thread/ThreadUtil.h + Common/Thread/ThreadPool.cpp + Common/Thread/ThreadPool.h + Common/UI/Root.cpp + Common/UI/Root.h + Common/UI/Screen.cpp + Common/UI/Screen.h + Common/UI/UI.cpp + Common/UI/UI.h + Common/UI/Context.cpp + Common/UI/Context.h + Common/UI/UIScreen.cpp + Common/UI/UIScreen.h + Common/UI/Tween.cpp + Common/UI/Tween.h + Common/UI/View.cpp + Common/UI/View.h + Common/UI/ViewGroup.cpp + Common/UI/ViewGroup.h + Common/BitScan.h + Common/BitSet.h + Common/Buffer.h + Common/Buffer.cpp + Common/CodeBlock.h + Common/ColorConv.cpp + Common/ColorConv.h + Common/Common.h + Common/CommonFuncs.h + Common/CommonTypes.h + Common/ConsoleListener.cpp + Common/ConsoleListener.h + Common/DbgNew.h + Common/FakeEmitter.h + Common/ExceptionHandlerSetup.cpp + Common/ExceptionHandlerSetup.h + Common/Log.h + Common/Log.cpp Common/LogManager.cpp Common/LogManager.h Common/MakeUnique.h @@ -443,53 +628,31 @@ add_library(Common STATIC Common/MemArena.h Common/MemoryUtil.cpp Common/MemoryUtil.h - Common/Misc.cpp - Common/MsgHandler.cpp - Common/MsgHandler.h Common/OSVersion.cpp Common/OSVersion.h Common/StringUtils.cpp Common/StringUtils.h - Common/ThreadPools.cpp - Common/ThreadPools.h - Common/ThreadSafeList.h - Common/Timer.cpp - Common/Timer.h + Common/SysError.h + Common/SysError.cpp + Common/TimeUtil.cpp + Common/TimeUtil.h ) -add_subdirectory(ext) - include_directories(Common) setup_target_project(Common Common) target_link_libraries(Common Ext::Snappy) -if(WIN32) - include_directories(dx9sdk/Include) - include_directories(dx9sdk/Include/DX11) - if(MINGW) - set(CMAKE_RC_COMPILE_OBJECT " -O coff ") - # required when using the dx9sdk include paths - add_definitions(-include ${CMAKE_CURRENT_SOURCE_DIR}/Windows/mingw_defines.h) - else() - target_link_libraries(Common dxguid) - endif() - target_link_libraries(Common winmm d3d9 dsound) -endif() - -if(TARGET SDL2::SDL2) - target_link_libraries(Common SDL2::SDL2) -endif() - if(USING_GLES2 OR (USING_EGL AND NOT USING_FBDEV)) find_package(X11) endif() add_library(gason STATIC - ext/native/ext/gason/gason.cpp - ext/native/ext/gason/gason.h + ext/gason/gason.cpp + ext/gason/gason.h ) + if(USE_FFMPEG) if(NOT FFMPEG_DIR) if(NOT USE_SYSTEM_FFMPEG) @@ -578,9 +741,9 @@ else() endif() add_library(cityhash STATIC - ext/native/ext/cityhash/city.cpp - ext/native/ext/cityhash/city.h - ext/native/ext/cityhash/citycrc.h + ext/cityhash/city.cpp + ext/cityhash/city.h + ext/cityhash/citycrc.h ) include_directories(ext/cityhash) @@ -599,64 +762,64 @@ if(LIBZIP_FOUND AND USE_SYSTEM_LIBZIP) add_definitions(-DSHARED_LIBZIP) else() add_library(libzip STATIC - ext/native/ext/libzip/zip.h - ext/native/ext/libzip/mkstemp.c - ext/native/ext/libzip/zip_add.c - ext/native/ext/libzip/zip_add_dir.c - ext/native/ext/libzip/zip_close.c - ext/native/ext/libzip/zip_delete.c - ext/native/ext/libzip/zip_dirent.c - ext/native/ext/libzip/zip_entry_free.c - ext/native/ext/libzip/zip_entry_new.c - ext/native/ext/libzip/zip_err_str.c - ext/native/ext/libzip/zip_error.c - ext/native/ext/libzip/zip_error_clear.c - ext/native/ext/libzip/zip_error_get.c - ext/native/ext/libzip/zip_error_get_sys_type.c - ext/native/ext/libzip/zip_error_strerror.c - ext/native/ext/libzip/zip_error_to_str.c - ext/native/ext/libzip/zip_fclose.c - ext/native/ext/libzip/zip_file_error_clear.c - ext/native/ext/libzip/zip_file_error_get.c - ext/native/ext/libzip/zip_file_get_offset.c - ext/native/ext/libzip/zip_file_strerror.c - ext/native/ext/libzip/zip_filerange_crc.c - ext/native/ext/libzip/zip_fopen.c - ext/native/ext/libzip/zip_fopen_index.c - ext/native/ext/libzip/zip_fread.c - ext/native/ext/libzip/zip_free.c - ext/native/ext/libzip/zip_get_archive_comment.c - ext/native/ext/libzip/zip_get_archive_flag.c - ext/native/ext/libzip/zip_get_file_comment.c - ext/native/ext/libzip/zip_get_name.c - ext/native/ext/libzip/zip_get_num_files.c - ext/native/ext/libzip/zip_memdup.c - ext/native/ext/libzip/zip_name_locate.c - ext/native/ext/libzip/zip_new.c - ext/native/ext/libzip/zip_open.c - ext/native/ext/libzip/zip_rename.c - ext/native/ext/libzip/zip_replace.c - ext/native/ext/libzip/zip_set_archive_comment.c - ext/native/ext/libzip/zip_set_archive_flag.c - ext/native/ext/libzip/zip_set_file_comment.c - ext/native/ext/libzip/zip_set_name.c - ext/native/ext/libzip/zip_source_buffer.c - ext/native/ext/libzip/zip_source_file.c - ext/native/ext/libzip/zip_source_filep.c - ext/native/ext/libzip/zip_source_free.c - ext/native/ext/libzip/zip_source_function.c - ext/native/ext/libzip/zip_source_zip.c - ext/native/ext/libzip/zip_stat.c - ext/native/ext/libzip/zip_stat_index.c - ext/native/ext/libzip/zip_stat_init.c - ext/native/ext/libzip/zip_strerror.c - 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/libzip/zip.h + ext/libzip/mkstemp.c + ext/libzip/zip_add.c + ext/libzip/zip_add_dir.c + ext/libzip/zip_close.c + ext/libzip/zip_delete.c + ext/libzip/zip_dirent.c + ext/libzip/zip_entry_free.c + ext/libzip/zip_entry_new.c + ext/libzip/zip_err_str.c + ext/libzip/zip_error.c + ext/libzip/zip_error_clear.c + ext/libzip/zip_error_get.c + ext/libzip/zip_error_get_sys_type.c + ext/libzip/zip_error_strerror.c + ext/libzip/zip_error_to_str.c + ext/libzip/zip_fclose.c + ext/libzip/zip_file_error_clear.c + ext/libzip/zip_file_error_get.c + ext/libzip/zip_file_get_offset.c + ext/libzip/zip_file_strerror.c + ext/libzip/zip_filerange_crc.c + ext/libzip/zip_fopen.c + ext/libzip/zip_fopen_index.c + ext/libzip/zip_fread.c + ext/libzip/zip_free.c + ext/libzip/zip_get_archive_comment.c + ext/libzip/zip_get_archive_flag.c + ext/libzip/zip_get_file_comment.c + ext/libzip/zip_get_name.c + ext/libzip/zip_get_num_files.c + ext/libzip/zip_memdup.c + ext/libzip/zip_name_locate.c + ext/libzip/zip_new.c + ext/libzip/zip_open.c + ext/libzip/zip_rename.c + ext/libzip/zip_replace.c + ext/libzip/zip_set_archive_comment.c + ext/libzip/zip_set_archive_flag.c + ext/libzip/zip_set_file_comment.c + ext/libzip/zip_set_name.c + ext/libzip/zip_source_buffer.c + ext/libzip/zip_source_file.c + ext/libzip/zip_source_filep.c + ext/libzip/zip_source_free.c + ext/libzip/zip_source_function.c + ext/libzip/zip_source_zip.c + ext/libzip/zip_stat.c + ext/libzip/zip_stat_index.c + ext/libzip/zip_stat_init.c + ext/libzip/zip_strerror.c + ext/libzip/zip_unchange.c + ext/libzip/zip_unchange_all.c + ext/libzip/zip_unchange_archive.c + ext/libzip/zip_unchange_data.c ) target_link_libraries(libzip) - include_directories(ext/native/ext/libzip) + include_directories(ext/libzip) set(LIBZIP_LIBRARY libzip) endif() @@ -673,38 +836,38 @@ if(PNG_FOUND) 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/libpng17/arm/arm_init.c + ext/libpng17/arm/filter_neon.S + ext/libpng17/arm/filter_neon_intrinsics.c ) endif() add_library(png17 STATIC - ext/native/ext/libpng17/pngconf.h - ext/native/ext/libpng17/pngdebug.h - ext/native/ext/libpng17/png.c - ext/native/ext/libpng17/png.h - ext/native/ext/libpng17/pngerror.c - ext/native/ext/libpng17/pngget.c - ext/native/ext/libpng17/pnginfo.h - ext/native/ext/libpng17/pnglibconf.h - ext/native/ext/libpng17/pngmem.c - ext/native/ext/libpng17/pngpread.c - ext/native/ext/libpng17/pngpriv.h - ext/native/ext/libpng17/pngread.c - ext/native/ext/libpng17/pngrio.c - ext/native/ext/libpng17/pngrtran.c - ext/native/ext/libpng17/pngrutil.c - ext/native/ext/libpng17/pngset.c - ext/native/ext/libpng17/pngstruct.h - ext/native/ext/libpng17/pngtrans.c - ext/native/ext/libpng17/pngwio.c - ext/native/ext/libpng17/pngwrite.c - ext/native/ext/libpng17/pngwtran.c - ext/native/ext/libpng17/pngwutil.c + ext/libpng17/pngconf.h + ext/libpng17/pngdebug.h + ext/libpng17/png.c + ext/libpng17/png.h + ext/libpng17/pngerror.c + ext/libpng17/pngget.c + ext/libpng17/pnginfo.h + ext/libpng17/pnglibconf.h + ext/libpng17/pngmem.c + ext/libpng17/pngpread.c + ext/libpng17/pngpriv.h + ext/libpng17/pngread.c + ext/libpng17/pngrio.c + ext/libpng17/pngrtran.c + ext/libpng17/pngrutil.c + ext/libpng17/pngset.c + ext/libpng17/pngstruct.h + ext/libpng17/pngtrans.c + ext/libpng17/pngwio.c + ext/libpng17/pngwrite.c + ext/libpng17/pngwtran.c + ext/libpng17/pngwutil.c ${PNG_ARM_INCLUDES} ) set(PNG_LIBRARIES png17) - include_directories(ext/native/ext/libpng17) + include_directories(ext/libpng17) endif() set(nativeExtra) @@ -721,7 +884,6 @@ if(ANDROID) ) set(NativeAppSource ${NativeAppSource} - ext/native/base/NativeApp.h android/jni/app-android.cpp android/jni/AndroidEGLContext.cpp android/jni/AndroidEGLContext.h @@ -730,10 +892,10 @@ if(ANDROID) android/jni/AndroidVulkanContext.cpp android/jni/AndroidVulkanContext.h android/jni/AndroidGraphicsContext.h - android/jni/native_audio.cpp - android/jni/native_audio.h - android/jni/native-audio-so.cpp - android/jni/native-audio-so.h + android/jni/AndroidAudio.cpp + android/jni/AndroidAudio.h + android/jni/OpenSLContext.cpp + android/jni/OpenSLContext.h ) # No target elseif(IOS) @@ -795,11 +957,13 @@ elseif(USING_QT_UI) if(USING_GLES2) add_definitions(-DQT_OPENGL_ES -DQT_OPENGL_ES_2) endif() - include_directories(${CMAKE_CURRENT_BINARY_DIR} Qt) + + include_directories(Qt) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(nativeExtraLibs ${nativeExtraLibs} Qt5::OpenGL Qt5::Gui Qt5::Core Qt5::Multimedia) set(TargetBin PPSSPPQt) - # Enable SDL if found + # Enable SDL joystick if SDL is found if(SDL2_FOUND) add_definitions(-DSDL) set(nativeExtra ${nativeExtra} @@ -817,7 +981,6 @@ elseif(WIN32) else() link_directories(dx9sdk/Lib/x86) endif() - set(nativeExtra ${nativeExtra} ext/native/base/logging.cpp) elseif(TARGET SDL2::SDL2) set(TargetBin PPSSPPSDL) # Require SDL @@ -841,6 +1004,22 @@ elseif(NOT LIBRETRO) message(FATAL_ERROR "Could not find SDL2. Failing.") endif() +if(WIN32) + if(MINGW) + set(CMAKE_RC_COMPILE_OBJECT " -O coff ") + # required when using the dx9sdk include paths + add_definitions(-include ${CMAKE_CURRENT_SOURCE_DIR}/Windows/mingw_defines.h) + else() + target_link_libraries(Common dxguid) + endif() + target_link_libraries(Common winmm d3d9 dsound) +endif() + +if(TARGET SDL2::SDL2) + target_link_libraries(Common SDL2::SDL2) +endif() + + list(APPEND NativeAppSource android/jni/TestRunner.cpp UI/DiscordIntegration.cpp @@ -888,195 +1067,15 @@ if(ANDROID) endif() endif() -set(THIN3D_PLATFORMS ext/native/thin3d/thin3d_gl.cpp - ext/native/thin3d/GLRenderManager.cpp - ext/native/thin3d/GLRenderManager.h - ext/native/thin3d/GLQueueRunner.cpp - ext/native/thin3d/GLQueueRunner.h - ext/native/thin3d/DataFormatGL.cpp - ext/native/thin3d/DataFormatGL.h -) - -set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} - ext/native/thin3d/thin3d_vulkan.cpp - ext/native/thin3d/VulkanRenderManager.cpp - ext/native/thin3d/VulkanRenderManager.h - ext/native/thin3d/VulkanQueueRunner.cpp - ext/native/thin3d/VulkanQueueRunner.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 - ) -endif() - add_library(native STATIC ${nativeExtra} - ext/native/base/backtrace.cpp - ext/native/base/backtrace.h - ext/native/base/basictypes.h - ext/native/base/buffer.cpp - ext/native/base/buffer.h - ext/native/base/colorutil.cpp - ext/native/base/colorutil.h - ext/native/base/display.cpp - ext/native/base/display.h - ext/native/base/linked_ptr.h - ext/native/base/logging.h - ext/native/base/stringutil.cpp - ext/native/base/stringutil.h - ext/native/base/timeutil.cpp - ext/native/base/timeutil.h - ext/native/data/base64.cpp - ext/native/data/base64.h - ext/native/data/compression.cpp - ext/native/data/compression.h - ext/native/file/chunk_file.cpp - ext/native/file/chunk_file.h - ext/native/file/fd_util.cpp - ext/native/file/fd_util.h - ext/native/file/file_util.cpp - ext/native/file/file_util.h - ext/native/file/free.cpp - ext/native/file/free.h - ext/native/file/ini_file.cpp - ext/native/file/ini_file.h - ext/native/file/path.cpp - ext/native/file/path.h - ext/native/file/vfs.h - ext/native/file/zip_read.cpp - ext/native/file/zip_read.h - ext/native/gfx/gl_common.h - ext/native/gfx/gl_debug_log.cpp - ext/native/gfx/gl_debug_log.h - ext/native/gfx/texture_atlas.cpp - ext/native/gfx/texture_atlas.h - ext/native/gfx/d3d9_shader.cpp - ext/native/gfx/d3d9_shader.h - ext/native/gfx/d3d9_state.cpp - ext/native/gfx/d3d9_state.h - ext/native/gfx_es2/draw_buffer.cpp - ext/native/gfx_es2/draw_buffer.h - ext/native/gfx_es2/draw_text.cpp - ext/native/gfx_es2/draw_text.h - ext/native/gfx_es2/draw_text_win.cpp - ext/native/gfx_es2/draw_text_win.h - ext/native/gfx_es2/draw_text_qt.cpp - ext/native/gfx_es2/draw_text_qt.h - ext/native/gfx_es2/draw_text_android.cpp - ext/native/gfx_es2/draw_text_android.h - ext/native/gfx_es2/gpu_features.cpp - ext/native/gfx_es2/gpu_features.h - ext/native/gfx_es2/glsl_program.cpp - ext/native/gfx_es2/glsl_program.h - ext/native/gfx_es2/gl3stub.c - ext/native/gfx_es2/gl3stub.h - ext/native/i18n/i18n.cpp - ext/native/i18n/i18n.h - ext/native/image/png_load.cpp - ext/native/image/png_load.h - ext/native/image/zim_load.cpp - ext/native/image/zim_load.h - ext/native/image/zim_save.cpp - ext/native/image/zim_save.h - ext/native/input/gesture_detector.cpp - ext/native/input/gesture_detector.h - ext/native/input/keycodes.h - ext/native/input/input_state.h - ext/native/input/input_state.cpp - ext/native/json/json_reader.h - ext/native/json/json_reader.cpp - ext/native/json/json_writer.h - ext/native/json/json_writer.cpp - ext/native/math/fast/fast_math.c - ext/native/math/fast/fast_matrix.c - ext/native/math/fast/fast_matrix_neon.S - ext/native/math/fast/fast_matrix_sse.c - ext/native/math/dataconv.cpp - ext/native/math/dataconv.h - ext/native/math/curves.cpp - ext/native/math/curves.h - ext/native/math/expression_parser.cpp - ext/native/math/expression_parser.h - ext/native/math/lin/matrix4x4.cpp - ext/native/math/lin/matrix4x4.h - ext/native/math/lin/plane.cpp - ext/native/math/lin/plane.h - ext/native/math/lin/quat.cpp - ext/native/math/lin/quat.h - ext/native/math/lin/ray.h - ext/native/math/lin/vec3.cpp - ext/native/math/lin/vec3.h - ext/native/math/math_util.cpp - ext/native/math/math_util.h - ext/native/net/http_client.cpp - ext/native/net/http_client.h - ext/native/net/http_headers.cpp - ext/native/net/http_headers.h - ext/native/net/http_server.cpp - ext/native/net/http_server.h - ext/native/net/resolve.cpp - ext/native/net/resolve.h - ext/native/net/sinks.cpp - ext/native/net/sinks.h - ext/native/net/url.cpp - ext/native/net/url.h - ext/native/net/websocket_server.cpp - ext/native/net/websocket_server.h - ext/native/profiler/profiler.cpp - ext/native/profiler/profiler.h - ext/native/thin3d/thin3d.cpp - ext/native/thin3d/thin3d.h - ext/native/thin3d/thin3d_create.h - ${THIN3D_PLATFORMS} - ext/native/thread/executor.cpp - ext/native/thread/executor.h - ext/native/thread/prioritizedworkqueue.cpp - ext/native/thread/prioritizedworkqueue.h - ext/native/thread/threadutil.cpp - ext/native/thread/threadutil.h - ext/native/thread/threadpool.cpp - ext/native/thread/threadpool.h - ext/native/ui/root.cpp - ext/native/ui/root.h - ext/native/ui/screen.cpp - ext/native/ui/screen.h - ext/native/ui/ui.cpp - ext/native/ui/ui.h - ext/native/ui/ui_context.cpp - ext/native/ui/ui_context.h - ext/native/ui/ui_screen.cpp - ext/native/ui/ui_screen.h - ext/native/ui/ui_tween.cpp - ext/native/ui/ui_tween.h - ext/native/ui/view.cpp - ext/native/ui/view.h - ext/native/ui/viewgroup.cpp - ext/native/ui/viewgroup.h - ext/native/util/hash/hash.cpp - ext/native/util/hash/hash.h - ext/native/util/random/rng.h - ext/native/util/text/utf8.h - ext/native/util/text/utf8.cpp - ext/native/util/text/parsers.h - ext/native/util/text/parsers.cpp - ext/native/util/text/wrap_text.h - ext/native/util/text/wrap_text.cpp - ext/native/util/const_map.h - ext/native/util/tiny_set.h - ext/native/ext/jpge/jpgd.cpp - ext/native/ext/jpge/jpgd.h - ext/native/ext/jpge/jpge.cpp - ext/native/ext/jpge/jpge.h + Common/Render/Text/draw_text_qt.cpp + Common/Render/Text/draw_text_qt.h + ext/jpge/jpgd.cpp + ext/jpge/jpgd.h + ext/jpge/jpge.cpp + ext/jpge/jpge.h ) -include_directories(ext/native) if(LINUX AND NOT ANDROID) set(RT_LIB rt) @@ -1087,7 +1086,7 @@ if(ANDROID) set(ATOMIC_LIB atomic) endif() -target_link_libraries(native ${LIBZIP_LIBRARY} ${PNG_LIBRARIES} ${ZLIB_LIBRARY} gason udis86 ${RT_LIB} ${nativeExtraLibs} ${ATOMIC_LIB}) +target_link_libraries(native ${LIBZIP_LIBRARY} ${PNG_LIBRARIES} ${ZLIB_LIBRARY} gason udis86 ${RT_LIB} ${nativeExtraLibs} ${ATOMIC_LIB} Common) if(TARGET Ext::GLEW) target_link_libraries(native Ext::GLEW) endif() @@ -1099,7 +1098,6 @@ elseif(WIN32) elseif(${CMAKE_SYSTEM_NAME} MATCHES "^(DragonFly|FreeBSD|NetBSD)$") target_link_libraries(native execinfo) endif() -setup_target_project(native native) add_library(kirk STATIC ext/libkirk/AES.c @@ -1267,8 +1265,8 @@ set(GPU_VULKAN GPU/Vulkan/DrawEngineVulkan.h GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp GPU/Vulkan/FragmentShaderGeneratorVulkan.h - GPU/Vulkan/FramebufferVulkan.cpp - GPU/Vulkan/FramebufferVulkan.h + GPU/Vulkan/FramebufferManagerVulkan.cpp + GPU/Vulkan/FramebufferManagerVulkan.h GPU/Vulkan/GPU_Vulkan.cpp GPU/Vulkan/GPU_Vulkan.h GPU/Vulkan/PipelineManagerVulkan.cpp @@ -1295,8 +1293,8 @@ set(GPU_D3D9 GPU/Directx9/DrawEngineDX9.h GPU/Directx9/PixelShaderGeneratorDX9.cpp GPU/Directx9/PixelShaderGeneratorDX9.h - GPU/Directx9/FramebufferDX9.cpp - GPU/Directx9/FramebufferDX9.h + GPU/Directx9/FramebufferManagerDX9.cpp + GPU/Directx9/FramebufferManagerDX9.h GPU/Directx9/GPU_DX9.cpp GPU/Directx9/GPU_DX9.h GPU/Directx9/ShaderManagerDX9.cpp @@ -1352,8 +1350,8 @@ set(GPU_SOURCES ${GPU_NEON} GPU/Common/DepalettizeShaderCommon.cpp GPU/Common/DepalettizeShaderCommon.h - GPU/Common/FramebufferCommon.cpp - GPU/Common/FramebufferCommon.h + GPU/Common/FramebufferManagerCommon.cpp + GPU/Common/FramebufferManagerCommon.h GPU/Common/GPUDebugInterface.cpp GPU/Common/GPUDebugInterface.h GPU/Common/GPUStateUtils.cpp @@ -1402,6 +1400,8 @@ set(GPU_SOURCES GPU/Debugger/RecordFormat.h GPU/Debugger/Stepping.cpp GPU/Debugger/Stepping.h + GPU/ge_constants.h + GPU/GeConstants.cpp GPU/GPUInterface.h GPU/GeDisasm.cpp GPU/GeDisasm.h @@ -1450,6 +1450,10 @@ add_library(${CoreLibName} ${CoreLinkType} Core/CwCheat.h Core/HDRemaster.cpp Core/HDRemaster.h + Core/Instance.cpp + Core/Instance.h + Core/KeyMap.cpp + Core/KeyMap.h Core/ThreadEventQueue.h Core/WebServer.cpp Core/WebServer.h @@ -1480,6 +1484,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Debugger/WebSocket/HLESubscriber.h Core/Debugger/WebSocket/LogBroadcaster.cpp Core/Debugger/WebSocket/LogBroadcaster.h + Core/Debugger/WebSocket/MemorySubscriber.cpp + Core/Debugger/WebSocket/MemorySubscriber.h Core/Debugger/WebSocket/SteppingBroadcaster.cpp Core/Debugger/WebSocket/SteppingBroadcaster.h Core/Debugger/WebSocket/SteppingSubscriber.cpp @@ -1542,6 +1548,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/KernelWaitHelpers.h Core/HLE/KUBridge.h Core/HLE/KUBridge.cpp + Core/HLE/Plugins.h + Core/HLE/Plugins.cpp Core/HLE/ThreadQueueList.h Core/HLE/__sceAudio.cpp Core/HLE/__sceAudio.h @@ -1681,6 +1689,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HW/SimpleAudioDec.h Core/HW/AsyncIOManager.cpp Core/HW/AsyncIOManager.h + Core/HW/BufferQueue.cpp + Core/HW/BufferQueue.h Core/HW/Camera.cpp Core/HW/Camera.h Core/HW/MediaEngine.cpp @@ -1741,6 +1751,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/MIPS/MIPSVFPUUtils.h Core/MIPS/MIPSAsm.cpp Core/MIPS/MIPSAsm.h + Core/MemFault.cpp + Core/MemFault.h Core/MemMap.cpp Core/MemMap.h Core/MemMapFunctions.cpp @@ -1759,12 +1771,16 @@ add_library(${CoreLibName} ${CoreLinkType} Core/System.h Core/TextureReplacer.cpp Core/TextureReplacer.h + Core/ThreadPools.cpp + Core/ThreadPools.h Core/Util/AudioFormat.cpp Core/Util/AudioFormat.h Core/Util/AudioFormatNEON.cpp Core/Util/AudioFormatNEON.h Core/Util/GameManager.cpp Core/Util/GameManager.h + Core/Util/PortManager.cpp + Core/Util/PortManager.h Core/Util/BlockAllocator.cpp Core/Util/BlockAllocator.h Core/Util/PPGeDraw.cpp @@ -1789,7 +1805,6 @@ set(CoreExtraLibs ${CoreExtraLibs} armips) # target_link_libraries(native X11-xcb X11) #endif() - set(GlslangLibs glslang OGLCompiler OSDependent SPIRV SPVRemapper spirv-cross-glsl) if(WIN32) @@ -1817,14 +1832,92 @@ if(USE_DISCORD AND NOT IOS AND NOT LIBRETRO) target_link_libraries(${CoreLibName} discord-rpc) endif() +# miniUPnPc integration (MiniUPnPc supposed to works on any POSIX system, not sure if some of these are redundant/not needed tho) +if(USE_MINIUPNPC) + set (MINIUPNPC_VERSION 2.1) # used by miniupnpcstrings.h.cmake + set (MINIUPNPC_API_VERSION 17) + option(UPNPC_BUILD_STATIC "Build static library" TRUE) + option(NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) + mark_as_advanced(NO_GETADDRINFO) + if (NO_GETADDRINFO) + add_definitions(-DNO_GETADDRINFO) + endif() + + if (NOT WIN32) + add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT) + add_definitions (-D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L) + endif() + if (MACOSX) + add_definitions (-D_DARWIN_C_SOURCE) + endif() + if(WIN32) + add_definitions(-DWIN32 -DMINIUPNP_EXPORTS ) + else() + add_definitions(-fPIC) + endif() + + add_definitions(-DMINIUPNP_STATICLIB) + set(MINIUPNP_DIR "ext/miniupnp/miniupnpc") + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + configure_file(${MINIUPNP_DIR}/miniupnpcstrings.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h) # by default miniupnp repo doesn't contains miniupnpcstrings.h and need to be generated + set(MINIUPNPC_SOURCES + # the needed bits of miniupnpc (no python module, no tests, no cli) + ${MINIUPNP_DIR}/connecthostport.c + ${MINIUPNP_DIR}/igd_desc_parse.c + ${MINIUPNP_DIR}/minisoap.c + ${MINIUPNP_DIR}/minissdpc.c + ${MINIUPNP_DIR}/miniupnpc.c + ${MINIUPNP_DIR}/miniwget.c + ${MINIUPNP_DIR}/minixml.c + ${MINIUPNP_DIR}/minixmlvalid.c + ${MINIUPNP_DIR}/portlistingparse.c + ${MINIUPNP_DIR}/receivedata.c + #${MINIUPNP_DIR}/upnpc.c # causing an error due to already existing _main() + ${MINIUPNP_DIR}/upnpcommands.c + ${MINIUPNP_DIR}/upnpdev.c + ${MINIUPNP_DIR}/upnperrors.c + ${MINIUPNP_DIR}/upnpreplyparse.c + ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h + ) + if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") + #set(MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c) # causing an error due to duplication in MINIUPNPC_SOURCES? + endif() + if (WIN32) + set_source_files_properties(${MINIUPNPC_SOURCES} PROPERTIES COMPILE_DEFINITIONS "MINIUPNP_STATICLIB;MINIUPNP_EXPORTS") + find_library(WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32) + find_library(IPHLPAPI_LIBRARY NAMES iphlpapi) + set(LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS}) + #elseif (CMAKE_SYSTEM_NAME STREQUAL "Solaris") + # find_library (SOCKET_LIBRARY NAMES socket) + # find_library (NSL_LIBRARY NAMES nsl) + # find_library (RESOLV_LIBRARY NAMES resolv) + # set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS}) + endif() + if (UPNPC_BUILD_STATIC) + add_library(miniupnpc STATIC ${MINIUPNPC_SOURCES}) + target_link_libraries(${CoreLibName} miniupnpc ${LDLIBS}) + set(UPNPC_LIBRARY miniupnpc) + if (MSVC) + # Suppress noise warnings + target_compile_definitions(miniupnpc PRIVATE _CRT_SECURE_NO_WARNINGS _WINSOCK_DEPRECATED_NO_WARNINGS) + endif() + endif() +endif() + setup_target_project(${CoreLibName} Core) -# Generate git-version.cpp at build time. -add_custom_target(GitVersion ALL - DEPENDS something_that_never_exists) +# Generate git-version at build time. +add_custom_target(GitVersion DEPENDS something_that_never_exists) + +set(WIN_VERSION_CMD "") +if (WIN32) + set(WIN_VERSION_CMD COMMAND ${CMAKE_SOURCE_DIR}/Windows/git-version-gen.cmd PPSSPPWindows) +endif() + add_custom_command(OUTPUT something_that_never_exists COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} - -P ${CMAKE_CURRENT_SOURCE_DIR}/git-version.cmake) + -P ${CMAKE_CURRENT_SOURCE_DIR}/git-version.cmake + ${WIN_VERSION_CMD}) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/git-version.cpp PROPERTIES GENERATED TRUE @@ -1953,6 +2046,11 @@ set(NativeAssets assets/rargray.png assets/unknown.png assets/zip.png + assets/sfx_back.wav + assets/sfx_confirm.wav + assets/sfx_select.wav + assets/sfx_toggle_off.wav + assets/sfx_toggle_on.wav source_assets/image/logo.png source_assets/image/icon_regular_72.png ) diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index e3e148a60a..467dd6d8ee 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -5,23 +5,19 @@ #include "ppsspp_config.h" #include -#include #include #include #include -#include -#include +#include +#include -#include "base/basictypes.h" - -#include "Arm64Emitter.h" -#include "MathUtil.h" -#include "CommonTypes.h" -#include "CommonWindows.h" -#include "CPUDetect.h" - -#include "CommonWindows.h" +#include "Common/Arm64Emitter.h" +#include "Common/Math/math_util.h" +#include "Common/CommonTypes.h" +#include "Common/CommonWindows.h" +#include "Common/CPUDetect.h" +#include "Common/Log.h" #ifdef IOS #include @@ -211,7 +207,7 @@ bool IsImmLogical(uint64_t value, unsigned int width, unsigned int *n, unsigned }; int multiplier_idx = CountLeadingZeros(d, kXRegSizeInBits) - 57; // Ensure that the index to the multipliers array is within bounds. - _dbg_assert_(JIT, (multiplier_idx >= 0) && + _dbg_assert_((multiplier_idx >= 0) && (static_cast(multiplier_idx) < ARRAY_SIZE(multipliers))); uint64_t multiplier = multipliers[multiplier_idx]; uint64_t candidate = (b - a) * multiplier; @@ -491,11 +487,11 @@ void ARM64XEmitter::EncodeCompareBranchInst(u32 op, ARM64Reg Rt, const void* ptr bool b64Bit = Is64Bit(Rt); s64 distance = (s64)ptr - (s64)m_code; - _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %llx", __FUNCTION__, distance); + _assert_msg_(!(distance & 0x3), "%s: distance must be a multiple of 4: %llx", __FUNCTION__, distance); distance >>= 2; - _assert_msg_(DYNA_REC, distance >= -0x40000 && distance <= 0x3FFFF, "%s: Received too large distance: %llx", __FUNCTION__, distance); + _assert_msg_(distance >= -0x40000 && distance <= 0x3FFFF, "%s: Received too large distance: %llx", __FUNCTION__, distance); Rt = DecodeReg(Rt); Write32((b64Bit << 31) | (0x34 << 24) | (op << 24) | \ @@ -507,11 +503,11 @@ void ARM64XEmitter::EncodeTestBranchInst(u32 op, ARM64Reg Rt, u8 bits, const voi bool b64Bit = Is64Bit(Rt); s64 distance = (s64)ptr - (s64)m_code; - _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %llx", __FUNCTION__, distance); + _assert_msg_(!(distance & 0x3), "%s: distance must be a multiple of 4: %llx", __FUNCTION__, distance); distance >>= 2; - _assert_msg_(DYNA_REC, distance >= -0x1FFF && distance < 0x1FFF, "%s: Received too large distance: %llx", __FUNCTION__, distance); + _assert_msg_(distance >= -0x1FFF && distance < 0x1FFF, "%s: Received too large distance: %llx", __FUNCTION__, distance); Rt = DecodeReg(Rt); Write32((b64Bit << 31) | (0x36 << 24) | (op << 24) | \ @@ -522,11 +518,11 @@ void ARM64XEmitter::EncodeUnconditionalBranchInst(u32 op, const void* ptr) { s64 distance = (s64)ptr - s64(m_code); - _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %llx", __FUNCTION__, distance); + _assert_msg_(!(distance & 0x3), "%s: distance must be a multiple of 4: %llx", __FUNCTION__, distance); distance >>= 2; - _assert_msg_(DYNA_REC, distance >= -0x2000000LL && distance <= 0x1FFFFFFLL, "%s: Received too large distance: %llx", __FUNCTION__, distance); + _assert_msg_(distance >= -0x2000000LL && distance <= 0x1FFFFFFLL, "%s: Received too large distance: %llx", __FUNCTION__, distance); Write32((op << 31) | (0x5 << 26) | (distance & 0x3FFFFFF)); } @@ -539,7 +535,7 @@ void ARM64XEmitter::EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 void ARM64XEmitter::EncodeExceptionInst(u32 instenc, u32 imm) { - _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: Exception instruction too large immediate: %d", __FUNCTION__, imm); + _assert_msg_(!(imm & ~0xFFFF), "%s: Exception instruction too large immediate: %d", __FUNCTION__, imm); Write32((0xD4 << 24) | (ExcEnc[instenc][0] << 21) | (imm << 5) | (ExcEnc[instenc][1] << 2) | ExcEnc[instenc][2]); } @@ -575,8 +571,8 @@ void ARM64XEmitter::EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 n { bool b64Bit = Is64Bit(Rn); - _assert_msg_(DYNA_REC, !(imm & ~0x1F), "%s: too large immediate: %d", __FUNCTION__, imm) - _assert_msg_(DYNA_REC, !(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) + _assert_msg_(!(imm & ~0x1F), "%s: too large immediate: %d", __FUNCTION__, imm) + _assert_msg_(!(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) Rn = DecodeReg(Rn); Write32((b64Bit << 31) | (op << 30) | (1 << 29) | (0xD2 << 21) | \ @@ -587,7 +583,7 @@ void ARM64XEmitter::EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u { bool b64Bit = Is64Bit(Rm); - _assert_msg_(DYNA_REC, !(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) + _assert_msg_(!(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) Rm = DecodeReg(Rm); Rn = DecodeReg(Rn); @@ -659,7 +655,7 @@ void ARM64XEmitter::EncodeLoadRegisterInst(u32 bitop, ARM64Reg Rt, u32 imm) bool b64Bit = Is64Bit(Rt); bool bVec = IsVector(Rt); - _assert_msg_(DYNA_REC, !(imm & 0xFFFFF), "%s: offset too large %d", __FUNCTION__, imm); + _assert_msg_(!(imm & 0xFFFFF), "%s: offset too large %d", __FUNCTION__, imm); Rt = DecodeReg(Rt); if (b64Bit && bitop != 0x2) // LDRSW(0x2) uses 64bit reg, doesn't have 64bit bit set @@ -692,7 +688,7 @@ void ARM64XEmitter::EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, else imm >>= 2; - _assert_msg_(DYNA_REC, !(imm & ~0xF), "%s: offset too large %d", __FUNCTION__, imm); + _assert_msg_(!(imm & ~0xF), "%s: offset too large %d", __FUNCTION__, imm); u32 opc = 0; if (b128Bit) @@ -715,7 +711,7 @@ void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, u32 op2, ARM64Reg Rt, ARM u32 offset = imm & 0x1FF; - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s: offset too large %d", __FUNCTION__, imm); + _assert_msg_(!(imm < -256 || imm > 255), "%s: offset too large %d", __FUNCTION__, imm); Rt = DecodeReg(Rt); Rn = DecodeReg(Rn); @@ -736,12 +732,12 @@ void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, shift = 1; if (shift) { - _assert_msg_(DYNA_REC, ((imm >> shift) << shift) == imm, "%s(INDEX_UNSIGNED): offset must be aligned %d", __FUNCTION__, imm); + _assert_msg_(((imm >> shift) << shift) == imm, "%s(INDEX_UNSIGNED): offset must be aligned %d", __FUNCTION__, imm); imm >>= shift; } - _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED): offset must be positive %d", __FUNCTION__, imm); - _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s(INDEX_UNSIGNED): offset too large %d", __FUNCTION__, imm); + _assert_msg_(imm >= 0, "%s(INDEX_UNSIGNED): offset must be positive %d", __FUNCTION__, imm); + _assert_msg_(!(imm & ~0xFFF), "%s(INDEX_UNSIGNED): offset too large %d", __FUNCTION__, imm); Rt = DecodeReg(Rt); Rn = DecodeReg(Rn); @@ -752,7 +748,7 @@ void ARM64XEmitter::EncodeMOVWideInst(u32 op, ARM64Reg Rd, u32 imm, ShiftAmount { bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: immediate out of range: %d", __FUNCTION__, imm); + _assert_msg_(!(imm & ~0xFFFF), "%s: immediate out of range: %d", __FUNCTION__, imm); Rd = DecodeReg(Rd); Write32((b64Bit << 31) | (op << 29) | (0x25 << 23) | (pos << 21) | (imm << 5) | Rd); @@ -782,7 +778,7 @@ void ARM64XEmitter::EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, { bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s: immediate too large: %x", __FUNCTION__, imm); + _assert_msg_(!(imm & ~0xFFF), "%s: immediate too large: %x", __FUNCTION__, imm); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -819,7 +815,7 @@ void ARM64XEmitter::EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64R type_encode = 3; break; case INDEX_UNSIGNED: - _assert_msg_(DYNA_REC, false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); + _assert_msg_(false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); break; } @@ -832,7 +828,7 @@ void ARM64XEmitter::EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64R imm >>= 2; } - _assert_msg_(JIT, imm >= -64 && imm <= 63, "%s recieved too large imm: %d", __FUNCTION__, imm); + _assert_msg_(imm >= -64 && imm <= 63, "%s recieved too large imm: %d", __FUNCTION__, imm); Rt = DecodeReg(Rt); Rt2 = DecodeReg(Rt2); @@ -851,7 +847,7 @@ void ARM64XEmitter::EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm) void ARM64XEmitter::EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s received too large offset: %d", __FUNCTION__, imm); + _assert_msg_(!(imm < -256 || imm > 255), "%s received too large offset: %d", __FUNCTION__, imm); Rt = DecodeReg(Rt); Rn = DecodeReg(Rn); @@ -896,31 +892,31 @@ void ARM64XEmitter::SetJumpTarget(FixupBranch const& branch) Not = true; case 0: // CBZ { - _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); + _assert_msg_(IsInRangeImm19(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); bool b64Bit = Is64Bit(branch.reg); ARM64Reg reg = DecodeReg(branch.reg); inst = (b64Bit << 31) | (0x1A << 25) | (Not << 24) | (MaskImm19(distance) << 5) | reg; } break; case 2: // B (conditional) - _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); + _assert_msg_(IsInRangeImm19(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); inst = (0x2A << 25) | (MaskImm19(distance) << 5) | branch.cond; break; case 4: // TBNZ Not = true; case 3: // TBZ { - _assert_msg_(DYNA_REC, IsInRangeImm14(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); + _assert_msg_(IsInRangeImm14(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); ARM64Reg reg = DecodeReg(branch.reg); inst = ((branch.bit & 0x20) << 26) | (0x1B << 25) | (Not << 24) | ((branch.bit & 0x1F) << 19) | (MaskImm14(distance) << 5) | reg; } break; case 5: // B (unconditional) - _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); + _assert_msg_(IsInRangeImm26(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); inst = (0x5 << 26) | MaskImm26(distance); break; case 6: // BL (unconditional) - _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); + _assert_msg_(IsInRangeImm26(distance), "%s(%d): Received too large distance: %llx", __FUNCTION__, branch.type, distance); inst = (0x25 << 26) | MaskImm26(distance); break; } @@ -1010,7 +1006,7 @@ void ARM64XEmitter::B(CCFlags cond, const void* ptr) distance >>= 2; - _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s: Received too large distance: %p->%p %lld %llx", __FUNCTION__, m_code, ptr, distance, distance); + _assert_msg_(IsInRangeImm19(distance), "%s: Received too large distance: %p->%p %lld %llx", __FUNCTION__, m_code, ptr, distance, distance); Write32((0x54 << 24) | (MaskImm19(distance) << 5) | cond); } @@ -1119,7 +1115,7 @@ void ARM64XEmitter::_MSR(PStateField field, u8 imm) case FIELD_DAIFSet: op1 = 3; op2 = 6; break; case FIELD_DAIFClr: op1 = 3; op2 = 7; break; default: - _assert_msg_(JIT, false, "Invalid PStateField to do a imm move to"); + _assert_msg_(false, "Invalid PStateField to do a imm move to"); break; } EncodeSystemInst(0, op1, 4, imm, op2, WSP); @@ -1137,21 +1133,21 @@ static void GetSystemReg(PStateField field, int &o0, int &op1, int &CRn, int &CR o0 = 3; op1 = 3; CRn = 4; CRm = 4; op2 = 1; break; default: - _assert_msg_(JIT, false, "Invalid PStateField to do a register move from/to"); + _assert_msg_(false, "Invalid PStateField to do a register move from/to"); break; } } void ARM64XEmitter::_MSR(PStateField field, ARM64Reg Rt) { int o0 = 0, op1 = 0, CRn = 0, CRm = 0, op2 = 0; - _assert_msg_(JIT, Is64Bit(Rt), "MSR: Rt must be 64-bit"); + _assert_msg_(Is64Bit(Rt), "MSR: Rt must be 64-bit"); GetSystemReg(field, o0, op1, CRn, CRm, op2); EncodeSystemInst(o0, op1, CRn, CRm, op2, DecodeReg(Rt)); } void ARM64XEmitter::MRS(ARM64Reg Rt, PStateField field) { int o0 = 0, op1 = 0, CRn = 0, CRm = 0, op2 = 0; - _assert_msg_(JIT, Is64Bit(Rt), "MRS: Rt must be 64-bit"); + _assert_msg_(Is64Bit(Rt), "MRS: Rt must be 64-bit"); GetSystemReg(field, o0, op1, CRn, CRm, op2); EncodeSystemInst(o0 | 4, op1, CRn, CRm, op2, DecodeReg(Rt)); } @@ -1475,7 +1471,7 @@ void ARM64XEmitter::MOV(ARM64Reg Rd, ARM64Reg Rm) if (IsGPR(Rd) && IsGPR(Rm)) { ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, 0)); } else { - _assert_msg_(JIT, false, "Non-GPRs not supported in MOV"); + _assert_msg_(false, "Non-GPRs not supported in MOV"); } } @@ -1587,14 +1583,14 @@ void ARM64XEmitter::UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) void ARM64XEmitter::BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) { u32 size = Is64Bit(Rn) ? 64 : 32; - _assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", + _assert_msg_((lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", __FUNCTION__, lsb, width); EncodeBitfieldMOVInst(1, Rd, Rn, (size - lsb) % size, width - 1); } void ARM64XEmitter::UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) { u32 size = Is64Bit(Rn) ? 64 : 32; - _assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", + _assert_msg_((lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", __FUNCTION__, lsb, width); EncodeBitfieldMOVInst(2, Rd, Rn, (size - lsb) % size, width - 1); } @@ -1616,7 +1612,7 @@ void ARM64XEmitter::SXTH(ARM64Reg Rd, ARM64Reg Rn) } void ARM64XEmitter::SXTW(ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, Is64Bit(Rd), "%s requires 64bit register as destination", __FUNCTION__); + _assert_msg_(Is64Bit(Rd), "%s requires 64bit register as destination", __FUNCTION__); SBFM(Rd, Rn, 0, 31); } void ARM64XEmitter::UXTB(ARM64Reg Rd, ARM64Reg Rn) @@ -1912,7 +1908,7 @@ void ARM64XEmitter::LDUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm) } void ARM64XEmitter::LDURSW(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - _assert_msg_(DYNA_REC, !Is64Bit(Rt), "%s must have a 64bit destination register!", __FUNCTION__); + _assert_msg_(!Is64Bit(Rt), "%s must have a 64bit destination register!", __FUNCTION__); EncodeLoadStoreUnscaled(2, 2, Rt, Rn, imm); } @@ -2067,8 +2063,8 @@ void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, if (type == INDEX_UNSIGNED) { - _assert_msg_(DYNA_REC, !(imm & ((size - 1) >> 3)), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)", __FUNCTION__, imm, m_emit->GetCodePointer()); - _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", __FUNCTION__); + _assert_msg_(!(imm & ((size - 1) >> 3)), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)", __FUNCTION__, imm, m_emit->GetCodePointer()); + _assert_msg_(imm >= 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", __FUNCTION__); if (size == 16) imm >>= 1; else if (size == 32) @@ -2081,7 +2077,7 @@ void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, } else { - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s immediate offset must be within range of -256 to 255!", __FUNCTION__); + _assert_msg_(!(imm < -256 || imm > 255), "%s immediate offset must be within range of -256 to 255!", __FUNCTION__); encoded_imm = (imm & 0x1FF) << 2; if (type == INDEX_POST) encoded_imm |= 1; @@ -2095,7 +2091,7 @@ void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, void ARM64FloatEmitter::EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s only supports double and single registers!", __FUNCTION__); + _assert_msg_(!IsQuad(Rd), "%s only supports double and single registers!", __FUNCTION__); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); Rm = DecodeReg(Rm); @@ -2106,7 +2102,7 @@ void ARM64FloatEmitter::EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, void ARM64FloatEmitter::EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + _assert_msg_(!IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); bool quad = IsQuad(Rd); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -2127,7 +2123,7 @@ void ARM64FloatEmitter::EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd void ARM64FloatEmitter::Emit2RegMisc(bool Q, bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + _assert_msg_(!IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -2137,7 +2133,7 @@ void ARM64FloatEmitter::Emit2RegMisc(bool Q, bool U, u32 size, u32 opcode, ARM64 void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); + _assert_msg_(!IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); bool quad = IsQuad(Rt); Rt = DecodeReg(Rt); Rn = DecodeReg(Rn); @@ -2148,7 +2144,7 @@ void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); + _assert_msg_(!IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); bool quad = IsQuad(Rt); Rt = DecodeReg(Rt); Rn = DecodeReg(Rn); @@ -2160,7 +2156,7 @@ void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, void ARM64FloatEmitter::Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + _assert_msg_(!IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -2170,7 +2166,7 @@ void ARM64FloatEmitter::Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64R void ARM64FloatEmitter::EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, Rn <= SP, "%s only supports GPR as source!", __FUNCTION__); + _assert_msg_(Rn <= SP, "%s only supports GPR as source!", __FUNCTION__); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -2180,7 +2176,7 @@ void ARM64FloatEmitter::EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 void ARM64FloatEmitter::EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign) { - _dbg_assert_msg_(JIT, IsScalar(Rn), "fcvts: Rn must be floating point"); + _dbg_assert_msg_(IsScalar(Rn), "fcvts: Rn must be floating point"); if (IsGPR(Rd)) { // Use the encoding that transfers the result to a GPR. bool sf = Is64Bit(Rd); @@ -2235,7 +2231,7 @@ void ARM64FloatEmitter::EmitConversion2(bool sf, bool S, bool direction, u32 typ void ARM64FloatEmitter::EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsQuad(Rn), "%s doesn't support vector!", __FUNCTION__); + _assert_msg_(!IsQuad(Rn), "%s doesn't support vector!", __FUNCTION__); bool is_double = IsDouble(Rn); Rn = DecodeReg(Rn); @@ -2247,7 +2243,7 @@ void ARM64FloatEmitter::EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Re void ARM64FloatEmitter::EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + _assert_msg_(!IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); bool is_double = IsDouble(Rd); Rd = DecodeReg(Rd); @@ -2260,7 +2256,7 @@ void ARM64FloatEmitter::EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd void ARM64FloatEmitter::EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + _assert_msg_(!IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); bool quad = IsQuad(Rd); @@ -2282,7 +2278,7 @@ void ARM64FloatEmitter::EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, void ARM64FloatEmitter::EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64Reg Rd, u32 imm8) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + _assert_msg_(!IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); bool is_double = !IsSingle(Rd); @@ -2294,7 +2290,7 @@ void ARM64FloatEmitter::EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64R void ARM64FloatEmitter::EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, immh, "%s bad encoding! Can't have zero immh", __FUNCTION__); + _assert_msg_(immh, "%s bad encoding! Can't have zero immh", __FUNCTION__); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -2352,7 +2348,7 @@ void ARM64FloatEmitter::EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 void ARM64FloatEmitter::EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + _assert_msg_(!IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -2375,7 +2371,7 @@ void ARM64FloatEmitter::EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, void ARM64FloatEmitter::EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s received too large offset: %d", __FUNCTION__, imm); + _assert_msg_(!(imm < -256 || imm > 255), "%s received too large offset: %d", __FUNCTION__, imm); Rt = DecodeReg(Rt); Rn = DecodeReg(Rn); @@ -2399,25 +2395,25 @@ void ARM64FloatEmitter::EncodeLoadStorePair(u32 size, bool load, IndexType type, type_encode = 3; break; case INDEX_UNSIGNED: - _assert_msg_(DYNA_REC, false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); + _assert_msg_(false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); break; } if (size == 128) { - _assert_msg_(DYNA_REC, !(imm & 0xF), "%s received invalid offset 0x%x!", __FUNCTION__, imm); + _assert_msg_(!(imm & 0xF), "%s received invalid offset 0x%x!", __FUNCTION__, imm); opc = 2; imm >>= 4; } else if (size == 64) { - _assert_msg_(DYNA_REC, !(imm & 0x7), "%s received invalid offset 0x%x!", __FUNCTION__, imm); + _assert_msg_(!(imm & 0x7), "%s received invalid offset 0x%x!", __FUNCTION__, imm); opc = 1; imm >>= 3; } else if (size == 32) { - _assert_msg_(DYNA_REC, !(imm & 0x3), "%s received invalid offset 0x%x!", __FUNCTION__, imm); + _assert_msg_(!(imm & 0x3), "%s received invalid offset 0x%x!", __FUNCTION__, imm); opc = 0; imm >>= 2; } @@ -2433,7 +2429,7 @@ void ARM64FloatEmitter::EncodeLoadStorePair(u32 size, bool load, IndexType type, void ARM64FloatEmitter::EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - _assert_msg_(DYNA_REC, Rm.GetType() == ArithOption::TYPE_EXTENDEDREG, "%s must contain an extended reg as Rm!", __FUNCTION__); + _assert_msg_(Rm.GetType() == ArithOption::TYPE_EXTENDEDREG, "%s must contain an extended reg as Rm!", __FUNCTION__); u32 encoded_size = 0; u32 encoded_op = 0; @@ -2786,7 +2782,7 @@ void ARM64FloatEmitter::ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Re // Loadstore multiple structure void ARM64FloatEmitter::LD1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); + _assert_msg_(!(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); u32 opcode = 0; if (count == 1) opcode = 7; @@ -2800,8 +2796,8 @@ void ARM64FloatEmitter::LD1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) } void ARM64FloatEmitter::LD1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); - _assert_msg_(DYNA_REC, type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); + _assert_msg_(!(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); + _assert_msg_(type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); u32 opcode = 0; if (count == 1) @@ -2816,7 +2812,7 @@ void ARM64FloatEmitter::LD1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM6 } void ARM64FloatEmitter::ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); + _assert_msg_(!(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); u32 opcode = 0; if (count == 1) opcode = 7; @@ -2830,8 +2826,8 @@ void ARM64FloatEmitter::ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) } void ARM64FloatEmitter::ST1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); - _assert_msg_(DYNA_REC, type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); + _assert_msg_(!(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); + _assert_msg_(type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); u32 opcode = 0; if (count == 1) @@ -2851,7 +2847,7 @@ void ARM64FloatEmitter::FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top) if (IsScalar(Rd) && IsScalar(Rn)) { EmitScalar1Source(0, 0, IsDouble(Rd), 0, Rd, Rn); } else { - _assert_msg_(JIT, !IsQuad(Rd) && !IsQuad(Rn), "FMOV can't move to/from quads"); + _assert_msg_(!IsQuad(Rd) && !IsQuad(Rn), "FMOV can't move to/from quads"); int rmode = 0; int opcode = 6; int sf = 0; @@ -2862,7 +2858,7 @@ void ARM64FloatEmitter::FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top) // Scalar single to GPR - defaults are correct } else { // TODO - _assert_msg_(JIT, 0, "FMOV: Unhandled case"); + _assert_msg_(false, "FMOV: Unhandled case"); } Rd = DecodeReg(Rd); Rn = DecodeReg(Rn); @@ -3234,8 +3230,8 @@ void ARM64FloatEmitter::INS(u8 size, ARM64Reg Rd, u8 index1, ARM64Reg Rn, u8 ind void ARM64FloatEmitter::UMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) { bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, Rd < SP, "%s destination must be a GPR!", __FUNCTION__); - _assert_msg_(DYNA_REC, !(b64Bit && size != 64), "%s must have a size of 64 when destination is 64bit!", __FUNCTION__); + _assert_msg_(Rd < SP, "%s destination must be a GPR!", __FUNCTION__); + _assert_msg_(!(b64Bit && size != 64), "%s must have a size of 64 when destination is 64bit!", __FUNCTION__); u32 imm5 = 0; if (size == 8) @@ -3264,8 +3260,8 @@ void ARM64FloatEmitter::UMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) void ARM64FloatEmitter::SMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) { bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, Rd < SP, "%s destination must be a GPR!", __FUNCTION__); - _assert_msg_(DYNA_REC, size != 64, "%s doesn't support 64bit destination. Use UMOV!", __FUNCTION__); + _assert_msg_(Rd < SP, "%s destination must be a GPR!", __FUNCTION__); + _assert_msg_(size != 64, "%s doesn't support 64bit destination. Use UMOV!", __FUNCTION__); u32 imm5 = 0; if (size == 8) @@ -3499,40 +3495,40 @@ static u32 EncodeImmShiftRight(u8 src_size, u32 shift) { void ARM64FloatEmitter::SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) { - _assert_msg_(DYNA_REC, shift < src_size, "%s shift amount must less than the element size!", __FUNCTION__); + _assert_msg_(shift < src_size, "%s shift amount must less than the element size!", __FUNCTION__); u32 imm = EncodeImmShiftLeft(src_size, shift); EmitShiftImm(upper, 0, imm >> 3, imm & 7, 0x14, Rd, Rn); } void ARM64FloatEmitter::USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) { - _assert_msg_(DYNA_REC, shift < src_size, "%s shift amount must less than the element size!", __FUNCTION__); + _assert_msg_(shift < src_size, "%s shift amount must less than the element size!", __FUNCTION__); u32 imm = EncodeImmShiftLeft(src_size, shift); EmitShiftImm(upper, 1, imm >> 3, imm & 7, 0x14, Rd, Rn); } void ARM64FloatEmitter::SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) { - _assert_msg_(DYNA_REC, shift > 0, "%s shift amount must be greater than zero!", __FUNCTION__); - _assert_msg_(DYNA_REC, shift <= dest_size, "%s shift amount must less than or equal to the element size!", __FUNCTION__); + _assert_msg_(shift > 0, "%s shift amount must be greater than zero!", __FUNCTION__); + _assert_msg_(shift <= dest_size, "%s shift amount must less than or equal to the element size!", __FUNCTION__); u32 imm = EncodeImmShiftRight(dest_size, shift); EmitShiftImm(upper, 0, imm >> 3, imm & 7, 0x10, Rd, Rn); } void ARM64FloatEmitter::SHL(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - _assert_msg_(DYNA_REC, shift < dest_size, "%s shift amount must less than the element size!", __FUNCTION__); + _assert_msg_(shift < dest_size, "%s shift amount must less than the element size!", __FUNCTION__); u32 imm = EncodeImmShiftLeft(dest_size, shift); EmitShiftImm(IsQuad(Rd), false, imm >> 3, imm & 7, 0xA, Rd, Rn); } void ARM64FloatEmitter::USHR(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - _assert_msg_(DYNA_REC, shift < dest_size, "%s shift amount must less than the element size!", __FUNCTION__); + _assert_msg_(shift < dest_size, "%s shift amount must less than the element size!", __FUNCTION__); u32 imm = EncodeImmShiftRight(dest_size, shift); EmitShiftImm(IsQuad(Rd), true, imm >> 3, imm & 7, 0x0, Rd, Rn); } void ARM64FloatEmitter::SSHR(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - _assert_msg_(DYNA_REC, shift < dest_size, "%s shift amount must less than the element size!", __FUNCTION__); + _assert_msg_(shift < dest_size, "%s shift amount must less than the element size!", __FUNCTION__); u32 imm = EncodeImmShiftRight(dest_size, shift); EmitShiftImm(IsQuad(Rd), false, imm >> 3, imm & 7, 0x0, Rd, Rn); } @@ -3550,7 +3546,7 @@ void ARM64FloatEmitter::UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper) // vector x indexed element void ARM64FloatEmitter::FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index) { - _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __FUNCTION__); + _assert_msg_(size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __FUNCTION__); bool L = false; bool H = false; @@ -3566,7 +3562,7 @@ void ARM64FloatEmitter::FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 void ARM64FloatEmitter::FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index) { - _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __FUNCTION__); + _assert_msg_(size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __FUNCTION__); bool L = false; bool H = false; @@ -3581,7 +3577,7 @@ void ARM64FloatEmitter::FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 } void ARM64FloatEmitter::ABI_PushRegisters(uint32_t registers, uint32_t fp_registers) { - _assert_msg_(DYNA_REC, (registers & 0x60000000) == 0, "ABI_PushRegisters: Do not include FP and LR, those are handled non-conditionally"); + _assert_msg_((registers & 0x60000000) == 0, "ABI_PushRegisters: Do not include FP and LR, those are handled non-conditionally"); ARM64Reg gprs[32]{}, fprs[32]{}; int num_gprs = 0, num_fprs = 0; @@ -3676,25 +3672,25 @@ void ARM64XEmitter::ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) if (!Is64Bit(Rn)) imm &= 0xFFFFFFFF; if (!TryANDI2R(Rd, Rn, imm)) { - _assert_msg_(JIT, scratch != INVALID_REG, "ANDI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "ANDI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); AND(Rd, Rn, scratch); } } void ARM64XEmitter::ORRI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - _assert_msg_(JIT, Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "ORRI2R - more bits in imm than Rn"); + _assert_msg_(Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "ORRI2R - more bits in imm than Rn"); if (!TryORRI2R(Rd, Rn, imm)) { - _assert_msg_(JIT, scratch != INVALID_REG, "ORRI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "ORRI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); ORR(Rd, Rn, scratch); } } void ARM64XEmitter::EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - _assert_msg_(JIT, Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "EORI2R - more bits in imm than Rn"); + _assert_msg_(Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "EORI2R - more bits in imm than Rn"); if (!TryEORI2R(Rd, Rn, imm)) { - _assert_msg_(JIT, scratch != INVALID_REG, "EORI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "EORI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); EOR(Rd, Rn, scratch); } @@ -3709,7 +3705,7 @@ void ARM64XEmitter::ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) } else if (imm == 0) { ANDS(Rd, Rn, Is64Bit(Rn) ? ZR : WZR); } else { - _assert_msg_(JIT, scratch != INVALID_REG, "ANDSI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "ANDSI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); ANDS(Rd, Rn, scratch); } @@ -3717,7 +3713,7 @@ void ARM64XEmitter::ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) void ARM64XEmitter::ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { if (!TryADDI2R(Rd, Rn, imm)) { - _assert_msg_(JIT, scratch != INVALID_REG, "ADDI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "ADDI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); ADD(Rd, Rn, scratch); } @@ -3725,7 +3721,7 @@ void ARM64XEmitter::ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) void ARM64XEmitter::SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { if (!TrySUBI2R(Rd, Rn, imm)) { - _assert_msg_(JIT, scratch != INVALID_REG, "SUBI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "SUBI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); SUB(Rd, Rn, scratch); } @@ -3733,7 +3729,7 @@ void ARM64XEmitter::SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) void ARM64XEmitter::CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch) { if (!TryCMPI2R(Rn, imm)) { - _assert_msg_(JIT, scratch != INVALID_REG, "CMPI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "CMPI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); CMP(Rn, scratch); } @@ -3807,7 +3803,7 @@ bool ARM64XEmitter::TryANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) { } } bool ARM64XEmitter::TryORRI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) { - _assert_msg_(JIT, Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "TryORRI2R - more bits in imm than Rn"); + _assert_msg_(Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "TryORRI2R - more bits in imm than Rn"); u32 n, imm_r, imm_s; if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) { ORR(Rd, Rn, imm_r, imm_s, n != 0); @@ -3822,7 +3818,7 @@ bool ARM64XEmitter::TryORRI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) { } } bool ARM64XEmitter::TryEORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) { - _assert_msg_(JIT, Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "TryEORI2R - more bits in imm than Rn"); + _assert_msg_(Is64Bit(Rn) || (imm & 0xFFFFFFFF00000000UL) == 0, "TryEORI2R - more bits in imm than Rn"); u32 n, imm_r, imm_s; if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) { EOR(Rd, Rn, imm_r, imm_s, n != 0); @@ -3872,7 +3868,7 @@ bool FPImm8FromFloat(float value, uint8_t *immOut) { } void ARM64FloatEmitter::MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch, bool negate) { - _assert_msg_(JIT, !IsDouble(Rd), "MOVI2F does not yet support double precision"); + _assert_msg_(!IsDouble(Rd), "MOVI2F does not yet support double precision"); uint8_t imm8; if (value == 0.0) { if (std::signbit(value)) { @@ -3891,7 +3887,7 @@ void ARM64FloatEmitter::MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch, bool FNEG(Rd, Rd); } } else { - _assert_msg_(JIT, scratch != INVALID_REG, "Failed to find a way to generate FP immediate %f without scratch", value); + _assert_msg_(scratch != INVALID_REG, "Failed to find a way to generate FP immediate %f without scratch", value); u32 ival; if (negate) { value = -value; @@ -3923,7 +3919,7 @@ void ARM64XEmitter::SUBSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) if (IsImmArithmetic(imm, &val, &shift)) { SUBS(Rd, Rn, val, shift); } else { - _assert_msg_(JIT, scratch != INVALID_REG, "SUBSI2R - failed to construct immediate value from %08x, need scratch", (u32)imm); + _assert_msg_(scratch != INVALID_REG, "SUBSI2R - failed to construct immediate value from %08x, need scratch", (u32)imm); MOVI2R(scratch, imm); SUBS(Rd, Rn, scratch); } diff --git a/Common/Arm64Emitter.h b/Common/Arm64Emitter.h index eb0fe1f1e5..e63052dcd8 100644 --- a/Common/Arm64Emitter.h +++ b/Common/Arm64Emitter.h @@ -6,10 +6,11 @@ #include -#include "ArmCommon.h" -#include "BitSet.h" -#include "CodeBlock.h" -#include "Common.h" +#include "Common/ArmCommon.h" +#include "Common/BitSet.h" +#include "Common/CodeBlock.h" +#include "Common/Common.h" +#include "Common/Log.h" #define DYNA_REC JIT @@ -329,7 +330,7 @@ public: (m_shift << 10); break; default: - _dbg_assert_msg_(DYNA_REC, false, "Invalid type in GetData"); + _dbg_assert_msg_(false, "Invalid type in GetData"); break; } return 0; @@ -697,7 +698,7 @@ public: void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true); template void MOVP2R(ARM64Reg Rd, P *ptr) { - _assert_msg_(JIT, Is64Bit(Rd), "Can't store pointers in 32-bit registers"); + _assert_msg_(Is64Bit(Rd), "Can't store pointers in 32-bit registers"); MOVI2R(Rd, (uintptr_t)ptr); } diff --git a/Common/ArmCPUDetect.cpp b/Common/ArmCPUDetect.cpp index da8d45f2f9..540f7d7b0c 100644 --- a/Common/ArmCPUDetect.cpp +++ b/Common/ArmCPUDetect.cpp @@ -16,14 +16,18 @@ // http://code.google.com/p/dolphin-emu/ #include "ppsspp_config.h" + +#include + #if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) #include -#include "Common.h" -#include "CPUDetect.h" -#include "StringUtils.h" -#include "FileUtil.h" -#include "util/text/utf8.h" + +#include "Common/Common.h" +#include "Common/CPUDetect.h" +#include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" +#include "Common/Data/Encoding/Utf8.h" #if PPSSPP_PLATFORM(WINDOWS) #if PPSSPP_PLATFORM(UWP) diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index dcaab522c5..b3878fd443 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -17,9 +17,6 @@ #include "ppsspp_config.h" -#include "base/logging.h" - -#include #include #include #include @@ -31,9 +28,10 @@ #include #endif -#include "MemoryUtil.h" -#include "ArmEmitter.h" -#include "CPUDetect.h" +#include "Common/Log.h" +#include "Common/MemoryUtil.h" +#include "Common/ArmEmitter.h" +#include "Common/CPUDetect.h" #ifdef _WIN32 #include "CommonWindows.h" @@ -95,7 +93,7 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated) Operand2 AssumeMakeOperand2(u32 imm) { Operand2 op2; bool result = TryMakeOperand2(imm, op2); - _dbg_assert_msg_(JIT, result, "Could not make assumed Operand2."); + _dbg_assert_msg_(result, "Could not make assumed Operand2."); if (!result) { // Make double sure that we get it logged. ERROR_LOG(JIT, "Could not make assumed Operand2."); @@ -705,7 +703,7 @@ FixupBranch ARMXEmitter::B_CC(CCFlags Cond) void ARMXEmitter::B_CC(CCFlags Cond, const void *fnptr) { ptrdiff_t distance = (intptr_t)fnptr - ((intptr_t)(code) + 8); - _assert_msg_(JIT, distance > -0x2000000 && distance < 0x2000000, + _assert_msg_(distance > -0x2000000 && distance < 0x2000000, "B_CC out of range (%p calls %p)", code, fnptr); Write32((Cond << 28) | 0x0A000000 | ((distance >> 2) & 0x00FFFFFF)); @@ -723,7 +721,7 @@ FixupBranch ARMXEmitter::BL_CC(CCFlags Cond) void ARMXEmitter::SetJumpTarget(FixupBranch const &branch) { ptrdiff_t distance = ((intptr_t)(code) - 8) - (intptr_t)branch.ptr; - _assert_msg_(JIT, distance > -0x2000000 && distance < 0x2000000, + _assert_msg_(distance > -0x2000000 && distance < 0x2000000, "SetJumpTarget out of range (%p calls %p)", code, branch.ptr); u32 instr = (u32)(branch.condition | ((distance >> 2) & 0x00FFFFFF)); instr |= branch.type == 0 ? /* B */ 0x0A000000 : /* BL */ 0x0B000000; @@ -732,7 +730,7 @@ void ARMXEmitter::SetJumpTarget(FixupBranch const &branch) void ARMXEmitter::B(const void *fnptr) { ptrdiff_t distance = (intptr_t)fnptr - (intptr_t(code) + 8); - _assert_msg_(JIT, distance > -0x2000000 && distance < 0x2000000, + _assert_msg_(distance > -0x2000000 && distance < 0x2000000, "B out of range (%p calls %p)", code, fnptr); Write32(condition | 0x0A000000 | ((distance >> 2) & 0x00FFFFFF)); @@ -754,7 +752,7 @@ bool ARMXEmitter::BLInRange(const void *fnptr) const { void ARMXEmitter::BL(const void *fnptr) { ptrdiff_t distance = (intptr_t)fnptr - (intptr_t(code) + 8); - _assert_msg_(JIT, distance > -0x2000000 && distance < 0x2000000, + _assert_msg_(distance > -0x2000000 && distance < 0x2000000, "BL out of range (%p calls %p)", code, fnptr); Write32(condition | 0x0B000000 | ((distance >> 2) & 0x00FFFFFF)); } @@ -894,7 +892,7 @@ void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, b } } if (op == -1) - _assert_msg_(JIT, false, "%s not yet support %d", InstNames[Op], Rm.GetType()); + _assert_msg_(false, "%s not yet support %d", InstNames[Op], Rm.GetType()); Write32(condition | (op << 21) | (SetFlags ? (1 << 20) : 0) | Rn << 16 | Rd << 12 | Data); } @@ -905,14 +903,12 @@ void ARMXEmitter::WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARM } void ARMXEmitter::UDIV(ARMReg dest, ARMReg dividend, ARMReg divisor) { - if (!cpu_info.bIDIVa) - PanicAlert("Trying to use integer divide on hardware that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bIDIVa, "Trying to use integer divide on hardware that doesn't support it."); WriteSignedMultiply(3, 0xF, 0, dest, divisor, dividend); } void ARMXEmitter::SDIV(ARMReg dest, ARMReg dividend, ARMReg divisor) { - if (!cpu_info.bIDIVa) - PanicAlert("Trying to use integer divide on hardware that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bIDIVa, "Trying to use integer divide on hardware that doesn't support it."); WriteSignedMultiply(1, 0xF, 0, dest, divisor, dividend); } @@ -921,21 +917,21 @@ void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedData void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);} void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);} void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { - _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "LSR must have a non-zero shift (use LSL.)"); + _assert_msg_(op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "LSR must have a non-zero shift (use LSL.)"); WriteShiftedDataOp(2, false, dest, src, op2); } void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, Operand2 op2) { - _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "LSRS must have a non-zero shift (use LSLS.)"); + _assert_msg_(op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "LSRS must have a non-zero shift (use LSLS.)"); WriteShiftedDataOp(2, true, dest, src, op2); } void ARMXEmitter::LSR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, false, dest, src, op2);} void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, true, dest, src, op2);} void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) { - _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "ASR must have a non-zero shift (use LSL.)"); + _assert_msg_(op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "ASR must have a non-zero shift (use LSL.)"); WriteShiftedDataOp(4, false, dest, src, op2); } void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) { - _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "ASRS must have a non-zero shift (use LSLS.)"); + _assert_msg_(op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "ASRS must have a non-zero shift (use LSLS.)"); WriteShiftedDataOp(4, true, dest, src, op2); } void ARMXEmitter::ASR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(5, false, dest, src, op2);} @@ -990,7 +986,7 @@ void ARMXEmitter::CLZ(ARMReg rd, ARMReg rm) } void ARMXEmitter::PLD(ARMReg rn, int offset, bool forWrite) { - _dbg_assert_msg_(JIT, offset < 0x3ff && offset > -0x3ff, "PLD: Max 12 bits of offset allowed"); + _dbg_assert_msg_(offset < 0x3ff && offset > -0x3ff, "PLD: Max 12 bits of offset allowed"); bool U = offset >= 0; if (offset < 0) offset = -offset; @@ -1060,7 +1056,7 @@ void ARMXEmitter::LDREX(ARMReg dest, ARMReg base) } void ARMXEmitter::STREX(ARMReg result, ARMReg base, ARMReg op) { - _assert_msg_(JIT, (result != base && result != op), "STREX dest can't be other two registers"); + _assert_msg_((result != base && result != op), "STREX dest can't be other two registers"); Write32(condition | (24 << 20) | (base << 16) | (result << 12) | (0xF9 << 4) | op); } void ARMXEmitter::DMB () @@ -1113,7 +1109,7 @@ void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool R bool SignedLoad = false; if (op == -1) - _assert_msg_(JIT, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType()); + _assert_msg_(false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType()); switch (Op) { @@ -1205,7 +1201,7 @@ void ARMXEmitter::WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegLi } void ARMXEmitter::WriteVRegStoreOp(u32 op, ARMReg Rn, bool Double, bool WriteBack, ARMReg Vd, u8 numregs) { - _dbg_assert_msg_(JIT, !WriteBack || Rn != R_PC, "VLDM/VSTM cannot use WriteBack with PC (PC is deprecated anyway.)"); + _dbg_assert_msg_(!WriteBack || Rn != R_PC, "VLDM/VSTM cannot use WriteBack with PC (PC is deprecated anyway.)"); Write32(condition | (op << 20) | (WriteBack << 21) | (Rn << 16) | EncodeVd(Vd) | ((0xA | (int)Double) << 8) | (numregs << (int)Double)); } void ARMXEmitter::STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...) @@ -1259,8 +1255,8 @@ void ARMXEmitter::LDMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack, // NEON Specific void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _assert_msg_(JIT, Vd >= D0, "Pass invalid register to VABD(float)"); - _assert_msg_(JIT, cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it"); + _assert_msg_(Vd >= D0, "Pass invalid register to VABD(float)"); + _assert_msg_(cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it"); bool register_quad = Vd >= Q0; // Gets encoded as a double register @@ -1274,8 +1270,8 @@ void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _assert_msg_(JIT, Vd >= D0, "Pass invalid register to VADD(integer)"); - _assert_msg_(JIT, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it"); + _assert_msg_(Vd >= D0, "Pass invalid register to VADD(integer)"); + _assert_msg_(cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it"); bool register_quad = Vd >= Q0; @@ -1291,8 +1287,8 @@ void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _assert_msg_(JIT, Vd >= Q0, "Pass invalid register to VSUB(integer)"); - _assert_msg_(JIT, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it"); + _assert_msg_(Vd >= Q0, "Pass invalid register to VSUB(integer)"); + _assert_msg_(cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it"); // Gets encoded as a double register Vd = SubBase(Vd); @@ -1399,7 +1395,7 @@ u32 encodedSize(u32 value) else if (value & I_64) return 3; else - _dbg_assert_msg_(JIT, false, "Passed invalid size to integer NEON instruction"); + _dbg_assert_msg_(false, "Passed invalid size to integer NEON instruction"); return 0; } @@ -1444,7 +1440,7 @@ void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm) VFPEnc enc = VFPOps[Op][quad_reg]; if (enc.opc1 == -1 && enc.opc2 == -1) - _assert_msg_(JIT, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP"); + _assert_msg_(false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP"); u32 VdEnc = EncodeVd(Vd); u32 VnEnc = EncodeVn(Vn); u32 VmEnc = EncodeVm(Vm); @@ -1481,25 +1477,25 @@ void ARMXEmitter::VSTMIA(ARMReg ptr, bool WriteBack, ARMReg firstvreg, int numvr void ARMXEmitter::VLDMDB(ARMReg ptr, bool WriteBack, ARMReg firstvreg, int numvregs) { - _dbg_assert_msg_(JIT, WriteBack, "Writeback is required for VLDMDB"); + _dbg_assert_msg_(WriteBack, "Writeback is required for VLDMDB"); WriteVRegStoreOp(0x80 | 0x040 | 0x10 | 1, ptr, firstvreg >= D0, WriteBack, firstvreg, numvregs); } void ARMXEmitter::VSTMDB(ARMReg ptr, bool WriteBack, ARMReg firstvreg, int numvregs) { - _dbg_assert_msg_(JIT, WriteBack, "Writeback is required for VSTMDB"); + _dbg_assert_msg_(WriteBack, "Writeback is required for VSTMDB"); WriteVRegStoreOp(0x80 | 0x040 | 0x10, ptr, firstvreg >= D0, WriteBack, firstvreg, numvregs); } void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) { - _assert_msg_(JIT, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR"); - _assert_msg_(JIT, Base <= R15, "Passed invalid Base register to VLDR"); + _assert_msg_(Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR"); + _assert_msg_(Base <= R15, "Passed invalid Base register to VLDR"); bool Add = offset >= 0 ? true : false; u32 imm = abs(offset); - _assert_msg_(JIT, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough"); + _assert_msg_((imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough"); if (imm & 0xC03) ERROR_LOG(JIT, "VLDR: Bad offset %08x", imm); @@ -1521,13 +1517,13 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) } void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset) { - _assert_msg_(JIT, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR"); - _assert_msg_(JIT, Base <= R15, "Passed invalid base register to VSTR"); + _assert_msg_(Src >= S0 && Src <= D31, "Passed invalid src register to VSTR"); + _assert_msg_(Base <= R15, "Passed invalid base register to VSTR"); bool Add = offset >= 0 ? true : false; u32 imm = abs(offset); - _assert_msg_(JIT, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough"); + _assert_msg_((imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough"); if (imm & 0xC03) ERROR_LOG(JIT, "VSTR: Bad offset %08x", imm); @@ -1560,15 +1556,15 @@ void ARMXEmitter::VMSR(ARMReg Rt) { void ARMXEmitter::VMOV(ARMReg Dest, Operand2 op2) { - _assert_msg_(JIT, cpu_info.bVFPv3, "VMOV #imm requires VFPv3"); + _assert_msg_(cpu_info.bVFPv3, "VMOV #imm requires VFPv3"); int sz = Dest >= D0 ? (1 << 8) : 0; Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (5 << 9) | sz | op2.Imm8VFP()); } void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, u32 imm) { - _assert_msg_(JIT, cpu_info.bNEON, "VMOV_neon #imm requires NEON"); - _assert_msg_(JIT, Vd >= D0, "VMOV_neon #imm must target a double or quad"); + _assert_msg_(cpu_info.bNEON, "VMOV_neon #imm requires NEON"); + _assert_msg_(Vd >= D0, "VMOV_neon #imm must target a double or quad"); bool register_quad = Vd >= Q0; int cmode = 0; @@ -1642,7 +1638,7 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, u32 imm) cmode = 7 << 1; op2 = IMM(imm8 | (imm8 << 4)); } else { - _assert_msg_(JIT, false, "VMOV_neon #imm invalid constant value"); + _assert_msg_(false, "VMOV_neon #imm invalid constant value"); } } @@ -1652,7 +1648,7 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, u32 imm) void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane) { - _assert_msg_(JIT, cpu_info.bNEON, "VMOV_neon requires NEON"); + _assert_msg_(cpu_info.bNEON, "VMOV_neon requires NEON"); int opc1 = 0; int opc2 = 0; @@ -1666,7 +1662,7 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane) opc1 = lane & 1; break; default: - _assert_msg_(JIT, false, "VMOV_neon unsupported size"); + _assert_msg_(false, "VMOV_neon unsupported size"); } if (Vd < S0 && Rt >= D0 && Rt < Q0) @@ -1675,7 +1671,7 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane) ARMReg Src = Rt; ARMReg Dest = Vd; - _dbg_assert_msg_(JIT, (Size & (I_UNSIGNED | I_SIGNED | F_32)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VMOV, unless F_32"); + _dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED | F_32)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VMOV, unless F_32"); int U = (Size & I_UNSIGNED) ? (1 << 23) : 0; Write32(condition | (0xE1 << 20) | U | (opc1 << 21) | EncodeVn(Src) | (Dest << 12) | (0xB << 8) | (opc2 << 5) | (1 << 4)); @@ -1687,12 +1683,12 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane) Write32(condition | (0xE0 << 20) | (opc1 << 21) | EncodeVn(Dest) | (Src << 12) | (0xB << 8) | (opc2 << 5) | (1 << 4)); } else - _assert_msg_(JIT, false, "VMOV_neon unsupported arguments (Dx -> Rx or Rx -> Dx)"); + _assert_msg_(false, "VMOV_neon unsupported arguments (Dx -> Rx or Rx -> Dx)"); } void ARMXEmitter::VMOV(ARMReg Vd, ARMReg Rt, ARMReg Rt2) { - _assert_msg_(JIT, cpu_info.bVFP | cpu_info.bNEON, "VMOV_neon requires VFP or NEON"); + _assert_msg_(cpu_info.bVFP | cpu_info.bNEON, "VMOV_neon requires VFP or NEON"); if (Vd < S0 && Rt < S0 && Rt2 >= D0) { @@ -1710,13 +1706,13 @@ void ARMXEmitter::VMOV(ARMReg Vd, ARMReg Rt, ARMReg Rt2) Write32(condition | (0xC4 << 20) | (Src2 << 16) | (Src1 << 12) | (0xB << 8) | EncodeVm(Dest) | (1 << 4)); } else - _assert_msg_(JIT, false, "VMOV_neon requires either Dm, Rt, Rt2 or Rt, Rt2, Dm."); + _assert_msg_(false, "VMOV_neon requires either Dm, Rt, Rt2 or Rt, Rt2, Dm."); } void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high) { - _assert_msg_(JIT, Src < S0, "This VMOV doesn't support SRC other than ARM Reg"); - _assert_msg_(JIT, Dest >= D0, "This VMOV doesn't support DEST other than VFP"); + _assert_msg_(Src < S0, "This VMOV doesn't support SRC other than ARM Reg"); + _assert_msg_(Dest >= D0, "This VMOV doesn't support DEST other than VFP"); Dest = SubBase(Dest); @@ -1744,7 +1740,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) else { // Move 64bit from Arm reg - _assert_msg_(JIT, false, "This VMOV doesn't support moving 64bit ARM to NEON"); + _assert_msg_(false, "This VMOV doesn't support moving 64bit ARM to NEON"); return; } } @@ -1764,14 +1760,14 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) else { // Move 64bit To Arm reg - _assert_msg_(JIT, false, "This VMOV doesn't support moving 64bit ARM From NEON"); + _assert_msg_(false, "This VMOV doesn't support moving 64bit ARM From NEON"); return; } } else { // Move Arm reg to Arm reg - _assert_msg_(JIT, false, "VMOV doesn't support moving ARM registers"); + _assert_msg_(false, "VMOV doesn't support moving ARM registers"); } } // Moving NEON registers @@ -1780,9 +1776,9 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) bool Single = DestSize == 1; bool Quad = DestSize == 4; - _assert_msg_(JIT, SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); + _assert_msg_(SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); if (SrcSize != DestSize) { - ELOG("SrcSize: %i (%s) DestDize: %i (%s)", SrcSize, ARMRegAsString(Src), DestSize, ARMRegAsString(Dest)); + ERROR_LOG(JIT, "SrcSize: %i (%s) DestDize: %i (%s)", SrcSize, ARMRegAsString(Src), DestSize, ARMRegAsString(Dest)); } Dest = SubBase(Dest); @@ -1798,7 +1794,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) // Double and quad if (Quad) { - _assert_msg_(JIT, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD."); + _assert_msg_(cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD."); // Gets encoded as a Double register Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (2 << 20) | ((Src & 0xF) << 16) \ | ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (1 << 6) \ @@ -1859,9 +1855,9 @@ void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags) void ARMXEmitter::VABA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | EncodeVn(Vn) \ @@ -1870,11 +1866,11 @@ void ARMXEmitter::VABA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \ | (encodedSize(Size) << 20) | EncodeVd(Vd) | (0x50 << 4) | EncodeVm(Vm)); @@ -1882,8 +1878,8 @@ void ARMXEmitter::VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VABD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -1895,11 +1891,11 @@ void ARMXEmitter::VABD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \ | (encodedSize(Size) << 20) | EncodeVd(Vd) | (0x70 << 4) | EncodeVm(Vm)); @@ -1907,8 +1903,8 @@ void ARMXEmitter::VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VABS(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xB1 << 16) | (encodedSize(Size) << 18) | EncodeVd(Vd) \ @@ -1918,8 +1914,8 @@ void ARMXEmitter::VABS(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VACGE(ARMReg Vd, ARMReg Vn, ARMReg Vm) { // Only Float - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) \ @@ -1929,8 +1925,8 @@ void ARMXEmitter::VACGE(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VACGT(ARMReg Vd, ARMReg Vn, ARMReg Vm) { // Only Float - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) \ @@ -1949,8 +1945,8 @@ void ARMXEmitter::VACLT(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -1963,11 +1959,11 @@ void ARMXEmitter::VADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \ | EncodeVd(Vd) | (0x80 << 4) | EncodeVm(Vm)); @@ -1975,84 +1971,84 @@ void ARMXEmitter::VADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VADDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \ | EncodeVd(Vd) | EncodeVm(Vm)); } void ARMXEmitter::VADDW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \ | EncodeVd(Vd) | (1 << 8) | EncodeVm(Vm)); } void ARMXEmitter::VAND(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__); - // _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__); + // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VBIC(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - // _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF2 << 24) | (1 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s: %i", __FUNCTION__, Vd); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s: %i", __FUNCTION__, Vd); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VBIF(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - // _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (3 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VBIT(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - // _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (2 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VBSL(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - // _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (1 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -2064,8 +2060,8 @@ void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2074,8 +2070,8 @@ void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -2086,8 +2082,8 @@ void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2095,8 +2091,8 @@ void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -2107,8 +2103,8 @@ void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2120,8 +2116,8 @@ void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2129,9 +2125,9 @@ void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VCLS(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \ @@ -2143,8 +2139,8 @@ void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2152,8 +2148,8 @@ void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VCLZ(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \ @@ -2161,9 +2157,9 @@ void ARMXEmitter::VCLZ(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VCNT(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, Size & I_8, "Can only use I_8 with %s", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Size & I_8, "Can only use I_8 with %s", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \ @@ -2171,9 +2167,9 @@ void ARMXEmitter::VCNT(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Vm, u8 index) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; u32 imm4 = 0; @@ -2188,9 +2184,9 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Vm, u8 index) } void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Rt) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Rt < S0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Rt < S0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Vd = SubBase(Vd); @@ -2207,8 +2203,8 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Rt) } void ARMXEmitter::VEXT(ARMReg Vd, ARMReg Vn, ARMReg Vm, u8 index) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF2 << 24) | (0xB << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (index & 0xF) \ @@ -2216,29 +2212,29 @@ void ARMXEmitter::VEXT(ARMReg Vd, ARMReg Vn, ARMReg Vm, u8 index) } void ARMXEmitter::VFMA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Size == F_32, "Passed invalid size to FP-only NEON instruction"); - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Size == F_32, "Passed invalid size to FP-only NEON instruction"); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xC1 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VFMS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Size == F_32, "Passed invalid size to FP-only NEON instruction"); - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Size == F_32, "Passed invalid size to FP-only NEON instruction"); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF2 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xC1 << 4) | (register_quad << 6) | EncodeVm(Vm)); } void ARMXEmitter::VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2247,9 +2243,9 @@ void ARMXEmitter::VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2258,8 +2254,8 @@ void ARMXEmitter::VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2271,8 +2267,8 @@ void ARMXEmitter::VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2284,8 +2280,8 @@ void ARMXEmitter::VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2296,8 +2292,8 @@ void ARMXEmitter::VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VMLS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2308,30 +2304,30 @@ void ARMXEmitter::VMLS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \ | EncodeVn(Vn) | EncodeVd(Vd) | (0x80 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float.", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \ | EncodeVn(Vn) | EncodeVd(Vd) | (0xA0 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2343,17 +2339,17 @@ void ARMXEmitter::VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0xC0 << 4) | ((Size & I_POLYNOMIAL) ? 1 << 9 : 0) | EncodeVm(Vm)); } void ARMXEmitter::VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2361,15 +2357,15 @@ void ARMXEmitter::VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) if (Size & F_32) Write32((0xF2 << 24) | (register_quad << 24) | (1 << 23) | (2 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x14 << 4) | EncodeVm(Vm)); else - _dbg_assert_msg_(JIT, false, "VMLA_scalar only supports float atm"); + _dbg_assert_msg_(false, "VMLA_scalar only supports float atm"); //else // Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x90 << 4) | (1 << 6) | EncodeVm(Vm)); // Unsigned support missing } void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2378,7 +2374,7 @@ void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) if (Size & F_32) // Q flag Write32((0xF2 << 24) | (register_quad << 24) | (1 << 23) | (2 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x94 << 4) | VmEnc); else - _dbg_assert_msg_(JIT, false, "VMUL_scalar only supports float atm"); + _dbg_assert_msg_(false, "VMUL_scalar only supports float atm"); // Write32((0xF2 << 24) | ((Size & I_POLYNOMIAL) ? (1 << 24) : 0) | (1 << 23) | (encodedSize(Size) << 20) | // EncodeVn(Vn) | EncodeVd(Vd) | (0x84 << 4) | (register_quad << 6) | EncodeVm(Vm)); @@ -2387,8 +2383,8 @@ void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMVN(ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2398,8 +2394,8 @@ void ARMXEmitter::VMVN(ARMReg Vd, ARMReg Vm) void ARMXEmitter::VNEG(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2408,8 +2404,8 @@ void ARMXEmitter::VNEG(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2417,9 +2413,9 @@ void ARMXEmitter::VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2427,9 +2423,9 @@ void ARMXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VPADAL(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2438,8 +2434,8 @@ void ARMXEmitter::VPADAL(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); if (Size & F_32) Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD0 << 4) | EncodeVm(Vm)); @@ -2449,9 +2445,9 @@ void ARMXEmitter::VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VPADDL(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2460,8 +2456,8 @@ void ARMXEmitter::VPADDL(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); if (Size & F_32) Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm)); @@ -2471,8 +2467,8 @@ void ARMXEmitter::VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); if (Size & F_32) Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm)); @@ -2482,9 +2478,9 @@ void ARMXEmitter::VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VQABS(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2493,9 +2489,9 @@ void ARMXEmitter::VQABS(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2504,45 +2500,45 @@ void ARMXEmitter::VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VQDMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x90 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VQDMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0xB0 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VQDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0xB0 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VQDMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0xD0 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VQNEG(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2551,18 +2547,18 @@ void ARMXEmitter::VQNEG(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VQRDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF3 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0xB0 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2571,9 +2567,9 @@ void ARMXEmitter::VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2582,9 +2578,9 @@ void ARMXEmitter::VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2593,17 +2589,17 @@ void ARMXEmitter::VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VRADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x40 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VRECPE(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2612,8 +2608,8 @@ void ARMXEmitter::VRECPE(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2621,9 +2617,9 @@ void ARMXEmitter::VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2632,9 +2628,9 @@ void ARMXEmitter::VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2643,8 +2639,8 @@ void ARMXEmitter::VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Vd = SubBase(Vd); @@ -2656,8 +2652,8 @@ void ARMXEmitter::VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2666,18 +2662,18 @@ void ARMXEmitter::VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VRSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x60 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VSHL(u32 Size, ARMReg Vd, ARMReg Vm, ARMReg Vn) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2694,7 +2690,7 @@ static int EncodeSizeShift(u32 Size, int amount, bool inverse, bool halve) { case I_64: sz = 64; break; } if (inverse && halve) { - _dbg_assert_msg_(JIT, amount <= sz / 2, "Amount %d too large for narrowing shift (max %d)", amount, sz/2); + _dbg_assert_msg_(amount <= sz / 2, "Amount %d too large for narrowing shift (max %d)", amount, sz/2); return (sz / 2) + (sz / 2) - amount; } else if (inverse) { return sz + (sz - amount); @@ -2704,9 +2700,9 @@ static int EncodeSizeShift(u32 Size, int amount, bool inverse, bool halve) { } void ARMXEmitter::EncodeShiftByImm(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount, u8 opcode, bool register_quad, bool inverse, bool halve) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, !(Size & F_32), "%s doesn't support float", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); int imm7 = EncodeSizeShift(Size, shiftAmount, inverse, halve); int L = (imm7 >> 6) & 1; int U = (Size & I_UNSIGNED) ? 1 : 0; @@ -2727,7 +2723,7 @@ void ARMXEmitter::VSHLL(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) { case I_16: sz = 1; break; case I_32: sz = 2; break; case I_64: - _dbg_assert_msg_(JIT, false, "Cannot VSHLL 64-bit elements"); + _dbg_assert_msg_(false, "Cannot VSHLL 64-bit elements"); } int imm6 = 0x32 | (sz << 2); u32 value = (0xF3 << 24) | (1 << 23) | (imm6 << 16) | EncodeVd(Vd) | (0x3 << 8) | EncodeVm(Vm); @@ -2748,8 +2744,8 @@ void ARMXEmitter::VSHRN(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) { void ARMXEmitter::VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2762,32 +2758,32 @@ void ARMXEmitter::VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x60 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VSUBL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x20 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VSUBW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x30 << 4) | EncodeVm(Vm)); } void ARMXEmitter::VSWP(ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2796,8 +2792,8 @@ void ARMXEmitter::VSWP(ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VTRN(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2806,8 +2802,8 @@ void ARMXEmitter::VTRN(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2816,8 +2812,8 @@ void ARMXEmitter::VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) } void ARMXEmitter::VUZP(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2826,8 +2822,8 @@ void ARMXEmitter::VUZP(u32 Size, ARMReg Vd, ARMReg Vm) } void ARMXEmitter::VZIP(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2837,10 +2833,10 @@ void ARMXEmitter::VZIP(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VMOVL(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vm >= D0 && Vm <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, (Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VMOVL"); + _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vm >= D0 && Vm <= D31, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VMOVL"); bool unsign = (Size & I_UNSIGNED) != 0; int imm3 = 0; @@ -2854,10 +2850,10 @@ void ARMXEmitter::VMOVL(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VMOVN(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, (Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); + _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); // For consistency with assembler syntax and VMOVL - encode one size down. int halfSize = encodedSize(Size) - 1; @@ -2867,11 +2863,11 @@ void ARMXEmitter::VMOVN(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VQMOVN(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, (Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in %s NEON", __FUNCTION__); - _dbg_assert_msg_(JIT, (Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); + _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in %s NEON", __FUNCTION__); + _dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); int halfSize = encodedSize(Size) - 1; int op = (1 << 7) | (Size & I_UNSIGNED ? 1 << 6 : 0); @@ -2881,10 +2877,10 @@ void ARMXEmitter::VQMOVN(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VQMOVUN(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); - _dbg_assert_msg_(JIT, (Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); + _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); int halfSize = encodedSize(Size) - 1; int op = (1 << 6); @@ -2894,7 +2890,7 @@ void ARMXEmitter::VQMOVUN(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VCVT(u32 Size, ARMReg Vd, ARMReg Vm) { - _dbg_assert_msg_(JIT, (Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VCVT NEON"); + _dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VCVT NEON"); bool register_quad = Vd >= Q0; bool toInteger = (Size & I_32) != 0; @@ -2907,18 +2903,18 @@ void ARMXEmitter::VCVT(u32 Size, ARMReg Vd, ARMReg Vm) static int RegCountToType(int nRegs, NEONAlignment align) { switch (nRegs) { case 1: - _dbg_assert_msg_(JIT, !((int)align & 1), "align & 1 must be == 0"); + _dbg_assert_msg_(!((int)align & 1), "align & 1 must be == 0"); return 7; case 2: - _dbg_assert_msg_(JIT, !((int)align == 3), "align must be != 3"); + _dbg_assert_msg_(!((int)align == 3), "align must be != 3"); return 10; case 3: - _dbg_assert_msg_(JIT, !((int)align & 1), "align & 1 must be == 0"); + _dbg_assert_msg_(!((int)align & 1), "align & 1 must be == 0"); return 6; case 4: return 2; default: - _dbg_assert_msg_(JIT, false, "Invalid number of registers passed to vector load/store"); + _dbg_assert_msg_(false, "Invalid number of registers passed to vector load/store"); return 0; } } @@ -2935,12 +2931,12 @@ void ARMXEmitter::WriteVLDST1(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int reg } void ARMXEmitter::VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1(true, Size, Vd, Rn, regCount, align, Rm); } void ARMXEmitter::VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1(false, Size, Vd, Rn, regCount, align, Rm); } @@ -2970,12 +2966,12 @@ void ARMXEmitter::WriteVLDST1_lane(bool load, u32 Size, ARMReg Vd, ARMReg Rn, in } void ARMXEmitter::VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1_lane(true, Size, Vd, Rn, lane, aligned, Rm); } void ARMXEmitter::VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1_lane(false, Size, Vd, Rn, lane, aligned, Rm); } @@ -3012,7 +3008,7 @@ void ARMXEmitter::WriteVimm(ARMReg Vd, int cmode, u8 imm, int op) { } void ARMXEmitter::VMOV_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3045,11 +3041,11 @@ void ARMXEmitter::VMOV_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { return; error: - _dbg_assert_msg_(JIT, false, "Bad Size or type specified in %s: Size %i Type %i", __FUNCTION__, (int)Size, type); + _dbg_assert_msg_(false, "Bad Size or type specified in %s: Size %i Type %i", __FUNCTION__, (int)Size, type); } void ARMXEmitter::VMOV_immf(ARMReg Vd, float value) { // This only works with a select few values. I've hardcoded 1.0f. - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); u8 bits = 0; if (value == 0.0f) { @@ -3065,13 +3061,13 @@ void ARMXEmitter::VMOV_immf(ARMReg Vd, float value) { // This only works with a } else if (value == -1.0f) { bits = 0xF0; } else { - _dbg_assert_msg_(JIT, false, "%s: Invalid floating point immediate", __FUNCTION__); + _dbg_assert_msg_(false, "%s: Invalid floating point immediate", __FUNCTION__); } WriteVimm(Vd, VIMMf000f000, bits, 0); } void ARMXEmitter::VORR_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3093,11 +3089,11 @@ void ARMXEmitter::VORR_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { } return; error: - _dbg_assert_msg_(JIT, false, "Bad Size or type specified in VORR_imm"); + _dbg_assert_msg_(false, "Bad Size or type specified in VORR_imm"); } void ARMXEmitter::VBIC_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3119,12 +3115,12 @@ void ARMXEmitter::VBIC_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { } return; error: - _dbg_assert_msg_(JIT, false, "Bad Size or type specified in VBIC_imm"); + _dbg_assert_msg_(false, "Bad Size or type specified in VBIC_imm"); } void ARMXEmitter::VMVN_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); + _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3146,7 +3142,7 @@ void ARMXEmitter::VMVN_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { } return; error: - _dbg_assert_msg_(JIT, false, "Bad Size or type specified in VMVN_imm"); + _dbg_assert_msg_(false, "Bad Size or type specified in VMVN_imm"); } @@ -3180,9 +3176,9 @@ void ARMXEmitter::VREV16(u32 Size, ARMReg Vd, ARMReg Vm) // Dest is a Q register, Src is a D register. void ARMXEmitter::VCVTF32F16(ARMReg Dest, ARMReg Src) { - _assert_msg_(JIT, cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4"); + _assert_msg_(cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4"); if (Dest < Q0 || Dest > Q15 || Src < D0 || Src > D15) { - _assert_msg_(JIT, cpu_info.bNEON, "Bad inputs to VCVTF32F16"); + _assert_msg_(cpu_info.bNEON, "Bad inputs to VCVTF32F16"); // Invalid! } @@ -3196,9 +3192,9 @@ void ARMXEmitter::VCVTF32F16(ARMReg Dest, ARMReg Src) { // UNTESTED // Dest is a D register, Src is a Q register. void ARMXEmitter::VCVTF16F32(ARMReg Dest, ARMReg Src) { - _assert_msg_(JIT, cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4"); + _assert_msg_(cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4"); if (Dest < D0 || Dest > D15 || Src < Q0 || Src > Q15) { - _assert_msg_(JIT, cpu_info.bNEON, "Bad inputs to VCVTF32F16"); + _assert_msg_(cpu_info.bNEON, "Bad inputs to VCVTF32F16"); // Invalid! } Dest = SubBase(Dest); diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index b8116129ec..e3857de088 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -20,10 +20,10 @@ #include #include -#include "Common.h" -#include "ArmCommon.h" -#include "CodeBlock.h" -#include "MsgHandler.h" +#include "Common/Common.h" +#include "Common/Log.h" +#include "Common/ArmCommon.h" +#include "Common/CodeBlock.h" // VCVT flags #define TO_FLOAT 0 @@ -145,7 +145,7 @@ public: Operand2(ARMReg base, ShiftType type, ARMReg shift) // RSR { Type = TYPE_RSR; - _assert_msg_(JIT, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount"); + _assert_msg_(type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount"); IndexOrShift = shift; Shift = type; Value = base; @@ -157,29 +157,29 @@ public: switch (type) { case ST_LSL: - _assert_msg_(JIT, shift < 32, "Invalid Operand2: LSL %u", shift); + _assert_msg_(shift < 32, "Invalid Operand2: LSL %u", shift); break; case ST_LSR: - _assert_msg_(JIT, shift <= 32, "Invalid Operand2: LSR %u", shift); + _assert_msg_(shift <= 32, "Invalid Operand2: LSR %u", shift); if (!shift) type = ST_LSL; if (shift == 32) shift = 0; break; case ST_ASR: - _assert_msg_(JIT, shift < 32, "Invalid Operand2: ASR %u", shift); + _assert_msg_(shift < 32, "Invalid Operand2: ASR %u", shift); if (!shift) type = ST_LSL; if (shift == 32) shift = 0; break; case ST_ROR: - _assert_msg_(JIT, shift < 32, "Invalid Operand2: ROR %u", shift); + _assert_msg_(shift < 32, "Invalid Operand2: ROR %u", shift); if (!shift) type = ST_LSL; break; case ST_RRX: - _assert_msg_(JIT, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount"); + _assert_msg_(shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount"); type = ST_ROR; break; } @@ -201,45 +201,45 @@ public: case TYPE_RSR: return RSR(); default: - _assert_msg_(JIT, false, "GetData with Invalid Type"); + _assert_msg_(false, "GetData with Invalid Type"); return 0; } } u32 IMMSR() // IMM shifted register { - _assert_msg_(JIT, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register"); + _assert_msg_(Type == TYPE_IMMSREG, "IMMSR must be imm shifted register"); return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value); } u32 RSR() // Register shifted register { - _assert_msg_(JIT, Type == TYPE_RSR, "RSR must be RSR Of Course"); + _assert_msg_(Type == TYPE_RSR, "RSR must be RSR Of Course"); return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value; } u32 Rm() const { - _assert_msg_(JIT, Type == TYPE_REG, "Rm must be with Reg"); + _assert_msg_(Type == TYPE_REG, "Rm must be with Reg"); return Value; } u32 Imm5() const { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm5 not IMM value"); + _assert_msg_((Type == TYPE_IMM), "Imm5 not IMM value"); return ((Value & 0x0000001F) << 7); } u32 Imm8() const { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value"); + _assert_msg_((Type == TYPE_IMM), "Imm8Rot not IMM value"); return Value & 0xFF; } u32 Imm8Rot() const // IMM8 with Rotation { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value"); - _assert_msg_(JIT, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation); + _assert_msg_((Type == TYPE_IMM), "Imm8Rot not IMM value"); + _assert_msg_((Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation); return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF); } u32 Imm12() const { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm12 not IMM"); + _assert_msg_((Type == TYPE_IMM), "Imm12 not IMM"); return (Value & 0x00000FFF); } @@ -250,12 +250,12 @@ public: // expand a 8bit IMM to a 32bit value and gives you some rotation as // well. // Each rotation rotates to the right by 2 bits - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm12Mod not IMM"); + _assert_msg_((Type == TYPE_IMM), "Imm12Mod not IMM"); return ((Rotation & 0xF) << 8) | (Value & 0xFF); } u32 Imm16() const { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM"); + _assert_msg_((Type == TYPE_IMM), "Imm16 not IMM"); return ( (Value & 0xF000) << 4) | (Value & 0x0FFF); } u32 Imm16Low() const @@ -264,23 +264,23 @@ public: } u32 Imm16High() const // Returns high 16bits { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM"); + _assert_msg_((Type == TYPE_IMM), "Imm16 not IMM"); return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF); } u32 Imm24() const { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM"); + _assert_msg_((Type == TYPE_IMM), "Imm16 not IMM"); return (Value & 0x0FFFFFFF); } // NEON and ASIMD specific u32 Imm8ASIMD() const { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8ASIMD not IMM"); + _assert_msg_((Type == TYPE_IMM), "Imm8ASIMD not IMM"); return ((Value & 0x80) << 17) | ((Value & 0x70) << 12) | (Value & 0xF); } u32 Imm8VFP() const { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8VFP not IMM"); + _assert_msg_((Type == TYPE_IMM), "Imm8VFP not IMM"); return ((Value & 0xF0) << 12) | (Value & 0xF); } }; @@ -733,7 +733,7 @@ public: } void VMOV_neon(u32 Size, ARMReg Vd, u32 imm); void VMOV_neon(u32 Size, ARMReg Vd, float imm) { - _dbg_assert_msg_(JIT, Size == F_32, "Expecting F_32 immediate for VMOV_neon float arg."); + _dbg_assert_msg_(Size == F_32, "Expecting F_32 immediate for VMOV_neon float arg."); union { float f; u32 u; diff --git a/Common/BitSet.h b/Common/BitSet.h index 2fbc80011b..caf7951509 100644 --- a/Common/BitSet.h +++ b/Common/BitSet.h @@ -2,6 +2,8 @@ #pragma once +#include +#include // for byte swapping #include #include "CommonTypes.h" @@ -39,3 +41,28 @@ inline int CountSetBits(u64 val) { return __builtin_popcountll(val); } inline int LeastSignificantSetBit(u32 val) { return __builtin_ctz(val); } inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val); } #endif + +// Byteswapping +// Just in case this has been defined by platform +#undef swap16 +#undef swap32 +#undef swap64 + +#ifdef _WIN32 +inline uint16_t swap16(uint16_t _data) { return _byteswap_ushort(_data); } +inline uint32_t swap32(uint32_t _data) { return _byteswap_ulong(_data); } +inline uint64_t swap64(uint64_t _data) { return _byteswap_uint64(_data); } +#elif defined(__GNUC__) +inline uint16_t swap16(uint16_t _data) { return __builtin_bswap16(_data); } +inline uint32_t swap32(uint32_t _data) { return __builtin_bswap32(_data); } +inline uint64_t swap64(uint64_t _data) { return __builtin_bswap64(_data); } +#else +// Slow generic implementation. Hopefully this never hits +inline uint16_t swap16(uint16_t data) { return (data >> 8) | (data << 8); } +inline uint32_t swap32(uint32_t data) { return (swap16(data) << 16) | swap16(data >> 16); } +inline uint64_t swap64(uint64_t data) { return ((uint64_t)swap32(data) << 32) | swap32(data >> 32); } +#endif + +inline uint16_t swap16(const uint8_t* _pData) { return swap16(*(const uint16_t*)_pData); } +inline uint32_t swap32(const uint8_t* _pData) { return swap32(*(const uint32_t*)_pData); } +inline uint64_t swap64(const uint8_t* _pData) { return swap64(*(const uint64_t*)_pData); } diff --git a/ext/native/base/buffer.cpp b/Common/Buffer.cpp similarity index 75% rename from ext/native/base/buffer.cpp rename to Common/Buffer.cpp index 68cc412dd3..423c2cfb3c 100644 --- a/ext/native/base/buffer.cpp +++ b/Common/Buffer.cpp @@ -1,4 +1,3 @@ -#include "base/buffer.h" #include #include @@ -18,14 +17,15 @@ #define MSG_NOSIGNAL 0x00 #endif -#include "base/logging.h" -#include "base/timeutil.h" -#include "file/fd_util.h" +#include "Common/File/FileDescriptor.h" +#include "Common/TimeUtil.h" +#include "Common/Buffer.h" +#include "Common/Log.h" Buffer::Buffer() { } Buffer::~Buffer() { } -char *Buffer::Append(ssize_t length) { +char *Buffer::Append(size_t length) { if (length > 0) { size_t old_size = data_.size(); data_.resize(old_size + length); @@ -63,7 +63,7 @@ void Buffer::AppendValue(int value) { void Buffer::Take(size_t length, std::string *dest) { if (length > data_.size()) { - ELOG("Truncating length in Buffer::Take()"); + ERROR_LOG(IO, "Truncating length in Buffer::Take()"); length = data_.size(); } dest->resize(length); @@ -90,7 +90,7 @@ int Buffer::TakeLineCRLF(std::string *dest) { void Buffer::Skip(size_t length) { if (length > data_.size()) { - ELOG("Truncating length in Buffer::Skip()"); + ERROR_LOG(IO, "Truncating length in Buffer::Skip()"); length = data_.size(); } data_.erase(data_.begin(), data_.begin() + length); @@ -119,13 +119,13 @@ void Buffer::Printf(const char *fmt, ...) { char buffer[2048]; va_list vl; va_start(vl, fmt); - ssize_t retval = vsnprintf(buffer, sizeof(buffer), fmt, vl); - if (retval >= (ssize_t)sizeof(buffer)) { + size_t retval = vsnprintf(buffer, sizeof(buffer), fmt, vl); + if ((int)retval >= (int)sizeof(buffer)) { // Output was truncated. TODO: Do something. - ELOG("Buffer::Printf truncated output"); + ERROR_LOG(IO, "Buffer::Printf truncated output"); } if (retval < 0) { - ELOG("Buffer::Printf failed"); + ERROR_LOG(IO, "Buffer::Printf failed"); } va_end(vl); char *ptr = Append(retval); @@ -134,7 +134,7 @@ void Buffer::Printf(const char *fmt, ...) { bool Buffer::Flush(int fd) { // Look into using send() directly. - bool success = (ssize_t)data_.size() == fd_util::WriteLine(fd, &data_[0], data_.size()); + bool success = data_.size() == fd_util::WriteLine(fd, &data_[0], data_.size()); if (success) { data_.resize(0); } @@ -152,15 +152,26 @@ bool Buffer::FlushToFile(const char *filename) { return true; } -bool Buffer::FlushSocket(uintptr_t sock, double timeout) { +bool Buffer::FlushSocket(uintptr_t sock, double timeout, bool *cancelled) { + static constexpr float CANCEL_INTERVAL = 0.25f; for (size_t pos = 0, end = data_.size(); pos < end; ) { - if (timeout >= 0.0 && !fd_util::WaitUntilReady(sock, timeout, true)) { - ELOG("FlushSocket timed out"); - return false; + bool ready = false; + double leftTimeout = timeout; + while (!ready && (leftTimeout >= 0 || cancelled)) { + if (cancelled && *cancelled) + return false; + ready = fd_util::WaitUntilReady(sock, CANCEL_INTERVAL, true); + if (!ready && leftTimeout >= 0.0) { + leftTimeout -= CANCEL_INTERVAL; + if (leftTimeout < 0) { + ERROR_LOG(IO, "FlushSocket timed out"); + return false; + } + } } int sent = send(sock, &data_[pos], (int)(end - pos), MSG_NOSIGNAL); if (sent < 0) { - ELOG("FlushSocket failed"); + ERROR_LOG(IO, "FlushSocket failed"); return false; } pos += sent; @@ -189,7 +200,7 @@ bool Buffer::ReadAll(int fd, int hintSize) { if (retval == 0) { break; } else if (retval < 0) { - ELOG("Error reading from buffer: %i", retval); + ERROR_LOG(IO, "Error reading from buffer: %i", retval); return false; } char *p = Append((size_t)retval); @@ -199,6 +210,7 @@ bool Buffer::ReadAll(int fd, int hintSize) { } bool Buffer::ReadAllWithProgress(int fd, int knownSize, float *progress, bool *cancelled) { + static constexpr float CANCEL_INTERVAL = 0.25f; std::vector buf; if (knownSize >= 65536 * 16) { buf.resize(65536); @@ -210,19 +222,24 @@ bool Buffer::ReadAllWithProgress(int fd, int knownSize, float *progress, bool *c int total = 0; while (true) { - if (cancelled && *cancelled) - return false; + bool ready = false; + while (!ready && cancelled) { + if (*cancelled) + return false; + ready = fd_util::WaitUntilReady(fd, CANCEL_INTERVAL, false); + } int retval = recv(fd, &buf[0], (int)buf.size(), 0); if (retval == 0) { return true; } else if (retval < 0) { - ELOG("Error reading from buffer: %i", retval); + ERROR_LOG(IO, "Error reading from buffer: %i", retval); return false; } char *p = Append((size_t)retval); memcpy(p, &buf[0], retval); total += retval; - *progress = (float)total / (float)knownSize; + if (progress) + *progress = (float)total / (float)knownSize; } return true; } diff --git a/ext/native/base/buffer.h b/Common/Buffer.h similarity index 88% rename from ext/native/base/buffer.h rename to Common/Buffer.h index b34901fb17..3fad61d549 100644 --- a/ext/native/base/buffer.h +++ b/Common/Buffer.h @@ -1,11 +1,9 @@ -#ifndef _IO_BUFFER_H -#define _IO_BUFFER_H +#pragma once #include #include -#include "base/basictypes.h" -#include "base/logging.h" +#include "Common/Common.h" // Acts as a queue. Intended to be as fast as possible for most uses. // Does not do synchronization, must use external mutexes. @@ -16,8 +14,7 @@ class Buffer { // Write max [length] bytes to the returned pointer. // Any other operation on this Buffer invalidates the pointer. - char *Append(ssize_t length); - char *Append(size_t length) { return Append((ssize_t)length); } + char *Append(size_t length); // These work pretty much like you'd expect. void Append(const char *str); // str null-terminated. The null is not copied. @@ -64,7 +61,7 @@ class Buffer { // written. bool Flush(int fd); bool FlushToFile(const char *filename); - bool FlushSocket(uintptr_t sock, double timeout = -1.0); // Windows portability + bool FlushSocket(uintptr_t sock, double timeout = -1.0, bool *cancelled = nullptr); // Windows portability bool ReadAll(int fd, int hintSize = 0); bool ReadAllWithProgress(int fd, int knownSize, float *progress, bool *cancelled); @@ -84,5 +81,3 @@ class Buffer { DISALLOW_COPY_AND_ASSIGN(Buffer); }; - -#endif // _IO_BUFFER_H diff --git a/Common/CPUDetect.cpp b/Common/CPUDetect.cpp index ac5cd2e640..9910f651cc 100644 --- a/Common/CPUDetect.cpp +++ b/Common/CPUDetect.cpp @@ -28,14 +28,11 @@ #include #include -#include "base/logging.h" -#include "base/basictypes.h" -#include "file/file_util.h" -#include "Common.h" -#include "CPUDetect.h" -#include "FileUtil.h" -#include "StringUtils.h" +#include "Common/Common.h" +#include "Common/CPUDetect.h" +#include "Common/File/FileUtil.h" +#include "Common/StringUtils.h" #if defined(_WIN32) && !defined(__MINGW32__) #define WIN32_LEAN_AND_MEAN diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h deleted file mode 100644 index 42d5b38675..0000000000 --- a/Common/ChunkFile.h +++ /dev/null @@ -1,707 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "ppsspp_config.h" - -// Extremely simple serialization framework. -// Currently mis-named, a native ChunkFile is something different (a RIFF file) - -// (mis)-features: -// + Super fast -// + Very simple -// + Same code is used for serialization and deserializaition (in most cases) -// + Sections can be versioned for backwards/forwards compatibility -// - Serialization code for anything complex has to be manually written. - -#include -#include -#include -#include -#include -#include -#include - -#include "Common.h" -#include "Swap.h" -#include "FileUtil.h" - -template -struct LinkedListItem : public T -{ - LinkedListItem *next; -}; - -class PointerWrap; - -class PointerWrapSection -{ -public: - PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { - } - ~PointerWrapSection(); - - bool operator == (const int &v) const { return ver_ == v; } - bool operator != (const int &v) const { return ver_ != v; } - bool operator <= (const int &v) const { return ver_ <= v; } - bool operator >= (const int &v) const { return ver_ >= v; } - bool operator < (const int &v) const { return ver_ < v; } - bool operator > (const int &v) const { return ver_ > v; } - - operator bool() const { - return ver_ > 0; - } - -private: - PointerWrap &p_; - int ver_; - const char *title_; -}; - -// Wrapper class -class PointerWrap -{ - // This makes it a compile error if you forget to define DoState() on non-POD. - // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... -#ifdef _MSC_VER - template::value, bool isPointer = std::is_pointer::value> -#else - template::value> -#endif - struct DoHelper - { - static void DoArray(PointerWrap *p, T *x, int count) - { - for (int i = 0; i < count; ++i) - p->Do(x[i]); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoClass(x); - } - }; - - template - struct DoHelper - { - static void DoArray(PointerWrap *p, T *x, int count) - { - p->DoVoid((void *)x, sizeof(T) * count); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoVoid((void *)&x, sizeof(x)); - } - }; - -public: - enum Mode { - MODE_READ = 1, // load - MODE_WRITE, // save - MODE_MEASURE, // calculate size - MODE_VERIFY, // compare - }; - - enum Error { - ERROR_NONE = 0, - ERROR_WARNING = 1, - ERROR_FAILURE = 2, - }; - - u8 **ptr; - Mode mode; - Error error; - -public: - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} - - PointerWrapSection Section(const char *title, int ver); - - // The returned object can be compared against the version that was loaded. - // This can be used to support versions as old as minVer. - // Version = 0 means the section was not found. - PointerWrapSection Section(const char *title, int minVer, int ver); - - void SetMode(Mode mode_) {mode = mode_;} - Mode GetMode() const {return mode;} - u8 **GetPPtr() {return ptr;} - void SetError(Error error_); - - // Same as DoVoid, except doesn't advance pointer if it doesn't match on read. - bool ExpectVoid(void *data, int size); - void DoVoid(void *data, int size); - - template - void Do(std::map &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMap(x, dv); - } - - template - void Do(std::map &x) - { - T dv = T(); - DoMap(x, dv); - } - - template - void Do(std::unordered_map &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMap(x, dv); - } - - template - void Do(std::unordered_map &x) - { - T dv = T(); - DoMap(x, dv); - } - - template - void DoMap(M &x, typename M::mapped_type &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - typename M::key_type first = typename M::key_type(); - Do(first); - typename M::mapped_type second = default_val; - Do(second); - x[first] = second; - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename M::iterator itr = x.begin(); - while (number > 0) - { - typename M::key_type first = itr->first; - Do(first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - template - void Do(std::multimap &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMultimap(x, dv); - } - - template - void Do(std::multimap &x) - { - T dv = T(); - DoMultimap(x, dv); - } - - template - void Do(std::unordered_multimap &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMultimap(x, dv); - } - - template - void Do(std::unordered_multimap &x) - { - T dv = T(); - DoMultimap(x, dv); - } - - template - void DoMultimap(M &x, typename M::mapped_type &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - typename M::key_type first = typename M::key_type(); - Do(first); - typename M::mapped_type second = default_val; - Do(second); - x.insert(std::make_pair(first, second)); - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename M::iterator itr = x.begin(); - while (number > 0) - { - Do(itr->first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - // Store vectors. - template - void Do(std::vector &x) - { - T *dv = NULL; - DoVector(x, dv); - } - - template - void Do(std::vector &x) - { - T dv = T(); - DoVector(x, dv); - } - - template - void Do(std::vector &x, T &default_val) - { - DoVector(x, default_val); - } - - template - void DoVector(std::vector &x, T &default_val) - { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size, default_val); - if (vec_size > 0) - DoArray(&x[0], vec_size); - } - - // Store deques. - template - void Do(std::deque &x) - { - T *dv = NULL; - DoDeque(x, dv); - } - - template - void Do(std::deque &x) - { - T dv = T(); - DoDeque(x, dv); - } - - template - void DoDeque(std::deque &x, T &default_val) - { - u32 deq_size = (u32)x.size(); - Do(deq_size); - x.resize(deq_size, default_val); - u32 i; - for(i = 0; i < deq_size; i++) - Do(x[i]); - } - - // Store STL lists. - template - void Do(std::list &x) - { - T *dv = NULL; - Do(x, dv); - } - - template - void Do(std::list &x) - { - T dv = T(); - DoList(x, dv); - } - - template - void Do(std::list &x, T &default_val) - { - DoList(x, default_val); - } - - template - void DoList(std::list &x, T &default_val) - { - u32 list_size = (u32)x.size(); - Do(list_size); - x.resize(list_size, default_val); - - typename std::list::iterator itr, end; - for (itr = x.begin(), end = x.end(); itr != end; ++itr) - Do(*itr); - } - - // Store STL sets. - template - void Do(std::set &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (*it != NULL) - delete *it; - } - } - DoSet(x); - } - - template - void Do(std::set &x) - { - DoSet(x); - } - - template - void DoSet(std::set &x) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - - switch (mode) - { - case MODE_READ: - { - x.clear(); - while (number-- > 0) - { - T it = T(); - Do(it); - x.insert(it); - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::set::iterator itr = x.begin(); - while (number-- > 0) - Do(*itr++); - } - break; - - default: - ERROR_LOG(SAVESTATE, "Savestate error: invalid mode %d.", mode); - } - } - - // Store strings. - void Do(std::string &x); - void Do(std::wstring &x); // DEPRECATED, do not save wstrings - void Do(std::u16string &x); - - void Do(tm &t); - - template - void Do(swap_struct_t &x) { - T v = x.swap(); - Do(v); - x = v; - } - - template - void DoClass(T &x) { - x.DoState(*this); - } - - template - void DoClass(T *&x) { - if (mode == MODE_READ) - { - if (x != NULL) - delete x; - x = new T(); - } - x->DoState(*this); - } - - template - void DoArray(T *x, int count) { - DoHelper::DoArray(this, x, count); - } - - template - void Do(T &x) { - DoHelper::Do(this, x); - } - - template - void DoPointer(T* &x, T*const base) { - // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range - s32 offset = x - base; - Do(offset); - if (mode == MODE_READ) - x = base + offset; - } - - template* (*TNew)(), void (*TFree)(LinkedListItem*), void (*TDo)(PointerWrap&, T*)> - void DoLinkedList(LinkedListItem*& list_start, LinkedListItem** list_end=0) - { - LinkedListItem* list_cur = list_start; - LinkedListItem* prev = 0; - - while (true) - { - u8 shouldExist = (list_cur ? 1 : 0); - Do(shouldExist); - if (shouldExist == 1) - { - LinkedListItem* cur = list_cur ? list_cur : TNew(); - TDo(*this, (T*)cur); - if (!list_cur) - { - if (mode == MODE_READ) - { - cur->next = 0; - list_cur = cur; - if (prev) - prev->next = cur; - else - list_start = cur; - } - else - { - TFree(cur); - continue; - } - } - } - else - { - if (shouldExist != 0) - { - WARN_LOG(SAVESTATE, "Savestate failure: incorrect item marker %d", shouldExist); - SetError(ERROR_FAILURE); - } - if (mode == MODE_READ) - { - if (prev) - prev->next = 0; - if (list_end) - *list_end = prev; - if (list_cur) - { - if (list_start == list_cur) - list_start = 0; - do - { - LinkedListItem* next = list_cur->next; - TFree(list_cur); - list_cur = next; - } - while (list_cur); - } - } - break; - } - prev = list_cur; - list_cur = list_cur->next; - } - } - - void DoMarker(const char *prevName, u32 arbitraryNumber = 0x42); -}; - -class CChunkFileReader -{ -public: - enum Error { - ERROR_NONE, - ERROR_BAD_FILE, - ERROR_BROKEN_STATE, - ERROR_BAD_ALLOC, - }; - - // May fail badly if ptr doesn't point to valid data. - template - static Error LoadPtr(u8 *ptr, T &_class) - { - PointerWrap p(&ptr, PointerWrap::MODE_READ); - _class.DoState(p); - - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - template - static size_t MeasurePtr(T &_class) - { - u8 *ptr = 0; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - return (size_t)ptr; - } - - // Expects ptr to have at least MeasurePtr bytes at ptr. - template - static Error SavePtr(u8 *ptr, T &_class) - { - PointerWrap p(&ptr, PointerWrap::MODE_WRITE); - _class.DoState(p); - - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - // Load file template - template - static Error Load(const std::string &filename, std::string *gitVersion, T& _class, std::string *failureReason) - { - *failureReason = "LoadStateWrongVersion"; - - u8 *ptr = nullptr; - size_t sz; - Error error = LoadFile(filename, gitVersion, ptr, sz, failureReason); - if (error == ERROR_NONE) { - error = LoadPtr(ptr, _class); - delete [] ptr; - } - - INFO_LOG(SAVESTATE, "ChunkReader: Done loading %s", filename.c_str()); - if (error == ERROR_NONE) { - failureReason->clear(); - } - return error; - } - - // Save file template - template - static Error Save(const std::string &filename, const std::string &title, const char *gitVersion, T& _class) - { - // Get data - size_t const sz = MeasurePtr(_class); - u8 *buffer = (u8 *)malloc(sz); - if (!buffer) - return ERROR_BAD_ALLOC; - Error error = SavePtr(buffer, _class); - - // SaveFile takes ownership of buffer - if (error == ERROR_NONE) - error = SaveFile(filename, title, gitVersion, buffer, sz); - return error; - } - - template - static Error Verify(T& _class) - { - u8 *ptr = 0; - - // Step 1: Measure the space required. - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - std::vector buffer(sz); - - // Step 2: Dump the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Step 3: Verify the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_VERIFY); - _class.DoState(p); - - return ERROR_NONE; - } - - static Error GetFileTitle(const std::string &filename, std::string *title); - -private: - struct SChunkHeader - { - int Revision; - int Compress; - u32 ExpectedSize; - u32 UncompressedSize; - char GitVersion[32]; - }; - - enum { - REVISION_MIN = 4, - REVISION_TITLE = 5, - REVISION_CURRENT = REVISION_TITLE, - }; - - static Error LoadFile(const std::string &filename, std::string *gitVersion, u8 *&buffer, size_t &sz, std::string *failureReason); - static Error SaveFile(const std::string &filename, const std::string &title, const char *gitVersion, u8 *buffer, size_t sz); - static Error LoadFileHeader(File::IOFile &pFile, SChunkHeader &header, std::string *title); -}; diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index f60c4b9305..9aad2440d7 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -5,8 +5,10 @@ #pragma once #include -#include "Common.h" -#include "MemoryUtil.h" + +#include "Common/CommonTypes.h" +#include "Common/Log.h" +#include "Common/MemoryUtil.h" // Everything that needs to generate code should inherit from this. // You get memory management for free, plus, you can use all emitter functions without @@ -19,7 +21,7 @@ public: CodeBlockCommon() {} virtual ~CodeBlockCommon() {} - bool IsInSpace(const u8 *ptr) { + bool IsInSpace(const u8 *ptr) const { return (ptr >= region) && (ptr < (region + region_size)); } @@ -85,11 +87,8 @@ public: // If you don't specify a size and we later encounter an executable non-writable block, we're screwed. // These CANNOT be nested. We rely on the memory protection starting at READ|WRITE after start and reset. void BeginWrite(size_t sizeEstimate = 1) { -#ifdef _DEBUG - if (writeStart_) { - PanicAlert("Can't nest BeginWrite calls"); - } -#endif + _dbg_assert_msg_(!writeStart_, "Can't nest BeginWrite calls"); + // In case the last block made the current page exec/no-write, let's fix that. if (PlatformIsWXExclusive()) { writeStart_ = GetCodePtr(); diff --git a/Common/ColorConv.cpp b/Common/ColorConv.cpp index 449643b37c..0146967e99 100644 --- a/Common/ColorConv.cpp +++ b/Common/ColorConv.cpp @@ -485,7 +485,7 @@ void ConvertRGBA5551ToBGRA8888(u32 *dst, const u16 *src, u32 numPixels) { for (u32 x = 0; x < numPixels; x++) { u16 c = src[x]; u32 r = Convert5To8(c & 0x001f); - u32 g = Convert6To8((c >> 5) & 0x001f); + u32 g = Convert5To8((c >> 5) & 0x001f); u32 b = Convert5To8((c >> 10) & 0x001f); // We force an arithmetic shift to get the sign bits/ u32 a = ((s32)(s16)c) & 0xff000000; diff --git a/Common/ColorConv.h b/Common/ColorConv.h index e2ae708bf7..9e66b73ea8 100644 --- a/Common/ColorConv.h +++ b/Common/ColorConv.h @@ -66,25 +66,18 @@ inline u32 RGB565ToRGBA8888(u16 src) { } inline u16 RGBA8888ToRGB565(u32 value) { - u8 r = value & 0xFF; - u8 g = (value >> 8) & 0xFF; - u8 b = (value >> 16) & 0xFF; - r >>= 3; - g >>= 2; - b >>= 3; - return (u16)r | ((u16)g << 5) | ((u16)b << 11); + u32 r = (value >> 3) & 0x1F; + u32 g = (value >> 5) & (0x3F << 5); + u32 b = (value >> 8) & (0x1F << 11); + return (u16)(r | g | b); } inline u16 RGBA8888ToRGBA5551(u32 value) { - u8 r = value & 0xFF; - u8 g = (value >> 8) & 0xFF; - u8 b = (value >> 16) & 0xFF; - u8 a = (value >> 24) & 0xFF; - r >>= 3; - g >>= 3; - b >>= 3; - a >>= 7; - return (u16)r | ((u16)g << 5) | ((u16)b << 10) | ((u16)a << 15); + u32 r = (value >> 3) & 0x1F; + u32 g = (value >> 6) & (0x1F << 5); + u32 b = (value >> 9) & (0x1F << 10); + u32 a = (value >> 16) & 0x8000; + return (u16)(r | g | b | a); } inline u16 RGBA8888ToRGBA4444(u32 value) { diff --git a/Common/Common.h b/Common/Common.h index ec69b6022b..184db926d7 100644 --- a/Common/Common.h +++ b/Common/Common.h @@ -23,19 +23,11 @@ #include #ifdef _MSC_VER -#pragma warning (disable:4100) +#pragma warning(disable:4100) +#pragma warning(disable:4244) +#pragma warning(disable:4996) #endif -// Force enable logging in the right modes. For some reason, something had changed -// so that debugfast no longer logged. -#if defined(_DEBUG) || defined(DEBUGFAST) -#undef LOGGING -#define LOGGING 1 -#endif - -#define STACKALIGN - -#include "Log.h" #include "CommonTypes.h" #include "CommonFuncs.h" @@ -45,17 +37,25 @@ void operator =(const t &other) = delete; #endif -#ifdef __APPLE__ -// The Darwin ABI requires that stack frames be aligned to 16-byte boundaries. -// This is only needed on i386 gcc - x86_64 already aligns to 16 bytes. -#if defined __i386__ && defined __GNUC__ -#undef STACKALIGN -#define STACKALIGN __attribute__((__force_align_arg_pointer__)) +#ifndef ENUM_CLASS_BITOPS +#define ENUM_CLASS_BITOPS(T) \ + static inline T operator |(const T &lhs, const T &rhs) { \ + return T((int)lhs | (int)rhs); \ + } \ + static inline T &operator |= (T &lhs, const T &rhs) { \ + lhs = lhs | rhs; \ + return lhs; \ + } \ + static inline bool operator &(const T &lhs, const T &rhs) { \ + return ((int)lhs & (int)rhs) != 0; \ + } #endif -#define CHECK_HEAP_INTEGRITY() +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#endif -#elif defined(_WIN32) +#if defined(_WIN32) // Memory leak checks #define CHECK_HEAP_INTEGRITY() @@ -64,7 +64,7 @@ #if defined(_DEBUG) #include #undef CHECK_HEAP_INTEGRITY - #define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) PanicAlert("memory corruption detected. see log.");} + #define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) _assert_msg_(false, "Memory corruption detected. See log.");} #endif #else @@ -82,18 +82,16 @@ #define __forceinline inline __attribute__((always_inline)) #endif -#if !defined(__GNUC__) && (defined(_M_X64) || defined(_M_IX86)) +#if defined __SSE4_2__ +# define _M_SSE 0x402 +#elif defined __SSE4_1__ +# define _M_SSE 0x401 +#elif defined __SSSE3__ +# define _M_SSE 0x301 +#elif defined __SSE3__ +# define _M_SSE 0x300 +#elif defined __SSE2__ +# define _M_SSE 0x200 +#elif !defined(__GNUC__) && (defined(_M_X64) || defined(_M_IX86)) # define _M_SSE 0x402 -#else -# if defined __SSE4_2__ -# define _M_SSE 0x402 -# elif defined __SSE4_1__ -# define _M_SSE 0x401 -# elif defined __SSSE3__ -# define _M_SSE 0x301 -# elif defined __SSE3__ -# define _M_SSE 0x300 -# elif defined __SSE2__ -# define _M_SSE 0x200 -# endif #endif diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index ddc0fd6869..0bb5e7ef50 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -132,12 +132,11 @@ - Use Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - stdafx.h;Common/DbgNew.h + Common/DbgNew.h MultiThreadedDebug - ../ext/native;../ext/snappy;../ext/glslang;.. + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. StreamingSIMDExtensions2 Precise true @@ -149,22 +148,20 @@ Windows true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - - Use Level3 - stdafx.h;Common/DbgNew.h + Common/DbgNew.h MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/native;../ext/snappy;../ext/glslang;.. + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. NotSet Precise false @@ -177,22 +174,20 @@ Windows true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - - Use Level3 - stdafx.h;Common/DbgNew.h + Common/DbgNew.h MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/native;../ext/snappy;../ext/glslang;.. + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. NotSet Precise false @@ -205,22 +200,21 @@ Windows true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - - Use Level3 - stdafx.h + + MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/native;../ext/snappy;../ext/glslang;.. + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. NotSet Precise false @@ -233,27 +227,26 @@ Windows true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - Level3 - Use MaxSpeed true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - stdafx.h + + false StreamingSIMDExtensions2 Precise - ../ext/native;../ext/snappy;../ext/glslang;.. + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. Speed true false @@ -266,24 +259,23 @@ true true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - Level3 - Use MaxSpeed true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - stdafx.h - ../ext/native;../ext/snappy;../ext/glslang;.. + + + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. false NotSet Precise @@ -301,24 +293,23 @@ true true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - Level3 - Use MaxSpeed true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - stdafx.h - ../ext/native;../ext/snappy;../ext/glslang;.. + + + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. false NotSet Precise @@ -336,24 +327,23 @@ true true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - Level3 - Use MaxSpeed true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - stdafx.h - ../ext/native;../ext/snappy;../ext/glslang;.. + + + ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;.. false NotSet Precise @@ -371,23 +361,114 @@ true true + - Winmm.lib + ws2_32.lib + + - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + @@ -400,8 +481,7 @@ - - + true @@ -424,33 +504,190 @@ true - - - + - - + - - + + + + + + + + - - - - - - + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + @@ -464,6 +701,7 @@ false + true true @@ -474,14 +712,86 @@ false false - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + true true @@ -512,7 +822,6 @@ true true - @@ -520,36 +829,39 @@ - - + - - Create - Create - Create - Create - Create - Create - Create - Create - - + + + + + - - - - - - + + + + + + + + + - - {c4df647e-80ea-4111-a0a8-218b1b711e18} + + + + + {f761046e-6c38-4428-a5f1-38391a37bb34} + + + + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 9a413fe9a8..5cc1151375 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -1,32 +1,24 @@ ๏ปฟ - - - - - - - Crypto - @@ -38,12 +30,10 @@ - - GL\GLInterface @@ -55,53 +45,358 @@ - - Vulkan - - - Vulkan - - - Vulkan - - - Vulkan - - - + + + + Serialize + + + Serialize + + + Serialize + + + Serialize + + + Serialize + + + Serialize + + + + + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + Thread + + + Thread + + + Thread + + + Thread + + + Input + + + Input + + + Input + + + Data\Random + + + Data\Text + + + Data\Text + + + Data\Text + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Hash + + + Data\Collections + + + Data\Collections + + + Data\Color + + + Data\Convert + + + Math + + + Math + + + Math + + + Math + + + Math\lin + + + Math\lin + + + Math\fast + + + Math\fast + + + Data\Format + + + File + + + File + + + File\VFS + + + File\VFS + + + Data\Format + + + Data\Format + + + Data\Format + + + Profiler + + + System + + + System + + + System + + + File + + + File + + + File + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Data\Format + + + Data\Format + + + Data\Format + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + GPU\D3D9 + + + GPU\D3D9 + + + GPU\D3D9 + + + GPU\D3D11 + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU + + + GPU + + + GPU + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU\OpenGL + + + Render + + + Render + + + GPU\OpenGL + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\Vulkan + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + + + Data\Collections + + + Data\Collections + + + Data\Collections + - - - - - - Crypto - Crypto Crypto - @@ -115,24 +410,319 @@ GL\GLInterface - - Vulkan - - - Vulkan - - - Vulkan - - - Vulkan - - + + + Serialize + + + + + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + Thread + + + Thread + + + Thread + + + Thread + + + Input + + + Input + + + Data\Text + + + Data\Text + + + Data\Text + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Hash + + + Data\Color + + + Data\Convert + + + Math + + + Math + + + Math + + + Math\lin + + + Math\lin + + + Math\fast + + + Math\fast + + + Math\fast + + + Data\Format + + + File + + + File + + + File\VFS + + + File\VFS + + + Data\Format + + + Data\Format + + + Data\Format + + + Profiler + + + System + + + File + + + File + + + File + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Data\Format + + + Data\Format + + + Data\Format + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + GPU\D3D9 + + + GPU\D3D11 + + + GPU\D3D9 + + + GPU\D3D9 + + + GPU\D3D9 + + + GPU\D3D11 + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU\OpenGL + + + GPU + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\OpenGL + + + GPU\OpenGL + + + Render + + + Render + + + GPU\OpenGL + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\Vulkan + + + GPU\Vulkan + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + @@ -144,8 +734,108 @@ {2c723cf4-75b6-406a-90c0-ebb7a13ba476} - - {c14d66ef-5f7c-4565-975a-72774e7ccfb9} + + {7be79ad5-3520-46a1-a370-dce2a943978c} + + + {b2685193-5954-4ab6-af7c-d6064f63e278} + + + {1d04f87f-73a2-4027-a6ff-e998e92e7d3c} + + + {41bcd391-8641-432c-ae4a-ab03812df762} + + + {fd0bac4f-e3e2-4201-8902-2d19b50d5bf7} + + + {072c36eb-a283-40b2-b8b1-02ec57d3bbae} + + + {a162915f-e53a-4f42-a222-e863235a2d37} + + + {891eae07-622d-46d5-9fc6-a4c320649eb9} + + + {0bd9bfae-7d4e-4f54-9aae-8fb11ab8c999} + + + {16fc7858-b6db-4eb2-bd4c-1354ffacda5f} + + + {c2d25b54-23fc-4e80-8d9b-5d7e94fe557e} + + + {1ada1f0f-6f1c-4bf2-8450-1fc63d77da17} + + + {9f70c234-1671-49db-aa45-1a6a75698a40} + + + {98967255-542c-490d-9183-a4b21c074703} + + + {aa083b68-34ed-4679-a8de-1797a00a1772} + + + {ffa5052d-e78f-4c47-a43e-e3537c5e7ad0} + + + {3eebbd6c-0c35-4dac-9869-5d38419432a6} + + + {d9e60709-9bf4-4bc7-b902-742219df7ffb} + + + {b10822cf-4cc0-4bc3-91a9-b20cb66e5cbd} + + + {8321632b-8fc5-4a67-adb7-126a328d50eb} + + + {89ddf0bd-3fc4-4a69-87a7-b82cfc412e0a} + + + {b338dd13-cdae-4ef4-b122-b22967ae9bcb} + + + {6a61d762-e71c-4428-8cef-c7ddda405ba5} + + + {3b448d70-d5c6-4732-96f0-29f3e101bfe8} + + + {a1745de8-f61a-4f11-b715-705a8812862e} + + + {8241d0c2-78c8-4fc6-9543-69042ec5eb54} + + + {e9d7bdf2-c412-4030-a423-671066c4ea51} + + + {19ad2070-4f85-48d3-abab-add446ea3a77} + + + {c9aba118-5c31-4607-9a69-18eca9f92b44} + + + {9da96cce-c74a-4669-b755-c95defbe1e93} + + + ext\libpng17 + + + + + Math\lin + + + Math\fast + + \ No newline at end of file diff --git a/Common/CommonFuncs.h b/Common/CommonFuncs.h index cfcbbe0e78..72cf14356f 100644 --- a/Common/CommonFuncs.h +++ b/Common/CommonFuncs.h @@ -25,7 +25,6 @@ #if !defined(_WIN32) - #include #include @@ -77,17 +76,5 @@ inline u64 __rotr64(u64 x, unsigned int shift){ #define ftello _ftelli64 #define atoll _atoi64 #endif - #if _M_IX86 - #define Crash() {__asm int 3} - #else - #define Crash() {__debugbreak();} - #endif // M_IX86 + #define Crash() {__debugbreak();} #endif // WIN32 ndef - -// Generic function to get last error message. -// Call directly after the command or use the error num. -// This function might change the error code. -// Defined in Misc.cpp. -const char *GetLastErrorMsg(); -const char *GetStringErrorMsg(int errCode); - diff --git a/Common/CommonTypes.h b/Common/CommonTypes.h index 93a0c8cb30..ab2b7145af 100644 --- a/Common/CommonTypes.h +++ b/Common/CommonTypes.h @@ -22,14 +22,6 @@ #pragma once -struct u24_be { - unsigned char value[3]; - - operator unsigned int(){ - return 0x00000000 | (value[0] << 16) | (value[1] << 8) | (value[2] << 0); - } -}; - #if defined(_MSC_VER) typedef unsigned __int8 u8; diff --git a/Common/ConsoleListener.cpp b/Common/ConsoleListener.cpp index 18472eaa07..e5625c4f0f 100644 --- a/Common/ConsoleListener.cpp +++ b/Common/ConsoleListener.cpp @@ -17,6 +17,7 @@ #include #include // min +#include #include // System: To be able to add strings with "+" #include #ifdef _WIN32 @@ -31,10 +32,11 @@ #endif #include "ppsspp_config.h" -#include "thread/threadutil.h" -#include "util/text/utf8.h" -#include "Common.h" -#include "ConsoleListener.h" // Common +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Common.h" +#include "Common/ConsoleListener.h" +#include "Common/StringUtils.h" #if defined(USING_WIN_UI) const int LOG_PENDING_MAX = 120 * 10000; @@ -48,8 +50,8 @@ HANDLE ConsoleListener::hTriggerEvent = NULL; CRITICAL_SECTION ConsoleListener::criticalSection; char *ConsoleListener::logPending = NULL; -std::atomic ConsoleListener::logPendingReadPos; -std::atomic ConsoleListener::logPendingWritePos; +std::atomic ConsoleListener::logPendingReadPos; +std::atomic ConsoleListener::logPendingWritePos; #endif ConsoleListener::ConsoleListener() : bHidden(true) @@ -232,7 +234,7 @@ bool ConsoleListener::IsOpen() */ void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) { - _dbg_assert_msg_(COMMON, IsOpen(), "Don't call this before opening the console."); + _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); #if defined(USING_WIN_UI) BOOL SB, SW; if (BufferFirst) @@ -257,7 +259,7 @@ void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int S } void ConsoleListener::LetterSpace(int Width, int Height) { - _dbg_assert_msg_(COMMON, IsOpen(), "Don't call this before opening the console."); + _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); #if defined(USING_WIN_UI) // Get console info CONSOLE_SCREEN_BUFFER_INFO ConInfo; @@ -392,7 +394,7 @@ void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text) // Not ANSI, since the console doesn't support it, but ANSI-like. snprintf(ColorAttr, 16, "\033%d", Level); // For now, rather than properly support it. - _dbg_assert_msg_(COMMON, strlen(ColorAttr) == 2, "Console logging doesn't support > 9 levels."); + _dbg_assert_msg_(strlen(ColorAttr) == 2, "Console logging doesn't support > 9 levels."); ColorLen = (int)strlen(ColorAttr); } @@ -455,7 +457,7 @@ void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text) void ConsoleListener::WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Text, size_t Len) { - _dbg_assert_msg_(COMMON, IsOpen(), "Don't call this before opening the console."); + _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); /* const int MAX_BYTES = 1024*10; @@ -510,7 +512,7 @@ void ConsoleListener::WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Tex void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) { - _dbg_assert_msg_(COMMON, IsOpen(), "Don't call this before opening the console."); + _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); #if defined(USING_WIN_UI) // Check size if (Width < 8 || Height < 12) return; @@ -632,7 +634,7 @@ void ConsoleListener::Log(const LogMessage &msg) { // Clear console screen void ConsoleListener::ClearScreen(bool Cursor) { - _dbg_assert_msg_(COMMON, IsOpen(), "Don't call this before opening the console."); + _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); #if defined(USING_WIN_UI) COORD coordScreen = { 0, 0 }; DWORD cCharsWritten; diff --git a/Common/ConsoleListener.h b/Common/ConsoleListener.h index 66a612a849..976e7531cd 100644 --- a/Common/ConsoleListener.h +++ b/Common/ConsoleListener.h @@ -63,8 +63,8 @@ private: static CRITICAL_SECTION criticalSection; static char *logPending; - static std::atomic logPendingReadPos; - static std::atomic logPendingWritePos; + static std::atomic logPendingReadPos; + static std::atomic logPendingWritePos; int openWidth_; int openHeight_; diff --git a/ext/native/util/const_map.h b/Common/Data/Collections/ConstMap.h similarity index 100% rename from ext/native/util/const_map.h rename to Common/Data/Collections/ConstMap.h diff --git a/Common/FixedSizeQueue.h b/Common/Data/Collections/FixedSizeQueue.h similarity index 96% rename from Common/FixedSizeQueue.h rename to Common/Data/Collections/FixedSizeQueue.h index d59555f7d8..ed7eb14a75 100644 --- a/Common/FixedSizeQueue.h +++ b/Common/Data/Collections/FixedSizeQueue.h @@ -18,8 +18,8 @@ #pragma once #include -#include "ChunkFile.h" -#include "MemoryUtil.h" +#include "Common/MemoryUtil.h" +#include "Common/Serialize/Serializer.h" // STL-look-a-like interface, but name is mixed case to distinguish it clearly from the // real STL classes. @@ -147,16 +147,16 @@ public: void DoState(PointerWrap &p) { int size = N; - p.Do(size); + Do(p, size); if (size != N) { ERROR_LOG(COMMON, "Savestate failure: Incompatible queue size."); return; } - p.DoArray(storage_, N); - p.Do(head_); - p.Do(tail_); - p.Do(count_); + DoArray(p, storage_, N); + Do(p, head_); + Do(p, tail_); + Do(p, count_); p.DoMarker("FixedSizeQueue"); } diff --git a/Common/Hashmaps.h b/Common/Data/Collections/Hashmaps.h similarity index 90% rename from Common/Hashmaps.h rename to Common/Data/Collections/Hashmaps.h index e5e36be02e..4c6664277c 100644 --- a/Common/Hashmaps.h +++ b/Common/Data/Collections/Hashmaps.h @@ -8,14 +8,11 @@ #include "Common/CommonFuncs.h" #include "Common/Log.h" -// Whatever random value. -const uint32_t hashmapSeed = 0x23B58532; - // TODO: Try hardware CRC. Unfortunately not available on older Intels or ARM32. // Seems to be ubiquitous on ARM64 though. template inline uint32_t HashKey(const K &k) { - return XXH32(&k, sizeof(k), hashmapSeed); + return XXH3_64bits(&k, sizeof(k)) & 0xFFFFFFFF; } template inline bool KeyEquals(const K &a, const K &b) { @@ -53,7 +50,7 @@ public: return NullValue; p = (p + 1) & mask; // If the state is REMOVED, we just keep on walking. if (p == pos) { - _assert_msg_(SYSTEM, false, "DenseHashMap: Hit full on Get()"); + _assert_msg_(false, "DenseHashMap: Hit full on Get()"); } } return NullValue; @@ -72,7 +69,7 @@ public: if (state[p] == BucketState::TAKEN) { if (KeyEquals(key, map[p].key)) { // Bad! We already got this one. Let's avoid this case. - _assert_msg_(SYSTEM, false, "DenseHashMap: Duplicate key inserted"); + _assert_msg_(false, "DenseHashMap: Duplicate key inserted"); return false; } // continue looking.... @@ -83,7 +80,7 @@ public: p = (p + 1) & mask; if (p == pos) { // FULL! Error. Should not happen thanks to Grow(). - _assert_msg_(SYSTEM, false, "DenseHashMap: Hit full on Insert()"); + _assert_msg_(false, "DenseHashMap: Hit full on Insert()"); } } if (state[p] == BucketState::REMOVED) { @@ -111,7 +108,7 @@ public: p = (p + 1) & mask; if (p == pos) { // FULL! Error. Should not happen. - _assert_msg_(SYSTEM, false, "DenseHashMap: Hit full on Remove()"); + _assert_msg_(false, "DenseHashMap: Hit full on Remove()"); } } return false; @@ -168,7 +165,7 @@ private: Insert(old[i].key, old[i].value); } } - _assert_msg_(SYSTEM, oldCount == count_, "DenseHashMap: count should not change in Grow()"); + _assert_msg_(oldCount == count_, "DenseHashMap: count should not change in Grow()"); } struct Pair { Key key; @@ -204,7 +201,7 @@ public: return NullValue; p = (p + 1) & mask; // If the state is REMOVED, we just keep on walking. if (p == pos) { - _assert_msg_(SYSTEM, false, "PrehashMap: Hit full on Get()"); + _assert_msg_(false, "PrehashMap: Hit full on Get()"); } } return NullValue; @@ -230,7 +227,7 @@ public: p = (p + 1) & mask; if (p == pos) { // FULL! Error. Should not happen thanks to Grow(). - _assert_msg_(SYSTEM, false, "PrehashMap: Hit full on Insert()"); + _assert_msg_(false, "PrehashMap: Hit full on Insert()"); } } if (state[p] == BucketState::REMOVED) { @@ -257,7 +254,7 @@ public: } p = (p + 1) & mask; if (p == pos) { - _assert_msg_(SYSTEM, false, "PrehashMap: Hit full on Remove()"); + _assert_msg_(false, "PrehashMap: Hit full on Remove()"); } } return false; @@ -317,7 +314,7 @@ private: } } INFO_LOG(G3D, "Grew hashmap capacity from %d to %d", oldCapacity, capacity_); - _assert_msg_(SYSTEM, oldCount == count_, "PrehashMap: count should not change in Grow()"); + _assert_msg_(oldCount == count_, "PrehashMap: count should not change in Grow()"); } struct Pair { uint32_t hash; diff --git a/Common/ThreadSafeList.h b/Common/Data/Collections/ThreadSafeList.h similarity index 99% rename from Common/ThreadSafeList.h rename to Common/Data/Collections/ThreadSafeList.h index 37389286ba..9697438bb9 100644 --- a/Common/ThreadSafeList.h +++ b/Common/Data/Collections/ThreadSafeList.h @@ -75,7 +75,7 @@ public: void DoState(PointerWrap &p) { std::lock_guard guard(lock); - p.Do(list); + Do(p, list); } private: diff --git a/ext/native/util/tiny_set.h b/Common/Data/Collections/TinySet.h similarity index 100% rename from ext/native/util/tiny_set.h rename to Common/Data/Collections/TinySet.h diff --git a/ext/native/base/colorutil.cpp b/Common/Data/Color/RGBAUtil.cpp similarity index 61% rename from ext/native/base/colorutil.cpp rename to Common/Data/Color/RGBAUtil.cpp index bdb4bdbcb1..8b93a0fc96 100644 --- a/ext/native/base/colorutil.cpp +++ b/Common/Data/Color/RGBAUtil.cpp @@ -1,4 +1,4 @@ -#include "base/colorutil.h" +#include "Common/Data/Color/RGBAUtil.h" template static T clamp(T f, T low, T high) { @@ -46,7 +46,7 @@ uint32_t colorBlend(uint32_t rgb1, uint32_t rgb2, float alpha) { uint32_t alphaMul(uint32_t color, float alphaMul) { uint32_t rgb = color & 0xFFFFFF; int32_t alpha = color >> 24; - alpha *= alphaMul; + alpha = (int32_t)(alpha * alphaMul); if (alpha < 0) alpha = 0; if (alpha > 255) alpha = 255; return (alpha << 24) | (rgb & 0xFFFFFF); @@ -63,52 +63,3 @@ uint32_t rgba(float r, float g, float b, float alpha) { uint32_t rgba_clamp(float r, float g, float b, float a) { return rgba(clamp(r, 0.0f, 1.0f), clamp(g, 0.0f, 1.0f), clamp(b, 0.0f, 1.0f), clamp(a, 0.0f, 1.0f)); } - -/* hsv2rgb.c -* Convert Hue Saturation Value to Red Green Blue -* -* P.J. 08-Aug-98 -* -* Reference: -* D. F. Rogers -* Procedural Elements for Computer Graphics -* McGraw Hill 1985 -*/ -uint32_t hsva(float H, float S, float V, float alpha) { - /* - * Purpose: - * Convert HSV values to RGB values - * All values are in the range [0.0 .. 1.0] - */ - float F, M, N, K; - int I; - if ( S == 0.0 ) { - // Achromatic case, set level of grey - return rgba(V, V, V, alpha); - } else { - /* - * Determine levels of primary colours. - */ - if (H >= 1.0) { - H = 0.0; - } else { - H = H * 6; - } - I = (int) H; /* should be in the range 0..5 */ - F = H - I; /* fractional part */ - - M = V * (1 - S); - N = V * (1 - S * F); - K = V * (1 - S * (1 - F)); - - float r, g, b; - if (I == 0) { r = V; g = K; b = M; } - else if (I == 1) { r = N; g = V; b = M; } - else if (I == 2) { r = M; g = V; b = K; } - else if (I == 3) { r = M; g = N; b = V; } - else if (I == 4) { r = K; g = M; b = V; } - else if (I == 5) { r = V; g = M; b = N; } - else return 0; - return rgba(r, g, b, alpha); - } -} diff --git a/ext/native/base/colorutil.h b/Common/Data/Color/RGBAUtil.h similarity index 68% rename from ext/native/base/colorutil.h rename to Common/Data/Color/RGBAUtil.h index f79c4a214b..9e8128bae1 100644 --- a/ext/native/base/colorutil.h +++ b/Common/Data/Color/RGBAUtil.h @@ -1,6 +1,6 @@ #pragma once -#include "base/basictypes.h" +#include uint32_t whiteAlpha(float alpha); uint32_t blackAlpha(float alpha); @@ -9,7 +9,6 @@ uint32_t colorBlend(uint32_t color, uint32_t color2, float alpha); uint32_t alphaMul(uint32_t color, float alphaMul); uint32_t rgba(float r, float g, float b, float alpha); uint32_t rgba_clamp(float r, float g, float b, float alpha); -uint32_t hsva(float h, float s, float v, float alpha); typedef unsigned int Color; @@ -17,10 +16,3 @@ typedef unsigned int Color; inline Color darkenColor(Color color) { return (color & 0xFF000000) | ((color >> 1) & 0x7F7F7F); } -inline Color whitenColor(Color color) { - return ((color & 0xFF000000) | ((color >> 1) & 0x7F7F7F)) + 0x7F7F7F; -} -inline Color colorInterpol(Color x, Color y, int n) { - // TODO - return x; -} diff --git a/ext/native/math/dataconv.cpp b/Common/Data/Convert/SmallDataConvert.cpp similarity index 68% rename from ext/native/math/dataconv.cpp rename to Common/Data/Convert/SmallDataConvert.cpp index 2fcc339c90..4f0d65ea11 100644 --- a/ext/native/math/dataconv.cpp +++ b/Common/Data/Convert/SmallDataConvert.cpp @@ -1,3 +1,3 @@ -#include "dataconv.h" +#include "Common/Data/Convert/SmallDataConvert.h" alignas(16) const float one_over_255_x4[4] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, }; diff --git a/ext/native/math/dataconv.h b/Common/Data/Convert/SmallDataConvert.h similarity index 100% rename from ext/native/math/dataconv.h rename to Common/Data/Convert/SmallDataConvert.h diff --git a/ext/native/data/base64.cpp b/Common/Data/Encoding/Base64.cpp similarity index 95% rename from ext/native/data/base64.cpp rename to Common/Data/Encoding/Base64.cpp index 8df7abaa1e..50dbc465a5 100644 --- a/ext/native/data/base64.cpp +++ b/Common/Data/Encoding/Base64.cpp @@ -1,4 +1,4 @@ -#include "data/base64.h" +#include "Common/Data/Encoding/Base64.h" // TODO: This is a simple but not very efficient implementation. std::string Base64Encode(const uint8_t *p, size_t sz) { diff --git a/ext/native/data/base64.h b/Common/Data/Encoding/Base64.h similarity index 100% rename from ext/native/data/base64.h rename to Common/Data/Encoding/Base64.h diff --git a/ext/native/data/compression.cpp b/Common/Data/Encoding/Compression.cpp similarity index 91% rename from ext/native/data/compression.cpp rename to Common/Data/Encoding/Compression.cpp index f2bc6494ee..751a9595cf 100644 --- a/ext/native/data/compression.cpp +++ b/Common/Data/Encoding/Compression.cpp @@ -11,7 +11,7 @@ #include -#include "base/logging.h" +#include "Common/Log.h" /** Compress a STL string using zlib with given compression level and return * the binary data. */ @@ -20,7 +20,7 @@ bool compress_string(const std::string& str, std::string *dest, int compressionl memset(&zs, 0, sizeof(zs)); if (deflateInit(&zs, compressionlevel) != Z_OK) { - ELOG("deflateInit failed while compressing."); + ERROR_LOG(IO, "deflateInit failed while compressing."); return false; } @@ -67,7 +67,7 @@ bool decompress_string(const std::string& str, std::string *dest) { // modification by hrydgard: inflateInit2, 16+MAXWBITS makes it read gzip data too if (inflateInit2(&zs, 32+MAX_WBITS) != Z_OK) { - ELOG("inflateInit failed while decompressing."); + ERROR_LOG(IO, "inflateInit failed while decompressing."); return false; } @@ -96,7 +96,7 @@ bool decompress_string(const std::string& str, std::string *dest) { if (ret != Z_STREAM_END) { // an error occurred that was not EOF std::ostringstream oss; - ELOG("Exception during zlib decompression: (%i) %s", ret, zs.msg); + ERROR_LOG(IO, "Exception during zlib decompression: (%i) %s", ret, zs.msg); return false; } diff --git a/Common/Data/Encoding/Compression.h b/Common/Data/Encoding/Compression.h new file mode 100644 index 0000000000..5323b8f549 --- /dev/null +++ b/Common/Data/Encoding/Compression.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +// inflate/deflate convenience wrapper. Uses zlib. +bool compress_string(const std::string& str, std::string *dest, int compressionlevel = 9); +bool decompress_string(const std::string& str, std::string *dest); diff --git a/ext/native/util/text/shiftjis.h b/Common/Data/Encoding/Shiftjis.h similarity index 98% rename from ext/native/util/text/shiftjis.h rename to Common/Data/Encoding/Shiftjis.h index e92df04db6..5f77f7665d 100644 --- a/ext/native/util/text/shiftjis.h +++ b/Common/Data/Encoding/Shiftjis.h @@ -1,6 +1,6 @@ #pragma once -#include "base/basictypes.h" +#include // Warning: decodes/encodes JIS, not Unicode. // Use a table to map. @@ -137,4 +137,4 @@ struct ShiftJIS { private: const char *c_; int index_; -}; \ No newline at end of file +}; diff --git a/ext/native/util/text/utf16.h b/Common/Data/Encoding/Utf16.h similarity index 97% rename from ext/native/util/text/utf16.h rename to Common/Data/Encoding/Utf16.h index 830eac2c51..a04949ed35 100644 --- a/ext/native/util/text/utf16.h +++ b/Common/Data/Encoding/Utf16.h @@ -1,6 +1,8 @@ #pragma once -#include "base/basictypes.h" +#include + +#include "Common/BitSet.h" // Should optimize out. #define UTF16_IS_LITTLE_ENDIAN (*(const uint16_t *)"\0\xff" >= 0x100) diff --git a/ext/native/util/text/utf8.cpp b/Common/Data/Encoding/Utf8.cpp similarity index 98% rename from ext/native/util/text/utf8.cpp rename to Common/Data/Encoding/Utf8.cpp index 5c24b761af..8e3bb0f05d 100644 --- a/ext/native/util/text/utf8.cpp +++ b/Common/Data/Encoding/Utf8.cpp @@ -18,17 +18,17 @@ #undef max #endif -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include -#include "base/basictypes.h" -#include "utf8.h" -#include "utf16.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Encoding/Utf16.h" // is start of UTF sequence inline bool isutf(char c) { diff --git a/ext/native/util/text/utf8.h b/Common/Data/Encoding/Utf8.h similarity index 98% rename from ext/native/util/text/utf8.h rename to Common/Data/Encoding/Utf8.h index fd6ddf64e7..9d04a788a0 100644 --- a/ext/native/util/text/utf8.h +++ b/Common/Data/Encoding/Utf8.h @@ -16,7 +16,7 @@ #pragma once -#include "base/basictypes.h" +#include #include uint32_t u8_nextchar(const char *s, int *i); diff --git a/ext/native/file/ini_file.cpp b/Common/Data/Format/IniFile.cpp similarity index 87% rename from ext/native/file/ini_file.cpp rename to Common/Data/Format/IniFile.cpp index 99bdcd163a..8e001f802d 100644 --- a/ext/native/file/ini_file.cpp +++ b/Common/Data/Format/IniFile.cpp @@ -2,30 +2,30 @@ // Taken from Dolphin but relicensed by me, Henrik Rydgard, under the MIT // license as I wrote the whole thing originally and it has barely changed. -#include -#include +#include +#include #ifndef _MSC_VER #include #endif -#include -#include +#include #include #include -#include +#include +#include +#include -#include "base/logging.h" -#include "base/stringutil.h" -#include "file/ini_file.h" -#include "file/vfs.h" +#include "Common/Data/Format/IniFile.h" +#include "Common/File/VFS/VFS.h" +#include "Common/Data/Text/Parsers.h" #ifdef _WIN32 -#include "../util/text/utf8.h" - // Function Cross-Compatibility -#define strcasecmp _stricmp +#include "Common/Data/Encoding/Utf8.h" #endif +#include "Common/StringUtils.h" + static bool ParseLineKey(const std::string &line, size_t &pos, std::string *keyOut) { std::string key = ""; @@ -148,11 +148,11 @@ static std::string EscapeComments(const std::string &value) { return result; } -void IniFile::Section::Clear() { +void Section::Clear() { lines.clear(); } -std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut) +std::string* Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut) { for (std::vector::iterator iter = lines.begin(); iter != lines.end(); ++iter) { @@ -165,7 +165,23 @@ std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, s return 0; } -void IniFile::Section::Set(const char* key, const char* newValue) +void Section::Set(const char* key, uint32_t newValue) { + Set(key, StringFromFormat("0x%08x", newValue).c_str()); +} + +void Section::Set(const char* key, float newValue) { + Set(key, StringFromFormat("%f", newValue).c_str()); +} + +void Section::Set(const char* key, double newValue) { + Set(key, StringFromFormat("%f", newValue).c_str()); +} + +void Section::Set(const char* key, int newValue) { + Set(key, StringFromInt(newValue).c_str()); +} + +void Section::Set(const char* key, const char* newValue) { std::string value, commented; std::string* line = GetLine(key, &value, &commented); @@ -181,7 +197,7 @@ void IniFile::Section::Set(const char* key, const char* newValue) } } -void IniFile::Section::Set(const char* key, const std::string& newValue, const std::string& defaultValue) +void Section::Set(const char* key, const std::string& newValue, const std::string& defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -189,7 +205,7 @@ void IniFile::Section::Set(const char* key, const std::string& newValue, const s Delete(key); } -bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue) +bool Section::Get(const char* key, std::string* value, const char* defaultValue) { const std::string* line = GetLine(key, value, 0); if (!line) @@ -203,7 +219,7 @@ bool IniFile::Section::Get(const char* key, std::string* value, const char* defa return true; } -void IniFile::Section::Set(const char* key, const float newValue, const float defaultValue) +void Section::Set(const char* key, const float newValue, const float defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -211,7 +227,7 @@ void IniFile::Section::Set(const char* key, const float newValue, const float de Delete(key); } -void IniFile::Section::Set(const char* key, int newValue, int defaultValue) +void Section::Set(const char* key, int newValue, int defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -219,7 +235,7 @@ void IniFile::Section::Set(const char* key, int newValue, int defaultValue) Delete(key); } -void IniFile::Section::Set(const char* key, bool newValue, bool defaultValue) +void Section::Set(const char* key, bool newValue, bool defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -227,7 +243,7 @@ void IniFile::Section::Set(const char* key, bool newValue, bool defaultValue) Delete(key); } -void IniFile::Section::Set(const char* key, const std::vector& newValues) +void Section::Set(const char* key, const std::vector& newValues) { std::string temp; // Join the strings with , @@ -242,11 +258,11 @@ void IniFile::Section::Set(const char* key, const std::vector& newV Set(key, temp.c_str()); } -void IniFile::Section::AddComment(const std::string &comment) { +void Section::AddComment(const std::string &comment) { lines.push_back("# " + comment); } -bool IniFile::Section::Get(const char* key, std::vector& values) +bool Section::Get(const char* key, std::vector& values) { std::string temp; bool retval = Get(key, &temp, 0); @@ -274,7 +290,7 @@ bool IniFile::Section::Get(const char* key, std::vector& values) return true; } -bool IniFile::Section::Get(const char* key, int* value, int defaultValue) +bool Section::Get(const char* key, int* value, int defaultValue) { std::string temp; bool retval = Get(key, &temp, 0); @@ -284,7 +300,7 @@ bool IniFile::Section::Get(const char* key, int* value, int defaultValue) return false; } -bool IniFile::Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) +bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) { std::string temp; bool retval = Get(key, &temp, 0); @@ -294,7 +310,7 @@ bool IniFile::Section::Get(const char* key, uint32_t* value, uint32_t defaultVal return false; } -bool IniFile::Section::Get(const char* key, bool* value, bool defaultValue) +bool Section::Get(const char* key, bool* value, bool defaultValue) { std::string temp; bool retval = Get(key, &temp, 0); @@ -304,7 +320,7 @@ bool IniFile::Section::Get(const char* key, bool* value, bool defaultValue) return false; } -bool IniFile::Section::Get(const char* key, float* value, float defaultValue) +bool Section::Get(const char* key, float* value, float defaultValue) { std::string temp; bool retval = Get(key, &temp, 0); @@ -314,7 +330,7 @@ bool IniFile::Section::Get(const char* key, float* value, float defaultValue) return false; } -bool IniFile::Section::Get(const char* key, double* value, double defaultValue) +bool Section::Get(const char* key, double* value, double defaultValue) { std::string temp; bool retval = Get(key, &temp, 0); @@ -324,7 +340,7 @@ bool IniFile::Section::Get(const char* key, double* value, double defaultValue) return false; } -bool IniFile::Section::Exists(const char *key) const +bool Section::Exists(const char *key) const { for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) { @@ -336,7 +352,7 @@ bool IniFile::Section::Exists(const char *key) const return false; } -std::map IniFile::Section::ToMap() const +std::map Section::ToMap() const { std::map outMap; for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) @@ -350,7 +366,7 @@ std::map IniFile::Section::ToMap() const } -bool IniFile::Section::Delete(const char *key) +bool Section::Delete(const char *key) { std::string* line = GetLine(key, 0, 0); for (std::vector::iterator liter = lines.begin(); liter != lines.end(); ++liter) @@ -366,7 +382,7 @@ bool IniFile::Section::Delete(const char *key) // IniFile -const IniFile::Section* IniFile::GetSection(const char* sectionName) const +const Section* IniFile::GetSection(const char* sectionName) const { for (std::vector
::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) if (!strcasecmp(iter->name().c_str(), sectionName)) @@ -374,7 +390,7 @@ const IniFile::Section* IniFile::GetSection(const char* sectionName) const return 0; } -IniFile::Section* IniFile::GetSection(const char* sectionName) +Section* IniFile::GetSection(const char* sectionName) { for (std::vector
::iterator iter = sections.begin(); iter != sections.end(); ++iter) if (!strcasecmp(iter->name().c_str(), sectionName)) @@ -382,7 +398,7 @@ IniFile::Section* IniFile::GetSection(const char* sectionName) return 0; } -IniFile::Section* IniFile::GetOrCreateSection(const char* sectionName) +Section* IniFile::GetOrCreateSection(const char* sectionName) { Section* section = GetSection(sectionName); if (!section) diff --git a/Common/Data/Format/IniFile.h b/Common/Data/Format/IniFile.h new file mode 100644 index 0000000000..5d65045033 --- /dev/null +++ b/Common/Data/Format/IniFile.h @@ -0,0 +1,147 @@ +// IniFile +// Taken from Dolphin but relicensed by me, Henrik Rydgard, under the MIT +// license as I wrote the whole thing originally and it has barely changed. + +#pragma once + +#include +#include +#include +#include + +class Section +{ + friend class IniFile; + +public: + Section() {} + Section(const std::string& name) : name_(name) {} + + bool Exists(const char *key) const; + bool Delete(const char *key); + + void Clear(); + + std::map ToMap() const; + + std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut); + void Set(const char* key, const char* newValue); + void Set(const char* key, const std::string& newValue, const std::string& defaultValue); + + void Set(const std::string &key, const std::string &value) { + Set(key.c_str(), value.c_str()); + } + bool Get(const char* key, std::string* value, const char* defaultValue); + + void Set(const char* key, uint32_t newValue); + void Set(const char* key, float newValue); + void Set(const char* key, const float newValue, const float defaultValue); + void Set(const char* key, double newValue); + + void Set(const char* key, int newValue, int defaultValue); + void Set(const char* key, int newValue); + + void Set(const char* key, bool newValue, bool defaultValue); + void Set(const char* key, bool newValue) { + Set(key, newValue ? "True" : "False"); + } + void Set(const char* key, const std::vector& newValues); + + // Declare without a body to make it fail to compile. This is to prevent accidentally + // setting a pointer as a bool. The failure is in the linker unfortunately, but that's better + // than accidentally succeeding in a bad way. + template + void Set(const char *key, T *ptr); + + void AddComment(const std::string &comment); + + bool Get(const char* key, int* value, int defaultValue = 0); + bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0); + bool Get(const char* key, bool* value, bool defaultValue = false); + bool Get(const char* key, float* value, float defaultValue = false); + bool Get(const char* key, double* value, double defaultValue = false); + bool Get(const char* key, std::vector& values); + + bool operator < (const Section& other) const { + return name_ < other.name_; + } + + const std::string &name() const { + return name_; + } + +protected: + std::vector lines; + std::string name_; + std::string comment; +}; + +class IniFile +{ +public: + bool Load(const char* filename); + bool Load(const std::string &filename) { return Load(filename.c_str()); } + bool Load(std::istream &istream); + bool LoadFromVFS(const std::string &filename); + + bool Save(const char* filename); + bool Save(const std::string &filename) { return Save(filename.c_str()); } + + // Returns true if key exists in section + bool Exists(const char* sectionName, const char* key) const; + + // TODO: Get rid of these, in favor of the Section ones. + void Set(const char* sectionName, const char* key, const char* newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, const std::string& newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue.c_str()); + } + void Set(const char* sectionName, const char* key, int newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, uint32_t newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, bool newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, const std::vector& newValues) { + GetOrCreateSection(sectionName)->Set(key, newValues); + } + + // TODO: Get rid of these, in favor of the Section ones. + bool Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue = ""); + bool Get(const char* sectionName, const char* key, int* value, int defaultValue = 0); + bool Get(const char* sectionName, const char* key, uint32_t* value, uint32_t defaultValue = 0); + bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false); + bool Get(const char* sectionName, const char* key, std::vector& values); + + template bool GetIfExists(const char* sectionName, const char* key, T value) + { + if (Exists(sectionName, key)) + return Get(sectionName, key, value); + return false; + } + + bool GetKeys(const char* sectionName, std::vector& keys) const; + + void SetLines(const char* sectionName, const std::vector &lines); + bool GetLines(const char* sectionName, std::vector& lines, const bool remove_comments = true) const; + + bool DeleteKey(const char* sectionName, const char* key); + bool DeleteSection(const char* sectionName); + + void SortSections(); + std::vector
&Sections() { return sections; } + + bool HasSection(const char *section) { return GetSection(section) != 0; } + + Section* GetOrCreateSection(const char* section); + +private: + std::vector
sections; + + const Section* GetSection(const char* section) const; + Section* GetSection(const char* section); +}; diff --git a/ext/native/json/json_reader.cpp b/Common/Data/Format/JSONReader.cpp similarity index 90% rename from ext/native/json/json_reader.cpp rename to Common/Data/Format/JSONReader.cpp index 1663a915ef..4f299eab4a 100644 --- a/ext/native/json/json_reader.cpp +++ b/Common/Data/Format/JSONReader.cpp @@ -1,6 +1,6 @@ -#include "file/zip_read.h" -#include "file/vfs.h" -#include "json/json_reader.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/FileUtil.h" +#include "Common/Data/Format/JSONReader.h" namespace json { @@ -15,7 +15,7 @@ JsonReader::JsonReader(const std::string &filename) { if (buffer_) { parse(); } else { - ELOG("Failed to read json %s", filename.c_str()); + ERROR_LOG(IO, "Failed to read json file '%s'", filename.c_str()); } } } @@ -33,7 +33,7 @@ int JsonGet::numChildren() const { const JsonNode *JsonGet::get(const char *child_name) const { if (!child_name) { - FLOG("JSON: Cannot get from null child name"); + ERROR_LOG(IO, "JSON: Cannot get from null child name"); return nullptr; } if (value_.getTag() != JSON_OBJECT) { @@ -58,7 +58,7 @@ const char *JsonGet::getStringOrDie(const char *child_name) const { const JsonNode *val = get(child_name, JSON_STRING); if (val) return val->value.toString(); - FLOG("String '%s' missing from node", child_name); + ERROR_LOG(IO, "String '%s' missing from node", child_name); return nullptr; } diff --git a/ext/native/json/json_reader.h b/Common/Data/Format/JSONReader.h similarity index 92% rename from ext/native/json/json_reader.h rename to Common/Data/Format/JSONReader.h index a18915f488..60cc78cfb9 100644 --- a/ext/native/json/json_reader.h +++ b/Common/Data/Format/JSONReader.h @@ -1,9 +1,10 @@ +#include #include #include -#include "base/basictypes.h" -#include "base/logging.h" #include "ext/gason/gason.h" +#include "Common/Common.h" +#include "Common/Log.h" namespace json { @@ -72,7 +73,7 @@ private: char *error_pos; int status = jsonParse(buffer_, &error_pos, &root_, alloc_); if (status != JSON_OK) { - ELOG("Error at (%i): %s\n%s\n\n", (int)(error_pos - buffer_), jsonStrError(status), error_pos); + ERROR_LOG(IO, "Error at (%i): %s\n%s\n\n", (int)(error_pos - buffer_), jsonStrError(status), error_pos); return false; } ok_ = true; diff --git a/ext/native/json/json_writer.cpp b/Common/Data/Format/JSONWriter.cpp similarity index 99% rename from ext/native/json/json_writer.cpp rename to Common/Data/Format/JSONWriter.cpp index 7440cf731d..3d0801be94 100644 --- a/ext/native/json/json_writer.cpp +++ b/Common/Data/Format/JSONWriter.cpp @@ -2,8 +2,8 @@ #include #include -#include "json/json_reader.h" -#include "json/json_writer.h" +#include "Common/Data/Format/JSONReader.h" +#include "Common/Data/Format/JSONWriter.h" namespace json { diff --git a/ext/native/json/json_writer.h b/Common/Data/Format/JSONWriter.h similarity index 100% rename from ext/native/json/json_writer.h rename to Common/Data/Format/JSONWriter.h diff --git a/Common/Data/Format/PNGLoad.cpp b/Common/Data/Format/PNGLoad.cpp new file mode 100644 index 0000000000..7c5baf0e75 --- /dev/null +++ b/Common/Data/Format/PNGLoad.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +#include "Common/Data/Format/PNGLoad.h" +#include "Common/Log.h" + +// *image_data_ptr should be deleted with free() +// return value of 1 == success. +int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_data_ptr) { + png_image png; + memset(&png, 0, sizeof(png)); + png.version = PNG_IMAGE_VERSION; + + png_image_begin_read_from_file(&png, file); + + if (PNG_IMAGE_FAILED(png)) + { + ERROR_LOG(IO, "pngLoad: %s", png.message); + return 0; + } + *pwidth = png.width; + *pheight = png.height; + png.format = PNG_FORMAT_RGBA; + + int stride = PNG_IMAGE_ROW_STRIDE(png); + *image_data_ptr = (unsigned char *)malloc(PNG_IMAGE_SIZE(png)); + png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL); + return 1; +} + +int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, int *pheight, unsigned char **image_data_ptr) { + png_image png{}; + png.version = PNG_IMAGE_VERSION; + + png_image_begin_read_from_memory(&png, input_ptr, input_len); + + if (PNG_IMAGE_FAILED(png)) { + ERROR_LOG(IO, "pngLoad: %s", png.message); + return 0; + } + *pwidth = png.width; + *pheight = png.height; + png.format = PNG_FORMAT_RGBA; + + int stride = PNG_IMAGE_ROW_STRIDE(png); + + size_t size = PNG_IMAGE_SIZE(png); + if (!size) { + ERROR_LOG(IO, "pngLoad: empty image"); + return 0; + } + + *image_data_ptr = (unsigned char *)malloc(size); + png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL); + return 1; +} diff --git a/ext/native/image/png_load.h b/Common/Data/Format/PNGLoad.h similarity index 65% rename from ext/native/image/png_load.h rename to Common/Data/Format/PNGLoad.h index bae14c210e..48eaf6a1db 100644 --- a/ext/native/image/png_load.h +++ b/Common/Data/Format/PNGLoad.h @@ -4,9 +4,9 @@ // *image_data_ptr should be deleted with free() // return value of 1 == success. int pngLoad(const char *file, int *pwidth, - int *pheight, unsigned char **image_data_ptr, bool flip); + int *pheight, unsigned char **image_data_ptr); int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, - int *pheight, unsigned char **image_data_ptr, bool flip); + int *pheight, unsigned char **image_data_ptr); #endif // _PNG_LOAD_H diff --git a/ext/native/file/chunk_file.cpp b/Common/Data/Format/RIFF.cpp similarity index 85% rename from ext/native/file/chunk_file.cpp rename to Common/Data/Format/RIFF.cpp index 4cd4e5157c..2b6056a125 100644 --- a/ext/native/file/chunk_file.cpp +++ b/Common/Data/Format/RIFF.cpp @@ -1,9 +1,7 @@ -#include "base/logging.h" -#include "file/chunk_file.h" -#include "file/zip_read.h" -#include "file/file_util.h" +#include #include "Common/Log.h" +#include "Common/Data/Format/RIFF.h" inline uint32_t flipID(uint32_t id) { return ((id >> 24) & 0xFF) | ((id >> 8) & 0xFF00) | ((id << 8) & 0xFF0000) | ((id << 24) & 0xFF000000); @@ -30,7 +28,6 @@ int RIFFReader::ReadInt() { return 0; } -// let's get into the business bool RIFFReader::Descend(uint32_t intoId) { if (depth_ > 30) return false; @@ -49,7 +46,7 @@ bool RIFFReader::Descend(uint32_t intoId) { int startLocation = pos_; if (pos_ + length > fileSize_) { - ERROR_LOG(SYSTEM, "Block extends outside of RIFF file - failing descend"); + ERROR_LOG(IO, "Block extends outside of RIFF file - failing descend"); pos_ = stack[depth_].parentStartLocation; return false; } @@ -64,7 +61,7 @@ bool RIFFReader::Descend(uint32_t intoId) { if (length > 0) { pos_ += length; // try next block } else { - ERROR_LOG(SYSTEM, "Bad data in RIFF file : block length %d. Not descending.", length); + ERROR_LOG(IO, "Bad data in RIFF file : block length %d. Not descending.", length); pos_ = stack[depth_].parentStartLocation; return false; } @@ -84,7 +81,6 @@ bool RIFFReader::Descend(uint32_t intoId) { return true; } -// let's ascend out void RIFFReader::Ascend() { // ascend, and restore information depth_--; @@ -92,7 +88,6 @@ void RIFFReader::Ascend() { eof_ = stack[depth_].parentEOF; } -// read a block void RIFFReader::ReadData(void *what, int count) { memcpy(what, data_ + pos_, count); pos_ += count; diff --git a/ext/native/file/chunk_file.h b/Common/Data/Format/RIFF.h similarity index 78% rename from ext/native/file/chunk_file.h rename to Common/Data/Format/RIFF.h index 18d8a80e8b..0e0dbee623 100644 --- a/ext/native/file/chunk_file.h +++ b/Common/Data/Format/RIFF.h @@ -1,7 +1,7 @@ #pragma once -// RIFF file format reader/writer. Very old code, basically a total mess but it still works. -// Has nothing to do with the ChunkFile.h used in Dolphin or PPSSPP. +// Simple RIFF file format reader. +// Unrelated to the ChunkFile.h used in Dolphin and PPSSPP. // TO REMEMBER WHEN USING: @@ -10,7 +10,6 @@ // otherwise the scheme breaks. #include -#include #include class RIFFReader { diff --git a/ext/native/image/zim_load.cpp b/Common/Data/Format/ZIMLoad.cpp similarity index 74% rename from ext/native/image/zim_load.cpp rename to Common/Data/Format/ZIMLoad.cpp index 2b9f097d72..45f23e2857 100644 --- a/ext/native/image/zim_load.cpp +++ b/Common/Data/Format/ZIMLoad.cpp @@ -1,12 +1,13 @@ -#include -#include -#include +#include +#include +#include -#include "base/logging.h" #include "zlib.h" -#include "image/zim_load.h" -#include "math/math_util.h" -#include "file/vfs.h" + +#include "Common/Log.h" +#include "Common/Data/Format/ZIMLoad.h" +#include "Common/Math/math_util.h" +#include "Common/File/VFS/VFS.h" int ezuncompress(unsigned char* pDest, long* pnDestLen, const unsigned char* pSrc, long nSrcLen) { z_stream stream; @@ -49,7 +50,7 @@ int ezuncompress(unsigned char* pDest, long* pnDestLen, const unsigned char* pSr int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int *flags, uint8_t **image) { if (zim[0] != 'Z' || zim[1] != 'I' || zim[2] != 'M' || zim[3] != 'G') { - ELOG("Not a ZIM file"); + ERROR_LOG(IO, "Not a ZIM file"); return 0; } memcpy(width, zim + 4, 4); @@ -76,15 +77,14 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int image_data_size[i] = width[i] * height[i] * 2; break; default: - ELOG("Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK); + ERROR_LOG(IO, "Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK); return 0; } total_data_size += image_data_size[i]; } - if (total_data_size == 0) - { - ELOG("Invalid ZIM data size 0"); + if (total_data_size == 0) { + ERROR_LOG(IO, "Invalid ZIM data size 0"); return 0; } @@ -95,18 +95,21 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int if (*flags & ZIM_ZLIB_COMPRESSED) { long outlen = (long)total_data_size; - if (Z_OK != ezuncompress(*image, &outlen, (unsigned char *)(zim + 16), (long)datasize - 16)) { + int retcode = ezuncompress(*image, &outlen, (unsigned char *)(zim + 16), (long)datasize - 16); + if (Z_OK != retcode) { + ERROR_LOG(IO, "ZIM zlib format decompression failed: %d", retcode); free(*image); *image = 0; return 0; } if (outlen != total_data_size) { - ELOG("Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size); + // Shouldn't happen if return value was Z_OK. + ERROR_LOG(IO, "Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size); } } else { memcpy(*image, zim + 16, datasize - 16); if (datasize - 16 != (size_t)total_data_size) { - ELOG("Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size); + ERROR_LOG(IO, "Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size); } } return num_levels; @@ -116,11 +119,13 @@ int LoadZIM(const char *filename, int *width, int *height, int *format, uint8_t size_t size; uint8_t *buffer = VFSReadFile(filename, &size); if (!buffer) { + ERROR_LOG(IO, "Couldn't read data for '%s'", buffer); return 0; } + int retval = LoadZIMPtr(buffer, (int)size, width, height, format, image); if (!retval) { - ELOG("Not a valid ZIM file: %s", filename); + ERROR_LOG(IO, "Not a valid ZIM file: %s (size: %d bytes)", filename, (int)size); } delete [] buffer; return retval; diff --git a/ext/native/image/zim_load.h b/Common/Data/Format/ZIMLoad.h similarity index 98% rename from ext/native/image/zim_load.h rename to Common/Data/Format/ZIMLoad.h index ccec2d71b9..18354bc6d6 100644 --- a/ext/native/image/zim_load.h +++ b/Common/Data/Format/ZIMLoad.h @@ -1,6 +1,6 @@ #pragma once -#include "base/basictypes.h" +#include // LoadZIM's responsibility: // * Parse the ZIM format diff --git a/ext/native/image/zim_save.cpp b/Common/Data/Format/ZIMSave.cpp similarity index 93% rename from ext/native/image/zim_save.cpp rename to Common/Data/Format/ZIMSave.cpp index 93dd945b67..4f5fb230c6 100644 --- a/ext/native/image/zim_save.cpp +++ b/Common/Data/Format/ZIMSave.cpp @@ -1,10 +1,13 @@ -#include -#include -#include -#include "base/logging.h" -#include "image/zim_save.h" +#include +#include +#include + #include "zlib.h" +#include "Common/Log.h" +#include "Common/Data/Format/ZIMLoad.h" +#include "Common/Data/Format/ZIMSave.h" + static const char magic[5] = "ZIMG"; /*int num_levels = 1; @@ -75,8 +78,6 @@ bool ispowerof2 (int x) { return true; } - - void Convert(const uint8_t *image_data, int width, int height, int pitch, int flags, uint8_t **data, int *data_size) { // For 4444 and 565. Ordered dither matrix. looks really surprisingly good on cell phone screens at 4444. @@ -141,7 +142,7 @@ void Convert(const uint8_t *image_data, int width, int height, int pitch, int fl break; default: - ELOG("Unhandled ZIM format %i", flags & ZIM_FORMAT_MASK); + ERROR_LOG(IO, "Unhandled ZIM format %d", flags & ZIM_FORMAT_MASK); *data = 0; *data_size = 0; return; @@ -155,10 +156,10 @@ uint8_t *DownsampleBy2(const uint8_t *image, int width, int height, int pitch) { int degamma[256]; int gamma[32768]; for (int i =0; i < 256; i++) { - degamma[i] = powf((float)i / 255.0f, 1.0f/2.2f) * 8191.0f; + degamma[i] = (int)(powf((float)i / 255.0f, 1.0f/2.2f) * 8191.0f); } for (int i = 0; i < 32768; i++) { - gamma[i] = powf((float)i / 32764.0f, 2.2f) * 255.0f; + gamma[i] = (int)(powf((float)i / 32764.0f, 2.2f) * 255.0f); } // Really stupid mipmap downsampling - at least it does gamma though. @@ -197,7 +198,7 @@ void SaveZIM(FILE *f, int width, int height, int pitch, int flags, const uint8_t if (Z_OK == ezcompress(dest, &dest_len, data, data_size)) { fwrite(dest, 1, dest_len, f); } else { - ELOG("Zlib compression failed.\n"); + ERROR_LOG(IO, "Zlib compression failed.\n"); } delete [] dest; } else { diff --git a/ext/native/image/zim_save.h b/Common/Data/Format/ZIMSave.h similarity index 80% rename from ext/native/image/zim_save.h rename to Common/Data/Format/ZIMSave.h index 3fe5c2f68a..90158d3d55 100644 --- a/ext/native/image/zim_save.h +++ b/Common/Data/Format/ZIMSave.h @@ -1,9 +1,10 @@ #pragma once #include +#include -#include "base/basictypes.h" -#include "image/zim_load.h" +// For the type enums etc. +#include "Common/Data/Format/ZIMLoad.h" // SaveZIM's responsibility: // * Write the ZIM format diff --git a/ext/native/util/hash/hash.cpp b/Common/Data/Hash/Hash.cpp similarity index 93% rename from ext/native/util/hash/hash.cpp rename to Common/Data/Hash/Hash.cpp index 3bb840f84d..d19e1a1e00 100644 --- a/ext/native/util/hash/hash.cpp +++ b/Common/Data/Hash/Hash.cpp @@ -1,5 +1,5 @@ -#include "base/basictypes.h" -#include "util/hash/hash.h" +#include +#include "Common/Data/Hash/Hash.h" namespace hash { diff --git a/ext/native/util/hash/hash.h b/Common/Data/Hash/Hash.h similarity index 64% rename from ext/native/util/hash/hash.h rename to Common/Data/Hash/Hash.h index 2f7e4305b6..cd4a194a46 100644 --- a/ext/native/util/hash/hash.h +++ b/Common/Data/Hash/Hash.h @@ -1,10 +1,7 @@ -#ifndef _UTIL_HASH_HASH_H -#define _UTIL_HASH_HASH_H +#pragma once #include -#include "base/basictypes.h" - namespace hash { // Fairly decent function for hashing strings. @@ -12,4 +9,3 @@ uint32_t Adler32(const uint8_t *data, size_t len); } // namespace hash -#endif diff --git a/ext/native/util/random/rng.h b/Common/Data/Random/Rng.h similarity index 98% rename from ext/native/util/random/rng.h rename to Common/Data/Random/Rng.h index 0a5960fa70..50ec4ea60e 100644 --- a/ext/native/util/random/rng.h +++ b/Common/Data/Random/Rng.h @@ -1,6 +1,6 @@ #pragma once -#include "base/basictypes.h" +#include // George Marsaglia-style random number generator. class GMRng { diff --git a/ext/native/i18n/i18n.cpp b/Common/Data/Text/I18n.cpp similarity index 82% rename from ext/native/i18n/i18n.cpp rename to Common/Data/Text/I18n.cpp index eb823dc2b9..72e16a6eb6 100644 --- a/ext/native/i18n/i18n.cpp +++ b/Common/Data/Text/I18n.cpp @@ -1,7 +1,8 @@ -#include "base/logging.h" -#include "i18n/i18n.h" -#include "file/ini_file.h" -#include "file/vfs.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Format/IniFile.h" +#include "Common/File/VFS/VFS.h" + +#include "Common/StringUtils.h" I18NRepo i18nrepo; @@ -31,7 +32,7 @@ const char *I18NCategory::T(const char *key, const char *def) { auto iter = map_.find(modifiedKey); if (iter != map_.end()) { -// ILOG("translation key found in %s: %s", name_.c_str(), key); +// INFO_LOG(SYSTEM, "translation key found in %s: %s", name_.c_str(), key); return iter->second.text.c_str(); } else { std::lock_guard guard(missedKeyLock_); @@ -39,7 +40,7 @@ const char *I18NCategory::T(const char *key, const char *def) { missedKeyLog_[key] = def; else missedKeyLog_[key] = modifiedKey.c_str(); -// ILOG("Missed translation key in %s: %s", name_.c_str(), key); +// INFO_LOG(SYSTEM, "Missed translation key in %s: %s", name_.c_str(), key); return def ? def : key; } } @@ -49,7 +50,7 @@ void I18NCategory::SetMap(const std::map &m) { if (map_.find(iter->first) == map_.end()) { std::string text = ReplaceAll(iter->second, "\\n", "\n"); map_[iter->first] = I18NEntry(text); -// ILOG("Language entry: %s -> %s", iter->first.c_str(), text.c_str()); +// INFO_LOG(SYSTEM, "Language entry: %s -> %s", iter->first.c_str(), text.c_str()); } } } @@ -83,7 +84,7 @@ bool I18NRepo::LoadIni(const std::string &languageID, const std::string &overrid IniFile ini; std::string iniPath; -// ILOG("Loading lang ini %s", iniPath.c_str()); +// INFO_LOG(SYSTEM, "Loading lang ini %s", iniPath.c_str()); if (!overridePath.empty()) { iniPath = overridePath + languageID + ".ini"; } else { @@ -95,7 +96,7 @@ bool I18NRepo::LoadIni(const std::string &languageID, const std::string &overrid Clear(); - const std::vector §ions = ini.Sections(); + const std::vector
§ions = ini.Sections(); std::lock_guard guard(catsLock_); for (auto iter = sections.begin(); iter != sections.end(); ++iter) { @@ -108,7 +109,7 @@ bool I18NRepo::LoadIni(const std::string &languageID, const std::string &overrid return true; } -I18NCategory *I18NRepo::LoadSection(const IniFile::Section *section, const char *name) { +I18NCategory *I18NRepo::LoadSection(const Section *section, const char *name) { I18NCategory *cat = new I18NCategory(this, name); std::map sectionMap = section->ToMap(); cat->SetMap(sectionMap); @@ -123,13 +124,13 @@ void I18NRepo::SaveIni(const std::string &languageID) { std::lock_guard guard(catsLock_); for (auto iter = cats_.begin(); iter != cats_.end(); ++iter) { std::string categoryName = iter->first; - IniFile::Section *section = ini.GetOrCreateSection(categoryName.c_str()); + Section *section = ini.GetOrCreateSection(categoryName.c_str()); SaveSection(ini, section, iter->second); } ini.Save(GetIniPath(languageID)); } -void I18NRepo::SaveSection(IniFile &ini, IniFile::Section *section, std::shared_ptr cat) { +void I18NRepo::SaveSection(IniFile &ini, Section *section, std::shared_ptr cat) { const std::map &missed = cat->Missed(); for (auto iter = missed.begin(); iter != missed.end(); ++iter) { diff --git a/ext/native/i18n/i18n.h b/Common/Data/Text/I18n.h similarity index 92% rename from ext/native/i18n/i18n.h rename to Common/Data/Text/I18n.h index bc4e3ca4bf..f8493d1b99 100644 --- a/ext/native/i18n/i18n.h +++ b/Common/Data/Text/I18n.h @@ -14,12 +14,13 @@ #include #include -#include "base/stringutil.h" -#include "file/ini_file.h" +#include "Common/Common.h" // Reasonably thread safe. class I18NRepo; +class IniFile; +class Section; struct I18NEntry { I18NEntry(const std::string &t) : text(t), readFlag(false) {} @@ -90,8 +91,8 @@ public: private: std::string GetIniPath(const std::string &languageID) const; void Clear(); - I18NCategory *LoadSection(const IniFile::Section *section, const char *name); - void SaveSection(IniFile &ini, IniFile::Section *section, std::shared_ptr cat); + I18NCategory *LoadSection(const Section *section, const char *name); + void SaveSection(IniFile &ini, Section *section, std::shared_ptr cat); mutable std::mutex catsLock_; std::map> cats_; diff --git a/Common/Data/Text/Parsers.cpp b/Common/Data/Text/Parsers.cpp new file mode 100644 index 0000000000..ab7c057339 --- /dev/null +++ b/Common/Data/Text/Parsers.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +#include "Common/Data/Text/Parsers.h" + +#include "Common/StringUtils.h" + +bool Version::ParseVersionString(std::string str) { + if (str.empty()) + return false; + if (str[0] == 'v') + str = str.substr(1); + if (3 != sscanf(str.c_str(), "%i.%i.%i", &major, &minor, &sub)) { + sub = 0; + if (2 != sscanf(str.c_str(), "%i.%i", &major, &minor)) + return false; + } + return true; +} + +std::string Version::ToString() const { + char temp[128]; + sprintf(temp, "%i.%i.%i", major, minor, sub); + return std::string(temp); +} + +int Version::ToInteger() const { + // This allows for ~2000 major versions, ~100 minor versions, and ~10000 sub versions. + return major * 1000000 + minor * 10000 + sub; +} + +bool ParseMacAddress(std::string str, uint8_t macAddr[6]) { + unsigned int mac[6]; + if (6 != sscanf(str.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])) { + return false; + } + for (int i = 0; i < 6; i++) { + macAddr[i] = mac[i]; + } + return true; +} + +bool TryParse(const std::string &str, uint32_t *const output) { + char *endptr = NULL; + + // Holy crap this is ugly. + + // Reset errno to a value other than ERANGE + errno = 0; + + unsigned long value = strtoul(str.c_str(), &endptr, 0); + + if (!endptr || *endptr) + return false; + + if (errno == ERANGE) + return false; + + if (ULONG_MAX > UINT_MAX) { +#ifdef _MSC_VER +#pragma warning (disable:4309) +#endif + // Note: The typecasts avoid GCC warnings when long is 32 bits wide. + if (value >= static_cast(0x100000000ull) + && value <= static_cast(0xFFFFFFFF00000000ull)) + return false; + } + + *output = static_cast(value); + return true; +} + +bool TryParse(const std::string &str, bool *const output) { + if ("1" == str || !strcasecmp("true", str.c_str())) + *output = true; + else if ("0" == str || !strcasecmp("false", str.c_str())) + *output = false; + else + return false; + + return true; +} diff --git a/ext/native/util/text/parsers.h b/Common/Data/Text/Parsers.h similarity index 73% rename from ext/native/util/text/parsers.h rename to Common/Data/Text/Parsers.h index fbf2c36d99..909e667178 100644 --- a/ext/native/util/text/parsers.h +++ b/Common/Data/Text/Parsers.h @@ -1,8 +1,8 @@ #pragma once #include - -#include "base/basictypes.h" +#include +#include #undef major #undef minor @@ -53,4 +53,19 @@ private: bool ParseVersionString(std::string str); }; -bool ParseMacAddress(std::string str, uint8_t macAddr[6]); \ No newline at end of file +bool ParseMacAddress(std::string str, uint8_t macAddr[6]); + +bool TryParse(const std::string &str, bool *const output); +bool TryParse(const std::string &str, uint32_t *const output); + +template +static bool TryParse(const std::string &str, N *const output) { + std::istringstream iss(str); + + N tmp = 0; + if (iss >> tmp) { + *output = tmp; + return true; + } else + return false; +} diff --git a/ext/native/util/text/wrap_text.cpp b/Common/Data/Text/WrapText.cpp similarity index 96% rename from ext/native/util/text/wrap_text.cpp rename to Common/Data/Text/WrapText.cpp index c052056034..c88628acf5 100644 --- a/ext/native/util/text/wrap_text.cpp +++ b/Common/Data/Text/WrapText.cpp @@ -1,7 +1,7 @@ #include -#include "gfx_es2/draw_buffer.h" -#include "util/text/utf8.h" -#include "util/text/wrap_text.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Text/WrapText.h" bool WordWrapper::IsCJK(uint32_t c) { if (c < 0x1000) { @@ -143,6 +143,10 @@ void WordWrapper::Wrap() { // First, let's check if it fits as-is. size_t len = strlen(str_); + + // We know it'll be approximately this size. It's fine if the guess is a little off. + out_.reserve(len + len / 16); + if (MeasureWidth(str_, len) <= maxW_) { // If it fits, we don't need to go through each character. out_ = str_; diff --git a/ext/native/util/text/wrap_text.h b/Common/Data/Text/WrapText.h similarity index 100% rename from ext/native/util/text/wrap_text.h rename to Common/Data/Text/WrapText.h diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp new file mode 100644 index 0000000000..8232b4ba9e --- /dev/null +++ b/Common/ExceptionHandlerSetup.cpp @@ -0,0 +1,342 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +// The corresponding file is called MemTools in the Dolphin project. + +#include "ppsspp_config.h" + +#include +#include +#include +#include +#include + +#include "Common/CommonFuncs.h" +#include "Common/CommonTypes.h" +#include "Common/Log.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/MachineContext.h" +#include "Common/ExceptionHandlerSetup.h" + +static BadAccessHandler g_badAccessHandler; +static void *altStack = nullptr; + +#ifdef MACHINE_CONTEXT_SUPPORTED + +// We cannot handle exceptions in UWP builds. Bleh. +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) + +static PVOID g_vectoredExceptionHandle; + +static LONG NTAPI GlobalExceptionHandler(PEXCEPTION_POINTERS pPtrs) { + switch (pPtrs->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + { + int accessType = (int)pPtrs->ExceptionRecord->ExceptionInformation[0]; + if (accessType == 8) { // Rule out DEP + return (DWORD)EXCEPTION_CONTINUE_SEARCH; + } + + // virtual address of the inaccessible data + uintptr_t badAddress = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1]; + CONTEXT* ctx = pPtrs->ContextRecord; + + if (g_badAccessHandler(badAddress, ctx)) { + return (DWORD)EXCEPTION_CONTINUE_EXECUTION; + } else { + // Let's not prevent debugging. + return (DWORD)EXCEPTION_CONTINUE_SEARCH; + } + } + + case EXCEPTION_STACK_OVERFLOW: + // Dolphin has some handling of this for the RET optimization emulation. + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_ILLEGAL_INSTRUCTION: + // No SSE support? Or simply bad codegen? + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_PRIV_INSTRUCTION: + // okay, dynarec codegen is obviously broken. + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_IN_PAGE_ERROR: + // okay, something went seriously wrong, out of memory? + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_BREAKPOINT: + // might want to do something fun with this one day? + return EXCEPTION_CONTINUE_SEARCH; + + default: + return EXCEPTION_CONTINUE_SEARCH; + } +} + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + if (g_vectoredExceptionHandle) { + g_badAccessHandler = badAccessHandler; + return; + } + + INFO_LOG(SYSTEM, "Installing exception handler"); + g_badAccessHandler = badAccessHandler; + g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, GlobalExceptionHandler); +} + +void UninstallExceptionHandler() { + if (g_vectoredExceptionHandle) { + RemoveVectoredExceptionHandler(g_vectoredExceptionHandle); + INFO_LOG(SYSTEM, "Removed exception handler"); + g_vectoredExceptionHandle = nullptr; + } + g_badAccessHandler = nullptr; +} + +#elif defined(__APPLE__) + +static void CheckKR(const char* name, kern_return_t kr) { + _assert_msg_(kr == 0, "%s failed: kr=%x", name, kr); +} + +static void ExceptionThread(mach_port_t port) { + setCurrentThreadName("Mach exception thread"); +#pragma pack(4) + struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[x86_THREAD_STATE64_COUNT]; + mach_msg_trailer_t trailer; + } msg_in; + + struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[x86_THREAD_STATE64_COUNT]; + } msg_out; +#pragma pack() + memset(&msg_in, 0xee, sizeof(msg_in)); + memset(&msg_out, 0xee, sizeof(msg_out)); + mach_msg_header_t* send_msg = nullptr; + mach_msg_size_t send_size = 0; + mach_msg_option_t option = MACH_RCV_MSG; + while (true) { + // If this isn't the first run, send the reply message. Then, receive + // a message: either a mach_exception_raise_state RPC due to + // thread_set_exception_ports, or MACH_NOTIFY_NO_SENDERS due to + // mach_port_request_notification. + CheckKR("mach_msg_overwrite", + mach_msg_overwrite(send_msg, option, send_size, sizeof(msg_in), port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)); + + if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS) { + // the other thread exited + mach_port_destroy(mach_task_self(), port); + return; + } + + _assert_msg_(msg_in.Head.msgh_id == 2406, "unknown message received"); + _assert_msg_(msg_in.flavor == x86_THREAD_STATE64, "unknown flavor %d (expected %d)", msg_in.flavor, x86_THREAD_STATE64); + + x86_thread_state64_t* state = (x86_thread_state64_t*)msg_in.old_state; + + bool ok = g_badAccessHandler((uintptr_t)msg_in.code[1], state); + + // Set up the reply. + msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); + msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port; + msg_out.Head.msgh_local_port = MACH_PORT_NULL; + msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100; + msg_out.NDR = msg_in.NDR; + if (ok) { + msg_out.RetCode = KERN_SUCCESS; + msg_out.flavor = x86_THREAD_STATE64; + msg_out.new_stateCnt = x86_THREAD_STATE64_COUNT; + memcpy(msg_out.new_state, msg_in.old_state, x86_THREAD_STATE64_COUNT * sizeof(natural_t)); + } else { + // Pass the exception to the next handler (debugger or crash). + msg_out.RetCode = KERN_FAILURE; + msg_out.flavor = 0; + msg_out.new_stateCnt = 0; + } + msg_out.Head.msgh_size = + offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t); + + send_msg = &msg_out.Head; + send_size = msg_out.Head.msgh_size; + option |= MACH_SEND_MSG; + } +} + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + if (g_badAccessHandler) { + // The rest of the setup we don't need to do again. + g_badAccessHandler = badAccessHandler; + return; + } + g_badAccessHandler = badAccessHandler; + + INFO_LOG(SYSTEM, "Installing exception handler"); + mach_port_t port; + CheckKR("mach_port_allocate", + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)); + std::thread exc_thread(ExceptionThread, port); + exc_thread.detach(); + // Obtain a send right for thread_set_exception_ports to copy... + CheckKR("mach_port_insert_right", + mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)); + // Mach tries the following exception ports in order: thread, task, host. + // Debuggers set the task port, so we grab the thread port. + CheckKR("thread_set_exception_ports", + thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, port, + EXCEPTION_STATE | MACH_EXCEPTION_CODES, x86_THREAD_STATE64)); + // ...and get rid of our copy so that MACH_NOTIFY_NO_SENDERS works. + CheckKR("mach_port_mod_refs", + mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)); + mach_port_t previous; + CheckKR("mach_port_request_notification", + mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)); +} + +void UninstallExceptionHandler() { +} + +#else + +static struct sigaction old_sa_segv; +static struct sigaction old_sa_bus; + +static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { + if (sig != SIGSEGV && sig != SIGBUS) { + // We are not interested in other signals - handle it as usual. + return; + } + ucontext_t* context = (ucontext_t*)raw_context; + int sicode = info->si_code; + if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR) { + // Huh? Return. + return; + } + uintptr_t bad_address = (uintptr_t)info->si_addr; + + // Get all the information we can out of the context. +#ifdef __OpenBSD__ + ucontext_t* ctx = context; +#else + mcontext_t* ctx = &context->uc_mcontext; +#endif + // assume it's not a write + if (!g_badAccessHandler(bad_address, +#ifdef __APPLE__ + *ctx +#else + ctx +#endif + )) { + // retry and crash + // According to the sigaction man page, if sa_flags "SA_SIGINFO" is set to the sigaction + // function pointer, otherwise sa_handler contains one of: + // SIG_DEF: The 'default' action is performed + // SIG_IGN: The signal is ignored + // Any other value is a function pointer to a signal handler + + struct sigaction* old_sa; + if (sig == SIGSEGV) { + old_sa = &old_sa_segv; + } else { + old_sa = &old_sa_bus; + } + + if (old_sa->sa_flags & SA_SIGINFO) { + old_sa->sa_sigaction(sig, info, raw_context); + return; + } + if (old_sa->sa_handler == SIG_DFL) { + signal(sig, SIG_DFL); + return; + } + if (old_sa->sa_handler == SIG_IGN) { + // Ignore signal + return; + } + old_sa->sa_handler(sig); + } +} + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + if (!badAccessHandler) { + return; + } + if (g_badAccessHandler) { + g_badAccessHandler = badAccessHandler; + return; + } + + INFO_LOG(SYSTEM, "Installed exception handler"); + g_badAccessHandler = badAccessHandler; + + stack_t signal_stack{}; + altStack = malloc(SIGSTKSZ); +#ifdef __FreeBSD__ + signal_stack.ss_sp = (char*)altStack; +#else + signal_stack.ss_sp = altStack; +#endif + signal_stack.ss_size = SIGSTKSZ; + signal_stack.ss_flags = 0; + if (sigaltstack(&signal_stack, nullptr)) { + _assert_msg_(false, "sigaltstack failed"); + } + struct sigaction sa{}; + sa.sa_handler = nullptr; + sa.sa_sigaction = &sigsegv_handler; + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigemptyset(&sa.sa_mask); + sigaction(SIGSEGV, &sa, &old_sa_segv); +#ifdef __APPLE__ + sigaction(SIGBUS, &sa, &old_sa_bus); +#endif +} + +void UninstallExceptionHandler() { + if (!g_badAccessHandler) { + return; + } + stack_t signal_stack{}; + signal_stack.ss_flags = SS_DISABLE; + if (0 != sigaltstack(&signal_stack, nullptr)) { + ERROR_LOG(SYSTEM, "Could not remove signal altstack"); + } + if (altStack) { + free(altStack); + altStack = nullptr; + } + sigaction(SIGSEGV, &old_sa_segv, nullptr); +#ifdef __APPLE__ + sigaction(SIGBUS, &old_sa_bus, nullptr); +#endif + INFO_LOG(SYSTEM, "Uninstalled exception handler"); + g_badAccessHandler = nullptr; +} + +#endif + +#else // !MACHINE_CONTEXT_SUPPORTED + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + ERROR_LOG(SYSTEM, "Exception handler not implemented on this platform, can't install"); +} +void UninstallExceptionHandler() { } + +#endif // MACHINE_CONTEXT_SUPPORTED diff --git a/Common/ExceptionHandlerSetup.h b/Common/ExceptionHandlerSetup.h new file mode 100644 index 0000000000..8f88176e0e --- /dev/null +++ b/Common/ExceptionHandlerSetup.h @@ -0,0 +1,17 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +// On Windows, context is a CONTEXT object. +// On Apple, context is a x86_thread_state64_t. +// On Unix/Linux, context is a mcontext_t. +// On OpenBSD, context is a ucontext_t. +// Ugh, might need to abstract this better. +typedef bool (*BadAccessHandler)(uintptr_t address, void *context); + +void InstallExceptionHandler(BadAccessHandler accessHandler); +void UninstallExceptionHandler(); diff --git a/Common/FakeCPUDetect.cpp b/Common/FakeCPUDetect.cpp index 41251b698a..e110f0cdc0 100644 --- a/Common/FakeCPUDetect.cpp +++ b/Common/FakeCPUDetect.cpp @@ -15,10 +15,10 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#include +#include +#include -#include -#include "base/logging.h" -#include "base/basictypes.h" #include "Common.h" #include "CPUDetect.h" #include "StringUtils.h" diff --git a/Common/FakeEmitter.h b/Common/FakeEmitter.h index 25ef39b419..6b827655c8 100644 --- a/Common/FakeEmitter.h +++ b/Common/FakeEmitter.h @@ -24,7 +24,6 @@ #include #include "Common.h" -#include "MsgHandler.h" // VCVT flags #define TO_FLOAT 0 diff --git a/ext/native/file/file_util.cpp b/Common/File/DirListing.cpp similarity index 64% rename from ext/native/file/file_util.cpp rename to Common/File/DirListing.cpp index 5b1087b425..89c30e35b7 100644 --- a/ext/native/file/file_util.cpp +++ b/Common/File/DirListing.cpp @@ -4,9 +4,6 @@ #define WIN32_LEAN_AND_MEAN #include #include -#ifndef strcasecmp -#define strcasecmp _stricmp -#endif #else #include #include @@ -21,10 +18,9 @@ #include #include -#include "base/logging.h" -#include "base/basictypes.h" -#include "file/file_util.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/StringUtils.h" +#include "Common/File/DirListing.h" #if !defined(__linux__) && !defined(_WIN32) && !defined(__QNX__) #define stat64 stat @@ -37,122 +33,14 @@ #define fileno #endif // HAVE_LIBNX -FILE *openCFile(const std::string &filename, const char *mode) -{ -#if defined(_WIN32) && defined(UNICODE) - return _wfopen(ConvertUTF8ToWString(filename).c_str(), ConvertUTF8ToWString(mode).c_str()); -#else - return fopen(filename.c_str(), mode); -#endif -} - -bool writeStringToFile(bool text_file, const std::string &str, const char *filename) -{ - FILE *f = openCFile(filename, text_file ? "w" : "wb"); - if (!f) - return false; - size_t len = str.size(); - if (len != fwrite(str.data(), 1, str.size(), f)) - { - fclose(f); - return false; - } - fclose(f); - return true; -} - -bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename) -{ - FILE *f = openCFile(filename, text_file ? "w" : "wb"); - if (!f) - return false; - size_t len = size; - if (len != fwrite(data, 1, len, f)) - { - fclose(f); - return false; - } - fclose(f); - return true; -} - -uint64_t GetSize(FILE *f) -{ - // This will only support 64-bit when large file support is available. - // That won't be the case on some versions of Android, at least. -#if defined(__ANDROID__) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64) - int fd = fileno(f); - - off64_t pos = lseek64(fd, 0, SEEK_CUR); - off64_t size = lseek64(fd, 0, SEEK_END); - if (size != pos && lseek64(fd, pos, SEEK_SET) != pos) { - // Should error here. - return 0; - } - return size; -#else -#ifdef _WIN32 - uint64_t pos = _ftelli64(f); -#else - uint64_t pos = ftello(f); -#endif - if (fseek(f, 0, SEEK_END) != 0) { - return 0; - } -#ifdef _WIN32 - uint64_t size = _ftelli64(f); - // Reset the seek position to where it was when we started. - if (size != pos && _fseeki64(f, pos, SEEK_SET) != 0) { -#else - uint64_t size = ftello(f); - // Reset the seek position to where it was when we started. - if (size != pos && fseeko(f, pos, SEEK_SET) != 0) { -#endif - // Should error here. - return 0; - } - return size; -#endif -} - -bool readFileToString(bool text_file, const char *filename, std::string &str) -{ - FILE *f = openCFile(filename, text_file ? "r" : "rb"); - if (!f) - return false; - size_t len = (size_t)GetSize(f); - char *buf = new char[len + 1]; - buf[fread(buf, 1, len, f)] = 0; - str = std::string(buf, len); - fclose(f); - delete [] buf; - return true; -} - - -bool readDataFromFile(bool text_file, unsigned char* &data, const unsigned int size, const char *filename) -{ - FILE *f = openCFile(filename, text_file ? "r" : "rb"); - if (!f) - return false; - size_t len = (size_t)GetSize(f); - if(len < size) { - fclose(f); - return false; - } - data[fread(data, 1, size, f)] = 0; - fclose(f); - return true; -} - // Returns true if filename is a directory -bool isDirectory(const std::string &filename) { +bool isDirectory(const std::string & filename) { FileInfo info; getFileInfo(filename.c_str(), &info); return info.isDirectory; } -bool getFileInfo(const char *path, FileInfo *fileInfo) { +bool getFileInfo(const char *path, FileInfo * fileInfo) { // TODO: Expand relative paths? fileInfo->fullName = path; @@ -195,17 +83,17 @@ bool getFileInfo(const char *path, FileInfo *fileInfo) { return true; } -std::string getFileExtension(const std::string &fn) { +std::string getFileExtension(const std::string & fn) { int pos = (int)fn.rfind("."); if (pos < 0) return ""; - std::string ext = fn.substr(pos+1); + std::string ext = fn.substr(pos + 1); for (size_t i = 0; i < ext.size(); i++) { ext[i] = tolower(ext[i]); } return ext; } -bool FileInfo::operator <(const FileInfo &other) const { +bool FileInfo::operator <(const FileInfo & other) const { if (isDirectory && !other.isDirectory) return true; else if (!isDirectory && other.isDirectory) @@ -216,7 +104,7 @@ bool FileInfo::operator <(const FileInfo &other) const { return false; } -size_t getFilesInDir(const char *directory, std::vector *files, const char *filter, int flags) { +size_t getFilesInDir(const char *directory, std::vector * files, const char *filter, int flags) { size_t foundEntries = 0; std::set filters; if (filter) { @@ -311,7 +199,7 @@ size_t getFilesInDir(const char *directory, std::vector *files, const return foundEntries; } -int64_t getDirectoryRecursiveSize(const std::string &path, const char *filter, int flags) { +int64_t getDirectoryRecursiveSize(const std::string & path, const char *filter, int flags) { std::vector fileInfo; getFilesInDir(path.c_str(), &fileInfo, filter, flags); int64_t sizeSum = 0; @@ -337,7 +225,7 @@ std::vector getWindowsDrives() std::vector drives; const DWORD buffsize = GetLogicalDriveStrings(0, NULL); - std::vector buff(buffsize); + std::vector buff(buffsize); if (GetLogicalDriveStrings(buffsize, buff.data()) == buffsize - 1) { auto drive = buff.data(); @@ -347,7 +235,7 @@ std::vector getWindowsDrives() str.pop_back(); // we don't want the final backslash str += "/"; drives.push_back(str); - + // advance to next drive while (*drive++) {} } diff --git a/ext/native/file/file_util.h b/Common/File/DirListing.h similarity index 67% rename from ext/native/file/file_util.h rename to Common/File/DirListing.h index b6c414139b..965ca5d6bf 100644 --- a/ext/native/file/file_util.h +++ b/Common/File/DirListing.h @@ -7,13 +7,6 @@ #include -// Whole-file reading/writing -bool writeStringToFile(bool text_file, const std::string &str, const char *filename); -bool readFileToString(bool text_file, const char *filename, std::string &str); - -bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename); -bool readDataFromFile(bool text_file, unsigned char* &data, const unsigned int size, const char *filename); - // Beginnings of a directory utility system. TODO: Improve. struct FileInfo { diff --git a/ext/native/file/free.cpp b/Common/File/DiskFree.cpp similarity index 94% rename from ext/native/file/free.cpp rename to Common/File/DiskFree.cpp index 3948008057..7c571d4a3d 100644 --- a/ext/native/file/free.cpp +++ b/Common/File/DiskFree.cpp @@ -17,8 +17,7 @@ #include #endif -#include "base/basictypes.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" bool free_disk_space(const std::string &dir, uint64_t &space) { #ifdef _WIN32 diff --git a/ext/native/file/free.h b/Common/File/DiskFree.h similarity index 76% rename from ext/native/file/free.h rename to Common/File/DiskFree.h index 1c5690737e..df671fa3ed 100644 --- a/ext/native/file/free.h +++ b/Common/File/DiskFree.h @@ -1,6 +1,6 @@ #pragma once #include -#include "base/basictypes.h" +#include bool free_disk_space(const std::string &dir, uint64_t &space); diff --git a/ext/native/file/fd_util.cpp b/Common/File/FileDescriptor.cpp similarity index 84% rename from ext/native/file/fd_util.cpp rename to Common/File/FileDescriptor.cpp index 38a84f0f22..0c40ee1da7 100644 --- a/ext/native/file/fd_util.cpp +++ b/Common/File/FileDescriptor.cpp @@ -1,5 +1,4 @@ #include "ppsspp_config.h" -#include "file/fd_util.h" #include #include @@ -18,19 +17,21 @@ #endif #include -#include "base/logging.h" +#include "Common/Common.h" +#include "Common/Log.h" +#include "Common/File/FileDescriptor.h" namespace fd_util { // Slow as hell and should only be used for prototyping. // Reads from a socket, up to an '\n'. This means that if the line ends // with '\r', the '\r' will be returned. -ssize_t ReadLine(int fd, char *vptr, size_t buf_size) { +size_t ReadLine(int fd, char *vptr, size_t buf_size) { char *buffer = vptr; size_t n; for (n = 1; n < buf_size; n++) { char c; - ssize_t rc; + size_t rc; if ((rc = read(fd, &c, 1)) == 1) { *buffer++ = c; if (c == '\n') @@ -45,7 +46,7 @@ ssize_t ReadLine(int fd, char *vptr, size_t buf_size) { else { if (errno == EINTR) continue; - FLOG("Error in Readline()"); + _assert_msg_(false, "Error in Readline()"); } } @@ -54,7 +55,7 @@ ssize_t ReadLine(int fd, char *vptr, size_t buf_size) { } // Misnamed, it just writes raw data in a retry loop. -ssize_t WriteLine(int fd, const char *vptr, size_t n) { +size_t WriteLine(int fd, const char *vptr, size_t n) { const char *buffer = vptr; size_t nleft = n; @@ -64,7 +65,7 @@ ssize_t WriteLine(int fd, const char *vptr, size_t n) { if (errno == EINTR) nwritten = 0; else - FLOG("Error in Writeline()"); + _assert_msg_(false, "Error in Writeline()"); } nleft -= nwritten; buffer += nwritten; @@ -73,11 +74,11 @@ ssize_t WriteLine(int fd, const char *vptr, size_t n) { return n; } -ssize_t WriteLine(int fd, const char *buffer) { +size_t WriteLine(int fd, const char *buffer) { return WriteLine(fd, buffer, strlen(buffer)); } -ssize_t Write(int fd, const std::string &str) { +size_t Write(int fd, const std::string &str) { return WriteLine(fd, str.c_str(), str.size()); } @@ -113,7 +114,7 @@ void SetNonBlocking(int sock, bool non_blocking) { int opts = fcntl(sock, F_GETFL); if (opts < 0) { perror("fcntl(F_GETFL)"); - ELOG("Error getting socket status while changing nonblocking status"); + ERROR_LOG(IO, "Error getting socket status while changing nonblocking status"); } if (non_blocking) { opts = (opts | O_NONBLOCK); @@ -123,12 +124,12 @@ void SetNonBlocking(int sock, bool non_blocking) { if (fcntl(sock, F_SETFL, opts) < 0) { perror("fcntl(F_SETFL)"); - ELOG("Error setting socket nonblocking status"); + ERROR_LOG(IO, "Error setting socket nonblocking status"); } #else u_long val = non_blocking ? 1 : 0; if (ioctlsocket(sock, FIONBIO, &val) != 0) { - ELOG("Error setting socket nonblocking status"); + ERROR_LOG(IO, "Error setting socket nonblocking status"); } #endif } diff --git a/ext/native/file/fd_util.h b/Common/File/FileDescriptor.h similarity index 54% rename from ext/native/file/fd_util.h rename to Common/File/FileDescriptor.h index 922a50eb70..230cba88f1 100644 --- a/ext/native/file/fd_util.h +++ b/Common/File/FileDescriptor.h @@ -1,20 +1,17 @@ -#ifndef _FD_UTIL -#define _FD_UTIL +#pragma once -#include +#include #include -#include "base/basictypes.h" - namespace fd_util { // Slow as hell and should only be used for prototyping. -ssize_t ReadLine(int fd, char *buffer, size_t buf_size); +size_t ReadLine(int fd, char *buffer, size_t buf_size); // Decently fast. -ssize_t WriteLine(int fd, const char *buffer, size_t buf_size); -ssize_t WriteLine(int fd, const char *buffer); -ssize_t Write(int fd, const std::string &str); +size_t WriteLine(int fd, const char *buffer, size_t buf_size); +size_t WriteLine(int fd, const char *buffer); +size_t Write(int fd, const std::string &str); // Returns true if the fd became ready, false if it didn't or // if there was another error. @@ -25,5 +22,3 @@ void SetNonBlocking(int fd, bool non_blocking); std::string GetLocalIP(int sock); } // fd_util - -#endif // _FD_UTIL diff --git a/Common/FileUtil.cpp b/Common/File/FileUtil.cpp similarity index 86% rename from Common/FileUtil.cpp rename to Common/File/FileUtil.cpp index d1ad8a5b72..05af060d95 100644 --- a/Common/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -24,12 +24,16 @@ #include "ppsspp_config.h" +#include #include -#include "FileUtil.h" -#include "StringUtils.h" + +#include "Common/Log.h" +#include "Common/File/FileUtil.h" +#include "Common/StringUtils.h" +#include "Common/SysError.h" #ifdef _WIN32 -#include "CommonWindows.h" +#include "Common/CommonWindows.h" #include #include // for SHGetFolderPath #include @@ -57,7 +61,7 @@ #endif // !defined(IOS) #endif // __APPLE__ -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include @@ -244,8 +248,7 @@ bool IsDirectory(const std::string &filename) struct stat file_info; int result = stat(copy.c_str(), &file_info); if (result < 0) { - WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", - fn.c_str(), GetLastErrorMsg()); + WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", fn.c_str(), GetLastErrorMsg().c_str()); return false; } return S_ISDIR(file_info.st_mode); @@ -272,14 +275,13 @@ bool Delete(const std::string &filename) { #ifdef _WIN32 if (!DeleteFile(ConvertUTF8ToWString(filename).c_str())) { - WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); + WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); return false; } #else if (unlink(filename.c_str()) == -1) { WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); + filename.c_str(), GetLastErrorMsg().c_str()); return false; } #endif @@ -388,7 +390,7 @@ bool DeleteDir(const std::string &filename) if (rmdir(filename.c_str()) == 0) return true; #endif - ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg()); + ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); return false; } @@ -408,7 +410,7 @@ bool Rename(const std::string &srcFilename, const std::string &destFilename) return true; #endif ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; } @@ -427,7 +429,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) return true; #endif ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; #else @@ -441,7 +443,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) if (!input) { ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; } @@ -451,7 +453,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) { fclose(input); ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; } @@ -466,7 +468,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) { ERROR_LOG(COMMON, "Copy: failed reading from source, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); fclose(input); fclose(output); return false; @@ -479,7 +481,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) { ERROR_LOG(COMMON, "Copy: failed writing to output, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); fclose(input); fclose(output); return false; @@ -510,7 +512,7 @@ bool GetFileDetails(const std::string &filename, FileDetails *details) { if (!GetFileAttributesEx(ConvertUTF8ToWString(filename).c_str(), GetFileExInfoStandard, &attr)) return false; details->isDirectory = (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - details->size = ((u64)attr.nFileSizeHigh << 32) | (u64)attr.nFileSizeLow; + details->size = ((uint64_t)attr.nFileSizeHigh << 32) | (uint64_t)attr.nFileSizeLow; details->atime = FiletimeToStatTime(attr.ftLastAccessTime); details->mtime = FiletimeToStatTime(attr.ftLastWriteTime); details->ctime = FiletimeToStatTime(attr.ftCreationTime); @@ -587,14 +589,14 @@ std::string GetFilename(std::string path) { // Returns the size of file (64bit) // TODO: Add a way to return an error. -u64 GetFileSize(const std::string &filename) { +uint64_t GetFileSize(const std::string &filename) { #if defined(_WIN32) && defined(UNICODE) WIN32_FILE_ATTRIBUTE_DATA attr; if (!GetFileAttributesEx(ConvertUTF8ToWString(filename).c_str(), GetFileExInfoStandard, &attr)) return 0; if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return 0; - return ((u64)attr.nFileSizeHigh << 32) | (u64)attr.nFileSizeLow; + return ((uint64_t)attr.nFileSizeHigh << 32) | (uint64_t)attr.nFileSizeLow; #else #if __ANDROID__ && __ANDROID_API__ < 21 struct stat file_info; @@ -616,22 +618,43 @@ u64 GetFileSize(const std::string &filename) { #endif } -// Overloaded GetSize, accepts FILE* -u64 GetFileSize(FILE *f) { - // can't use off_t here because it can be 32-bit - u64 pos = ftello(f); - if (fseeko(f, 0, SEEK_END) != 0) { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg()); - return 0; - } - u64 size = ftello(f); - if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg()); +uint64_t GetFileSize(FILE *f) +{ + // This will only support 64-bit when large file support is available. + // That won't be the case on some versions of Android, at least. +#if defined(__ANDROID__) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64) + int fd = fileno(f); + + off64_t pos = lseek64(fd, 0, SEEK_CUR); + off64_t size = lseek64(fd, 0, SEEK_END); + if (size != pos && lseek64(fd, pos, SEEK_SET) != pos) { + // Should error here. return 0; } return size; +#else +#ifdef _WIN32 + uint64_t pos = _ftelli64(f); +#else + uint64_t pos = ftello(f); +#endif + if (fseek(f, 0, SEEK_END) != 0) { + return 0; + } +#ifdef _WIN32 + uint64_t size = _ftelli64(f); + // Reset the seek position to where it was when we started. + if (size != pos && _fseeki64(f, pos, SEEK_SET) != 0) { +#else + uint64_t size = ftello(f); + // Reset the seek position to where it was when we started. + if (size != pos && fseeko(f, pos, SEEK_SET) != 0) { +#endif + // Should error here. + return 0; + } + return size; +#endif } // creates an empty file filename, returns true on success @@ -641,8 +664,7 @@ bool CreateEmptyFile(const std::string &filename) FILE *pFile = OpenCFile(filename, "wb"); if (!pFile) { - ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", - filename.c_str(), GetLastErrorMsg()); + ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); return false; } fclose(pFile); @@ -804,7 +826,7 @@ const std::string &GetExeDirectory() sz = GetModuleFileName(nullptr, &program_path[0], (DWORD)program_path.size()); } while (sz >= program_path.size()); - TCHAR *last_slash = _tcsrchr(&program_path[0], '\\'); + const wchar_t *last_slash = wcsrchr(&program_path[0], '\\'); if (last_slash != nullptr) program_path.resize(last_slash - &program_path[0] + 1); else @@ -906,7 +928,7 @@ void IOFile::SetHandle(std::FILE* file) m_file = file; } -u64 IOFile::GetSize() +uint64_t IOFile::GetSize() { if (IsOpen()) return File::GetFileSize(m_file); @@ -914,7 +936,7 @@ u64 IOFile::GetSize() return 0; } -bool IOFile::Seek(s64 off, int origin) +bool IOFile::Seek(int64_t off, int origin) { if (!IsOpen() || 0 != fseeko(m_file, off, origin)) m_good = false; @@ -922,7 +944,7 @@ bool IOFile::Seek(s64 off, int origin) return m_good; } -u64 IOFile::Tell() +uint64_t IOFile::Tell() { if (IsOpen()) return ftello(m_file); @@ -938,7 +960,7 @@ bool IOFile::Flush() return m_good; } -bool IOFile::Resize(u64 size) +bool IOFile::Resize(uint64_t size) { if (!IsOpen() || 0 != #ifdef _WIN32 @@ -956,3 +978,74 @@ bool IOFile::Resize(u64 size) } } // namespace + +bool readFileToString(bool text_file, const char *filename, std::string & str) +{ + FILE *f = File::OpenCFile(filename, text_file ? "r" : "rb"); + if (!f) + return false; + size_t len = (size_t)File::GetFileSize(f); + char *buf = new char[len + 1]; + buf[fread(buf, 1, len, f)] = 0; + str = std::string(buf, len); + fclose(f); + delete[] buf; + return true; +} + +uint8_t *ReadLocalFile(const char *filename, size_t * size) { + FILE *file = File::OpenCFile(filename, "rb"); + if (!file) { + *size = 0; + return nullptr; + } + fseek(file, 0, SEEK_END); + size_t f_size = ftell(file); + if ((long)f_size < 0) { + *size = 0; + fclose(file); + return nullptr; + } + fseek(file, 0, SEEK_SET); + uint8_t *contents = new uint8_t[f_size + 1]; + if (fread(contents, 1, f_size, file) != f_size) { + delete[] contents; + contents = nullptr; + *size = 0; + } else { + contents[f_size] = 0; + *size = f_size; + } + fclose(file); + return contents; +} + +bool writeStringToFile(bool text_file, const std::string &str, const char *filename) +{ + FILE *f = File::OpenCFile(filename, text_file ? "w" : "wb"); + if (!f) + return false; + size_t len = str.size(); + if (len != fwrite(str.data(), 1, str.size(), f)) + { + fclose(f); + return false; + } + fclose(f); + return true; +} + +bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename) +{ + FILE *f = File::OpenCFile(filename, text_file ? "w" : "wb"); + if (!f) + return false; + size_t len = size; + if (len != fwrite(data, 1, len, f)) + { + fclose(f); + return false; + } + fclose(f); + return true; +} diff --git a/Common/FileUtil.h b/Common/File/FileUtil.h similarity index 87% rename from Common/FileUtil.h rename to Common/File/FileUtil.h index e088ceda4c..a191f554eb 100644 --- a/Common/FileUtil.h +++ b/Common/File/FileUtil.h @@ -22,8 +22,9 @@ #include #include #include +#include -#include "Common.h" +#include "Common/Common.h" #ifdef _MSC_VER inline struct tm* localtime_r(const time_t *clock, struct tm *result) { @@ -35,19 +36,9 @@ inline struct tm* localtime_r(const time_t *clock, struct tm *result) { namespace File { -// FileSystem tree node/ -struct FSTEntry -{ - bool isDirectory; - u64 size; // file length or number of entries from children - std::string physicalName; // name on disk - std::string virtualName; // name in FST names table - std::vector children; -}; - struct FileDetails { bool isDirectory; - u64 size; + uint64_t size; uint64_t atime; uint64_t mtime; uint64_t ctime; @@ -80,10 +71,10 @@ std::string GetFilename(std::string path); bool GetModifTime(const std::string &filename, tm &return_time); // Returns the size of filename (64bit) -u64 GetFileSize(const std::string &filename); +uint64_t GetFileSize(const std::string &filename); // Overloaded GetSize, accepts FILE* -u64 GetFileSize(FILE *f); +uint64_t GetFileSize(FILE *f); // Returns true if successful, or path already exists. bool CreateDir(const std::string &filename); @@ -124,13 +115,14 @@ bool SetCurrentDir(const std::string &directory); const std::string &GetExeDirectory(); + // simple wrapper for cstdlib file functions to // hopefully will make error checking easier // and make forgetting an fclose() harder class IOFile { public: IOFile(); - IOFile(std::FILE* file); + IOFile(FILE* file); IOFile(const std::string& filename, const char openmode[]); ~IOFile(); @@ -181,10 +173,10 @@ public: void SetHandle(std::FILE* file); - bool Seek(s64 off, int origin); - u64 Tell(); - u64 GetSize(); - bool Resize(u64 size); + bool Seek(int64_t off, int origin); + uint64_t Tell(); + uint64_t GetSize(); + bool Resize(uint64_t size); bool Flush(); // clear error state @@ -200,3 +192,13 @@ private: }; } // namespace + +// TODO: Refactor, this was moved from the old file_util.cpp. + +// Whole-file reading/writing +bool writeStringToFile(bool text_file, const std::string &str, const char *filename); +bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename); + +bool readFileToString(bool text_file, const char *filename, std::string &str); +// Return value must be delete[]-d. +uint8_t *ReadLocalFile(const char *filename, size_t *size); diff --git a/ext/native/file/path.cpp b/Common/File/PathBrowser.cpp similarity index 95% rename from ext/native/file/path.cpp rename to Common/File/PathBrowser.cpp index ec62c179b5..712e5a95e6 100644 --- a/ext/native/file/path.cpp +++ b/Common/File/PathBrowser.cpp @@ -1,11 +1,15 @@ #include +#include #include -#include "base/stringutil.h" -#include "base/timeutil.h" -#include "file/path.h" -#include "net/http_client.h" -#include "net/url.h" -#include "thread/threadutil.h" + +#include "Common/Net/HTTPClient.h" +#include "Common/Net/URL.h" + +#include "Common/File/PathBrowser.h" +#include "Common/StringUtils.h" +#include "Common/TimeUtil.h" +#include "Common/Log.h" +#include "Common/Thread/ThreadUtil.h" bool LoadRemoteFileList(const std::string &url, bool *cancel, std::vector &files) { http::Client http; @@ -56,7 +60,7 @@ bool LoadRemoteFileList(const std::string &url, bool *cancel, std::vector #include #include -#include +#include #include #include -#include +#include -#include "file/file_util.h" +#include "Common/File/DirListing.h" // Abstraction above path that lets you navigate easily. // "/" is a special path that means the root of the file system. On Windows, @@ -36,7 +36,7 @@ public: // Do nothing #elif defined(__linux) char *home = getenv("HOME"); - if (home != NULL && !strncmp(str.c_str(), home, strlen(home))) { + if (home != nullptr && !strncmp(str.c_str(), home, strlen(home))) { str = str.substr(strlen(home)); str.insert(0, 1, '~'); } diff --git a/ext/native/file/zip_read.cpp b/Common/File/VFS/AssetReader.cpp similarity index 58% rename from ext/native/file/zip_read.cpp rename to Common/File/VFS/AssetReader.cpp index 5069cfc223..1fec28922b 100644 --- a/ext/native/file/zip_read.cpp +++ b/Common/File/VFS/AssetReader.cpp @@ -7,9 +7,9 @@ #include #endif -#include "base/basictypes.h" -#include "base/logging.h" -#include "file/zip_read.h" +#include "Common/Common.h" +#include "Common/Log.h" +#include "Common/File/VFS/AssetReader.h" #ifdef __ANDROID__ uint8_t *ReadFromZip(zip *archive, const char* filename, size_t *size) { @@ -17,7 +17,7 @@ uint8_t *ReadFromZip(zip *archive, const char* filename, size_t *size) { struct zip_stat zstat; zip_file *file = zip_fopen(archive, filename, ZIP_FL_NOCASE|ZIP_FL_UNCHANGED); if (!file) { - ELOG("Error opening %s from ZIP", filename); + ERROR_LOG(IO, "Error opening %s from ZIP", filename); return 0; } zip_stat(archive, filename, ZIP_FL_NOCASE|ZIP_FL_UNCHANGED, &zstat); @@ -33,50 +33,22 @@ uint8_t *ReadFromZip(zip *archive, const char* filename, size_t *size) { #endif -// The return is non-const because - why not? -uint8_t *ReadLocalFile(const char *filename, size_t *size) { - FILE *file = openCFile(filename, "rb"); - if (!file) { - *size = 0; - return nullptr; - } - fseek(file, 0, SEEK_END); - size_t f_size = ftell(file); - if ((long)f_size < 0) { - *size = 0; - fclose(file); - return nullptr; - } - fseek(file, 0, SEEK_SET); - uint8_t *contents = new uint8_t[f_size+1]; - if (fread(contents, 1, f_size, file) != f_size) { - delete [] contents; - contents = nullptr; - *size = 0; - } else { - contents[f_size] = 0; - *size = f_size; - } - fclose(file); - return contents; -} - #ifdef __ANDROID__ ZipAssetReader::ZipAssetReader(const char *zip_file, const char *in_zip_path) { zip_file_ = zip_open(zip_file, 0, NULL); strcpy(in_zip_path_, in_zip_path); if (!zip_file_) { - ELOG("Failed to open %s as a zip file", zip_file); + ERROR_LOG(IO, "Failed to open %s as a zip file", zip_file); } std::vector info; GetFileListing("assets", &info, 0); for (size_t i = 0; i < info.size(); i++) { if (info[i].isDirectory) { - DLOG("Directory: %s", info[i].name.c_str()); + DEBUG_LOG(IO, "Directory: %s", info[i].name.c_str()); } else { - DLOG("File: %s", info[i].name.c_str()); + DEBUG_LOG(IO, "File: %s", info[i].name.c_str()); } } } @@ -200,6 +172,11 @@ bool ZipAssetReader::GetFileInfo(const char *path, FileInfo *info) { #endif +DirectoryAssetReader::DirectoryAssetReader(const char *path) { + strncpy(path_, path, ARRAY_SIZE(path_)); + path_[ARRAY_SIZE(path_) - 1] = '\0'; +} + uint8_t *DirectoryAssetReader::ReadAsset(const char *path, size_t *size) { char new_path[2048]; new_path[0] = '\0'; @@ -252,117 +229,3 @@ bool DirectoryAssetReader::GetFileInfo(const char *path, FileInfo *info) strcat(new_path, path); return getFileInfo(new_path, info); } - -struct VFSEntry { - const char *prefix; - AssetReader *reader; -}; - -static VFSEntry entries[16]; -static int num_entries = 0; - -void VFSRegister(const char *prefix, AssetReader *reader) { - entries[num_entries].prefix = prefix; - entries[num_entries].reader = reader; - DLOG("Registered VFS for prefix %s: %s", prefix, reader->toString().c_str()); - num_entries++; -} - -void VFSShutdown() { - for (int i = 0; i < num_entries; i++) { - delete entries[i].reader; - } - num_entries = 0; -} - -static bool IsLocalPath(const char *path) { - bool isUnixLocal = path[0] == '/'; -#ifdef _WIN32 - bool isWindowsLocal = isalpha(path[0]) && path[1] == ':'; -#else - bool isWindowsLocal = false; -#endif - return isUnixLocal || isWindowsLocal; -} - -uint8_t *VFSReadFile(const char *filename, size_t *size) { - if (IsLocalPath(filename)) { - // Local path, not VFS. - // ILOG("Not a VFS path: %s . Reading local file.", filename); - return ReadLocalFile(filename, size); - } - - int fn_len = (int)strlen(filename); - bool fileSystemFound = false; - for (int i = 0; i < num_entries; i++) { - int prefix_len = (int)strlen(entries[i].prefix); - if (prefix_len >= fn_len) continue; - if (0 == memcmp(filename, entries[i].prefix, prefix_len)) { - fileSystemFound = true; - // ILOG("Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len); - uint8_t *data = entries[i].reader->ReadAsset(filename + prefix_len, size); - if (data) - return data; - else - continue; - // Else try the other registered file systems. - } - } - if (!fileSystemFound) { - ELOG("Missing filesystem for '%s'", filename); - } // Otherwise, the file was just missing. No need to log. - return 0; -} - -bool VFSGetFileListing(const char *path, std::vector *listing, const char *filter) { - if (IsLocalPath(path)) { - // Local path, not VFS. - // ILOG("Not a VFS path: %s . Reading local directory.", path); - getFilesInDir(path, listing, filter); - return true; - } - - int fn_len = (int)strlen(path); - bool fileSystemFound = false; - for (int i = 0; i < num_entries; i++) { - int prefix_len = (int)strlen(entries[i].prefix); - if (prefix_len >= fn_len) continue; - if (0 == memcmp(path, entries[i].prefix, prefix_len)) { - fileSystemFound = true; - if (entries[i].reader->GetFileListing(path + prefix_len, listing, filter)) { - return true; - } - } - } - - if (!fileSystemFound) { - ELOG("Missing filesystem for %s", path); - } // Otherwise, the file was just missing. No need to log. - return false; -} - -bool VFSGetFileInfo(const char *path, FileInfo *info) { - if (IsLocalPath(path)) { - // Local path, not VFS. - // ILOG("Not a VFS path: %s . Getting local file info.", path); - return getFileInfo(path, info); - } - - bool fileSystemFound = false; - int fn_len = (int)strlen(path); - for (int i = 0; i < num_entries; i++) { - int prefix_len = (int)strlen(entries[i].prefix); - if (prefix_len >= fn_len) continue; - if (0 == memcmp(path, entries[i].prefix, prefix_len)) { - fileSystemFound = true; - if (entries[i].reader->GetFileInfo(path + prefix_len, info)) - return true; - else - continue; - } - } - if (!fileSystemFound) { - ELOG("Missing filesystem for %s", path); - } // Otherwise, the file was just missing. No need to log. - return false; -} diff --git a/ext/native/file/zip_read.h b/Common/File/VFS/AssetReader.h similarity index 87% rename from ext/native/file/zip_read.h rename to Common/File/VFS/AssetReader.h index 3607ddb926..5dcf98efc8 100644 --- a/ext/native/file/zip_read.h +++ b/Common/File/VFS/AssetReader.h @@ -8,9 +8,7 @@ #include #include -#include "base/basictypes.h" -#include "file/vfs.h" -#include "file/file_util.h" +#include "Common/File/VFS/VFS.h" // Direct readers. deallocate using delete []. uint8_t *ReadLocalFile(const char *filename, size_t *size); @@ -48,10 +46,7 @@ private: class DirectoryAssetReader : public AssetReader { public: - DirectoryAssetReader(const char *path) { - strncpy(path_, path, ARRAY_SIZE(path_)); - path_[ARRAY_SIZE(path_) - 1] = '\0'; - } + explicit DirectoryAssetReader(const char *path); // use delete[] virtual uint8_t *ReadAsset(const char *path, size_t *size); virtual bool GetFileListing(const char *path, std::vector *listing, const char *filter); @@ -61,6 +56,6 @@ public: } private: - char path_[512]; + char path_[512]{}; }; diff --git a/Common/File/VFS/VFS.cpp b/Common/File/VFS/VFS.cpp new file mode 100644 index 0000000000..0353169d79 --- /dev/null +++ b/Common/File/VFS/VFS.cpp @@ -0,0 +1,118 @@ +#include "Common/Log.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" + +struct VFSEntry { + const char *prefix; + AssetReader *reader; +}; + +static VFSEntry entries[16]; +static int num_entries = 0; + +void VFSRegister(const char *prefix, AssetReader *reader) { + entries[num_entries].prefix = prefix; + entries[num_entries].reader = reader; + DEBUG_LOG(IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str()); + num_entries++; +} + +void VFSShutdown() { + for (int i = 0; i < num_entries; i++) { + delete entries[i].reader; + } + num_entries = 0; +} + +static bool IsLocalPath(const char *path) { + bool isUnixLocal = path[0] == '/'; +#ifdef _WIN32 + bool isWindowsLocal = isalpha(path[0]) && path[1] == ':'; +#else + bool isWindowsLocal = false; +#endif + return isUnixLocal || isWindowsLocal; +} + +// The returned data should be free'd with delete[]. +uint8_t *VFSReadFile(const char *filename, size_t *size) { + if (IsLocalPath(filename)) { + // Local path, not VFS. + // INFO_LOG(IO, "Not a VFS path: %s . Reading local file.", filename); + return ReadLocalFile(filename, size); + } + + int fn_len = (int)strlen(filename); + bool fileSystemFound = false; + for (int i = 0; i < num_entries; i++) { + int prefix_len = (int)strlen(entries[i].prefix); + if (prefix_len >= fn_len) continue; + if (0 == memcmp(filename, entries[i].prefix, prefix_len)) { + fileSystemFound = true; + // INFO_LOG(IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len); + uint8_t *data = entries[i].reader->ReadAsset(filename + prefix_len, size); + if (data) + return data; + else + continue; + // Else try the other registered file systems. + } + } + if (!fileSystemFound) { + ERROR_LOG(IO, "Missing filesystem for '%s'", filename); + } // Otherwise, the file was just missing. No need to log. + return 0; +} + +bool VFSGetFileListing(const char *path, std::vector *listing, const char *filter) { + if (IsLocalPath(path)) { + // Local path, not VFS. + // INFO_LOG(IO, "Not a VFS path: %s . Reading local directory.", path); + getFilesInDir(path, listing, filter); + return true; + } + + int fn_len = (int)strlen(path); + bool fileSystemFound = false; + for (int i = 0; i < num_entries; i++) { + int prefix_len = (int)strlen(entries[i].prefix); + if (prefix_len >= fn_len) continue; + if (0 == memcmp(path, entries[i].prefix, prefix_len)) { + fileSystemFound = true; + if (entries[i].reader->GetFileListing(path + prefix_len, listing, filter)) { + return true; + } + } + } + + if (!fileSystemFound) { + ERROR_LOG(IO, "Missing filesystem for %s", path); + } // Otherwise, the file was just missing. No need to log. + return false; +} + +bool VFSGetFileInfo(const char *path, FileInfo *info) { + if (IsLocalPath(path)) { + // Local path, not VFS. + // INFO_LOG(IO, "Not a VFS path: %s . Getting local file info.", path); + return getFileInfo(path, info); + } + + bool fileSystemFound = false; + int fn_len = (int)strlen(path); + for (int i = 0; i < num_entries; i++) { + int prefix_len = (int)strlen(entries[i].prefix); + if (prefix_len >= fn_len) continue; + if (0 == memcmp(path, entries[i].prefix, prefix_len)) { + fileSystemFound = true; + if (entries[i].reader->GetFileInfo(path + prefix_len, info)) + return true; + else + continue; + } + } + if (!fileSystemFound) { + ERROR_LOG(IO, "Missing filesystem for %s", path); + } // Otherwise, the file was just missing. No need to log. + return false; +} diff --git a/ext/native/file/vfs.h b/Common/File/VFS/VFS.h similarity index 92% rename from ext/native/file/vfs.h rename to Common/File/VFS/VFS.h index ce1023b635..693e8fbc1d 100644 --- a/ext/native/file/vfs.h +++ b/Common/File/VFS/VFS.h @@ -1,7 +1,9 @@ #pragma once -#include "base/basictypes.h" -#include "file/file_util.h" +#include + +#include "Common/File/DirListing.h" + // Basic virtual file system. Used to manage assets on Android, where we have to // read them manually out of the APK zipfile, while being able to run on other // platforms as well with the appropriate directory set-up. diff --git a/Common/GL/GLInterface/EGL.cpp b/Common/GL/GLInterface/EGL.cpp index fb215af598..5f3c782f2c 100644 --- a/Common/GL/GLInterface/EGL.cpp +++ b/Common/GL/GLInterface/EGL.cpp @@ -5,9 +5,8 @@ #include #include -#include "Common/GL/GLInterface/EGL.h" - #include "Common/Log.h" +#include "Common/GL/GLInterface/EGL.h" // Show the current FPS void cInterfaceEGL::Swap() { diff --git a/Common/GL/GLInterface/EGL.h b/Common/GL/GLInterface/EGL.h index 65169b91da..e9d789748c 100644 --- a/Common/GL/GLInterface/EGL.h +++ b/Common/GL/GLInterface/EGL.h @@ -7,22 +7,12 @@ #include #include +#include "Common/Log.h" #include "Common/GL/GLInterfaceBase.h" -#ifdef __ANDROID__ -// On Android, EGL creation is so early that our regular logging system is not -// up and running yet. Use Android logging. -#include "base/logging.h" -#define EGL_ILOG(...) ILOG(__VA_ARGS__) -#define EGL_ELOG(...) ELOG(__VA_ARGS__) - -#else - #define EGL_ILOG(...) INFO_LOG(G3D, __VA_ARGS__) #define EGL_ELOG(...) INFO_LOG(G3D, __VA_ARGS__) -#endif - class cInterfaceEGL : public cInterfaceBase { public: diff --git a/ext/native/thin3d/d3d11_loader.cpp b/Common/GPU/D3D11/D3D11Loader.cpp similarity index 98% rename from ext/native/thin3d/d3d11_loader.cpp rename to Common/GPU/D3D11/D3D11Loader.cpp index fe0d0a02a9..2d81727ddb 100644 --- a/ext/native/thin3d/d3d11_loader.cpp +++ b/Common/GPU/D3D11/D3D11Loader.cpp @@ -1,4 +1,4 @@ -#include "thin3d/d3d11_loader.h" +#include "Common/GPU/D3D11/D3D11Loader.h" #if PPSSPP_PLATFORM(UWP) #error This file should not be compiled for UWP. diff --git a/ext/native/thin3d/d3d11_loader.h b/Common/GPU/D3D11/D3D11Loader.h similarity index 100% rename from ext/native/thin3d/d3d11_loader.h rename to Common/GPU/D3D11/D3D11Loader.h diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp similarity index 96% rename from ext/native/thin3d/thin3d_d3d11.cpp rename to Common/GPU/D3D11/thin3d_d3d11.cpp index 3e4afdde4a..f822d7e087 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -1,18 +1,18 @@ #include "ppsspp_config.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" #if PPSSPP_PLATFORM(UWP) #define ptr_D3DCompile D3DCompile #else -#include "thin3d/d3d11_loader.h" +#include "Common/GPU/D3D11/D3D11Loader.h" #endif -#include "base/display.h" -#include "math/dataconv.h" -#include "util/text/utf8.h" +#include "Common/System/Display.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Data/Encoding/Utf8.h" #include "Common/ColorConv.h" +#include "Common/Log.h" -#include #include #include #include @@ -65,12 +65,12 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override; - bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; - bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride); + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override; + bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override; + bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag); // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; // color must be 0, for now. void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; @@ -78,6 +78,8 @@ public: void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; + void InvalidateCachedState() override; + void BindTextures(int start, int count, Texture **textures) override; void BindSamplerStates(int start, int count, SamplerState **states) override; void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override; @@ -100,6 +102,8 @@ public: stencilRefDirty_ = true; } + void EndFrame() override; + void Draw(int vertexCount, int offset) override; void DrawIndexed(int vertexCount, int offset) override; void DrawUP(const void *vdata, int vertexCount) override; @@ -131,26 +135,26 @@ public: } } - uintptr_t GetNativeObject(NativeObject obj) override { + uint64_t GetNativeObject(NativeObject obj) override { switch (obj) { case NativeObject::DEVICE: - return (uintptr_t)device_; + return (uint64_t)(uintptr_t)device_; case NativeObject::CONTEXT: - return (uintptr_t)context_; + return (uint64_t)(uintptr_t)context_; case NativeObject::DEVICE_EX: - return (uintptr_t)device1_; + return (uint64_t)(uintptr_t)device1_; case NativeObject::CONTEXT_EX: - return (uintptr_t)context1_; + return (uint64_t)(uintptr_t)context1_; case NativeObject::BACKBUFFER_COLOR_TEX: - return (uintptr_t)bbRenderTargetTex_; + return (uint64_t)(uintptr_t)bbRenderTargetTex_; case NativeObject::BACKBUFFER_DEPTH_TEX: - return (uintptr_t)bbDepthStencilTex_; + return (uint64_t)(uintptr_t)bbDepthStencilTex_; case NativeObject::BACKBUFFER_COLOR_VIEW: - return (uintptr_t)bbRenderTargetView_; + return (uint64_t)(uintptr_t)bbRenderTargetView_; case NativeObject::BACKBUFFER_DEPTH_VIEW: - return (uintptr_t)bbDepthStencilView_; + return (uint64_t)(uintptr_t)bbDepthStencilView_; case NativeObject::FEATURE_LEVEL: - return (uintptr_t)featureLevel_; + return (uint64_t)(uintptr_t)featureLevel_; default: return 0; } @@ -158,6 +162,10 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; + int GetCurrentStepId() const override { + return stepId_; + } + private: void ApplyCurrentState(); @@ -166,6 +174,7 @@ private: ID3D11DeviceContext *context_; ID3D11Device1 *device1_; ID3D11DeviceContext1 *context1_; + int stepId_ = -1; ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED ID3D11RenderTargetView *bbRenderTargetView_ = nullptr; @@ -281,7 +290,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de packDesc.SampleDesc.Count = 1; packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; hr = device_->CreateTexture2D(&packDesc, nullptr, &packTexture_); - assert(SUCCEEDED(hr)); + _assert_(SUCCEEDED(hr)); } D3D11DrawContext::~D3D11DrawContext() { @@ -353,10 +362,15 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1 // Make sure that we don't eliminate the next time the render target is set. curRenderTargetView_ = nullptr; curDepthStencilView_ = nullptr; + stepId_ = 0; break; } } +void D3D11DrawContext::EndFrame() { + curPipeline_ = nullptr; +} + void D3D11DrawContext::SetViewports(int count, Viewport *viewports) { D3D11_VIEWPORT vp[4]; for (int i = 0; i < count; i++) { @@ -858,7 +872,7 @@ public: ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const std::string &tag) { if (language != ShaderLanguage::HLSL_D3D11) { - ELOG("Unsupported shader language"); + ERROR_LOG(G3D, "Unsupported shader language"); return nullptr; } @@ -903,7 +917,7 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang } if (errorMsgs) { errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); - ELOG("Failed compiling:\n%s\n%s", data, errors.c_str()); + ERROR_LOG(G3D, "Failed compiling:\n%s\n%s", data, errors.c_str()); errorMsgs->Release(); } @@ -928,7 +942,7 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs); break; default: - ELOG("Unsupported shader stage"); + ERROR_LOG(G3D, "Unsupported shader stage"); result = S_FALSE; break; } @@ -1008,19 +1022,20 @@ void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { context_->Unmap(curPipeline_->dynamicUniforms, 0); } -void D3D11DrawContext::BindPipeline(Pipeline *pipeline) { - if (pipeline == nullptr) { - // This is a signal to forget all our caching. - curBlend_ = nullptr; - curDepth_ = nullptr; - curRaster_ = nullptr; - curPS_ = nullptr; - curVS_ = nullptr; - curGS_ = nullptr; - curInputLayout_ = nullptr; - curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; - } +void D3D11DrawContext::InvalidateCachedState() { + // This is a signal to forget all our state caching. + curBlend_ = nullptr; + curDepth_ = nullptr; + curRaster_ = nullptr; + curPS_ = nullptr; + curVS_ = nullptr; + curGS_ = nullptr; + curInputLayout_ = nullptr; + curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + curPipeline_ = nullptr; +} +void D3D11DrawContext::BindPipeline(Pipeline *pipeline) { D3D11Pipeline *dPipeline = (D3D11Pipeline *)pipeline; if (curPipeline_ == dPipeline) return; @@ -1348,7 +1363,7 @@ void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int st } }*/ -void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBit) { +void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBit, const char *tag) { D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb; D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb; @@ -1394,19 +1409,21 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x D3D11_BOX srcBox{ (UINT)x, (UINT)y, (UINT)z, (UINT)(x + width), (UINT)(y + height), (UINT)(z + depth) }; context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox); } + stepId_++; } -bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { +bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) { // Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead. Crash(); + stepId_++; return false; } -bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int bx, int by, int bw, int bh, Draw::DataFormat format, void *pixels, int pixelStride) { +bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int bx, int by, int bw, int bh, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) { D3D11Framebuffer *fb = (D3D11Framebuffer *)src; if (fb) { - assert(fb->colorFormat == DXGI_FORMAT_R8G8B8A8_UNORM); + _assert_(fb->colorFormat == DXGI_FORMAT_R8G8B8A8_UNORM); // TODO: Figure out where the badness really comes from. if (bx + bw > fb->width) { @@ -1447,7 +1464,7 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel packDesc.Format = fb->depthStencilFormat; break; default: - assert(false); + _assert_(false); } device_->CreateTexture2D(&packDesc, nullptr, &packTex); } else { @@ -1470,11 +1487,11 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel case FB_DEPTH_BIT: case FB_STENCIL_BIT: // For depth/stencil buffers, we can't reliably copy subrectangles, so just copy the whole resource. - assert(fb); // Can't copy depth/stencil from backbuffer. Shouldn't happen thanks to checks above. + _assert_(fb); // Can't copy depth/stencil from backbuffer. Shouldn't happen thanks to checks above. context_->CopyResource(packTex, fb->depthStencilTex); break; default: - assert(false); + _assert_(false); break; } @@ -1519,10 +1536,11 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel if (!useGlobalPacktex) { packTex->Release(); } + stepId_++; return true; } -void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) { +void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { // TODO: deviceContext1 can actually discard. Useful on Windows Mobile. if (fbo) { D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; @@ -1562,6 +1580,8 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren if (mask && curDepthStencilView_) { context_->ClearDepthStencilView(curDepthStencilView_, mask, rp.clearDepth, rp.clearStencil); } + + stepId_++; } // color must be 0, for now. diff --git a/ext/native/gfx/d3d9_shader.cpp b/Common/GPU/D3D9/D3D9ShaderCompiler.cpp similarity index 70% rename from ext/native/gfx/d3d9_shader.cpp rename to Common/GPU/D3D9/D3D9ShaderCompiler.cpp index 2fdec6c41f..b54bb215c1 100644 --- a/ext/native/gfx/d3d9_shader.cpp +++ b/Common/GPU/D3D9/D3D9ShaderCompiler.cpp @@ -1,19 +1,12 @@ #ifdef _WIN32 #include "ppsspp_config.h" -#include "d3d9_shader.h" + +#include "Common/CommonWindows.h" +#include "Common/GPU/D3D9/D3DCompilerLoader.h" +#include "Common/GPU/D3D9/D3D9ShaderCompiler.h" #include "Common/CommonFuncs.h" - -#if PPSSPP_API(D3DX9) -#include "thin3d/d3dx9_loader.h" - -// They are the same types, just different names. -#define LPD3D_SHADER_MACRO LPD3DXMACRO -#define LPD3DINCLUDE LPD3DXINCLUDE -#define LPD3DBLOB LPD3DXBUFFER -#elif PPSSPP_API(D3D9_D3DCOMPILER) -#include "thin3d/d3d9_d3dcompiler_loader.h" -#endif +#include "Common/SysError.h" struct ID3DXConstantTable; @@ -24,18 +17,6 @@ bool CompilePixelShader(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DPI LPD3DBLOB pErrorMsg = nullptr; // Compile pixel shader. -#if PPSSPP_API(D3DX9) - HRESULT hr = dyn_D3DXCompileShader(code, - (UINT)strlen(code), - nullptr, - nullptr, - "main", - "ps_2_0", - 0, - &pShaderCode, - &pErrorMsg, - pShaderTable); -#elif PPSSPP_API(D3D9_D3DCOMPILER) HRESULT hr = dyn_D3DCompile(code, (UINT)strlen(code), nullptr, @@ -47,7 +28,6 @@ bool CompilePixelShader(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DPI 0, &pShaderCode, &pErrorMsg); -#endif if (pErrorMsg) { errorMessage = (CHAR *)pErrorMsg->GetBufferPointer(); @@ -78,18 +58,6 @@ bool CompileVertexShader(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DV LPD3DBLOB pErrorMsg = nullptr; // Compile pixel shader. -#if PPSSPP_API(D3DX9) - HRESULT hr = dyn_D3DXCompileShader(code, - (UINT)strlen(code), - nullptr, - nullptr, - "main", - "vs_2_0", - 0, - &pShaderCode, - &pErrorMsg, - pShaderTable); -#elif PPSSPP_API(D3D9_D3DCOMPILER) HRESULT hr = dyn_D3DCompile(code, (UINT)strlen(code), nullptr, @@ -101,7 +69,6 @@ bool CompileVertexShader(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DV 0, &pShaderCode, &pErrorMsg); -#endif if (pErrorMsg) { errorMessage = (CHAR *)pErrorMsg->GetBufferPointer(); diff --git a/ext/native/gfx/d3d9_shader.h b/Common/GPU/D3D9/D3D9ShaderCompiler.h similarity index 95% rename from ext/native/gfx/d3d9_shader.h rename to Common/GPU/D3D9/D3D9ShaderCompiler.h index 289ed24954..6c4aaf75a2 100644 --- a/ext/native/gfx/d3d9_shader.h +++ b/Common/GPU/D3D9/D3D9ShaderCompiler.h @@ -1,6 +1,7 @@ #pragma once #include "Common/CommonWindows.h" + #include #include #include @@ -12,4 +13,4 @@ namespace DX9 { bool CompilePixelShader(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DPIXELSHADER9 *pShader, ID3DXConstantTable **pShaderTable, std::string &errorMessage); bool CompileVertexShader(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DVERTEXSHADER9 *pShader, ID3DXConstantTable **pShaderTable, std::string &errorMessage); -} // namespace +} // namespace DX9 diff --git a/ext/native/gfx/d3d9_state.cpp b/Common/GPU/D3D9/D3D9StateCache.cpp similarity index 97% rename from ext/native/gfx/d3d9_state.cpp rename to Common/GPU/D3D9/D3D9StateCache.cpp index 14887f7f17..ed0bbdeff4 100644 --- a/ext/native/gfx/d3d9_state.cpp +++ b/Common/GPU/D3D9/D3D9StateCache.cpp @@ -1,7 +1,6 @@ #ifdef _WIN32 -#include "d3d9_state.h" -#include +#include "Common/GPU/D3D9/D3D9StateCache.h" namespace DX9 { diff --git a/ext/native/gfx/d3d9_state.h b/Common/GPU/D3D9/D3D9StateCache.h similarity index 99% rename from ext/native/gfx/d3d9_state.h rename to Common/GPU/D3D9/D3D9StateCache.h index a156834517..2a7a9cad89 100644 --- a/ext/native/gfx/d3d9_state.h +++ b/Common/GPU/D3D9/D3D9StateCache.h @@ -1,9 +1,8 @@ #pragma once -#include -#include +#include -#include "gfx/d3d9_shader.h" +#include "Common/GPU/D3D9/D3D9ShaderCompiler.h" namespace DX9 { diff --git a/ext/native/thin3d/d3d9_d3dcompiler_loader.cpp b/Common/GPU/D3D9/D3DCompilerLoader.cpp similarity index 77% rename from ext/native/thin3d/d3d9_d3dcompiler_loader.cpp rename to Common/GPU/D3D9/D3DCompilerLoader.cpp index 8cc76529fc..0a231190f9 100644 --- a/ext/native/thin3d/d3d9_d3dcompiler_loader.cpp +++ b/Common/GPU/D3D9/D3DCompilerLoader.cpp @@ -1,24 +1,23 @@ -#include -#include +#include "ppsspp_config.h" + +#include "Common/CommonWindows.h" #include -#include "thin3d/d3d9_d3dcompiler_loader.h" +#include "Common/Log.h" +#include "Common/GPU/D3D9/D3DCompilerLoader.h" static HMODULE g_D3DCompileModule; extern pD3DCompile ptr_D3DCompile; -int d3dcompiler_version = 47; - -#define GB_MAKE_STR(s) # s -#define GB_MAKE_STR2(x) GB_MAKE_STR(x) -#define GB_D3D9_D3DCOMPILER_LOADER_CHECK_ENTRY_NULL_PTR(funcname) assert(false && GB_MAKE_STR2(funcname) ); +static int d3dcompiler_version = 47; bool LoadD3DCompilerDynamic() { g_D3DCompileModule = LoadLibrary(D3DCOMPILER_DLL); #if PPSSPP_ARCH(X86) // Workaround for distributing both 32-bit and 64-bit versions of the DLL. - if (!g_D3DCompileModule) + if (!g_D3DCompileModule) { g_D3DCompileModule = LoadLibrary(L"D3dcompiler_47.x86.dll"); + } #endif if (!g_D3DCompileModule) { g_D3DCompileModule = LoadLibrary(L"D3dcompiler_42.dll"); @@ -50,13 +49,10 @@ bool UnloadD3DCompiler() { return true; } - HRESULT dyn_D3DCompile(LPCSTR pSrcData, UINT SrcDataSize, LPCSTR pFileName, CONST D3D_SHADER_MACRO* pDefines, LPD3DINCLUDE pInclude, LPCSTR pEntrypoint, LPCSTR pTarget, UINT Flags1, UINT Flags2, LPD3DBLOB* ppShader, LPD3DBLOB* ppErrorMsgs) { - if (!g_D3DCompileModule) { - GB_D3D9_D3DCOMPILER_LOADER_CHECK_ENTRY_NULL_PTR(D3DCompile) - } + _assert_(g_D3DCompileModule != nullptr); return ptr_D3DCompile(pSrcData, SrcDataSize, pFileName, pDefines, pInclude, pEntrypoint, pTarget, Flags1, Flags2, ppShader, ppErrorMsgs); } diff --git a/ext/native/thin3d/d3d9_d3dcompiler_loader.h b/Common/GPU/D3D9/D3DCompilerLoader.h similarity index 100% rename from ext/native/thin3d/d3d9_d3dcompiler_loader.h rename to Common/GPU/D3D9/D3DCompilerLoader.h diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp similarity index 95% rename from ext/native/thin3d/thin3d_d3d9.cpp rename to Common/GPU/D3D9/thin3d_d3d9.cpp index f8531661ba..6c7b5c233f 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -13,30 +13,18 @@ #undef new #endif -#if PPSSPP_API(D3DX9) -#include -#ifdef USE_CRT_DBG -#define new DBG_NEW -#endif -#include "thin3d/d3dx9_loader.h" - -// They are the same types, just different names. -#define LPD3D_SHADER_MACRO LPD3DXMACRO -#define LPD3DINCLUDE LPD3DXINCLUDE -#define LPD3DBLOB LPD3DXBUFFER -#elif PPSSPP_API(D3D9_D3DCOMPILER) #include -#include "thin3d/d3d9_d3dcompiler_loader.h" -#endif +#include "Common/GPU/D3D9/D3DCompilerLoader.h" #ifndef D3DXERR_INVALIDDATA #define D3DXERR_INVALIDDATA 0x88760b59 #endif -#include "base/logging.h" -#include "math/lin/matrix4x4.h" -#include "thin3d/thin3d.h" -#include "gfx/d3d9_state.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" + +#include "Common/Log.h" namespace Draw { @@ -381,7 +369,7 @@ bool D3D9Texture::Create(const TextureDesc &desc) { break; } if (FAILED(hr)) { - ELOG("Texture creation failed"); + ERROR_LOG(G3D, "Texture creation failed"); return false; } @@ -476,7 +464,7 @@ void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int d } default: - ELOG("Non-LINEAR2D textures not yet supported"); + ERROR_LOG(G3D, "Non-LINEAR2D textures not yet supported"); break; } } @@ -525,11 +513,13 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override {} - bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override { + // Not implemented + } + bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; // color must be 0, for now. void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; @@ -559,6 +549,8 @@ public: curPipeline_ = (D3D9Pipeline *)pipeline; } + void EndFrame() override; + void UpdateDynamicUniformBuffer(const void *ub, size_t size) override; // Raster state @@ -572,14 +564,14 @@ public: void DrawUP(const void *vdata, int vertexCount) override; void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal); - uintptr_t GetNativeObject(NativeObject obj) override { + uint64_t GetNativeObject(NativeObject obj) override { switch (obj) { case NativeObject::CONTEXT: - return (uintptr_t)d3d_; + return (uint64_t)(uintptr_t)d3d_; case NativeObject::DEVICE: - return (uintptr_t)device_; + return (uint64_t)(uintptr_t)device_; case NativeObject::DEVICE_EX: - return (uintptr_t)deviceEx_; + return (uint64_t)(uintptr_t)deviceEx_; default: return 0; } @@ -599,11 +591,18 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; + int GetCurrentStepId() const override { + return stepId_; + } + + void InvalidateCachedState() override; + private: LPDIRECT3D9 d3d_; LPDIRECT3D9EX d3dEx_; LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9EX deviceEx_; + int stepId_ = -1; int adapterId_ = -1; D3DADAPTER_IDENTIFIER9 identifier_{}; D3DCAPS9 d3dCaps_; @@ -623,13 +622,17 @@ private: bool supportsINTZ = false; }; +void D3D9Context::InvalidateCachedState() { + curPipeline_ = nullptr; +} + #define FB_DIV 1 #define FOURCC_INTZ ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))) D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) : d3d_(d3d), d3dEx_(d3dEx), adapterId_(adapterId), device_(device), deviceEx_(deviceEx), caps_{} { if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) { - ELOG("Failed to get adapter identifier: %d", adapterId); + ERROR_LOG(G3D, "Failed to get adapter identifier: %d", adapterId); } switch (identifier_.VendorId) { case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break; @@ -684,13 +687,13 @@ ShaderModule *D3D9Context::CreateShaderModule(ShaderStage stage, ShaderLanguage Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc) { if (!desc.shaders.size()) { - ELOG("Pipeline requires at least one shader"); + ERROR_LOG(G3D, "Pipeline requires at least one shader"); return NULL; } D3D9Pipeline *pipeline = new D3D9Pipeline(device_); for (auto iter : desc.shaders) { if (!iter) { - ELOG("NULL shader passed to CreateGraphicsPipeline"); + ERROR_LOG(G3D, "NULL shader passed to CreateGraphicsPipeline"); delete pipeline; return NULL; } @@ -797,6 +800,10 @@ void D3D9Context::BindTextures(int start, int count, Texture **textures) { } } +void D3D9Context::EndFrame() { + curPipeline_ = nullptr; +} + static void SemanticToD3D9UsageAndIndex(int semantic, BYTE *usage, BYTE *index) { *index = 0; switch (semantic) { @@ -845,7 +852,7 @@ D3D9InputLayout::D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc HRESULT hr = device->CreateVertexDeclaration(elements, &decl_); if (FAILED(hr)) { - ELOG("Error creating vertex decl"); + ERROR_LOG(G3D, "Error creating vertex decl"); } delete[] elements; } @@ -889,8 +896,7 @@ inline void Transpose4x4(float out[16], const float in[16]) { } void D3D9Context::UpdateDynamicUniformBuffer(const void *ub, size_t size) { - if (size != curPipeline_->dynamicUniforms.uniformBufferSize) - Crash(); + _assert_(size == curPipeline_->dynamicUniforms.uniformBufferSize); for (auto &uniform : curPipeline_->dynamicUniforms.uniforms) { int count = 0; switch (uniform.type) { @@ -924,7 +930,7 @@ void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offse if (!size) return; if (offset + size > buf->maxSize_) { - ELOG("Can't SubData with bigger size than buffer was created with"); + ERROR_LOG(G3D, "Can't SubData with bigger size than buffer was created with"); return; } if (buf->vbuffer_) { @@ -1026,11 +1032,7 @@ bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, si LPD3DBLOB errorBuffer = nullptr; const char *source = (const char *)data; auto compile = [&](const char *profile) -> HRESULT { -#if PPSSPP_API(D3DX9) - return dyn_D3DXCompileShader(source, (UINT)strlen(source), defines, includes, "main", profile, flags, &codeBuffer, &errorBuffer, nullptr); -#elif PPSSPP_API(D3D9_D3DCOMPILER) return dyn_D3DCompile(source, (UINT)strlen(source), nullptr, defines, includes, "main", profile, 0, 0, &codeBuffer, &errorBuffer); -#endif }; HRESULT hr = compile(stage_ == ShaderStage::FRAGMENT ? "ps_2_0" : "vs_2_0"); if (FAILED(hr) && hr == D3DXERR_INVALIDDATA) { @@ -1093,7 +1095,7 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { HRESULT rtResult = device_->CreateTexture(fbo->width, fbo->height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, NULL); if (FAILED(rtResult)) { - ELOG("Failed to create render target"); + ERROR_LOG(G3D, "Failed to create render target"); delete fbo; return NULL; } @@ -1109,7 +1111,7 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { dsResult = device_->CreateDepthStencilSurface(fbo->width, fbo->height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &fbo->depthstencil, NULL); } if (FAILED(dsResult)) { - ELOG("Failed to create depth buffer"); + ERROR_LOG(G3D, "Failed to create depth buffer"); fbo->surf->Release(); fbo->tex->Release(); if (fbo->depthstenciltex) { @@ -1131,7 +1133,7 @@ D3D9Framebuffer::~D3D9Framebuffer() { } } -void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) { +void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { using namespace DX9; if (fbo) { D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; @@ -1160,6 +1162,7 @@ void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPa dxstate.scissorRect.restore(); dxstate.viewport.restore(); + stepId_++; } uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) { @@ -1187,10 +1190,6 @@ uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit } } -LPDIRECT3DSURFACE9 fbo_get_color_for_read(D3D9Framebuffer *fbo) { - return fbo->surf; -} - void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int color) { D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; switch (channelBit) { @@ -1219,7 +1218,7 @@ void D3D9Context::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { } } -bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { +bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) { D3D9Framebuffer *src = (D3D9Framebuffer *)srcfb; D3D9Framebuffer *dst = (D3D9Framebuffer *)dstfb; if (channelBits != FB_COLOR_BIT) @@ -1228,6 +1227,7 @@ bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int RECT dstRect{ (LONG)dstX1, (LONG)dstY1, (LONG)dstX2, (LONG)dstY2 }; LPDIRECT3DSURFACE9 srcSurf = src ? src->surf : deviceRTsurf; LPDIRECT3DSURFACE9 dstSurf = dst ? dst->surf : deviceRTsurf; + stepId_++; return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, filter == FB_BLIT_LINEAR ? D3DTEXF_LINEAR : D3DTEXF_POINT)); } @@ -1245,23 +1245,18 @@ void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, voi device_->GetRenderTarget(0, &deviceRTsurf); device_->GetDepthStencilSurface(&deviceDSsurf); break; + case Event::PRESENTED: + stepId_ = 0; + break; } } DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) { -#if PPSSPP_API(D3DX9) - int d3dx_ver = LoadD3DX9Dynamic(); - if (!d3dx_ver) { - ELOG("Failed to load D3DX9!"); - return NULL; - } -#elif PPSSPP_API(D3D9_D3DCOMPILER) bool result = LoadD3DCompilerDynamic(); if (!result) { - ELOG("Failed to load D3DCompiler!"); - return NULL; + ERROR_LOG(G3D, "Failed to load D3DCompiler!"); + return nullptr; } -#endif return new D3D9Context(d3d, d3dEx, adapterId, device, deviceEx); } diff --git a/ext/native/thin3d/DataFormat.h b/Common/GPU/DataFormat.h similarity index 100% rename from ext/native/thin3d/DataFormat.h rename to Common/GPU/DataFormat.h diff --git a/ext/native/thin3d/DataFormatGL.cpp b/Common/GPU/OpenGL/DataFormatGL.cpp similarity index 96% rename from ext/native/thin3d/DataFormatGL.cpp rename to Common/GPU/OpenGL/DataFormatGL.cpp index b3a8092abf..1b8ba63acc 100644 --- a/ext/native/thin3d/DataFormatGL.cpp +++ b/Common/GPU/OpenGL/DataFormatGL.cpp @@ -1,5 +1,4 @@ -#include "thin3d/DataFormatGL.h" -#include "base/logging.h" +#include "Common/GPU/OpenGL/DataFormatGL.h" #include "Common/Log.h" namespace Draw { diff --git a/ext/native/thin3d/DataFormatGL.h b/Common/GPU/OpenGL/DataFormatGL.h similarity index 67% rename from ext/native/thin3d/DataFormatGL.h rename to Common/GPU/OpenGL/DataFormatGL.h index 28b48f60ff..63fc0a22ec 100644 --- a/ext/native/thin3d/DataFormatGL.h +++ b/Common/GPU/OpenGL/DataFormatGL.h @@ -1,7 +1,7 @@ #pragma once -#include "gfx/gl_common.h" -#include "thin3d/DataFormat.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/DataFormat.h" namespace Draw { diff --git a/ext/native/gfx/gl_common.h b/Common/GPU/OpenGL/GLCommon.h similarity index 96% rename from ext/native/gfx/gl_common.h rename to Common/GPU/OpenGL/GLCommon.h index fd8711b647..b9fbb3e413 100644 --- a/ext/native/gfx/gl_common.h +++ b/Common/GPU/OpenGL/GLCommon.h @@ -1,5 +1,7 @@ #pragma once +#include "ppsspp_config.h" + #ifdef IOS #include #include @@ -22,7 +24,7 @@ typedef char GLchar; #ifdef USING_GLES2 // Support OpenGL ES 3.0 // This uses the "DYNAMIC" approach from the gles3jni NDK sample. -#include "../gfx_es2/gl3stub.h" +#include "Common/GPU/OpenGL/gl3stub.h" #endif @@ -51,7 +53,7 @@ extern PFNGLMAPBUFFERPROC glMapBuffer; typedef void (EGLAPIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); extern PFNGLDRAWTEXTURENVPROC glDrawTextureNV; -#ifndef ARM64 +#if !PPSSPP_ARCH(ARM64) typedef void (EGLAPIENTRYP PFNGLBLITFRAMEBUFFERNVPROC) ( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, diff --git a/ext/native/gfx/gl_debug_log.cpp b/Common/GPU/OpenGL/GLDebugLog.cpp similarity index 82% rename from ext/native/gfx/gl_debug_log.cpp rename to Common/GPU/OpenGL/GLDebugLog.cpp index e72e286e7f..94b79dabc0 100644 --- a/ext/native/gfx/gl_debug_log.cpp +++ b/Common/GPU/OpenGL/GLDebugLog.cpp @@ -1,8 +1,9 @@ #include -#include "base/logging.h" -#include "gfx/gl_common.h" -#include "gfx/gl_debug_log.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" + +#include "Common/Log.h" // This we can expand as needed. std::string GLEnumToString(uint16_t value) { @@ -33,9 +34,11 @@ std::string GLEnumToString(uint16_t value) { } } -void CheckGLError(const char *file, int line) { +bool CheckGLError(const char *file, int line) { GLenum err = glGetError(); if (err != GL_NO_ERROR) { - ELOG("GL error %s on %s:%d", GLEnumToString(err).c_str(), file, line); + ERROR_LOG(G3D, "GL error %s on %s:%d", GLEnumToString(err).c_str(), file, line); + return false; } + return true; } diff --git a/ext/native/gfx/gl_debug_log.h b/Common/GPU/OpenGL/GLDebugLog.h similarity index 72% rename from ext/native/gfx/gl_debug_log.h rename to Common/GPU/OpenGL/GLDebugLog.h index ae22ab1700..d6d37c4271 100644 --- a/ext/native/gfx/gl_debug_log.h +++ b/Common/GPU/OpenGL/GLDebugLog.h @@ -10,8 +10,8 @@ #if defined(DEBUG_OPENGL) -void CheckGLError(const char *file, int line); -#define CHECK_GL_ERROR_IF_DEBUG() CheckGLError(__FILE__, __LINE__) +bool CheckGLError(const char *file, int line); +#define CHECK_GL_ERROR_IF_DEBUG() if (!CheckGLError(__FILE__, __LINE__)) __debugbreak(); #else diff --git a/ext/native/gfx_es2/gpu_features.cpp b/Common/GPU/OpenGL/GLFeatures.cpp similarity index 94% rename from ext/native/gfx_es2/gpu_features.cpp rename to Common/GPU/OpenGL/GLFeatures.cpp index ca4df8c26a..7048b6198a 100644 --- a/ext/native/gfx_es2/gpu_features.cpp +++ b/Common/GPU/OpenGL/GLFeatures.cpp @@ -3,19 +3,19 @@ #include #include -#include "base/logging.h" -#include "base/stringutil.h" +#include "Common/StringUtils.h" #if PPSSPP_API(ANY_GL) -#include "gfx/gl_common.h" +#include "Common/GPU/OpenGL/GLCommon.h" #if defined(_WIN32) #include "GL/wglew.h" #endif #endif -#include "gfx_es2/gpu_features.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Log.h" #if defined(USING_GLES2) #if defined(__ANDROID__) @@ -96,7 +96,7 @@ int GLExtensions::GLSLVersion() { void ProcessGPUFeatures() { gl_extensions.bugs = 0; - DLOG("Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model); + DEBUG_LOG(G3D, "Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model); if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { if (!strcmp(gl_extensions.model, "PowerVR SGX 545") || @@ -106,11 +106,11 @@ void ProcessGPUFeatures() { !strcmp(gl_extensions.model, "PowerVR SGX 540") || !strcmp(gl_extensions.model, "PowerVR SGX 530") || !strcmp(gl_extensions.model, "PowerVR SGX 520") ) { - WLOG("GL DRIVER BUG: PVR with bad and terrible precision"); + WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad and terrible precision"); gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_TERRIBLE | BUG_PVR_SHADER_PRECISION_BAD; } else { // TODO: I'm not sure if the Rogue series is affected by this. - WLOG("GL DRIVER BUG: PVR with bad precision"); + WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad precision"); gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_BAD; } } @@ -172,7 +172,7 @@ void CheckGLExtensions() { gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN; } - ILOG("GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor, renderer ? renderer : "N/A", versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A"); + INFO_LOG(G3D, "GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor, renderer ? renderer : "N/A", versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A"); if (renderer) { strncpy(gl_extensions.model, renderer, sizeof(gl_extensions.model)); @@ -245,7 +245,7 @@ void CheckGLExtensions() { gl_extensions.ver[1] = 0; } else if (parsed[0] && (gl_extensions.ver[0] != parsed[0] || gl_extensions.ver[1] != parsed[1])) { // Something going wrong. Possible bug in GL ES drivers. See #9688 - ILOG("GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.", + INFO_LOG(G3D, "GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.", versionStr ? versionStr : "N/A", parsed[0], parsed[1], gl_extensions.ver[0], gl_extensions.ver[1]); gl_extensions.ver[0] = 2; @@ -289,9 +289,9 @@ void CheckGLExtensions() { if (gl_extensions.GLES3) { if (gl_extensions.ver[1] >= 1) { - ILOG("OpenGL ES 3.1 support detected!\n"); + INFO_LOG(G3D, "OpenGL ES 3.1 support detected!\n"); } else { - ILOG("OpenGL ES 3.0 support detected!\n"); + INFO_LOG(G3D, "OpenGL ES 3.0 support detected!\n"); } } } @@ -315,7 +315,7 @@ void CheckGLExtensions() { ParseExtensionsString(g_all_gl_extensions, g_set_gl_extensions); } -#ifdef WIN32 +#if defined(WIN32) && !defined(__LIBRETRO__) const char *wglString = 0; if (wglGetExtensionsStringEXT) wglString = wglGetExtensionsStringEXT(); @@ -376,7 +376,7 @@ void CheckGLExtensions() { #ifdef _DEBUG void *invalidAddress = (void *)eglGetProcAddress("InvalidGlCall1"); void *invalidAddress2 = (void *)eglGetProcAddress("AnotherInvalidGlCall2"); - DLOG("Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2); + DEBUG_LOG(G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2); #endif // These are all the same. Let's alias. @@ -473,7 +473,7 @@ void CheckGLExtensions() { // Now, Adreno lies. So let's override it. if (gl_extensions.gpuVendor == GPU_VENDOR_QUALCOMM) { - WLOG("Detected Adreno - lowering int precision"); + WARN_LOG(G3D, "Detected Adreno - lowering int precision"); gl_extensions.range[1][5][0] = 15; gl_extensions.range[1][5][1] = 15; } @@ -549,15 +549,14 @@ void CheckGLExtensions() { int error = glGetError(); if (error) - ELOG("GL error in init: %i", error); + ERROR_LOG(G3D, "GL error in init: %i", error); #endif } void SetGLCoreContext(bool flag) { - if (extensionsDone) - FLOG("SetGLCoreContext() after CheckGLExtensions()"); + _assert_msg_(!extensionsDone, "SetGLCoreContext() after CheckGLExtensions()"); useCoreContext = flag; // For convenience, it'll get reset later. diff --git a/ext/native/gfx_es2/gpu_features.h b/Common/GPU/OpenGL/GLFeatures.h similarity index 96% rename from ext/native/gfx_es2/gpu_features.h rename to Common/GPU/OpenGL/GLFeatures.h index 4617e544a4..0c4a619b45 100644 --- a/ext/native/gfx_es2/gpu_features.h +++ b/Common/GPU/OpenGL/GLFeatures.h @@ -5,16 +5,15 @@ #pragma once #include -#include "base/NativeApp.h" enum { GPU_VENDOR_NVIDIA = 1, GPU_VENDOR_AMD = 2, GPU_VENDOR_INTEL = 3, GPU_VENDOR_ARM = 4, // Mali - GPU_VENDOR_IMGTEC = 5, - GPU_VENDOR_QUALCOMM = 6, - GPU_VENDOR_BROADCOM = 7, + GPU_VENDOR_IMGTEC = 5, // PowerVR + GPU_VENDOR_QUALCOMM = 6, // Adreno + GPU_VENDOR_BROADCOM = 7, // Raspberry PI etc GPU_VENDOR_VIVANTE = 8, GPU_VENDOR_UNKNOWN = 0, }; diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp similarity index 89% rename from ext/native/thin3d/GLQueueRunner.cpp rename to Common/GPU/OpenGL/GLQueueRunner.cpp index 1406872239..7776d7da4d 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -1,17 +1,20 @@ #include + +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/OpenGL/DataFormatGL.h" +#include "Common/Math/math_util.h" + +#include "Common/Log.h" #include "Common/MemoryUtil.h" +#include "Common/StringUtils.h" +#include "Common/Data/Convert/SmallDataConvert.h" + #include "Core/Reporting.h" #include "GLQueueRunner.h" #include "GLRenderManager.h" #include "DataFormatGL.h" -#include "base/logging.h" -#include "base/stringutil.h" -#include "gfx/gl_common.h" -#include "gfx/gl_debug_log.h" -#include "gfx_es2/gpu_features.h" -#include "thin3d/DataFormatGL.h" -#include "math/dataconv.h" -#include "math/math_util.h" #define TEXCACHE_NAME_CACHE_SIZE 16 @@ -56,6 +59,8 @@ void GLQueueRunner::CreateDeviceObjects() { populate(GL_EXTENSIONS); } CHECK_GL_ERROR_IF_DEBUG(); + + useDebugGroups_ = !gl_extensions.IsGLES && gl_extensions.VersionGEThan(4, 3); } void GLQueueRunner::DestroyDeviceObjects() { @@ -132,6 +137,11 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski return; } +#if !defined(USING_GLES2) + if (useDebugGroups_) + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "InitSteps"); +#endif + CHECK_GL_ERROR_IF_DEBUG(); glActiveTexture(GL_TEXTURE0); GLuint boundTexture = (GLuint)-1; @@ -173,10 +183,10 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski CHECK_GL_ERROR_IF_DEBUG(); GLRProgram *program = step.create_program.program; program->program = glCreateProgram(); - _assert_msg_(G3D, step.create_program.num_shaders > 0, "Can't create a program with zero shaders"); + _assert_msg_(step.create_program.num_shaders > 0, "Can't create a program with zero shaders"); bool anyFailed = false; for (int j = 0; j < step.create_program.num_shaders; j++) { - _dbg_assert_msg_(G3D, step.create_program.shaders[j]->shader, "Can't create a program with a null shader"); + _dbg_assert_msg_(step.create_program.shaders[j]->shader, "Can't create a program with a null shader"); anyFailed = anyFailed || step.create_program.shaders[j]->failed; glAttachShader(program->program, step.create_program.shaders[j]->shader); } @@ -216,7 +226,7 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski if (!anyFailed) Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", infoLog.c_str(), fsDesc.c_str(), fsCode, vsDesc.c_str(), vsCode); - ELOG("Could not link program:\n %s", infoLog.c_str()); + ERROR_LOG(G3D, "Could not link program:\n %s", infoLog.c_str()); ERROR_LOG(G3D, "VS desc:\n%s", vsDesc.c_str()); ERROR_LOG(G3D, "FS desc:\n%s", fsDesc.c_str()); ERROR_LOG(G3D, "VS:\n%s\n", vsCode); @@ -238,7 +248,7 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski // Query all the uniforms. for (size_t j = 0; j < program->queries_.size(); j++) { auto &x = program->queries_[j]; - assert(x.name); + _dbg_assert_(x.name); *x.dest = glGetUniformLocation(program->program, x.name); } @@ -270,8 +280,8 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski if (!success) { std::string infoLog = GetInfoLog(shader, glGetShaderiv, glGetShaderInfoLog); #ifdef __ANDROID__ - ELOG("Error in shader compilation! %s\n", infoLog.c_str()); - ELOG("Shader source:\n%s\n", (const char *)code); + ERROR_LOG(G3D, "Error in shader compilation! %s\n", infoLog.c_str()); + ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)code); #endif ERROR_LOG(G3D, "Error in shader compilation for: %s", step.create_shader.shader->desc.c_str()); ERROR_LOG(G3D, "Info log: %s", infoLog.c_str()); @@ -379,6 +389,14 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski WARN_LOG(G3D, "Got an error after init: %08x (%s)", err, GLEnumToString(err).c_str()); } } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + +#if !defined(USING_GLES2) + if (useDebugGroups_) + glPopDebugGroup(); +#endif } void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { @@ -423,7 +441,7 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { retry_depth: if (!fbo->z_stencil_) { - ILOG("Creating %i x %i FBO using no depth", fbo->width, fbo->height); + INFO_LOG(G3D, "Creating %d x %d FBO using no depth", fbo->width, fbo->height); fbo->z_stencil_buffer = 0; fbo->stencil_buffer = 0; @@ -436,7 +454,7 @@ retry_depth: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); } else if (gl_extensions.IsGLES) { if (gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3)) { - ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); fbo->z_stencil_buffer = 0; fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -457,7 +475,7 @@ retry_depth: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); } } else if (gl_extensions.OES_packed_depth_stencil) { - ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8", fbo->width, fbo->height); + INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8", fbo->width, fbo->height); // Standard method fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -472,7 +490,7 @@ retry_depth: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer); } else { - ILOG("Creating %i x %i FBO using separate stencil", fbo->width, fbo->height); + INFO_LOG(G3D, "Creating %d x %d FBO using separate stencil", fbo->width, fbo->height); // TEGRA fbo->z_stencil_buffer = 0; // 16/24-bit Z, separate 8-bit stencil @@ -493,7 +511,7 @@ retry_depth: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer); } } else if (gl_extensions.VersionGEThan(3, 0)) { - ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); fbo->z_stencil_buffer = 0; fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -529,16 +547,16 @@ retry_depth: switch (status) { case GL_FRAMEBUFFER_COMPLETE: - // ILOG("Framebuffer verified complete."); + // INFO_LOG(G3D, "Framebuffer verified complete."); break; case GL_FRAMEBUFFER_UNSUPPORTED: - ELOG("GL_FRAMEBUFFER_UNSUPPORTED"); + ERROR_LOG(G3D, "GL_FRAMEBUFFER_UNSUPPORTED"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + ERROR_LOG(G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); break; default: - FLOG("Other framebuffer error: %i", status); + _assert_msg_(false, "Other framebuffer error: %d", status); break; } @@ -582,12 +600,70 @@ void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCal return; } + size_t totalRenderCount = 0; + for (auto &step : steps) { + if (step->stepType == GLRStepType::RENDER) { + // Skip empty render steps. + if (step->commands.empty()) { + step->stepType = GLRStepType::RENDER_SKIP; + continue; + } + totalRenderCount++; + } + } + + auto ignoresContents = [](GLRRenderPassAction act) { + return act == GLRRenderPassAction::CLEAR || act == GLRRenderPassAction::DONT_CARE; + }; + int invalidateAllMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + + for (int j = 0; j < (int)steps.size() - 1; ++j) { + GLRStep &primaryStep = *steps[j]; + if (primaryStep.stepType == GLRStepType::RENDER) { + const GLRFramebuffer *fb = primaryStep.render.framebuffer; + + // Let's see if we can invalidate it... + int invalidateMask = 0; + for (int i = j + 1; i < (int)steps.size(); ++i) { + const GLRStep &secondaryStep = *steps[i]; + if (secondaryStep.stepType == GLRStepType::RENDER && secondaryStep.render.framebuffer == fb) { + if (ignoresContents(secondaryStep.render.color)) + invalidateMask |= GL_COLOR_BUFFER_BIT; + if (ignoresContents(secondaryStep.render.depth)) + invalidateMask |= GL_DEPTH_BUFFER_BIT; + if (ignoresContents(secondaryStep.render.stencil)) + invalidateMask |= GL_STENCIL_BUFFER_BIT; + + if (invalidateMask == invalidateAllMask) + break; + } else if (secondaryStep.dependencies.contains(fb)) { + // Can't do it, this step may depend on fb's data. + break; + } + } + + if (invalidateMask) { + GLRRenderData data{ GLRRenderCommand::INVALIDATE }; + data.clear.clearMask = invalidateMask; + primaryStep.commands.push_back(data); + } + } + } + CHECK_GL_ERROR_IF_DEBUG(); + size_t renderCount = 0; for (size_t i = 0; i < steps.size(); i++) { const GLRStep &step = *steps[i]; + +#if !defined(USING_GLES2) + if (useDebugGroups_) + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, (GLuint)i + 10000, -1, step.tag); +#endif + switch (step.stepType) { case GLRStepType::RENDER: - PerformRenderPass(step); + renderCount++; + PerformRenderPass(step, renderCount == 1, renderCount == totalRenderCount); break; case GLRStepType::COPY: PerformCopy(step); @@ -601,10 +677,18 @@ void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCal case GLRStepType::READBACK_IMAGE: PerformReadbackImage(step); break; + case GLRStepType::RENDER_SKIP: + break; default: Crash(); break; } + +#if !defined(USING_GLES2) + if (useDebugGroups_) + glPopDebugGroup(); +#endif + delete steps[i]; } CHECK_GL_ERROR_IF_DEBUG(); @@ -644,27 +728,24 @@ void GLQueueRunner::PerformBlit(const GLRStep &step) { } } -void GLQueueRunner::PerformRenderPass(const GLRStep &step) { +void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last) { CHECK_GL_ERROR_IF_DEBUG(); - // Don't execute empty renderpasses. - if (step.commands.empty()) { - // Nothing to do. - return; - } PerformBindFramebufferAsRenderTarget(step); - glDisable(GL_DEPTH_TEST); - glDisable(GL_STENCIL_TEST); - glDisable(GL_BLEND); - glDisable(GL_CULL_FACE); - glDisable(GL_DITHER); - glEnable(GL_SCISSOR_TEST); + if (first) { + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); + glDisable(GL_DITHER); + glEnable(GL_SCISSOR_TEST); #ifndef USING_GLES2 - if (!gl_extensions.IsGLES) { - glDisable(GL_COLOR_LOGIC_OP); - } + if (!gl_extensions.IsGLES) { + glDisable(GL_COLOR_LOGIC_OP); + } #endif + } /* #ifndef USING_GLES2 @@ -678,21 +759,22 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { #endif */ - if (gl_extensions.ARB_vertex_array_object) { + if (first && gl_extensions.ARB_vertex_array_object) { glBindVertexArray(globalVAO_); } GLRProgram *curProgram = nullptr; int activeSlot = 0; - glActiveTexture(GL_TEXTURE0 + activeSlot); + if (first) + glActiveTexture(GL_TEXTURE0 + activeSlot); // State filtering tracking. int attrMask = 0; int colorMask = -1; int depthMask = -1; int depthFunc = -1; - GLuint curArrayBuffer = (GLuint)-1; - GLuint curElemArrayBuffer = (GLuint)-1; + GLuint curArrayBuffer = (GLuint)0; + GLuint curElemArrayBuffer = (GLuint)0; bool depthEnabled = false; bool stencilEnabled = false; bool blendEnabled = false; @@ -796,7 +878,6 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } if (c.clear.colorMask != colorMask) { glColorMask(c.clear.colorMask & 1, (c.clear.colorMask >> 1) & 1, (c.clear.colorMask >> 2) & 1, (c.clear.colorMask >> 3) & 1); - colorMask = c.clear.colorMask; } if (c.clear.clearMask & GL_COLOR_BUFFER_BIT) { float color[4]; @@ -818,6 +899,10 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { glClearStencil(c.clear.clearStencil); } glClear(c.clear.clearMask); + // Restore the color mask if it was different. + if (c.clear.colorMask != colorMask) { + glColorMask(colorMask & 1, (colorMask >> 1) & 1, (colorMask >> 2) & 1, (colorMask >> 3) & 1); + } if (c.clear.scissorW == 0) { glEnable(GL_SCISSOR_TEST); } @@ -899,7 +984,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } case GLRRenderCommand::UNIFORM4I: { - assert(curProgram); + _dbg_assert_(curProgram); int loc = c.uniform4.loc ? *c.uniform4.loc : -1; if (c.uniform4.name) { loc = curProgram->GetUniformLoc(c.uniform4.name); @@ -925,7 +1010,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } case GLRRenderCommand::UNIFORMMATRIX: { - assert(curProgram); + _dbg_assert_(curProgram); int loc = c.uniformMatrix4.loc ? *c.uniformMatrix4.loc : -1; if (c.uniformMatrix4.name) { loc = curProgram->GetUniformLoc(c.uniformMatrix4.name); @@ -991,7 +1076,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { // TODO: Add fast path for glBindVertexBuffer GLRInputLayout *layout = c.bindVertexBuffer.inputLayout; GLuint buf = c.bindVertexBuffer.buffer ? c.bindVertexBuffer.buffer->buffer_ : 0; - assert(!c.bindVertexBuffer.buffer->Mapped()); + _dbg_assert_(!c.bindVertexBuffer.buffer->Mapped()); if (buf != curArrayBuffer) { glBindBuffer(GL_ARRAY_BUFFER, buf); curArrayBuffer = buf; @@ -1020,14 +1105,14 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { Crash(); } else if (c.bind_buffer.target == GL_ELEMENT_ARRAY_BUFFER) { GLuint buf = c.bind_buffer.buffer ? c.bind_buffer.buffer->buffer_ : 0; - assert(!c.bind_buffer.buffer->Mapped()); + _dbg_assert_(!c.bind_buffer.buffer->Mapped()); if (buf != curElemArrayBuffer) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); curElemArrayBuffer = buf; } } else { GLuint buf = c.bind_buffer.buffer ? c.bind_buffer.buffer->buffer_ : 0; - assert(!c.bind_buffer.buffer->Mapped()); + _dbg_assert_(!c.bind_buffer.buffer->Mapped()); glBindBuffer(c.bind_buffer.target, buf); } CHECK_GL_ERROR_IF_DEBUG(); @@ -1061,6 +1146,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { if (!tex) { break; } + CHECK_GL_ERROR_IF_DEBUG(); if (tex->canWrap) { if (tex->wrapS != c.textureSampler.wrapS) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c.textureSampler.wrapS); @@ -1071,14 +1157,17 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { tex->wrapT = c.textureSampler.wrapT; } } + CHECK_GL_ERROR_IF_DEBUG(); if (tex->magFilter != c.textureSampler.magFilter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, c.textureSampler.magFilter); tex->magFilter = c.textureSampler.magFilter; } + CHECK_GL_ERROR_IF_DEBUG(); if (tex->minFilter != c.textureSampler.minFilter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c.textureSampler.minFilter); tex->minFilter = c.textureSampler.minFilter; } + CHECK_GL_ERROR_IF_DEBUG(); if (tex->anisotropy != c.textureSampler.anisotropy) { if (c.textureSampler.anisotropy != 0.0f) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, c.textureSampler.anisotropy); @@ -1176,22 +1265,30 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { CHECK_GL_ERROR_IF_DEBUG(); // Wipe out the current state. - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - if (gl_extensions.ARB_vertex_array_object) { + if (curArrayBuffer != 0) + glBindBuffer(GL_ARRAY_BUFFER, 0); + if (curElemArrayBuffer != 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + if (last && gl_extensions.ARB_vertex_array_object) { glBindVertexArray(0); } - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_STENCIL_TEST); - glDisable(GL_BLEND); - glDisable(GL_CULL_FACE); + if (last) + glDisable(GL_SCISSOR_TEST); + if (depthEnabled) + glDisable(GL_DEPTH_TEST); + if (stencilEnabled) + glDisable(GL_STENCIL_TEST); + if (blendEnabled) + glDisable(GL_BLEND); + if (cullEnabled) + glDisable(GL_CULL_FACE); #ifndef USING_GLES2 - if (!gl_extensions.IsGLES) { + if (!gl_extensions.IsGLES && logicEnabled) { glDisable(GL_COLOR_LOGIC_OP); } #endif - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + if ((colorMask & 15) != 15) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); CHECK_GL_ERROR_IF_DEBUG(); } @@ -1220,7 +1317,7 @@ void GLQueueRunner::PerformCopy(const GLRStep &step) { break; case GL_DEPTH_BUFFER_BIT: // TODO: Support depth copies. - _assert_msg_(G3D, false, "Depth copies not yet supported - soon"); + _assert_msg_(false, "Depth copies not yet supported - soon"); target = GL_RENDERBUFFER; /* srcTex = src->depth.texture; @@ -1229,8 +1326,8 @@ void GLQueueRunner::PerformCopy(const GLRStep &step) { break; } - _dbg_assert_(G3D, srcTex); - _dbg_assert_(G3D, dstTex); + _dbg_assert_(srcTex); + _dbg_assert_(dstTex); #if defined(USING_GLES2) #ifndef IOS @@ -1473,16 +1570,16 @@ void GLQueueRunner::fbo_ext_create(const GLRInitStep &step) { GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch (status) { case GL_FRAMEBUFFER_COMPLETE_EXT: - // ILOG("Framebuffer verified complete."); + // INFO_LOG(G3D, "Framebuffer verified complete."); break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - ELOG("GL_FRAMEBUFFER_UNSUPPORTED"); + ERROR_LOG(G3D, "GL_FRAMEBUFFER_UNSUPPORTED"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT "); + ERROR_LOG(G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT "); break; default: - FLOG("Other framebuffer error: %i", status); + _assert_msg_(false, "Other framebuffer error: %d", status); break; } // Unbind state we don't need diff --git a/ext/native/thin3d/GLQueueRunner.h b/Common/GPU/OpenGL/GLQueueRunner.h similarity index 97% rename from ext/native/thin3d/GLQueueRunner.h rename to Common/GPU/OpenGL/GLQueueRunner.h index e66e346e18..742f885768 100644 --- a/ext/native/thin3d/GLQueueRunner.h +++ b/Common/GPU/OpenGL/GLQueueRunner.h @@ -4,9 +4,9 @@ #include #include -#include "gfx/gl_common.h" -#include "thin3d/DataFormat.h" -#include "util/tiny_set.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/DataFormat.h" +#include "Common/Data/Collections/TinySet.h" struct GLRViewport { float x, y, w, h, minZ, maxZ; @@ -276,6 +276,7 @@ enum class GLRStepType : uint8_t { BLIT, READBACK, READBACK_IMAGE, + RENDER_SKIP, }; enum class GLRRenderPassAction { @@ -297,6 +298,7 @@ struct GLRStep { GLRStepType stepType; std::vector commands; TinySet dependencies; + const char *tag; union { struct { GLRFramebuffer *framebuffer; @@ -371,7 +373,7 @@ private: void InitCreateFramebuffer(const GLRInitStep &step); void PerformBindFramebufferAsRenderTarget(const GLRStep &pass); - void PerformRenderPass(const GLRStep &pass); + void PerformRenderPass(const GLRStep &pass, bool first, bool last); void PerformCopy(const GLRStep &pass); void PerformBlit(const GLRStep &pass); void PerformReadback(const GLRStep &pass); @@ -414,9 +416,11 @@ private: GLuint currentReadHandle_ = 0; GLuint AllocTextureName(); + // Texture name cache. Ripped straight from TextureCacheGLES. std::vector nameCache_; std::unordered_map glStrings_; bool sawOutOfMemory_ = false; + bool useDebugGroups_ = false; }; diff --git a/ext/native/thin3d/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp similarity index 91% rename from ext/native/thin3d/GLRenderManager.cpp rename to Common/GPU/OpenGL/GLRenderManager.cpp index e1d8393162..7764adfde8 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -1,15 +1,13 @@ -#include - #include "GLRenderManager.h" -#include "gfx_es2/gpu_features.h" -#include "thin3d/thin3d.h" -#include "thread/threadutil.h" -#include "base/logging.h" -#include "GPU/GPUState.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/thin3d.h" +#include "Common/Thread/ThreadUtil.h" + +#include "Common/Log.h" #include "Common/MemoryUtil.h" #if 0 // def _DEBUG -#define VLOG ILOG +#define VLOG(...) INFO_LOG(G3D, __VA_ARGS__) #else #define VLOG(...) #endif @@ -21,6 +19,24 @@ static bool OnRenderThread() { } #endif +void GLDeleter::Take(GLDeleter &other) { + _assert_msg_(IsEmpty(), "Deleter already has stuff"); + shaders = std::move(other.shaders); + programs = std::move(other.programs); + buffers = std::move(other.buffers); + textures = std::move(other.textures); + inputLayouts = std::move(other.inputLayouts); + framebuffers = std::move(other.framebuffers); + pushBuffers = std::move(other.pushBuffers); + other.shaders.clear(); + other.programs.clear(); + other.buffers.clear(); + other.textures.clear(); + other.inputLayouts.clear(); + other.framebuffers.clear(); + other.pushBuffers.clear(); +} + // Runs on the GPU thread. void GLDeleter::Perform(GLRenderManager *renderManager, bool skipGLCalls) { for (auto pushBuffer : pushBuffers) { @@ -96,7 +112,7 @@ void GLRenderManager::ThreadStart(Draw::DrawContext *draw) { renderThreadId = std::this_thread::get_id(); if (newInflightFrames_ != -1) { - ILOG("Updating inflight frames to %d", newInflightFrames_); + INFO_LOG(G3D, "Updating inflight frames to %d", newInflightFrames_); inflightFrames_ = newInflightFrames_; newInflightFrames_ = -1; } @@ -136,7 +152,7 @@ void GLRenderManager::ThreadStart(Draw::DrawContext *draw) { } void GLRenderManager::ThreadEnd() { - ILOG("ThreadEnd"); + INFO_LOG(G3D, "ThreadEnd"); // Wait for any shutdown to complete in StopThread(). std::unique_lock lock(mutex_); @@ -195,11 +211,11 @@ bool GLRenderManager::ThreadFrame() { // Only increment next time if we're done. nextFrame = frameData.type == GLRRunType::END; - assert(frameData.type == GLRRunType::END || frameData.type == GLRRunType::SYNC); + _assert_(frameData.type == GLRRunType::END || frameData.type == GLRRunType::SYNC); } VLOG("PULL: Running frame %d", threadFrame_); if (firstFrame) { - ILOG("Running first frame (%d)", threadFrame_); + INFO_LOG(G3D, "Running first frame (%d)", threadFrame_); firstFrame = false; } Run(threadFrame_); @@ -228,7 +244,7 @@ void GLRenderManager::StopThread() { // Wait until we've definitely stopped the threadframe. std::unique_lock lock(mutex_); - ILOG("GL submission thread paused. Frame=%d", curFrame_); + INFO_LOG(G3D, "GL submission thread paused. Frame=%d", curFrame_); // Eat whatever has been queued up for this frame if anything. Wipe(); @@ -256,12 +272,12 @@ void GLRenderManager::StopThread() { } } } else { - ILOG("GL submission thread was already paused."); + INFO_LOG(G3D, "GL submission thread was already paused."); } } -void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil) { - assert(insideFrame_); +void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) { + _assert_(insideFrame_); #ifdef _DEBUG curProgram_ = nullptr; #endif @@ -269,6 +285,7 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende if (steps_.size() && steps_.back()->render.framebuffer == fb && steps_.back()->stepType == GLRStepType::RENDER) { if (color != GLRRenderPassAction::CLEAR && depth != GLRRenderPassAction::CLEAR && stencil != GLRRenderPassAction::CLEAR) { // We don't move to a new step, this bind was unnecessary and we can safely skip it. + curRenderStep_ = steps_.back(); return; } } @@ -283,6 +300,7 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende step->render.depth = depth; step->render.stencil = stencil; step->render.numDraws = 0; + step->tag = tag; steps_.push_back(step); GLuint clearMask = 0; @@ -316,13 +334,10 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende step->dependencies.insert(fb); } } - - // Every step clears this state. - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); } void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BIND_FB_TEXTURE }; data.bind_fb_texture.slot = binding; data.bind_fb_texture.framebuffer = fb; @@ -331,7 +346,7 @@ void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, curRenderStep_->dependencies.insert(fb); } -void GLRenderManager::CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLOffset2D dstPos, int aspectMask) { +void GLRenderManager::CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLOffset2D dstPos, int aspectMask, const char *tag) { GLRStep *step = new GLRStep{ GLRStepType::COPY }; step->copy.srcRect = srcRect; step->copy.dstPos = dstPos; @@ -339,16 +354,14 @@ void GLRenderManager::CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLR step->copy.dst = dst; step->copy.aspectMask = aspectMask; step->dependencies.insert(src); + step->tag = tag; bool fillsDst = dst && srcRect.x == 0 && srcRect.y == 0 && srcRect.w == dst->width && srcRect.h == dst->height; if (dstPos.x != 0 || dstPos.y != 0 || !fillsDst) step->dependencies.insert(dst); steps_.push_back(step); - - // Every step clears this state. - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); } -void GLRenderManager::BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLRect2D dstRect, int aspectMask, bool filter) { +void GLRenderManager::BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLRect2D dstRect, int aspectMask, bool filter, const char *tag) { GLRStep *step = new GLRStep{ GLRStepType::BLIT }; step->blit.srcRect = srcRect; step->blit.dstRect = dstRect; @@ -357,16 +370,14 @@ void GLRenderManager::BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLR step->blit.aspectMask = aspectMask; step->blit.filter = filter; step->dependencies.insert(src); + step->tag = tag; bool fillsDst = dst && dstRect.x == 0 && dstRect.y == 0 && dstRect.w == dst->width && dstRect.h == dst->height; if (!fillsDst) step->dependencies.insert(dst); steps_.push_back(step); - - // Every step clears this state. - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); } -bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) { +bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { _assert_(pixels); GLRStep *step = new GLRStep{ GLRStepType::READBACK }; @@ -375,11 +386,9 @@ bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspec step->readback.aspectMask = aspectBits; step->readback.dstFormat = destFormat; step->dependencies.insert(src); + step->tag = tag; steps_.push_back(step); - // Every step clears this state. - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); - curRenderStep_ = nullptr; FlushSync(); @@ -399,18 +408,16 @@ bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspec return true; } -void GLRenderManager::CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) { +void GLRenderManager::CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { _assert_(texture); _assert_(pixels); GLRStep *step = new GLRStep{ GLRStepType::READBACK_IMAGE }; step->readback_image.texture = texture; step->readback_image.mipLevel = mipLevel; step->readback_image.srcRect = { x, y, w, h }; + step->tag = tag; steps_.push_back(step); - // Every step clears this state. - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); - curRenderStep_ = nullptr; FlushSync(); @@ -445,13 +452,14 @@ void GLRenderManager::BeginFrame() { // Must be after the fence - this performs deletes. VLOG("PUSH: BeginFrame %d", curFrame); if (!run_) { - WLOG("BeginFrame while !run_!"); + WARN_LOG(G3D, "BeginFrame while !run_!"); } // vulkan_->BeginFrame(); // In GL, we have to do deletes on the submission thread. insideFrame_ = true; + renderStepOffset_ = 0; } void GLRenderManager::Finish() { @@ -499,7 +507,7 @@ void GLRenderManager::Submit(int frame, bool triggerFence) { VLOG("PULL: Frame %d.readyForFence = true", frame); std::unique_lock lock(frameData.push_mutex); - assert(frameData.readyForSubmit); + _assert_(frameData.readyForSubmit); frameData.readyForFence = true; frameData.readyForSubmit = false; frameData.push_condVar.notify_all(); @@ -567,7 +575,7 @@ void GLRenderManager::Run(int frame) { break; default: - assert(false); + _assert_(false); } VLOG("PULL: Finished running frame %d", frame); @@ -575,6 +583,8 @@ void GLRenderManager::Run(int frame) { void GLRenderManager::FlushSync() { // TODO: Reset curRenderStep_? + renderStepOffset_ += (int)steps_.size(); + int curFrame = curFrame_; FrameData &frameData = frameData_[curFrame]; { @@ -585,7 +595,7 @@ void GLRenderManager::FlushSync() { frameData.steps = std::move(steps_); steps_.clear(); frameData.readyForRun = true; - assert(frameData.readyForFence == false); + _assert_(frameData.readyForFence == false); frameData.type = GLRRunType::SYNC; frameData.pull_condVar.notify_all(); } @@ -654,7 +664,7 @@ GLPushBuffer::~GLPushBuffer() { } void GLPushBuffer::Map() { - assert(!writePtr_); + _assert_(!writePtr_); auto &info = buffers_[buf_]; writePtr_ = info.deviceMemory ? info.deviceMemory : info.localMemory; info.flushOffset = 0; @@ -664,11 +674,11 @@ void GLPushBuffer::Map() { offset_++; info.flushOffset++; } - assert(writePtr_); + _assert_(writePtr_); } void GLPushBuffer::Unmap() { - assert(writePtr_); + _assert_(writePtr_); if (!buffers_[buf_].deviceMemory) { // Here we simply upload the data to the last buffer. // Might be worth trying with size_ instead of offset_, so the driver can replace @@ -682,13 +692,13 @@ void GLPushBuffer::Unmap() { void GLPushBuffer::Flush() { // Must be called from the render thread. - _dbg_assert_(G3D, OnRenderThread()); + _dbg_assert_(OnRenderThread()); buffers_[buf_].flushOffset = offset_; if (!buffers_[buf_].deviceMemory && writePtr_) { auto &info = buffers_[buf_]; if (info.flushOffset != 0) { - assert(info.buffer->buffer_); + _assert_(info.buffer->buffer_); glBindBuffer(target_, info.buffer->buffer_); glBufferSubData(target_, 0, info.flushOffset, info.localMemory); } @@ -754,7 +764,7 @@ void GLPushBuffer::NextBuffer(size_t minSize) { } bool res = AddBuffer(); - assert(res); + _assert_(res); if (!res) { // Let's try not to crash at least? buf_ = 0; @@ -767,7 +777,7 @@ void GLPushBuffer::NextBuffer(size_t minSize) { } void GLPushBuffer::Defragment() { - _dbg_assert_msg_(G3D, !OnRenderThread(), "Defragment must not run on the render thread"); + _dbg_assert_msg_(!OnRenderThread(), "Defragment must not run on the render thread"); if (buffers_.size() <= 1) { // Let's take this chance to jetison localMemory we don't need. @@ -787,7 +797,7 @@ void GLPushBuffer::Defragment() { size_ = newSize; bool res = AddBuffer(); - _assert_msg_(G3D, res, "AddBuffer failed"); + _assert_msg_(res, "AddBuffer failed"); } size_t GLPushBuffer::GetTotalSize() const { @@ -799,7 +809,7 @@ size_t GLPushBuffer::GetTotalSize() const { } void GLPushBuffer::MapDevice(GLBufferStrategy strategy) { - _dbg_assert_msg_(G3D, OnRenderThread(), "MapDevice must run on render thread"); + _dbg_assert_msg_(OnRenderThread(), "MapDevice must run on render thread"); strategy_ = strategy; if (strategy_ == GLBufferStrategy::SUBDATA) { @@ -822,7 +832,7 @@ void GLPushBuffer::MapDevice(GLBufferStrategy strategy) { mapChanged = true; } - _dbg_assert_msg_(G3D, info.localMemory || info.deviceMemory, "Local or device memory must succeed"); + _dbg_assert_msg_(info.localMemory || info.deviceMemory, "Local or device memory must succeed"); } if (writePtr_ && mapChanged) { @@ -833,7 +843,7 @@ void GLPushBuffer::MapDevice(GLBufferStrategy strategy) { } void GLPushBuffer::UnmapDevice() { - _dbg_assert_msg_(G3D, OnRenderThread(), "UnmapDevice must run on render thread"); + _dbg_assert_msg_(OnRenderThread(), "UnmapDevice must run on render thread"); for (auto &info : buffers_) { if (info.deviceMemory) { @@ -845,7 +855,7 @@ void GLPushBuffer::UnmapDevice() { } void *GLRBuffer::Map(GLBufferStrategy strategy) { - assert(buffer_ != 0); + _assert_(buffer_ != 0); GLbitfield access = GL_MAP_WRITE_BIT; if ((strategy & GLBufferStrategy::MASK_FLUSH) != 0) { diff --git a/ext/native/thin3d/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h similarity index 84% rename from ext/native/thin3d/GLRenderManager.h rename to Common/GPU/OpenGL/GLRenderManager.h index e579eb7b10..a2f3a7effe 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -8,11 +8,9 @@ #include #include #include -#include -#include "base/logging.h" -#include "gfx/gl_common.h" -#include "math/dataconv.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Log.h" #include "GLQueueRunner.h" @@ -30,8 +28,10 @@ public: glDeleteTextures(1, &texture); } } + GLuint texture = 0; - // Could also trust OpenGL defaults I guess.. + + // We don't trust OpenGL defaults - setting wildly off values ensures that we'll end up overwriting these parameters. GLenum target = 0xFFFF; GLenum wrapS = 0xFFFF; GLenum wrapT = 0xFFFF; @@ -64,7 +64,7 @@ public: int width; int height; - GLuint colorDepth; + GLuint colorDepth = 0; bool z_stencil_; }; @@ -217,7 +217,7 @@ private: // Note: we must defrag because some buffers may be smaller than size_. Defragment(); Map(); - assert(writePtr_); + _dbg_assert_(writePtr_); } void BeginNoReset() { @@ -253,14 +253,14 @@ public: // Returns the offset that should be used when binding this buffer to get this data. size_t Push(const void *data, size_t size, GLRBuffer **vkbuf) { - assert(writePtr_); + _dbg_assert_(writePtr_); size_t off = Allocate(size, vkbuf); memcpy(writePtr_ + off, data, size); return off; } uint32_t PushAligned(const void *data, size_t size, int align, GLRBuffer **vkbuf) { - assert(writePtr_); + _dbg_assert_(writePtr_); offset_ = (offset_ + align - 1) & ~(align - 1); size_t off = Allocate(size, vkbuf); memcpy(writePtr_ + off, data, size); @@ -274,13 +274,13 @@ public: // "Zero-copy" variant - you can write the data directly as you compute it. // Recommended. void *Push(size_t size, uint32_t *bindOffset, GLRBuffer **vkbuf) { - assert(writePtr_); + _dbg_assert_(writePtr_); size_t off = Allocate(size, vkbuf); *bindOffset = (uint32_t)off; return writePtr_ + off; } void *PushAligned(size_t size, uint32_t *bindOffset, GLRBuffer **vkbuf, int align) { - assert(writePtr_); + _dbg_assert_(writePtr_); offset_ = (offset_ + align - 1) & ~(align - 1); size_t off = Allocate(size, vkbuf); *bindOffset = (uint32_t)off; @@ -324,23 +324,7 @@ public: return shaders.empty() && programs.empty() && buffers.empty() && textures.empty() && inputLayouts.empty() && framebuffers.empty() && pushBuffers.empty(); } - void Take(GLDeleter &other) { - _assert_msg_(G3D, IsEmpty(), "Deleter already has stuff"); - shaders = std::move(other.shaders); - programs = std::move(other.programs); - buffers = std::move(other.buffers); - textures = std::move(other.textures); - inputLayouts = std::move(other.inputLayouts); - framebuffers = std::move(other.framebuffers); - pushBuffers = std::move(other.pushBuffers); - other.shaders.clear(); - other.programs.clear(); - other.buffers.clear(); - other.textures.clear(); - other.inputLayouts.clear(); - other.framebuffers.clear(); - other.pushBuffers.clear(); - } + void Take(GLDeleter &other); std::vector shaders; std::vector programs; @@ -431,22 +415,22 @@ public: std::vector shaders, std::vector semantics, std::vector queries, std::vector initalizers, bool supportDualSource) { GLRInitStep step{ GLRInitStepType::CREATE_PROGRAM }; - assert(shaders.size() <= ARRAY_SIZE(step.create_program.shaders)); + _assert_(shaders.size() <= ARRAY_SIZE(step.create_program.shaders)); step.create_program.program = new GLRProgram(); step.create_program.program->semantics_ = semantics; step.create_program.program->queries_ = queries; step.create_program.program->initialize_ = initalizers; step.create_program.support_dual_source = supportDualSource; - _assert_msg_(G3D, shaders.size() > 0, "Can't create a program with zero shaders"); + _assert_msg_(shaders.size() > 0, "Can't create a program with zero shaders"); for (size_t i = 0; i < shaders.size(); i++) { step.create_program.shaders[i] = shaders[i]; } #ifdef _DEBUG for (auto &iter : queries) { - assert(iter.name); + _dbg_assert_(iter.name); } for (auto &sem : semantics) { - assert(sem.attrib); + _dbg_assert_(sem.attrib); } #endif step.create_program.num_shaders = (int)shaders.size(); @@ -501,21 +485,38 @@ public: pushbuffer->End(); } - void BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil); - void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment); - bool CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride); - void CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride); + // This starts a new step (like a "render pass" in Vulkan). + // + // After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce + // making any new render state changes or draw calls. + // + // The following state needs to be reset by the caller after calling this (and will thus not safely carry over from + // the previous one): + // * Viewport/Scissor + // * Depth/stencil + // * Blend + // * Raster state like primitive, culling, etc. + // + // It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're + // not keeping track of your calls to this function on your own. + void BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag); - void CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLOffset2D dstPos, int aspectMask); - void BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLRect2D dstRect, int aspectMask, bool filter); + // Binds a framebuffer as a texture, for the following draws. + void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment); + + bool CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); + void CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); + + void CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLOffset2D dstPos, int aspectMask, const char *tag); + void BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLRect2D dstRect, int aspectMask, bool filter, const char *tag); // Takes ownership of data if deleteData = true. void BufferSubdata(GLRBuffer *buffer, size_t offset, size_t size, uint8_t *data, bool deleteData = true) { // TODO: Maybe should be a render command instead of an init command? When possible it's better as // an init command, that's for sure. GLRInitStep step{ GLRInitStepType::BUFFER_SUBDATA }; - _dbg_assert_(G3D, offset >= 0); - _dbg_assert_(G3D, offset <= buffer->size_ - size); + _dbg_assert_(offset >= 0); + _dbg_assert_(offset <= buffer->size_ - size); step.buffer_subdata.buffer = buffer; step.buffer_subdata.offset = (int)offset; step.buffer_subdata.size = (int)size; @@ -539,7 +540,7 @@ public: } void TextureSubImage(GLRTexture *texture, int level, int x, int y, int width, int height, Draw::DataFormat format, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData _data{ GLRRenderCommand::TEXTURE_SUBIMAGE }; _data.texture_subimage.texture = texture; _data.texture_subimage.data = data; @@ -562,18 +563,18 @@ public: } void BindTexture(int slot, GLRTexture *tex) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BINDTEXTURE }; - _dbg_assert_(G3D, slot < 16); + _dbg_assert_(slot < 16); data.texture.slot = slot; data.texture.texture = tex; curRenderStep_->commands.push_back(data); } void BindProgram(GLRProgram *program) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BINDPROGRAM }; - _dbg_assert_(G3D, program != nullptr); + _dbg_assert_(program != nullptr); data.program.program = program; curRenderStep_->commands.push_back(data); #ifdef _DEBUG @@ -582,7 +583,7 @@ public: } void BindPixelPackBuffer(GLRBuffer *buffer) { // Want to support an offset but can't in ES 2.0. We supply an offset when binding the buffers instead. - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BIND_BUFFER }; data.bind_buffer.buffer = buffer; data.bind_buffer.target = GL_PIXEL_PACK_BUFFER; @@ -590,7 +591,7 @@ public: } void BindIndexBuffer(GLRBuffer *buffer) { // Want to support an offset but can't in ES 2.0. We supply an offset when binding the buffers instead. - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BIND_BUFFER}; data.bind_buffer.buffer = buffer; data.bind_buffer.target = GL_ELEMENT_ARRAY_BUFFER; @@ -598,8 +599,8 @@ public: } void BindVertexBuffer(GLRInputLayout *inputLayout, GLRBuffer *buffer, size_t offset) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); - assert(inputLayout); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(inputLayout); GLRRenderData data{ GLRRenderCommand::BIND_VERTEX_BUFFER }; data.bindVertexBuffer.inputLayout = inputLayout; data.bindVertexBuffer.offset = offset; @@ -608,7 +609,7 @@ public: } void SetDepth(bool enabled, bool write, GLenum func) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::DEPTH }; data.depth.enabled = enabled; data.depth.write = write; @@ -617,23 +618,23 @@ public: } void SetViewport(const GLRViewport &vp) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::VIEWPORT }; data.viewport.vp = vp; curRenderStep_->commands.push_back(data); } void SetScissor(const GLRect2D &rc) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::SCISSOR }; data.scissor.rc = rc; curRenderStep_->commands.push_back(data); } void SetUniformI(const GLint *loc, int count, const int *udata) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG - assert(curProgram_); + _dbg_assert_(curProgram_); #endif GLRRenderData data{ GLRRenderCommand::UNIFORM4I }; data.uniform4.loc = loc; @@ -643,9 +644,9 @@ public: } void SetUniformI1(const GLint *loc, int udata) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG - assert(curProgram_); + _dbg_assert_(curProgram_); #endif GLRRenderData data{ GLRRenderCommand::UNIFORM4I }; data.uniform4.loc = loc; @@ -655,9 +656,9 @@ public: } void SetUniformF(const GLint *loc, int count, const float *udata) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG - assert(curProgram_); + _dbg_assert_(curProgram_); #endif GLRRenderData data{ GLRRenderCommand::UNIFORM4F }; data.uniform4.loc = loc; @@ -667,9 +668,9 @@ public: } void SetUniformF1(const GLint *loc, const float udata) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG - assert(curProgram_); + _dbg_assert_(curProgram_); #endif GLRRenderData data{ GLRRenderCommand::UNIFORM4F }; data.uniform4.loc = loc; @@ -679,9 +680,9 @@ public: } void SetUniformF(const char *name, int count, const float *udata) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG - assert(curProgram_); + _dbg_assert_(curProgram_); #endif GLRRenderData data{ GLRRenderCommand::UNIFORM4F }; data.uniform4.name = name; @@ -691,9 +692,9 @@ public: } void SetUniformM4x4(const GLint *loc, const float *udata) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG - assert(curProgram_); + _dbg_assert_(curProgram_); #endif GLRRenderData data{ GLRRenderCommand::UNIFORMMATRIX }; data.uniformMatrix4.loc = loc; @@ -702,9 +703,9 @@ public: } void SetUniformM4x4(const char *name, const float *udata) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG - assert(curProgram_); + _dbg_assert_(curProgram_); #endif GLRRenderData data{ GLRRenderCommand::UNIFORMMATRIX }; data.uniformMatrix4.name = name; @@ -713,7 +714,7 @@ public: } void SetBlendAndMask(int colorMask, bool blendEnabled, GLenum srcColor, GLenum dstColor, GLenum srcAlpha, GLenum dstAlpha, GLenum funcColor, GLenum funcAlpha) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BLEND }; data.blend.mask = colorMask; data.blend.enabled = blendEnabled; @@ -727,7 +728,7 @@ public: } void SetNoBlendAndMask(int colorMask) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BLEND }; data.blend.mask = colorMask; data.blend.enabled = false; @@ -736,7 +737,7 @@ public: #ifndef USING_GLES2 void SetLogicOp(bool enabled, GLenum logicOp) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::LOGICOP }; data.logic.enabled = enabled; data.logic.logicOp = logicOp; @@ -745,7 +746,7 @@ public: #endif void SetStencilFunc(bool enabled, GLenum func, uint8_t refValue, uint8_t compareMask) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::STENCILFUNC }; data.stencilFunc.enabled = enabled; data.stencilFunc.func = func; @@ -755,7 +756,7 @@ public: } void SetStencilOp(uint8_t writeMask, GLenum sFail, GLenum zFail, GLenum pass) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::STENCILOP }; data.stencilOp.writeMask = writeMask; data.stencilOp.sFail = sFail; @@ -765,7 +766,7 @@ public: } void SetStencilDisabled() { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data; data.cmd = GLRRenderCommand::STENCILFUNC; data.stencilFunc.enabled = false; @@ -773,14 +774,14 @@ public: } void SetBlendFactor(const float color[4]) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::BLENDCOLOR }; CopyFloat4(data.blendColor.color, color); curRenderStep_->commands.push_back(data); } void SetRaster(GLboolean cullEnable, GLenum frontFace, GLenum cullFace, GLboolean ditherEnable) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::RASTER }; data.raster.cullEnable = cullEnable; data.raster.frontFace = frontFace; @@ -791,7 +792,7 @@ public: // Modifies the current texture as per GL specs, not global state. void SetTextureSampler(int slot, GLenum wrapS, GLenum wrapT, GLenum magFilter, GLenum minFilter, float anisotropy) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::TEXTURESAMPLER }; data.textureSampler.slot = slot; data.textureSampler.wrapS = wrapS; @@ -803,7 +804,7 @@ public: } void SetTextureLod(int slot, float minLod, float maxLod, float lodBias) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::TEXTURELOD}; data.textureLod.slot = slot; data.textureLod.minLod = minLod; @@ -812,9 +813,9 @@ public: curRenderStep_->commands.push_back(data); } - // If scissorW == 0, no scissor is applied. + // If scissorW == 0, no scissor is applied (the whole render target is cleared). void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask, int colorMask, int scissorX, int scissorY, int scissorW, int scissorH) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); if (!clearMask) return; GLRRenderData data{ GLRRenderCommand::CLEAR }; @@ -831,14 +832,14 @@ public: } void Invalidate(int invalidateMask) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::INVALIDATE }; data.clear.clearMask = invalidateMask; curRenderStep_->commands.push_back(data); } void Draw(GLenum mode, int first, int count) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::DRAW }; data.draw.mode = mode; data.draw.first = first; @@ -849,7 +850,7 @@ public: } void DrawIndexed(GLenum mode, int count, GLenum indexType, void *indices, int instances = 1) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::DRAW_INDEXED }; data.drawIndexed.mode = mode; data.drawIndexed.count = count; @@ -885,7 +886,7 @@ public: foundCount++; } } - assert(foundCount == 1); + _dbg_assert_(foundCount == 1); } void SetSwapFunction(std::function swapFunction) { @@ -920,6 +921,12 @@ public: skipGLCalls_ = true; } + // Gets a frame-unique ID of the current step being recorded. Can be used to figure out + // when the current step has changed, which means the caller will need to re-record its state. + int GetCurrentStepId() const { + return renderStepOffset_ + (int)steps_.size(); + } + private: void BeginSubmitFrame(int frame); void EndSubmitFrame(int frame); @@ -966,6 +973,8 @@ private: // Submission time state bool insideFrame_ = false; + // This is the offset within this frame, in case of a mid-frame sync. + int renderStepOffset_ = 0; GLRStep *curRenderStep_ = nullptr; std::vector steps_; std::vector initSteps_; diff --git a/ext/native/gfx_es2/glsl_program.cpp b/Common/GPU/OpenGL/GLSLProgram.cpp similarity index 86% rename from ext/native/gfx_es2/glsl_program.cpp rename to Common/GPU/OpenGL/GLSLProgram.cpp index 91ced3dad2..bdc41644a4 100644 --- a/ext/native/gfx_es2/glsl_program.cpp +++ b/Common/GPU/OpenGL/GLSLProgram.cpp @@ -1,13 +1,14 @@ #include -#include -#include +#include +#include #include -#include "base/logging.h" -#include "file/vfs.h" -#include "file/zip_read.h" -#include "glsl_program.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/FileUtil.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" + +#include "Common/Log.h" static std::set active_programs; @@ -22,9 +23,9 @@ bool CompileShader(const char *source, GLuint shader, const char *filename, std: GLsizei len; glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog); infoLog[len] = '\0'; - ELOG("Error in shader compilation of %s!\n", filename); - ELOG("Info log: %s\n", infoLog); - ELOG("Shader source:\n%s\n", (const char *)source); + ERROR_LOG(G3D, "Error in shader compilation of %s!\n", filename); + ERROR_LOG(G3D, "Info log: %s\n", infoLog); + ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)source); if (error_message) *error_message = infoLog; return false; @@ -45,7 +46,7 @@ GLSLProgram *glsl_create(const char *vshader, const char *fshader, std::string * if (glsl_recompile(program, error_message)) { active_programs.insert(program); } else { - ELOG("Failed compiling GLSL program: %s %s", vshader, fshader); + ERROR_LOG(G3D, "Failed compiling GLSL program: %s %s", vshader, fshader); delete program; return 0; } @@ -65,7 +66,7 @@ GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src if (glsl_recompile(program, error_message)) { active_programs.insert(program); } else { - ELOG("Failed compiling GLSL program from source strings"); + ERROR_LOG(G3D, "Failed compiling GLSL program from source strings"); delete program; return 0; } @@ -124,7 +125,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { vsh_src.reset((char *)VFSReadFile(program->vshader_filename, &sz)); } if (!program->vshader_source && !vsh_src) { - ELOG("File missing: %s", program->vshader_filename); + ERROR_LOG(G3D, "File missing: %s", program->vshader_filename); if (error_message) { *error_message = std::string("File missing: ") + program->vshader_filename; } @@ -135,7 +136,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { fsh_src.reset((char *)VFSReadFile(program->fshader_filename, &sz)); } if (!program->fshader_source && !fsh_src) { - ELOG("File missing: %s", program->fshader_filename); + ERROR_LOG(G3D, "File missing: %s", program->fshader_filename); if (error_message) { *error_message = std::string("File missing: ") + program->fshader_filename; } @@ -169,15 +170,15 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { if (bufLength) { char* buf = new char[bufLength + 1]; // safety glGetProgramInfoLog(prog, bufLength, NULL, buf); - ILOG("vsh: %i fsh: %i", vsh, fsh); - ELOG("Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf); + INFO_LOG(G3D, "vsh: %i fsh: %i", vsh, fsh); + ERROR_LOG(G3D, "Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf); if (error_message) { *error_message = buf; } delete [] buf; } else { - ILOG("vsh: %i fsh: %i", vsh, fsh); - ELOG("Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus); + INFO_LOG(G3D, "vsh: %i fsh: %i", vsh, fsh); + ERROR_LOG(G3D, "Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus); if (error_message) { *error_message = "(no error message available)"; } @@ -212,7 +213,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { program->u_sundir = glGetUniformLocation(program->program_, "u_sundir"); program->u_camerapos = glGetUniformLocation(program->program_, "u_camerapos"); - //ILOG("Shader compilation success: %s %s", + //INFO_LOG(G3D, "Shader compilation success: %s %s", // program->vshader_filename, // program->fshader_filename); return true; @@ -233,7 +234,7 @@ void glsl_destroy(GLSLProgram *program) { glDeleteProgram(program->program_); active_programs.erase(program); } else { - ELOG("Deleting null GLSL program!"); + ERROR_LOG(G3D, "Deleting null GLSL program!"); } delete program; } diff --git a/ext/native/gfx_es2/glsl_program.h b/Common/GPU/OpenGL/GLSLProgram.h similarity index 97% rename from ext/native/gfx_es2/glsl_program.h rename to Common/GPU/OpenGL/GLSLProgram.h index e2efd2a3d7..ae6020c43a 100644 --- a/ext/native/gfx_es2/glsl_program.h +++ b/Common/GPU/OpenGL/GLSLProgram.h @@ -7,7 +7,7 @@ #include #include -#include "gfx/gl_common.h" +#include "Common/GPU/OpenGL/GLCommon.h" // Represent a compiled and linked vshader/fshader pair. // A just-constructed object is valid but cannot be used as a shader program, meaning that diff --git a/ext/native/gfx_es2/gl3stub.c b/Common/GPU/OpenGL/gl3stub.c similarity index 99% rename from ext/native/gfx_es2/gl3stub.c rename to Common/GPU/OpenGL/gl3stub.c index 265004a9c3..28bbcd774a 100644 --- a/ext/native/gfx_es2/gl3stub.c +++ b/Common/GPU/OpenGL/gl3stub.c @@ -15,7 +15,8 @@ */ #include "ppsspp_config.h" -#include "../gfx/gl_common.h" + +#include "Common/GPU/OpenGL/GLCommon.h" #if defined(USING_GLES2) #if !PPSSPP_PLATFORM(IOS) diff --git a/ext/native/gfx_es2/gl3stub.h b/Common/GPU/OpenGL/gl3stub.h similarity index 100% rename from ext/native/gfx_es2/gl3stub.h rename to Common/GPU/OpenGL/gl3stub.h diff --git a/ext/native/thin3d/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp similarity index 89% rename from ext/native/thin3d/thin3d_gl.cpp rename to Common/GPU/OpenGL/thin3d_gl.cpp index f8c6c11a2e..a58432e14b 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1,21 +1,19 @@ -#include +#include #include #include #include #include -#include -#include "base/logging.h" -#include "math/dataconv.h" -#include "math/math_util.h" -#include "math/lin/matrix4x4.h" -#include "thin3d/thin3d.h" -#include "thin3d/DataFormatGL.h" -#include "gfx/gl_common.h" -#include "gfx/gl_debug_log.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Math/math_util.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/OpenGL/DataFormatGL.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" +#include "Common/GPU/OpenGL/GLFeatures.h" -#include "thin3d/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" // #define DEBUG_READ_PIXELS 1 @@ -231,7 +229,7 @@ GLuint ShaderStageToOpenGL(ShaderStage stage) { class OpenGLShaderModule : public ShaderModule { public: OpenGLShaderModule(GLRenderManager *render, ShaderStage stage, const std::string &tag) : render_(render), stage_(stage), tag_(tag) { - DLOG("Shader module created (%p)", this); + DEBUG_LOG(G3D, "Shader module created (%p)", this); glstage_ = ShaderStageToOpenGL(stage); } @@ -297,7 +295,6 @@ public: OpenGLPipeline(GLRenderManager *render) : render_(render) { } ~OpenGLPipeline() { - DLOG("OpenGLPipeline released"); for (auto &iter : shaders) { iter->Release(); } @@ -372,20 +369,20 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override; - bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; - bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override; + bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override; + bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; // color must be 0, for now. void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; void BindSamplerStates(int start, int count, SamplerState **states) override { - if (boundSamplers_.size() < (size_t)(start + count)) { - boundSamplers_.resize(start + count); + if (start + count >= MAX_TEXTURE_SLOTS) { + return; } for (int i = 0; i < count; i++) { int index = i + start; @@ -469,10 +466,10 @@ public: } } - uintptr_t GetNativeObject(NativeObject obj) override { + uint64_t GetNativeObject(NativeObject obj) override { switch (obj) { case NativeObject::RENDER_MANAGER: - return (uintptr_t)&renderManager_; + return (uint64_t)(uintptr_t)&renderManager_; default: return 0; } @@ -480,17 +477,23 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override {} + int GetCurrentStepId() const override { + return renderManager_.GetCurrentStepId(); + } + + void InvalidateCachedState() override; + private: void ApplySamplers(); GLRenderManager renderManager_; - std::vector boundSamplers_; - OpenGLTexture *boundTextures_[8]{}; - int maxTextures_ = 0; DeviceCaps caps_{}; // Bound state + OpenGLSamplerState *boundSamplers_[MAX_TEXTURE_SLOTS]{}; + OpenGLTexture *boundTextures_[MAX_TEXTURE_SLOTS]{}; + OpenGLPipeline *curPipeline_ = nullptr; OpenGLBuffer *curVBuffers_[4]{}; int curVBufferOffsets_[4]{}; @@ -601,7 +604,6 @@ OpenGLContext::~OpenGLContext() { for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { renderManager_.DeletePushBuffer(frameData_[i].push); } - boundSamplers_.clear(); } void OpenGLContext::BeginFrame() { @@ -614,6 +616,19 @@ void OpenGLContext::EndFrame() { FrameData &frameData = frameData_[renderManager_.GetCurFrame()]; renderManager_.EndPushBuffer(frameData.push); // upload the data! renderManager_.Finish(); + + InvalidateCachedState(); +} + +void OpenGLContext::InvalidateCachedState() { + // Unbind stuff. + for (auto &texture : boundTextures_) { + texture = nullptr; + } + for (auto &sampler : boundSamplers_) { + sampler = nullptr; + } + curPipeline_ = nullptr; } InputLayout *OpenGLContext::CreateInputLayout(const InputLayoutDesc &desc) { @@ -635,7 +650,7 @@ GLuint TypeToTarget(TextureType type) { #endif case TextureType::ARRAY2D: return GL_TEXTURE_2D_ARRAY; default: - ELOG("Bad texture type %d", (int)type); + ERROR_LOG(G3D, "Bad texture type %d", (int)type); return GL_NONE; } } @@ -655,6 +670,9 @@ public: void Bind(int stage) { render_->BindTexture(stage, tex_); } + int NumMipmaps() const { + return mipLevels_; + } private: void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback callback); @@ -671,7 +689,6 @@ private: OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) : render_(render) { generatedMips_ = false; - canWrap_ = true; width_ = desc.width; height_ = desc.height; depth_ = desc.depth; @@ -782,36 +799,36 @@ static void LogReadPixelsError(GLenum error) { case GL_NO_ERROR: break; case GL_INVALID_ENUM: - ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_ENUM"); + ERROR_LOG(G3D, "glReadPixels: GL_INVALID_ENUM"); break; case GL_INVALID_VALUE: - ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_VALUE"); + ERROR_LOG(G3D, "glReadPixels: GL_INVALID_VALUE"); break; case GL_INVALID_OPERATION: - ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_OPERATION"); + ERROR_LOG(G3D, "glReadPixels: GL_INVALID_OPERATION"); break; case GL_INVALID_FRAMEBUFFER_OPERATION: - ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION"); + ERROR_LOG(G3D, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION"); break; case GL_OUT_OF_MEMORY: - ERROR_LOG(FRAMEBUF, "glReadPixels: GL_OUT_OF_MEMORY"); + ERROR_LOG(G3D, "glReadPixels: GL_OUT_OF_MEMORY"); break; #ifndef USING_GLES2 case GL_STACK_UNDERFLOW: - ERROR_LOG(FRAMEBUF, "glReadPixels: GL_STACK_UNDERFLOW"); + ERROR_LOG(G3D, "glReadPixels: GL_STACK_UNDERFLOW"); break; case GL_STACK_OVERFLOW: - ERROR_LOG(FRAMEBUF, "glReadPixels: GL_STACK_OVERFLOW"); + ERROR_LOG(G3D, "glReadPixels: GL_STACK_OVERFLOW"); break; #endif default: - ERROR_LOG(FRAMEBUF, "glReadPixels: %08x", error); + ERROR_LOG(G3D, "glReadPixels: %08x", error); break; } } #endif -bool OpenGLContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat dataFormat, void *pixels, int pixelStride) { +bool OpenGLContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat dataFormat, void *pixels, int pixelStride, const char *tag) { if (gl_extensions.IsGLES && (channelBits & FB_COLOR_BIT) == 0) { // Can't readback depth or stencil on GLES. return false; @@ -824,7 +841,7 @@ bool OpenGLContext::CopyFramebufferToMemorySync(Framebuffer *src, int channelBit aspect |= GL_DEPTH_BUFFER_BIT; if (channelBits & FB_STENCIL_BIT) aspect |= GL_STENCIL_BUFFER_BIT; - renderManager_.CopyFramebufferToMemorySync(fb ? fb->framebuffer : nullptr, aspect, x, y, w, h, dataFormat, (uint8_t *)pixels, pixelStride); + renderManager_.CopyFramebufferToMemorySync(fb ? fb->framebuffer : nullptr, aspect, x, y, w, h, dataFormat, (uint8_t *)pixels, pixelStride, tag); return true; } @@ -948,16 +965,25 @@ void OpenGLContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t off Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { if (!desc.shaders.size()) { - ELOG("Pipeline requires at least one shader"); + ERROR_LOG(G3D, "Pipeline requires at least one shader"); return nullptr; } + if ((int)desc.prim >= (int)Primitive::PRIMITIVE_TYPE_COUNT) { + ERROR_LOG(G3D, "Invalid primitive type"); + return nullptr; + } + if (!desc.depthStencil || !desc.blend || !desc.raster || !desc.inputLayout) { + ERROR_LOG(G3D, "Incomplete prim desciption"); + return nullptr; + } + OpenGLPipeline *pipeline = new OpenGLPipeline(&renderManager_); for (auto iter : desc.shaders) { if (iter) { iter->AddRef(); pipeline->shaders.push_back(static_cast(iter)); } else { - ELOG("ERROR: Tried to create graphics pipeline with a null shader module"); + ERROR_LOG(G3D, "ERROR: Tried to create graphics pipeline with a null shader module"); delete pipeline; return nullptr; } @@ -966,7 +992,6 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { pipeline->dynamicUniforms = *desc.uniformDesc; pipeline->dynamicUniformLocs_.resize(desc.uniformDesc->uniforms.size()); } - ILOG("Linking shaders."); if (pipeline->LinkShaders()) { // Build the rest of the virtual pipeline object. pipeline->prim = primToGL[(int)desc.prim]; @@ -980,14 +1005,16 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { pipeline->inputLayout->AddRef(); return pipeline; } else { - ELOG("Failed to create pipeline - shaders failed to link"); + ERROR_LOG(G3D, "Failed to create pipeline - shaders failed to link"); delete pipeline; return nullptr; } } void OpenGLContext::BindTextures(int start, int count, Texture **textures) { - maxTextures_ = std::max(maxTextures_, start + count); + if (start + count >= MAX_TEXTURE_SLOTS) { + return; + } for (int i = start; i < start + count; i++) { OpenGLTexture *glTex = static_cast(textures[i - start]); if (!glTex) { @@ -1001,25 +1028,27 @@ void OpenGLContext::BindTextures(int start, int count, Texture **textures) { } void OpenGLContext::ApplySamplers() { - for (int i = 0; i < maxTextures_; i++) { - if ((int)boundSamplers_.size() > i && boundSamplers_[i]) { - const OpenGLSamplerState *samp = boundSamplers_[i]; - const OpenGLTexture *tex = boundTextures_[i]; - if (!tex) - continue; - GLenum wrapS; - GLenum wrapT; - if (tex->CanWrap()) { - wrapS = samp->wrapU; - wrapT = samp->wrapV; - } else { - wrapS = GL_CLAMP_TO_EDGE; - wrapT = GL_CLAMP_TO_EDGE; - } - GLenum magFilt = samp->magFilt; - GLenum minFilt = tex->HasMips() ? samp->mipMinFilt : samp->minFilt; - renderManager_.SetTextureSampler(i, wrapS, wrapT, magFilt, minFilt, 0.0f); + for (int i = 0; i < MAX_TEXTURE_SLOTS; i++) { + const OpenGLSamplerState *samp = boundSamplers_[i]; + const OpenGLTexture *tex = boundTextures_[i]; + if (tex) { + _assert_(samp); + } else { + continue; } + GLenum wrapS; + GLenum wrapT; + if (tex->CanWrap()) { + wrapS = samp->wrapU; + wrapT = samp->wrapV; + } else { + wrapS = GL_CLAMP_TO_EDGE; + wrapT = GL_CLAMP_TO_EDGE; + } + GLenum magFilt = samp->magFilt; + GLenum minFilt = tex->HasMips() ? samp->mipMinFilt : samp->minFilt; + renderManager_.SetTextureSampler(i, wrapS, wrapT, magFilt, minFilt, 0.0f); + renderManager_.SetTextureLod(i, 0.0, (float)(tex->NumMipmaps() - 1), 0.0); } } @@ -1035,9 +1064,21 @@ ShaderModule *OpenGLContext::CreateShaderModule(ShaderStage stage, ShaderLanguag bool OpenGLPipeline::LinkShaders() { std::vector linkShaders; - for (auto iter : shaders) { - linkShaders.push_back(iter->GetShader()); + for (auto shaderModule : shaders) { + if (shaderModule) { + GLRShader *shader = shaderModule->GetShader(); + if (shader) { + linkShaders.push_back(shader); + } else { + ERROR_LOG(G3D, "LinkShaders: Bad shader module"); + return false; + } + } else { + ERROR_LOG(G3D, "LinkShaders: Bad shader in module"); + return false; + } } + std::vector semantics; // Bind all the common vertex data points. Mismatching ones will be ignored. semantics.push_back({ SEM_POSITION, "Position" }); @@ -1064,12 +1105,13 @@ bool OpenGLPipeline::LinkShaders() { void OpenGLContext::BindPipeline(Pipeline *pipeline) { curPipeline_ = (OpenGLPipeline *)pipeline; - if (curPipeline_) { - curPipeline_->blend->Apply(&renderManager_); - curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_); - curPipeline_->raster->Apply(&renderManager_); - renderManager_.BindProgram(curPipeline_->program_); + if (!curPipeline_) { + return; } + curPipeline_->blend->Apply(&renderManager_); + curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_); + curPipeline_->raster->Apply(&renderManager_); + renderManager_.BindProgram(curPipeline_->program_); } void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { @@ -1096,15 +1138,15 @@ void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { } void OpenGLContext::Draw(int vertexCount, int offset) { - _dbg_assert_msg_(G3D, curVBuffers_[0], "Can't call Draw without a vertex buffer"); + _dbg_assert_msg_(curVBuffers_[0], "Can't call Draw without a vertex buffer"); ApplySamplers(); renderManager_.BindVertexBuffer(curPipeline_->inputLayout->inputLayout_, curVBuffers_[0]->buffer_, curVBufferOffsets_[0]); renderManager_.Draw(curPipeline_->prim, offset, vertexCount); } void OpenGLContext::DrawIndexed(int vertexCount, int offset) { - _dbg_assert_msg_(G3D, curVBuffers_[0], "Can't call DrawIndexed without a vertex buffer"); - _dbg_assert_msg_(G3D, curIBuffer_, "Can't call DrawIndexed without an index buffer"); + _dbg_assert_msg_(curVBuffers_[0], "Can't call DrawIndexed without a vertex buffer"); + _dbg_assert_msg_(curIBuffer_, "Can't call DrawIndexed without an index buffer"); ApplySamplers(); renderManager_.BindVertexBuffer(curPipeline_->inputLayout->inputLayout_, curVBuffers_[0]->buffer_, curVBufferOffsets_[0]); renderManager_.BindIndexBuffer(curIBuffer_->buffer_); @@ -1121,7 +1163,6 @@ void OpenGLContext::DrawUP(const void *vdata, int vertexCount) { size_t offset = frameData.push->Push(vdata, dataSize, &buf); ApplySamplers(); - renderManager_.BindVertexBuffer(curPipeline_->inputLayout->inputLayout_, buf, offset); renderManager_.Draw(curPipeline_->prim, 0, vertexCount); } @@ -1184,7 +1225,7 @@ void OpenGLInputLayout::Compile(const InputLayoutDesc &desc) { break; case DataFormat::UNDEFINED: default: - ELOG("Thin3DGLVertexFormat: Invalid or unknown component type applied."); + ERROR_LOG(G3D, "Thin3DGLVertexFormat: Invalid or unknown component type applied."); break; } @@ -1201,16 +1242,16 @@ Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) { return fbo; } -void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) { +void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; GLRRenderPassAction color = (GLRRenderPassAction)rp.color; GLRRenderPassAction depth = (GLRRenderPassAction)rp.depth; GLRRenderPassAction stencil = (GLRRenderPassAction)rp.stencil; - renderManager_.BindFramebufferAsRenderTarget(fb ? fb->framebuffer : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil); + renderManager_.BindFramebufferAsRenderTarget(fb ? fb->framebuffer : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, tag); } -void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int srcX, int srcY, int srcZ, Framebuffer *fbdst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) { +void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int srcX, int srcY, int srcZ, Framebuffer *fbdst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) { OpenGLFramebuffer *src = (OpenGLFramebuffer *)fbsrc; OpenGLFramebuffer *dst = (OpenGLFramebuffer *)fbdst; @@ -1223,10 +1264,10 @@ void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int s if (channelBits & FB_STENCIL_BIT) aspect |= GL_STENCIL_BUFFER_BIT; } - renderManager_.CopyFramebuffer(src->framebuffer, GLRect2D{ srcX, srcY, width, height }, dst->framebuffer, GLOffset2D{ dstX, dstY }, aspect); + renderManager_.CopyFramebuffer(src->framebuffer, GLRect2D{ srcX, srcY, width, height }, dst->framebuffer, GLOffset2D{ dstX, dstY }, aspect, tag); } -bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *fbdst, int dstX1, int dstY1, int dstX2, int dstY2, int channels, FBBlitFilter linearFilter) { +bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *fbdst, int dstX1, int dstY1, int dstX2, int dstY2, int channels, FBBlitFilter linearFilter, const char *tag) { OpenGLFramebuffer *src = (OpenGLFramebuffer *)fbsrc; OpenGLFramebuffer *dst = (OpenGLFramebuffer *)fbdst; GLuint aspect = 0; @@ -1237,7 +1278,7 @@ bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, in if (channels & FB_STENCIL_BIT) aspect |= GL_STENCIL_BUFFER_BIT; - renderManager_.BlitFramebuffer(src->framebuffer, GLRect2D{ srcX1, srcY1, srcX2 - srcX1, srcY2 - srcY1 }, dst->framebuffer, GLRect2D{ dstX1, dstY1, dstX2 - dstX1, dstY2 - dstY1 }, aspect, linearFilter == FB_BLIT_LINEAR); + renderManager_.BlitFramebuffer(src->framebuffer, GLRect2D{ srcX1, srcY1, srcX2 - srcX1, srcY2 - srcY1 }, dst->framebuffer, GLRect2D{ dstX1, dstY1, dstX2 - dstX1, dstY2 - dstY1 }, aspect, linearFilter == FB_BLIT_LINEAR, tag); return true; } diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp similarity index 87% rename from Common/Vulkan/VulkanContext.cpp rename to Common/GPU/Vulkan/VulkanContext.cpp index b901388a1c..ef139e4ca7 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -1,13 +1,14 @@ #define __STDC_LIMIT_MACROS + #include #include -#include #include #include -#include "base/basictypes.h" -#include "base/display.h" -#include "VulkanContext.h" +#include "Common/System/Display.h" +#include "Common/Log.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanDebug.h" #include "GPU/Common/ShaderCommon.h" #include "Common/StringUtils.h" #include "Core/Config.h" @@ -35,6 +36,8 @@ #define new DBG_NEW #endif +VulkanLogOptions g_LogOptions; + static const char *validationLayers[] = { "VK_LAYER_KHRONOS_validation", /* @@ -85,6 +88,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { return VK_ERROR_INITIALIZATION_FAILED; } + instance_layer_names_.clear(); + device_layer_names_.clear(); + // We can get the list of layers and extensions without an instance so we can use this information // to enable the extensions we need that are available. GetInstanceLayerProperties(); @@ -133,15 +139,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { } 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; + INFO_LOG(G3D, "Vulkan debug_utils validation enabled."); } else { - ELOG("Validation layer extension not available - not enabling Vulkan validation."); + ERROR_LOG(G3D, "Validation layer extension not available - not enabling Vulkan validation."); flags_ &= ~VULKAN_FLAG_VALIDATE; } } @@ -154,7 +154,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { // Validate that all the instance extensions we ask for are actually available. for (auto ext : instance_extensions_enabled_) { if (!IsInstanceExtensionAvailable(ext)) - WLOG("WARNING: Does not seem that instance extension '%s' is available. Trying to proceed anyway.", ext); + WARN_LOG(G3D, "WARNING: Does not seem that instance extension '%s' is available. Trying to proceed anyway.", ext); } VkApplicationInfo app_info{ VK_STRUCTURE_TYPE_APPLICATION_INFO }; @@ -180,7 +180,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { #endif if (res != VK_SUCCESS) { if (res == VK_ERROR_LAYER_NOT_PRESENT) { - WLOG("Validation on but layers not available - dropping layers"); + WARN_LOG(G3D, "Validation on but instance layer not available - dropping layers"); // Drop the validation layers and try again. instance_layer_names_.clear(); device_layer_names_.clear(); @@ -188,9 +188,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { inst_info.ppEnabledLayerNames = nullptr; res = vkCreateInstance(&inst_info, nullptr, &instance_); if (res != VK_SUCCESS) - ELOG("Failed to create instance even without validation: %d", res); + ERROR_LOG(G3D, "Failed to create instance even without validation: %d", res); } else { - ELOG("Failed to create instance : %d", res); + ERROR_LOG(G3D, "Failed to create instance : %d", res); } } if (res != VK_SUCCESS) { @@ -200,7 +200,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { VulkanLoadInstanceFunctions(instance_, extensionsLookup_); if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) { - WLOG("CheckLayers for instance failed"); + WARN_LOG(G3D, "CheckLayers for instance failed"); // init_error_ = "Failed to validate instance layers"; // return; } @@ -212,14 +212,14 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { res = vkEnumeratePhysicalDevices(instance_, &gpu_count, nullptr); #endif if (gpu_count <= 0) { - ELOG("Vulkan driver found but no supported GPU is available"); + ERROR_LOG(G3D, "Vulkan driver found but no supported GPU is available"); init_error_ = "No Vulkan physical devices found"; vkDestroyInstance(instance_, nullptr); instance_ = nullptr; return VK_ERROR_INITIALIZATION_FAILED; } - assert(gpu_count > 0); + _dbg_assert_(gpu_count > 0); physical_devices_.resize(gpu_count); physicalDeviceProperties_.resize(gpu_count); res = vkEnumeratePhysicalDevices(instance_, &gpu_count, physical_devices_.data()); @@ -250,14 +250,26 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { vkGetPhysicalDeviceProperties(physical_devices_[i], &physicalDeviceProperties_[i].properties); } } + + if (extensionsLookup_.EXT_debug_utils) { + InitDebugUtilsCallback(); + } + return VK_SUCCESS; } VulkanContext::~VulkanContext() { - assert(instance_ == VK_NULL_HANDLE); + _dbg_assert_(instance_ == VK_NULL_HANDLE); } void VulkanContext::DestroyInstance() { + if (extensionsLookup_.EXT_debug_utils) { + while (utils_callbacks.size() > 0) { + vkDestroyDebugUtilsMessengerEXT(instance_, utils_callbacks.back(), nullptr); + utils_callbacks.pop_back(); + } + } + vkDestroyInstance(instance_, nullptr); VulkanFree(); instance_ = VK_NULL_HANDLE; @@ -278,7 +290,7 @@ void VulkanContext::EndFrame() { } void VulkanContext::UpdateInflightFrames(int n) { - assert(n >= 1 && n <= MAX_INFLIGHT_FRAMES); + _dbg_assert_(n >= 1 && n <= MAX_INFLIGHT_FRAMES); inflightFrames_ = n; if (curFrame_ >= inflightFrames_) { curFrame_ = 0; @@ -306,26 +318,18 @@ bool VulkanContext::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirem return false; } -bool VulkanContext::InitObjects() { - if (!InitQueue()) { - return false; +void VulkanContext::DestroySwapchain() { + if (swapchain_ != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(device_, swapchain_, nullptr); + swapchain_ = VK_NULL_HANDLE; } - - if (!InitSwapchain()) { - // Destroy queue? - return false; - } - return true; } -void VulkanContext::DestroyObjects() { - ILOG("VulkanContext::DestroyObjects (including swapchain)"); - if (swapchain_ != VK_NULL_HANDLE) - vkDestroySwapchainKHR(device_, swapchain_, nullptr); - swapchain_ = VK_NULL_HANDLE; - - vkDestroySurfaceKHR(instance_, surface_, nullptr); - surface_ = VK_NULL_HANDLE; +void VulkanContext::DestroySurface() { + if (surface_ != VK_NULL_HANDLE) { + vkDestroySurfaceKHR(instance_, surface_, nullptr); + surface_ = VK_NULL_HANDLE; + } } VkResult VulkanContext::GetInstanceLayerExtensionList(const char *layerName, std::vector &extensions) { @@ -504,19 +508,19 @@ int VulkanContext::GetBestPhysicalDevice() { void VulkanContext::ChooseDevice(int physical_device) { physical_device_ = physical_device; - ILOG("Chose physical device %d: %p", physical_device, physical_devices_[physical_device]); + INFO_LOG(G3D, "Chose physical device %d: %p", physical_device, physical_devices_[physical_device]); GetDeviceLayerProperties(); if (!CheckLayers(device_layer_properties_, device_layer_names_)) { - WLOG("CheckLayers for device %d failed", physical_device); + WARN_LOG(G3D, "CheckLayers for device %d failed", physical_device); } vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr); - assert(queue_count >= 1); + _dbg_assert_(queue_count >= 1); queueFamilyProperties_.resize(queue_count); vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, queueFamilyProperties_.data()); - assert(queue_count >= 1); + _dbg_assert_(queue_count >= 1); // Detect preferred formats, in this order. static const VkFormat depthStencilFormats[] = { @@ -535,17 +539,17 @@ void VulkanContext::ChooseDevice(int physical_device) { } if (deviceInfo_.preferredDepthStencilFormat == VK_FORMAT_UNDEFINED) { // WTF? This is bad. - ELOG("Could not find a usable depth stencil format."); + ERROR_LOG(G3D, "Could not find a usable depth stencil format."); } // 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); + INFO_LOG(G3D, "Memory Types (%d):", memory_properties.memoryTypeCount); for (int i = 0; i < (int)memory_properties.memoryTypeCount; i++) { // Don't bother printing dummy memory types. if (!memory_properties.memoryTypes[i].propertyFlags) continue; - ILOG(" %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, + INFO_LOG(G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL " : "", (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE " : "", (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED " : "", @@ -607,7 +611,7 @@ bool VulkanContext::EnableDeviceExtension(const char *extension) { VkResult VulkanContext::CreateDevice() { if (!init_error_.empty() || physical_device_ < 0) { - ELOG("Vulkan init failed: %s", init_error_.c_str()); + ERROR_LOG(G3D, "Vulkan init failed: %s", init_error_.c_str()); return VK_ERROR_INITIALIZATION_FAILED; } @@ -623,7 +627,7 @@ VkResult VulkanContext::CreateDevice() { break; } } - assert(found); + _dbg_assert_(found); extensionsLookup_.KHR_maintenance1 = EnableDeviceExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME); extensionsLookup_.KHR_maintenance2 = EnableDeviceExtension(VK_KHR_MAINTENANCE2_EXTENSION_NAME); @@ -657,78 +661,47 @@ VkResult VulkanContext::CreateDevice() { VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_); if (res != VK_SUCCESS) { init_error_ = "Unable to create Vulkan device"; - ELOG("Unable to create Vulkan device"); + ERROR_LOG(G3D, "Unable to create Vulkan device"); } else { VulkanLoadDeviceFunctions(device_, extensionsLookup_); } - ILOG("Device created.\n"); + INFO_LOG(G3D, "Device created.\n"); VulkanSetAvailable(true); return res; } -VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata) { - VkDebugReportCallbackEXT msg_callback; +VkResult VulkanContext::InitDebugUtilsCallback() { + // We're intentionally skipping VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT and + // VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, just too spammy. + int bits = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - if (!(flags_ & VULKAN_FLAG_VALIDATE)) { - WLOG("Not registering debug report callback - extension not enabled!"); - return VK_SUCCESS; - } - ILOG("Registering debug report callback"); - - VkDebugReportCallbackCreateInfoEXT cb{VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT}; - cb.flags = bits; - cb.pfnCallback = dbgFunc; - cb.pUserData = userdata; - VkResult res = vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback); - switch (res) { - case VK_SUCCESS: - msg_callbacks.push_back(msg_callback); - break; - case VK_ERROR_OUT_OF_HOST_MEMORY: - return VK_ERROR_INITIALIZATION_FAILED; - default: - return VK_ERROR_INITIALIZATION_FAILED; - } - return res; -} - -void VulkanContext::DestroyDebugMsgCallback() { - if (!extensionsLookup_.EXT_debug_report) - return; - while (msg_callbacks.size() > 0) { - vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr); - msg_callbacks.pop_back(); - } -} - -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; + callback1.pfnUserCallback = &VulkanDebugUtilsCallback; + callback1.pUserData = (void *)&g_LogOptions; VkDebugUtilsMessengerEXT messenger; VkResult res = vkCreateDebugUtilsMessengerEXT(instance_, &callback1, nullptr, &messenger); if (res != VK_SUCCESS) { - ELOG("Failed to register debug callback with vkCreateDebugUtilsMessengerEXT"); + ERROR_LOG(G3D, "Failed to register debug callback with vkCreateDebugUtilsMessengerEXT"); // Do error handling for VK_ERROR_OUT_OF_MEMORY } else { - ILOG("Debug callback registered with vkCreateDebugUtilsMessengerEXT."); + INFO_LOG(G3D, "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(); - } +void VulkanContext::SetDebugNameImpl(uint64_t handle, VkObjectType type, const char *name) { + VkDebugUtilsObjectNameInfoEXT info{ VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT }; + info.pObjectName = name; + info.objectHandle = handle; + info.objectType = type; + vkSetDebugUtilsObjectNameEXT(device_, &info); } - VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2) { winsys_ = winsys; winsysData1_ = data1; @@ -738,12 +711,15 @@ VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data VkResult VulkanContext::ReinitSurface() { if (surface_ != VK_NULL_HANDLE) { - ILOG("Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height); + INFO_LOG(G3D, "Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height); vkDestroySurfaceKHR(instance_, surface_, nullptr); surface_ = VK_NULL_HANDLE; } - ILOG("Creating Vulkan surface for window"); + INFO_LOG(G3D, "Creating Vulkan surface for window (%p %p)", winsysData1_, winsysData2_); + + VkResult retval = VK_SUCCESS; + switch (winsys_) { #ifdef _WIN32 case WINDOWSYSTEM_WIN32: @@ -752,7 +728,8 @@ VkResult VulkanContext::ReinitSurface() { win32.flags = 0; win32.hwnd = (HWND)winsysData2_; win32.hinstance = (HINSTANCE)winsysData1_; - return vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); + retval = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); + break; } #endif #if defined(__ANDROID__) @@ -762,7 +739,8 @@ VkResult VulkanContext::ReinitSurface() { VkAndroidSurfaceCreateInfoKHR android{ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; android.flags = 0; android.window = wnd; - return vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); + retval = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_METAL_EXT) @@ -772,7 +750,8 @@ VkResult VulkanContext::ReinitSurface() { metal.flags = 0; metal.pLayer = winsysData1_; metal.pNext = winsysData2_; - return vkCreateMetalSurfaceEXT(instance_, &metal, nullptr, &surface_); + retval = vkCreateMetalSurfaceEXT(instance_, &metal, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) @@ -782,7 +761,8 @@ VkResult VulkanContext::ReinitSurface() { xlib.flags = 0; xlib.dpy = (Display *)winsysData1_; xlib.window = (Window)winsysData2_; - return vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); + retval = vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_XCB_KHR) @@ -792,7 +772,8 @@ VkResult VulkanContext::ReinitSurface() { xcb.flags = 0; xcb.connection = (Connection *)winsysData1_; xcb.window = (Window)(uintptr_t)winsysData2_; - return vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); + retval = vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) @@ -802,17 +783,28 @@ VkResult VulkanContext::ReinitSurface() { wayland.flags = 0; wayland.display = (wl_display *)winsysData1_; wayland.surface = (wl_surface *)winsysData2_; - return vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); + retval = vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); + break; } #endif default: - _assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented"); + _assert_msg_(false, "Vulkan support for chosen window system not implemented"); return VK_ERROR_INITIALIZATION_FAILED; } + + if (retval != VK_SUCCESS) { + return retval; + } + + if (!ChooseQueue()) { + return VK_ERROR_INITIALIZATION_FAILED; + } + + return VK_SUCCESS; } -bool VulkanContext::InitQueue() { +bool VulkanContext::ChooseQueue() { // Iterate over each queue to learn whether it supports presenting: VkBool32 *supportsPresent = new VkBool32[queue_count]; for (uint32_t i = 0; i < queue_count; i++) { @@ -850,7 +842,7 @@ bool VulkanContext::InitQueue() { // Generate error if could not find both a graphics and a present queue if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { - ELOG("Could not find a graphics and a present queue"); + ERROR_LOG(G3D, "Could not find a graphics and a present queue"); return false; } @@ -859,14 +851,14 @@ bool VulkanContext::InitQueue() { // Get the list of VkFormats that are supported: uint32_t formatCount = 0; VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, nullptr); - _assert_msg_(G3D, res == VK_SUCCESS, "Failed to get formats for device %d: %d", physical_device_, (int)res); + _assert_msg_(res == VK_SUCCESS, "Failed to get formats for device %d: %d", physical_device_, (int)res); if (res != VK_SUCCESS) { return false; } std::vector surfFormats(formatCount); res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, surfFormats.data()); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) { return false; } @@ -874,7 +866,7 @@ bool VulkanContext::InitQueue() { // the surface has no preferred format. Otherwise, at least one // supported format will be returned. if (formatCount == 0 || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) { - ILOG("swapchain_format: Falling back to B8G8R8A8_UNORM"); + INFO_LOG(G3D, "swapchain_format: Falling back to B8G8R8A8_UNORM"); swapchainFormat_ = VK_FORMAT_B8G8R8A8_UNORM; } else { swapchainFormat_ = VK_FORMAT_UNDEFINED; @@ -892,11 +884,10 @@ bool VulkanContext::InitQueue() { // Okay, take the first one then. swapchainFormat_ = surfFormats[0].format; } - ILOG("swapchain_format: %d (/%d)", swapchainFormat_, formatCount); + INFO_LOG(G3D, "swapchain_format: %d (/%d)", swapchainFormat_, formatCount); } vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_); - ILOG("gfx_queue_: %p", gfx_queue_); return true; } @@ -924,30 +915,36 @@ static std::string surface_transforms_to_string(VkSurfaceTransformFlagsKHR trans bool VulkanContext::InitSwapchain() { VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); uint32_t presentModeCount; res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, nullptr); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); VkPresentModeKHR *presentModes = new VkPresentModeKHR[presentModeCount]; - assert(presentModes); + _dbg_assert_(presentModes); res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, presentModes); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); - 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); - ILOG("swapChainExtent: %dx%d", swapChainExtent_.width, swapChainExtent_.height); + INFO_LOG(G3D, "surfCapabilities_.current: %dx%d min: %dx%d max: %dx%d computed: %dx%d", + surfCapabilities_.currentExtent.width, surfCapabilities_.currentExtent.height, + surfCapabilities_.minImageExtent.width, surfCapabilities_.minImageExtent.height, + surfCapabilities_.maxImageExtent.width, surfCapabilities_.maxImageExtent.height, + 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; + std::string modes = ""; for (size_t i = 0; i < presentModeCount; i++) { - ILOG("Supported present mode: %d (%s)", presentModes[i], PresentModeString(presentModes[i])); + modes += PresentModeString(presentModes[i]); + if (i != presentModeCount - 1) { + modes += ", "; + } } + INFO_LOG(G3D, "Supported present modes: %s", modes.c_str()); for (size_t i = 0; i < presentModeCount; i++) { bool match = false; match = match || ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR); @@ -967,13 +964,11 @@ bool VulkanContext::InitSwapchain() { // HACK swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; #endif - ILOG("Chosen present mode: %d (%s)", swapchainPresentMode, PresentModeString(swapchainPresentMode)); delete[] presentModes; // Determine the number of VkImage's to use in the swap chain (we desire to // own only 1 image at a time, besides the images being displayed and // queued for display): uint32_t desiredNumberOfSwapChainImages = surfCapabilities_.minImageCount + 1; - ILOG("numSwapChainImages: %d", desiredNumberOfSwapChainImages); if ((surfCapabilities_.maxImageCount > 0) && (desiredNumberOfSwapChainImages > surfCapabilities_.maxImageCount)) { @@ -981,14 +976,16 @@ bool VulkanContext::InitSwapchain() { desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount; } + INFO_LOG(G3D, "Chosen present mode: %d (%s). numSwapChainImages: %d/%d", + swapchainPresentMode, PresentModeString(swapchainPresentMode), + desiredNumberOfSwapChainImages, surfCapabilities_.maxImageCount); + // We mostly follow the practices from // https://arm-software.github.io/vulkan_best_practice_for_mobile_developers/samples/surface_rotation/surface_rotation_tutorial.html // VkSurfaceTransformFlagBitsKHR preTransform; std::string supportedTransforms = surface_transforms_to_string(surfCapabilities_.supportedTransforms); std::string currentTransform = surface_transforms_to_string(surfCapabilities_.currentTransform); - ILOG("Supported transforms: %s", supportedTransforms.c_str()); - ILOG("Current transform: %s", currentTransform.c_str()); g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); bool swapChainExtentSwap = false; @@ -1014,17 +1011,19 @@ bool VulkanContext::InitSwapchain() { std::swap(swapChainExtent_.width, swapChainExtent_.height); break; default: - assert(false); + _dbg_assert_(false); } } else { // Let the OS rotate the image (potentially slow on many Android devices) preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } + std::string preTransformStr = surface_transforms_to_string(preTransform); - ILOG("Chosen pretransform transform: %s", preTransformStr.c_str()); + + INFO_LOG(G3D, "Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str()); if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) { - ILOG("Applying PowerVR hack (rounding off the width!)"); + INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!)"); // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). // To keep the size consistent even with pretransform, do this after the swap. Should be fine. // This is fixed in newer PowerVR drivers but I don't know the cutoff. @@ -1044,6 +1043,7 @@ bool VulkanContext::InitSwapchain() { swap_chain_info.oldSwapchain = VK_NULL_HANDLE; swap_chain_info.clipped = true; swap_chain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + // Don't ask for TRANSFER_DST for the swapchain image, we don't use that. // if (surfCapabilities_.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) // swap_chain_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; @@ -1068,10 +1068,10 @@ bool VulkanContext::InitSwapchain() { res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swapchain_); if (res != VK_SUCCESS) { - ELOG("vkCreateSwapchainKHR failed!"); + ERROR_LOG(G3D, "vkCreateSwapchainKHR failed!"); return false; } - ILOG("Created swapchain: %dx%d", swap_chain_info.imageExtent.width, swap_chain_info.imageExtent.height); + INFO_LOG(G3D, "Created swapchain: %dx%d", swap_chain_info.imageExtent.width, swap_chain_info.imageExtent.height); return true; } @@ -1091,7 +1091,14 @@ void VulkanContext::PerformPendingDeletes() { } void VulkanContext::DestroyDevice() { - ILOG("VulkanContext::DestroyDevice (performing deletes)"); + if (swapchain_) { + ERROR_LOG(G3D, "DestroyDevice: Swapchain should have been destroyed."); + } + if (surface_) { + ERROR_LOG(G3D, "DestroyDevice: Surface should have been destroyed."); + } + + INFO_LOG(G3D, "VulkanContext::DestroyDevice (performing deletes)"); PerformPendingDeletes(); vkDestroyDevice(device_, nullptr); @@ -1267,22 +1274,22 @@ const char *VulkanResultToString(VkResult res) { } void VulkanDeleteList::Take(VulkanDeleteList &del) { - assert(cmdPools_.empty()); - assert(descPools_.empty()); - assert(modules_.empty()); - assert(buffers_.empty()); - assert(bufferViews_.empty()); - assert(images_.empty()); - assert(imageViews_.empty()); - assert(deviceMemory_.empty()); - assert(samplers_.empty()); - assert(pipelines_.empty()); - assert(pipelineCaches_.empty()); - assert(renderPasses_.empty()); - assert(framebuffers_.empty()); - assert(pipelineLayouts_.empty()); - assert(descSetLayouts_.empty()); - assert(callbacks_.empty()); + _dbg_assert_(cmdPools_.empty()); + _dbg_assert_(descPools_.empty()); + _dbg_assert_(modules_.empty()); + _dbg_assert_(buffers_.empty()); + _dbg_assert_(bufferViews_.empty()); + _dbg_assert_(images_.empty()); + _dbg_assert_(imageViews_.empty()); + _dbg_assert_(deviceMemory_.empty()); + _dbg_assert_(samplers_.empty()); + _dbg_assert_(pipelines_.empty()); + _dbg_assert_(pipelineCaches_.empty()); + _dbg_assert_(renderPasses_.empty()); + _dbg_assert_(framebuffers_.empty()); + _dbg_assert_(pipelineLayouts_.empty()); + _dbg_assert_(descSetLayouts_.empty()); + _dbg_assert_(callbacks_.empty()); cmdPools_ = std::move(del.cmdPools_); descPools_ = std::move(del.descPools_); modules_ = std::move(del.modules_); @@ -1384,7 +1391,7 @@ void VulkanDeleteList::PerformDeletes(VkDevice device) { } void VulkanContext::GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation) { - if (DeviceExtensions().KHR_dedicated_allocation) { + if (Extensions().KHR_dedicated_allocation) { VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; memReqInfo2.image = image; diff --git a/Common/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h similarity index 77% rename from Common/Vulkan/VulkanContext.h rename to Common/GPU/Vulkan/VulkanContext.h index 7a5e515265..a14f96bdd7 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -1,12 +1,13 @@ #pragma once -#include +#include #include #include #include -#include "base/logging.h" -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/Log.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanDebug.h" enum { VULKAN_FLAG_VALIDATE = 1, @@ -66,21 +67,21 @@ class VulkanDeleteList { public: // NOTE: These all take reference handles so they can zero the input value. - void QueueDeleteCommandPool(VkCommandPool &pool) { cmdPools_.push_back(pool); pool = VK_NULL_HANDLE; } - void QueueDeleteDescriptorPool(VkDescriptorPool &pool) { descPools_.push_back(pool); pool = VK_NULL_HANDLE; } - void QueueDeleteShaderModule(VkShaderModule &module) { modules_.push_back(module); module = VK_NULL_HANDLE; } - void QueueDeleteBuffer(VkBuffer &buffer) { buffers_.push_back(buffer); buffer = VK_NULL_HANDLE; } - void QueueDeleteBufferView(VkBufferView &bufferView) { bufferViews_.push_back(bufferView); bufferView = VK_NULL_HANDLE; } - void QueueDeleteImage(VkImage &image) { images_.push_back(image); image = VK_NULL_HANDLE; } - void QueueDeleteImageView(VkImageView &imageView) { imageViews_.push_back(imageView); imageView = VK_NULL_HANDLE; } - void QueueDeleteDeviceMemory(VkDeviceMemory &deviceMemory) { deviceMemory_.push_back(deviceMemory); deviceMemory = VK_NULL_HANDLE; } - void QueueDeleteSampler(VkSampler &sampler) { samplers_.push_back(sampler); sampler = VK_NULL_HANDLE; } - void QueueDeletePipeline(VkPipeline &pipeline) { pipelines_.push_back(pipeline); pipeline = VK_NULL_HANDLE; } - void QueueDeletePipelineCache(VkPipelineCache &pipelineCache) { pipelineCaches_.push_back(pipelineCache); pipelineCache = VK_NULL_HANDLE; } - void QueueDeleteRenderPass(VkRenderPass &renderPass) { renderPasses_.push_back(renderPass); renderPass = VK_NULL_HANDLE; } - void QueueDeleteFramebuffer(VkFramebuffer &framebuffer) { framebuffers_.push_back(framebuffer); framebuffer = VK_NULL_HANDLE; } - void QueueDeletePipelineLayout(VkPipelineLayout &pipelineLayout) { pipelineLayouts_.push_back(pipelineLayout); pipelineLayout = VK_NULL_HANDLE; } - void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; } + void QueueDeleteCommandPool(VkCommandPool &pool) { _dbg_assert_(pool != VK_NULL_HANDLE); cmdPools_.push_back(pool); pool = VK_NULL_HANDLE; } + void QueueDeleteDescriptorPool(VkDescriptorPool &pool) { _dbg_assert_(pool != VK_NULL_HANDLE); descPools_.push_back(pool); pool = VK_NULL_HANDLE; } + void QueueDeleteShaderModule(VkShaderModule &module) { _dbg_assert_(module != VK_NULL_HANDLE); modules_.push_back(module); module = VK_NULL_HANDLE; } + void QueueDeleteBuffer(VkBuffer &buffer) { _dbg_assert_(buffer != VK_NULL_HANDLE); buffers_.push_back(buffer); buffer = VK_NULL_HANDLE; } + void QueueDeleteBufferView(VkBufferView &bufferView) { _dbg_assert_(bufferView != VK_NULL_HANDLE); bufferViews_.push_back(bufferView); bufferView = VK_NULL_HANDLE; } + void QueueDeleteImage(VkImage &image) { _dbg_assert_(image != VK_NULL_HANDLE); images_.push_back(image); image = VK_NULL_HANDLE; } + void QueueDeleteImageView(VkImageView &imageView) { _dbg_assert_(imageView != VK_NULL_HANDLE); imageViews_.push_back(imageView); imageView = VK_NULL_HANDLE; } + void QueueDeleteDeviceMemory(VkDeviceMemory &deviceMemory) { _dbg_assert_(deviceMemory != VK_NULL_HANDLE); deviceMemory_.push_back(deviceMemory); deviceMemory = VK_NULL_HANDLE; } + void QueueDeleteSampler(VkSampler &sampler) { _dbg_assert_(sampler != VK_NULL_HANDLE); samplers_.push_back(sampler); sampler = VK_NULL_HANDLE; } + void QueueDeletePipeline(VkPipeline &pipeline) { _dbg_assert_(pipeline != VK_NULL_HANDLE); pipelines_.push_back(pipeline); pipeline = VK_NULL_HANDLE; } + void QueueDeletePipelineCache(VkPipelineCache &pipelineCache) { _dbg_assert_(pipelineCache != VK_NULL_HANDLE); pipelineCaches_.push_back(pipelineCache); pipelineCache = VK_NULL_HANDLE; } + void QueueDeleteRenderPass(VkRenderPass &renderPass) { _dbg_assert_(renderPass != VK_NULL_HANDLE); renderPasses_.push_back(renderPass); renderPass = VK_NULL_HANDLE; } + void QueueDeleteFramebuffer(VkFramebuffer &framebuffer) { _dbg_assert_(framebuffer != VK_NULL_HANDLE); framebuffers_.push_back(framebuffer); framebuffer = VK_NULL_HANDLE; } + void QueueDeletePipelineLayout(VkPipelineLayout &pipelineLayout) { _dbg_assert_(pipelineLayout != VK_NULL_HANDLE); pipelineLayouts_.push_back(pipelineLayout); pipelineLayout = VK_NULL_HANDLE; } + void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { _dbg_assert_(descSetLayout != VK_NULL_HANDLE); descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; } void QueueCallback(void(*func)(void *userdata), void *userdata) { callbacks_.push_back(Callback(func, userdata)); } void Take(VulkanDeleteList &del); @@ -146,12 +147,11 @@ public: VkResult InitSurface(WindowSystem winsys, void *data1, void *data2); VkResult ReinitSurface(); - bool InitQueue(); - bool InitObjects(); bool InitSwapchain(); - // Also destroys the surface. - void DestroyObjects(); + void DestroySwapchain(); + void DestroySurface(); + void DestroyDevice(); void PerformPendingDeletes(); @@ -167,15 +167,16 @@ public: void BeginFrame(); void EndFrame(); + // Simple workaround for the casting warning. + template + void SetDebugName(T handle, VkObjectType type, const char *name) { + if (extensionsLookup_.EXT_debug_utils) { + SetDebugNameImpl((uint64_t)handle, type, name); + } + } + bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); - 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) const { return physical_devices_[n]; } @@ -274,11 +275,17 @@ public: MAX_INFLIGHT_FRAMES = 3, }; - const VulkanDeviceExtensions &DeviceExtensions() { return extensionsLookup_; } + const VulkanExtensions &Extensions() { return extensionsLookup_; } void GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation); private: + bool ChooseQueue(); + + void SetDebugNameImpl(uint64_t handle, VkObjectType type, const char *name); + + VkResult InitDebugUtilsCallback(); + // A layer can expose extensions, keep track of those extensions here. struct LayerProperties { VkLayerProperties properties; @@ -310,7 +317,7 @@ private: std::vector device_extensions_enabled_; std::vector device_extension_properties_; - VulkanDeviceExtensions extensionsLookup_{}; + VulkanExtensions extensionsLookup_{}; std::vector physical_devices_; @@ -342,7 +349,6 @@ private: // the next time the frame comes around again. VulkanDeleteList globalDeleteList_; - std::vector msg_callbacks; std::vector utils_callbacks; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; @@ -373,3 +379,5 @@ std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props); // Simple heuristic. bool IsHashMaliDriverVersion(const VkPhysicalDeviceProperties &props); + +extern VulkanLogOptions g_LogOptions; diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp new file mode 100644 index 0000000000..f165d73609 --- /dev/null +++ b/Common/GPU/Vulkan/VulkanDebug.cpp @@ -0,0 +1,92 @@ +// Copyright (c) 2016- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include + +#include "Common/Log.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanDebug.h" + +VKAPI_ATTR 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; + if (messageCode == 101294395) { + // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed - benign perf warning + return false; + } + + 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 << ":" << messageCode << ") " << pMessage << "\n"; + + std::string msg = message.str(); + +#ifdef _WIN32 + 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 + + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + ERROR_LOG(G3D, "VKDEBUG: %s", msg.c_str()); + } else { + WARN_LOG(G3D, "VKDEBUG: %s", msg.c_str()); + } + + // false indicates that layer should not bail-out of an + // API call that had validation failures. This may mean that the + // app dies inside the driver due to invalid parameter(s). + // That's what would happen without validation layers, so we'll + // keep that behavior here. + return false; +} diff --git a/Common/Vulkan/VulkanDebug.h b/Common/GPU/Vulkan/VulkanDebug.h similarity index 63% rename from Common/Vulkan/VulkanDebug.h rename to Common/GPU/Vulkan/VulkanDebug.h index 10cb70d8ed..9287c1e8c5 100644 --- a/Common/Vulkan/VulkanDebug.h +++ b/Common/GPU/Vulkan/VulkanDebug.h @@ -17,7 +17,7 @@ #pragma once -#include "Common/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanContext.h" struct VulkanLogOptions { bool breakOnWarning; @@ -25,5 +25,4 @@ struct VulkanLogOptions { bool msgBoxOnError; }; -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); +VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData); diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp similarity index 85% rename from Common/Vulkan/VulkanImage.cpp rename to Common/GPU/Vulkan/VulkanImage.cpp index 614cd0e3fb..5301a47803 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -1,5 +1,5 @@ -#include "Common/Vulkan/VulkanImage.h" -#include "Common/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanImage.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" #include "Common/Log.h" void VulkanTexture::Wipe() { @@ -67,19 +67,23 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all 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)); + ERROR_LOG(G3D, "vkCreateImage failed: %s", VulkanResultToString(res)); return false; } + // Apply the tag + vulkan_ ->SetDebugName(image_, VK_OBJECT_TYPE_IMAGE, tag_.c_str()); + VkMemoryRequirements mem_reqs{}; bool dedicatedAllocation = false; vulkan_->GetImageMemoryRequirements(image_, &mem_reqs, &dedicatedAllocation); if (allocator && !dedicatedAllocation) { allocator_ = allocator; - offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); + // ok to use the tag like this, because the lifetime of the VulkanImage exceeds that of the allocation. + offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag().c_str()); if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { - ELOG("Image memory allocation failed (mem_reqs.size=%d, typebits=%08x", (int)mem_reqs.size, (int)mem_reqs.memoryTypeBits); + ERROR_LOG(G3D, "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; } @@ -100,8 +104,8 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all 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!"); + ERROR_LOG(G3D, "vkAllocateMemory failed: %s", VulkanResultToString(res)); + _assert_msg_(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); return false; } @@ -111,7 +115,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all res = vkBindImageMemory(vulkan_->GetDevice(), image_, mem_, offset_); if (res != VK_SUCCESS) { - ELOG("vkBindImageMemory failed: %s", VulkanResultToString(res)); + ERROR_LOG(G3D, "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; @@ -153,7 +157,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view_); if (res != VK_SUCCESS) { - ELOG("vkCreateImageView failed: %s", VulkanResultToString(res)); + ERROR_LOG(G3D, "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; @@ -161,6 +165,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all return true; } +// TODO: Batch these. void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) { VkBufferImageCopy copy_region{}; copy_region.bufferOffset = offset; @@ -177,9 +182,23 @@ void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mi vkCmdCopyBufferToImage(cmd, buffer, image_, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region); } +void VulkanTexture::ClearMip(VkCommandBuffer cmd, int mip, uint32_t value) { + // Must be in TRANSFER_DST mode. + VkClearColorValue clearVal; + for (int i = 0; i < 4; i++) { + clearVal.float32[i] = ((value >> (i * 8)) & 0xFF) / 255.0f; + } + VkImageSubresourceRange range{}; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.layerCount = 1; + range.baseMipLevel = mip; + range.levelCount = 1; + vkCmdClearColorImage(cmd, image_, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearVal, 1, &range); +} + void VulkanTexture::GenerateMip(VkCommandBuffer cmd, int mip) { - _assert_msg_(G3D, mip != 0, "Cannot generate the first level"); - _assert_msg_(G3D, mip < numMips_, "Cannot generate mipmaps past the maximum created (%d vs %d)", mip, numMips_); + _assert_msg_(mip != 0, "Cannot generate the first level"); + _assert_msg_(mip < numMips_, "Cannot generate mipmaps past the maximum created (%d vs %d)", mip, numMips_); VkImageBlit blit{}; blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.srcSubresource.layerCount = 1; @@ -239,7 +258,7 @@ VkImageView VulkanTexture::CreateViewForMip(int mip) { view_info.subresourceRange.layerCount = 1; VkImageView view; VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view); - assert(res == VK_SUCCESS); + _assert_(res == VK_SUCCESS); return view; } diff --git a/Common/Vulkan/VulkanImage.h b/Common/GPU/Vulkan/VulkanImage.h similarity index 92% rename from Common/Vulkan/VulkanImage.h rename to Common/GPU/Vulkan/VulkanImage.h index 2c809b2bdb..0745e0e352 100644 --- a/Common/Vulkan/VulkanImage.h +++ b/Common/GPU/Vulkan/VulkanImage.h @@ -1,6 +1,6 @@ #pragma once -#include "Common/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanContext.h" class VulkanDeviceAllocator; @@ -19,6 +19,7 @@ public: // Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip. // When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. bool CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *allocator, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); + void ClearMip(VkCommandBuffer cmd, int mip, uint32_t value); void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels void GenerateMip(VkCommandBuffer cmd, int mip); void EndCreate(VkCommandBuffer cmd, bool vertexTexture = false, VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); @@ -29,10 +30,10 @@ public: void Destroy(); - void SetTag(const std::string &tag) { + void SetTag(const char *tag) { tag_ = tag; } - std::string Tag() const { + const std::string &Tag() const { return tag_; } void Touch(); diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp similarity index 89% rename from Common/Vulkan/VulkanLoader.cpp rename to Common/GPU/Vulkan/VulkanLoader.cpp index c748696c2c..f319979c8a 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -15,13 +15,13 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" #include #include +#include -#include "base/logging.h" -#include "base/basictypes.h" -#include "base/NativeApp.h" +#include "Common/Log.h" +#include "Common/System/System.h" #ifndef _WIN32 #include @@ -199,10 +199,6 @@ PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; PFN_vkQueuePresentKHR vkQueuePresentKHR; -// And the DEBUG_REPORT extension. We dynamically load this. -PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; -PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; - PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; @@ -228,9 +224,9 @@ const char *VulkanResultToString(VkResult res); bool g_vulkanAvailabilityChecked = false; bool g_vulkanMayBeAvailable = false; -#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {ILOG("Missing (instance): %s", #x);} -#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {ILOG("Missing (device): %s", #x);} -#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {ILOG("Missing (global): %s", #x);} +#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {INFO_LOG(G3D, "Missing (instance): %s", #x);} +#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {INFO_LOG(G3D, "Missing (device): %s", #x);} +#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {INFO_LOG(G3D,"Missing (global): %s", #x);} #define LOAD_GLOBAL_FUNC_LOCAL(lib, x) (PFN_ ## x)dlsym(lib, #x); @@ -263,20 +259,20 @@ bool VulkanMayBeAvailable() { std::string name = System_GetProperty(SYSPROP_NAME); for (const char *blacklisted_name : device_name_blacklist) { if (!strcmp(name.c_str(), blacklisted_name)) { - ILOG("VulkanMayBeAvailable: Device blacklisted ('%s')", name.c_str()); + INFO_LOG(G3D, "VulkanMayBeAvailable: Device blacklisted ('%s')", name.c_str()); g_vulkanAvailabilityChecked = true; g_vulkanMayBeAvailable = false; return false; } } - ILOG("VulkanMayBeAvailable: Device allowed ('%s')", name.c_str()); + INFO_LOG(G3D, "VulkanMayBeAvailable: Device allowed ('%s')", name.c_str()); #ifndef _WIN32 void *lib = nullptr; for (int i = 0; i < ARRAY_SIZE(so_names); i++) { lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL); if (lib) { - ILOG("VulkanMayBeAvailable: Library loaded ('%s')", so_names[i]); + INFO_LOG(G3D, "VulkanMayBeAvailable: Library loaded ('%s')", so_names[i]); break; } } @@ -285,7 +281,7 @@ bool VulkanMayBeAvailable() { HINSTANCE lib = LoadLibrary(L"vulkan-1.dll"); #endif if (!lib) { - ILOG("Vulkan loader: Library not available"); + INFO_LOG(G3D, "Vulkan loader: Library not available"); g_vulkanAvailabilityChecked = true; g_vulkanMayBeAvailable = false; return false; @@ -325,32 +321,32 @@ bool VulkanMayBeAvailable() { #endif if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) { - WLOG("VulkanMayBeAvailable: Function pointer missing, bailing"); + WARN_LOG(G3D, "VulkanMayBeAvailable: Function pointer missing, bailing"); goto bail; } - ILOG("VulkanMayBeAvailable: Enumerating instance extensions"); + INFO_LOG(G3D, "VulkanMayBeAvailable: Enumerating instance extensions"); res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr); // Maximum paranoia. if (res != VK_SUCCESS) { - ELOG("Enumerating VK extensions failed (%s)", VulkanResultToString(res)); + ERROR_LOG(G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res)); goto bail; } if (instanceExtCount == 0) { - ELOG("No VK instance extensions - won't be able to present."); + ERROR_LOG(G3D, "No VK instance extensions - won't be able to present."); goto bail; } - ILOG("VulkanMayBeAvailable: Instance extension count: %d", instanceExtCount); + INFO_LOG(G3D, "VulkanMayBeAvailable: Instance extension count: %d", instanceExtCount); instanceExts.resize(instanceExtCount); res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data()); if (res != VK_SUCCESS) { - ELOG("Enumerating VK extensions failed (%s)", VulkanResultToString(res)); + ERROR_LOG(G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res)); goto bail; } for (auto iter : instanceExts) { - ILOG("VulkanMaybeAvailable: Instance extension found: %s (%08x)", iter.extensionName, iter.specVersion); + INFO_LOG(G3D, "VulkanMaybeAvailable: Instance extension found: %s (%08x)", iter.extensionName, iter.specVersion); if (platformSurfaceExtension && !strcmp(iter.extensionName, platformSurfaceExtension)) { - ILOG("VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension); + INFO_LOG(G3D, "VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension); instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension; platformSurfaceExtensionFound = true; break; @@ -361,19 +357,19 @@ bool VulkanMayBeAvailable() { } if (platformSurfaceExtension) { if (!platformSurfaceExtensionFound || !surfaceExtensionFound) { - ELOG("Platform surface extension not found"); + ERROR_LOG(G3D, "Platform surface extension not found"); goto bail; } } else { if (!surfaceExtensionFound) { - ELOG("Surface extension not found"); + ERROR_LOG(G3D, "Surface extension not found"); goto bail; } } // This can't happen unless the driver is double-reporting a surface extension. if (ci.enabledExtensionCount > 2) { - ELOG("Unexpected number of enabled instance extensions"); + ERROR_LOG(G3D, "Unexpected number of enabled instance extensions"); goto bail; } @@ -386,27 +382,27 @@ bool VulkanMayBeAvailable() { info.pEngineName = "VulkanCheckerEngine"; ci.pApplicationInfo = &info; ci.flags = 0; - ILOG("VulkanMayBeAvailable: Calling vkCreateInstance"); + INFO_LOG(G3D, "VulkanMayBeAvailable: Calling vkCreateInstance"); res = localCreateInstance(&ci, nullptr, &instance); if (res != VK_SUCCESS) { instance = nullptr; - ELOG("VulkanMayBeAvailable: Failed to create vulkan instance (%s)", VulkanResultToString(res)); + ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to create vulkan instance (%s)", VulkanResultToString(res)); goto bail; } - ILOG("VulkanMayBeAvailable: Vulkan test instance created successfully."); + INFO_LOG(G3D, "VulkanMayBeAvailable: Vulkan test instance created successfully."); res = localEnumerate(instance, &physicalDeviceCount, nullptr); if (res != VK_SUCCESS) { - ELOG("VulkanMayBeAvailable: Failed to count physical devices (%s)", VulkanResultToString(res)); + ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to count physical devices (%s)", VulkanResultToString(res)); goto bail; } if (physicalDeviceCount == 0) { - ELOG("VulkanMayBeAvailable: No physical Vulkan devices (count = 0)."); + ERROR_LOG(G3D, "VulkanMayBeAvailable: No physical Vulkan devices (count = 0)."); goto bail; } devices.resize(physicalDeviceCount); res = localEnumerate(instance, &physicalDeviceCount, devices.data()); if (res != VK_SUCCESS) { - ELOG("VulkanMayBeAvailable: Failed to enumerate physical devices (%s)", VulkanResultToString(res)); + ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to enumerate physical devices (%s)", VulkanResultToString(res)); goto bail; } anyGood = false; @@ -420,24 +416,24 @@ bool VulkanMayBeAvailable() { anyGood = true; break; default: - ILOG("VulkanMayBeAvailable: Ineligible device found and ignored: '%s'", props.deviceName); + INFO_LOG(G3D, "VulkanMayBeAvailable: Ineligible device found and ignored: '%s'", props.deviceName); break; } // TODO: Should also check queuefamilyproperties for a GRAPHICS queue family? Oh well. } if (!anyGood) { - WLOG("VulkanMayBeAvailable: Found Vulkan API, but no good Vulkan device!"); + WARN_LOG(G3D, "VulkanMayBeAvailable: Found Vulkan API, but no good Vulkan device!"); g_vulkanMayBeAvailable = false; } else { - ILOG("VulkanMayBeAvailable: Found working Vulkan API!"); + INFO_LOG(G3D, "VulkanMayBeAvailable: Found working Vulkan API!"); g_vulkanMayBeAvailable = true; } bail: g_vulkanAvailabilityChecked = true; if (instance) { - ILOG("VulkanMayBeAvailable: Destroying instance"); + INFO_LOG(G3D, "VulkanMayBeAvailable: Destroying instance"); localDestroyInstance(instance, nullptr); } if (lib) { @@ -447,7 +443,7 @@ bail: FreeLibrary(lib); #endif } else { - ELOG("Vulkan with working device not detected."); + ERROR_LOG(G3D, "Vulkan with working device not detected."); } return g_vulkanMayBeAvailable; } @@ -458,7 +454,7 @@ bool VulkanLoad() { for (int i = 0; i < ARRAY_SIZE(so_names); i++) { vulkanLibrary = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL); if (vulkanLibrary) { - ILOG("VulkanLoad: Found library '%s'", so_names[i]); + INFO_LOG(G3D, "VulkanLoad: Found library '%s'", so_names[i]); break; } } @@ -479,10 +475,10 @@ bool VulkanLoad() { LOAD_GLOBAL_FUNC(vkEnumerateInstanceLayerProperties); if (vkCreateInstance && vkGetInstanceProcAddr && vkGetDeviceProcAddr && vkEnumerateInstanceExtensionProperties && vkEnumerateInstanceLayerProperties) { - WLOG("VulkanLoad: Base functions loaded."); + INFO_LOG(G3D, "VulkanLoad: Base functions loaded."); return true; } else { - ELOG("VulkanLoad: Failed to load Vulkan base functions."); + ERROR_LOG(G3D, "VulkanLoad: Failed to load Vulkan base functions."); #ifndef _WIN32 dlclose(vulkanLibrary); #else @@ -493,7 +489,7 @@ bool VulkanLoad() { } } -void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions) { +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions) { // OK, let's use the above functions to get the rest. LOAD_INSTANCE_FUNC(instance, vkDestroyInstance); LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices); @@ -542,11 +538,6 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensio 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); @@ -557,14 +548,14 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensio LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectTagEXT); } - WLOG("Vulkan instance functions loaded."); + INFO_LOG(G3D, "Vulkan instance functions loaded."); } // On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may // increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very // good for multi-device - not likely we'll ever try that anyway though. -void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions) { - WLOG("Vulkan device functions loaded."); +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions) { + INFO_LOG(G3D, "Vulkan device functions loaded."); LOAD_DEVICE_FUNC(device, vkQueueSubmit); LOAD_DEVICE_FUNC(device, vkQueueWaitIdle); diff --git a/Common/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h similarity index 96% rename from Common/Vulkan/VulkanLoader.h rename to Common/GPU/Vulkan/VulkanLoader.h index 99b560cfa6..c91ad6296c 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/GPU/Vulkan/VulkanLoader.h @@ -199,11 +199,6 @@ extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; 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 vkCreateDebugReportCallbackEXT; -extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; - extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; @@ -219,10 +214,8 @@ extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesE extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; - // For fast extension-enabled checks. -struct VulkanDeviceExtensions { - bool EXT_debug_report; +struct VulkanExtensions { bool EXT_debug_utils; bool KHR_maintenance1; // required for KHR_create_renderpass2 bool KHR_maintenance2; @@ -243,6 +236,6 @@ bool VulkanMayBeAvailable(); void VulkanSetAvailable(bool available); bool VulkanLoad(); -void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions); -void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions); +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions); +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions); void VulkanFree(); diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp similarity index 85% rename from Common/Vulkan/VulkanMemory.cpp rename to Common/GPU/Vulkan/VulkanMemory.cpp index 3673d3ea6f..ce002733b7 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/GPU/Vulkan/VulkanMemory.cpp @@ -18,19 +18,20 @@ // Additionally, Common/Vulkan/* , including this file, are also licensed // under the public domain. +#include "Common/Math/math_util.h" + #include "Common/Log.h" -#include "Common/Vulkan/VulkanMemory.h" -#include "base/timeutil.h" -#include "math/math_util.h" +#include "Common/TimeUtil.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryPropertyMask) : vulkan_(vulkan), memoryPropertyMask_(memoryPropertyMask), size_(size), usage_(usage) { bool res = AddBuffer(); - assert(res); + _assert_(res); } VulkanPushBuffer::~VulkanPushBuffer() { - assert(buffers_.empty()); + _assert_(buffers_.empty()); } bool VulkanPushBuffer::AddBuffer() { @@ -47,7 +48,7 @@ bool VulkanPushBuffer::AddBuffer() { VkResult res = vkCreateBuffer(device, &b, nullptr, &info.buffer); if (VK_SUCCESS != res) { - _assert_msg_(G3D, false, "vkCreateBuffer failed! result=%d", (int)res); + _assert_msg_(false, "vkCreateBuffer failed! result=%d", (int)res); return false; } @@ -62,13 +63,13 @@ bool VulkanPushBuffer::AddBuffer() { res = vkAllocateMemory(device, &alloc, nullptr, &info.deviceMemory); if (VK_SUCCESS != res) { - _assert_msg_(G3D, false, "vkAllocateMemory failed! size=%d result=%d", (int)reqs.size, (int)res); + _assert_msg_(false, "vkAllocateMemory failed! size=%d result=%d", (int)reqs.size, (int)res); vkDestroyBuffer(device, info.buffer, nullptr); return false; } res = vkBindBufferMemory(device, info.buffer, info.deviceMemory, 0); if (VK_SUCCESS != res) { - ELOG("vkBindBufferMemory failed! result=%d", (int)res); + ERROR_LOG(G3D, "vkBindBufferMemory failed! result=%d", (int)res); vkFreeMemory(device, info.deviceMemory, nullptr); vkDestroyBuffer(device, info.buffer, nullptr); return false; @@ -100,7 +101,7 @@ void VulkanPushBuffer::NextBuffer(size_t minSize) { } bool res = AddBuffer(); - assert(res); + _assert_(res); if (!res) { // Let's try not to crash at least? buf_ = 0; @@ -124,7 +125,7 @@ void VulkanPushBuffer::Defragment(VulkanContext *vulkan) { size_ = newSize; bool res = AddBuffer(); - assert(res); + _assert_(res); } size_t VulkanPushBuffer::GetTotalSize() const { @@ -136,14 +137,16 @@ size_t VulkanPushBuffer::GetTotalSize() const { } void VulkanPushBuffer::Map() { - _dbg_assert_(G3D, !writePtr_); + _dbg_assert_(!writePtr_); VkResult res = vkMapMemory(vulkan_->GetDevice(), buffers_[buf_].deviceMemory, 0, size_, 0, (void **)(&writePtr_)); - _dbg_assert_(G3D, writePtr_); - assert(VK_SUCCESS == res); + _dbg_assert_(writePtr_); + _assert_(VK_SUCCESS == res); } void VulkanPushBuffer::Unmap() { - _dbg_assert_(G3D, writePtr_ != 0); + _dbg_assert_msg_(writePtr_ != nullptr, "VulkanPushBuffer::Unmap: writePtr_ null here means we have a bug (map/unmap mismatch)"); + if (!writePtr_) + return; if ((memoryPropertyMask_ & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) { VkMappedMemoryRange range{ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; @@ -159,12 +162,12 @@ void VulkanPushBuffer::Unmap() { VulkanDeviceAllocator::VulkanDeviceAllocator(VulkanContext *vulkan, size_t minSlabSize, size_t maxSlabSize) : vulkan_(vulkan), minSlabSize_(minSlabSize), maxSlabSize_(maxSlabSize) { - assert((minSlabSize_ & (SLAB_GRAIN_SIZE - 1)) == 0); + _assert_((minSlabSize_ & (SLAB_GRAIN_SIZE - 1)) == 0); } VulkanDeviceAllocator::~VulkanDeviceAllocator() { - assert(destroyed_); - assert(slabs_.empty()); + _assert_(destroyed_); + _assert_(slabs_.empty()); } void VulkanDeviceAllocator::Destroy() { @@ -177,23 +180,23 @@ void VulkanDeviceAllocator::Destroy() { if (slabUsage == 1) { ERROR_LOG(G3D, "VulkanDeviceAllocator detected memory leak of size %d", (int)pair.second); } else { - _dbg_assert_msg_(G3D, slabUsage == 2, "Destroy: slabUsage has unexpected value %d", slabUsage); + _dbg_assert_msg_(slabUsage == 2, "Destroy: slabUsage has unexpected value %d", slabUsage); } } - assert(slab.deviceMemory); + _assert_(slab.deviceMemory); vulkan_->Delete().QueueDeleteDeviceMemory(slab.deviceMemory); } slabs_.clear(); destroyed_ = true; } -size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDeviceMemory *deviceMemory, const std::string &tag) { - assert(!destroyed_); +size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDeviceMemory *deviceMemory, const char *tag) { + _assert_(!destroyed_); uint32_t memoryTypeIndex; bool pass = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex); if (!pass) { - ELOG("Failed to pick an appropriate memory type (req: %08x)", reqs.memoryTypeBits); + ERROR_LOG(G3D, "Failed to pick an appropriate memory type (req: %08x)", reqs.memoryTypeBits); return ALLOCATE_FAILED; } @@ -241,8 +244,8 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic return ALLOCATE_FAILED; } -bool VulkanDeviceAllocator::AllocateFromSlab(Slab &slab, size_t &start, size_t blocks, const std::string &tag) { - assert(!destroyed_); +bool VulkanDeviceAllocator::AllocateFromSlab(Slab &slab, size_t &start, size_t blocks, const char *tag) { + _assert_(!destroyed_); bool matched = true; if (start + blocks > slab.usage.size()) { @@ -275,7 +278,7 @@ bool VulkanDeviceAllocator::AllocateFromSlab(Slab &slab, size_t &start, size_t b // Remember the size so we can free. slab.allocSizes[start] = blocks; - slab.tags[start] = { tag, time_now(), 0.0f }; + slab.tags[start] = { time_now_d(), 0.0, tag }; slab.totalUsage += blocks; return true; } @@ -309,18 +312,18 @@ void VulkanDeviceAllocator::DoTouch(VkDeviceMemory deviceMemory, size_t offset) auto it = slab.tags.find(start); if (it != slab.tags.end()) { - it->second.touched = time_now(); + it->second.touched = time_now_d(); found = true; } } - _assert_msg_(G3D, found, "Failed to find allocation to touch - use after free?"); + _assert_msg_(found, "Failed to find allocation to touch - use after free?"); } void VulkanDeviceAllocator::Free(VkDeviceMemory deviceMemory, size_t offset) { - assert(!destroyed_); + _assert_(!destroyed_); - _assert_msg_(G3D, !slabs_.empty(), "No slabs - can't be anything to free! double-freed?"); + _assert_msg_(!slabs_.empty(), "No slabs - can't be anything to free! double-freed?"); // First, let's validate. This will allow stack traces to tell us when frees are bad. size_t start = offset >> SLAB_GRAIN_SHIFT; @@ -331,9 +334,9 @@ void VulkanDeviceAllocator::Free(VkDeviceMemory deviceMemory, size_t offset) { } auto it = slab.allocSizes.find(start); - _assert_msg_(G3D, it != slab.allocSizes.end(), "Double free?"); + _assert_msg_(it != slab.allocSizes.end(), "Double free?"); // This means a double free, while queued to actually free. - _assert_msg_(G3D, slab.usage[start] == 1, "Double free when queued to free!"); + _assert_msg_(slab.usage[start] == 1, "Double free when queued to free!"); // Mark it as "free in progress". slab.usage[start] = 2; @@ -342,7 +345,7 @@ void VulkanDeviceAllocator::Free(VkDeviceMemory deviceMemory, size_t offset) { } // Wrong deviceMemory even? Maybe it was already decimated, but that means a double-free. - _assert_msg_(G3D, found, "Failed to find allocation to free! Double-freed?"); + _assert_msg_(found, "Failed to find allocation to free! Double-freed?"); // Okay, now enqueue. It's valid. FreeInfo *info = new FreeInfo(this, deviceMemory, offset); @@ -383,7 +386,7 @@ void VulkanDeviceAllocator::ExecuteFree(FreeInfo *userdata) { } } else { // Ack, a double free? - _assert_msg_(G3D, false, "Double free? Block missing at offset %d", (int)userdata->offset); + _assert_msg_(false, "Double free? Block missing at offset %d", (int)userdata->offset); } auto itTag = slab.tags.find(start); if (itTag != slab.tags.end()) { @@ -394,12 +397,12 @@ void VulkanDeviceAllocator::ExecuteFree(FreeInfo *userdata) { } // Wrong deviceMemory even? Maybe it was already decimated, but that means a double-free. - _assert_msg_(G3D, found, "ExecuteFree: Block not found (offset %d)", (int)offset); + _assert_msg_(found, "ExecuteFree: Block not found (offset %d)", (int)offset); delete userdata; } bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex) { - assert(!destroyed_); + _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? @@ -418,7 +421,7 @@ bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes, int memoryTypeIn VkResult res = vkAllocateMemory(vulkan_->GetDevice(), &alloc, NULL, &deviceMemory); if (res != VK_SUCCESS) { // If it's something else, we used it wrong? - assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); + _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); // Okay, so we ran out of memory. return false; } @@ -433,15 +436,15 @@ bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes, int memoryTypeIn } void VulkanDeviceAllocator::ReportOldUsage() { - float now = time_now(); - static const float OLD_AGE = 10.0f; + double now = time_now_d(); + static const double OLD_AGE = 10.0; for (size_t i = 0; i < slabs_.size(); ++i) { const auto &slab = slabs_[i]; bool hasOldAllocs = false; - for (auto it : slab.tags) { + for (auto &it : slab.tags) { const auto info = it.second; - float touchedAge = now - info.touched; + double touchedAge = now - info.touched; if (touchedAge >= OLD_AGE) { hasOldAllocs = true; break; @@ -450,19 +453,19 @@ void VulkanDeviceAllocator::ReportOldUsage() { if (hasOldAllocs) { NOTICE_LOG(G3D, "Slab %d usage:", (int)i); - for (auto it : slab.tags) { + for (auto &it : slab.tags) { const auto info = it.second; - float createAge = now - info.created; - float touchedAge = now - info.touched; - NOTICE_LOG(G3D, " * %s (created %fs ago, used %fs ago)", info.tag.c_str(), createAge, touchedAge); + double createAge = now - info.created; + double touchedAge = now - info.touched; + NOTICE_LOG(G3D, " * %s (created %fs ago, used %fs ago)", info.tag, createAge, touchedAge); } } } } void VulkanDeviceAllocator::Decimate() { - assert(!destroyed_); + _assert_(!destroyed_); bool foundFree = false; if (TRACK_TOUCH) { diff --git a/Common/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h similarity index 94% rename from Common/Vulkan/VulkanMemory.h rename to Common/GPU/Vulkan/VulkanMemory.h index 5c4cec8b1e..fc415681a0 100644 --- a/Common/Vulkan/VulkanMemory.h +++ b/Common/GPU/Vulkan/VulkanMemory.h @@ -2,7 +2,9 @@ #include #include -#include "Common/Vulkan/VulkanContext.h" + +#include "Common/Log.h" +#include "Common/GPU/Vulkan/VulkanContext.h" // VulkanMemory // @@ -73,14 +75,14 @@ public: // Returns the offset that should be used when binding this buffer to get this data. size_t Push(const void *data, size_t size, VkBuffer *vkbuf) { - assert(writePtr_); + _dbg_assert_(writePtr_); size_t off = Allocate(size, vkbuf); memcpy(writePtr_ + off, data, size); return off; } uint32_t PushAligned(const void *data, size_t size, int align, VkBuffer *vkbuf) { - assert(writePtr_); + _dbg_assert_(writePtr_); offset_ = (offset_ + align - 1) & ~(align - 1); size_t off = Allocate(size, vkbuf); memcpy(writePtr_ + off, data, size); @@ -94,13 +96,13 @@ public: // "Zero-copy" variant - you can write the data directly as you compute it. // Recommended. void *Push(size_t size, uint32_t *bindOffset, VkBuffer *vkbuf) { - assert(writePtr_); + _dbg_assert_(writePtr_); size_t off = Allocate(size, vkbuf); *bindOffset = (uint32_t)off; return writePtr_ + off; } void *PushAligned(size_t size, uint32_t *bindOffset, VkBuffer *vkbuf, int align) { - assert(writePtr_); + _dbg_assert_(writePtr_); offset_ = (offset_ + align - 1) & ~(align - 1); size_t off = Allocate(size, vkbuf); *bindOffset = (uint32_t)off; @@ -147,7 +149,8 @@ public: } // May return ALLOCATE_FAILED if the allocation fails. - size_t Allocate(const VkMemoryRequirements &reqs, VkDeviceMemory *deviceMemory, const std::string &tag); + // NOTE: Lifetime of the string tag points to must exceed that of the allocation. + size_t Allocate(const VkMemoryRequirements &reqs, VkDeviceMemory *deviceMemory, const char *tag); // Crashes on a double or misfree. void Free(VkDeviceMemory deviceMemory, size_t offset); @@ -175,9 +178,9 @@ private: static const uint32_t UNDEFINED_MEMORY_TYPE = -1; struct UsageInfo { - std::string tag; - float created; - float touched; + double created; + double touched; + const char *tag; }; struct Slab { @@ -210,7 +213,7 @@ private: } bool AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex); - bool AllocateFromSlab(Slab &slab, size_t &start, size_t blocks, const std::string &tag); + bool AllocateFromSlab(Slab &slab, size_t &start, size_t blocks, const char *tag); void Decimate(); void DoTouch(VkDeviceMemory deviceMemory, size_t offset); void ExecuteFree(FreeInfo *userdata); diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp similarity index 79% rename from ext/native/thin3d/VulkanQueueRunner.cpp rename to Common/GPU/Vulkan/VulkanQueueRunner.cpp index a74a679e6e..ff5fb56d2f 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1,31 +1,32 @@ #include -#include "base/timeutil.h" -#include "DataFormat.h" +#include "Common/GPU/DataFormat.h" +#include "Common/Log.h" +#include "Common/TimeUtil.h" #include "VulkanQueueRunner.h" #include "VulkanRenderManager.h" // Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP NativeGLView NativeRenderer NativeSurfaceView PowerSaveModeReceiver InputDeviceState void VulkanQueueRunner::CreateDeviceObjects() { - ILOG("VulkanQueueRunner::CreateDeviceObjects"); + INFO_LOG(G3D, "VulkanQueueRunner::CreateDeviceObjects"); InitBackbufferRenderPass(); framebufferRenderPass_ = GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); #if 0 // Just to check whether it makes sense to split some of these. drawidx is way bigger than the others... // We should probably just move to variable-size data in a raw buffer anyway... VkRenderData rd; - ILOG("sizeof(pipeline): %d", (int)sizeof(rd.pipeline)); - ILOG("sizeof(draw): %d", (int)sizeof(rd.draw)); - ILOG("sizeof(drawidx): %d", (int)sizeof(rd.drawIndexed)); - ILOG("sizeof(clear): %d", (int)sizeof(rd.clear)); - ILOG("sizeof(viewport): %d", (int)sizeof(rd.viewport)); - ILOG("sizeof(scissor): %d", (int)sizeof(rd.scissor)); - ILOG("sizeof(blendColor): %d", (int)sizeof(rd.blendColor)); - ILOG("sizeof(push): %d", (int)sizeof(rd.push)); + INFO_LOG(G3D, "sizeof(pipeline): %d", (int)sizeof(rd.pipeline)); + INFO_LOG(G3D, "sizeof(draw): %d", (int)sizeof(rd.draw)); + INFO_LOG(G3D, "sizeof(drawidx): %d", (int)sizeof(rd.drawIndexed)); + INFO_LOG(G3D, "sizeof(clear): %d", (int)sizeof(rd.clear)); + INFO_LOG(G3D, "sizeof(viewport): %d", (int)sizeof(rd.viewport)); + INFO_LOG(G3D, "sizeof(scissor): %d", (int)sizeof(rd.scissor)); + INFO_LOG(G3D, "sizeof(blendColor): %d", (int)sizeof(rd.blendColor)); + INFO_LOG(G3D, "sizeof(push): %d", (int)sizeof(rd.push)); #endif } @@ -48,7 +49,8 @@ void VulkanQueueRunner::ResizeReadbackBuffer(VkDeviceSize requiredSize) { buf.size = readbackBufferSize_; buf.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; - vkCreateBuffer(device, &buf, nullptr, &readbackBuffer_); + VkResult res = vkCreateBuffer(device, &buf, nullptr, &readbackBuffer_); + _assert_(res == VK_SUCCESS); VkMemoryRequirements reqs{}; vkGetBufferMemoryRequirements(device, readbackBuffer_, &reqs); @@ -74,7 +76,7 @@ void VulkanQueueRunner::ResizeReadbackBuffer(VkDeviceSize requiredSize) { _assert_(successTypeReqs != 0); readbackBufferIsCoherent_ = (successTypeReqs & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0; - VkResult res = vkAllocateMemory(device, &allocInfo, nullptr, &readbackMemory_); + res = vkAllocateMemory(device, &allocInfo, nullptr, &readbackMemory_); if (res != VK_SUCCESS) { readbackMemory_ = VK_NULL_HANDLE; vkDestroyBuffer(device, readbackBuffer_, nullptr); @@ -86,9 +88,13 @@ void VulkanQueueRunner::ResizeReadbackBuffer(VkDeviceSize requiredSize) { } void VulkanQueueRunner::DestroyDeviceObjects() { - ILOG("VulkanQueueRunner::DestroyDeviceObjects"); - vulkan_->Delete().QueueDeleteDeviceMemory(readbackMemory_); - vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_); + INFO_LOG(G3D, "VulkanQueueRunner::DestroyDeviceObjects"); + if (readbackMemory_) { + vulkan_->Delete().QueueDeleteDeviceMemory(readbackMemory_); + } + if (readbackBuffer_) { + vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_); + } readbackBufferSize_ = 0; renderPasses_.Iterate([&](const RPKey &rpkey, VkRenderPass rp) { @@ -97,7 +103,7 @@ void VulkanQueueRunner::DestroyDeviceObjects() { }); renderPasses_.Clear(); - assert(backbufferRenderPass_ != VK_NULL_HANDLE); + _assert_(backbufferRenderPass_ != VK_NULL_HANDLE); vulkan_->Delete().QueueDeleteRenderPass(backbufferRenderPass_); backbufferRenderPass_ = VK_NULL_HANDLE; } @@ -237,8 +243,8 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { attachments[1].initialLayout = VK_IMAGE_LAYOUT_GENERAL; attachments[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL; #else - attachments[1].initialLayout = key.prevDepthLayout; - attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[1].initialLayout = key.prevDepthStencilLayout; + attachments[1].finalLayout = key.finalDepthStencilLayout; #endif attachments[1].flags = 0; @@ -289,11 +295,11 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; break; default: - _dbg_assert_msg_(G3D, false, "GetRenderPass: Unexpected color layout %d", (int)key.prevColorLayout); + _dbg_assert_msg_(false, "GetRenderPass: Unexpected color layout %d", (int)key.prevColorLayout); break; } - switch (key.prevDepthLayout) { + switch (key.prevDepthStencilLayout) { case VK_IMAGE_LAYOUT_UNDEFINED: // No need to specify stage or access. break; @@ -313,7 +319,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; break; default: - _dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected depth layout %d", (int)key.prevDepthLayout); + _dbg_assert_msg_(false, "GetRenderPass: Unexpected depth layout %d", (int)key.prevDepthStencilLayout); break; } @@ -346,7 +352,29 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { // Nothing to do. break; default: - _dbg_assert_msg_(G3D, false, "GetRenderPass: Unexpected final color layout %d", (int)key.finalColorLayout); + _dbg_assert_msg_(false, "GetRenderPass: Unexpected final color layout %d", (int)key.finalColorLayout); + break; + } + + switch (key.finalDepthStencilLayout) { + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + deps[numDeps].dstAccessMask |= VK_ACCESS_SHADER_READ_BIT; + deps[numDeps].dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + deps[numDeps].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; + deps[numDeps].dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + deps[numDeps].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; + deps[numDeps].dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + // Nothing to do. + break; + default: + _dbg_assert_msg_(false, "GetRenderPass: Unexpected final depth layout %d", (int)key.finalDepthStencilLayout); break; } @@ -354,8 +382,8 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { deps[numDeps].srcSubpass = 0; deps[numDeps].dstSubpass = VK_SUBPASS_EXTERNAL; deps[numDeps].dependencyFlags = 0; - deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - deps[numDeps].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + deps[numDeps].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; numDeps++; } @@ -377,9 +405,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { return pass; } -void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &steps, QueueProfileContext *profile) { - if (profile) - profile->cpuStartTime = real_time_now(); +void VulkanQueueRunner::PreprocessSteps(std::vector &steps) { // Optimizes renderpasses, then sequences them. // Planned optimizations: // * Create copies of render target that are rendered to multiple times and textured from in sequence, and push those render passes @@ -387,10 +413,13 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st for (int j = 0; j < (int)steps.size(); j++) { if (steps[j]->stepType == VKRStepType::RENDER && - steps[j]->render.framebuffer && - steps[j]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - // Just leave it at color_optimal. - steps[j]->render.finalColorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + steps[j]->render.framebuffer) { + if (steps[j]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps[j]->render.finalColorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + if (steps[j]->render.finalDepthStencilLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps[j]->render.finalDepthStencilLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } } } @@ -446,9 +475,22 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st ApplyRenderPassMerge(steps); } } +} +void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &steps, QueueProfileContext *profile) { + if (profile) + profile->cpuStartTime = time_now_d(); + + bool emitLabels = vulkan_->Extensions().EXT_debug_utils; for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; + + if (emitLabels) { + VkDebugUtilsLabelEXT labelInfo{ VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT }; + labelInfo.pLabelName = step.tag; + vkCmdBeginDebugUtilsLabelEXT(cmd, &labelInfo); + } + switch (step.stepType) { case VKRStepType::RENDER: PerformRenderPass(step, cmd); @@ -473,6 +515,10 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st vkCmdWriteTimestamp(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, profile->queryPool, (uint32_t)profile->timestampDescriptions.size()); profile->timestampDescriptions.push_back(StepToString(step)); } + + if (emitLabels) { + vkCmdEndDebugUtilsLabelEXT(cmd); + } } // Deleting all in one go should be easier on the instruction cache than deleting @@ -482,7 +528,7 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st } if (profile) - profile->cpuEndTime = real_time_now(); + profile->cpuEndTime = time_now_d(); } void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { @@ -543,7 +589,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { for (int j = 0; j < (int)renders.size(); j++) { steps[i + j + copies.size()] = renders[j]; } - assert(steps[i + copies.size()]->stepType == VKRStepType::RENDER); + _assert_(steps[i + copies.size()]->stepType == VKRStepType::RENDER); // Combine the renders. for (int j = 1; j < (int)renders.size(); j++) { for (int k = 0; k < (int)renders[j]->commands.size(); k++) { @@ -573,7 +619,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { VKRFramebuffer *depalFramebuffer = steps[i]->render.framebuffer; VKRFramebuffer *targetFramebuffer = steps[i + 1]->render.framebuffer; // OK, found the start of a post-process sequence. Let's scan until we find the end. - for (int j = i; j < steps.size() - 3; j++) { + for (int j = i; j < (int)steps.size() - 3; j++) { if (((j - i) & 1) == 0) { // This should be a depal draw. if (steps[j]->render.numDraws != 1) @@ -714,6 +760,16 @@ void VulkanQueueRunner::ApplySonicHack(std::vector &steps) { } } +const char *AspectToString(VkImageAspectFlags aspect) { + switch (aspect) { + case VK_IMAGE_ASPECT_COLOR_BIT: return "COLOR"; + case VK_IMAGE_ASPECT_DEPTH_BIT: return "DEPTH"; + case VK_IMAGE_ASPECT_STENCIL_BIT: return "STENCIL"; + case VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT: return "DEPTHSTENCIL"; + default: return "UNUSUAL"; + } +} + std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { char buffer[256]; switch (step.stepType) { @@ -721,23 +777,23 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { { int w = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth(); int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight(); - snprintf(buffer, sizeof(buffer), "RenderPass (draws: %d, %dx%d, fb: %p, )", step.render.numDraws, w, h, step.render.framebuffer); + snprintf(buffer, sizeof(buffer), "RENDER %s (draws: %d, %dx%d, fb: %p, )", step.tag, step.render.numDraws, w, h, step.render.framebuffer); break; } case VKRStepType::COPY: - snprintf(buffer, sizeof(buffer), "Copy (%dx%d)", step.copy.srcRect.extent.width, step.copy.srcRect.extent.height); + snprintf(buffer, sizeof(buffer), "COPY '%s' %s -> %s (%dx%d, %s)", step.tag, step.copy.src->tag.c_str(), step.copy.dst->tag.c_str(), step.copy.srcRect.extent.width, step.copy.srcRect.extent.height, AspectToString(step.copy.aspectMask)); break; case VKRStepType::BLIT: - snprintf(buffer, sizeof(buffer), "Blit (%dx%d->%dx%d)", step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height); + snprintf(buffer, sizeof(buffer), "BLIT '%s' %s -> %s (%dx%d->%dx%d, %s)", step.tag, step.copy.src->tag.c_str(), step.copy.dst->tag.c_str(), step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height, AspectToString(step.blit.aspectMask)); break; case VKRStepType::READBACK: - snprintf(buffer, sizeof(buffer), "Readback (%dx%d, fb: %p)", step.readback.srcRect.extent.width, step.readback.srcRect.extent.height, step.readback.src); + snprintf(buffer, sizeof(buffer), "READBACK '%s' %s (%dx%d, %s)", step.tag, step.readback.src->tag.c_str(), step.readback.srcRect.extent.width, step.readback.srcRect.extent.height, AspectToString(step.readback.aspectMask)); break; case VKRStepType::READBACK_IMAGE: - snprintf(buffer, sizeof(buffer), "ReadbackImage (%dx%d)", step.readback_image.srcRect.extent.width, step.readback_image.srcRect.extent.height); + snprintf(buffer, sizeof(buffer), "READBACK_IMAGE '%s' (%dx%d)", step.tag, step.readback_image.srcRect.extent.width, step.readback_image.srcRect.extent.height); break; case VKRStepType::RENDER_SKIP: - snprintf(buffer, sizeof(buffer), "(SKIPPED RenderPass)"); + snprintf(buffer, sizeof(buffer), "(RENDER_SKIP) %s", step.tag); break; default: buffer[0] = 0; @@ -833,14 +889,13 @@ void VulkanQueueRunner::ApplyRenderPassMerge(std::vector &steps) { } } -void VulkanQueueRunner::LogSteps(const std::vector &steps) { - ILOG("======================================="); +void VulkanQueueRunner::LogSteps(const std::vector &steps, bool verbose) { + INFO_LOG(G3D, "=================== FRAME ===================="); for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; - ILOG("%s", StepToString(step).c_str()); switch (step.stepType) { case VKRStepType::RENDER: - LogRenderPass(step); + LogRenderPass(step, verbose); break; case VKRStepType::COPY: LogCopy(step); @@ -855,78 +910,118 @@ void VulkanQueueRunner::LogSteps(const std::vector &steps) { LogReadbackImage(step); break; case VKRStepType::RENDER_SKIP: - ILOG("(skipped render pass)"); + INFO_LOG(G3D, "(skipped render pass)"); break; } } + INFO_LOG(G3D, "------------------- SUBMIT ------------------"); +} + +const char *RenderPassActionName(VKRRenderPassAction a) { + switch (a) { + case VKRRenderPassAction::CLEAR: + return "CLEAR"; + case VKRRenderPassAction::DONT_CARE: + return "DONT_CARE"; + case VKRRenderPassAction::KEEP: + return "KEEP"; + } + return "?"; +} + +const char *ImageLayoutToString(VkImageLayout layout) { + switch (layout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return "COLOR_ATTACHMENT"; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return "DEPTH_STENCIL_ATTACHMENT"; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return "SHADER_READ_ONLY"; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return "TRANSFER_SRC"; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return "TRANSFER_DST"; + case VK_IMAGE_LAYOUT_GENERAL: return "GENERAL"; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: return "PRESENT_SRC_KHR"; + case VK_IMAGE_LAYOUT_UNDEFINED: return "UNDEFINED"; + default: return "(unknown)"; + } } -void VulkanQueueRunner::LogRenderPass(const VKRStep &pass) { - int fb = (int)(intptr_t)(pass.render.framebuffer ? pass.render.framebuffer->framebuf : 0); - ILOG("RenderPass Begin(%x)", fb); - for (auto &cmd : pass.commands) { - switch (cmd.cmd) { - case VKRRenderCommand::REMOVED: - ILOG(" (Removed)"); - break; +void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { + const auto &r = pass.render; + const char *framebuf = r.framebuffer ? r.framebuffer->tag.c_str() : "backbuffer"; + int w = r.framebuffer ? r.framebuffer->width : vulkan_->GetBackbufferWidth(); + int h = r.framebuffer ? r.framebuffer->height : vulkan_->GetBackbufferHeight(); - case VKRRenderCommand::BIND_PIPELINE: - ILOG(" BindPipeline(%x)", (int)(intptr_t)cmd.pipeline.pipeline); - break; - case VKRRenderCommand::BLEND: - ILOG(" BlendColor(%08x)", cmd.blendColor.color); - break; - case VKRRenderCommand::CLEAR: - ILOG(" Clear"); - break; - case VKRRenderCommand::DRAW: - ILOG(" Draw(%d)", cmd.draw.count); - break; - case VKRRenderCommand::DRAW_INDEXED: - ILOG(" DrawIndexed(%d)", cmd.drawIndexed.count); - break; - case VKRRenderCommand::SCISSOR: - ILOG(" Scissor(%d, %d, %d, %d)", (int)cmd.scissor.scissor.offset.x, (int)cmd.scissor.scissor.offset.y, (int)cmd.scissor.scissor.extent.width, (int)cmd.scissor.scissor.extent.height); - break; - case VKRRenderCommand::STENCIL: - ILOG(" Stencil(ref=%d, compare=%d, write=%d)", cmd.stencil.stencilRef, cmd.stencil.stencilCompareMask, cmd.stencil.stencilWriteMask); - break; - case VKRRenderCommand::VIEWPORT: - ILOG(" Viewport(%f, %f, %f, %f, %f, %f)", cmd.viewport.vp.x, cmd.viewport.vp.y, cmd.viewport.vp.width, cmd.viewport.vp.height, cmd.viewport.vp.minDepth, cmd.viewport.vp.maxDepth); - break; - case VKRRenderCommand::PUSH_CONSTANTS: - ILOG(" PushConstants(%d)", cmd.push.size); - break; + INFO_LOG(G3D, "RENDER %s Begin(%s, draws: %d, %dx%d, %s, %s, %s)", pass.tag, framebuf, r.numDraws, w, h, RenderPassActionName(r.color), RenderPassActionName(r.depth), RenderPassActionName(r.stencil)); + // TODO: Log these in detail. + for (int i = 0; i < pass.preTransitions.size(); i++) { + INFO_LOG(G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->tag.c_str(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout)); + } - case VKRRenderCommand::NUM_RENDER_COMMANDS: - break; + if (verbose) { + for (auto &cmd : pass.commands) { + switch (cmd.cmd) { + case VKRRenderCommand::REMOVED: + INFO_LOG(G3D, " (Removed)"); + break; + + case VKRRenderCommand::BIND_PIPELINE: + INFO_LOG(G3D, " BindPipeline(%x)", (int)(intptr_t)cmd.pipeline.pipeline); + break; + case VKRRenderCommand::BLEND: + INFO_LOG(G3D, " BlendColor(%08x)", cmd.blendColor.color); + break; + case VKRRenderCommand::CLEAR: + INFO_LOG(G3D, " Clear"); + break; + case VKRRenderCommand::DRAW: + INFO_LOG(G3D, " Draw(%d)", cmd.draw.count); + break; + case VKRRenderCommand::DRAW_INDEXED: + INFO_LOG(G3D, " DrawIndexed(%d)", cmd.drawIndexed.count); + break; + case VKRRenderCommand::SCISSOR: + INFO_LOG(G3D, " Scissor(%d, %d, %d, %d)", (int)cmd.scissor.scissor.offset.x, (int)cmd.scissor.scissor.offset.y, (int)cmd.scissor.scissor.extent.width, (int)cmd.scissor.scissor.extent.height); + break; + case VKRRenderCommand::STENCIL: + INFO_LOG(G3D, " Stencil(ref=%d, compare=%d, write=%d)", cmd.stencil.stencilRef, cmd.stencil.stencilCompareMask, cmd.stencil.stencilWriteMask); + break; + case VKRRenderCommand::VIEWPORT: + INFO_LOG(G3D, " Viewport(%f, %f, %f, %f, %f, %f)", cmd.viewport.vp.x, cmd.viewport.vp.y, cmd.viewport.vp.width, cmd.viewport.vp.height, cmd.viewport.vp.minDepth, cmd.viewport.vp.maxDepth); + break; + case VKRRenderCommand::PUSH_CONSTANTS: + INFO_LOG(G3D, " PushConstants(%d)", cmd.push.size); + break; + + case VKRRenderCommand::NUM_RENDER_COMMANDS: + break; + } } } - ILOG("RenderPass End(%x)", fb); + + INFO_LOG(G3D, " Final: %s %s", ImageLayoutToString(pass.render.finalColorLayout), ImageLayoutToString(pass.render.finalDepthStencilLayout)); + INFO_LOG(G3D, "RENDER End(%s) - %d commands executed", framebuf, (int)pass.commands.size()); } void VulkanQueueRunner::LogCopy(const VKRStep &step) { - ILOG("%s", StepToString(step).c_str()); + INFO_LOG(G3D, "%s", StepToString(step).c_str()); } void VulkanQueueRunner::LogBlit(const VKRStep &step) { - ILOG("%s", StepToString(step).c_str()); + INFO_LOG(G3D, "%s", StepToString(step).c_str()); } void VulkanQueueRunner::LogReadback(const VKRStep &step) { - ILOG("%s", StepToString(step).c_str()); + INFO_LOG(G3D, "%s", StepToString(step).c_str()); } void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) { - ILOG("%s", StepToString(step).c_str()); + INFO_LOG(G3D, "%s", StepToString(step).c_str()); } void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) { // TODO: If there are multiple, we can transition them together. + for (const auto &iter : step.preTransitions) { - if (iter.fb->color.layout != iter.targetLayout) { - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + if (iter.aspect == VK_IMAGE_ASPECT_COLOR_BIT && iter.fb->color.layout != iter.targetLayout) { + VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; barrier.oldLayout = iter.fb->color.layout; barrier.subresourceRange.layerCount = 1; barrier.subresourceRange.levelCount = 1; @@ -951,7 +1046,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; default: - _assert_msg_(G3D, false, "PerformRenderPass: Unexpected oldLayout: %d", (int)barrier.oldLayout); + _assert_msg_(false, "PerformRenderPass: Unexpected oldLayout: %d", (int)barrier.oldLayout); break; } barrier.newLayout = iter.targetLayout; @@ -961,41 +1056,111 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; default: - _assert_msg_(G3D, false, "PerformRenderPass: Unexpected newLayout: %d", (int)barrier.newLayout); + _assert_msg_(false, "PerformRenderPass: Unexpected newLayout: %d", (int)barrier.newLayout); break; } barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vkCmdPipelineBarrier(cmd, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); iter.fb->color.layout = barrier.newLayout; + } else if ((iter.aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) && iter.fb->depth.layout != iter.targetLayout) { + VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + barrier.oldLayout = iter.fb->depth.layout; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; + barrier.image = iter.fb->depth.image; + barrier.srcAccessMask = 0; + VkPipelineStageFlags srcStage; + VkPipelineStageFlags dstStage; + switch (barrier.oldLayout) { + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + srcStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + default: + Crash(); + break; + } + barrier.newLayout = iter.targetLayout; + switch (barrier.newLayout) { + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + default: + Crash(); + break; + } + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkCmdPipelineBarrier(cmd, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); + iter.fb->depth.layout = barrier.newLayout; } } // Don't execute empty renderpasses that keep the contents. if (step.commands.empty() && step.render.color == VKRRenderPassAction::KEEP && step.render.depth == VKRRenderPassAction::KEEP && step.render.stencil == VKRRenderPassAction::KEEP) { // Nothing to do. + + // TODO: Though - a later step might have used this step's finalColorLayout etc to get things in a layout it expects. + // Should we just do a barrier? Or just let the later step deal with not having things in its preferred layout, like now? + return; } - if (step.render.framebuffer && step.render.framebuffer->color.layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier.subresourceRange.layerCount = 1; - barrier.subresourceRange.levelCount = 1; - barrier.image = step.render.framebuffer->color.image; - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); + // Write-after-write hazards. Fixed flicker in God of War on ARM (before we added another fix that removed these). + if (step.render.framebuffer) { + int n = 0; + int stage = 0; + VkImageMemoryBarrier barriers[2]{}; + if (step.render.framebuffer->color.layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { + barriers[n].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[n].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barriers[n].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barriers[n].subresourceRange.layerCount = 1; + barriers[n].subresourceRange.levelCount = 1; + barriers[n].image = step.render.framebuffer->color.image; + barriers[n].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barriers[n].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + barriers[n].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[n].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[n].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + stage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + n++; + } + if (step.render.framebuffer->depth.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { + barriers[n].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[n].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barriers[n].newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barriers[n].subresourceRange.layerCount = 1; + barriers[n].subresourceRange.levelCount = 1; + barriers[n].image = step.render.framebuffer->depth.image; + barriers[n].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barriers[n].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + barriers[n].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + barriers[n].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[n].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + stage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + n++; + } + if (stage) { + vkCmdPipelineBarrier(cmd, stage, stage, 0, 0, nullptr, 0, nullptr, n, barriers); + // No need to modify the image layouts here - it's just an execution barrier. + } } - // This is supposed to bind a vulkan render pass to the command buffer. + // This reads the layout of the color and depth images, and chooses a render pass using them that + // will transition to the desired final layout. PerformBindFramebufferAsRenderTarget(step, cmd); int curWidth = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth(); @@ -1056,8 +1221,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c const VkRect2D &rc = c.scissor.scissor; DisplayRect rotated_rc{ rc.offset.x, rc.offset.y, (int)rc.extent.width, (int)rc.extent.height }; RotateRectToDisplay(rotated_rc, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - _dbg_assert_(G3D, rotated_rc.x >= 0); - _dbg_assert_(G3D, rotated_rc.y >= 0); + _dbg_assert_(rotated_rc.x >= 0); + _dbg_assert_(rotated_rc.y >= 0); VkRect2D finalRect = VkRect2D{ { rotated_rc.x, rotated_rc.y }, { (uint32_t)rotated_rc.w, (uint32_t)rotated_rc.h} }; vkCmdSetScissor(cmd, 0, 1, &finalRect); } @@ -1115,7 +1280,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c rc.layerCount = 1; rc.rect.extent.width = (uint32_t)curWidth; rc.rect.extent.height = (uint32_t)curHeight; - VkClearAttachment attachments[2]; + VkClearAttachment attachments[2]{}; if (c.clear.clearMask & VK_IMAGE_ASPECT_COLOR_BIT) { VkClearAttachment &attachment = attachments[numAttachments++]; attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -1140,7 +1305,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c break; } default: - ELOG("Unimpl queue command"); + ERROR_LOG(G3D, "Unimpl queue command"); ; } } @@ -1149,6 +1314,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c // The renderpass handles the layout transition. if (fb) { fb->color.layout = step.render.finalColorLayout; + fb->depth.layout = step.render.finalDepthStencilLayout; } } @@ -1160,7 +1326,8 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step int w; int h; if (step.render.framebuffer) { - _dbg_assert_(G3D, step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED); + _dbg_assert_(step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED); + _dbg_assert_(step.render.finalDepthStencilLayout != VK_IMAGE_LAYOUT_UNDEFINED); VKRFramebuffer *fb = step.render.framebuffer; framebuf = fb->framebuf; @@ -1185,11 +1352,13 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step renderPass = GetRenderPass( step.render.color, step.render.depth, step.render.stencil, - fb->color.layout, fb->depth.layout, step.render.finalColorLayout); + fb->color.layout, fb->depth.layout, + step.render.finalColorLayout, + step.render.finalDepthStencilLayout); // We now do any layout pretransitions as part of the render pass. - fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + fb->color.layout = step.render.finalColorLayout; + fb->depth.layout = step.render.finalDepthStencilLayout; if (step.render.color == VKRRenderPassAction::CLEAR) { Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor); @@ -1259,13 +1428,14 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { } } - // We can't copy only depth or only stencil unfortunately. + // We can't copy only depth or only stencil unfortunately - or can we?. if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (src->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { SetupTransitionToTransferSrc(src->depth, srcBarriers[srcCount++], srcStage, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); } if (dst->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { SetupTransitionToTransferDst(dst->depth, dstBarriers[dstCount++], dstStage, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + _dbg_assert_(dst->depth.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } } @@ -1282,16 +1452,8 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { vkCmdCopyImage(cmd, src->color.image, src->color.layout, dst->color.image, dst->color.layout, 1, ©); } if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - copy.srcSubresource.aspectMask = 0; - copy.dstSubresource.aspectMask = 0; - if (step.copy.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) { - copy.srcSubresource.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - copy.dstSubresource.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - } - if (step.copy.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) { - copy.srcSubresource.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - copy.dstSubresource.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } + copy.srcSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + copy.dstSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); vkCmdCopyImage(cmd, src->depth.image, src->depth.layout, dst->depth.image, dst->depth.layout, 1, ©); } } @@ -1404,7 +1566,7 @@ void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageMemor stage |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; default: - _dbg_assert_msg_(G3D, false, "Transition from this layout to transfer src not supported (%d)", (int)img.layout); + _dbg_assert_msg_(false, "Transition from this layout to transfer src not supported (%d)", (int)img.layout); break; } barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; @@ -1463,7 +1625,7 @@ void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageMemor stage |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; default: - _dbg_assert_msg_(G3D, false, "Transition from this layout to transfer dst not supported (%d)", (int)img.layout); + _dbg_assert_msg_(false, "Transition from this layout to transfer dst not supported (%d)", (int)img.layout); break; } barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -1528,7 +1690,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd } else if (step.readback.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { srcImage = &step.readback.src->depth; } else { - _dbg_assert_msg_(G3D, false, "No image aspect to readback?"); + _dbg_assert_msg_(false, "No image aspect to readback?"); return; } @@ -1560,7 +1722,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffer cmd) { // TODO: Clean this up - just reusing `SetupTransitionToTransferSrc`. - VKRImage srcImage; + VKRImage srcImage{}; srcImage.image = step.readback_image.image; srcImage.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -1611,7 +1773,7 @@ void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataForm } if (res != VK_SUCCESS) { - ELOG("CopyReadbackBuffer: vkMapMemory failed! result=%d", (int)res); + ERROR_LOG(G3D, "CopyReadbackBuffer: vkMapMemory failed! result=%d", (int)res); return; } @@ -1621,6 +1783,7 @@ void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataForm } else if (srcFormat == Draw::DataFormat::B8G8R8A8_UNORM) { ConvertFromBGRA8888(pixels, (const uint8_t *)mappedData, pixelStride, width, width, height, destFormat); } else if (srcFormat == destFormat) { + // Can just memcpy when it matches no matter the format! uint8_t *dst = pixels; const uint8_t *src = (const uint8_t *)mappedData; for (int y = 0; y < height; ++y) { @@ -1632,8 +1795,8 @@ void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataForm ConvertToD32F(pixels, (const uint8_t *)mappedData, pixelStride, width, width, height, srcFormat); } else { // TODO: Maybe a depth conversion or something? - ELOG("CopyReadbackBuffer: Unknown format"); - assert(false); + ERROR_LOG(G3D, "CopyReadbackBuffer: Unknown format"); + _assert_msg_(false, "CopyReadbackBuffer: Unknown src format %d", (int)srcFormat); } vkUnmapMemory(vulkan_->GetDevice(), readbackMemory_); } diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h similarity index 89% rename from ext/native/thin3d/VulkanQueueRunner.h rename to Common/GPU/Vulkan/VulkanQueueRunner.h index 1c9e46a5cf..ada7cc49e2 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -2,11 +2,11 @@ #include -#include "Common/Hashmaps.h" -#include "Common/Vulkan/VulkanContext.h" -#include "math/dataconv.h" -#include "thin3d/DataFormat.h" -#include "util/tiny_set.h" +#include "Common/Data/Collections/Hashmaps.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Data/Collections/TinySet.h" +#include "Common/GPU/DataFormat.h" class VKRFramebuffer; struct VKRImage; @@ -107,6 +107,7 @@ enum class VKRRenderPassAction : uint8_t { }; struct TransitionRequest { + VkImageAspectFlags aspect; // COLOR or DEPTH VKRFramebuffer *fb; VkImageLayout targetLayout; }; @@ -127,6 +128,7 @@ struct VKRStep { std::vector commands; std::vector preTransitions; TinySet dependencies; + const char *tag; union { struct { VKRFramebuffer *framebuffer; @@ -140,6 +142,7 @@ struct VKRStep { // Downloads and textures from this pass. int numReads; VkImageLayout finalColorLayout; + VkImageLayout finalDepthStencilLayout; } render; struct { VKRFramebuffer *src; @@ -177,9 +180,9 @@ public: backbufferImage_ = img; } - // RunSteps can modify steps but will leave it in a valid state. + void PreprocessSteps(std::vector &steps); void RunSteps(VkCommandBuffer cmd, std::vector &steps, QueueProfileContext *profile); - void LogSteps(const std::vector &steps); + void LogSteps(const std::vector &steps, bool verbose); std::string StepToString(const VKRStep &step) const; @@ -207,16 +210,16 @@ public: VKRRenderPassAction depthLoadAction; VKRRenderPassAction stencilLoadAction; VkImageLayout prevColorLayout; - VkImageLayout prevDepthLayout; + VkImageLayout prevDepthStencilLayout; VkImageLayout finalColorLayout; - // TODO: Also pre-transition depth, for copies etc. + VkImageLayout finalDepthStencilLayout; }; // Only call this from the render thread! Also ok during initialization (LoadCache). VkRenderPass GetRenderPass( VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction, - VkImageLayout prevColorLayout, VkImageLayout prevDepthLayout, VkImageLayout finalColorLayout) { - RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction, prevColorLayout, prevDepthLayout, finalColorLayout }; + VkImageLayout prevColorLayout, VkImageLayout prevDepthStencilLayout, VkImageLayout finalColorLayout, VkImageLayout finalDepthStencilLayout) { + RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction, prevColorLayout, prevDepthStencilLayout, finalColorLayout, finalDepthStencilLayout }; return GetRenderPass(key); } @@ -247,7 +250,7 @@ private: void PerformReadback(const VKRStep &pass, VkCommandBuffer cmd); void PerformReadbackImage(const VKRStep &pass, VkCommandBuffer cmd); - void LogRenderPass(const VKRStep &pass); + void LogRenderPass(const VKRStep &pass, bool verbose); void LogCopy(const VKRStep &pass); void LogBlit(const VKRStep &pass); void LogReadback(const VKRStep &pass); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp similarity index 69% rename from ext/native/thin3d/VulkanRenderManager.cpp rename to Common/GPU/Vulkan/VulkanRenderManager.cpp index 475b64aa06..0a60251896 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -4,15 +4,14 @@ #include #include "Common/Log.h" -#include "base/logging.h" +#include "Common/StringUtils.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Core/Config.h" -#include "thin3d/VulkanRenderManager.h" -#include "thread/threadutil.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/Thread/ThreadUtil.h" #if 0 // def _DEBUG -#define VLOG ILOG +#define VLOG(...) INFO_LOG(G3D, __VA_ARGS__) #else #define VLOG(...) #endif @@ -21,8 +20,56 @@ #define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL #endif +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag) : vulkan_(vk) { + width = _width; + height = _height; -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color) { + CreateImage(vulkan_, initCmd, color, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + CreateImage(vulkan_, initCmd, depth, width, height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + + VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + VkImageView views[2]{}; + + fbci.renderPass = renderPass; + fbci.attachmentCount = 2; + fbci.pAttachments = views; + views[0] = color.imageView; + views[1] = depth.imageView; + fbci.width = width; + fbci.height = height; + fbci.layers = 1; + + VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf); + _assert_(res == VK_SUCCESS); + + if (tag && vk->Extensions().EXT_debug_utils) { + vk->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_color_%s", tag).c_str()); + vk->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_depth_%s", tag).c_str()); + vk->SetDebugName(framebuf, VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag).c_str()); + this->tag = tag; + } +} + +VKRFramebuffer::~VKRFramebuffer() { + if (color.image) + vulkan_->Delete().QueueDeleteImage(color.image); + if (depth.image) + vulkan_->Delete().QueueDeleteImage(depth.image); + if (color.imageView) + vulkan_->Delete().QueueDeleteImageView(color.imageView); + if (depth.imageView) + vulkan_->Delete().QueueDeleteImageView(depth.imageView); + if (depth.depthSampleView) + vulkan_->Delete().QueueDeleteImageView(depth.depthSampleView); + if (color.memory) + vulkan_->Delete().QueueDeleteDeviceMemory(color.memory); + if (depth.memory) + vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory); + if (framebuf) + vulkan_->Delete().QueueDeleteFramebuffer(framebuf); +} + +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; ici.arrayLayers = 1; ici.mipLevels = 1; @@ -42,7 +89,8 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } - vkCreateImage(vulkan->GetDevice(), &ici, nullptr, &img.image); + VkResult res = vkCreateImage(vulkan->GetDevice(), &ici, nullptr, &img.image); + _dbg_assert_(res == VK_SUCCESS); VkMemoryRequirements memreq; bool dedicatedAllocation = false; @@ -58,11 +106,11 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int vulkan->MemoryTypeFromProperties(memreq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc.memoryTypeIndex); - VkResult res = vkAllocateMemory(vulkan->GetDevice(), &alloc, nullptr, &img.memory); - assert(res == VK_SUCCESS); + res = vkAllocateMemory(vulkan->GetDevice(), &alloc, nullptr, &img.memory); + _dbg_assert_(res == VK_SUCCESS); res = vkBindImageMemory(vulkan->GetDevice(), img.image, img.memory, 0); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); VkImageAspectFlags aspects = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); @@ -75,7 +123,16 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ivci.subresourceRange.layerCount = 1; ivci.subresourceRange.levelCount = 1; res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.imageView); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); + + // Separate view for texture sampling that only exposes depth. + if (!color) { + ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.depthSampleView); + _dbg_assert_(res == VK_SUCCESS); + } else { + img.depthSampleView = VK_NULL_HANDLE; + } VkPipelineStageFlags dstStage; VkAccessFlagBits dstAccessMask; @@ -104,15 +161,16 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int img.layout = initialLayout; img.format = format; + img.tag = tag ? tag : "N/A"; } VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan), queueRunner_(vulkan) { VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; semaphoreCreateInfo.flags = 0; VkResult res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, nullptr, &acquireSemaphore_); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, nullptr, &renderingCompleteSemaphore_); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); inflightFramesAtStart_ = vulkan_->GetInflightFrames(); for (int i = 0; i < inflightFramesAtStart_; i++) { @@ -120,9 +178,9 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan cmd_pool_info.queueFamilyIndex = vulkan_->GetGraphicsQueueFamilyIndex(); cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VkResult res = vkCreateCommandPool(vulkan_->GetDevice(), &cmd_pool_info, nullptr, &frameData_[i].cmdPoolInit); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); res = vkCreateCommandPool(vulkan_->GetDevice(), &cmd_pool_info, nullptr, &frameData_[i].cmdPoolMain); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); VkCommandBufferAllocateInfo cmd_alloc = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; cmd_alloc.commandPool = frameData_[i].cmdPoolInit; @@ -130,11 +188,16 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan cmd_alloc.commandBufferCount = 1; res = vkAllocateCommandBuffers(vulkan_->GetDevice(), &cmd_alloc, &frameData_[i].initCmd); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); cmd_alloc.commandPool = frameData_[i].cmdPoolMain; res = vkAllocateCommandBuffers(vulkan_->GetDevice(), &cmd_alloc, &frameData_[i].mainCmd); - assert(res == VK_SUCCESS); - frameData_[i].fence = vulkan_->CreateFence(true); // So it can be instantly waited on + _dbg_assert_(res == VK_SUCCESS); + + // Creating the frame fence with true so they can be instantly waited on the first frame + frameData_[i].fence = vulkan_->CreateFence(true); + + // This fence one is used for synchronizing readbacks. Does not need preinitialization. + frameData_[i].readbackFence = vulkan_->CreateFence(false); VkQueryPoolCreateInfo query_ci{ VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO }; query_ci.queryCount = MAX_TIMESTAMP_QUERIES; @@ -146,20 +209,18 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan // Temporary AMD hack for issue #10097 if (vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_AMD) { - if (!g_Config.bVulkanMultithreading) { useThread_ = false; - } } } void VulkanRenderManager::CreateBackbuffers() { VkResult res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, nullptr); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); VkImage *swapchainImages = new VkImage[swapchainImageCount_]; res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, swapchainImages); if (res != VK_SUCCESS) { - ELOG("vkGetSwapchainImagesKHR failed"); + ERROR_LOG(G3D, "vkGetSwapchainImagesKHR failed"); delete[] swapchainImages; return; } @@ -191,7 +252,7 @@ void VulkanRenderManager::CreateBackbuffers() { res = vkCreateImageView(vulkan_->GetDevice(), &color_image_view, nullptr, &sc_buffer.view); swapchainImages_.push_back(sc_buffer); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); } delete[] swapchainImages; @@ -207,17 +268,19 @@ void VulkanRenderManager::CreateBackbuffers() { } if (newInflightFrames_ != -1) { - ILOG("Updating inflight frames to %d", newInflightFrames_); + INFO_LOG(G3D, "Updating inflight frames to %d", newInflightFrames_); vulkan_->UpdateInflightFrames(newInflightFrames_); newInflightFrames_ = -1; } + outOfDateFrames_ = 0; + // Start the thread. if (useThread_ && HasBackbuffers()) { run_ = true; // Won't necessarily be 0. threadInitFrame_ = vulkan_->GetCurFrame(); - ILOG("Starting Vulkan submission thread (threadInitFrame_ = %d)", vulkan_->GetCurFrame()); + INFO_LOG(G3D, "Starting Vulkan submission thread (threadInitFrame_ = %d)", vulkan_->GetCurFrame()); thread_ = std::thread(&VulkanRenderManager::ThreadFunc, this); } } @@ -240,7 +303,7 @@ void VulkanRenderManager::StopThread() { frameData.profile.timestampDescriptions.clear(); } thread_.join(); - ILOG("Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame()); + INFO_LOG(G3D, "Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame()); // Eat whatever has been queued up for this frame if anything. Wipe(); @@ -270,7 +333,7 @@ void VulkanRenderManager::StopThread() { } } } else { - ILOG("Vulkan submission thread was already stopped."); + INFO_LOG(G3D, "Vulkan submission thread was already stopped."); } } @@ -285,7 +348,7 @@ void VulkanRenderManager::DestroyBackbuffers() { vulkan_->Delete().QueueDeleteImage(depth_.image); vulkan_->Delete().QueueDeleteDeviceMemory(depth_.mem); for (uint32_t i = 0; i < framebuffers_.size(); i++) { - assert(framebuffers_[i] != VK_NULL_HANDLE); + _dbg_assert_(framebuffers_[i] != VK_NULL_HANDLE); vulkan_->Delete().QueueDeleteFramebuffer(framebuffers_[i]); } framebuffers_.clear(); @@ -295,7 +358,7 @@ void VulkanRenderManager::DestroyBackbuffers() { } VulkanRenderManager::~VulkanRenderManager() { - ILOG("VulkanRenderManager destructor"); + INFO_LOG(G3D, "VulkanRenderManager destructor"); StopThread(); vulkan_->WaitUntilQueueIdle(); @@ -308,6 +371,7 @@ VulkanRenderManager::~VulkanRenderManager() { vkDestroyCommandPool(device, frameData_[i].cmdPoolInit, nullptr); vkDestroyCommandPool(device, frameData_[i].cmdPoolMain, nullptr); vkDestroyFence(device, frameData_[i].fence, nullptr); + vkDestroyFence(device, frameData_[i].readbackFence, nullptr); vkDestroyQueryPool(device, frameData_[i].profile.queryPool, nullptr); } queueRunner_.DestroyDeviceObjects(); @@ -342,11 +406,11 @@ void VulkanRenderManager::ThreadFunc() { // Only increment next time if we're done. nextFrame = frameData.type == VKRRunType::END; - assert(frameData.type == VKRRunType::END || frameData.type == VKRRunType::SYNC); + _dbg_assert_(frameData.type == VKRRunType::END || frameData.type == VKRRunType::SYNC); } VLOG("PULL: Running frame %d", threadFrame); if (firstFrame) { - ILOG("Running first frame (%d)", threadFrame); + INFO_LOG(G3D, "Running first frame (%d)", threadFrame); firstFrame = false; } Run(threadFrame); @@ -381,6 +445,8 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling) { vkWaitForFences(device, 1, &frameData.fence, true, UINT64_MAX); vkResetFences(device, 1, &frameData.fence); + frameData.readbackFenceUsed = false; + uint64_t queryResults[MAX_TIMESTAMP_QUERIES]; if (frameData.profilingEnabled_) { @@ -420,14 +486,15 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling) { // Must be after the fence - this performs deletes. VLOG("PUSH: BeginFrame %d", curFrame); if (!run_) { - WLOG("BeginFrame while !run_!"); + WARN_LOG(G3D, "BeginFrame while !run_!"); } vulkan_->BeginFrame(); insideFrame_ = true; + renderStepOffset_ = 0; frameData.profile.timestampDescriptions.clear(); - if (frameData_->profilingEnabled_) { + if (frameData.profilingEnabled_) { // For various reasons, we need to always use an init cmd buffer in this case to perform the vkCmdResetQueryPool, // unless we want to limit ourselves to only measure the main cmd buffer. // Reserve the first two queries for initCmd. @@ -457,21 +524,53 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { return frameData_[curFrame].initCmd; } -void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, VKRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil) { - assert(insideFrame_); - // Eliminate dupes. - if (steps_.size() && steps_.back()->render.framebuffer == fb && steps_.back()->stepType == VKRStepType::RENDER) { - if (color != VKRRenderPassAction::CLEAR && depth != VKRRenderPassAction::CLEAR && stencil != VKRRenderPassAction::CLEAR) { - // We don't move to a new step, this bind was unnecessary and we can safely skip it. - // Not sure how much this is still happening but probably worth checking for nevertheless. +void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, VKRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) { + _dbg_assert_(insideFrame_); + // Eliminate dupes, instantly convert to a clear if possible. + if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) { + u32 clearMask = 0; + if (color == VKRRenderPassAction::CLEAR) { + clearMask |= VK_IMAGE_ASPECT_COLOR_BIT; + } + if (depth == VKRRenderPassAction::CLEAR) { + clearMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + if (stencil == VKRRenderPassAction::CLEAR) { + clearMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + + // If we need a clear and the previous step has commands already, it's best to just add a clear and keep going. + // If there's no clear needed, let's also do that. + // + // However, if we do need a clear and there are no commands in the previous pass, + // we want the queuerunner to have the opportunity to merge, so we'll go ahead and make a new renderpass. + if (clearMask == 0 || !steps_.back()->commands.empty()) { + curRenderStep_ = steps_.back(); + curStepHasViewport_ = false; + curStepHasScissor_ = false; + for (const auto &c : steps_.back()->commands) { + if (c.cmd == VKRRenderCommand::VIEWPORT) { + curStepHasViewport_ = true; + } else if (c.cmd == VKRRenderCommand::SCISSOR) { + curStepHasScissor_ = true; + } + } + if (clearMask != 0) { + VkRenderData data{ VKRRenderCommand::CLEAR }; + data.clear.clearColor = clearColor; + data.clear.clearZ = clearDepth; + data.clear.clearStencil = clearStencil; + data.clear.clearMask = clearMask; + curRenderStep_->commands.push_back(data); + } return; } } // More redundant bind elimination. - if (curRenderStep_ && curRenderStep_->commands.size() == 0 && curRenderStep_->render.color == VKRRenderPassAction::KEEP && curRenderStep_->render.depth == VKRRenderPassAction::KEEP && curRenderStep_->render.stencil == VKRRenderPassAction::KEEP) { + if (curRenderStep_ && curRenderStep_->commands.size() == 0 && curRenderStep_->render.color != VKRRenderPassAction::CLEAR && curRenderStep_->render.depth != VKRRenderPassAction::CLEAR && curRenderStep_->render.stencil != VKRRenderPassAction::CLEAR) { // Can trivially kill the last empty render step. - assert(steps_.back() == curRenderStep_); + _dbg_assert_(steps_.back() == curRenderStep_); delete steps_.back(); steps_.pop_back(); curRenderStep_ = nullptr; @@ -480,6 +579,23 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR VLOG("Empty render step. Usually happens after uploading pixels.."); } + // Older Mali drivers have issues with depth and stencil don't match load/clear/etc. + // TODO: Determine which versions and do this only where necessary. + u32 lateClearMask = 0; + if (depth != stencil && vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_ARM) { + if (stencil == VKRRenderPassAction::DONT_CARE) { + stencil = depth; + } else if (depth == VKRRenderPassAction::DONT_CARE) { + depth = stencil; + } else if (stencil == VKRRenderPassAction::CLEAR) { + depth = stencil; + lateClearMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } else if (depth == VKRRenderPassAction::CLEAR) { + stencil = depth; + lateClearMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + } + VKRStep *step = new VKRStep{ VKRStepType::RENDER }; step->render.framebuffer = fb; step->render.color = color; @@ -491,6 +607,8 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR step->render.numDraws = 0; step->render.numReads = 0; step->render.finalColorLayout = !fb ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; + step->render.finalDepthStencilLayout = !fb ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; + step->tag = tag; steps_.push_back(step); if (fb) { @@ -501,6 +619,8 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR } curRenderStep_ = step; + curStepHasViewport_ = false; + curStepHasScissor_ = false; if (fb) { curWidth_ = fb->width; curHeight_ = fb->height; @@ -508,9 +628,20 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR curWidth_ = vulkan_->GetBackbufferWidth(); curHeight_ = vulkan_->GetBackbufferHeight(); } + + // See above - we add a clear afterward if only one side for depth/stencil CLEAR/KEEP. + if (lateClearMask != 0) { + VkRenderData data{ VKRRenderCommand::CLEAR }; + data.clear.clearColor = clearColor; + data.clear.clearZ = clearDepth; + data.clear.clearStencil = clearStencil; + data.clear.clearMask = lateClearMask; + curRenderStep_->commands.push_back(data); + } } -bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) { +bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { + _dbg_assert_(insideFrame_); for (int i = (int)steps_.size() - 1; i >= 0; i--) { if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == src) { steps_[i]->render.numReads++; @@ -524,6 +655,7 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int a step->readback.srcRect.offset = { x, y }; step->readback.srcRect.extent = { (uint32_t)w, (uint32_t)h }; step->dependencies.insert(src); + step->tag = tag; steps_.push_back(step); curRenderStep_ = nullptr; @@ -540,7 +672,7 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int a } else { // Backbuffer. if (!(vulkan_->GetSurfaceCapabilities().supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) { - ELOG("Copying from backbuffer not supported, can't take screenshots"); + ERROR_LOG(G3D, "Copying from backbuffer not supported, can't take screenshots"); return false; } switch (vulkan_->GetSwapchainFormat()) { @@ -548,7 +680,7 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int a case VK_FORMAT_R8G8B8A8_UNORM: srcFormat = Draw::DataFormat::R8G8B8A8_UNORM; break; // NOTE: If you add supported formats here, make sure to also support them in VulkanQueueRunner::CopyReadbackBuffer. default: - ELOG("Unsupported backbuffer format for screenshots"); + ERROR_LOG(G3D, "Unsupported backbuffer format for screenshots"); return false; } } @@ -570,12 +702,14 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int a return true; } -void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) { +void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { + _dbg_assert_(insideFrame_); VKRStep *step = new VKRStep{ VKRStepType::READBACK_IMAGE }; step->readback_image.image = image; step->readback_image.srcRect.offset = { x, y }; step->readback_image.srcRect.extent = { (uint32_t)w, (uint32_t)h }; step->readback_image.mipLevel = mipLevel; + step->tag = tag; steps_.push_back(step); curRenderStep_ = nullptr; @@ -605,7 +739,7 @@ bool VulkanRenderManager::InitBackbufferFramebuffers(int width, int height) { for (uint32_t i = 0; i < swapchainImageCount_; i++) { attachments[0] = swapchainImages_[i].view; res = vkCreateFramebuffer(vulkan_->GetDevice(), &fb_info, nullptr, &framebuffers_[i]); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) { framebuffers_.clear(); return false; @@ -640,10 +774,12 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { VkDevice device = vulkan_->GetDevice(); res = vkCreateImage(device, &image_info, nullptr, &depth_.image); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) return false; + vulkan_->SetDebugName(depth_.image, VK_OBJECT_TYPE_IMAGE, "BackbufferDepth"); + bool dedicatedAllocation = false; VkMemoryRequirements mem_reqs; vulkan_->GetImageMemoryRequirements(depth_.image, &mem_reqs, &dedicatedAllocation); @@ -662,17 +798,17 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, 0, /* No requirements */ &mem_alloc.memoryTypeIndex); - assert(pass); + _dbg_assert_(pass); if (!pass) return false; res = vkAllocateMemory(device, &mem_alloc, NULL, &depth_.mem); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) return false; res = vkBindImageMemory(device, depth_.image, depth_.mem, 0); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) return false; @@ -698,7 +834,7 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { depth_view_info.flags = 0; res = vkCreateImageView(device, &depth_view_info, NULL, &depth_.view); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) return false; @@ -767,7 +903,7 @@ static void CleanupRenderCommands(std::vector *cmds) { } void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); if (!clearMask) return; // If this is the first drawing command or clears everything, merge it into the pass. @@ -793,24 +929,31 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten } } -void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask) { - _dbg_assert_msg_(G3D, srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); - _dbg_assert_msg_(G3D, srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); - _dbg_assert_msg_(G3D, srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); - _dbg_assert_msg_(G3D, srcRect.offset.y + srcRect.extent.height <= (uint32_t)src->height, "srcrect offset y (%d) + extent (%d) > height (%d)", srcRect.offset.y, srcRect.extent.height, (uint32_t)src->height); +void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag) { + _dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); + _dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); + _dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); + _dbg_assert_msg_(srcRect.offset.y + srcRect.extent.height <= (uint32_t)src->height, "srcrect offset y (%d) + extent (%d) > height (%d)", srcRect.offset.y, srcRect.extent.height, (uint32_t)src->height); - _dbg_assert_msg_(G3D, srcRect.extent.width > 0, "copy srcwidth == 0"); - _dbg_assert_msg_(G3D, srcRect.extent.height > 0, "copy srcheight == 0"); + _dbg_assert_msg_(srcRect.extent.width > 0, "copy srcwidth == 0"); + _dbg_assert_msg_(srcRect.extent.height > 0, "copy srcheight == 0"); - _dbg_assert_msg_(G3D, dstPos.x >= 0, "dstPos offset x (%d) < 0", dstPos.x); - _dbg_assert_msg_(G3D, dstPos.y >= 0, "dstPos offset y (%d) < 0", dstPos.y); - _dbg_assert_msg_(G3D, dstPos.x + srcRect.extent.width <= (uint32_t)dst->width, "dstPos + extent x > width"); - _dbg_assert_msg_(G3D, dstPos.y + srcRect.extent.height <= (uint32_t)dst->height, "dstPos + extent y > height"); + _dbg_assert_msg_(dstPos.x >= 0, "dstPos offset x (%d) < 0", dstPos.x); + _dbg_assert_msg_(dstPos.y >= 0, "dstPos offset y (%d) < 0", dstPos.y); + _dbg_assert_msg_(dstPos.x + srcRect.extent.width <= (uint32_t)dst->width, "dstPos + extent x > width"); + _dbg_assert_msg_(dstPos.y + srcRect.extent.height <= (uint32_t)dst->height, "dstPos + extent y > height"); for (int i = (int)steps_.size() - 1; i >= 0; i--) { if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == src) { - if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + if (aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + } + } + if (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + if (steps_[i]->render.finalDepthStencilLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps_[i]->render.finalDepthStencilLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + } } steps_[i]->render.numReads++; break; @@ -818,8 +961,15 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, } for (int i = (int)steps_.size() - 1; i >= 0; i--) { if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == dst) { - if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + if (aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + } + } + if (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + if (steps_[i]->render.finalDepthStencilLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps_[i]->render.finalDepthStencilLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + } } break; } @@ -833,6 +983,7 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, step->copy.dst = dst; step->copy.dstPos = dstPos; step->dependencies.insert(src); + step->tag = tag; bool fillsDst = dst && srcRect.offset.x == 0 && srcRect.offset.y == 0 && srcRect.extent.width == dst->width && srcRect.extent.height == dst->height; if (dstPos.x != 0 || dstPos.y != 0 || !fillsDst) step->dependencies.insert(dst); @@ -842,22 +993,24 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, curRenderStep_ = nullptr; } -void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, int aspectMask, VkFilter filter) { - _dbg_assert_msg_(G3D, srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); - _dbg_assert_msg_(G3D, srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); - _dbg_assert_msg_(G3D, srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); - _dbg_assert_msg_(G3D, srcRect.offset.y + srcRect.extent.height <= (uint32_t)src->height, "srcrect offset y (%d) + extent (%d) > height (%d)", srcRect.offset.y, srcRect.extent.height, (uint32_t)src->height); +void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag) { + _dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); + _dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); + _dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); + _dbg_assert_msg_(srcRect.offset.y + srcRect.extent.height <= (uint32_t)src->height, "srcrect offset y (%d) + extent (%d) > height (%d)", srcRect.offset.y, srcRect.extent.height, (uint32_t)src->height); - _dbg_assert_msg_(G3D, srcRect.extent.width > 0, "blit srcwidth == 0"); - _dbg_assert_msg_(G3D, srcRect.extent.height > 0, "blit srcheight == 0"); + _dbg_assert_msg_(srcRect.extent.width > 0, "blit srcwidth == 0"); + _dbg_assert_msg_(srcRect.extent.height > 0, "blit srcheight == 0"); - _dbg_assert_msg_(G3D, dstRect.offset.x >= 0, "dstrect offset x < 0"); - _dbg_assert_msg_(G3D, dstRect.offset.y >= 0, "dstrect offset y < 0"); - _dbg_assert_msg_(G3D, dstRect.offset.x + dstRect.extent.width <= (uint32_t)dst->width, "dstrect offset x + extent > width"); - _dbg_assert_msg_(G3D, dstRect.offset.y + dstRect.extent.height <= (uint32_t)dst->height, "dstrect offset y + extent > height"); + _dbg_assert_msg_(dstRect.offset.x >= 0, "dstrect offset x < 0"); + _dbg_assert_msg_(dstRect.offset.y >= 0, "dstrect offset y < 0"); + _dbg_assert_msg_(dstRect.offset.x + dstRect.extent.width <= (uint32_t)dst->width, "dstrect offset x + extent > width"); + _dbg_assert_msg_(dstRect.offset.y + dstRect.extent.height <= (uint32_t)dst->height, "dstrect offset y + extent > height"); - _dbg_assert_msg_(G3D, dstRect.extent.width > 0, "blit dstwidth == 0"); - _dbg_assert_msg_(G3D, dstRect.extent.height > 0, "blit dstheight == 0"); + _dbg_assert_msg_(dstRect.extent.width > 0, "blit dstwidth == 0"); + _dbg_assert_msg_(dstRect.extent.height > 0, "blit dstheight == 0"); + + // TODO: Seem to be missing final layouts here like in Copy... for (int i = (int)steps_.size() - 1; i >= 0; i--) { if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == src) { @@ -875,6 +1028,7 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, step->blit.dstRect = dstRect; step->blit.filter = filter; step->dependencies.insert(src); + step->tag = tag; bool fillsDst = dst && dstRect.offset.x == 0 && dstRect.offset.y == 0 && dstRect.extent.width == dst->width && dstRect.extent.height == dst->height; if (!fillsDst) step->dependencies.insert(dst); @@ -884,16 +1038,26 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, curRenderStep_ = nullptr; } -VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment) { - _dbg_assert_(G3D, curRenderStep_ != nullptr); +VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit, int attachment) { + _dbg_assert_(curRenderStep_ != nullptr); // Mark the dependency, check for required transitions, and return the image. + // Optimization: If possible, use final*Layout to put the texture into the correct layout "early". for (int i = (int)steps_.size() - 1; i >= 0; i--) { if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == fb) { - // If this framebuffer was rendered to earlier in this frame, make sure to pre-transition it to the correct layout. - if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } + if (aspectBit == VK_IMAGE_ASPECT_COLOR_BIT) { + // If this framebuffer was rendered to earlier in this frame, make sure to pre-transition it to the correct layout. + if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + // If we find some other layout, a copy after this is likely involved. It's fine though, + // we'll just transition it right as we need it and lose a tiny optimization. + } else if (aspectBit == VK_IMAGE_ASPECT_DEPTH_BIT) { + // If this framebuffer was rendered to earlier in this frame, make sure to pre-transition it to the correct layout. + if (steps_[i]->render.finalDepthStencilLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + steps_[i]->render.finalDepthStencilLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + } // We don't (yet?) support texturing from stencil images. steps_[i]->render.numReads++; break; } @@ -903,13 +1067,13 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in curRenderStep_->dependencies.insert(fb); if (!curRenderStep_->preTransitions.empty() && - curRenderStep_->preTransitions.back().fb == fb && - curRenderStep_->preTransitions.back().targetLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + curRenderStep_->preTransitions.back().fb == fb && + curRenderStep_->preTransitions.back().targetLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { // We're done. - return fb->color.imageView; + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; } else { - curRenderStep_->preTransitions.push_back({ fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }); - return fb->color.imageView; + curRenderStep_->preTransitions.push_back({ aspectBit, fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }); + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; } } @@ -962,19 +1126,19 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) { VkResult res = vkAcquireNextImageKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, &frameData.curSwapchainImage); if (res == VK_SUBOPTIMAL_KHR) { // Hopefully the resize will happen shortly. Ignore - one frame might look bad or something. - WLOG("VK_SUBOPTIMAL_KHR returned - ignoring"); + WARN_LOG(G3D, "VK_SUBOPTIMAL_KHR returned - ignoring"); } else if (res == VK_ERROR_OUT_OF_DATE_KHR) { - WLOG("VK_ERROR_OUT_OF_DATE_KHR returned - not presenting"); + WARN_LOG(G3D, "VK_ERROR_OUT_OF_DATE_KHR returned - processing the frame, but not presenting"); frameData.skipSwap = true; } else { - _assert_msg_(G3D, res == VK_SUCCESS, "vkAcquireNextImageKHR failed! result=%s", VulkanResultToString(res)); + _assert_msg_(res == VK_SUCCESS, "vkAcquireNextImageKHR failed! result=%s", VulkanResultToString(res)); } VkCommandBufferBeginInfo begin{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; res = vkBeginCommandBuffer(frameData.mainCmd, &begin); - _assert_msg_(G3D, res == VK_SUCCESS, "vkBeginCommandBuffer failed! result=%s", VulkanResultToString(res)); + _assert_msg_(res == VK_SUCCESS, "vkBeginCommandBuffer failed! result=%s", VulkanResultToString(res)); queueRunner_.SetBackbuffer(framebuffers_[frameData.curSwapchainImage], swapchainImages_[frameData.curSwapchainImage].image); @@ -982,25 +1146,24 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) { } } -void VulkanRenderManager::Submit(int frame, bool triggerFence) { +void VulkanRenderManager::Submit(int frame, bool triggerFrameFence) { FrameData &frameData = frameData_[frame]; if (frameData.hasInitCommands) { - if (frameData.profilingEnabled_ && triggerFence) { + if (frameData.profilingEnabled_ && triggerFrameFence) { // Pre-allocated query ID 1. vkCmdWriteTimestamp(frameData.initCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frameData.profile.queryPool, 1); } VkResult res = vkEndCommandBuffer(frameData.initCmd); - _assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (init)! result=%s", VulkanResultToString(res)); + _assert_msg_(res == VK_SUCCESS, "vkEndCommandBuffer failed (init)! result=%s", VulkanResultToString(res)); } VkResult res = vkEndCommandBuffer(frameData.mainCmd); - _assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (main)! result=%s", VulkanResultToString(res)); + _assert_msg_(res == VK_SUCCESS, "vkEndCommandBuffer failed (main)! result=%s", VulkanResultToString(res)); VkCommandBuffer cmdBufs[2]; int numCmdBufs = 0; if (frameData.hasInitCommands) { cmdBufs[numCmdBufs++] = frameData.initCmd; - frameData.hasInitCommands = false; if (splitSubmit_) { // Send the init commands off separately. Used this once to confirm that the cause of a device loss was in the init cmdbuf. VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; @@ -1008,13 +1171,9 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { submit_info.pCommandBuffers = cmdBufs; res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE); if (res == VK_ERROR_DEVICE_LOST) { -#ifdef _WIN32 - _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to Direct3D11"); -#else - _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to OpenGL"); -#endif + _assert_msg_(false, "Lost the Vulkan device in split submit! If this happens again, switch Graphics Backend away from Vulkan"); } else { - _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (init)! result=%s", VulkanResultToString(res)); + _assert_msg_(res == VK_SUCCESS, "vkQueueSubmit failed (init)! result=%s", VulkanResultToString(res)); } numCmdBufs = 0; } @@ -1023,35 +1182,33 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkPipelineStageFlags waitStage[1]{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; - if (triggerFence && !frameData.skipSwap) { + if (triggerFrameFence && !frameData.skipSwap) { submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &acquireSemaphore_; submit_info.pWaitDstStageMask = waitStage; } submit_info.commandBufferCount = (uint32_t)numCmdBufs; submit_info.pCommandBuffers = cmdBufs; - if (triggerFence && !frameData.skipSwap) { + if (triggerFrameFence && !frameData.skipSwap) { submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &renderingCompleteSemaphore_; } - res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, triggerFence ? frameData.fence : VK_NULL_HANDLE); + res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, triggerFrameFence ? frameData.fence : frameData.readbackFence); if (res == VK_ERROR_DEVICE_LOST) { -#ifdef _WIN32 - _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to Direct3D11"); -#else - _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to OpenGL"); -#endif + _assert_msg_(false, "Lost the Vulkan device in vkQueueSubmit! If this happens again, switch Graphics Backend away from Vulkan"); } else { - _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (main, split=%d)! result=%s", (int)splitSubmit_, VulkanResultToString(res)); + _assert_msg_(res == VK_SUCCESS, "vkQueueSubmit failed (main, split=%d)! result=%s", (int)splitSubmit_, VulkanResultToString(res)); } // When !triggerFence, we notify after syncing with Vulkan. - if (useThread_ && triggerFence) { + if (useThread_ && triggerFrameFence) { VLOG("PULL: Frame %d.readyForFence = true", frame); std::unique_lock lock(frameData.push_mutex); frameData.readyForFence = true; frameData.push_condVar.notify_all(); } + + frameData.hasInitCommands = false; } void VulkanRenderManager::EndSubmitFrame(int frame) { @@ -1070,13 +1227,21 @@ void VulkanRenderManager::EndSubmitFrame(int frame) { present.waitSemaphoreCount = 1; VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present); - // TODO: Deal with VK_SUBOPTIMAL_KHR ? - if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) { - // ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain. + if (res == VK_ERROR_OUT_OF_DATE_KHR) { + // We clearly didn't get this in vkAcquireNextImageKHR because of the skipSwap check above. + // Do the increment. + outOfDateFrames_++; + } else if (res == VK_SUBOPTIMAL_KHR) { + outOfDateFrames_++; + } else if (res != VK_SUCCESS) { + _assert_msg_(false, "vkQueuePresentKHR failed! result=%s", VulkanResultToString(res)); } else { - _assert_msg_(G3D, res == VK_SUCCESS, "vkQueuePresentKHR failed! result=%s", VulkanResultToString(res)); + // Success + outOfDateFrames_ = 0; } } else { + // We only get here if vkAcquireNextImage returned VK_ERROR_OUT_OF_DATE. + outOfDateFrames_++; frameData.skipSwap = false; } } @@ -1087,7 +1252,8 @@ void VulkanRenderManager::Run(int frame) { FrameData &frameData = frameData_[frame]; auto &stepsOnThread = frameData_[frame].steps; VkCommandBuffer cmd = frameData.mainCmd; - // queueRunner_.LogSteps(stepsOnThread); + queueRunner_.PreprocessSteps(stepsOnThread); + //queueRunner_.LogSteps(stepsOnThread, false); queueRunner_.RunSteps(cmd, stepsOnThread, frameData.profilingEnabled_ ? &frameData.profile : nullptr); stepsOnThread.clear(); @@ -1101,7 +1267,7 @@ void VulkanRenderManager::Run(int frame) { break; default: - assert(false); + _dbg_assert_(false); } VLOG("PULL: Finished running frame %d", frame); @@ -1109,11 +1275,15 @@ void VulkanRenderManager::Run(int frame) { void VulkanRenderManager::EndSyncFrame(int frame) { FrameData &frameData = frameData_[frame]; + + frameData.readbackFenceUsed = true; + + // The submit will trigger the readbackFence. Submit(frame, false); - // This is brutal! Should probably wait for a fence instead, not that it'll matter much since we'll - // still stall everything. - vkDeviceWaitIdle(vulkan_->GetDevice()); + // Hard stall of the GPU, not ideal, but necessary so the CPU has the contents of the readback. + vkWaitForFences(vulkan_->GetDevice(), 1, &frameData.readbackFence, true, UINT64_MAX); + vkResetFences(vulkan_->GetDevice(), 1, &frameData.readbackFence); // At this point we can resume filling the command buffers for the current frame since // we know the device is idle - and thus all previously enqueued command buffers have been processed. @@ -1134,7 +1304,8 @@ void VulkanRenderManager::EndSyncFrame(int frame) { } void VulkanRenderManager::FlushSync() { - // TODO: Reset curRenderStep_? + renderStepOffset_ += (int)steps_.size(); + int curFrame = vulkan_->GetCurFrame(); FrameData &frameData = frameData_[curFrame]; if (!useThread_) { @@ -1148,7 +1319,7 @@ void VulkanRenderManager::FlushSync() { frameData.steps = std::move(steps_); steps_.clear(); frameData.readyForRun = true; - assert(frameData.readyForFence == false); + _dbg_assert_(!frameData.readyForFence); frameData.type = VKRRunType::SYNC; frameData.pull_condVar.notify_all(); } diff --git a/ext/native/thin3d/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h similarity index 69% rename from ext/native/thin3d/VulkanRenderManager.h rename to Common/GPU/Vulkan/VulkanRenderManager.h index 530912d857..d1a781c7b3 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -10,64 +10,35 @@ #include #include -#include "base/display.h" -#include "Common/Vulkan/VulkanContext.h" -#include "math/dataconv.h" -#include "math/math_util.h" -#include "thin3d/DataFormat.h" -#include "thin3d/VulkanQueueRunner.h" +#include "Common/System/Display.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Math/math_util.h" +#include "Common/GPU/DataFormat.h" +#include "Common/GPU/Vulkan/VulkanQueueRunner.h" // Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine // to let them have individual non-pooled allocations. Until it's not fine. We'll see. struct VKRImage { + // These four are "immutable". VkImage image; VkImageView imageView; + VkImageView depthSampleView; VkDeviceMemory memory; - VkImageLayout layout; VkFormat format; + + // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. + VkImageLayout layout; + + // For debugging. + std::string tag; }; -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color); +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); class VKRFramebuffer { public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height) : vulkan_(vk) { - width = _width; - height = _height; - - CreateImage(vulkan_, initCmd, color, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - CreateImage(vulkan_, initCmd, depth, width, height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false); - - VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - VkImageView views[2]{}; - - fbci.renderPass = renderPass; - fbci.attachmentCount = 2; - fbci.pAttachments = views; - views[0] = color.imageView; - views[1] = depth.imageView; - fbci.width = width; - fbci.height = height; - fbci.layers = 1; - - vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf); - } - - ~VKRFramebuffer() { - if (color.image) - vulkan_->Delete().QueueDeleteImage(color.image); - if (depth.image) - vulkan_->Delete().QueueDeleteImage(depth.image); - if (color.imageView) - vulkan_->Delete().QueueDeleteImageView(color.imageView); - if (depth.imageView) - vulkan_->Delete().QueueDeleteImageView(depth.imageView); - if (color.memory) - vulkan_->Delete().QueueDeleteDeviceMemory(color.memory); - if (depth.memory) - vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory); - if (framebuf) - vulkan_->Delete().QueueDeleteFramebuffer(framebuf); - } + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag); + ~VKRFramebuffer(); int numShadows = 1; // TODO: Support this. @@ -78,6 +49,7 @@ public: int height = 0; VulkanContext *vulkan_; + std::string tag; }; enum class VKRRunType { @@ -105,26 +77,45 @@ public: // Zaps queued up commands. Use if you know there's a risk you've queued up stuff that has already been deleted. Can happen during in-game shutdown. void Wipe(); - void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, VKRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil); - VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment); - bool CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride); - void CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride); + // This starts a new step containing a render pass. + // + // After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce + // making any new render state changes or draw calls. + // + // The following dynamic state needs to be reset by the caller after calling this (and will thus not safely carry over from + // the previous one): + // * Viewport/Scissor + // * Stencil parameters + // * Blend color + // + // (Most other state is directly decided by your choice of pipeline and descriptor set, so not handled here). + // + // It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're + // not keeping track of your calls to this function on your own. + void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, VKRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag); - void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask); - void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, int aspectMask, VkFilter filter); + // Returns an ImageView corresponding to a framebuffer. Is called BindFramebufferAsTexture to maintain a similar interface + // as the other backends, even though there's no actual binding happening here. + VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits, int attachment); + + bool CopyFramebufferToMemorySync(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); + void CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); + + void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag); + void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag); void BindPipeline(VkPipeline pipeline) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); - _dbg_assert_(G3D, pipeline != VK_NULL_HANDLE); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(pipeline != VK_NULL_HANDLE); VkRenderData data{ VKRRenderCommand::BIND_PIPELINE }; data.pipeline.pipeline = pipeline; curRenderStep_->commands.push_back(data); } void SetViewport(const VkViewport &vp) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); - _dbg_assert_(G3D, (int)vp.width >= 0); - _dbg_assert_(G3D, (int)vp.height >= 0); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_((int)vp.width >= 0); + _dbg_assert_((int)vp.height >= 0); VkRenderData data{ VKRRenderCommand::VIEWPORT }; data.viewport.vp.x = vp.x; data.viewport.vp.y = vp.y; @@ -136,19 +127,21 @@ public: data.viewport.vp.minDepth = clamp_value(vp.minDepth, 0.0f, 1.0f); data.viewport.vp.maxDepth = clamp_value(vp.maxDepth, 0.0f, 1.0f); curRenderStep_->commands.push_back(data); + curStepHasViewport_ = true; } void SetScissor(const VkRect2D &rc) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); - _dbg_assert_(G3D, (int)rc.extent.width >= 0); - _dbg_assert_(G3D, (int)rc.extent.height >= 0); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_((int)rc.extent.width >= 0); + _dbg_assert_((int)rc.extent.height >= 0); VkRenderData data{ VKRRenderCommand::SCISSOR }; data.scissor.scissor = rc; curRenderStep_->commands.push_back(data); + curStepHasScissor_ = true; } void SetStencilParams(uint8_t writeMask, uint8_t compareMask, uint8_t refValue) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); VkRenderData data{ VKRRenderCommand::STENCIL }; data.stencil.stencilWriteMask = writeMask; data.stencil.stencilCompareMask = compareMask; @@ -157,15 +150,15 @@ public: } void SetBlendFactor(uint32_t color) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); VkRenderData data{ VKRRenderCommand::BLEND }; data.blendColor.color = color; curRenderStep_->commands.push_back(data); } void PushConstants(VkPipelineLayout pipelineLayout, VkShaderStageFlags stages, int offset, int size, void *constants) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); - assert(size + offset < 40); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(size + offset < 40); VkRenderData data{ VKRRenderCommand::PUSH_CONSTANTS }; data.push.pipelineLayout = pipelineLayout; data.push.stages = stages; @@ -178,7 +171,7 @@ public: void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask); void Draw(VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count, int offset = 0) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && curStepHasViewport_ && curStepHasScissor_); VkRenderData data{ VKRRenderCommand::DRAW }; data.draw.count = count; data.draw.offset = offset; @@ -187,7 +180,7 @@ public: data.draw.vbuffer = vbuffer; data.draw.voffset = voffset; data.draw.numUboOffsets = numUboOffsets; - assert(numUboOffsets <= ARRAY_SIZE(data.draw.uboOffsets)); + _dbg_assert_(numUboOffsets <= ARRAY_SIZE(data.draw.uboOffsets)); for (int i = 0; i < numUboOffsets; i++) data.draw.uboOffsets[i] = uboOffsets[i]; curRenderStep_->commands.push_back(data); @@ -195,7 +188,7 @@ public: } void DrawIndexed(VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, int numInstances, VkIndexType indexType) { - _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && curStepHasViewport_ && curStepHasScissor_); VkRenderData data{ VKRRenderCommand::DRAW_INDEXED }; data.drawIndexed.count = count; data.drawIndexed.instances = numInstances; @@ -206,7 +199,7 @@ public: data.drawIndexed.ibuffer = ibuffer; data.drawIndexed.ioffset = ioffset; data.drawIndexed.numUboOffsets = numUboOffsets; - assert(numUboOffsets <= ARRAY_SIZE(data.drawIndexed.uboOffsets)); + _dbg_assert_(numUboOffsets <= ARRAY_SIZE(data.drawIndexed.uboOffsets)); for (int i = 0; i < numUboOffsets; i++) data.drawIndexed.uboOffsets[i] = uboOffsets[i]; data.drawIndexed.indexType = indexType; @@ -230,6 +223,12 @@ public: } } + // Gets a frame-unique ID of the current step being recorded. Can be used to figure out + // when the current step has changed, which means the caller will need to re-record its state. + int GetCurrentStepId() const { + return renderStepOffset_ + (int)steps_.size(); + } + void CreateBackbuffers(); void DestroyBackbuffers(); @@ -258,6 +257,11 @@ public: return frameData_[vulkan_->GetCurFrame()].profile.profileSummary; } + bool NeedsSwapchainRecreate() const { + // Accepting a few of these makes shutdown simpler. + return outOfDateFrames_ > VulkanContext::MAX_INFLIGHT_FRAMES; + } + private: bool InitBackbufferFramebuffers(int width, int height); bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. @@ -289,6 +293,9 @@ private: VKRRunType type = VKRRunType::END; VkFence fence; + VkFence readbackFence; // Strictly speaking we might only need one of these. + bool readbackFenceUsed = false; + // These are on different threads so need separate pools. VkCommandPool cmdPoolInit; VkCommandPool cmdPoolMain; @@ -310,11 +317,17 @@ private: int newInflightFrames_ = -1; int inflightFramesAtStart_ = 0; + int outOfDateFrames_ = 0; + // Submission time state int curWidth_ = -1; int curHeight_ = -1; bool insideFrame_ = false; + // This is the offset within this frame, in case of a mid-frame sync. + int renderStepOffset_ = 0; VKRStep *curRenderStep_ = nullptr; + bool curStepHasViewport_ = false; + bool curStepHasScissor_ = false; std::vector steps_; bool splitSubmit_ = false; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp similarity index 90% rename from ext/native/thin3d/thin3d_vulkan.cpp rename to Common/GPU/Vulkan/thin3d_vulkan.cpp index cdcadbea29..502a5194f5 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -19,23 +19,21 @@ #include #include #include -#include + +#include "Common/System/Display.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" + +#include "Common/Log.h" +#include "Common/StringUtils.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanImage.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" #include "Core/Config.h" -#include "base/logging.h" -#include "base/display.h" -#include "base/stringutil.h" -#include "image/zim_load.h" -#include "math/lin/matrix4x4.h" -#include "math/dataconv.h" -#include "thin3d/thin3d.h" -#include "thin3d/VulkanRenderManager.h" - -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanImage.h" -#include "Common/Vulkan/VulkanMemory.h" - // We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point. // binding 0 - uniform data // binding 1 - sampler @@ -43,7 +41,7 @@ // // Vertex data lives in a separate namespace (location = 0, 1, etc) -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" namespace Draw { @@ -252,7 +250,8 @@ public: ubo_ = new uint8_t[uboSize_]; } ~VKPipeline() { - vulkan_->Delete().QueueDeletePipeline(vkpipeline); + vulkan_->Delete().QueueDeletePipeline(backbufferPipeline); + vulkan_->Delete().QueueDeletePipeline(framebufferPipeline); delete[] ubo_; } @@ -273,7 +272,8 @@ public: return false; } - VkPipeline vkpipeline; + VkPipeline backbufferPipeline = VK_NULL_HANDLE; + VkPipeline framebufferPipeline = VK_NULL_HANDLE; int stride[4]{}; int dynamicUniformSize = 0; @@ -383,13 +383,13 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override; - bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; - bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override; + bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override; + bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; // color must be 0, for now. void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; @@ -404,6 +404,7 @@ public: void BindSamplerStates(int start, int count, SamplerState **state) override; void BindTextures(int start, int count, Texture **textures) override; + void BindPipeline(Pipeline *pipeline) override { curPipeline_ = (VKPipeline *)pipeline; } @@ -427,6 +428,7 @@ public: void DrawIndexed(int vertexCount, int offset) override; void DrawUP(const void *vdata, int vertexCount) override; + void BindCompatiblePipeline(); void ApplyDynamicState(); void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override; @@ -459,25 +461,25 @@ public: std::vector GetFeatureList() const override; std::vector GetExtensionList() const override; - uintptr_t GetNativeObject(NativeObject obj) override { + uint64_t GetNativeObject(NativeObject obj) override { switch (obj) { case NativeObject::FRAMEBUFFER_RENDERPASS: // Return a representative renderpass. - return (uintptr_t)renderManager_.GetFramebufferRenderPass(); + return (uint64_t)renderManager_.GetFramebufferRenderPass(); case NativeObject::BACKBUFFER_RENDERPASS: - return (uintptr_t)renderManager_.GetBackbufferRenderPass(); + return (uint64_t)renderManager_.GetBackbufferRenderPass(); case NativeObject::COMPATIBLE_RENDERPASS: - return (uintptr_t)renderManager_.GetCompatibleRenderPass(); + return (uint64_t)renderManager_.GetCompatibleRenderPass(); case NativeObject::INIT_COMMANDBUFFER: - return (uintptr_t)renderManager_.GetInitCmd(); + return (uint64_t)renderManager_.GetInitCmd(); case NativeObject::BOUND_TEXTURE0_IMAGEVIEW: - return (uintptr_t)boundImageView_[0]; + return (uint64_t)boundImageView_[0]; case NativeObject::BOUND_TEXTURE1_IMAGEVIEW: - return (uintptr_t)boundImageView_[1]; + return (uint64_t)boundImageView_[1]; case NativeObject::RENDER_MANAGER: - return (uintptr_t)&renderManager_; + return (uint64_t)(uintptr_t)&renderManager_; case NativeObject::NULL_IMAGEVIEW: - return (uintptr_t)GetNullTexture()->GetImageView(); + return (uint64_t)GetNullTexture()->GetImageView(); default: Crash(); return 0; @@ -486,7 +488,14 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; + int GetCurrentStepId() const override { + return renderManager_.GetCurrentStepId(); + } + + void InvalidateCachedState() override; + private: + VulkanTexture *GetNullTexture(); VulkanContext *vulkan_ = nullptr; @@ -690,7 +699,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur // Zero-sized textures not allowed. _assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1! if (desc.width * desc.height * desc.depth <= 0) { - ELOG("Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth); + ERROR_LOG(G3D, "Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth); return false; } _assert_(push); @@ -700,7 +709,9 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur height_ = desc.height; depth_ = desc.depth; vkTex_ = new VulkanTexture(vulkan_); - vkTex_->SetTag(desc.tag); + if (desc.tag) { + vkTex_->SetTag(desc.tag); + } VkFormat vulkanFormat = DataFormatToVulkan(format_); int bpp = GetBpp(vulkanFormat); int bytesPerPixel = bpp / 8; @@ -711,7 +722,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur } if (!vkTex_->CreateDirect(cmd, alloc, width_, height_, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) { - ELOG("Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_); + ERROR_LOG(G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_); return false; } if (desc.initData.size()) { @@ -775,8 +786,13 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) // Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off. // See: https://github.com/hrydgard/ppsspp/pull/11684 if (deviceProps.deviceID >= 0x05000000 && deviceProps.deviceID < 0x06000000) { - bugs_.Infest(Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL); + if (deviceProps.driverVersion < 0x80180000) { + bugs_.Infest(Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL); + } } + // Color write mask not masking write in certain scenarios with a depth test, see #10421. + // Known still present on driver 0x80180000 and Adreno 5xx (possibly more.) + bugs_.Infest(Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST); } else if (caps_.vendor == GPUVendor::VENDOR_AMD) { // See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for. if (deviceProps.driverVersion < 0x00407000) { @@ -837,7 +853,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) dsl.bindingCount = ARRAY_SIZE(bindings); dsl.pBindings = bindings; VkResult res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; @@ -845,11 +861,11 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) pl.setLayoutCount = 1; pl.pSetLayouts = &descriptorSetLayout_; res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); renderManager_.SetSplitSubmit(splitSubmit); @@ -901,6 +917,23 @@ void VKContext::EndFrame() { renderManager_.Finish(); push_ = nullptr; + + // Unbind stuff, to avoid accidentally relying on it across frames (and provide some protection against forgotten unbinds of deleted things). + InvalidateCachedState(); +} + +void VKContext::InvalidateCachedState() { + curPipeline_ = nullptr; + + for (auto &view : boundImageView_) { + view = VK_NULL_HANDLE; + } + for (auto &sampler : boundSamplers_) { + sampler = nullptr; + } + for (auto &texture : boundTextures_) { + texture = nullptr; + } } void VKContext::WipeQueue() { @@ -936,9 +969,8 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { bufferDesc.offset = 0; bufferDesc.range = curPipeline_->GetUBOSize(); - VkDescriptorImageInfo imageDesc; - - VkWriteDescriptorSet writes[1 + MAX_BOUND_TEXTURES] = {}; + VkDescriptorImageInfo imageDesc[MAX_BOUND_TEXTURES]{}; + VkWriteDescriptorSet writes[1 + MAX_BOUND_TEXTURES]{}; // If handles are NULL for whatever buggy reason, it's best to leave the descriptors // unwritten instead of trying to write a zero, which is not legal. @@ -959,19 +991,19 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) { if (key.imageViews_[i] && key.samplers_[i] && key.samplers_[i]->GetSampler()) { - imageDesc.imageView = key.imageViews_[i]; - imageDesc.sampler = key.samplers_[i]->GetSampler(); + imageDesc[i].imageView = key.imageViews_[i]; + imageDesc[i].sampler = key.samplers_[i]->GetSampler(); #ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR - imageDesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageDesc[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; #else - imageDesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageDesc[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; #endif writes[numWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writes[numWrites].dstSet = descSet; writes[numWrites].dstArrayElement = 0; writes[numWrites].dstBinding = i + 1; writes[numWrites].pBufferInfo = nullptr; - writes[numWrites].pImageInfo = &imageDesc; + writes[numWrites].pImageInfo = &imageDesc[i]; writes[numWrites].pTexelBufferView = nullptr; writes[numWrites].descriptorCount = 1; writes[numWrites].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; @@ -1001,7 +1033,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { for (auto &iter : desc.shaders) { VKShaderModule *vkshader = (VKShaderModule *)iter; if (!vkshader) { - ELOG("CreateGraphicsPipeline got passed a null shader"); + ERROR_LOG(G3D, "CreateGraphicsPipeline got passed a null shader"); return nullptr; } VkPipelineShaderStageCreateInfo &stage = stages[i++]; @@ -1037,30 +1069,40 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; raster->ToVulkan(&rs); - VkGraphicsPipelineCreateInfo info{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; - info.flags = 0; - info.stageCount = (uint32_t)stages.size(); - info.pStages = stages.data(); - info.pColorBlendState = &blend->info; - info.pDepthStencilState = &depth->info; - info.pDynamicState = &dynamicInfo; - info.pInputAssemblyState = &inputAssembly; - info.pTessellationState = nullptr; - info.pMultisampleState = &ms; - info.pVertexInputState = &input->visc; - info.pRasterizationState = &rs; - info.pViewportState = &vs; // Must set viewport and scissor counts even if we set the actual state dynamically. - info.layout = pipelineLayout_; - info.subpass = 0; - info.renderPass = renderManager_.GetBackbufferRenderPass(); + VkGraphicsPipelineCreateInfo createInfo[2]{}; + for (auto &info : createInfo) { + info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + info.flags = 0; + info.stageCount = (uint32_t)stages.size(); + info.pStages = stages.data(); + info.pColorBlendState = &blend->info; + info.pDepthStencilState = &depth->info; + info.pDynamicState = &dynamicInfo; + info.pInputAssemblyState = &inputAssembly; + info.pTessellationState = nullptr; + info.pMultisampleState = &ms; + info.pVertexInputState = &input->visc; + info.pRasterizationState = &rs; + info.pViewportState = &vs; // Must set viewport and scissor counts even if we set the actual state dynamically. + info.layout = pipelineLayout_; + info.subpass = 0; + } - // OK, need to create a new pipeline. - VkResult result = vkCreateGraphicsPipelines(device_, pipelineCache_, 1, &info, nullptr, &pipeline->vkpipeline); + createInfo[0].renderPass = renderManager_.GetBackbufferRenderPass(); + createInfo[1].renderPass = renderManager_.GetFramebufferRenderPass(); + + // OK, need to create new pipelines. + VkPipeline pipelines[2]{}; + VkResult result = vkCreateGraphicsPipelines(device_, pipelineCache_, 2, createInfo, nullptr, pipelines); if (result != VK_SUCCESS) { - ELOG("Failed to create graphics pipeline"); + ERROR_LOG(G3D, "Failed to create graphics pipeline"); delete pipeline; return nullptr; } + + pipeline->backbufferPipeline = pipelines[0]; + pipeline->framebufferPipeline = pipelines[1]; + if (desc.uniformDesc) { pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize; } @@ -1130,14 +1172,14 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) { VkCommandBuffer initCmd = renderManager_.GetInitCmd(); if (!push_ || !initCmd) { // Too early! Fail. - ELOG("Can't create textures before the first frame has started."); + ERROR_LOG(G3D, "Can't create textures before the first frame has started."); return nullptr; } VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc); if (tex->Create(initCmd, push_, desc, allocator_)) { return tex; } else { - ELOG("Failed to create texture"); + ERROR_LOG(G3D, "Failed to create texture"); delete tex; return nullptr; } @@ -1224,7 +1266,7 @@ ShaderModule *VKContext::CreateShaderModule(ShaderStage stage, ShaderLanguage la if (shader->Compile(vulkan_, language, data, size)) { return shader; } else { - ELOG("Failed to compile shader: %s", (const char *)data); + ERROR_LOG(G3D, "Failed to compile shader: %s", (const char *)data); shader->Release(); return nullptr; } @@ -1262,7 +1304,7 @@ void VKContext::Draw(int vertexCount, int offset) { VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); - renderManager_.BindPipeline(curPipeline_->vkpipeline); + BindCompatiblePipeline(); ApplyDynamicState(); renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount, offset); } @@ -1278,7 +1320,7 @@ void VKContext::DrawIndexed(int vertexCount, int offset) { VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); - renderManager_.BindPipeline(curPipeline_->vkpipeline); + BindCompatiblePipeline(); ApplyDynamicState(); renderManager_.DrawIndexed(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vulkanIbuf, (int)ibBindOffset + offset * sizeof(uint32_t), vertexCount, 1, VK_INDEX_TYPE_UINT16); } @@ -1290,11 +1332,20 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) { VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); - renderManager_.BindPipeline(curPipeline_->vkpipeline); + BindCompatiblePipeline(); ApplyDynamicState(); renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount); } +void VKContext::BindCompatiblePipeline() { + VkRenderPass renderPass = renderManager_.GetCompatibleRenderPass(); + if (renderPass == renderManager_.GetBackbufferRenderPass()) { + renderManager_.BindPipeline(curPipeline_->backbufferPipeline); + } else { + renderManager_.BindPipeline(curPipeline_->framebufferPipeline); + } +} + void VKContext::Clear(int clearMask, uint32_t colorval, float depthVal, int stencilVal) { int mask = 0; if (clearMask & FBChannel::FB_COLOR_BIT) @@ -1355,11 +1406,6 @@ std::vector VKContext::GetFeatureList() const { features.push_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat)); - // Also list texture formats and their properties. - for (int i = VK_FORMAT_BEGIN_RANGE; i <= VK_FORMAT_END_RANGE; i++) { - // TODO - } - return features; } @@ -1397,9 +1443,9 @@ uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const { // use this frame's init command buffer. class VKFramebuffer : public Framebuffer { public: - VKFramebuffer(VKRFramebuffer *fb) : buf_(fb) { _assert_msg_(G3D, fb, "Null fb in VKFramebuffer constructor"); } + VKFramebuffer(VKRFramebuffer *fb) : buf_(fb) { _assert_msg_(fb, "Null fb in VKFramebuffer constructor"); } ~VKFramebuffer() { - _assert_msg_(G3D, buf_, "Null buf_ in VKFramebuffer - double delete?"); + _assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?"); buf_->vulkan_->Delete().QueueCallback([](void *fb) { VKRFramebuffer *vfb = static_cast(fb); delete vfb; @@ -1413,11 +1459,13 @@ private: Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetFramebufferRenderPass(), desc.width, desc.height); + // TODO: We always create with depth here, even when it's not needed (such as color temp FBOs). + // Should optimize those away. + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetFramebufferRenderPass(), desc.width, desc.height, desc.tag); return new VKFramebuffer(vkrfb); } -void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) { +void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) { VKFramebuffer *src = (VKFramebuffer *)srcfb; VKFramebuffer *dst = (VKFramebuffer *)dstfb; @@ -1426,10 +1474,10 @@ void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - renderManager_.CopyFramebuffer(src->GetFB(), VkRect2D{ {x, y}, {(uint32_t)width, (uint32_t)height } }, dst->GetFB(), VkOffset2D{ dstX, dstY }, aspectMask); + renderManager_.CopyFramebuffer(src->GetFB(), VkRect2D{ {x, y}, {(uint32_t)width, (uint32_t)height } }, dst->GetFB(), VkOffset2D{ dstX, dstY }, aspectMask, tag); } -bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { +bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) { VKFramebuffer *src = (VKFramebuffer *)srcfb; VKFramebuffer *dst = (VKFramebuffer *)dstfb; @@ -1438,11 +1486,11 @@ bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int sr if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - renderManager_.BlitFramebuffer(src->GetFB(), VkRect2D{ {srcX1, srcY1}, {(uint32_t)(srcX2 - srcX1), (uint32_t)(srcY2 - srcY1) } }, dst->GetFB(), VkRect2D{ {dstX1, dstY1}, {(uint32_t)(dstX2 - dstX1), (uint32_t)(dstY2 - dstY1) } }, aspectMask, filter == FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); + renderManager_.BlitFramebuffer(src->GetFB(), VkRect2D{ {srcX1, srcY1}, {(uint32_t)(srcX2 - srcX1), (uint32_t)(srcY2 - srcY1) } }, dst->GetFB(), VkRect2D{ {dstX1, dstY1}, {(uint32_t)(dstX2 - dstX1), (uint32_t)(dstY2 - dstY1) } }, aspectMask, filter == FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, tag); return true; } -bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride) { +bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) { VKFramebuffer *src = (VKFramebuffer *)srcfb; int aspectMask = 0; @@ -1450,7 +1498,7 @@ bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits, if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - return renderManager_.CopyFramebufferToMemorySync(src ? src->GetFB() : nullptr, aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride); + return renderManager_.CopyFramebufferToMemorySync(src ? src->GetFB() : nullptr, aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride, tag); } DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) { @@ -1464,13 +1512,13 @@ DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) { return DrawContext::PreferredFramebufferReadbackFormat(src); } -void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) { +void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { VKFramebuffer *fb = (VKFramebuffer *)fbo; VKRRenderPassAction color = (VKRRenderPassAction)rp.color; VKRRenderPassAction depth = (VKRRenderPassAction)rp.depth; VKRRenderPassAction stencil = (VKRRenderPassAction)rp.stencil; - renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil); + renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, tag); curFramebuffer_ = fb; } @@ -1478,15 +1526,21 @@ void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPass void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) { VKFramebuffer *fb = (VKFramebuffer *)fbo; - if (fb == curFramebuffer_) { - Crash(); - } + // TODO: There are cases where this is okay, actually. + _assert_(fb != curFramebuffer_); int aspect = 0; - if (channelBit & FBChannel::FB_COLOR_BIT) aspect |= VK_IMAGE_ASPECT_COLOR_BIT; - if (channelBit & FBChannel::FB_DEPTH_BIT) aspect |= VK_IMAGE_ASPECT_DEPTH_BIT; - if (channelBit & FBChannel::FB_STENCIL_BIT) aspect |= VK_IMAGE_ASPECT_STENCIL_BIT; - + switch (channelBit) { + case FBChannel::FB_COLOR_BIT: + aspect = VK_IMAGE_ASPECT_COLOR_BIT; + break; + case FBChannel::FB_DEPTH_BIT: + aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + break; + default: + _assert_(false); + break; + } boundTextures_[binding] = nullptr; boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment); } @@ -1529,7 +1583,7 @@ void VKContext::HandleEvent(Event ev, int width, int height, void *param1, void renderManager_.CreateBackbuffers(); break; default: - assert(false); + _assert_(false); break; } } diff --git a/ext/native/thin3d/thin3d.cpp b/Common/GPU/thin3d.cpp similarity index 96% rename from ext/native/thin3d/thin3d.cpp rename to Common/GPU/thin3d.cpp index 5ee4a9e44a..95dce26147 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -2,12 +2,10 @@ #include #include -#include "base/logging.h" -#include "base/display.h" -#include "thin3d/thin3d.h" +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" #include "Common/Log.h" #include "Common/ColorConv.h" -#include "Core/Reporting.h" namespace Draw { @@ -78,13 +76,13 @@ bool RefCountedObject::Release() { } } else { - _dbg_assert_msg_(G3D, false, "Refcount (%d) invalid for object %p - corrupt?", refcount_, this); + _dbg_assert_msg_(false, "Refcount (%d) invalid for object %p - corrupt?", refcount_, this); } return false; } bool RefCountedObject::ReleaseAssertLast() { - _dbg_assert_msg_(G3D, refcount_ == 1, "RefCountedObject: Expected to be the last reference, but isn't!"); + _dbg_assert_msg_(refcount_ == 1, "RefCountedObject: Expected to be the last reference, but isn't!"); if (refcount_ > 0 && refcount_ < 10000) { refcount_--; if (refcount_ == 0) { @@ -92,7 +90,7 @@ bool RefCountedObject::ReleaseAssertLast() { return true; } } else { - ELOG("Refcount (%d) invalid for object %p - corrupt?", refcount_, this); + ERROR_LOG(G3D, "Refcount (%d) invalid for object %p - corrupt?", refcount_, this); } return false; } @@ -451,7 +449,7 @@ void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, u case Draw::DataFormat::R8G8B8A8_UNORM: case Draw::DataFormat::UNDEFINED: default: - WARN_LOG_REPORT_ONCE(convFromRGBA, G3D, "Unable to convert from format: %d", (int)format); + WARN_LOG(G3D, "Unable to convert from format: %d", (int)format); break; } } @@ -493,7 +491,7 @@ void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, u dst += dstStride * 3; } } else { - WARN_LOG_REPORT_ONCE(convFromBGRA, G3D, "Unable to convert from format to BGRA: %d", (int)format); + WARN_LOG(G3D, "Unable to convert from format to BGRA: %d", (int)format); } } diff --git a/ext/native/thin3d/thin3d.h b/Common/GPU/thin3d.h similarity index 94% rename from ext/native/thin3d/thin3d.h rename to Common/GPU/thin3d.h index b64b33e886..e3f6390afe 100644 --- a/ext/native/thin3d/thin3d.h +++ b/Common/GPU/thin3d.h @@ -12,7 +12,6 @@ #include #include -#include "base/logging.h" #include "DataFormat.h" namespace Lin { @@ -136,6 +135,7 @@ enum class Primitive { TRIANGLE_STRIP_ADJ, UNDEFINED, + PRIMITIVE_TYPE_COUNT, }; enum VertexShaderPreset : int { @@ -301,6 +301,8 @@ enum class Event { PRESENTED, }; +constexpr uint32_t MAX_TEXTURE_SLOTS = 2; + struct FramebufferDesc { int width; int height; @@ -308,6 +310,7 @@ struct FramebufferDesc { int numColorAttachments; bool z_stencil; FBColorDepth colorDepth; + const char *tag; // For graphics debuggers }; // Binary compatible with D3D11 viewport. @@ -335,6 +338,7 @@ public: ANY_MAP_BUFFER_RANGE_SLOW = 2, PVR_GENMIPMAP_HEIGHT_GREATER = 3, BROKEN_NAN_IN_CONDITIONAL = 4, + COLORWRITEMASK_BROKEN_WITH_DEPTHTEST = 5, }; protected: @@ -532,8 +536,8 @@ struct TextureDesc { int depth; int mipLevels; bool generateMips; - // Optional, for tracking memory usage. - std::string tag; + // Optional, for tracking memory usage and graphcis debuggers. + const char *tag; // Does not take ownership over pointed-to data. std::vector initData; TextureCallback initDataCallback; @@ -552,6 +556,7 @@ struct RenderPassInfo { uint32_t clearColor; float clearDepth; uint8_t clearStencil; + const char *tag; }; class DrawContext { @@ -595,9 +600,9 @@ public: // Copies data from the CPU over into the buffer, at a specific offset. This does not change the size of the buffer and cannot write outside it. virtual void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) = 0; - virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) = 0; - virtual bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) = 0; - virtual bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride) { + virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) = 0; + virtual bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) = 0; + virtual bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) { return false; } virtual DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) { @@ -606,9 +611,9 @@ public: // These functions should be self explanatory. // Binding a zero render target means binding the backbuffer. - virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) = 0; + virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) = 0; - // color must be 0, for now. + // binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2). virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) = 0; // deprecated @@ -641,7 +646,11 @@ public: BindTextures(stage, 1, textures); } // from sampler 0 and upwards - // Call this with 0 to signal that you have been drawing on your own, and need the state reset on the next pipeline bind. + // Clear state cached within thin3d. Must be called after directly calling API functions. + // Note that framebuffer state (which framebuffer is bounds) may not be cached. + // Must not actually perform any API calls itself since this can be called when no framebuffer is bound for rendering. + virtual void InvalidateCachedState() = 0; + virtual void BindPipeline(Pipeline *pipeline) = 0; virtual void Draw(int vertexCount, int offset) = 0; @@ -650,7 +659,7 @@ public: // Frame management (for the purposes of sync and resource management, necessary with modern APIs). Default implementations here. virtual void BeginFrame() {} - virtual void EndFrame() {} + virtual void EndFrame() = 0; virtual void WipeQueue() {} // This should be avoided as much as possible, in favor of clearing when binding a render target, which is native @@ -664,13 +673,15 @@ public: } virtual std::string GetInfoString(InfoField info) const = 0; - virtual uintptr_t GetNativeObject(NativeObject obj) = 0; + virtual uint64_t GetNativeObject(NativeObject obj) = 0; virtual void HandleEvent(Event ev, int width, int height, void *param1 = nullptr, void *param2 = nullptr) = 0; // Flush state like scissors etc so the caller can do its own custom drawing. virtual void FlushState() {} + virtual int GetCurrentStepId() const = 0; + protected: ShaderModule *vsPresets_[VS_MAX_PRESET]; ShaderModule *fsPresets_[FS_MAX_PRESET]; diff --git a/ext/native/thin3d/thin3d_create.h b/Common/GPU/thin3d_create.h similarity index 97% rename from ext/native/thin3d/thin3d_create.h rename to Common/GPU/thin3d_create.h index a89c74ab96..a2030792af 100644 --- a/ext/native/thin3d/thin3d_create.h +++ b/Common/GPU/thin3d_create.h @@ -2,7 +2,7 @@ #include #include -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" // Separated this stuff into its own file so we don't get Windows.h included if all we want is the thin3d declarations. diff --git a/Common/GraphicsContext.h b/Common/GraphicsContext.h index 5dfec7f6d9..873722764c 100644 --- a/Common/GraphicsContext.h +++ b/Common/GraphicsContext.h @@ -2,7 +2,7 @@ #include -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" // Init is done differently on each platform, and done close to the creation, so it's // expected to be implemented by subclasses. @@ -34,15 +34,9 @@ public: virtual void ThreadEnd() {} virtual void StopThread() {} + // Useful for checks that need to be performed every frame. + // Should strive to get rid of these. + virtual void Poll() {} + virtual Draw::DrawContext *GetDrawContext() = 0; }; - -class DummyGraphicsContext : public GraphicsContext { -public: - void Shutdown() override {} - void SwapInterval(int interval) override {} - void SwapBuffers() override {} - void Resize() override {} - - Draw::DrawContext *GetDrawContext() override { return nullptr; } -}; diff --git a/ext/native/input/gesture_detector.cpp b/Common/Input/GestureDetector.cpp similarity index 96% rename from ext/native/input/gesture_detector.cpp rename to Common/Input/GestureDetector.cpp index 6bd194c768..cab29e1b1a 100644 --- a/ext/native/input/gesture_detector.cpp +++ b/Common/Input/GestureDetector.cpp @@ -2,10 +2,8 @@ // TODO: // Zoom gesture a la http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-6-implementing-the-pinch-zoom-gesture/1847 -#include "base/logging.h" -#include "base/timeutil.h" -#include "input/gesture_detector.h" - +#include "Common/TimeUtil.h" +#include "Common/Input/GestureDetector.h" const float estimatedInertiaDamping = 0.75f; diff --git a/ext/native/input/gesture_detector.h b/Common/Input/GestureDetector.h similarity index 93% rename from ext/native/input/gesture_detector.h rename to Common/Input/GestureDetector.h index 783843cee3..5d4e54f36e 100644 --- a/ext/native/input/gesture_detector.h +++ b/Common/Input/GestureDetector.h @@ -1,5 +1,5 @@ -#include "input/input_state.h" -#include "math/geom2d.h" +#include "Common/Input/InputState.h" +#include "Common/Math/geom2d.h" // Mainly for detecting (multi-)touch gestures but also useable for left button mouse dragging etc. // Currently only supports simple scroll-drags with inertia. diff --git a/ext/native/input/input_state.cpp b/Common/Input/InputState.cpp similarity index 96% rename from ext/native/input/input_state.cpp rename to Common/Input/InputState.cpp index 8c28473f1d..90fc9b6a1a 100644 --- a/ext/native/input/input_state.cpp +++ b/Common/Input/InputState.cpp @@ -1,5 +1,5 @@ -#include "input/input_state.h" -#include "input/keycodes.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" #include const char *GetDeviceName(int deviceId) { diff --git a/ext/native/input/input_state.h b/Common/Input/InputState.h similarity index 98% rename from ext/native/input/input_state.h rename to Common/Input/InputState.h index c648612e34..59a0a6e057 100644 --- a/ext/native/input/input_state.h +++ b/Common/Input/InputState.h @@ -7,9 +7,8 @@ #include #include -#include "math/lin/vec3.h" -#include "base/basictypes.h" -#include "input/keycodes.h" +#include "Common/Math/lin/vec3.h" +#include "Common/Input/KeyCodes.h" // Default device IDs diff --git a/ext/native/input/keycodes.h b/Common/Input/KeyCodes.h similarity index 100% rename from ext/native/input/keycodes.h rename to Common/Input/KeyCodes.h diff --git a/Common/Log.cpp b/Common/Log.cpp new file mode 100644 index 0000000000..1d3b1ba56c --- /dev/null +++ b/Common/Log.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +#include "ppsspp_config.h" + +#include "Common.h" +#include "Common/Log.h" +#include "StringUtils.h" +#include "Common/Data/Encoding/Utf8.h" + +#if PPSSPP_PLATFORM(ANDROID) +#include +#elif PPSSPP_PLATFORM(WINDOWS) +#include "CommonWindows.h" +#endif + +#define LOG_BUF_SIZE 2048 + +bool HandleAssert(const char *function, const char *file, int line, const char *expression, const char* format, ...) { + // Read message and write it to the log + char text[LOG_BUF_SIZE]; + const char *caption = "Critical"; + va_list args; + va_start(args, format); + vsnprintf(text, sizeof(text), format, args); + va_end(args); + + // Secondary formatting. Wonder if this can be combined into the vsnprintf somehow. + char formatted[LOG_BUF_SIZE]; + snprintf(formatted, sizeof(formatted), "(%s:%s:%d) %s: [%s] %s", file, function, line, caption, expression, text); + + // Normal logging (will also log to Android log) + ERROR_LOG(SYSTEM, "%s", formatted); + // Also do a simple printf for good measure, in case logging of SYSTEM is disabled (should we disallow that?) + printf("%s\n", formatted); + +#if defined(USING_WIN_UI) + int msgBoxStyle = MB_ICONINFORMATION | MB_YESNO; + std::wstring wtext = ConvertUTF8ToWString(formatted) + L"\n\nTry to continue?"; + std::wstring wcaption = ConvertUTF8ToWString(caption); + OutputDebugString(wtext.c_str()); + if (IDYES != MessageBox(0, wtext.c_str(), wcaption.c_str(), msgBoxStyle)) { + return false; + } else { + return true; + } +#elif PPSSPP_PLATFORM(ANDROID) + __android_log_assert(expression, "PPSSPP", "%s", formatted); + // Doesn't matter what we return here. + return false; +#else + OutputDebugStringUTF8(text); + return false; +#endif +} diff --git a/Common/Log.h b/Common/Log.h index 1e463acadc..f8a56730a6 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -17,15 +17,7 @@ #pragma once -#include -#include - #include "CommonFuncs.h" -#include "Common/MsgHandler.h" - -#if defined(__ANDROID__) -#include -#endif #define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and debugprintfs from the game itself. #define ERROR_LEVEL 2 // Important errors. @@ -34,11 +26,10 @@ #define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. #define VERBOSE_LEVEL 6 // Noisy debugging - sometimes needed but usually unimportant. - namespace LogTypes { enum LOG_TYPE { - SYSTEM = 0, + SYSTEM = 0, // Catch-all for uncategorized things BOOT, COMMON, CPU, @@ -52,6 +43,8 @@ enum LOG_TYPE { SASMIX, SAVESTATE, FRAMEBUF, + AUDIO, + IO, SCEAUDIO, SCECTRL, @@ -90,98 +83,78 @@ void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, ; bool GenericLogEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type); -#if defined(LOGGING) || defined(_DEBUG) || defined(DEBUGFAST) || defined(_WIN32) +#if defined(_DEBUG) || defined(_WIN32) + #define MAX_LOGLEVEL DEBUG_LEVEL + #else + #ifndef MAX_LOGLEVEL #define MAX_LOGLEVEL INFO_LEVEL #endif // loglevel + #endif // logging -// Let the compiler optimize this out +// Let the compiler optimize this out. +// TODO: Compute a dynamic max level as well that can be checked here. #define GENERIC_LOG(t, v, ...) { \ if (v <= MAX_LOGLEVEL) \ GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ } -#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (false) +#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (false) #define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (false) -#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (false) -#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (false) -#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (false) +#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (false) +#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (false) +#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (false) #define VERBOSE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LVERBOSE, __VA_ARGS__) } while (false) +// Currently only actually shows a dialog box on Windows. +bool HandleAssert(const char *function, const char *file, int line, const char *expression, const char* format, ...) +#ifdef __GNUC__ +__attribute__((format(printf, 5, 6))) +#endif +; + #if defined(__ANDROID__) - // Tricky macro to get the basename, that also works if *built* on Win32. +// Doesn't mean this macro can be used on Win32 though. #define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : (__builtin_strrchr(__FILE__, '\\') ? __builtin_strrchr(__FILE__, '\\') + 1 : __FILE__)) -void AndroidAssertLog(const char *func, const char *file, int line, const char *condition, const char *fmt, ...); - +#else +#define __FILENAME__ __FILE__ #endif +// If we're in "debug" assert mode #if MAX_LOGLEVEL >= DEBUG_LEVEL -#define _dbg_assert_(_t_, _a_) \ + +#define _dbg_assert_(_a_) \ if (!(_a_)) {\ - ERROR_LOG(_t_, #_a_ "\n\nError...\n\n Line: %d\n File: %s\n\nIgnore and continue?", \ - __LINE__, __FILE__); \ - if (!PanicYesNo("*** Assertion ***\n")) { Crash(); } \ + if (!HandleAssert(__FUNCTION__, __FILENAME__, __LINE__, #_a_, "*** Assertion ***\n")) Crash(); \ } -#if defined(__ANDROID__) - -#define _dbg_assert_msg_(_t_, _a_, ...)\ - if (!(_a_)) {\ - printf(__VA_ARGS__); \ - ERROR_LOG(_t_, __VA_ARGS__); \ - if (!PanicYesNo(__VA_ARGS__)) AndroidAssertLog(__FUNCTION__, __FILENAME__, __LINE__, #_a_, __VA_ARGS__); \ +#define _dbg_assert_msg_(_a_, ...) \ + if (!(_a_)) { \ + if (!HandleAssert(__FUNCTION__, __FILENAME__, __LINE__, #_a_, __VA_ARGS__)) Crash(); \ } -#else // !defined(__ANDROID__) - -#define _dbg_assert_msg_(_t_, _a_, ...)\ - if (!(_a_)) {\ - printf(__VA_ARGS__); \ - ERROR_LOG(_t_, __VA_ARGS__); \ - if (!PanicYesNo(__VA_ARGS__)) { Crash();} \ - } - -#endif // __ANDROID__ - -#define _dbg_update_() ; //Host_UpdateLogDisplay(); - #else // not debug -#define _dbg_update_() ; #ifndef _dbg_assert_ -#define _dbg_assert_(_t_, _a_) {} -#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {} +#define _dbg_assert_(_a_) {} +#define _dbg_assert_msg_(_a_, _desc_, ...) {} #endif // dbg_assert + #endif // MAX_LOGLEVEL DEBUG -#if defined(__ANDROID__) - #define _assert_(_a_) \ if (!(_a_)) {\ - AndroidAssertLog(__FUNCTION__, __FILENAME__, __LINE__, #_a_, "Assertion failed!"); \ + if (!HandleAssert(__FUNCTION__, __FILENAME__, __LINE__, #_a_, "*** Assertion ***\n")) Crash(); \ } -#define _assert_msg_(_t_, _a_, ...) \ - if (!(_a_) && !PanicYesNo(__VA_ARGS__)) { \ - AndroidAssertLog(__FUNCTION__, __FILENAME__, __LINE__, #_a_, __VA_ARGS__); \ +#define _assert_msg_(_a_, ...) \ + if (!(_a_)) { \ + if (!HandleAssert(__FUNCTION__, __FILENAME__, __LINE__, #_a_, __VA_ARGS__)) Crash(); \ } -#else // __ANDROID__ - -#define _assert_(_a_) \ - if (!(_a_)) {\ - ERROR_LOG(SYSTEM, "Error...\n\n Line: %d\n File: %s\n\nIgnore and continue?", \ - __LINE__, __FILE__); \ - if (!PanicYesNo("*** Assertion ***\n")) { Crash(); } \ - } - -#define _assert_msg_(_t_, _a_, ...) \ - if (!(_a_) && !PanicYesNo(__VA_ARGS__)) { \ - Crash(); \ - } - -#endif // __ANDROID__ +// Just INFO_LOGs on nonWindows. On Windows it outputs to the VS output console. +void OutputDebugStringUTF8(const char *p); diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index 485a7b47da..d518df7a99 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -18,19 +18,21 @@ #include "ppsspp_config.h" #include +#include -#include "base/logging.h" -#include "util/text/utf8.h" -#include "LogManager.h" -#include "ConsoleListener.h" -#include "Timer.h" -#include "FileUtil.h" -#include "StringUtils.h" -#include "Core/Config.h" +#include "Common/Data/Encoding/Utf8.h" + +#include "Common/LogManager.h" +#include "Common/ConsoleListener.h" +#include "Common/TimeUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/StringUtils.h" // Don't need to savestate this. const char *hleCurrentThreadName = nullptr; +bool *g_bLogEnabledSetting = nullptr; + static const char level_to_char[8] = "-NEWIDV"; #if PPSSPP_PLATFORM(UWP) && defined(_DEBUG) @@ -40,38 +42,27 @@ static const char level_to_char[8] = "-NEWIDV"; #endif void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char *file, int line, const char* fmt, ...) { - if (!g_Config.bEnableLogging) + if (g_bLogEnabledSetting && !(*g_bLogEnabledSetting)) return; va_list args; va_start(args, fmt); LogManager *instance = LogManager::GetInstance(); if (instance) { instance->Log(level, type, file, line, fmt, args); + } else { + // Fall back to printf if we're before the log manager has been initialized. + vprintf(fmt, args); + printf("\n"); } va_end(args); } bool GenericLogEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type) { if (LogManager::GetInstance()) - return g_Config.bEnableLogging && LogManager::GetInstance()->IsEnabled(level, type); + return (*g_bLogEnabledSetting) && LogManager::GetInstance()->IsEnabled(level, type); return false; } -#if defined(__ANDROID__) - -#define LOG_BUF_SIZE 1024 - -void AndroidAssertLog(const char *func, const char *file, int line, const char *condition, const char *fmt, ...) { - char buf[LOG_BUF_SIZE]; - va_list args; - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - __android_log_assert(condition, "PPSSPP", "%s:%d (%s): [%s] %s", file, line, func, condition, buf); - va_end(args); -} - -#endif - LogManager *LogManager::logManager_ = NULL; struct LogNameTableEntry { @@ -94,6 +85,8 @@ static const LogNameTableEntry logTable[] = { {LogTypes::SASMIX, "SASMIX"}, {LogTypes::SAVESTATE, "SAVESTATE"}, {LogTypes::FRAMEBUF, "FRAMEBUF"}, + {LogTypes::AUDIO, "AUDIO"}, + {LogTypes::IO, "IO"}, {LogTypes::SCEAUDIO, "SCEAUDIO"}, {LogTypes::SCECTRL, "SCECTRL"}, @@ -111,11 +104,11 @@ static const LogNameTableEntry logTable[] = { {LogTypes::SCEMISC, "SCEMISC"}, }; -LogManager::LogManager() { +LogManager::LogManager(bool *enabledSetting) { + g_bLogEnabledSetting = enabledSetting; + for (size_t i = 0; i < ARRAY_SIZE(logTable); i++) { - if (i != logTable[i].logType) { - FLOG("Bad logtable at %i", (int)i); - } + _assert_msg_(i == logTable[i].logType, "Bad logtable at %i", (int)i); truncate_cpy(log_[logTable[i].logType].m_shortName, logTable[i].name); log_[logTable[i].logType].enabled = true; #if defined(_DEBUG) @@ -185,14 +178,14 @@ void LogManager::ChangeFileLog(const char *filename) { } } -void LogManager::SaveConfig(IniFile::Section *section) { +void LogManager::SaveConfig(Section *section) { for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) { section->Set((std::string(log_[i].m_shortName) + "Enabled").c_str(), log_[i].enabled); section->Set((std::string(log_[i].m_shortName) + "Level").c_str(), (int)log_[i].level); } } -void LogManager::LoadConfig(IniFile::Section *section, bool debugDefaults) { +void LogManager::LoadConfig(Section *section, bool debugDefaults) { for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) { bool enabled = false; int level = 0; @@ -227,7 +220,7 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const } std::lock_guard lk(log_lock_); - Common::Timer::GetTimeFormatted(message.timestamp); + GetTimeFormatted(message.timestamp); if (hleCurrentThreadName) { snprintf(message.header, sizeof(message.header), "%-12.12s %c[%s]: %s:%d", @@ -268,8 +261,8 @@ bool LogManager::IsEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type) return true; } -void LogManager::Init() { - logManager_ = new LogManager(); +void LogManager::Init(bool *enabledSetting) { + logManager_ = new LogManager(enabledSetting); } void LogManager::Shutdown() { @@ -325,3 +318,24 @@ void RingbufferLogListener::Log(const LogMessage &message) { curMessage_ -= MAX_LOGS; count_++; } + +#ifdef _WIN32 + +void OutputDebugStringUTF8(const char *p) { + wchar_t temp[4096]; + + int len = std::min(4095, (int)strlen(p)); + int size = (int)MultiByteToWideChar(CP_UTF8, 0, p, len, NULL, 0); + MultiByteToWideChar(CP_UTF8, 0, p, len, temp, size); + temp[size] = 0; + + OutputDebugString(temp); +} + +#else + +void OutputDebugStringUTF8(const char *p) { + INFO_LOG(SYSTEM, "%s", p); +} + +#endif diff --git a/Common/LogManager.h b/Common/LogManager.h index 1e8e39547d..9fcff28d80 100644 --- a/Common/LogManager.h +++ b/Common/LogManager.h @@ -19,13 +19,13 @@ #include "ppsspp_config.h" -#include +#include #include +#include -#include "file/ini_file.h" -#include "Log.h" -#include "StringUtils.h" -#include "FileUtil.h" +#include "Common/Data/Format/IniFile.h" +#include "Common/CommonFuncs.h" +#include "Common/Log.h" #define MAX_MESSAGES 8000 @@ -106,7 +106,7 @@ class ConsoleListener; class LogManager { private: - LogManager(); + LogManager(bool *enabledSetting); ~LogManager(); // Prevent copies. @@ -123,6 +123,7 @@ private: std::mutex log_lock_; std::mutex listeners_lock_; std::vector listeners_; + public: void AddListener(LogListener *listener); void RemoveListener(LogListener *listener); @@ -176,11 +177,11 @@ public: logManager_ = logManager; } - static void Init(); + static void Init(bool *enabledSetting); static void Shutdown(); void ChangeFileLog(const char *filename); - void SaveConfig(IniFile::Section *section); - void LoadConfig(IniFile::Section *section, bool debugDefaults); + void SaveConfig(Section *section); + void LoadConfig(Section *section, bool debugDefaults); }; diff --git a/Common/MachineContext.h b/Common/MachineContext.h new file mode 100644 index 0000000000..0cac3d97ce --- /dev/null +++ b/Common/MachineContext.h @@ -0,0 +1,349 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +// Note: If MACHINE_CONTEXT_SUPPORTED is not set after including this, +// there is no access to the context from exception handlers (and possibly no exception handling support). + +#pragma once + +#include "ppsspp_config.h" + +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) + +#include +typedef CONTEXT SContext; + +#if defined(__LIBRETRO__) + +#elif PPSSPP_ARCH(AMD64) + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX Rax +#define CTX_RBX Rbx +#define CTX_RCX Rcx +#define CTX_RDX Rdx +#define CTX_RDI Rdi +#define CTX_RSI Rsi +#define CTX_RBP Rbp +#define CTX_RSP Rsp +#define CTX_R8 R8 +#define CTX_R9 R9 +#define CTX_R10 R10 +#define CTX_R11 R11 +#define CTX_R12 R12 +#define CTX_R13 R13 +#define CTX_R14 R14 +#define CTX_R15 R15 +#define CTX_RIP Rip + +#elif PPSSPP_ARCH(X86) + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX Eax +#define CTX_RBX Ebx +#define CTX_RCX Ecx +#define CTX_RDX Edx +#define CTX_RDI Edi +#define CTX_RSI Esi +#define CTX_RBP Ebp +#define CTX_RSP Esp +#define CTX_RIP Eip + +#elif PPSSPP_ARCH(ARM64) + +#define CTX_REG(x) X[x] +#define CTX_SP Sp +#define CTX_PC Pc + +#elif PPSSPP_ARCH(ARM) + +//#define CTX_REG(x) R##x +#define CTX_SP Sp +#define CTX_PC Pc + +#endif + +#elif PPSSPP_PLATFORM(MAC) + +// for modules: +#define _XOPEN_SOURCE +#include + +#include +#include + +#if PPSSPP_ARCH(AMD64) + +#define MACHINE_CONTEXT_SUPPORTED + +typedef x86_thread_state64_t SContext; +#define CTX_RAX __rax +#define CTX_RBX __rbx +#define CTX_RCX __rcx +#define CTX_RDX __rdx +#define CTX_RDI __rdi +#define CTX_RSI __rsi +#define CTX_RBP __rbp +#define CTX_RSP __rsp +#define CTX_R8 __r8 +#define CTX_R9 __r9 +#define CTX_R10 __r10 +#define CTX_R11 __r11 +#define CTX_R12 __r12 +#define CTX_R13 __r13 +#define CTX_R14 __r14 +#define CTX_R15 __r15 +#define CTX_RIP __rip + +#else + +// No context definition for architecture + +#endif + +#elif defined(__linux__) + +#include + +#if PPSSPP_ARCH(AMD64) + +#include +typedef mcontext_t SContext; + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX gregs[REG_RAX] +#define CTX_RBX gregs[REG_RBX] +#define CTX_RCX gregs[REG_RCX] +#define CTX_RDX gregs[REG_RDX] +#define CTX_RDI gregs[REG_RDI] +#define CTX_RSI gregs[REG_RSI] +#define CTX_RBP gregs[REG_RBP] +#define CTX_RSP gregs[REG_RSP] +#define CTX_R8 gregs[REG_R8] +#define CTX_R9 gregs[REG_R9] +#define CTX_R10 gregs[REG_R10] +#define CTX_R11 gregs[REG_R11] +#define CTX_R12 gregs[REG_R12] +#define CTX_R13 gregs[REG_R13] +#define CTX_R14 gregs[REG_R14] +#define CTX_R15 gregs[REG_R15] +#define CTX_RIP gregs[REG_RIP] + +#elif PPSSPP_ARCH(X86) + +#include +typedef mcontext_t SContext; + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX gregs[REG_EAX] +#define CTX_RBX gregs[REG_EBX] +#define CTX_RCX gregs[REG_ECX] +#define CTX_RDX gregs[REG_EDX] +#define CTX_RDI gregs[REG_EDI] +#define CTX_RSI gregs[REG_ESI] +#define CTX_RBP gregs[REG_EBP] +#define CTX_RSP gregs[REG_ESP] +#define CTX_RIP gregs[REG_EIP] + +#elif PPSSPP_ARCH(ARM64) + +#define MACHINE_CONTEXT_SUPPORTED + +typedef sigcontext SContext; + +#define CTX_REG(x) regs[x] +#define CTX_SP sp +#define CTX_PC pc + +#elif PPSSPP_ARCH(ARM) + +#define MACHINE_CONTEXT_SUPPORTED + +typedef sigcontext SContext; +#define CTX_PC arm_pc +#define CTX_REG(x) regs[x] + +#else + +// No context definition for architecture + +#endif + +#elif defined(__OpenBSD__) + +#if PPSSPP_ARCH(AMD64) + +#include +typedef ucontext_t SContext; + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX sc_rax +#define CTX_RBX sc_rbx +#define CTX_RCX sc_rcx +#define CTX_RDX sc_rdx +#define CTX_RDI sc_rdi +#define CTX_RSI sc_rsi +#define CTX_RBP sc_rbp +#define CTX_RSP sc_rsp +#define CTX_R8 sc_r8 +#define CTX_R9 sc_r9 +#define CTX_R10 sc_r10 +#define CTX_R11 sc_r11 +#define CTX_R12 sc_r12 +#define CTX_R13 sc_r13 +#define CTX_R14 sc_r14 +#define CTX_R15 sc_r15 +#define CTX_RIP sc_rip + +#else + +// No context definition for architecture + +#endif + +#elif defined(__NetBSD__) + +#if PPSSPP_ARCH(AMD64) + +#include +typedef mcontext_t SContext; + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX __gregs[_REG_RAX] +#define CTX_RBX __gregs[_REG_RBX] +#define CTX_RCX __gregs[_REG_RCX] +#define CTX_RDX __gregs[_REG_RDX] +#define CTX_RDI __gregs[_REG_RDI] +#define CTX_RSI __gregs[_REG_RSI] +#define CTX_RBP __gregs[_REG_RBP] +#define CTX_RSP __gregs[_REG_RSP] +#define CTX_R8 __gregs[_REG_R8] +#define CTX_R9 __gregs[_REG_R9] +#define CTX_R10 __gregs[_REG_R10] +#define CTX_R11 __gregs[_REG_R11] +#define CTX_R12 __gregs[_REG_R12] +#define CTX_R13 __gregs[_REG_R13] +#define CTX_R14 __gregs[_REG_R14] +#define CTX_R15 __gregs[_REG_R15] +#define CTX_RIP __gregs[_REG_RIP] + +#else + +// No context definition for architecture + +#endif + +#elif defined(__FreeBSD__) + +#if PPSSPP_ARCH(AMD64) + +#include +typedef mcontext_t SContext; + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX mc_rax +#define CTX_RBX mc_rbx +#define CTX_RCX mc_rcx +#define CTX_RDX mc_rdx +#define CTX_RDI mc_rdi +#define CTX_RSI mc_rsi +#define CTX_RBP mc_rbp +#define CTX_RSP mc_rsp +#define CTX_R8 mc_r8 +#define CTX_R9 mc_r9 +#define CTX_R10 mc_r10 +#define CTX_R11 mc_r11 +#define CTX_R12 mc_r12 +#define CTX_R13 mc_r13 +#define CTX_R14 mc_r14 +#define CTX_R15 mc_r15 +#define CTX_RIP mc_rip + +#else + +// No context definition for architecture + +#endif + +#elif defined(__HAIKU__) + +#if PPSSPP_ARCH(AMD64) + +#include +typedef mcontext_t SContext; + +#define MACHINE_CONTEXT_SUPPORTED + +#define CTX_RAX rax +#define CTX_RBX rbx +#define CTX_RCX rcx +#define CTX_RDX rdx +#define CTX_RDI rdi +#define CTX_RSI rsi +#define CTX_RBP rbp +#define CTX_RSP rsp +#define CTX_R8 r8 +#define CTX_R9 r9 +#define CTX_R10 r10 +#define CTX_R11 r11 +#define CTX_R12 r12 +#define CTX_R13 r13 +#define CTX_R14 r14 +#define CTX_R15 r15 +#define CTX_RIP rip + +#else + +// No context definition for machine + +#endif + +#else + +// No context definition for OS + +#endif + +#ifdef MACHINE_CONTEXT_SUPPORTED + +#if PPSSPP_ARCH(AMD64) + +#include +#include +#define CTX_PC CTX_RIP +static inline uint64_t *ContextRN(SContext* ctx, int n) { + static const uint8_t offsets[] = { + offsetof(SContext, CTX_RAX), offsetof(SContext, CTX_RCX), offsetof(SContext, CTX_RDX), + offsetof(SContext, CTX_RBX), offsetof(SContext, CTX_RSP), offsetof(SContext, CTX_RBP), + offsetof(SContext, CTX_RSI), offsetof(SContext, CTX_RDI), offsetof(SContext, CTX_R8), + offsetof(SContext, CTX_R9), offsetof(SContext, CTX_R10), offsetof(SContext, CTX_R11), + offsetof(SContext, CTX_R12), offsetof(SContext, CTX_R13), offsetof(SContext, CTX_R14), + offsetof(SContext, CTX_R15)}; + return (uint64_t *)((char *)ctx + offsets[n]); +} + +#elif PPSSPP_ARCH(X86) + +#include +#include +#define CTX_PC CTX_RIP + +static inline uint32_t *ContextRN(SContext* ctx, int n) { + static const uint8_t offsets[] = { + offsetof(SContext, CTX_RAX), offsetof(SContext, CTX_RCX), offsetof(SContext, CTX_RDX), + offsetof(SContext, CTX_RBX), offsetof(SContext, CTX_RSP), offsetof(SContext, CTX_RBP), + offsetof(SContext, CTX_RSI), offsetof(SContext, CTX_RDI)}; + return (uint32_t *)((char*)ctx + offsets[n]); +} + +#endif // arch + +#endif // MACHINE_CONTEXT_SUPPORTED diff --git a/ext/native/math/curves.cpp b/Common/Math/curves.cpp similarity index 96% rename from ext/native/math/curves.cpp rename to Common/Math/curves.cpp index ae5ad95ee7..2488ba5c30 100644 --- a/ext/native/math/curves.cpp +++ b/Common/Math/curves.cpp @@ -1,9 +1,11 @@ -#include +#include -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "curves.h" +#include "Common/Common.h" + float linearInOut(int t, int fadeInLength, int solidLength, int fadeOutLength) { if (t < 0) return 0; if (t < fadeInLength) { diff --git a/ext/native/math/curves.h b/Common/Math/curves.h similarity index 95% rename from ext/native/math/curves.h rename to Common/Math/curves.h index 8799a0cf82..8a2004e012 100644 --- a/ext/native/math/curves.h +++ b/Common/Math/curves.h @@ -1,10 +1,7 @@ #pragma once -#include "base/basictypes.h" - // Easy curve computation for fades etc. - // output range: [0.0, 1.0] float linearInOut(int t, int fadeInLength, int solidLength, int fadeOutLength); float linearIn(int t, int fadeInLength); diff --git a/ext/native/math/expression_parser.cpp b/Common/Math/expression_parser.cpp similarity index 91% rename from ext/native/math/expression_parser.cpp rename to Common/Math/expression_parser.cpp index f4aa82ff56..9499cce7e0 100644 --- a/ext/native/math/expression_parser.cpp +++ b/Common/Math/expression_parser.cpp @@ -1,7 +1,8 @@ #include "expression_parser.h" #include -#include -#include +#include +#include +#include typedef enum { EXOP_BRACKETL, EXOP_BRACKETR, EXOP_MEML, EXOP_MEMR, EXOP_MEMSIZE, EXOP_SIGNPLUS, EXOP_SIGNMINUS, @@ -243,7 +244,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf isFloat = true; else if (parseNumber(subStr,16,subPos,value) == false) { - sprintf(expressionError,"Invalid number \"%s\"",subStr); + snprintf(expressionError, sizeof(expressionError), "Invalid number \"%s\"",subStr); return false; } @@ -272,14 +273,14 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf continue; } - sprintf(expressionError,"Invalid symbol \"%s\"",subStr); + snprintf(expressionError, sizeof(expressionError), "Invalid symbol \"%s\"",subStr); return false; } else { int len; ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode); if (type == EXOP_NONE) { - sprintf(expressionError,"Invalid operator at \"%s\"",&infix[infixPos]); + snprintf(expressionError, sizeof(expressionError), "Invalid operator at \"%s\"",&infix[infixPos]); return false; } @@ -294,7 +295,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf { if (opcodeStack.empty()) { - sprintf(expressionError,"Closing parenthesis without opening one"); + snprintf(expressionError, sizeof(expressionError), "Closing parenthesis without opening one"); return false; } ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; @@ -308,7 +309,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf { if (opcodeStack.empty()) { - sprintf(expressionError,"Closing bracket without opening one"); + snprintf(expressionError, sizeof(expressionError), "Closing bracket without opening one"); return false; } ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; @@ -361,7 +362,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf if (t == EXOP_BRACKETL) // opening bracket without closing one { - sprintf(expressionError,"Parenthesis not closed"); + snprintf(expressionError, sizeof(expressionError), "Parenthesis not closed"); return false; } dest.push_back(ExpressionPair(EXCOMM_OP,t)); @@ -420,7 +421,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, opcode = exp[num++].second; if (valueStack.size() < ExpressionOpcodes[opcode].args) { - sprintf(expressionError,"Not enough arguments"); + snprintf(expressionError, sizeof(expressionError), "Not enough arguments"); return false; } for (int l = 0; l < ExpressionOpcodes[opcode].args; l++) @@ -436,7 +437,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, case EXOP_MEMSIZE: // must be followed by EXOP_MEM if (exp[num++].second != EXOP_MEM) { - sprintf(expressionError,"Invalid memsize operator"); + snprintf(expressionError, sizeof(expressionError), "Invalid memsize operator"); return false; } @@ -457,11 +458,11 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, valueStack.push_back(val); } break; - case EXOP_SIGNPLUS: // keine aktion n๖tig + case EXOP_SIGNPLUS: // keine aktion nรถtig break; case EXOP_SIGNMINUS: // -0 if (useFloat) - valueStack.push_back(0.0-fArg[0]); + valueStack.push_back(0.0 - fArg[0]); else valueStack.push_back(0-arg[0]); break; @@ -480,7 +481,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, case EXOP_DIV: // a/b if (arg[0] == 0) { - sprintf(expressionError,"Division by zero"); + snprintf(expressionError, sizeof(expressionError), "Division by zero"); return false; } if (useFloat) @@ -491,7 +492,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, case EXOP_MOD: // a%b if (arg[0] == 0) { - sprintf(expressionError,"Modulo by zero"); + snprintf(expressionError, sizeof(expressionError), "Modulo by zero"); return false; } valueStack.push_back(arg[1]%arg[0]); @@ -564,7 +565,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen! if (exp[num++].second != EXOP_TERTIF) { - sprintf(expressionError,"Invalid tertiary operator"); + snprintf(expressionError, sizeof(expressionError), "Invalid tertiary operator"); return false; } valueStack.push_back(arg[2]?arg[1]:arg[0]); @@ -588,6 +589,6 @@ bool parseExpression(char* exp, IExpressionFunctions* funcs, uint32_t& dest) const char* getExpressionError() { - if (expressionError[0] == 0) strcpy(expressionError,"Invalid expression"); + if (expressionError[0] == 0) snprintf(expressionError, sizeof(expressionError), "Invalid expression"); return expressionError; } diff --git a/ext/native/math/expression_parser.h b/Common/Math/expression_parser.h similarity index 96% rename from ext/native/math/expression_parser.h rename to Common/Math/expression_parser.h index 306075c9c9..3d39340a42 100644 --- a/ext/native/math/expression_parser.h +++ b/Common/Math/expression_parser.h @@ -1,6 +1,6 @@ #pragma once -#include "../base/basictypes.h" +#include #include typedef std::pair ExpressionPair; diff --git a/ext/native/math/fast/fast_math.c b/Common/Math/fast/fast_math.c similarity index 100% rename from ext/native/math/fast/fast_math.c rename to Common/Math/fast/fast_math.c diff --git a/ext/native/math/fast/fast_math.h b/Common/Math/fast/fast_math.h similarity index 100% rename from ext/native/math/fast/fast_math.h rename to Common/Math/fast/fast_math.h diff --git a/ext/native/math/fast/fast_matrix.c b/Common/Math/fast/fast_matrix.c similarity index 100% rename from ext/native/math/fast/fast_matrix.c rename to Common/Math/fast/fast_matrix.c diff --git a/ext/native/math/fast/fast_matrix.h b/Common/Math/fast/fast_matrix.h similarity index 100% rename from ext/native/math/fast/fast_matrix.h rename to Common/Math/fast/fast_matrix.h diff --git a/ext/native/math/fast/fast_matrix_neon.S b/Common/Math/fast/fast_matrix_neon.S similarity index 100% rename from ext/native/math/fast/fast_matrix_neon.S rename to Common/Math/fast/fast_matrix_neon.S diff --git a/ext/native/math/fast/fast_matrix_sse.c b/Common/Math/fast/fast_matrix_sse.c similarity index 100% rename from ext/native/math/fast/fast_matrix_sse.c rename to Common/Math/fast/fast_matrix_sse.c diff --git a/ext/native/math/geom2d.h b/Common/Math/geom2d.h similarity index 100% rename from ext/native/math/geom2d.h rename to Common/Math/geom2d.h diff --git a/Common/Math/lin/matrix4x4.cpp b/Common/Math/lin/matrix4x4.cpp new file mode 100644 index 0000000000..e341210cee --- /dev/null +++ b/Common/Math/lin/matrix4x4.cpp @@ -0,0 +1,94 @@ +#include "Common/Math/lin/matrix4x4.h" + +#include + +#include "Common/Math/lin/vec3.h" +#include "Common/Math/fast/fast_matrix.h" + +#ifdef _WIN32 +#undef far +#undef near +#endif + +// See http://code.google.com/p/oolongengine/source/browse/trunk/Oolong+Engine2/Math/neonmath/neon_matrix_impl.cpp?spec=svn143&r=143 when we need speed +// no wait. http://code.google.com/p/math-neon/ + +namespace Lin { + +Matrix4x4 Matrix4x4::transpose() const +{ + Matrix4x4 out; + out.xx = xx;out.xy = yx;out.xz = zx;out.xw = wx; + out.yx = xy;out.yy = yy;out.yz = zy;out.yw = wy; + out.zx = xz;out.zy = yz;out.zz = zz;out.zw = wz; + out.wx = xw;out.wy = yw;out.wz = zw;out.ww = ww; + return out; +} + +Matrix4x4 Matrix4x4::operator * (const Matrix4x4 &other) const +{ + Matrix4x4 temp; + fast_matrix_mul_4x4(temp.m, other.m, this->m); + return temp; +} + +void Matrix4x4::setViewFrame(const Vec3 &pos, const Vec3 &vRight, const Vec3 &vView, const Vec3 &vUp) { + xx = vRight.x; xy = vUp.x; xz=vView.x; xw = 0.0f; + yx = vRight.y; yy = vUp.y; yz=vView.y; yw = 0.0f; + zx = vRight.z; zy = vUp.z; zz=vView.z; zw = 0.0f; + + wx = -pos * vRight; + wy = -pos * vUp; + wz = -pos * vView; + ww = 1.0f; +} + +void Matrix4x4::setOrtho(float left, float right, float bottom, float top, float near, float far) { + empty(); + xx = 2.0f / (right - left); + yy = 2.0f / (top - bottom); + zz = 2.0f / (far - near); + wx = -(right + left) / (right - left); + wy = -(top + bottom) / (top - bottom); + wz = -(far + near) / (far - near); + ww = 1.0f; +} + +void Matrix4x4::setOrthoD3D(float left, float right, float bottom, float top, float near, float far) { + empty(); + xx = 2.0f / (right - left); + yy = 2.0f / (top - bottom); + zz = 1.0f / (far - near); + wx = -(right + left) / (right - left); + wy = -(top + bottom) / (top - bottom); + wz = -near / (far - near); + ww = 1.0f; +} + +void Matrix4x4::setOrthoVulkan(float left, float right, float top, float bottom, float near, float far) { + empty(); + xx = 2.0f / (right - left); + yy = 2.0f / (bottom - top); + zz = 1.0f / (far - near); + wx = -(right + left) / (right - left); + wy = -(top + bottom) / (bottom - top); + wz = -near / (far - near); + ww = 1.0f; +} + +void Matrix4x4::toText(char *buffer, int len) const { + snprintf(buffer, len, "%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", + xx,xy,xz,xw, + yx,yy,yz,yw, + zx,zy,zz,zw, + wx,wy,wz,ww); + buffer[len - 1] = '\0'; +} + +void Matrix4x4::print() const { + char buffer[256]; + toText(buffer, 256); + puts(buffer); +} + +} diff --git a/ext/native/math/lin/matrix4x4.h b/Common/Math/lin/matrix4x4.h similarity index 66% rename from ext/native/math/lin/matrix4x4.h rename to Common/Math/lin/matrix4x4.h index a9e312de70..575b6a61d4 100644 --- a/ext/native/math/lin/matrix4x4.h +++ b/Common/Math/lin/matrix4x4.h @@ -1,7 +1,7 @@ #ifndef _MATH_LIN_MATRIX4X4_H #define _MATH_LIN_MATRIX4X4_H -#include "math/lin/vec3.h" +#include "Common/Math/lin/vec3.h" namespace Lin { @@ -24,19 +24,6 @@ public: const Vec3 front() const {return Vec3(zx, zy, zz);} const Vec3 move() const {return Vec3(wx, wy, wz);} - void setRight(const Vec3 &v) { - xx = v.x; xy = v.y; xz = v.z; - } - void setUp(const Vec3 &v) { - yx = v.x; yy = v.y; yz = v.z; - } - void setFront(const Vec3 &v) { - zx = v.x; zy = v.y; zz = v.z; - } - void setMove(const Vec3 &v) { - wx = v.x; wy = v.y; wz = v.z; - } - const float &operator[](int i) const { return *(((const float *)this) + i); } @@ -53,17 +40,14 @@ public: void empty() { memset(this, 0, 16 * sizeof(float)); } - void setScaling(const float f) { - empty(); - xx=yy=zz=f; ww=1.0f; - } static Matrix4x4 identity() { Matrix4x4 id; id.setIdentity(); return id; } void setIdentity() { - setScaling(1.0f); + empty(); + xx = yy = zz = ww = 1.0f; } void setTranslation(const Vec3 &trans) { setIdentity(); @@ -72,37 +56,8 @@ public: wz = trans.z; } - Matrix4x4 inverse() const; - Matrix4x4 simpleInverse() const; Matrix4x4 transpose() const; - void setRotationX(const float a) { - empty(); - float c = cosf(a); - float s = sinf(a); - xx = 1.0f; - yy = c; yz = s; - zy = -s; zz = c; - ww = 1.0f; - } - void setRotationY(const float a) { - empty(); - float c = cosf(a); - float s = sinf(a); - xx = c; xz = -s; - yy = 1.0f; - zx = s; zz = c; - ww = 1.0f; - } - void setRotationZ(const float a) { - empty(); - float c = cosf(a); - float s = sinf(a); - xx = c; xy = s; - yx = -s; yy = c; - zz = 1.0f; - ww = 1.0f; - } // Exact angles to avoid any artifacts. void setRotationZ90() { empty(); @@ -132,15 +87,10 @@ public: ww = 1.0f; } - void setRotation(float x,float y, float z); - void setProjection(float near_plane, float far_plane, float fov_horiz, float aspect = 0.75f); - void setProjectionD3D(float near_plane, float far_plane, float fov_horiz, float aspect = 0.75f); void setOrtho(float left, float right, float bottom, float top, float near, float far); void setOrthoD3D(float left, float right, float bottom, float top, float near, float far); void setOrthoVulkan(float left, float right, float top, float bottom, float near, float far); - void setViewLookAt(const Vec3 &from, const Vec3 &at, const Vec3 &worldup); - void setViewLookAtD3D(const Vec3 &from, const Vec3 &at, const Vec3 &worldup); void setViewFrame(const Vec3 &pos, const Vec3 &right, const Vec3 &forward, const Vec3 &up); void toText(char *buffer, int len) const; void print() const; diff --git a/ext/native/math/lin/matrix_neon.s b/Common/Math/lin/matrix_neon.s similarity index 100% rename from ext/native/math/lin/matrix_neon.s rename to Common/Math/lin/matrix_neon.s diff --git a/Common/Math/lin/vec3.cpp b/Common/Math/lin/vec3.cpp new file mode 100644 index 0000000000..8329e2191e --- /dev/null +++ b/Common/Math/lin/vec3.cpp @@ -0,0 +1,20 @@ +#include + +#include "Common/Math/lin/vec3.h" +#include "Common/Math/lin/matrix4x4.h" + +namespace Lin { + +Vec3 Vec3::operator *(const Matrix4x4 &m) const { + return Vec3(x*m.xx + y*m.yx + z*m.zx + m.wx, + x*m.xy + y*m.yy + z*m.zy + m.wy, + x*m.xz + y*m.yz + z*m.zz + m.wz); +} + +Vec3 Vec3::rotatedBy(const Matrix4x4 &m) const { + return Vec3(x*m.xx + y*m.yx + z*m.zx, + x*m.xy + y*m.yy + z*m.zy, + x*m.xz + y*m.yz + z*m.zz); +} + +} // namespace Lin diff --git a/ext/native/math/lin/vec3.h b/Common/Math/lin/vec3.h similarity index 95% rename from ext/native/math/lin/vec3.h rename to Common/Math/lin/vec3.h index 10096153d7..988a2d08b5 100644 --- a/ext/native/math/lin/vec3.h +++ b/Common/Math/lin/vec3.h @@ -14,7 +14,6 @@ public: float x,y,z,w; Vec4(){} Vec4(float a, float b, float c, float d) {x=a;y=b;z=c;w=d;} - Vec4 multiply4D(Matrix4x4 &m) const; }; class Vec3 { @@ -80,7 +79,6 @@ public: void operator *=(const Matrix4x4 &m) { *this = *this * m; } - Vec4 multiply4D(const Matrix4x4 &m) const; Vec3 rotatedBy(const Matrix4x4 &m) const; Vec3 operator %(const Vec3 &v) const { return Vec3(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); @@ -134,10 +132,6 @@ inline Vec3 cross(const Vec3 &a, const Vec3 &b) { return a % b; } -inline float sqr(const Vec3 &v) { - return dot(v, v); -} - class AABBox { public: Vec3 min; diff --git a/ext/native/math/math_util.cpp b/Common/Math/math_util.cpp similarity index 96% rename from ext/native/math/math_util.cpp rename to Common/Math/math_util.cpp index 11eb15b215..9b1a59a755 100644 --- a/ext/native/math/math_util.cpp +++ b/Common/Math/math_util.cpp @@ -1,4 +1,4 @@ -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include // QNX can only use RunFast mode and it is already the default. diff --git a/ext/native/math/math_util.h b/Common/Math/math_util.h similarity index 77% rename from ext/native/math/math_util.h rename to Common/Math/math_util.h index 4d30d080c6..0807d47003 100644 --- a/ext/native/math/math_util.h +++ b/Common/Math/math_util.h @@ -5,11 +5,7 @@ #include #include - -#include "base/basictypes.h" - -inline float sqr(float f) {return f*f;} -inline float sqr_signed(float f) {return f<0 ? -f*f : f*f;} +#include typedef unsigned short float16; @@ -56,33 +52,6 @@ inline uint32_t log2i(uint32_t val) { #define M_PI 3.141592653589793f #endif -// Calculate pseudo-random 32 bit number based on linear congruential method. -void SetSeed(unsigned int seed); -unsigned int GenerateRandomNumber(); -inline float GenerateRandomFloat01() { - return (float)((double)GenerateRandomNumber() / 0xFFFFFFFF); -} -inline float GenerateRandomSignedFloat() { - return (float)((double)GenerateRandomNumber() / 0x80000000) - 1.0f; -} - - -inline float GaussRand() -{ - float R1 = GenerateRandomFloat01(); - float R2 = GenerateRandomFloat01(); - - float X = sqrtf(-2.0f * logf(R1)) * cosf(2.0f * PI * R2); - if (X > 4.0f) X = 4.0f; - if (X < -4.0f) X = -4.0f; - return X; -} - -// Accuracy unknown -inline double atan_fast(double x) { - return (x / (1.0 + 0.28 * (x * x))); -} - template inline T clamp_value(T val, T floor, T cap) { if (val > cap) @@ -93,16 +62,24 @@ inline T clamp_value(T val, T floor, T cap) { return val; } -// linear -> dB conversion -inline float lin2dB(float lin) { - const float LOG_2_DB = 8.6858896380650365530225783783321f; // 20 / ln( 10 ) - return logf(lin) * LOG_2_DB; +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) + +template +inline void Clamp(T* val, const T& min, const T& max) +{ + if (*val < min) + *val = min; + else if (*val > max) + *val = max; } -// dB -> linear conversion -inline float dB2lin(float dB) { - const float DB_2_LOG = 0.11512925464970228420089957273422f; // ln( 10 ) / 20 - return expf(dB * DB_2_LOG); +template +inline T Clamp(const T val, const T& min, const T& max) +{ + T ret = val; + Clamp(&ret, min, max); + return ret; } union FP32 { @@ -143,7 +120,7 @@ inline int is_even(float d) { // Rounds *.5 to closest even number inline double round_ieee_754(double d) { - float i = floor(d); + float i = (float)floor(d); d -= i; if (d < 0.5f) return i; diff --git a/Common/MathUtil.h b/Common/MathUtil.h deleted file mode 100644 index d56d5c19e5..0000000000 --- a/Common/MathUtil.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -namespace MathUtil -{ - -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) - -template -inline void Clamp(T* val, const T& min, const T& max) -{ - if (*val < min) - *val = min; - else if (*val > max) - *val = max; -} - -template -inline T Clamp(const T val, const T& min, const T& max) -{ - T ret = val; - Clamp(&ret, min, max); - return ret; -} - -} \ No newline at end of file diff --git a/Common/MemArenaAndroid.cpp b/Common/MemArenaAndroid.cpp index a0b8614f19..c304f86435 100644 --- a/Common/MemArenaAndroid.cpp +++ b/Common/MemArenaAndroid.cpp @@ -19,12 +19,6 @@ #ifdef __ANDROID__ -#include "base/logging.h" -#include "base/NativeApp.h" -#include "MemoryUtil.h" -#include "MemArena.h" -#include "StringUtils.h" - #include #include #include @@ -33,6 +27,12 @@ #include #include +#include "Common/Log.h" +#include "Common/MemoryUtil.h" +#include "Common/MemArena.h" +#include "Common/StringUtils.h" +#include "Common/System/System.h" + // Hopefully this ABI will never change... #define ASHMEM_DEVICE "/dev/ashmem" @@ -140,15 +140,15 @@ u8* MemArena::Find4GBBase() { // address by grabbing 8GB and aligning the pointer. const uint64_t EIGHT_GIGS = 0x200000000ULL; void *base = mmap(0, EIGHT_GIGS, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); - if (base) { - ILOG("base: %p", base); + if (base && base != MAP_FAILED) { + INFO_LOG(SYSTEM, "base: %p", base); uint64_t aligned_base = ((uint64_t)base + 0xFFFFFFFF) & ~0xFFFFFFFFULL; - ILOG("aligned_base: %p", (void *)aligned_base); + INFO_LOG(SYSTEM, "aligned_base: %p", (void *)aligned_base); munmap(base, EIGHT_GIGS); return reinterpret_cast(aligned_base); } else { u8 *hardcoded_ptr = reinterpret_cast(0x2300000000ULL); - ILOG("Failed to anonymously map 8GB. Fall back to the hardcoded pointer %p.", hardcoded_ptr); + INFO_LOG(SYSTEM, "Failed to anonymously map 8GB. Fall back to the hardcoded pointer %p.", hardcoded_ptr); // Just grab some random 4GB... // This has been known to fail lately though, see issue #12249. return hardcoded_ptr; @@ -156,10 +156,7 @@ u8* MemArena::Find4GBBase() { #else // Address masking is used in 32-bit mode, so we can get away with less memory. void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); - if (base == MAP_FAILED) { - PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno)); - return 0; - } + _assert_msg_(base != MAP_FAILED, "Failed to map 256 MB of memory space: %s", strerror(errno)); munmap(base, 0x10000000); return static_cast(base); #endif diff --git a/Common/MemArenaDarwin.cpp b/Common/MemArenaDarwin.cpp index 593bb1495e..d35fb7f84d 100644 --- a/Common/MemArenaDarwin.cpp +++ b/Common/MemArenaDarwin.cpp @@ -20,12 +20,7 @@ #if defined(__APPLE__) #include -#include - -#include "FileUtil.h" -#include "MemoryUtil.h" -#include "MemArena.h" - +#include #include #include #include @@ -35,6 +30,11 @@ #include #include +#include "Common/Log.h" +#include "Common/File/FileUtil.h" +#include "Common/MemoryUtil.h" +#include "Common/MemArena.h" + size_t MemArena::roundup(size_t x) { return x; } diff --git a/Common/MemArenaPosix.cpp b/Common/MemArenaPosix.cpp index 5ee371ed17..65a812001b 100644 --- a/Common/MemArenaPosix.cpp +++ b/Common/MemArenaPosix.cpp @@ -19,17 +19,17 @@ #if !defined(_WIN32) && !defined(ANDROID) && !defined(__APPLE__) -#include - -#include "FileUtil.h" -#include "MemoryUtil.h" -#include "MemArena.h" - #include #include #include #include #include +#include + +#include "Common/Log.h" +#include "Common/File/FileUtil.h" +#include "Common/MemoryUtil.h" +#include "Common/MemArena.h" static const std::string tmpfs_location = "/dev/shm"; static const std::string tmpfs_ram_temp_file = "/dev/shm/gc_mem.tmp"; @@ -108,8 +108,8 @@ u8* MemArena::Find4GBBase() { // aligned to 4GB for the movk trick. We can ensure that we get an aligned 4GB // address by grabbing 8GB and aligning the pointer. const uint64_t EIGHT_GIGS = 0x200000000ULL; - void *base = mmap(0, EIGHT_GIGS, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); - if (base) { + void *base = mmap(0, EIGHT_GIGS, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED | MAP_NORESERVE, -1, 0); + if (base && base != MAP_FAILED) { INFO_LOG(MEMMAP, "base: %p", base); uint64_t aligned_base = ((uint64_t)base + 0xFFFFFFFF) & ~0xFFFFFFFFULL; INFO_LOG(MEMMAP, "aligned_base: %p", (void *)aligned_base); @@ -124,12 +124,8 @@ u8* MemArena::Find4GBBase() { } #else size_t size = 0x10000000; - void* base = mmap(0, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - if (base == MAP_FAILED) { - PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno)); - return 0; - } + void* base = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED | MAP_NORESERVE, -1, 0); + _assert_msg_(base != MAP_FAILED, "Failed to map 256 MB of memory space: %s", strerror(errno)); munmap(base, size); return static_cast(base); #endif diff --git a/Common/MemoryUtil.cpp b/Common/MemoryUtil.cpp index 519bfc6bd5..a6f5d5e919 100644 --- a/Common/MemoryUtil.cpp +++ b/Common/MemoryUtil.cpp @@ -17,14 +17,16 @@ #include "ppsspp_config.h" -#include "base/logging.h" +#include -#include "Common.h" -#include "MemoryUtil.h" -#include "StringUtils.h" +#include "Common/Common.h" +#include "Common/Log.h" +#include "Common/MemoryUtil.h" +#include "Common/StringUtils.h" +#include "Common/SysError.h" #ifdef _WIN32 -#include "CommonWindows.h" +#include "Common/CommonWindows.h" #else #include #include @@ -53,7 +55,7 @@ static SYSTEM_INFO sys_info; #define ppsspp_round_page(x) ((((uintptr_t)(x)) + MEM_PAGE_MASK) & ~(MEM_PAGE_MASK)) #ifdef _WIN32 -// Win32 flags are odd... +// Win32 memory protection flags are odd... static uint32_t ConvertProtFlagsWin32(uint32_t flags) { uint32_t protect = 0; switch (flags) { @@ -185,7 +187,6 @@ void *AllocateExecutableMemory(size_t size) { if (ptr == failed_result) { ptr = nullptr; ERROR_LOG(MEMMAP, "Failed to allocate executable memory (%d) errno=%d", (int)size, errno); - PanicAlert("Failed to allocate executable memory\n%s", GetLastErrorMsg()); } #if defined(_M_X64) && !defined(_WIN32) @@ -214,13 +215,15 @@ void *AllocateMemoryPages(size_t size, uint32_t memProtFlags) { #else void* ptr = VirtualAlloc(0, size, MEM_COMMIT, protect); #endif - if (!ptr) - PanicAlert("Failed to allocate raw memory"); + if (!ptr) { + ERROR_LOG(MEMMAP, "Failed to allocate raw memory pages"); + return nullptr; + } #else uint32_t protect = ConvertProtFlagsUnix(memProtFlags); void *ptr = mmap(0, size, protect, MAP_ANON | MAP_PRIVATE, -1, 0); if (ptr == MAP_FAILED) { - ERROR_LOG(MEMMAP, "Failed to allocate memory pages: errno=%d", errno); + ERROR_LOG(MEMMAP, "Failed to allocate raw memory pages: errno=%d", errno); return nullptr; } #endif @@ -232,23 +235,19 @@ void *AllocateMemoryPages(size_t size, uint32_t memProtFlags) { void *AllocateAlignedMemory(size_t size, size_t alignment) { #ifdef _WIN32 - void* ptr = _aligned_malloc(size,alignment); + void* ptr = _aligned_malloc(size,alignment); #else void* ptr = NULL; #ifdef __ANDROID__ ptr = memalign(alignment, size); #else - if (posix_memalign(&ptr, alignment, size) != 0) - ptr = NULL; + if (posix_memalign(&ptr, alignment, size) != 0) { + ptr = nullptr; + } #endif #endif - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == NULL) - PanicAlert("Failed to allocate aligned memory"); - + _assert_msg_(ptr != nullptr, "Failed to allocate aligned memory"); return ptr; } @@ -258,8 +257,9 @@ void FreeMemoryPages(void *ptr, size_t size) { uintptr_t page_size = GetMemoryProtectPageSize(); size = (size + page_size - 1) & (~(page_size - 1)); #ifdef _WIN32 - if (!VirtualFree(ptr, 0, MEM_RELEASE)) - PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); + if (!VirtualFree(ptr, 0, MEM_RELEASE)) { + ERROR_LOG(MEMMAP, "FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); + } #else munmap(ptr, size); #endif @@ -292,8 +292,7 @@ bool ProtectMemoryPages(const void* ptr, size_t size, uint32_t memProtFlags) { if (PlatformIsWXExclusive()) { if ((memProtFlags & (MEM_PROT_WRITE | MEM_PROT_EXEC)) == (MEM_PROT_WRITE | MEM_PROT_EXEC)) { - ERROR_LOG(MEMMAP, "Bad memory protection %d!", memProtFlags); - PanicAlert("Bad memory protect : W^X is in effect, can't both write and exec"); + _assert_msg_(false, "Bad memory protect flags %d: W^X is in effect, can't both write and exec", memProtFlags); } } // Note - VirtualProtect will affect the full pages containing the requested range. @@ -304,13 +303,13 @@ bool ProtectMemoryPages(const void* ptr, size_t size, uint32_t memProtFlags) { #if PPSSPP_PLATFORM(UWP) DWORD oldValue; if (!VirtualProtectFromApp((void *)ptr, size, protect, &oldValue)) { - PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg()); + ERROR_LOG(MEMMAP, "WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); return false; } #else DWORD oldValue; if (!VirtualProtect((void *)ptr, size, protect, &oldValue)) { - PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg()); + ERROR_LOG(MEMMAP, "WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); return false; } #endif diff --git a/Common/MipsEmitter.cpp b/Common/MipsEmitter.cpp index bd26315ba0..5d6288be3e 100644 --- a/Common/MipsEmitter.cpp +++ b/Common/MipsEmitter.cpp @@ -15,18 +15,16 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" - -#include #include #include #include #include #include -#include "MemoryUtil.h" -#include "MipsEmitter.h" -#include "CPUDetect.h" +#include "Common/Log.h" +#include "Common/MemoryUtil.h" +#include "Common/MipsEmitter.h" +#include "Common/CPUDetect.h" namespace MIPSGen { void MIPSEmitter::SetCodePtr(u8 *ptr) { @@ -76,7 +74,7 @@ void MIPSEmitter::FlushIcacheSection(u8 *start, u8 *end) { void MIPSEmitter::BREAK(u32 code) { // 000000 iiiiiiiiiiiiiiiiiiii 001101 - _dbg_assert_msg_(JIT, code <= 0xfffff, "Bad emitter arguments"); + _dbg_assert_msg_(code <= 0xfffff, "Bad emitter arguments"); Write32Fields(26, 0x00, 6, code & 0xfffff, 0, 0x0d); } @@ -106,21 +104,21 @@ void MIPSEmitter::JAL(const void *func, std::function delaySlot) { void MIPSEmitter::JR(MIPSReg rs, std::function delaySlot) { // 000000 sssss xxxxxxxxxx hint- 001000 (hint must be 0.) - _dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 0, 0x08); ApplyDelaySlot(delaySlot); } void MIPSEmitter::JALR(MIPSReg rd, MIPSReg rs, std::function delaySlot) { // 000000 sssss xxxxx ddddd hint- 001001 (hint must be 0.) - _dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 11, rd, 0, 0x09); ApplyDelaySlot(delaySlot); } FixupBranch MIPSEmitter::BLTZ(MIPSReg rs, std::function delaySlot) { // 000001 sssss xxxxx iiiiiiiiiiiiiii (fix up) - _dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments"); FixupBranch b = MakeFixupBranch(BRANCH_16); Write32Fields(26, 0x01, 21, rs); ApplyDelaySlot(delaySlot); @@ -133,7 +131,7 @@ void MIPSEmitter::BLTZ(MIPSReg rs, const void *func, std::function dela FixupBranch MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt, std::function delaySlot) { // 000100 sssss ttttt iiiiiiiiiiiiiii (fix up) - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); FixupBranch b = MakeFixupBranch(BRANCH_16); Write32Fields(26, 0x04, 21, rs, 16, rt); ApplyDelaySlot(delaySlot); @@ -146,7 +144,7 @@ void MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt, const void *func, std::function delaySlot) { // 000101 sssss ttttt iiiiiiiiiiiiiii (fix up) - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); FixupBranch b = MakeFixupBranch(BRANCH_16); Write32Fields(26, 0x05, 21, rs, 16, rt); ApplyDelaySlot(delaySlot); @@ -159,7 +157,7 @@ void MIPSEmitter::BNE(MIPSReg rs, MIPSReg rt, const void *func, std::function delaySlot) { // 000110 sssss xxxxx iiiiiiiiiiiiiii (fix up) - _dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments"); FixupBranch b = MakeFixupBranch(BRANCH_16); Write32Fields(26, 0x06, 21, rs); ApplyDelaySlot(delaySlot); @@ -172,7 +170,7 @@ void MIPSEmitter::BLEZ(MIPSReg rs, const void *func, std::function dela FixupBranch MIPSEmitter::BGTZ(MIPSReg rs, std::function delaySlot) { // 000111 sssss xxxxx iiiiiiiiiiiiiii (fix up) - _dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE, "Bad emitter arguments"); FixupBranch b = MakeFixupBranch(BRANCH_16); Write32Fields(26, 0x07, 21, rs); ApplyDelaySlot(delaySlot); @@ -200,16 +198,16 @@ void MIPSEmitter::SetJumpTarget(const FixupBranch &branch, const void *dst) { const intptr_t dstp = (intptr_t)dst; u32 *fixup = (u32 *)branch.ptr; - _dbg_assert_msg_(JIT, (dstp & 3) == 0, "Destination should be aligned"); + _dbg_assert_msg_((dstp & 3) == 0, "Destination should be aligned"); if (branch.type == BRANCH_16) { // The distance is encoded as words from the delay slot. ptrdiff_t distance = (dstp - srcp - 4) >> 2; - _dbg_assert_msg_(JIT, BInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst); + _dbg_assert_msg_(BInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst); *fixup = (*fixup & 0xffff0000) | (distance & 0x0000ffff); } else { // Absolute, easy. - _dbg_assert_msg_(JIT, JInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst); + _dbg_assert_msg_(JInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst); *fixup = (*fixup & 0xfc000000) | ((dstp >> 2) & 0x03ffffff); } } @@ -240,7 +238,7 @@ void MIPSEmitter::ApplyDelaySlot(std::function delaySlot) { } void MIPSEmitter::QuickCallFunction(MIPSReg scratchreg, const void *func) { - _dbg_assert_msg_(JIT, scratchreg < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(scratchreg < F_BASE, "Bad emitter arguments"); if (JInRange(func)) { JAL(func); } else { @@ -259,176 +257,176 @@ FixupBranch MIPSEmitter::MakeFixupBranch(FixupBranchType type) { void MIPSEmitter::LB(MIPSReg value, MIPSReg base, s16 offset) { // 100000 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value - _dbg_assert_msg_(JIT, value < F_BASE && base < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x20, 21, base, 16, value, 0, (u16)offset); } void MIPSEmitter::LH(MIPSReg value, MIPSReg base, s16 offset) { // 100001 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value - _dbg_assert_msg_(JIT, value < F_BASE && base < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x21, 21, base, 16, value, 0, (u16)offset); } void MIPSEmitter::LW(MIPSReg value, MIPSReg base, s16 offset) { // 100011 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value - _dbg_assert_msg_(JIT, value < F_BASE && base < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x23, 21, base, 16, value, 0, (u16)offset); } void MIPSEmitter::SB(MIPSReg value, MIPSReg base, s16 offset) { // 101000 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value - _dbg_assert_msg_(JIT, value < F_BASE && base < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x28, 21, base, 16, value, 0, (u16)offset); } void MIPSEmitter::SH(MIPSReg value, MIPSReg base, s16 offset) { // 101001 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value - _dbg_assert_msg_(JIT, value < F_BASE && base < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x29, 21, base, 16, value, 0, (u16)offset); } void MIPSEmitter::SW(MIPSReg value, MIPSReg base, s16 offset) { // 101011 sssss ttttt iiiiiiiiiiiiiiii - rs = base, rt = value - _dbg_assert_msg_(JIT, value < F_BASE && base < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(value < F_BASE && base < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x2b, 21, base, 16, value, 0, (u16)offset); } void MIPSEmitter::SLL(MIPSReg rd, MIPSReg rt, u8 sa) { // 000000 xxxxx ttttt ddddd aaaaa 000000 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments"); Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x00); } void MIPSEmitter::SRL(MIPSReg rd, MIPSReg rt, u8 sa) { // 000000 xxxxx ttttt ddddd aaaaa 000010 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments"); Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x02); } void MIPSEmitter::SRA(MIPSReg rd, MIPSReg rt, u8 sa) { // 000000 xxxxx ttttt ddddd aaaaa 000011 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x1f, "Bad emitter arguments"); Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x03); } void MIPSEmitter::SLLV(MIPSReg rd, MIPSReg rt, MIPSReg rs) { // 000000 sssss ttttt ddddd xxxxx 000100 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x04); } void MIPSEmitter::SRLV(MIPSReg rd, MIPSReg rt, MIPSReg rs) { // 000000 sssss ttttt ddddd xxxxx 000110 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x06); } void MIPSEmitter::SRAV(MIPSReg rd, MIPSReg rt, MIPSReg rs) { // 000000 sssss ttttt ddddd xxxxx 000111 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x07); } void MIPSEmitter::SLT(MIPSReg rd, MIPSReg rs, MIPSReg rt) { // 000000 sssss ttttt ddddd xxxxx 101010 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x2a); } void MIPSEmitter::SLTU(MIPSReg rd, MIPSReg rs, MIPSReg rt) { // 000000 sssss ttttt ddddd xxxxx 101011 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x2b); } void MIPSEmitter::SLTI(MIPSReg rt, MIPSReg rs, s16 imm) { // 001010 sssss ttttt iiiiiiiiiiiiiiii - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x0a, 21, rs, 16, rt, 0, (u16)imm); } void MIPSEmitter::SLTIU(MIPSReg rt, MIPSReg rs, s16 imm) { // 001011 sssss ttttt iiiiiiiiiiiiiiii - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x0b, 21, rs, 16, rt, 0, (u16)imm); } void MIPSEmitter::ADDU(MIPSReg rd, MIPSReg rs, MIPSReg rt) { // 000000 sssss ttttt ddddd 00000100001 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x21); } void MIPSEmitter::SUBU(MIPSReg rd, MIPSReg rs, MIPSReg rt) { // 000000 sssss ttttt ddddd 00000100011 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x23); } void MIPSEmitter::ADDIU(MIPSReg rt, MIPSReg rs, s16 imm) { // 001001 sssss ttttt iiiiiiiiiiiiiiii - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x09, 21, rs, 16, rt, 0, (u16)imm); } void MIPSEmitter::AND(MIPSReg rd, MIPSReg rs, MIPSReg rt) { // 000000 sssss ttttt ddddd 00000100100 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x24); } void MIPSEmitter::OR(MIPSReg rd, MIPSReg rs, MIPSReg rt) { // 000000 sssss ttttt ddddd 00000100101 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x25); } void MIPSEmitter::XOR(MIPSReg rd, MIPSReg rs, MIPSReg rt) { // 000000 sssss ttttt ddddd 00000100110 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && rs < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x00, 21, rs, 16, rt, 11, rd, 0, 0x26); } void MIPSEmitter::ANDI(MIPSReg rt, MIPSReg rs, s16 imm) { // 001100 sssss ttttt iiiiiiiiiiiiiiii - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x0c, 21, rs, 16, rt, 0, (u16)imm); } void MIPSEmitter::ORI(MIPSReg rt, MIPSReg rs, s16 imm) { // 001101 sssss ttttt iiiiiiiiiiiiiiii - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x0d, 21, rs, 16, rt, 0, (u16)imm); } void MIPSEmitter::XORI(MIPSReg rt, MIPSReg rs, s16 imm) { // 001110 sssss ttttt iiiiiiiiiiiiiiii - _dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rs < F_BASE && rt < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x0e, 21, rs, 16, rt, 0, (u16)imm); } void MIPSEmitter::LUI(MIPSReg rt, s16 imm) { // 001111 00000 ttttt iiiiiiiiiiiiiiii - _dbg_assert_msg_(JIT, rt < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(rt < F_BASE, "Bad emitter arguments"); Write32Fields(26, 0x0f, 16, rt, 0, (u16)imm); } void MIPSEmitter::INS(MIPSReg rt, MIPSReg rs, s8 pos, s8 size) { // 011111 sssss ttttt xxxxx yyyyy 000100 - _dbg_assert_msg_(JIT, rt < F_BASE && rs < F_BASE && pos <= 0x1f && (size+pos+1) <= 0x1f, "Bad emitter arguments"); + _dbg_assert_msg_(rt < F_BASE && rs < F_BASE && pos <= 0x1f && (size+pos+1) <= 0x1f, "Bad emitter arguments"); Write32Fields(26, 0x1f, 21, rt, 16, rs, 11, (size+pos+1) & 0x1f, 6, pos & 0x1f, 0, 0x04); } void MIPSEmitter::EXT(MIPSReg rt, MIPSReg rs, s8 pos, s8 size) { // 111111 sssss ttttt xxxxx yyyyy 000000 - _dbg_assert_msg_(JIT, rt < F_BASE && rs < F_BASE && pos <= 0x1f && size >= 1, "Bad emitter arguments"); + _dbg_assert_msg_(rt < F_BASE && rs < F_BASE && pos <= 0x1f && size >= 1, "Bad emitter arguments"); Write32Fields(26, 0x3f, 21, rt, 16, rs, 11, (size-1) & 0x1f, 6, pos & 0x1f, 0, 0x00); } void MIPSEmitter::DSLL(MIPSReg rd, MIPSReg rt, u8 sa) { // 000000 xxxxx ttttt ddddd aaaaa 111000 DSLL // 000000 xxxxx ttttt ddddd aaaaa 111100 DSLL32 - _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && sa <= 0x3f, "Bad emitter arguments"); + _dbg_assert_msg_(rd < F_BASE && rt < F_BASE && sa <= 0x3f, "Bad emitter arguments"); // TODO: Assert MIPS64. if (sa >= 32) { Write32Fields(26, 0x00, 16, rt, 11, rd, 6, (sa - 32) & 0x1f, 0, 0x3c); @@ -438,7 +436,7 @@ void MIPSEmitter::DSLL(MIPSReg rd, MIPSReg rt, u8 sa) { } void MIPSEmitter::MOVI2R(MIPSReg reg, u64 imm) { - _dbg_assert_msg_(JIT, reg < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(reg < F_BASE, "Bad emitter arguments"); // TODO: Assert MIPS64. // Probably better to use a literal pool and load. @@ -451,7 +449,7 @@ void MIPSEmitter::MOVI2R(MIPSReg reg, u64 imm) { } void MIPSEmitter::MOVI2R(MIPSReg reg, u32 imm) { - _dbg_assert_msg_(JIT, reg < F_BASE, "Bad emitter arguments"); + _dbg_assert_msg_(reg < F_BASE, "Bad emitter arguments"); if ((imm & 0xffff0000) != 0) { #if 0 diff --git a/Common/MipsEmitter.h b/Common/MipsEmitter.h index 582e1eb4b4..19913ec2e2 100644 --- a/Common/MipsEmitter.h +++ b/Common/MipsEmitter.h @@ -22,7 +22,6 @@ #include #include "Common.h" -#include "MsgHandler.h" namespace MIPSGen { diff --git a/Common/MsgHandler.cpp b/Common/MsgHandler.cpp deleted file mode 100644 index b53d79d41a..0000000000 --- a/Common/MsgHandler.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -#include "ppsspp_config.h" - -#include "Common.h" -#include "StringUtils.h" -#include "base/logging.h" -#include "util/text/utf8.h" - -bool MsgHandler(const char *caption, const char *text, bool yes_no, int Style); - -bool MsgAlert(bool yes_no, int Style, const char* format, ...) { - // Read message and write it to the log - char buffer[2048]; - static const char *captions[] = { - "Information", - "Question", - "Warning", - "Critical" - }; - - const char *caption = captions[Style]; - va_list args; - va_start(args, format); - CharArrayFromFormatV(buffer, sizeof(buffer)-1, format, args); - va_end(args); - // Normal logging (will also log to Android log) - ERROR_LOG(SYSTEM, "%s: %s", caption, buffer); - // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored - if (Style == QUESTION || Style == CRITICAL) - return MsgHandler(caption, buffer, yes_no, Style); - return true; -} - -#ifdef _WIN32 -#include "CommonWindows.h" -#endif - -// Default non library dependent panic alert -bool MsgHandler(const char* caption, const char* text, bool yes_no, int Style) { -#if defined(USING_WIN_UI) - int msgBoxStyle = MB_ICONINFORMATION; - if (Style == QUESTION) msgBoxStyle = MB_ICONQUESTION; - if (Style == WARNING) msgBoxStyle = MB_ICONWARNING; - - std::wstring wtext = ConvertUTF8ToWString(text) + L"\n\nTry to continue?"; - std::wstring wcaption = ConvertUTF8ToWString(caption); - OutputDebugString(wtext.c_str()); - return IDYES == MessageBox(0, wtext.c_str(), wcaption.c_str(), msgBoxStyle | (yes_no ? MB_YESNO : MB_OK)); -#elif PPSSPP_PLATFORM(UWP) - OutputDebugStringUTF8(text); - return false; -#else - // Will use android-log if available, printf if not. - ELOG("%s", text); - return false; -#endif -} diff --git a/Common/MsgHandler.h b/Common/MsgHandler.h index ee28d8ea33..5f16e105d3 100644 --- a/Common/MsgHandler.h +++ b/Common/MsgHandler.h @@ -17,21 +17,17 @@ #pragma once -// Message alerts -enum MSG_TYPE { - INFORMATION, - QUESTION, - WARNING, - CRITICAL -}; - -bool MsgAlert(bool yes_no, int Style, const char* format, ...) +// Currently only actually shows a dialog box on Windows. +bool ShowAssertDialog(const char *function, const char *file, int line, const char *expression, const char* format, ...) #ifdef __GNUC__ - __attribute__((format(printf, 3, 4))) + __attribute__((format(printf, 5, 6))) #endif ; -#define PanicAlert(...) MsgAlert(false, WARNING, __VA_ARGS__) +#if defined(__ANDROID__) -// Used only for asserts. -#define PanicYesNo(...) MsgAlert(true, CRITICAL, __VA_ARGS__) +// Tricky macro to get the basename, that also works if *built* on Win32. +#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : (__builtin_strrchr(__FILE__, '\\') ? __builtin_strrchr(__FILE__, '\\') + 1 : __FILE__)) +void AndroidAssert(const char *func, const char *file, int line, const char *condition, const char *fmt, ...); + +#endif diff --git a/ext/native/net/http_client.cpp b/Common/Net/HTTPClient.cpp similarity index 83% rename from ext/native/net/http_client.cpp rename to Common/Net/HTTPClient.cpp index 91fec283a8..41cf350625 100644 --- a/ext/native/net/http_client.cpp +++ b/Common/Net/HTTPClient.cpp @@ -1,5 +1,7 @@ -#include "net/http_client.h" -#include "base/timeutil.h" +#include "Common/Net/HTTPClient.h" + +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" #ifndef _WIN32 #include @@ -15,17 +17,17 @@ #endif #include -#include -#include +#include +#include -#include "base/logging.h" -#include "base/buffer.h" -#include "base/stringutil.h" -#include "data/compression.h" -#include "file/fd_util.h" -#include "net/resolve.h" -#include "net/url.h" -#include "thread/threadutil.h" +#include "Common/Net/Resolve.h" +#include "Common/Net/URL.h" + +#include "Common/File/FileDescriptor.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Compression.h" +#include "Common/Buffer.h" +#include "Common/Log.h" namespace net { @@ -48,11 +50,11 @@ inline unsigned short myhtons(unsigned short x) { bool Connection::Resolve(const char *host, int port, DNSType type) { if ((intptr_t)sock_ != -1) { - ELOG("Resolve: Already have a socket"); + ERROR_LOG(IO, "Resolve: Already have a socket"); return false; } if (!host || port < 1 || port > 65535) { - ELOG("Resolve: Invalid host or port (%d)", port); + ERROR_LOG(IO, "Resolve: Invalid host or port (%d)", port); return false; } @@ -64,7 +66,7 @@ bool Connection::Resolve(const char *host, int port, DNSType type) { std::string err; if (!net::DNSResolve(host, port_str, &resolved_, err, type)) { - ELOG("Failed to resolve host %s: %s", host, err.c_str()); + ERROR_LOG(IO, "Failed to resolve host %s: %s", host, err.c_str()); // So that future calls fail. port_ = 0; return false; @@ -75,7 +77,7 @@ bool Connection::Resolve(const char *host, int port, DNSType type) { bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { if (port_ <= 0) { - ELOG("Bad port"); + ERROR_LOG(IO, "Bad port"); return false; } sock_ = -1; @@ -91,7 +93,7 @@ bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { int sock = socket(possible->ai_family, SOCK_STREAM, IPPROTO_TCP); if ((intptr_t)sock == -1) { - ELOG("Bad socket"); + ERROR_LOG(IO, "Bad socket"); continue; } fd_util::SetNonBlocking(sock, true); @@ -229,13 +231,13 @@ int Client::GET(const char *resource, Buffer *output, std::vector & const char *otherHeaders = "Accept: */*\r\n" "Accept-Encoding: gzip\r\n"; - int err = SendRequest("GET", resource, otherHeaders, progress); + int err = SendRequest("GET", resource, otherHeaders, progress, cancelled); if (err < 0) { return err; } Buffer readbuf; - int code = ReadResponseHeaders(&readbuf, responseHeaders, progress); + int code = ReadResponseHeaders(&readbuf, responseHeaders, progress, cancelled); if (code < 0) { return code; } @@ -283,11 +285,11 @@ int Client::POST(const char *resource, const std::string &data, Buffer *output, return POST(resource, data, "", output, progress); } -int Client::SendRequest(const char *method, const char *resource, const char *otherHeaders, float *progress) { - return SendRequestWithData(method, resource, "", otherHeaders, progress); +int Client::SendRequest(const char *method, const char *resource, const char *otherHeaders, float *progress, bool *cancelled) { + return SendRequestWithData(method, resource, "", otherHeaders, progress, cancelled); } -int Client::SendRequestWithData(const char *method, const char *resource, const std::string &data, const char *otherHeaders, float *progress) { +int Client::SendRequestWithData(const char *method, const char *resource, const std::string &data, const char *otherHeaders, float *progress, bool *cancelled) { if (progress) { *progress = 0.01f; } @@ -314,14 +316,26 @@ int Client::SendRequestWithData(const char *method, const char *resource, const return 0; } -int Client::ReadResponseHeaders(Buffer *readbuf, std::vector &responseHeaders, float *progress) { +int Client::ReadResponseHeaders(Buffer *readbuf, std::vector &responseHeaders, float *progress, bool *cancelled) { // Snarf all the data we can into RAM. A little unsafe but hey. - if (dataTimeout_ >= 0.0 && !fd_util::WaitUntilReady(sock(), dataTimeout_, false)) { - ELOG("HTTP headers timed out"); - return -1; - } + static constexpr float CANCEL_INTERVAL = 0.25f; + bool ready = false; + double leftTimeout = dataTimeout_; + while (!ready) { + if (cancelled && *cancelled) + return -1; + ready = fd_util::WaitUntilReady(sock(), CANCEL_INTERVAL, false); + if (!ready && leftTimeout >= 0.0) { + leftTimeout -= CANCEL_INTERVAL; + if (leftTimeout < 0) { + ERROR_LOG(IO, "HTTP headers timed out"); + return -1; + } + } + }; + // Let's hope all the headers are available in a single packet... if (readbuf->Read(sock(), 4096) < 0) { - ELOG("Failed to read HTTP headers :("); + ERROR_LOG(IO, "Failed to read HTTP headers :("); return -1; } @@ -396,7 +410,7 @@ int Client::ReadResponseEntity(Buffer *readbuf, const std::vector & if (!contentLength || !progress) { // No way to know how far along we are. Let's just not update the progress counter. - if (!readbuf->ReadAll(sock(), contentLength)) + if (!readbuf->ReadAllWithProgress(sock(), contentLength, nullptr, cancelled)) return -1; } else { // Let's read in chunks, updating progress between each. @@ -417,7 +431,7 @@ int Client::ReadResponseEntity(Buffer *readbuf, const std::vector & output->TakeAll(&compressed); bool result = decompress_string(compressed, &decompressed); if (!result) { - ELOG("Error decompressing using zlib"); + ERROR_LOG(IO, "Error decompressing using zlib"); if (progress) *progress = 0.0f; return -1; @@ -436,12 +450,19 @@ Download::Download(const std::string &url, const std::string &outfile) } Download::~Download() { - if (thread_.joinable()) - thread_.join(); + _assert_msg_(joined_, "Download destructed without join"); } -void Download::Start(std::shared_ptr self) { - thread_ = std::thread(std::bind(&Download::Do, this, self)); +void Download::Start() { + thread_ = std::thread(std::bind(&Download::Do, this)); +} + +void Download::Join() { + if (joined_) { + ERROR_LOG(IO, "Already joined thread!"); + } + thread_.join(); + joined_ = true; } void Download::SetFailed(int code) { @@ -458,7 +479,7 @@ int Download::PerformGET(const std::string &url) { http::Client client; if (!client.Resolve(fileUrl.Host().c_str(), fileUrl.Port())) { - ELOG("Failed resolving %s", url.c_str()); + ERROR_LOG(IO, "Failed resolving %s", url.c_str()); return -1; } @@ -467,7 +488,7 @@ int Download::PerformGET(const std::string &url) { } if (!client.Connect(2, 20.0, &cancelled_)) { - ELOG("Failed connecting to server or cancelled."); + ERROR_LOG(IO, "Failed connecting to server or cancelled."); return -1; } @@ -489,11 +510,8 @@ std::string Download::RedirectLocation(const std::string &baseUrl) { return redirectUrl; } -void Download::Do(std::shared_ptr self) { +void Download::Do() { setCurrentThreadName("Downloader::Do"); - // as long as this is in scope, we won't get destructed. - // yeah this is ugly, I need to think about how life time should be managed for these... - std::shared_ptr self_ = self; resultCode_ = 0; std::string downloadURL = url_; @@ -507,7 +525,7 @@ void Download::Do(std::shared_ptr self) { if (resultCode == 301 || resultCode == 302 || resultCode == 303 || resultCode == 307 || resultCode == 308) { std::string redirectURL = RedirectLocation(downloadURL); if (redirectURL.empty()) { - ELOG("Could not find Location header for redirect"); + ERROR_LOG(IO, "Could not find Location header for redirect"); resultCode_ = resultCode; } else if (redirectURL == downloadURL || redirectURL == url_) { // Simple loop detected, bail out. @@ -516,18 +534,18 @@ void Download::Do(std::shared_ptr self) { // Perform the next GET. if (resultCode_ == 0) - ILOG("Download of %s redirected to %s", downloadURL.c_str(), redirectURL.c_str()); + INFO_LOG(IO, "Download of %s redirected to %s", downloadURL.c_str(), redirectURL.c_str()); downloadURL = redirectURL; continue; } if (resultCode == 200) { - ILOG("Completed downloading %s to %s", url_.c_str(), outfile_.empty() ? "memory" : outfile_.c_str()); + INFO_LOG(IO, "Completed downloading %s to %s", url_.c_str(), outfile_.empty() ? "memory" : outfile_.c_str()); if (!outfile_.empty() && !buffer_.FlushToFile(outfile_.c_str())) { - ELOG("Failed writing download to %s", outfile_.c_str()); + ERROR_LOG(IO, "Failed writing download to %s", outfile_.c_str()); } } else { - ELOG("Error downloading %s to %s: %i", url_.c_str(), outfile_.c_str(), resultCode); + ERROR_LOG(IO, "Error downloading %s to %s: %i", url_.c_str(), outfile_.c_str(), resultCode); } resultCode_ = resultCode; } @@ -542,7 +560,7 @@ void Download::Do(std::shared_ptr self) { std::shared_ptr Downloader::StartDownload(const std::string &url, const std::string &outfile) { std::shared_ptr dl(new Download(url, outfile)); downloads_.push_back(dl); - dl->Start(dl); + dl->Start(); return dl; } @@ -553,7 +571,7 @@ std::shared_ptr Downloader::StartDownloadWithCallback( std::shared_ptr dl(new Download(url, outfile)); dl->SetCallback(callback); downloads_.push_back(dl); - dl->Start(dl); + dl->Start(); return dl; } @@ -562,6 +580,7 @@ void Downloader::Update() { for (size_t i = 0; i < downloads_.size(); i++) { if (downloads_[i]->Progress() == 1.0f || downloads_[i]->Failed()) { downloads_[i]->RunCallback(); + downloads_[i]->Join(); downloads_.erase(downloads_.begin() + i); goto restart; } @@ -581,6 +600,9 @@ void Downloader::CancelAll() { for (size_t i = 0; i < downloads_.size(); i++) { downloads_[i]->Cancel(); } + for (size_t i = 0; i < downloads_.size(); i++) { + downloads_[i]->Join(); + } downloads_.clear(); } diff --git a/ext/native/net/http_client.h b/Common/Net/HTTPClient.h similarity index 91% rename from ext/native/net/http_client.h rename to Common/Net/HTTPClient.h index b671169585..731ff75dd5 100644 --- a/ext/native/net/http_client.h +++ b/Common/Net/HTTPClient.h @@ -3,10 +3,9 @@ #include #include #include +#include -#include "base/basictypes.h" -#include "base/buffer.h" -#include "net/resolve.h" +#include "Common/Net/Resolve.h" #ifdef _WIN32 #ifndef NOMINMAX @@ -21,6 +20,8 @@ #include #endif +#include "Common/Buffer.h" + namespace net { class Connection { @@ -71,9 +72,9 @@ public: // HEAD, PUT, DELETE aren't implemented yet, but can be done with SendRequest. - int SendRequest(const char *method, const char *resource, const char *otherHeaders = nullptr, float *progress = nullptr); - int SendRequestWithData(const char *method, const char *resource, const std::string &data, const char *otherHeaders = nullptr, float *progress = nullptr); - int ReadResponseHeaders(Buffer *readbuf, std::vector &responseHeaders, float *progress = nullptr); + int SendRequest(const char *method, const char *resource, const char *otherHeaders = nullptr, float *progress = nullptr, bool *cancelled = nullptr); + int SendRequestWithData(const char *method, const char *resource, const std::string &data, const char *otherHeaders = nullptr, float *progress = nullptr, bool *cancelled = nullptr); + int ReadResponseHeaders(Buffer *readbuf, std::vector &responseHeaders, float *progress = nullptr, bool *cancelled = nullptr); // If your response contains a response, you must read it. int ReadResponseEntity(Buffer *readbuf, const std::vector &responseHeaders, Buffer *output, float *progress = nullptr, bool *cancelled = nullptr); @@ -93,9 +94,9 @@ public: Download(const std::string &url, const std::string &outfile); ~Download(); - // Keeps around an instance of the shared_ptr, so that it doesn't get destructed - // until done. - void Start(std::shared_ptr self); + void Start(); + + void Join(); // Returns 1.0 when done. That one value can be compared exactly - or just use Done(). float Progress() const { return progress_; } @@ -138,7 +139,7 @@ public: void SetHidden(bool hidden) { hidden_ = hidden; } private: - void Do(std::shared_ptr self); // Actually does the download. Runs on thread. + void Do(); // Actually does the download. Runs on thread. int PerformGET(const std::string &url); std::string RedirectLocation(const std::string &baseUrl); void SetFailed(int code); @@ -153,6 +154,7 @@ private: bool failed_ = false; bool cancelled_ = false; bool hidden_ = false; + bool joined_ = false; std::function callback_; }; diff --git a/ext/native/net/http_headers.cpp b/Common/Net/HTTPHeaders.cpp similarity index 89% rename from ext/native/net/http_headers.cpp rename to Common/Net/HTTPHeaders.cpp index fdfaa2c1ea..acb554ee70 100644 --- a/ext/native/net/http_headers.cpp +++ b/Common/Net/HTTPHeaders.cpp @@ -1,13 +1,14 @@ -#include "net/http_headers.h" +#include "Common/Net/HTTPHeaders.h" #include #include #include -#include "base/logging.h" -#include "base/stringutil.h" -#include "file/fd_util.h" -#include "net/sinks.h" +#include "Common/Net/Sinks.h" + +#include "Common/Log.h" +#include "Common/File/FileDescriptor.h" +#include "Common/StringUtils.h" namespace http { @@ -32,7 +33,7 @@ bool RequestHeader::GetParamValue(const char *param_name, std::string *value) co for (size_t i = 0; i < v.size(); i++) { std::vector parts; SplitString(v[i], '=', parts); - ILOG("Param: %s Value: %s", parts[0].c_str(), parts[1].c_str()); + INFO_LOG(IO, "Param: %s Value: %s", parts[0].c_str(), parts[1].c_str()); if (parts[0] == param_name) { *value = parts[1]; return true; @@ -120,13 +121,13 @@ int RequestHeader::ParseHttpHeader(const char *buffer) { if (!strncasecmp(key, "User-Agent", key_len)) { user_agent = new char[value_len + 1]; memcpy(user_agent, buffer, value_len + 1); - ILOG("user-agent: %s", user_agent); + INFO_LOG(IO, "user-agent: %s", user_agent); } else if (!strncasecmp(key, "Referer", key_len)) { referer = new char[value_len + 1]; memcpy(referer, buffer, value_len + 1); } else if (!strncasecmp(key, "Content-Length", key_len)) { content_length = atoi(buffer); - ILOG("Content-Length: %i", (int)content_length); + INFO_LOG(IO, "Content-Length: %i", (int)content_length); } else { std::string key_str(key, key_len); std::transform(key_str.begin(), key_str.end(), key_str.begin(), tolower); @@ -149,12 +150,12 @@ void RequestHeader::ParseHeaders(net::InputSink *sink) { line_count++; if (type == SIMPLE) { // Done! - ILOG("Simple: Done parsing http request."); + INFO_LOG(IO, "Simple: Done parsing http request."); break; } } - ILOG("finished parsing request."); + INFO_LOG(IO, "finished parsing request."); ok = line_count > 1; } diff --git a/ext/native/net/http_headers.h b/Common/Net/HTTPHeaders.h similarity index 90% rename from ext/native/net/http_headers.h rename to Common/Net/HTTPHeaders.h index 470f589972..0ee0b1b751 100644 --- a/ext/native/net/http_headers.h +++ b/Common/Net/HTTPHeaders.h @@ -1,9 +1,9 @@ -#ifndef _NET_HTTP_HTTP_HEADERS -#define _NET_HTTP_HTTP_HEADERS +#pragma once #include #include -#include "base/buffer.h" + +#include "Common/Buffer.h" namespace net { class InputSink; @@ -48,5 +48,3 @@ class RequestHeader { }; } // namespace http - -#endif diff --git a/ext/native/net/http_server.cpp b/Common/Net/HTTPServer.cpp similarity index 90% rename from ext/native/net/http_server.cpp rename to Common/Net/HTTPServer.cpp index c4120bae6a..da114da85a 100644 --- a/ext/native/net/http_server.cpp +++ b/Common/Net/HTTPServer.cpp @@ -1,4 +1,4 @@ -#include "base/timeutil.h" +#include "Common/TimeUtil.h" #include "ppsspp_config.h" #ifdef _WIN32 @@ -34,12 +34,13 @@ #include #include -#include "base/logging.h" -#include "base/buffer.h" -#include "file/fd_util.h" -#include "net/http_server.h" -#include "net/sinks.h" -#include "thread/executor.h" +#include "Common/Net/HTTPServer.h" +#include "Common/Net/Sinks.h" +#include "Common/File/FileDescriptor.h" +#include "Common/Thread/Executor.h" + +#include "Common/Buffer.h" +#include "Common/Log.h" namespace http { @@ -53,7 +54,7 @@ Request::Request(int fd) header_.ParseHeaders(in_); if (header_.ok) { - ILOG("The request carried with it %i bytes", (int)header_.content_length); + INFO_LOG(IO, "The request carried with it %i bytes", (int)header_.content_length); } else { Close(); } @@ -62,10 +63,10 @@ Request::Request(int fd) Request::~Request() { Close(); - CHECK(in_->Empty()); + _assert_(in_->Empty()); delete in_; if (!out_->Empty()) { - ELOG("Output not empty - connection abort?"); + ERROR_LOG(IO, "Output not empty - connection abort?"); } delete out_; } @@ -108,12 +109,12 @@ void Request::WriteHttpResponseHeader(const char *ver, int status, int64_t size, } void Request::WritePartial() const { - CHECK(fd_); + _assert_(fd_); out_->Flush(); } void Request::Write() { - CHECK(fd_); + _assert_(fd_); WritePartial(); Close(); } @@ -171,7 +172,7 @@ bool Server::Listen4(int port) { if (bind(listener_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { closesocket(listener_); - ELOG("Failed to bind to port %i. Bailing.", port); + ERROR_LOG(IO, "Failed to bind to port %d. Bailing.", port); return false; } @@ -188,7 +189,7 @@ bool Server::Listen4(int port) { port = ntohs(server_addr.sin_port); } - ILOG("HTTP server started on port %i", port); + INFO_LOG(IO, "HTTP server started on port %d", port); port_ = port; return true; @@ -216,7 +217,7 @@ bool Server::Listen6(int port, bool ipv6_only) { if (bind(listener_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { closesocket(listener_); - ELOG("Failed to bind to port %i. Bailing.", port); + ERROR_LOG(IO, "Failed to bind to port %d. Bailing.", port); return false; } @@ -233,7 +234,7 @@ bool Server::Listen6(int port, bool ipv6_only) { port = ntohs(server_addr.sin6_port); } - ILOG("HTTP server started on port %i", port); + INFO_LOG(IO, "HTTP server started on port %d", port); port_ = port; return true; @@ -268,7 +269,7 @@ bool Server::RunSlice(double timeout) { return true; } else { - ELOG("socket accept failed: %i", conn_fd); + ERROR_LOG(IO, "socket accept failed: %i", conn_fd); return false; } } @@ -293,7 +294,7 @@ void Server::Stop() { void Server::HandleConnection(int conn_fd) { Request request(conn_fd); if (!request.IsOK()) { - WLOG("Bad request, ignoring."); + WARN_LOG(IO, "Bad request, ignoring."); return; } HandleRequest(request); @@ -321,7 +322,7 @@ void Server::HandleRequestDefault(const Request &request) { } void Server::Handle404(const Request &request) { - ILOG("No handler for '%s', falling back to 404.", request.resource()); + INFO_LOG(IO, "No handler for '%s', falling back to 404.", request.resource()); const char *payload = "404 not found\r\n"; request.WriteHttpResponseHeader("1.0", 404, (int)strlen(payload)); request.Out()->Push(payload); diff --git a/ext/native/net/http_server.h b/Common/Net/HTTPServer.h similarity index 93% rename from ext/native/net/http_server.h rename to Common/Net/HTTPServer.h index 0b5dfbe668..9cfdf2fc1e 100644 --- a/ext/native/net/http_server.h +++ b/Common/Net/HTTPServer.h @@ -1,13 +1,11 @@ -#ifndef _HTTP_SERVER_H -#define _HTTP_SERVER_H +#pragma once #include #include -#include "base/buffer.h" -#include "net/http_headers.h" -#include "net/resolve.h" -#include "thread/executor.h" +#include "Common/Net/HTTPHeaders.h" +#include "Common/Net/Resolve.h" +#include "Common/Thread/Executor.h" namespace net { class InputSink; @@ -114,5 +112,3 @@ private: }; } // namespace http - -#endif // _HTTP_SERVER_H diff --git a/ext/native/net/resolve.cpp b/Common/Net/Resolve.cpp similarity index 52% rename from ext/native/net/resolve.cpp rename to Common/Net/Resolve.cpp index a5bd024c7a..aac2cdb6fd 100644 --- a/ext/native/net/resolve.cpp +++ b/Common/Net/Resolve.cpp @@ -1,11 +1,11 @@ -#include "net/resolve.h" -#include "base/logging.h" -#include "base/timeutil.h" +#include "ppsspp_config.h" +#include "Common/Net/Resolve.h" #include #include #include #include +#include #ifdef _WIN32 @@ -24,6 +24,7 @@ #include #endif +#include "Common/TimeUtil.h" namespace net { @@ -44,6 +45,7 @@ void Shutdown() } bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error, DNSType type) { + #if PPSSPP_PLATFORM(SWITCH) // Force IPv4 lookups. if (type == DNSType::IPV6) { @@ -101,6 +103,105 @@ void DNSResolveFree(addrinfo *res) freeaddrinfo(res); } +bool GetIPList(std::vector &IP4s) { + char ipstr[INET6_ADDRSTRLEN]; // We use IPv6 length since it's longer than IPv4 +#if defined(getifaddrs) // On Android: Requires __ANDROID_API__ >= 24 + struct ifaddrs* ifAddrStruct = NULL; + struct ifaddrs* ifa = NULL; + + getifaddrs(&ifAddrStruct); + if (ifAddrStruct != NULL) { + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) { + continue; + } + if (ifa->ifa_addr->sa_family == AF_INET) { + // is a valid IP4 Address + if (inet_ntop(AF_INET, &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr, ipstr, sizeof(ipstr)) != 0) { + IP4s.push_back(ipstr); + } + } + /*else if (ifa->ifa_addr->sa_family == AF_INET6) { + // is a valid IP6 Address + if (inet_ntop(AF_INET6, &((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr, ipstr, sizeof(ipstr)) != 0) { + IP6s.push_back(ipstr); + } + }*/ + } + + freeifaddrs(ifAddrStruct); + return true; + } +#elif defined(SIOCGIFCONF) // Better detection on Linux/UNIX/MacOS/some Android +#include + static struct ifreq ifreqs[32]; + struct ifconf ifconf; + memset(&ifconf, 0, sizeof(ifconf)); + ifconf.ifc_req = ifreqs; + ifconf.ifc_len = sizeof(ifreqs); + + int sd = socket(AF_INET, SOCK_DGRAM, 0); + if (sd < 0) return false; + + int r = ioctl(sd, SIOCGIFCONF, (char*)&ifconf); + if (r != 0) return false; + + for (int i = 0; i < ifconf.ifc_len / sizeof(struct ifreq); ++i) + { + if (ifreqs[i].ifr_addr.sa_family == AF_INET) { + // is a valid IP4 Address + if (inet_ntop(AF_INET, &((struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr, ipstr, sizeof(ipstr)) != 0) { + IP4s.push_back(ipstr); + } + } + /*else if (ifreqs[i].ifr_addr.sa_family == AF_INET6) { + // is a valid IP6 Address + if (inet_ntop(AF_INET6, &((struct sockaddr_in6*)&ifreqs[i].ifr_addr)->sin6_addr, ipstr, sizeof(ipstr)) != 0) { + IP6s.push_back(ipstr); + } + }*/ + } + + close(sd); + return true; +#else // Fallback to POSIX/Cross-platform way but may not works well on Linux (ie. only shows 127.0.0.1) + struct addrinfo hints, * res, * p; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version + hints.ai_socktype = SOCK_DGRAM; + + // Get local host name + char szHostName[256] = ""; + if (::gethostname(szHostName, sizeof(szHostName))) { + // Error handling + } + + int status; + if ((status = getaddrinfo(szHostName, NULL, &hints, &res)) != 0) { + //fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); + return false; + } + for (p = res; p != NULL; p = p->ai_next) { + if (p->ai_family == AF_INET) { + // is a valid IP4 Address + if (inet_ntop(p->ai_family, &(((struct sockaddr_in*)p->ai_addr)->sin_addr), ipstr, sizeof(ipstr)) != 0) { + IP4s.push_back(ipstr); + } + } + /*else if (p->ai_family == AF_INET6) { + // is a valid IP6 Address + if (inet_ntop(p->ai_family, &(((struct sockaddr_in6*)p->ai_addr)->sin6_addr), ipstr, sizeof(ipstr)) != 0) { + IP6s.push_back(ipstr); + } + }*/ + } + + freeaddrinfo(res); // free the linked list + return true; +#endif + return false; +} + int inet_pton(int af, const char* src, void* dst) { if (af == AF_INET) diff --git a/ext/native/net/resolve.h b/Common/Net/Resolve.h similarity index 77% rename from ext/native/net/resolve.h rename to Common/Net/Resolve.h index 58ce0984d9..882ed5c0d5 100644 --- a/ext/native/net/resolve.h +++ b/Common/Net/Resolve.h @@ -1,6 +1,7 @@ #pragma once #include +#include struct addrinfo; @@ -10,10 +11,6 @@ namespace net { void Init(); void Shutdown(); -// use free() to free the returned string. -char *DNSResolveTry(const char *host, const char **err); -char *DNSResolve(const char *host); - enum class DNSType { ANY = 0, IPV4 = 1, @@ -22,6 +19,7 @@ enum class DNSType { bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error, DNSType type = DNSType::ANY); void DNSResolveFree(addrinfo *res); +bool GetIPList(std::vector& IP4s); int inet_pton(int af, const char* src, void* dst); } // namespace net diff --git a/ext/native/net/sinks.cpp b/Common/Net/Sinks.cpp similarity index 93% rename from ext/native/net/sinks.cpp rename to Common/Net/Sinks.cpp index d9bf32d9d0..2d15de15cf 100644 --- a/ext/native/net/sinks.cpp +++ b/Common/Net/Sinks.cpp @@ -1,4 +1,6 @@ -#ifdef _WIN32 +#include "ppsspp_config.h" + +#if PPSSPP_PLATFORM(WINDOWS) #ifndef NOMINMAX #define NOMINMAX @@ -19,11 +21,13 @@ #endif #include +#include #include -#include "base/logging.h" -#include "net/sinks.h" -#include "file/fd_util.h" +#include "Common/Net/Sinks.h" + +#include "Common/Log.h" +#include "Common/File/FileDescriptor.h" #ifndef MSG_NOSIGNAL // Default value to 0x00 (do nothing) in systems where it's not supported @@ -182,7 +186,15 @@ bool InputSink::Block() { void InputSink::AccountFill(int bytes) { if (bytes < 0) { - ELOG("Error reading from socket"); +#if PPSSPP_PLATFORM(WINDOWS) + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) + return; +#else + if (errno == EWOULDBLOCK || errno == EAGAIN) + return; +#endif + ERROR_LOG(IO, "Error reading from socket"); return; } @@ -303,10 +315,10 @@ bool OutputSink::Printf(const char *fmt, ...) { // Okay, did we actually write? if (result >= (int)avail) { // This means the result string was too big for the buffer. - ELOG("Not enough space to format output."); + ERROR_LOG(IO, "Not enough space to format output."); return false; } else if (result < 0) { - ELOG("vsnprintf failed."); + ERROR_LOG(IO, "vsnprintf failed."); return false; } @@ -373,7 +385,7 @@ void OutputSink::AccountPush(size_t bytes) { void OutputSink::AccountDrain(int bytes) { if (bytes < 0) { - ELOG("Error writing to socket"); + ERROR_LOG(IO, "Error writing to socket"); return; } diff --git a/ext/native/net/sinks.h b/Common/Net/Sinks.h similarity index 100% rename from ext/native/net/sinks.h rename to Common/Net/Sinks.h diff --git a/ext/native/net/url.cpp b/Common/Net/URL.cpp similarity index 97% rename from ext/native/net/url.cpp rename to Common/Net/URL.cpp index 45175372e7..681fc45ff2 100644 --- a/ext/native/net/url.cpp +++ b/Common/Net/URL.cpp @@ -1,6 +1,6 @@ -#include "base/logging.h" -#include "base/stringutil.h" -#include "net/url.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" +#include "Common/Net/URL.h" const char *UrlEncoder::unreservedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~"; const char *UrlEncoder::hexChars = "0123456789ABCDEF"; @@ -10,7 +10,7 @@ int MultipartFormDataEncoder::seq = 0; void Url::Split() { size_t colonSlashSlash = url_.find("://"); if (colonSlashSlash == std::string::npos) { - ELOG("Invalid URL: %s", url_.c_str()); + ERROR_LOG(IO, "Invalid URL: %s", url_.c_str()); return; } diff --git a/ext/native/net/url.h b/Common/Net/URL.h similarity index 98% rename from ext/native/net/url.h rename to Common/Net/URL.h index a46564d642..1a8a91677b 100644 --- a/ext/native/net/url.h +++ b/Common/Net/URL.h @@ -1,13 +1,12 @@ #pragma once #include -#include -#include +#include +#include #include +#include #include -#include "base/basictypes.h" - #if defined(_MSC_VER) && _MSC_VER < 1900 #undef snprintf #define snprintf _snprintf diff --git a/ext/native/net/websocket_server.cpp b/Common/Net/WebsocketServer.cpp similarity index 94% rename from ext/native/net/websocket_server.cpp rename to Common/Net/WebsocketServer.cpp index 42efb36647..5af6bf2bdb 100644 --- a/ext/native/net/websocket_server.cpp +++ b/Common/Net/WebsocketServer.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -15,18 +14,15 @@ #include #include #endif -#include "base/stringutil.h" -#include "data/base64.h" -#include "net/http_server.h" -#include "net/sinks.h" -#include "net/websocket_server.h" -// TODO: Not a great cross dependency. -#include "Common/Crypto/sha1.h" -#ifdef _WIN32 -// Function Cross-Compatibility -#define strcasecmp _stricmp -#endif +#include "Common/Data/Encoding/Base64.h" +#include "Common/Net/HTTPServer.h" +#include "Common/Net/Sinks.h" +#include "Common/Net/WebsocketServer.h" + +#include "Common/Crypto/sha1.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" static const char *const WEBSOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; @@ -130,28 +126,28 @@ WebSocketServer *WebSocketServer::CreateAsUpgrade(const http::Request &request, } void WebSocketServer::Send(const std::string &str) { - assert(open_); - assert(fragmentOpcode_ == -1); + _assert_(open_); + _assert_(fragmentOpcode_ == -1); SendHeader(true, (int)Opcode::TEXT, str.size()); SendBytes(str.c_str(), str.size()); } void WebSocketServer::Send(const std::vector &payload) { - assert(open_); - assert(fragmentOpcode_ == -1); + _assert_(open_); + _assert_(fragmentOpcode_ == -1); SendHeader(true, (int)Opcode::BINARY, payload.size()); SendBytes((const char *)&payload[0], payload.size()); } void WebSocketServer::AddFragment(bool finish, const std::string &str) { - assert(open_); + _assert_(open_); if (fragmentOpcode_ == -1) { SendHeader(finish, (int)Opcode::TEXT, str.size()); fragmentOpcode_ = (int)Opcode::TEXT; } else if (fragmentOpcode_ == (int)Opcode::TEXT) { SendHeader(finish, (int)Opcode::CONTINUE, str.size()); } else { - assert(fragmentOpcode_ == (int)Opcode::TEXT || fragmentOpcode_ == -1); + _assert_(fragmentOpcode_ == (int)Opcode::TEXT || fragmentOpcode_ == -1); } SendBytes(str.c_str(), str.size()); if (finish) { @@ -160,14 +156,14 @@ void WebSocketServer::AddFragment(bool finish, const std::string &str) { } void WebSocketServer::AddFragment(bool finish, const std::vector &payload) { - assert(open_); + _assert_(open_); if (fragmentOpcode_ == -1) { SendHeader(finish, (int)Opcode::BINARY, payload.size()); fragmentOpcode_ = (int)Opcode::BINARY; } else if (fragmentOpcode_ == (int)Opcode::BINARY) { SendHeader(finish, (int)Opcode::CONTINUE, payload.size()); } else { - assert(fragmentOpcode_ == (int)Opcode::BINARY || fragmentOpcode_ == -1); + _assert_(fragmentOpcode_ == (int)Opcode::BINARY || fragmentOpcode_ == -1); } SendBytes((const char *)&payload[0], payload.size()); if (finish) { @@ -176,15 +172,15 @@ void WebSocketServer::AddFragment(bool finish, const std::vector &paylo } void WebSocketServer::Ping(const std::vector &payload) { - assert(open_); - assert(payload.size() <= 125); + _assert_(open_); + _assert_(payload.size() <= 125); SendHeader(true, (int)Opcode::PING, payload.size()); SendBytes((const char *)&payload[0], payload.size()); } void WebSocketServer::Pong(const std::vector &payload) { - assert(open_); - assert(payload.size() <= 125); + _assert_(open_); + _assert_(payload.size() <= 125); SendHeader(true, (int)Opcode::PONG, payload.size()); SendBytes((const char *)&payload[0], payload.size()); } @@ -280,7 +276,7 @@ bool WebSocketServer::ReadFrames() { } bool WebSocketServer::ReadFrame() { - assert(pendingLeft_ == 0); + _assert_(pendingLeft_ == 0); // TODO: For now blocking on header trickle, shouldn't be common. auto readExact = [&](void *p, size_t sz) { @@ -413,7 +409,7 @@ bool WebSocketServer::ReadPending() { binary_(pendingBuf_); } } else { - assert(false); + _assert_(false); } // All done, clear it out. @@ -460,14 +456,14 @@ bool WebSocketServer::ReadControlFrame(int opcode, size_t sz) { // Don't read anything more. return false; } else { - assert(false); + _assert_(false); } return true; } void WebSocketServer::SendHeader(bool fin, int opcode, size_t sz) { - assert((opcode & 0x0F) == opcode); + _assert_((opcode & 0x0F) == opcode); uint8_t frameHeader = (fin ? 0x80 : 0x00) | opcode; SendBytes(&frameHeader, 1); @@ -484,7 +480,7 @@ void WebSocketServer::SendHeader(bool fin, int opcode, size_t sz) { SendBytes(frameSize, sizeof(frameSize)); } else { uint64_t sz64 = sz; - assert((sz64 & 0x8000000000000000ULL) == 0); + _assert_((sz64 & 0x8000000000000000ULL) == 0); uint8_t frameSize[] = { 127, (uint8_t)((sz64 >> 56) & 0xFF), diff --git a/ext/native/net/websocket_server.h b/Common/Net/WebsocketServer.h similarity index 97% rename from ext/native/net/websocket_server.h rename to Common/Net/WebsocketServer.h index 2c4c59739e..7a05b0f03a 100644 --- a/ext/native/net/websocket_server.h +++ b/Common/Net/WebsocketServer.h @@ -2,8 +2,9 @@ #include #include -#include "net/http_server.h" -#include "net/sinks.h" + +#include "Common/Net/HTTPServer.h" +#include "Common/Net/Sinks.h" namespace net { diff --git a/ext/native/profiler/profiler.cpp b/Common/Profiler/Profiler.cpp similarity index 91% rename from ext/native/profiler/profiler.cpp rename to Common/Profiler/Profiler.cpp index bf037a9510..7d3521012e 100644 --- a/ext/native/profiler/profiler.cpp +++ b/Common/Profiler/Profiler.cpp @@ -5,14 +5,15 @@ #include #include #include +#include -#include - -#include "base/logging.h" -#include "base/timeutil.h" -#include "gfx_es2/draw_buffer.h" #include "ppsspp_config.h" -#include "profiler/profiler.h" + +#include "Common/Render/DrawBuffer.h" + +#include "Common/TimeUtil.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Log.h" #define MAX_CATEGORIES 64 // Can be any number, represents max profiled names. #define MAX_DEPTH 16 // Can be any number, represents max nesting depth of profiled names. @@ -139,7 +140,7 @@ int internal_profiler_enter(const char *category_name, int *out_thread_id) { int &depth = profiler.depth[thread_id]; if (profiler.eventStart[thread_id][category] == 0.0f) { - double now = real_time_now(); + double now = time_now_d(); int parent = profiler.parentCategory[thread_id][depth]; // Temporarily suspend the parent on entering a child. if (parent != -1) { @@ -147,7 +148,7 @@ int internal_profiler_enter(const char *category_name, int *out_thread_id) { } internal_profiler_resume(thread_id, category, now); } else { - DLOG("profiler: recursive enter (%i - %s)", category, category_name); + DEBUG_LOG(SYSTEM, "profiler: recursive enter (%i - %s)", category, category_name); } depth++; @@ -164,17 +165,15 @@ void internal_profiler_leave(int thread_id, int category) { int &depth = profiler.depth[thread_id]; if (category < 0 || category >= MAX_CATEGORIES) { - ELOG("Bad category index %d", category); + ERROR_LOG(SYSTEM, "Bad category index %d", category); depth--; return; } - double now = real_time_now(); + double now = time_now_d(); depth--; - if (depth < 0) { - FLOG("Profiler enter/leave mismatch!"); - } + _assert_msg_(depth >= 0, "Profiler enter/leave mismatch!"); int parent = profiler.parentCategory[thread_id][depth]; // When there's recursion, we don't suspend or resume. @@ -191,11 +190,8 @@ void internal_profiler_leave(int thread_id, int category) { void internal_profiler_end_frame() { int thread_id = internal_profiler_find_thread(); - if (profiler.depth[thread_id] != 0) { - // Threads may be off, but they'll fall into another frame. - FLOG("Can't be inside a profiler scope at end of frame!"); - } - profiler.curFrameStart = real_time_now(); + _assert_msg_(profiler.depth[thread_id] == 0, "Can't be inside a profiler scope at end of frame!"); + profiler.curFrameStart = time_now_d(); profiler.historyPos++; profiler.historyPos &= (HISTORY_SIZE - 1); memset(&history[MAX_THREADS * profiler.historyPos], 0, sizeof(CategoryFrame) * MAX_THREADS); diff --git a/ext/native/profiler/profiler.h b/Common/Profiler/Profiler.h similarity index 100% rename from ext/native/profiler/profiler.h rename to Common/Profiler/Profiler.h diff --git a/ext/native/gfx_es2/draw_buffer.cpp b/Common/Render/DrawBuffer.cpp similarity index 97% rename from ext/native/gfx_es2/draw_buffer.cpp rename to Common/Render/DrawBuffer.cpp index 94e5f28ae8..f23c753726 100644 --- a/ext/native/gfx_es2/draw_buffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -3,16 +3,16 @@ #include #include -#include "base/display.h" -#include "base/logging.h" -#include "base/stringutil.h" -#include "math/math_util.h" -#include "gfx/texture_atlas.h" -#include "gfx/gl_debug_log.h" -#include "gfx_es2/draw_buffer.h" -#include "gfx_es2/draw_text.h" -#include "util/text/utf8.h" -#include "util/text/wrap_text.h" +#include "Common/System/Display.h" +#include "Common/Math/math_util.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Render/Text/draw_text.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Text/WrapText.h" + +#include "Common/Log.h" +#include "Common/StringUtils.h" enum { // Enough? @@ -85,7 +85,7 @@ void DrawBuffer::Flush(bool set_blend_state) { if (count_ == 0) return; if (!pipeline_) { - ELOG("DrawBuffer: No program set, skipping flush!"); + ERROR_LOG(G3D, "DrawBuffer: No program set, skipping flush!"); count_ = 0; return; } @@ -106,10 +106,7 @@ void DrawBuffer::Flush(bool set_blend_state) { } void DrawBuffer::V(float x, float y, float z, uint32_t color, float u, float v) { - if (count_ >= MAX_VERTS) { - FLOG("Overflowed the DrawBuffer"); - return; - } + _assert_msg_(count_ < MAX_VERTS, "Overflowed the DrawBuffer"); Vertex *vert = &verts_[count_++]; vert->x = x; diff --git a/ext/native/gfx_es2/draw_buffer.h b/Common/Render/DrawBuffer.h similarity index 95% rename from ext/native/gfx_es2/draw_buffer.h rename to Common/Render/DrawBuffer.h index a702fd6693..40d482ef83 100644 --- a/ext/native/gfx_es2/draw_buffer.h +++ b/Common/Render/DrawBuffer.h @@ -3,13 +3,13 @@ // "Immediate mode"-lookalike buffered drawing. Very fast way to draw 2D. #include +#include -#include "base/basictypes.h" -#include "base/colorutil.h" -#include "gfx/texture_atlas.h" -#include "math/geom2d.h" -#include "math/lin/matrix4x4.h" -#include "thin3d/thin3d.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Math/geom2d.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/GPU/thin3d.h" struct Atlas; @@ -46,11 +46,6 @@ namespace Draw { class Pipeline; } -enum DrawBufferPrimitiveMode { - DBMODE_NORMAL = 0, - DBMODE_LINES = 1 -}; - struct GradientStop { float t; uint32_t color; @@ -190,7 +185,6 @@ private: Vertex *verts_; int count_; - DrawBufferPrimitiveMode mode_; const Atlas *atlas; bool inited_; diff --git a/ext/native/gfx_es2/draw_text.cpp b/Common/Render/Text/draw_text.cpp similarity index 84% rename from ext/native/gfx_es2/draw_text.cpp rename to Common/Render/Text/draw_text.cpp index 4463bdbb55..e236065483 100644 --- a/ext/native/gfx_es2/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -1,15 +1,16 @@ -#include "base/display.h" -#include "base/logging.h" -#include "base/stringutil.h" -#include "thin3d/thin3d.h" -#include "util/hash/hash.h" -#include "util/text/wrap_text.h" -#include "util/text/utf8.h" -#include "gfx_es2/draw_text.h" -#include "gfx_es2/draw_text_win.h" -#include "gfx_es2/draw_text_uwp.h" -#include "gfx_es2/draw_text_qt.h" -#include "gfx_es2/draw_text_android.h" +#include "ppsspp_config.h" + +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Hash/Hash.h" +#include "Common/Data/Text/WrapText.h" +#include "Common/Data/Encoding/Utf8.h" + +#include "Common/Render/Text/draw_text.h" +#include "Common/Render/Text/draw_text_win.h" +#include "Common/Render/Text/draw_text_uwp.h" +#include "Common/Render/Text/draw_text_qt.h" +#include "Common/Render/Text/draw_text_android.h" TextDrawer::TextDrawer(Draw::DrawContext *draw) : draw_(draw) { // These probably shouldn't be state. diff --git a/ext/native/gfx_es2/draw_text.h b/Common/Render/Text/draw_text.h similarity index 89% rename from ext/native/gfx_es2/draw_text.h rename to Common/Render/Text/draw_text.h index f6bf8e3e34..252029b8a3 100644 --- a/ext/native/gfx_es2/draw_text.h +++ b/Common/Render/Text/draw_text.h @@ -10,22 +10,17 @@ #include "ppsspp_config.h" -#include #include +#include -#include "base/basictypes.h" -#include "gfx_es2/draw_buffer.h" -#include "util/text/wrap_text.h" +#include "Common/Data/Text/WrapText.h" +#include "Common/Render/DrawBuffer.h" namespace Draw { class DrawContext; class Texture; } -#ifdef USING_QT_UI -#include -#endif - struct TextStringEntry { Draw::Texture *texture; int width; @@ -41,12 +36,6 @@ struct TextMeasureEntry { int lastUsedFrame; }; -// Not yet functional -enum { - FONTSTYLE_BOLD = 1, - FONTSTYLE_ITALIC = 2, -}; - class TextDrawer { public: virtual ~TextDrawer(); @@ -99,11 +88,10 @@ protected: bool ignoreGlobalDpi_ = false; }; - class TextDrawerWordWrapper : public WordWrapper { public: - TextDrawerWordWrapper(TextDrawer *drawer, const char *str, float maxW, int flags) : WordWrapper(str, maxW, flags), drawer_(drawer) { - } + TextDrawerWordWrapper(TextDrawer *drawer, const char *str, float maxW, int flags) + : WordWrapper(str, maxW, flags), drawer_(drawer) {} protected: float MeasureWidth(const char *str, size_t bytes) override; diff --git a/ext/native/gfx_es2/draw_text_android.cpp b/Common/Render/Text/draw_text_android.cpp similarity index 90% rename from ext/native/gfx_es2/draw_text_android.cpp rename to Common/Render/Text/draw_text_android.cpp index 608d0cfa0d..7e6a66d85f 100644 --- a/ext/native/gfx_es2/draw_text_android.cpp +++ b/Common/Render/Text/draw_text_android.cpp @@ -1,15 +1,14 @@ -#include "base/display.h" -#include "base/logging.h" -#include "base/stringutil.h" -#include "thin3d/thin3d.h" -#include "util/hash/hash.h" -#include "util/text/wrap_text.h" -#include "util/text/utf8.h" -#include "gfx_es2/draw_text.h" -#include "gfx_es2/draw_text_android.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Hash/Hash.h" +#include "Common/Data/Text/WrapText.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Render/Text/draw_text.h" +#include "Common/Render/Text/draw_text_android.h" #include "android/jni/app-android.h" -#include #if PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__) @@ -24,10 +23,10 @@ TextDrawerAndroid::TextDrawerAndroid(Draw::DrawContext *draw) : TextDrawer(draw) method_measureText = env->GetStaticMethodID(cls_textRenderer, "measureText", "(Ljava/lang/String;D)I"); method_renderText = env->GetStaticMethodID(cls_textRenderer, "renderText", "(Ljava/lang/String;D)[I"); } else { - ELOG("Failed to find class: '%s'", textRendererClassName); + ERROR_LOG(G3D, "Failed to find class: '%s'", textRendererClassName); } dpiScale_ = CalculateDPIScale(); - ILOG("Initializing TextDrawerAndroid with DPI scale %f", dpiScale_); + INFO_LOG(G3D, "Initializing TextDrawerAndroid with DPI scale %f", dpiScale_); } TextDrawerAndroid::~TextDrawerAndroid() { @@ -68,7 +67,7 @@ void TextDrawerAndroid::SetFont(uint32_t fontHandle) { if (iter != fontMap_.end()) { fontHash_ = fontHandle; } else { - ELOG("Invalid font handle %08x", fontHandle); + ERROR_LOG(G3D, "Invalid font handle %08x", fontHandle); } } @@ -88,7 +87,7 @@ void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, flo if (iter != fontMap_.end()) { scaledSize = iter->second.size; } else { - ELOG("Missing font"); + ERROR_LOG(G3D, "Missing font"); } std::string text(NormalizeString(std::string(str, len))); auto env = getEnv(); @@ -112,7 +111,7 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou if (iter != fontMap_.end()) { scaledSize = iter->second.size; } else { - ELOG("Missing font"); + ERROR_LOG(G3D, "Missing font"); } std::string toMeasure = std::string(str, len); @@ -168,7 +167,7 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS if (iter != fontMap_.end()) { size = iter->second.size; } else { - ELOG("Missing font"); + ERROR_LOG(G3D, "Missing font"); } auto env = getEnv(); @@ -192,7 +191,7 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS entry.lastUsedFrame = frameCount_; jint *jimage = env->GetIntArrayElements(imageData, nullptr); - assert(env->GetArrayLength(imageData) == imageWidth * imageHeight); + _assert_(env->GetArrayLength(imageData) == imageWidth * imageHeight); if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; @@ -213,8 +212,7 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS } } } else { - ELOG("Bad TextDrawer format"); - assert(false); + _assert_msg_(false, "Bad TextDrawer format"); } env->ReleaseIntArrayElements(imageData, jimage, 0); env->DeleteLocalRef(imageData); @@ -285,7 +283,7 @@ void TextDrawerAndroid::OncePerFrame() { float newDpiScale = CalculateDPIScale(); if (newDpiScale != dpiScale_) { // TODO: Don't bother if it's a no-op (cache already empty) - ILOG("DPI Scale changed (%f to %f) - wiping font cache (%d items, %d fonts)", dpiScale_, newDpiScale, (int)cache_.size(), (int)fontMap_.size()); + INFO_LOG(G3D, "DPI Scale changed (%f to %f) - wiping font cache (%d items, %d fonts)", dpiScale_, newDpiScale, (int)cache_.size(), (int)fontMap_.size()); dpiScale_ = newDpiScale; ClearCache(); fontMap_.clear(); // size is precomputed using dpiScale_. diff --git a/ext/native/gfx_es2/draw_text_android.h b/Common/Render/Text/draw_text_android.h similarity index 97% rename from ext/native/gfx_es2/draw_text_android.h rename to Common/Render/Text/draw_text_android.h index 51e5a3ab82..4b95bdeb75 100644 --- a/ext/native/gfx_es2/draw_text_android.h +++ b/Common/Render/Text/draw_text_android.h @@ -3,7 +3,7 @@ #include "ppsspp_config.h" #include -#include "gfx_es2/draw_text.h" +#include "Common/Render/Text/draw_text.h" #if PPSSPP_PLATFORM(ANDROID) diff --git a/ext/native/gfx_es2/draw_text_qt.cpp b/Common/Render/Text/draw_text_qt.cpp similarity index 93% rename from ext/native/gfx_es2/draw_text_qt.cpp rename to Common/Render/Text/draw_text_qt.cpp index 6589bf0743..ce0600cb81 100644 --- a/ext/native/gfx_es2/draw_text_qt.cpp +++ b/Common/Render/Text/draw_text_qt.cpp @@ -1,16 +1,16 @@ -#include -#include "base/display.h" -#include "base/logging.h" -#include "base/stringutil.h" -#include "thin3d/thin3d.h" -#include "util/hash/hash.h" -#include "util/text/wrap_text.h" -#include "util/text/utf8.h" -#include "gfx_es2/draw_text.h" -#include "gfx_es2/draw_text_qt.h" +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Hash/Hash.h" +#include "Common/Data/Text/WrapText.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Render/Text/draw_text.h" +#include "Common/Render/Text/draw_text_qt.h" + +#include "Common/Log.h" #if defined(USING_QT_UI) +#include #include #include #include @@ -47,7 +47,7 @@ void TextDrawerQt::SetFont(uint32_t fontHandle) { if (iter != fontMap_.end()) { fontHash_ = fontHandle; } else { - ELOG("Invalid font handle %08x", fontHandle); + ERROR_LOG(G3D, "Invalid font handle %08x", fontHandle); } } @@ -134,8 +134,7 @@ void TextDrawerQt::DrawStringBitmap(std::vector &bitmapData, TextString } } } else { - ELOG("Bad TextDrawer format"); - assert(false); + _assert_msg_(false, "Bad TextDrawer format"); } } diff --git a/ext/native/gfx_es2/draw_text_qt.h b/Common/Render/Text/draw_text_qt.h similarity index 95% rename from ext/native/gfx_es2/draw_text_qt.h rename to Common/Render/Text/draw_text_qt.h index c75cd51ca0..47fb8ab48f 100644 --- a/ext/native/gfx_es2/draw_text_qt.h +++ b/Common/Render/Text/draw_text_qt.h @@ -3,10 +3,12 @@ #include "ppsspp_config.h" #include -#include "gfx_es2/draw_text.h" +#include "Common/Render/Text/draw_text.h" #if defined(USING_QT_UI) +class QFont; + class TextDrawerQt : public TextDrawer { public: TextDrawerQt(Draw::DrawContext *draw); diff --git a/ext/native/gfx_es2/draw_text_uwp.cpp b/Common/Render/Text/draw_text_uwp.cpp similarity index 66% rename from ext/native/gfx_es2/draw_text_uwp.cpp rename to Common/Render/Text/draw_text_uwp.cpp index 52183a5c40..7ec375ae54 100644 --- a/ext/native/gfx_es2/draw_text_uwp.cpp +++ b/Common/Render/Text/draw_text_uwp.cpp @@ -1,13 +1,13 @@ -#include "base/display.h" -#include "base/logging.h" -#include "base/stringutil.h" -#include "thin3d/thin3d.h" -#include "util/hash/hash.h" -#include "util/text/wrap_text.h" -#include "util/text/utf8.h" -#include "gfx_es2/draw_text.h" -#include "gfx_es2/draw_text_uwp.h" +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Hash/Hash.h" +#include "Common/Data/Text/WrapText.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Render/Text/draw_text.h" +#include "Common/Render/Text/draw_text_uwp.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" #if PPSSPP_PLATFORM(UWP) @@ -71,7 +71,7 @@ TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(n IDXGIDevice* dxgiDevice; hr = d3ddevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); - if (FAILED(hr)) FLOG("ID3DDevice QueryInterface IDXGIDevice failed"); + if (FAILED(hr)) _assert_msg_(false, "ID3DDevice QueryInterface IDXGIDevice failed"); // Initialize the Direct2D Factory. D2D1_FACTORY_OPTIONS options = {}; @@ -92,15 +92,15 @@ TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(n // Create D2D Device and DeviceContext. // TODO: We have one sitting right in DX::DeviceResource, there might be a way to use that instead. hr = m_d2dFactory->CreateDevice(dxgiDevice, &m_d2dDevice); - if (FAILED(hr)) FLOG("D2D CreateDevice failed"); + if (FAILED(hr)) _assert_msg_(false, "D2D CreateDevice failed"); hr = m_d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &m_d2dContext); - if (FAILED(hr)) FLOG("D2D CreateDeviceContext failed"); + if (FAILED(hr)) _assert_msg_(false, "D2D CreateDeviceContext failed"); // Load the Roboto font hr = m_dwriteFactory->CreateFontFileReference(L"Content/Roboto-Condensed.ttf", nullptr, &m_fontFile); - if (FAILED(hr)) ELOG("CreateFontFileReference failed"); + if (FAILED(hr)) ERROR_LOG(SYSTEM, "CreateFontFileReference failed"); hr = m_dwriteFactory->CreateFontSetBuilder(&m_fontSetBuilder); - if (FAILED(hr)) ELOG("CreateFontSetBuilder failed"); + if (FAILED(hr)) ERROR_LOG(SYSTEM, "CreateFontSetBuilder failed"); hr = m_fontSetBuilder->AddFontFile(m_fontFile); hr = m_fontSetBuilder->CreateFontSet(&m_fontSet); hr = m_dwriteFactory->CreateFontCollectionFromFontSet(m_fontSet, &m_fontCollection); @@ -243,18 +243,22 @@ void TextDrawerUWP::MeasureString(const char *str, size_t len, float *w, float * } void TextDrawerUWP::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) { - - IDWriteTextFormat* format = nullptr; + IDWriteTextFormat *format = nullptr; auto iter = fontMap_.find(fontHash_); if (iter != fontMap_.end()) { format = iter->second->textFmt; } - if (!format) return; + if (!format) { + *w = 0; + *h = 0; + return; + } std::string toMeasure = std::string(str, len); - if (align & FLAG_WRAP_TEXT) { + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w); + WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); } std::vector lines; @@ -308,13 +312,130 @@ void TextDrawerUWP::MeasureStringRect(const char *str, size_t len, const Bounds *h = total_h * dpiScale_; } +void TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { + if (!strlen(str)) { + bitmapData.clear(); + return; + } + + std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(ReplaceAll(str, "\n", "\r\n"), "&&", "&")); + SIZE size; + + IDWriteTextFormat *format = nullptr; + auto iter = fontMap_.find(fontHash_); + if (iter != fontMap_.end()) { + format = iter->second->textFmt; + } + if (!format) { + bitmapData.clear(); + return; + } + + if (align & ALIGN_HCENTER) + format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); + else if (align & ALIGN_LEFT) + format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + else if (align & ALIGN_RIGHT) + format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING); + + IDWriteTextLayout *layout; + m_dwriteFactory->CreateTextLayout( + (LPWSTR)wstr.c_str(), + (int)wstr.size(), + format, + MAX_TEXT_WIDTH, + MAX_TEXT_HEIGHT, + &layout + ); + + DWRITE_TEXT_METRICS metrics; + layout->GetMetrics(&metrics); + + // Set the max size the same as current size, avoiding alignment issues + layout->SetMaxHeight(metrics.height); + layout->SetMaxWidth(metrics.width); + + size.cx = metrics.width + 1; + size.cy = metrics.height + 1; + + // Prevent zero-sized textures, which can occur. Not worth to avoid + // creating the texture altogether in this case. One example is a string + // containing only '\r\n', see issue #10764. + if (size.cx == 0) + size.cx = 1; + if (size.cy == 0) + size.cy = 1; + + entry.texture = nullptr; + entry.width = size.cx; + entry.height = size.cy; + entry.bmWidth = (size.cx + 3) & ~3; + entry.bmHeight = (size.cy + 3) & ~3; + entry.lastUsedFrame = frameCount_; + + m_d2dContext->BeginDraw(); + m_d2dContext->Clear(); + m_d2dContext->DrawTextLayout(D2D1::Point2F(0.0f, 0.0f), layout, m_d2dWhiteBrush); + m_d2dContext->EndDraw(); + + layout->Release(); + + D2D1_POINT_2U dstP = D2D1::Point2U(0, 0); + D2D1_RECT_U srcR = D2D1::RectU(0, 0, entry.bmWidth, entry.bmHeight); + D2D1_MAPPED_RECT map; + ctx_->mirror_bmp->CopyFromBitmap(&dstP, ctx_->bitmap, &srcR); + ctx_->mirror_bmp->Map(D2D1_MAP_OPTIONS_READ, &map); + + // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format + // because we need white. Well, we could using swizzle, but not all our backends support that. + if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint32_t)); + uint32_t *bitmapData32 = (uint32_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)(map.bits[map.pitch * y + x * 4] & 0xff); + bitmapData32[entry.bmWidth * y + x] = (bAlpha << 24) | 0x00ffffff; + } + } + } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)((map.bits[map.pitch * y + x * 4] & 0xff) >> 4); + bitmapData16[entry.bmWidth * y + x] = (bAlpha) | 0xfff0; + } + } + } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)((map.bits[map.pitch * y + x * 4] & 0xff) >> 4); + bitmapData16[entry.bmWidth * y + x] = (bAlpha << 12) | 0x0fff; + } + } + } else if (texFormat == Draw::DataFormat::R8_UNORM) { + bitmapData.resize(entry.bmWidth * entry.bmHeight); + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)(map.bits[map.pitch * y + x * 4] & 0xff); + bitmapData[entry.bmWidth * y + x] = bAlpha; + } + } + } else { + _assert_msg_(false, "Bad TextDrawer format"); + } + + ctx_->mirror_bmp->Unmap(); +} + void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { using namespace Draw; if (!strlen(str)) return; CacheKey key{ std::string(str), fontHash_ }; - target.Flush(true); TextStringEntry *entry; @@ -323,74 +444,7 @@ void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, flo if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; - } - else { - // Render the string to our bitmap and save to a GL texture. - std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(ReplaceAll(str, "\n", "\r\n"), "&&", "&")); - SIZE size; - - IDWriteTextFormat* format = nullptr; - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - format = iter->second->textFmt; - } - if (!format) return; - - if (align & ALIGN_HCENTER) - format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); - else if (align & ALIGN_LEFT) - format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - else if (align & ALIGN_RIGHT) - format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING); - - IDWriteTextLayout* layout; - m_dwriteFactory->CreateTextLayout( - (LPWSTR)wstr.c_str(), - (int)wstr.size(), - format, - MAX_TEXT_WIDTH, - MAX_TEXT_HEIGHT, - &layout - ); - - DWRITE_TEXT_METRICS metrics; - layout->GetMetrics(&metrics); - - // Set the max size the same as current size, avoiding alignment issues - layout->SetMaxHeight(metrics.height); - layout->SetMaxWidth(metrics.width); - - size.cx = metrics.width + 1; - size.cy = metrics.height + 1; - - // Prevent zero-sized textures, which can occur. Not worth to avoid - // creating the texture altogether in this case. One example is a string - // containing only '\r\n', see issue #10764. - if (size.cx == 0) - size.cx = 1; - if (size.cy == 0) - size.cy = 1; - - entry = new TextStringEntry(); - entry->width = size.cx; - entry->height = size.cy; - entry->bmWidth = (size.cx + 3) & ~3; - entry->bmHeight = (size.cy + 3) & ~3; - entry->lastUsedFrame = frameCount_; - - m_d2dContext->BeginDraw(); - m_d2dContext->Clear(); - m_d2dContext->DrawTextLayout(D2D1::Point2F(0.0f, 0.0f), layout, m_d2dWhiteBrush); - m_d2dContext->EndDraw(); - - layout->Release(); - - D2D1_POINT_2U dstP = D2D1::Point2U(0, 0); - D2D1_RECT_U srcR = D2D1::RectU(0, 0, entry->bmWidth, entry->bmHeight); - D2D1_MAPPED_RECT map; - ctx_->mirror_bmp->CopyFromBitmap(&dstP, ctx_->bitmap, &srcR); - ctx_->mirror_bmp->Map(D2D1_MAP_OPTIONS_READ, &map); - + } else { DataFormat texFormat; // For our purposes these are equivalent, so just choose the supported one. D3D can emulate them. if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) @@ -400,41 +454,14 @@ void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, flo else texFormat = Draw::DataFormat::R8G8B8A8_UNORM; + entry = new TextStringEntry(); + // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format // because we need white. Well, we could using swizzle, but not all our backends support that. TextureDesc desc{}; - uint32_t *bitmapData32 = nullptr; - uint16_t *bitmapData16 = nullptr; - if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { - bitmapData32 = new uint32_t[entry->bmWidth * entry->bmHeight]; - for (int y = 0; y < entry->bmHeight; y++) { - for (int x = 0; x < entry->bmWidth; x++) { - uint8_t bAlpha = (uint8_t)(map.bits[map.pitch * y + x * 4] & 0xff); - bitmapData32[entry->bmWidth * y + x] = (bAlpha << 24) | 0x00ffffff; - } - } - desc.initData.push_back((uint8_t *)bitmapData32); - } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16) { - bitmapData16 = new uint16_t[entry->bmWidth * entry->bmHeight]; - for (int y = 0; y < entry->bmHeight; y++) { - for (int x = 0; x < entry->bmWidth; x++) { - uint8_t bAlpha = (uint8_t)((map.bits[map.pitch * y + x * 4] & 0xff) >> 4); - bitmapData16[entry->bmWidth * y + x] = (bAlpha) | 0xfff0; - } - } - desc.initData.push_back((uint8_t *)bitmapData16); - } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) { - bitmapData16 = new uint16_t[entry->bmWidth * entry->bmHeight]; - for (int y = 0; y < entry->bmHeight; y++) { - for (int x = 0; x < entry->bmWidth; x++) { - uint8_t bAlpha = (uint8_t)((map.bits[map.pitch * y + x * 4] & 0xff) >> 4); - bitmapData16[entry->bmWidth * y + x] = (bAlpha << 12) | 0x0fff; - } - } - desc.initData.push_back((uint8_t *)bitmapData16); - } - - ctx_->mirror_bmp->Unmap(); + std::vector bitmapData; + DrawStringBitmap(bitmapData, *entry, texFormat, str, align); + desc.initData.push_back(&bitmapData[0]); desc.type = TextureType::LINEAR2D; desc.format = texFormat; @@ -444,14 +471,12 @@ void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, flo desc.mipLevels = 1; desc.tag = "TextDrawer"; entry->texture = draw_->CreateTexture(desc); - if (bitmapData16) - delete[] bitmapData16; - if (bitmapData32) - delete[] bitmapData32; cache_[key] = std::unique_ptr(entry); } - draw_->BindTexture(0, entry->texture); + if (entry->texture) { + draw_->BindTexture(0, entry->texture); + } // Okay, the texture is bound, let's draw. float w = entry->width * fontScaleX_ * dpiScale_; @@ -459,13 +484,14 @@ void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, flo float u = entry->width / (float)entry->bmWidth; float v = entry->height / (float)entry->bmHeight; DrawBuffer::DoAlign(align, &x, &y, &w, &h); - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, u, v, color); - target.Flush(true); - + if (entry->texture) { + target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, u, v, color); + target.Flush(true); + } } void TextDrawerUWP::RecreateFonts() { - for (auto& iter : fontMap_) { + for (auto &iter : fontMap_) { iter.second->dpiScale = dpiScale_; iter.second->Create(); } @@ -480,29 +506,6 @@ void TextDrawerUWP::ClearCache() { sizeCache_.clear(); } -void TextDrawerUWP::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) { - float x = bounds.x; - float y = bounds.y; - if (align & ALIGN_HCENTER) { - x = bounds.centerX(); - } else if (align & ALIGN_RIGHT) { - x = bounds.x2(); - } - if (align & ALIGN_VCENTER) { - y = bounds.centerY(); - } else if (align & ALIGN_BOTTOM) { - y = bounds.y2(); - } - - std::string toDraw = str; - if (align & FLAG_WRAP_TEXT) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toDraw, str, rotated ? bounds.h : bounds.w); - } - - DrawString(target, toDraw.c_str(), x, y, color, align); -} - void TextDrawerUWP::OncePerFrame() { frameCount_++; // If DPI changed (small-mode, future proper monitor DPI support), drop everything. diff --git a/ext/native/gfx_es2/draw_text_uwp.h b/Common/Render/Text/draw_text_uwp.h similarity index 89% rename from ext/native/gfx_es2/draw_text_uwp.h rename to Common/Render/Text/draw_text_uwp.h index 0697ea62d6..816ae7ec06 100644 --- a/ext/native/gfx_es2/draw_text_uwp.h +++ b/Common/Render/Text/draw_text_uwp.h @@ -3,7 +3,7 @@ #include "ppsspp_config.h" #include -#include "gfx_es2/draw_text.h" +#include "Common/Render/Text/draw_text.h" #if PPSSPP_PLATFORM(UWP) @@ -24,7 +24,7 @@ public: void MeasureString(const char *str, size_t len, float *w, float *h) override; void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) override; + void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; // Use for housekeeping like throwing out old strings. void OncePerFrame() override; diff --git a/ext/native/gfx_es2/draw_text_win.cpp b/Common/Render/Text/draw_text_win.cpp similarity index 97% rename from ext/native/gfx_es2/draw_text_win.cpp rename to Common/Render/Text/draw_text_win.cpp index 2570236feb..e7518857ef 100644 --- a/ext/native/gfx_es2/draw_text_win.cpp +++ b/Common/Render/Text/draw_text_win.cpp @@ -1,13 +1,13 @@ -#include -#include "base/display.h" -#include "base/logging.h" -#include "base/stringutil.h" -#include "thin3d/thin3d.h" -#include "util/hash/hash.h" -#include "util/text/wrap_text.h" -#include "util/text/utf8.h" -#include "gfx_es2/draw_text.h" -#include "gfx_es2/draw_text_win.h" +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Hash/Hash.h" +#include "Common/Data/Text/WrapText.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Render/Text/draw_text.h" +#include "Common/Render/Text/draw_text_win.h" + +#include "Common/Log.h" +#include "Common/StringUtils.h" #if defined(_WIN32) && !defined(USING_QT_UI) && !PPSSPP_PLATFORM(UWP) @@ -286,8 +286,7 @@ void TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStr } } } else { - ELOG("Bad TextDrawer format"); - assert(false); + _assert_msg_(false, "Bad TextDrawer format"); } } diff --git a/ext/native/gfx_es2/draw_text_win.h b/Common/Render/Text/draw_text_win.h similarity index 97% rename from ext/native/gfx_es2/draw_text_win.h rename to Common/Render/Text/draw_text_win.h index 41489eefbb..c59fa91db4 100644 --- a/ext/native/gfx_es2/draw_text_win.h +++ b/Common/Render/Text/draw_text_win.h @@ -3,7 +3,7 @@ #include "ppsspp_config.h" #include -#include "gfx_es2/draw_text.h" +#include "Common/Render/Text/draw_text.h" #if defined(_WIN32) && !defined(USING_QT_UI) && !PPSSPP_PLATFORM(UWP) diff --git a/ext/native/gfx/texture_atlas.cpp b/Common/Render/TextureAtlas.cpp similarity index 97% rename from ext/native/gfx/texture_atlas.cpp rename to Common/Render/TextureAtlas.cpp index 1622b3a42b..285f766892 100644 --- a/ext/native/gfx/texture_atlas.cpp +++ b/Common/Render/TextureAtlas.cpp @@ -1,7 +1,7 @@ #include #include -#include "base/logging.h" -#include "gfx/texture_atlas.h" + +#include "Common/Render/TextureAtlas.h" class ByteReader { public: diff --git a/ext/native/gfx/texture_atlas.h b/Common/Render/TextureAtlas.h similarity index 100% rename from ext/native/gfx/texture_atlas.h rename to Common/Render/TextureAtlas.h diff --git a/Common/stdafx.h b/Common/Serialize/SerializeDeque.h similarity index 57% rename from Common/stdafx.h rename to Common/Serialize/SerializeDeque.h index 1f18c24ec4..d0dc8adbb0 100644 --- a/Common/stdafx.h +++ b/Common/Serialize/SerializeDeque.h @@ -17,26 +17,28 @@ #pragma once -#ifdef _WIN32 -#ifndef _WIN32_WINNT +// Templates for save state serialization. See Serializer.h. +#include +#include "Common/Serialize/SerializeFuncs.h" -#if defined(_MSC_VER) && _MSC_VER < 1700 -#error You need a newer version of Visual Studio. -#else -#define _WIN32_WINNT 0x601 -#endif +template +void DoDeque(PointerWrap &p, std::deque &x, T &default_val) { + u32 deq_size = (u32)x.size(); + Do(p, deq_size); + x.resize(deq_size, default_val); + u32 i; + for (i = 0; i < deq_size; i++) + Do(p, x[i]); +} -#endif // #ifndef _WIN32_WINNT +template +void Do(PointerWrap &p, std::deque &x) { + T *dv = nullptr; + DoDeque(p, x, dv); +} -#undef WINVER -#define WINVER _WIN32_WINNT -#ifndef _WIN32_IE -#define _WIN32_IE 0x0600 // Default value is 0x0400 -#endif - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include "CommonWindows.h" -#include -#include -#endif +template +void Do(PointerWrap &p, std::deque &x) { + T dv = T(); + DoDeque(p, x, dv); +} diff --git a/Common/Serialize/SerializeFuncs.h b/Common/Serialize/SerializeFuncs.h new file mode 100644 index 0000000000..3080749fa3 --- /dev/null +++ b/Common/Serialize/SerializeFuncs.h @@ -0,0 +1,128 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +// Templates for save state serialization. See Serializer.h. +#include +#include +#include "Common/Serialize/Serializer.h" +#include "Common/Swap.h" + +void Do(PointerWrap &p, std::string &x); +void Do(PointerWrap &p, std::wstring &x); // DEPRECATED, do not save wstrings +void Do(PointerWrap &p, std::u16string &x); + +void Do(PointerWrap &p, tm &t); + +// Don't use DoHelper_ directly. Just use Do(). + +// This makes it a compile error if you forget to define DoState() on non-POD. +// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... +#ifdef _MSC_VER +template::value, bool isPointer = std::is_pointer::value> +#else +template::value> +#endif +struct DoHelper_ { + static void DoArray(PointerWrap &p, T *x, int count) { + for (int i = 0; i < count; ++i) + Do(p, x[i]); + } + + static void DoThing(PointerWrap &p, T &x) { + DoClass(p, x); + } +}; + +template +struct DoHelper_ { + static void DoArray(PointerWrap &p, T *x, int count) { + p.DoVoid((void *)x, sizeof(T) * count); + } + + static void DoThing(PointerWrap &p, T &x) { + p.DoVoid((void *)&x, sizeof(x)); + } +}; + +template +void DoClass(PointerWrap &p, T &x) { + x.DoState(p); +} + +template +void DoClass(PointerWrap &p, T *&x) { + if (p.mode == PointerWrap::MODE_READ) { + if (x != nullptr) + delete x; + x = new T(); + } + x->DoState(p); +} + +template +void DoArray(PointerWrap &p, T *x, int count) { + DoHelper_::DoArray(p, x, count); +} + +template +void Do(PointerWrap &p, T &x) { + DoHelper_::DoThing(p, x); +} + +template +void DoVector(PointerWrap &p, std::vector &x, T &default_val) { + u32 vec_size = (u32)x.size(); + Do(p, vec_size); + x.resize(vec_size, default_val); + if (vec_size > 0) + DoArray(p, &x[0], vec_size); +} + +template +void Do(PointerWrap &p, std::vector &x) { + T *dv = nullptr; + DoVector(p, x, dv); +} + +template +void Do(PointerWrap &p, std::vector &x) { + T dv = T(); + DoVector(p, x, dv); +} + +template +void Do(PointerWrap &p, std::vector &x, T &default_val) { + DoVector(p, x, default_val); +} + +template +void Do(PointerWrap &p, swap_struct_t &x) { + T v = x.swap(); + Do(p, v); + x = v; +} + +template +void DoPointer(PointerWrap &p, T *&x, T *const base) { + // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range + s32 offset = x - base; + Do(p, offset); + if (p.mode == PointerWrap::MODE_READ) + x = base + offset; +} diff --git a/Common/Serialize/SerializeList.h b/Common/Serialize/SerializeList.h new file mode 100644 index 0000000000..ff4ed57a9a --- /dev/null +++ b/Common/Serialize/SerializeList.h @@ -0,0 +1,101 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +// Templates for save state serialization. See Serializer.h. +#include +#include "Common/Serialize/SerializeFuncs.h" + +template +void DoList(PointerWrap &p, std::list &x, T &default_val) { + u32 list_size = (u32)x.size(); + Do(p, list_size); + x.resize(list_size, default_val); + + typename std::list::iterator itr, end; + for (itr = x.begin(), end = x.end(); itr != end; ++itr) + Do(p, *itr); +} + +template +void Do(PointerWrap &p, std::list &x) { + T *dv = nullptr; + Do(p, x, dv); +} + +template +void Do(PointerWrap &p, std::list &x) { + T dv = T(); + DoList(p, x, dv); +} + +template +void Do(PointerWrap &p, std::list &x, T &default_val) { + DoList(p, x, default_val); +} + +template *(*TNew)(), void (*TFree)(LinkedListItem *), void (*TDo)(PointerWrap &, T *)> +void DoLinkedList(PointerWrap &p, LinkedListItem *&list_start, LinkedListItem **list_end = nullptr) { + LinkedListItem *list_cur = list_start; + LinkedListItem *prev = nullptr; + + while (true) { + u8 shouldExist = (list_cur ? 1 : 0); + Do(p, shouldExist); + if (shouldExist == 1) { + LinkedListItem *cur = list_cur ? list_cur : TNew(); + TDo(p, (T *)cur); + if (!list_cur) { + if (p.mode == PointerWrap::MODE_READ) { + cur->next = 0; + list_cur = cur; + if (prev) + prev->next = cur; + else + list_start = cur; + } else { + TFree(cur); + continue; + } + } + } else { + if (shouldExist != 0) { + WARN_LOG(SAVESTATE, "Savestate failure: incorrect item marker %d", shouldExist); + p.SetError(p.ERROR_FAILURE); + } + if (p.mode == PointerWrap::MODE_READ) { + if (prev) + prev->next = nullptr; + if (list_end) + *list_end = prev; + if (list_cur) { + if (list_start == list_cur) + list_start = nullptr; + do { + LinkedListItem *next = list_cur->next; + TFree(list_cur); + list_cur = next; + } while (list_cur); + } + } + break; + } + prev = list_cur; + list_cur = list_cur->next; + } +} diff --git a/Common/Serialize/SerializeMap.h b/Common/Serialize/SerializeMap.h new file mode 100644 index 0000000000..9190f5067e --- /dev/null +++ b/Common/Serialize/SerializeMap.h @@ -0,0 +1,164 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +// Templates for save state serialization. See Serializer.h. +#include +#include +#include "Common/Serialize/SerializeFuncs.h" + +template +void DoMap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { + unsigned int number = (unsigned int)x.size(); + Do(p, number); + switch (p.mode) { + case PointerWrap::MODE_READ: + { + x.clear(); + while (number > 0) { + typename M::key_type first = typename M::key_type(); + Do(p, first); + typename M::mapped_type second = default_val; + Do(p, second); + x[first] = second; + --number; + } + } + break; + case PointerWrap::MODE_WRITE: + case PointerWrap::MODE_MEASURE: + case PointerWrap::MODE_VERIFY: + { + typename M::iterator itr = x.begin(); + while (number > 0) { + typename M::key_type first = itr->first; + Do(p, first); + Do(p, itr->second); + --number; + ++itr; + } + } + break; + } +} + +template +void Do(PointerWrap &p, std::map &x) { + if (p.mode == PointerWrap::MODE_READ) { + for (auto it = x.begin(), end = x.end(); it != end; ++it) { + if (it->second != nullptr) + delete it->second; + } + } + T *dv = nullptr; + DoMap(p, x, dv); +} + +template +void Do(PointerWrap &p, std::map &x) { + T dv = T(); + DoMap(p, x, dv); +} + +template +void Do(PointerWrap &p, std::unordered_map &x) { + if (p.mode == PointerWrap::MODE_READ) { + for (auto it = x.begin(), end = x.end(); it != end; ++it) { + if (it->second != nullptr) + delete it->second; + } + } + T *dv = nullptr; + DoMap(p, x, dv); +} + +template +void Do(PointerWrap &p, std::unordered_map &x) { + T dv = T(); + DoMap(p, x, dv); +} + +template +void DoMultimap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { + unsigned int number = (unsigned int)x.size(); + Do(p, number); + switch (p.mode) { + case PointerWrap::MODE_READ: + { + x.clear(); + while (number > 0) { + typename M::key_type first = typename M::key_type(); + Do(p, first); + typename M::mapped_type second = default_val; + Do(p, second); + x.insert(std::make_pair(first, second)); + --number; + } + } + break; + case PointerWrap::MODE_WRITE: + case PointerWrap::MODE_MEASURE: + case PointerWrap::MODE_VERIFY: + { + typename M::iterator itr = x.begin(); + while (number > 0) { + Do(p, itr->first); + Do(p, itr->second); + --number; + ++itr; + } + } + break; + } +} + +template +void Do(PointerWrap &p, std::multimap &x) { + if (p.mode == PointerWrap::MODE_READ) { + for (auto it = x.begin(), end = x.end(); it != end; ++it) { + if (it->second != nullptr) + delete it->second; + } + } + T *dv = nullptr; + DoMultimap(p, x, dv); +} + +template +void Do(PointerWrap &p, std::multimap &x) { + T dv = T(); + DoMultimap(p, x, dv); +} + +template +void Do(PointerWrap &p, std::unordered_multimap &x) { + if (p.mode == PointerWrap::MODE_READ) { + for (auto it = x.begin(), end = x.end(); it != end; ++it) { + if (it->second != nullptr) + delete it->second; + } + } + T *dv = nullptr; + DoMultimap(p, x, dv); +} + +template +void Do(PointerWrap &p, std::unordered_multimap &x) { + T dv = T(); + DoMultimap(p, x, dv); +} diff --git a/Common/Serialize/SerializeSet.h b/Common/Serialize/SerializeSet.h new file mode 100644 index 0000000000..7e22f21e56 --- /dev/null +++ b/Common/Serialize/SerializeSet.h @@ -0,0 +1,69 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +// Templates for save state serialization. See Serializer.h. +#include +#include "Common/Serialize/SerializeFuncs.h" + +template +void DoSet(PointerWrap &p, std::set &x) { + unsigned int number = (unsigned int)x.size(); + Do(p, number); + + switch (p.mode) { + case PointerWrap::MODE_READ: + { + x.clear(); + while (number-- > 0) { + T it = T(); + Do(p, it); + x.insert(it); + } + } + break; + case PointerWrap::MODE_WRITE: + case PointerWrap::MODE_MEASURE: + case PointerWrap::MODE_VERIFY: + { + typename std::set::iterator itr = x.begin(); + while (number-- > 0) + Do(p, *itr++); + } + break; + + default: + ERROR_LOG(SAVESTATE, "Savestate error: invalid mode %d.", p.mode); + } +} + +template +void Do(PointerWrap &p, std::set &x) { + if (p.mode == PointerWrap::MODE_READ) { + for (auto it = x.begin(), end = x.end(); it != end; ++it) { + if (*it != nullptr) + delete *it; + } + } + DoSet(p, x); +} + +template +void Do(PointerWrap &p, std::set &x) { + DoSet(p, x); +} diff --git a/Common/ChunkFile.cpp b/Common/Serialize/Serializer.cpp similarity index 77% rename from Common/ChunkFile.cpp rename to Common/Serialize/Serializer.cpp index 8334e9b5a7..4738b829f3 100644 --- a/Common/ChunkFile.cpp +++ b/Common/Serialize/Serializer.cpp @@ -19,8 +19,10 @@ #include #include -#include "ChunkFile.h" -#include "StringUtils.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/File/FileUtil.h" +#include "Common/StringUtils.h" PointerWrapSection PointerWrap::Section(const char *title, int ver) { return Section(title, ver, ver); @@ -30,23 +32,26 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) char marker[16] = {0}; int foundVersion = ver; - // This is strncpy because we rely on its weird non-null-terminating truncation behaviour. + // This is strncpy because we rely on its weird non-null-terminating zero-filling truncation behaviour. // Can't replace it with the more sensible truncate_cpy because that would break savestates. strncpy(marker, title, sizeof(marker)); - if (!ExpectVoid(marker, sizeof(marker))) - { + if (!ExpectVoid(marker, sizeof(marker))) { // Might be before we added name markers for safety. - if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) + if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) { DoMarker(title); - // Wasn't found, but maybe we can still load the state. - else + } else { + // Wasn't found, but maybe we can still load the state. foundVersion = 0; + } + } else { + Do(*this, foundVersion); } - else - Do(foundVersion); if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { - WARN_LOG(SAVESTATE, "Savestate failure: wrong version %d found for %s", foundVersion, title); + if (!firstBadSectionTitle_) { + firstBadSectionTitle_ = title; + } + WARN_LOG(SAVESTATE, "Savestate failure: wrong version %d found for section '%s'", foundVersion, title); SetError(ERROR_FAILURE); return PointerWrapSection(*this, -1, title); } @@ -58,6 +63,7 @@ void PointerWrap::SetError(Error error_) { error = error_; } if (error > ERROR_WARNING) { + // For the rest of this run, just measure. mode = PointerWrap::MODE_MEASURE; } } @@ -69,7 +75,7 @@ bool PointerWrap::ExpectVoid(void *data, int size) { case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything case MODE_VERIFY: for (int i = 0; i < size; i++) - _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); + _dbg_assert_msg_(((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; default: break; // throw an error? } @@ -84,50 +90,50 @@ void PointerWrap::DoVoid(void *data, int size) { case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything case MODE_VERIFY: for (int i = 0; i < size; i++) - _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); + _dbg_assert_msg_(((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; default: break; // throw an error? } (*ptr) += size; } -void PointerWrap::Do(std::string &x) { +void Do(PointerWrap &p, std::string &x) { int stringLen = (int)x.length() + 1; - Do(stringLen); + Do(p, stringLen); - switch (mode) { - case MODE_READ: x = (char*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break; + switch (p.mode) { + case PointerWrap::MODE_READ: x = (char*)*p.ptr; break; + case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; + case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(!strcmp(x.c_str(), (char*)*p.ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char *)*p.ptr, p.ptr); break; } - (*ptr) += stringLen; + (*p.ptr) += stringLen; } -void PointerWrap::Do(std::wstring &x) { +void Do(PointerWrap &p, std::wstring &x) { int stringLen = sizeof(wchar_t)*((int)x.length() + 1); - Do(stringLen); + Do(p, stringLen); - switch (mode) { - case MODE_READ: x = (wchar_t*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break; + switch (p.mode) { + case PointerWrap::MODE_READ: x = (wchar_t*)*p.ptr; break; + case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; + case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(x == (wchar_t*)*p.ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*p.ptr, p.ptr); break; } - (*ptr) += stringLen; + (*p.ptr) += stringLen; } -void PointerWrap::Do(std::u16string &x) { +void Do(PointerWrap &p, std::u16string &x) { int stringLen = sizeof(char16_t) * ((int)x.length() + 1); - Do(stringLen); + Do(p, stringLen); - switch (mode) { - case MODE_READ: x = (char16_t*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (char16_t*)*ptr, "Savestate verification failure: (at %p).\n", x.c_str()); break; + switch (p.mode) { + case PointerWrap::MODE_READ: x = (char16_t*)*p.ptr; break; + case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; + case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(x == (char16_t*)*p.ptr, "Savestate verification failure: (at %p).\n", x.c_str()); break; } - (*ptr) += stringLen; + (*p.ptr) += stringLen; } struct standard_tm { @@ -142,33 +148,33 @@ struct standard_tm { int tm_isdst; }; -void PointerWrap::Do(tm &t) { +void Do(PointerWrap &p, tm &t) { // We savestate this separately because some platforms use extra data at the end. // However, old files may have the native tm in them. // Since the first value in the struct is 0-59, we save a funny value and check for it. // If our funny value ('tm' 0x1337) exists, it's a new version savestate. int funnyValue = 0x13376D74; - if (ExpectVoid(&funnyValue, sizeof(funnyValue))) { + if (p.ExpectVoid(&funnyValue, sizeof(funnyValue))) { standard_tm stm; - if (mode == MODE_READ) { + if (p.mode == PointerWrap::MODE_READ) { // Null out the extra members, e.g. tm_gmtoff or tm_zone. memset(&t, 0, sizeof(t)); } else { memcpy(&stm, &t, sizeof(stm)); } - DoVoid((void *)&stm, sizeof(stm)); + p.DoVoid((void *)&stm, sizeof(stm)); memcpy(&t, &stm, sizeof(stm)); } else { - DoVoid((void *)&t, sizeof(t)); + p.DoVoid((void *)&t, sizeof(t)); } } void PointerWrap::DoMarker(const char *prevName, u32 arbitraryNumber) { u32 cookie = arbitraryNumber; - Do(cookie); + Do(*this, cookie); if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) { - PanicAlert("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); + _assert_msg_(false, "Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); SetError(ERROR_FAILURE); } } diff --git a/Common/Serialize/Serializer.h b/Common/Serialize/Serializer.h new file mode 100644 index 0000000000..99d7a5c343 --- /dev/null +++ b/Common/Serialize/Serializer.h @@ -0,0 +1,253 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "ppsspp_config.h" + +// Extremely simple serialization framework. +// Currently mis-named, a native ChunkFile is something different (a RIFF file) + +// (mis)-features: +// + Super fast +// + Very simple +// + Same code is used for serialization and deserializaition (in most cases) +// + Sections can be versioned for backwards/forwards compatibility +// - Serialization code for anything complex has to be manually written. + +#include +#include +#include "Common/CommonTypes.h" +#include "Common/Log.h" + +namespace File { +class IOFile; +}; + +template +struct LinkedListItem : public T +{ + LinkedListItem *next; +}; + +class PointerWrap; + +class PointerWrapSection +{ +public: + PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { + } + ~PointerWrapSection(); + + bool operator == (const int &v) const { return ver_ == v; } + bool operator != (const int &v) const { return ver_ != v; } + bool operator <= (const int &v) const { return ver_ <= v; } + bool operator >= (const int &v) const { return ver_ >= v; } + bool operator < (const int &v) const { return ver_ < v; } + bool operator > (const int &v) const { return ver_ > v; } + + operator bool() const { + return ver_ > 0; + } + +private: + PointerWrap &p_; + int ver_; + const char *title_; +}; + +// Wrapper class +class PointerWrap +{ +public: + enum Mode { + MODE_READ = 1, // load + MODE_WRITE, // save + MODE_MEASURE, // calculate size + MODE_VERIFY, // compare + }; + + enum Error { + ERROR_NONE = 0, + ERROR_WARNING = 1, + ERROR_FAILURE = 2, + }; + + u8 **ptr; + Mode mode; + Error error = ERROR_NONE; + + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} + PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_) {} + + PointerWrapSection Section(const char *title, int ver); + + // The returned object can be compared against the version that was loaded. + // This can be used to support versions as old as minVer. + // Version = 0 means the section was not found. + PointerWrapSection Section(const char *title, int minVer, int ver); + + void SetMode(Mode mode_) {mode = mode_;} + Mode GetMode() const {return mode;} + u8 **GetPPtr() {return ptr;} + void SetError(Error error_); + + const char *GetBadSectionTitle() const { + return firstBadSectionTitle_; + } + + // Same as DoVoid, except doesn't advance pointer if it doesn't match on read. + bool ExpectVoid(void *data, int size); + void DoVoid(void *data, int size); + + void DoMarker(const char *prevName, u32 arbitraryNumber = 0x42); + +private: + const char *firstBadSectionTitle_ = nullptr; +}; + +class CChunkFileReader +{ +public: + enum Error { + ERROR_NONE, + ERROR_BAD_FILE, + ERROR_BROKEN_STATE, + ERROR_BAD_ALLOC, + }; + + // May fail badly if ptr doesn't point to valid data. + template + static Error LoadPtr(u8 *ptr, T &_class, std::string *errorString) + { + PointerWrap p(&ptr, PointerWrap::MODE_READ); + _class.DoState(p); + + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + *errorString = std::string("Failure at ") + p.GetBadSectionTitle(); + return ERROR_BROKEN_STATE; + } + } + + template + static size_t MeasurePtr(T &_class) + { + u8 *ptr = 0; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + return (size_t)ptr; + } + + // Expects ptr to have at least MeasurePtr bytes at ptr. + template + static Error SavePtr(u8 *ptr, T &_class) + { + PointerWrap p(&ptr, PointerWrap::MODE_WRITE); + _class.DoState(p); + + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + return ERROR_BROKEN_STATE; + } + } + + // Load file template + template + static Error Load(const std::string &filename, std::string *gitVersion, T& _class, std::string *failureReason) + { + *failureReason = "LoadStateWrongVersion"; + + u8 *ptr = nullptr; + size_t sz; + Error error = LoadFile(filename, gitVersion, ptr, sz, failureReason); + if (error == ERROR_NONE) { + failureReason->clear(); + error = LoadPtr(ptr, _class, failureReason); + delete [] ptr; + INFO_LOG(SAVESTATE, "ChunkReader: Done loading '%s'", filename.c_str()); + } else { + WARN_LOG(SAVESTATE, "ChunkReader: Error found during load of '%s'", filename.c_str()); + } + return error; + } + + // Save file template + template + static Error Save(const std::string &filename, const std::string &title, const char *gitVersion, T& _class) + { + // Get data + size_t const sz = MeasurePtr(_class); + u8 *buffer = (u8 *)malloc(sz); + if (!buffer) + return ERROR_BAD_ALLOC; + Error error = SavePtr(buffer, _class); + + // SaveFile takes ownership of buffer + if (error == ERROR_NONE) + error = SaveFile(filename, title, gitVersion, buffer, sz); + return error; + } + + template + static Error Verify(T& _class) + { + u8 *ptr = 0; + + // Step 1: Measure the space required. + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + std::vector buffer(sz); + + // Step 2: Dump the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); + + // Step 3: Verify the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_VERIFY); + _class.DoState(p); + + return ERROR_NONE; + } + + static Error GetFileTitle(const std::string &filename, std::string *title); + +private: + struct SChunkHeader + { + int Revision; + int Compress; + u32 ExpectedSize; + u32 UncompressedSize; + char GitVersion[32]; + }; + + enum { + REVISION_MIN = 4, + REVISION_TITLE = 5, + REVISION_CURRENT = REVISION_TITLE, + }; + + static Error LoadFile(const std::string &filename, std::string *gitVersion, u8 *&buffer, size_t &sz, std::string *failureReason); + static Error SaveFile(const std::string &filename, const std::string &title, const char *gitVersion, u8 *buffer, size_t sz); + static Error LoadFileHeader(File::IOFile &pFile, SChunkHeader &header, std::string *title); +}; diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index c1289720b0..e812bad1b6 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -15,8 +15,35 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#include "Common.h" -#include "StringUtils.h" +#include + +#include "ppsspp_config.h" + +#ifdef _WIN32 +#include +#undef min +#undef max +#endif + +#if PPSSPP_PLATFORM(SWITCH) +#define _GNU_SOURCE +#include +#endif + +#include + +#include + +#include +#include +#include + +#include +#include + +#include "Common/Common.h" +#include "Common/Buffer.h" +#include "Common/StringUtils.h" void truncate_cpy(char *dest, size_t destSize, const char *src) { size_t len = strlen(src); @@ -38,6 +65,7 @@ long parseHexLong(std::string s) { value = strtoul(s.c_str(),0, 0); return value; } + long parseLong(std::string s) { long value = 0; if (s.substr(0,2) == "0x") { @@ -112,3 +140,179 @@ std::string GetFilenameFromPath(std::string full_path) { // No directory components, just return the full path. return full_path; } + +std::string LineNumberString(const std::string &str) { + std::stringstream input(str); + std::stringstream output; + std::string line; + + int lineNumber = 1; + while (std::getline(input, line)) { + output << std::setw(4) << lineNumber++ << ": " << line << std::endl; + } + + return output.str(); +} + +void SkipSpace(const char **ptr) { + while (**ptr && isspace(**ptr)) { + (*ptr)++; + } +} + +void DataToHexString(const uint8_t *data, size_t size, std::string *output) { + Buffer buffer; + for (size_t i = 0; i < size; i++) { + if (i && !(i & 15)) + buffer.Printf("\n"); + buffer.Printf("%02x ", data[i]); + } + buffer.TakeAll(output); +} + +void DataToHexString(const char* prefix, uint32_t startAddr, const uint8_t* data, size_t size, std::string* output) { + Buffer buffer; + size_t i = 0; + for (; i < size; i++) { + if (i && !(i & 15)) { + buffer.Printf(" "); + for (size_t j = i - 16; j < i; j++) { + buffer.Printf("%c", ((data[j] < 0x20) || (data[j] > 0x7e)) ? 0x2e : data[j]); + } + buffer.Printf("\n"); + } + if (!(i & 15)) + buffer.Printf("%s%08x ", prefix, startAddr + i); + buffer.Printf("%02x ", data[i]); + } + if (size & 15) { + size_t padded_size = ((size - 1) | 15) + 1; + for (size_t j = size; j < padded_size; j++) { + buffer.Printf(" "); + } + buffer.Printf(" "); + for (size_t j = size & ~UINT64_C(0xF); j < size; j++) { + buffer.Printf("%c", ((data[j] < 0x20) || (data[j] > 0x7e)) ? 0x2e : data[j]); + } + } + buffer.TakeAll(output); +} + +std::string StringFromFormat(const char* format, ...) +{ + va_list args; + std::string temp = ""; +#ifdef _WIN32 + int required = 0; + + va_start(args, format); + required = _vscprintf(format, args); + // Using + 2 to be safe between MSVC versions. + // In MSVC 2015 and later, vsnprintf counts the trailing zero (per c++11.) + temp.resize(required + 2); + if (vsnprintf(&temp[0], required + 1, format, args) < 0) { + temp.resize(0); + } else { + temp.resize(required); + } + va_end(args); +#else + char *buf = nullptr; + + va_start(args, format); + if (vasprintf(&buf, format, args) < 0) + buf = nullptr; + va_end(args); + + if (buf != nullptr) { + temp = buf; + free(buf); + } +#endif + return temp; +} + +std::string StringFromInt(int value) +{ + char temp[16]; + sprintf(temp, "%i", value); + return temp; +} + +// Turns " hej " into "hej". Also handles tabs. +std::string StripSpaces(const std::string &str) +{ + const size_t s = str.find_first_not_of(" \t\r\n"); + + if (str.npos != s) + return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); + else + return ""; +} + +// "\"hello\"" is turned to "hello" +// This one assumes that the string has already been space stripped in both +// ends, as done by StripSpaces above, for example. +std::string StripQuotes(const std::string& s) +{ + if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) + return s.substr(1, s.size() - 2); + else + return s; +} + +void SplitString(const std::string& str, const char delim, std::vector& output) +{ + size_t next = 0; + for (size_t pos = 0, len = str.length(); pos < len; ++pos) { + if (str[pos] == delim) { + output.push_back(str.substr(next, pos - next)); + // Skip the delimiter itself. + next = pos + 1; + } + } + + if (next == 0) { + output.push_back(str); + } else if (next < str.length()) { + output.push_back(str.substr(next)); + } +} + +void GetQuotedStrings(const std::string& str, std::vector& output) +{ + size_t next = 0; + bool even = 0; + for (size_t pos = 0, len = str.length(); pos < len; ++pos) { + if (str[pos] == '\"' || str[pos] == '\'') { + if (even) { + //quoted text + output.push_back(str.substr(next, pos - next)); + even = 0; + } else { + //non quoted text + even = 1; + } + // Skip the delimiter itself. + next = pos + 1; + } + } +} + +std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) +{ + size_t pos = 0; + + if (src == dest) + return result; + + while (1) + { + pos = result.find(src, pos); + if (pos == result.npos) + break; + result.replace(pos, src.size(), dest); + pos += dest.size(); + } + return result; +} diff --git a/Common/StringUtils.h b/Common/StringUtils.h index 58d433697c..0cc81c6cd3 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -17,10 +17,66 @@ #pragma once -#include - #include "Common.h" +#include +#include + +#ifdef _MSC_VER +#pragma warning (disable:4996) +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#else +#include +#endif + +// Useful for shaders with error messages.. +std::string LineNumberString(const std::string &str); + +// Other simple string utilities. + +inline bool startsWith(const std::string &str, const std::string &what) { + if (str.size() < what.size()) + return false; + return str.substr(0, what.size()) == what; +} + +inline bool endsWith(const std::string &str, const std::string &what) { + if (str.size() < what.size()) + return false; + return str.substr(str.size() - what.size()) == what; +} + +// Only use on strings where you're only concerned about ASCII. +inline bool startsWithNoCase(const std::string &str, const std::string &what) { + if (str.size() < what.size()) + return false; + return strncasecmp(str.c_str(), what.c_str(), what.size()) == 0; +} + +inline bool endsWithNoCase(const std::string &str, const std::string &what) { + if (str.size() < what.size()) + return false; + const size_t offset = str.size() - what.size(); + return strncasecmp(str.c_str() + offset, what.c_str(), what.size()) == 0; +} + +void DataToHexString(const uint8_t *data, size_t size, std::string *output); +void DataToHexString(const char* prefix, uint32_t startAddr, const uint8_t* data, size_t size, std::string* output); + +std::string StringFromFormat(const char* format, ...); +std::string StringFromInt(int value); + +std::string StripSpaces(const std::string &s); +std::string StripQuotes(const std::string &s); + +void SplitString(const std::string& str, const char delim, std::vector& output); + +void GetQuotedStrings(const std::string& str, std::vector& output); + +std::string ReplaceAll(std::string input, const std::string& src, const std::string& dest); + +void SkipSpace(const char **ptr); void truncate_cpy(char *dest, size_t destSize, const char *src); template diff --git a/Common/Misc.cpp b/Common/SysError.cpp similarity index 81% rename from Common/Misc.cpp rename to Common/SysError.cpp index af573729b9..2bf17740aa 100644 --- a/Common/Misc.cpp +++ b/Common/SysError.cpp @@ -15,24 +15,22 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#include "util/text/utf8.h" -#include "Common.h" +#include +#include -#include - -#if defined(__APPLE__) -#define __thread -#endif +#include "Common/Data/Encoding/Utf8.h" +#include "SysError.h" #ifdef _WIN32 #include "CommonWindows.h" +#else +#include #endif // Generic function to get last error message. // Call directly after the command or use the error num. // This function might change the error code. -const char *GetLastErrorMsg() -{ +std::string GetLastErrorMsg() { #ifdef _WIN32 return GetStringErrorMsg(GetLastError()); #else @@ -40,25 +38,26 @@ const char *GetLastErrorMsg() #endif } -const char *GetStringErrorMsg(int errCode) { +std::string GetStringErrorMsg(int errCode) { static const size_t buff_size = 1023; + #ifdef _WIN32 - static __THREAD wchar_t err_strw[buff_size] = {}; + wchar_t err_strw[buff_size] = {}; FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_strw, buff_size, NULL); - static __THREAD char err_str[buff_size] = {}; + char err_str[buff_size] = {}; snprintf(err_str, buff_size, "%s", ConvertWStringToUTF8(err_strw).c_str()); + return std::string(err_str); #else - static __thread char err_str[buff_size] = {}; + char err_str[buff_size] = {}; // Thread safe (XSI-compliant) if (strerror_r(errCode, err_str, buff_size) == 0) { return "Unknown error"; } -#endif - return err_str; +#endif } diff --git a/Common/SysError.h b/Common/SysError.h new file mode 100644 index 0000000000..b425b34fdc --- /dev/null +++ b/Common/SysError.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +// Generic function to get last error message. +// Call directly after the command or use the error num. +// This function might change the error code. +// Defined in Misc.cpp. +std::string GetLastErrorMsg(); +std::string GetStringErrorMsg(int errCode); diff --git a/ext/native/base/display.cpp b/Common/System/Display.cpp similarity index 95% rename from ext/native/base/display.cpp rename to Common/System/Display.cpp index 28a482aa06..0e9c1ffb62 100644 --- a/ext/native/base/display.cpp +++ b/Common/System/Display.cpp @@ -1,5 +1,5 @@ -#include "base/display.h" -#include "math/math_util.h" +#include "Common/System/Display.h" +#include "Common/Math/math_util.h" int dp_xres; int dp_yres; diff --git a/ext/native/base/display.h b/Common/System/Display.h similarity index 96% rename from ext/native/base/display.h rename to Common/System/Display.h index d91e426931..586c346f77 100644 --- a/ext/native/base/display.h +++ b/Common/System/Display.h @@ -1,6 +1,6 @@ #pragma once -#include "math/lin/matrix4x4.h" +#include "Common/Math/lin/matrix4x4.h" // This is meant to be a framework for handling DPI scaling etc. // For now, it just consists of these ugly globals. diff --git a/ext/native/base/NativeApp.h b/Common/System/NativeApp.h similarity index 55% rename from ext/native/base/NativeApp.h rename to Common/System/NativeApp.h index d109d1138c..d501d03b43 100644 --- a/ext/native/base/NativeApp.h +++ b/Common/System/NativeApp.h @@ -2,7 +2,6 @@ #include #include -#include // The Native App API. // @@ -10,24 +9,13 @@ // from the framework, which exposes the native JNI api which is a bit // more complicated. -// These are defined in input/input_state.h. +// These are defined in Common/Input/InputState.cpp struct TouchInput; struct KeyInput; struct AxisInput; class GraphicsContext; -enum SystemPermission { - SYSTEM_PERMISSION_STORAGE, -}; - -enum PermissionStatus { - PERMISSION_STATUS_UNKNOWN, - PERMISSION_STATUS_DENIED, - PERMISSION_STATUS_PENDING, - PERMISSION_STATUS_GRANTED, -}; - // The first function to get called, just write strings to the two pointers. // This might get called multiple times in some implementations, you must be able to handle that. void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, bool *landscape, std::string *version); @@ -101,89 +89,3 @@ void NativeSetMixer(void* mixer); // Main thread. void NativeShutdownGraphics(); void NativeShutdown(); - -// Calls back into Java / SDL -// These APIs must be implemented by every port (for example app-android.cpp, SDLMain.cpp). -// You are free to call these. -void SystemToast(const char *text); -void ShowKeyboard(); - -// Vibrate either takes a number of milliseconds to vibrate unconditionally, -// or you can specify these constants for "standard" feedback. On Android, -// these will only be performed if haptic feedback is enabled globally. -// Also, on Android, these will work even if you don't have the VIBRATE permission, -// while generic vibration will not if you don't have it. -enum { - HAPTIC_SOFT_KEYBOARD = -1, - HAPTIC_VIRTUAL_KEY = -2, - HAPTIC_LONG_PRESS_ACTIVATED = -3, -}; -void Vibrate(int length_ms); -void OpenDirectory(const char *path); -void LaunchBrowser(const char *url); -void LaunchMarket(const char *url); -void LaunchEmail(const char *email_address); -void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb); -void System_SendMessage(const char *command, const char *parameter); -PermissionStatus System_GetPermissionStatus(SystemPermission permission); -void System_AskForPermission(SystemPermission permission); - -// This will get muddy with multi-screen support :/ But this will always be the type of the main device. -enum SystemDeviceType { - DEVICE_TYPE_MOBILE = 0, // phones and pads - DEVICE_TYPE_TV = 1, // Android TV and similar - DEVICE_TYPE_DESKTOP = 2, // Desktop computer -}; - -enum SystemProperty { - SYSPROP_NAME, - SYSPROP_LANGREGION, - SYSPROP_CPUINFO, - SYSPROP_BOARDNAME, - SYSPROP_CLIPBOARD_TEXT, - SYSPROP_GPUDRIVER_VERSION, - - SYSPROP_HAS_FILE_BROWSER, - SYSPROP_HAS_IMAGE_BROWSER, - SYSPROP_HAS_BACK_BUTTON, - - // Available as Int: - SYSPROP_SYSTEMVERSION, - SYSPROP_DISPLAY_XRES, - SYSPROP_DISPLAY_YRES, - SYSPROP_DISPLAY_REFRESH_RATE, - SYSPROP_DISPLAY_LOGICAL_DPI, - SYSPROP_DISPLAY_DPI, - SYSPROP_DISPLAY_COUNT, - SYSPROP_MOGA_VERSION, - - // Float only: - SYSPROP_DISPLAY_SAFE_INSET_LEFT, - SYSPROP_DISPLAY_SAFE_INSET_RIGHT, - SYSPROP_DISPLAY_SAFE_INSET_TOP, - SYSPROP_DISPLAY_SAFE_INSET_BOTTOM, - - SYSPROP_DEVICE_TYPE, - SYSPROP_APP_GOLD, // To avoid having #ifdef GOLD other than in main.cpp and similar. - - // Exposed on Android. Choosing the optimal sample rate for audio - // will result in lower latencies. Buffer size is automatically matched - // by the OpenSL audio backend, only exposed here for debugging/info. - SYSPROP_AUDIO_SAMPLE_RATE, - SYSPROP_AUDIO_FRAMES_PER_BUFFER, - SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE, - SYSPROP_AUDIO_OPTIMAL_FRAMES_PER_BUFFER, - - // Exposed on SDL. - SYSPROP_AUDIO_DEVICE_LIST, - - SYSPROP_SUPPORTS_PERMISSIONS, - SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE, -}; - -std::string System_GetProperty(SystemProperty prop); -int System_GetPropertyInt(SystemProperty prop); -float System_GetPropertyFloat(SystemProperty prop); -bool System_GetPropertyBool(SystemProperty prop); - -std::vector __cameraGetDeviceList(); diff --git a/Common/System/System.h b/Common/System/System.h new file mode 100644 index 0000000000..2d87f7399d --- /dev/null +++ b/Common/System/System.h @@ -0,0 +1,101 @@ +#pragma once + +#include +#include +#include + +enum SystemPermission { + SYSTEM_PERMISSION_STORAGE, +}; + +enum PermissionStatus { + PERMISSION_STATUS_UNKNOWN, + PERMISSION_STATUS_DENIED, + PERMISSION_STATUS_PENDING, + PERMISSION_STATUS_GRANTED, +}; + +// These APIs must be implemented by every port (for example app-android.cpp, SDLMain.cpp). +// Ideally these should be safe to call from any thread. +void SystemToast(const char *text); +void ShowKeyboard(); + +// Vibrate either takes a number of milliseconds to vibrate unconditionally, +// or you can specify these constants for "standard" feedback. On Android, +// these will only be performed if haptic feedback is enabled globally. +// Also, on Android, these will work even if you don't have the VIBRATE permission, +// while generic vibration will not if you don't have it. +enum { + HAPTIC_SOFT_KEYBOARD = -1, + HAPTIC_VIRTUAL_KEY = -2, + HAPTIC_LONG_PRESS_ACTIVATED = -3, +}; +void Vibrate(int length_ms); +void OpenDirectory(const char *path); +void LaunchBrowser(const char *url); +void LaunchMarket(const char *url); +void LaunchEmail(const char *email_address); +void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb); +void System_SendMessage(const char *command, const char *parameter); +PermissionStatus System_GetPermissionStatus(SystemPermission permission); +void System_AskForPermission(SystemPermission permission); + +// This will get muddy with multi-screen support :/ But this will always be the type of the main device. +enum SystemDeviceType { + DEVICE_TYPE_MOBILE = 0, // phones and pads + DEVICE_TYPE_TV = 1, // Android TV and similar + DEVICE_TYPE_DESKTOP = 2, // Desktop computer +}; + +enum SystemProperty { + SYSPROP_NAME, + SYSPROP_LANGREGION, + SYSPROP_CPUINFO, + SYSPROP_BOARDNAME, + SYSPROP_CLIPBOARD_TEXT, + SYSPROP_GPUDRIVER_VERSION, + + SYSPROP_HAS_FILE_BROWSER, + SYSPROP_HAS_IMAGE_BROWSER, + SYSPROP_HAS_BACK_BUTTON, + + // Available as Int: + SYSPROP_SYSTEMVERSION, + SYSPROP_DISPLAY_XRES, + SYSPROP_DISPLAY_YRES, + SYSPROP_DISPLAY_REFRESH_RATE, + SYSPROP_DISPLAY_LOGICAL_DPI, + SYSPROP_DISPLAY_DPI, + SYSPROP_DISPLAY_COUNT, + SYSPROP_MOGA_VERSION, + + // Float only: + SYSPROP_DISPLAY_SAFE_INSET_LEFT, + SYSPROP_DISPLAY_SAFE_INSET_RIGHT, + SYSPROP_DISPLAY_SAFE_INSET_TOP, + SYSPROP_DISPLAY_SAFE_INSET_BOTTOM, + + SYSPROP_DEVICE_TYPE, + SYSPROP_APP_GOLD, // To avoid having #ifdef GOLD other than in main.cpp and similar. + + // Exposed on Android. Choosing the optimal sample rate for audio + // will result in lower latencies. Buffer size is automatically matched + // by the OpenSL audio backend, only exposed here for debugging/info. + SYSPROP_AUDIO_SAMPLE_RATE, + SYSPROP_AUDIO_FRAMES_PER_BUFFER, + SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE, + SYSPROP_AUDIO_OPTIMAL_FRAMES_PER_BUFFER, + + // Exposed on SDL. + SYSPROP_AUDIO_DEVICE_LIST, + + SYSPROP_SUPPORTS_PERMISSIONS, + SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE, +}; + +std::string System_GetProperty(SystemProperty prop); +int System_GetPropertyInt(SystemProperty prop); +float System_GetPropertyFloat(SystemProperty prop); +bool System_GetPropertyBool(SystemProperty prop); + +std::vector __cameraGetDeviceList(); diff --git a/ext/native/thread/executor.cpp b/Common/Thread/Executor.cpp similarity index 91% rename from ext/native/thread/executor.cpp rename to Common/Thread/Executor.cpp index 0ae2b41b64..6f9c689103 100644 --- a/ext/native/thread/executor.cpp +++ b/Common/Thread/Executor.cpp @@ -1,4 +1,4 @@ -#include "thread/executor.h" +#include "Common/Thread/Executor.h" #include #include diff --git a/ext/native/thread/executor.h b/Common/Thread/Executor.h similarity index 100% rename from ext/native/thread/executor.h rename to Common/Thread/Executor.h diff --git a/ext/native/thread/prioritizedworkqueue.cpp b/Common/Thread/PrioritizedWorkQueue.cpp similarity index 92% rename from ext/native/thread/prioritizedworkqueue.cpp rename to Common/Thread/PrioritizedWorkQueue.cpp index 35a1e94a62..d80ad80c41 100644 --- a/ext/native/thread/prioritizedworkqueue.cpp +++ b/Common/Thread/PrioritizedWorkQueue.cpp @@ -1,13 +1,14 @@ #include #include -#include "base/logging.h" -#include "base/timeutil.h" -#include "thread/prioritizedworkqueue.h" +#include "Common/TimeUtil.h" +#include "Common/Thread/PrioritizedWorkQueue.h" + +#include "Common/Log.h" PrioritizedWorkQueue::~PrioritizedWorkQueue() { if (!done_) { - ELOG("PrioritizedWorkQueue destroyed but not done!"); + ERROR_LOG(SYSTEM, "PrioritizedWorkQueue destroyed but not done!"); } } @@ -32,7 +33,7 @@ void PrioritizedWorkQueue::Flush() { } queue_.clear(); if (flush_count > 0) { - ILOG("PrioritizedWorkQueue: Flushed %d un-executed tasks", flush_count); + INFO_LOG(SYSTEM, "PrioritizedWorkQueue: Flushed %d un-executed tasks", flush_count); } } diff --git a/ext/native/thread/prioritizedworkqueue.h b/Common/Thread/PrioritizedWorkQueue.h similarity index 95% rename from ext/native/thread/prioritizedworkqueue.h rename to Common/Thread/PrioritizedWorkQueue.h index 032e6a9694..59231f48b1 100644 --- a/ext/native/thread/prioritizedworkqueue.h +++ b/Common/Thread/PrioritizedWorkQueue.h @@ -5,8 +5,9 @@ #include #include -#include "base/basictypes.h" -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" + +#include "Common/Common.h" // Priorities can change dynamically. // Try to make priority() fast, it will be called a lot. diff --git a/ext/native/thread/threadpool.cpp b/Common/Thread/ThreadPool.cpp similarity index 92% rename from ext/native/thread/threadpool.cpp rename to Common/Thread/ThreadPool.cpp index a312748014..e64d1c8786 100644 --- a/ext/native/thread/threadpool.cpp +++ b/Common/Thread/ThreadPool.cpp @@ -1,6 +1,7 @@ -#include "base/logging.h" -#include "thread/threadpool.h" -#include "thread/threadutil.h" +#include "Common/Thread/ThreadPool.h" +#include "Common/Thread/ThreadUtil.h" + +#include "Common/Log.h" #include "Common/MakeUnique.h" ///////////////////////////// WorkerThread @@ -86,9 +87,9 @@ void LoopWorkerThread::WorkFunc() { ThreadPool::ThreadPool(int numThreads) { if (numThreads <= 0) { numThreads_ = 1; - ILOG("ThreadPool: Bad number of threads %i", numThreads); + INFO_LOG(JIT, "ThreadPool: Bad number of threads %d", numThreads); } else if (numThreads > 8) { - ILOG("ThreadPool: Capping number of threads to 8 (was %i)", numThreads); + INFO_LOG(JIT, "ThreadPool: Capping number of threads to 8 (was %d)", numThreads); numThreads_ = 8; } else { numThreads_ = numThreads; diff --git a/ext/native/thread/threadpool.h b/Common/Thread/ThreadPool.h similarity index 100% rename from ext/native/thread/threadpool.h rename to Common/Thread/ThreadPool.h diff --git a/ext/native/thread/threadutil.cpp b/Common/Thread/ThreadUtil.cpp similarity index 92% rename from ext/native/thread/threadutil.cpp rename to Common/Thread/ThreadUtil.cpp index 403f8cadd9..b7c807e61b 100644 --- a/ext/native/thread/threadutil.cpp +++ b/Common/Thread/ThreadUtil.cpp @@ -8,16 +8,18 @@ #define TLS_SUPPORTED #endif -#include "base/basictypes.h" -#include "base/logging.h" -#include "thread/threadutil.h" +#include +#include + +#include "Common/Log.h" +#include "Common/Thread/ThreadUtil.h" #if defined(__ANDROID__) || defined(__APPLE__) || (defined(__GLIBC__) && defined(_GNU_SOURCE)) #include #endif #ifdef TLS_SUPPORTED -static __THREAD const char *curThreadName; +static thread_local const char *curThreadName; #endif #ifdef __MINGW32__ @@ -115,7 +117,7 @@ void setCurrentThreadName(const char* threadName) { void AssertCurrentThreadName(const char *threadName) { #ifdef TLS_SUPPORTED if (strcmp(curThreadName, threadName) != 0) { - ELOG("Thread name assert failed: Expected %s, was %s", threadName, curThreadName); + ERROR_LOG(SYSTEM, "Thread name assert failed: Expected %s, was %s", threadName, curThreadName); } #endif } diff --git a/ext/native/thread/threadutil.h b/Common/Thread/ThreadUtil.h similarity index 100% rename from ext/native/thread/threadutil.h rename to Common/Thread/ThreadUtil.h diff --git a/Common/Thunk.cpp b/Common/Thunk.cpp index fe4850b594..06e517cc6c 100644 --- a/Common/Thunk.cpp +++ b/Common/Thunk.cpp @@ -147,8 +147,8 @@ const void *ThunkManager::ProtectFunction(const void *function, int num_params) iter = thunks.find(function); if (iter != thunks.end()) return (const void *)iter->second; - if (!region) - PanicAlert("Trying to protect functions before the emu is started. Bad bad bad."); + + _assert_msg_(region != nullptr, "Can't protect functions before the emu is started."); BeginWrite(); const u8 *call_point = GetCodePtr(); diff --git a/Common/TimeUtil.cpp b/Common/TimeUtil.cpp new file mode 100644 index 0000000000..2cb375c9a0 --- /dev/null +++ b/Common/TimeUtil.cpp @@ -0,0 +1,93 @@ +#include +#include +#include + +#include "ppsspp_config.h" + +#include "Common/TimeUtil.h" + +#ifdef HAVE_LIBNX +#include +#endif // HAVE_LIBNX + +#ifdef _WIN32 +#include "CommonWindows.h" +#include +#include +#else +#include +#include +#endif + +static double curtime = 0; + +#ifdef _WIN32 + +static LARGE_INTEGER frequency; +static double frequencyMult; +static LARGE_INTEGER startTime; + +double time_now_d() { + if (frequency.QuadPart == 0) { + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&startTime); + curtime = 0.0; + frequencyMult = 1.0 / static_cast(frequency.QuadPart); + } + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + double elapsed = static_cast(time.QuadPart - startTime.QuadPart); + return elapsed * frequencyMult; +} + +#else + +static uint64_t _frequency = 0; +static uint64_t _starttime = 0; + +double time_now_d() { + static time_t start; + struct timeval tv; + gettimeofday(&tv, NULL); + if (start == 0) { + start = tv.tv_sec; + } + tv.tv_sec -= start; + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +#endif + +void sleep_ms(int ms) { +#ifdef _WIN32 + Sleep(ms); +#elif defined(HAVE_LIBNX) + svcSleepThread(ms * 1000000); +#else + usleep(ms * 1000); +#endif +} + +// Return the current time formatted as Minutes:Seconds:Milliseconds +// in the form 00:00:000. +void GetTimeFormatted(char formattedTime[13]) { + time_t sysTime; + struct tm * gmTime; + char tmp[13]; + + time(&sysTime); + gmTime = localtime(&sysTime); + + strftime(tmp, 6, "%M:%S", gmTime); + + // Now tack on the milliseconds +#ifdef _WIN32 + struct timeb tp; + (void)::ftime(&tp); + snprintf(formattedTime, 13, "%s:%03i", tmp, tp.millitm); +#else + struct timeval t; + (void)gettimeofday(&t, NULL); + snprintf(formattedTime, 13, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); +#endif +} diff --git a/Common/TimeUtil.h b/Common/TimeUtil.h new file mode 100644 index 0000000000..8d7273c466 --- /dev/null +++ b/Common/TimeUtil.h @@ -0,0 +1,9 @@ +#pragma once + +// Seconds. +double time_now_d(); + +// Sleep. Does not necessarily have millisecond granularity, especially on Windows. +void sleep_ms(int ms); + +void GetTimeFormatted(char formattedTime[13]); diff --git a/Common/Timer.cpp b/Common/Timer.cpp deleted file mode 100644 index 9c34ee151a..0000000000 --- a/Common/Timer.cpp +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -#include "ppsspp_config.h" - -#ifdef _WIN32 -#include "CommonWindows.h" -#include -#include -#else -#include -#endif - -#include "Timer.h" -#include "StringUtils.h" - -namespace Common -{ - -u32 Timer::GetTimeMs() -{ -#if defined(_WIN32) -#if PPSSPP_PLATFORM(UWP) - return (u32)GetTickCount64(); -#else - return timeGetTime(); -#endif -#else - // REALTIME is probably not a good idea for measuring updates. - struct timeval t; - (void)gettimeofday(&t, NULL); - return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); -#endif -} - -// -------------------------------------------- -// Initiate, Start, Stop, and Update the time -// -------------------------------------------- - -// Set initial values for the class -Timer::Timer() - : m_LastTime(0), m_StartTime(0), m_Running(false) -{ - Update(); - -#ifdef _WIN32 - QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency); -#endif -} - -// Write the starting time -void Timer::Start() -{ - m_StartTime = GetTimeMs(); - m_Running = true; -} - -// Stop the timer -void Timer::Stop() -{ - // Write the final time - m_LastTime = GetTimeMs(); - m_Running = false; -} - -// Update the last time variable -void Timer::Update() -{ - m_LastTime = GetTimeMs(); - //TODO(ector) - QPF -} - -// ------------------------------------- -// Get time difference and elapsed time -// ------------------------------------- - -// Get the number of milliseconds since the last Update() -u64 Timer::GetTimeDifference() const -{ - return GetTimeMs() - m_LastTime; -} - -// Add the time difference since the last Update() to the starting time. -// This is used to compensate for a paused game. -void Timer::AddTimeDifference() -{ - m_StartTime += GetTimeDifference(); -} - -// Wind back the starting time to a custom time -void Timer::WindBackStartingTime(u64 WindBack) -{ - m_StartTime += WindBack; -} - -// Get the time elapsed since the Start() -u64 Timer::GetTimeElapsed() const -{ - // If we have not started yet, return 1 (because then I don't - // have to change the FPS calculation in CoreRerecording.cpp . - if (m_StartTime == 0) return 1; - - // Return the final timer time if the timer is stopped - if (!m_Running) return (m_LastTime - m_StartTime); - - return (GetTimeMs() - m_StartTime); -} - -// Get the formatted time elapsed since the Start() -std::string Timer::GetTimeElapsedFormatted() const -{ - // If we have not started yet, return zero - if (m_StartTime == 0) - return "00:00:00:000"; - - // The number of milliseconds since the start. - // Use a different value if the timer is stopped. - u64 Milliseconds; - if (m_Running) - Milliseconds = GetTimeMs() - m_StartTime; - else - Milliseconds = m_LastTime - m_StartTime; - // Seconds - u32 Seconds = (u32)(Milliseconds / 1000); - // Minutes - u32 Minutes = Seconds / 60; - // Hours - u32 Hours = Minutes / 60; - - std::string TmpStr = StringFromFormat("%02d:%02d:%02d:%03d", - Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); - return TmpStr; -} - -// Get current time -void Timer::IncreaseResolution() -{ -#if defined(USING_WIN_UI) - timeBeginPeriod(1); -#endif -} - -void Timer::RestoreResolution() -{ -#if defined(USING_WIN_UI) - timeEndPeriod(1); -#endif -} - -// Get the number of seconds since January 1 1970 -u64 Timer::GetTimeSinceJan1970() -{ - time_t ltime; - time(<ime); - return((u64)ltime); -} - -u64 Timer::GetLocalTimeSinceJan1970() -{ - time_t sysTime, tzDiff, tzDST; - struct tm * gmTime; - - time(&sysTime); - - // Account for DST where needed - gmTime = localtime(&sysTime); - if(gmTime->tm_isdst == 1) - tzDST = 3600; - else - tzDST = 0; - - // Lazy way to get local time in sec - gmTime = gmtime(&sysTime); - tzDiff = sysTime - mktime(gmTime); - - return (u64)(sysTime + tzDiff + tzDST); -} - -// Return the current time formatted as Minutes:Seconds:Milliseconds -// in the form 00:00:000. -void Timer::GetTimeFormatted(char formattedTime[13]) -{ - time_t sysTime; - struct tm * gmTime; - char tmp[13]; - - time(&sysTime); - gmTime = localtime(&sysTime); - - strftime(tmp, 6, "%M:%S", gmTime); - - // Now tack on the milliseconds -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); - snprintf(formattedTime, 13, "%s:%03i", tmp, tp.millitm); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); - snprintf(formattedTime, 13, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); -#endif -} - -// Returns a timestamp with decimals for precise time comparisons -// ---------------- -double Timer::GetDoubleTime() -{ -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); -#endif - // Get continuous timestamp - u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); - - // Remove a few years. We only really want enough seconds to make - // sure that we are detecting actual actions, perhaps 60 seconds is - // enough really, but I leave a year of seconds anyway, in case the - // user's clock is incorrect or something like that. - TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); - - // Make a smaller integer that fits in the double - u32 Seconds = (u32)TmpSeconds; -#ifdef _WIN32 - double ms = tp.millitm / 1000.0 / 1000.0; -#else - double ms = t.tv_usec / 1000000.0; -#endif - double TmpTime = Seconds + ms; - - return TmpTime; -} - -} // Namespace Common diff --git a/Common/Timer.h b/Common/Timer.h deleted file mode 100644 index 8d775b8423..0000000000 --- a/Common/Timer.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "Common.h" -#include - -namespace Common -{ -class Timer -{ -public: - Timer(); - - void Start(); - void Stop(); - void Update(); - - // The time difference is always returned in milliseconds, regardless of alternative internal representation - u64 GetTimeDifference() const; - void AddTimeDifference(); - void WindBackStartingTime(u64 WindBack); - - static void IncreaseResolution(); - static void RestoreResolution(); - static u64 GetTimeSinceJan1970(); - static u64 GetLocalTimeSinceJan1970(); - static double GetDoubleTime(); - - static void GetTimeFormatted(char formattedTime[13]); - std::string GetTimeElapsedFormatted() const; - u64 GetTimeElapsed() const; - - static u32 GetTimeMs(); - -private: - u64 m_LastTime; - u64 m_StartTime; -#ifdef _WIN32 - u64 m_frequency; -#endif - bool m_Running; -}; - -} // Namespace Common diff --git a/ext/native/ui/ui_context.cpp b/Common/UI/Context.cpp similarity index 95% rename from ext/native/ui/ui_context.cpp rename to Common/UI/Context.cpp index ebc53dfb42..a2dcbf475b 100644 --- a/ext/native/ui/ui_context.cpp +++ b/Common/UI/Context.cpp @@ -2,16 +2,16 @@ #include -#include "base/display.h" -#include "base/NativeApp.h" -#include "base/logging.h" -#include "ui/ui.h" -#include "ui/view.h" -#include "ui/ui_context.h" -#include "gfx_es2/draw_buffer.h" -#include "gfx_es2/draw_text.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/UI/UI.h" +#include "Common/UI/View.h" +#include "Common/UI/Context.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Render/Text/draw_text.h" #include "Common/Log.h" +#include "UI/TextureUtil.h" UIContext::UIContext() { fontStyle_ = new UI::FontStyle(); @@ -38,9 +38,7 @@ void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pi void UIContext::BeginFrame() { if (!uitexture_) { uitexture_ = CreateTextureFromFile(draw_, "ui_atlas_luna.zim", ImageFileType::ZIM, false); - if (!uitexture_) { - PanicAlert("Failed to load ui_atlas_luna.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory."); - } + _dbg_assert_msg_(uitexture_, "Failed to load ui_atlas_luna.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory."); } uidrawbufferTop_->SetCurZ(0.0f); uidrawbuffer_->SetCurZ(0.0f); diff --git a/ext/native/ui/ui_context.h b/Common/UI/Context.h similarity index 93% rename from ext/native/ui/ui_context.h rename to Common/UI/Context.h index effc248136..18f18bd515 100644 --- a/ext/native/ui/ui_context.h +++ b/Common/UI/Context.h @@ -1,12 +1,12 @@ #pragma once +#include #include +#include -#include "base/basictypes.h" -#include "math/geom2d.h" -#include "math/lin/vec3.h" -#include "gfx/texture_atlas.h" -#include "UI/TextureUtil.h" +#include "Common/Math/geom2d.h" +#include "Common/Math/lin/vec3.h" +#include "Common/Render/TextureAtlas.h" // Everything you need to draw a UI collected into a single unit that can be passed around. // Everything forward declared so this header is safe everywhere. @@ -22,13 +22,17 @@ namespace Draw { } class Texture; +class ManagedTexture; class DrawBuffer; class TextDrawer; namespace UI { struct Drawable; + struct EventParams; struct Theme; struct FontStyle; + class Event; + class View; } class DrawBuffer; diff --git a/ext/native/ui/root.cpp b/Common/UI/Root.cpp similarity index 89% rename from ext/native/ui/root.cpp rename to Common/UI/Root.cpp index 0fd4700445..73cca79888 100644 --- a/ext/native/ui/root.cpp +++ b/Common/UI/Root.cpp @@ -2,9 +2,12 @@ #include #include "ppsspp_config.h" -#include "base/timeutil.h" -#include "ui/root.h" -#include "ui/viewgroup.h" + +#include "Common/UI/Root.h" +#include "Common/UI/ViewGroup.h" + +#include "Common/Log.h" +#include "Common/TimeUtil.h" namespace UI { @@ -17,6 +20,10 @@ static bool focusMovementEnabled; bool focusForced; static std::mutex eventMutex_; +static std::function soundCallback; +static bool soundEnabled = true; + + struct DispatchQueueItem { Event *e; EventParams params; @@ -50,6 +57,7 @@ void DispatchEvents() { } void RemoveQueuedEventsByView(View *view) { + std::unique_lock guard(eventMutex_); for (auto it = g_dispatchQueue.begin(); it != g_dispatchQueue.end(); ) { if (it->params.v == view) { it = g_dispatchQueue.erase(it); @@ -60,6 +68,7 @@ void RemoveQueuedEventsByView(View *view) { } void RemoveQueuedEventsByEvent(Event *event) { + std::unique_lock guard(eventMutex_); for (auto it = g_dispatchQueue.begin(); it != g_dispatchQueue.end(); ) { if (it->e == event) { it = g_dispatchQueue.erase(it); @@ -100,13 +109,13 @@ bool IsFocusMovementEnabled() { return focusMovementEnabled; } -void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root) { +void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root, bool ignoreInsets) { if (!root) { - ELOG("Tried to layout a view hierarchy from a zero pointer root"); + ERROR_LOG(SYSTEM, "Tried to layout a view hierarchy from a zero pointer root"); return; } - Bounds rootBounds = dc.GetLayoutBounds(); + Bounds rootBounds = ignoreInsets ? dc.GetBounds() : dc.GetLayoutBounds(); MeasureSpec horiz(EXACTLY, rootBounds.w); MeasureSpec vert(EXACTLY, rootBounds.h); @@ -131,6 +140,22 @@ void MoveFocus(ViewGroup *root, FocusDirection direction) { if (neigh.view) { neigh.view->SetFocus(); root->SubviewFocused(neigh.view); + + PlayUISound(UISound::SELECT); + } +} + +void SetSoundEnabled(bool enabled) { + soundEnabled = enabled; +} + +void SetSoundCallback(std::function func) { + soundCallback = func; +} + +void PlayUISound(UISound sound) { + if (soundEnabled && soundCallback) { + soundCallback(sound); } } @@ -312,10 +337,10 @@ bool AxisEvent(const AxisInput &axis, ViewGroup *root) { old.x = dir; } if (axis.axisId == JOYSTICK_AXIS_Y || axis.axisId == JOYSTICK_AXIS_HAT_Y) { - // We stupidly interpret the joystick Y axis backwards on Android instead of reversing + // We stupidly interpret the joystick Y axis backwards on Android and Linux instead of reversing // it early (see keymaps...). Too late to fix without invalidating a lot of config files, so we // reverse it here too. -#if PPSSPP_PLATFORM(ANDROID) +#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX) GenerateKeyFromAxis(old.y, dir, NKCODE_DPAD_UP, NKCODE_DPAD_DOWN); #else GenerateKeyFromAxis(old.y, dir, NKCODE_DPAD_DOWN, NKCODE_DPAD_UP); @@ -335,7 +360,7 @@ void UpdateViewHierarchy(ViewGroup *root) { frameCount++; if (!root) { - ELOG("Tried to update a view hierarchy from a zero pointer root"); + ERROR_LOG(SYSTEM, "Tried to update a view hierarchy from a zero pointer root"); return; } diff --git a/ext/native/ui/root.h b/Common/UI/Root.h similarity index 64% rename from ext/native/ui/root.h rename to Common/UI/Root.h index a51a20d095..c19dc44acc 100644 --- a/ext/native/ui/root.h +++ b/Common/UI/Root.h @@ -1,7 +1,9 @@ #pragma once -#include "ui/ui_context.h" -#include "input/input_state.h" +#include + +#include "Common/UI/Context.h" +#include "Common/Input/InputState.h" namespace UI { @@ -19,11 +21,25 @@ void DispatchEvents(); class ViewGroup; -void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root); +void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root, bool ignoreInsets); void UpdateViewHierarchy(ViewGroup *root); // Hooks arrow keys for navigation bool KeyEvent(const KeyInput &key, ViewGroup *root); bool TouchEvent(const TouchInput &touch, ViewGroup *root); bool AxisEvent(const AxisInput &axis, ViewGroup *root); +enum class UISound { + SELECT = 0, + BACK, + CONFIRM, + TOGGLE_ON, + TOGGLE_OFF, + COUNT, +}; + +void SetSoundEnabled(bool enabled); +void SetSoundCallback(std::function func); + +void PlayUISound(UISound sound); + } // namespace UI diff --git a/ext/native/ui/screen.cpp b/Common/UI/Screen.cpp similarity index 80% rename from ext/native/ui/screen.cpp rename to Common/UI/Screen.cpp index 958c1d70c3..f8f4cd10dc 100644 --- a/ext/native/ui/screen.cpp +++ b/Common/UI/Screen.cpp @@ -1,11 +1,12 @@ -#include "base/display.h" -#include "base/logging.h" -#include "base/timeutil.h" -#include "input/input_state.h" -#include "ui/root.h" -#include "ui/screen.h" -#include "ui/ui.h" -#include "ui/view.h" +#include "Common/System/Display.h" +#include "Common/Input/InputState.h" +#include "Common/UI/Root.h" +#include "Common/UI/Screen.h" +#include "Common/UI/UI.h" +#include "Common/UI/View.h" + +#include "Common/Log.h" +#include "Common/TimeUtil.h" ScreenManager::ScreenManager() { uiContext_ = 0; @@ -18,7 +19,7 @@ ScreenManager::~ScreenManager() { void ScreenManager::switchScreen(Screen *screen) { if (!nextStack_.empty() && screen == nextStack_.front().screen) { - ELOG("Already switching to this screen"); + ERROR_LOG(SYSTEM, "Already switching to this screen"); return; } // Note that if a dialog is found, this will be a silent background switch that @@ -26,12 +27,12 @@ void ScreenManager::switchScreen(Screen *screen) { // until that switch. // TODO: is this still true? if (!nextStack_.empty()) { - ELOG("Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen."); + ERROR_LOG(SYSTEM, "Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen."); delete screen; return; } if (screen == nullptr) { - WLOG("Swiching to a zero screen, this can't be good"); + WARN_LOG(SYSTEM, "Switching to a zero screen, this can't be good"); } if (stack_.empty() || screen != stack_.back().screen) { screen->setScreenManager(this); @@ -53,7 +54,7 @@ void ScreenManager::update() { void ScreenManager::switchToNext() { std::lock_guard guard(inputLock_); if (nextStack_.empty()) { - ELOG("switchToNext: No nextStack_!"); + ERROR_LOG(SYSTEM, "switchToNext: No nextStack_!"); } Layer temp = {nullptr, 0}; @@ -128,7 +129,7 @@ void ScreenManager::deviceRestored() { } void ScreenManager::resized() { - ILOG("ScreenManager::resized(dp: %dx%d)", dp_xres, dp_yres); + INFO_LOG(SYSTEM, "ScreenManager::resized(dp: %dx%d)", dp_xres, dp_yres); std::lock_guard guard(inputLock_); // Have to notify the whole stack, otherwise there will be problems when going back // to non-top screens. @@ -143,7 +144,7 @@ void ScreenManager::render() { case LAYER_SIDEMENU: case LAYER_TRANSPARENT: if (stack_.size() == 1) { - ELOG("Can't have sidemenu over nothing"); + ERROR_LOG(SYSTEM, "Can't have sidemenu over nothing"); break; } else { auto iter = stack_.end(); @@ -170,7 +171,7 @@ void ScreenManager::render() { break; } } else { - ELOG("No current screen!"); + ERROR_LOG(SYSTEM, "No current screen!"); } processFinishDialog(); @@ -235,7 +236,7 @@ void ScreenManager::pop() { delete stack_.back().screen; stack_.pop_back(); } else { - ELOG("Can't pop when stack empty"); + ERROR_LOG(SYSTEM, "Can't pop when stack empty"); } } @@ -247,11 +248,11 @@ void ScreenManager::RecreateAllViews() { void ScreenManager::finishDialog(Screen *dialog, DialogResult result) { if (stack_.empty()) { - ELOG("Must be in a dialog to finishDialog"); + ERROR_LOG(SYSTEM, "Must be in a dialog to finishDialog"); return; } if (dialog != stack_.back().screen) { - ELOG("Wrong dialog being finished!"); + ERROR_LOG(SYSTEM, "Wrong dialog being finished!"); return; } dialog->onFinish(result); @@ -272,22 +273,24 @@ Screen *ScreenManager::dialogParent(const Screen *dialog) const { void ScreenManager::processFinishDialog() { if (dialogFinished_) { - std::lock_guard guard(inputLock_); - // Another dialog may have been pushed before the render, so search for it. - Screen *caller = dialogParent(dialogFinished_); - for (size_t i = 0; i < stack_.size(); ++i) { - if (stack_[i].screen == dialogFinished_) { - stack_.erase(stack_.begin() + i); + { + std::lock_guard guard(inputLock_); + // Another dialog may have been pushed before the render, so search for it. + Screen *caller = dialogParent(dialogFinished_); + for (size_t i = 0; i < stack_.size(); ++i) { + if (stack_[i].screen == dialogFinished_) { + stack_.erase(stack_.begin() + i); + } } - } - if (!caller) { - ELOG("ERROR: no top screen when finishing dialog"); - } else if (caller != topScreen()) { - // The caller may get confused if we call dialogFinished() now. - WLOG("Skipping non-top dialog when finishing dialog."); - } else { - caller->dialogFinished(dialogFinished_, dialogResult_); + if (!caller) { + ERROR_LOG(SYSTEM, "ERROR: no top screen when finishing dialog"); + } else if (caller != topScreen()) { + // The caller may get confused if we call dialogFinished() now. + WARN_LOG(SYSTEM, "Skipping non-top dialog when finishing dialog."); + } else { + caller->dialogFinished(dialogFinished_, dialogResult_); + } } delete dialogFinished_; dialogFinished_ = nullptr; diff --git a/ext/native/ui/screen.h b/Common/UI/Screen.h similarity index 97% rename from ext/native/ui/screen.h rename to Common/UI/Screen.h index 0b97108afd..46f7261ddb 100644 --- a/ext/native/ui/screen.h +++ b/Common/UI/Screen.h @@ -15,11 +15,10 @@ #include #include +#include -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/NativeApp.h" -#include "input/input_state.h" +#include "Common/Common.h" +#include "Common/Input/InputState.h" namespace UI { class View; diff --git a/ext/native/ui/ui_tween.cpp b/Common/UI/Tween.cpp similarity index 95% rename from ext/native/ui/ui_tween.cpp rename to Common/UI/Tween.cpp index 4c3194d309..d06601cb71 100644 --- a/ext/native/ui/ui_tween.cpp +++ b/Common/UI/Tween.cpp @@ -1,7 +1,7 @@ -๏ปฟ#include "base/colorutil.h" -#include "ui/ui_tween.h" -#include "ui/view.h" -#include "ui/viewgroup.h" +๏ปฟ#include "Common/Data/Color/RGBAUtil.h" +#include "Common/UI/Tween.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" namespace UI { diff --git a/ext/native/ui/ui_tween.h b/Common/UI/Tween.h similarity index 89% rename from ext/native/ui/ui_tween.h rename to Common/UI/Tween.h index aad4fbfa5d..2786963d55 100644 --- a/ext/native/ui/ui_tween.h +++ b/Common/UI/Tween.h @@ -3,8 +3,8 @@ #include #include #include -#include "base/timeutil.h" -#include "ui/view.h" +#include "Common/TimeUtil.h" +#include "Common/UI/View.h" namespace UI { @@ -12,7 +12,7 @@ namespace UI { class Tween { public: explicit Tween(float duration, float (*curve)(float)) : duration_(duration), curve_(curve) { - start_ = time_now(); + start_ = time_now_d(); } virtual ~Tween() { } @@ -21,7 +21,7 @@ public: void Apply(View *view); bool Finished() { - return finishApplied_ && time_now() >= start_ + delay_ + duration_; + return finishApplied_ && time_now_d() >= start_ + delay_ + duration_; } void Persist() { @@ -41,7 +41,7 @@ public: protected: float DurationOffset() { - return time_now() - start_ - delay_; + return (time_now_d() - start_) - delay_; } float Position() { @@ -50,7 +50,7 @@ protected: virtual void DoApply(View *view, float pos) = 0; - float start_; + double start_; float duration_; float delay_ = 0.0f; bool finishApplied_ = false; @@ -78,7 +78,7 @@ public: const Value newFrom = valid_ ? Current(Position()) : newTo; // Are we already part way through another transition? - if (time_now() < start_ + delay_ + duration_ && valid_) { + if (time_now_d() < start_ + delay_ + duration_ && valid_) { if (newTo == to_) { // Already on course. Don't change. return; @@ -88,17 +88,17 @@ public: if (newDuration >= 0.0f) { newOffset *= newDuration / duration_; } - start_ = time_now() - newOffset - delay_; - } else if (time_now() <= start_ + delay_) { + start_ = time_now_d() - newOffset - delay_; + } else if (time_now_d() <= start_ + delay_) { // Start the delay over again. - start_ = time_now(); + start_ = time_now_d(); } else { // Since we've partially animated to the other value, skip delay. - start_ = time_now() - delay_; + start_ = time_now_d() - delay_; } } else { // Already finished, so restart. - start_ = time_now(); + start_ = time_now_d(); finishApplied_ = false; } diff --git a/ext/native/ui/ui.cpp b/Common/UI/UI.cpp similarity index 68% rename from ext/native/ui/ui.cpp rename to Common/UI/UI.cpp index f8ea4f574a..8a4ad5deaf 100644 --- a/ext/native/ui/ui.cpp +++ b/Common/UI/UI.cpp @@ -5,11 +5,11 @@ #include #include -#include "base/colorutil.h" -#include "ui/ui.h" -#include "ui/ui_context.h" -#include "gfx/texture_atlas.h" -#include "gfx_es2/draw_buffer.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/UI/UI.h" +#include "Common/UI/Context.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/DrawBuffer.h" // TODO: UI should probably not own these. DrawBuffer ui_draw2d; diff --git a/ext/native/ui/ui.h b/Common/UI/UI.h similarity index 96% rename from ext/native/ui/ui.h rename to Common/UI/UI.h index f3e2ff327f..ccd6b50dbe 100644 --- a/ext/native/ui/ui.h +++ b/Common/UI/UI.h @@ -26,8 +26,8 @@ #include #include -#include "gfx_es2/draw_buffer.h" -#include "input/input_state.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Input/InputState.h" class UIContext; diff --git a/ext/native/ui/ui_screen.cpp b/Common/UI/UIScreen.cpp similarity index 97% rename from ext/native/ui/ui_screen.cpp rename to Common/UI/UIScreen.cpp index b0490bc762..8e8d447dc9 100644 --- a/ext/native/ui/ui_screen.cpp +++ b/Common/UI/UIScreen.cpp @@ -1,15 +1,20 @@ #include #include -#include "base/display.h" -#include "input/input_state.h" -#include "input/keycodes.h" -#include "math/curves.h" -#include "ui/ui_screen.h" -#include "ui/ui_context.h" -#include "ui/screen.h" -#include "ui/root.h" -#include "i18n/i18n.h" -#include "gfx_es2/draw_buffer.h" +#include + +#include "Common/System/Display.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Math/curves.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/Context.h" +#include "Common/UI/Screen.h" +#include "Common/UI/Root.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Render/DrawBuffer.h" + +#include "Common/Log.h" +#include "Common/StringUtils.h" static const bool ClickDebug = false; @@ -45,7 +50,7 @@ void UIScreen::DoRecreateViews() { // Update layout and refocus so things scroll into view. // This is for resizing down, when focused on something now offscreen. - UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_); + UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_, ignoreInsets_); UI::View *focused = UI::GetFocusedView(); if (focused) { root_->SubviewFocused(focused); @@ -80,7 +85,7 @@ void UIScreen::preRender() { } draw->BeginFrame(); // Bind and clear the back buffer - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }); + draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); screenManager()->getUIContext()->BeginFrame(); Draw::Viewport viewport; @@ -107,7 +112,7 @@ void UIScreen::render() { if (root_) { UIContext *uiContext = screenManager()->getUIContext(); - UI::LayoutViewHierarchy(*uiContext, root_); + UI::LayoutViewHierarchy(*uiContext, root_, ignoreInsets_); uiContext->PushTransform({translation_, scale_, alpha_}); @@ -135,11 +140,11 @@ TouchInput UIScreen::transformTouch(const TouchInput &touch) { bool UIScreen::touch(const TouchInput &touch) { if (root_) { if (ClickDebug && (touch.flags & TOUCH_DOWN)) { - ILOG("Touch down!"); + INFO_LOG(SYSTEM, "Touch down!"); std::vector views; root_->Query(touch.x, touch.y, views); for (auto view : views) { - ILOG("%s", view->Describe().c_str()); + INFO_LOG(SYSTEM, "%s", view->Describe().c_str()); } } @@ -164,10 +169,11 @@ bool UIDialogScreen::key(const KeyInput &key) { bool retval = UIScreen::key(key); if (!retval && (key.flags & KEY_DOWN) && UI::IsEscapeKey(key)) { if (finished_) { - ELOG("Screen already finished"); + ERROR_LOG(SYSTEM, "Screen already finished"); } else { finished_ = true; TriggerFinish(DR_BACK); + UI::PlayUISound(UI::UISound::BACK); } return true; } diff --git a/ext/native/ui/ui_screen.h b/Common/UI/UIScreen.h similarity index 99% rename from ext/native/ui/ui_screen.h rename to Common/UI/UIScreen.h index 1f1c5b4317..aa660b0084 100644 --- a/ext/native/ui/ui_screen.h +++ b/Common/UI/UIScreen.h @@ -2,9 +2,9 @@ #include -#include "math/lin/vec3.h" -#include "ui/screen.h" -#include "ui/viewgroup.h" +#include "Common/Math/lin/vec3.h" +#include "Common/UI/Screen.h" +#include "Common/UI/ViewGroup.h" using namespace Lin; @@ -48,6 +48,7 @@ protected: Vec3 translation_ = Vec3(0.0f); Vec3 scale_ = Vec3(1.0f); float alpha_ = 1.0f; + bool ignoreInsets_ = false; private: void DoRecreateViews(); diff --git a/ext/native/ui/view.cpp b/Common/UI/View.cpp similarity index 96% rename from ext/native/ui/view.cpp rename to Common/UI/View.cpp index d452b6a8a3..ebd0e993e7 100644 --- a/ext/native/ui/view.cpp +++ b/Common/UI/View.cpp @@ -1,20 +1,20 @@ #include #include -#include "base/stringutil.h" -#include "base/timeutil.h" -#include "input/input_state.h" -#include "input/keycodes.h" -#include "gfx_es2/draw_buffer.h" -#include "gfx/texture_atlas.h" -#include "util/text/utf8.h" -#include "ui/ui.h" -#include "ui/view.h" -#include "ui/ui_context.h" -#include "ui/ui_tween.h" -#include "ui/root.h" -#include "thin3d/thin3d.h" -#include "base/NativeApp.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/UI/UI.h" +#include "Common/UI/View.h" +#include "Common/UI/Context.h" +#include "Common/UI/Tween.h" +#include "Common/UI/Root.h" +#include "Common/GPU/thin3d.h" +#include "Common/System/System.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" namespace UI { @@ -161,9 +161,8 @@ void View::PersistData(PersistStatus status, std::string anonId, PersistMap &sto break; } - ITOA stringify; for (int i = 0; i < (int)tweens_.size(); ++i) { - tweens_[i]->PersistData(status, tag + "/" + stringify.p((int)i), storage); + tweens_[i]->PersistData(status, tag + "/" + StringFromInt(i), storage); } } @@ -200,12 +199,12 @@ Clickable::Clickable(LayoutParams *layoutParams) void Clickable::DrawBG(UIContext &dc, const Style &style) { if (style.background.type == DRAW_SOLID_COLOR) { - if (time_now() - bgColorLast_ >= 0.25f) { + if (time_now_d() - bgColorLast_ >= 0.25f) { bgColor_->Reset(style.background.color); } else { bgColor_->Divert(style.background.color, down_ ? 0.05f : 0.1f); } - bgColorLast_ = time_now(); + bgColorLast_ = time_now_d(); dc.FillRect(Drawable(bgColor_->CurrentValue()), bounds_); } else { @@ -376,6 +375,7 @@ bool StickyChoice::Key(const KeyInput &key) { if (key.flags & KEY_DOWN) { if (IsAcceptKey(key)) { down_ = true; + UI::PlayUISound(UI::UISound::TOGGLE_ON); Click(); return true; } @@ -424,6 +424,11 @@ void ClickableItem::Draw(UIContext &dc) { DrawBG(dc, style); } +void Choice::Click() { + ClickableItem::Click(); + UI::PlayUISound(UI::UISound::CONFIRM); +} + void Choice::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const { if (atlasImage_.isValid()) { dc.Draw()->GetAtlas()->measureImage(atlasImage_, &w, &h); @@ -596,8 +601,10 @@ void PopupHeader::Draw(UIContext &dc) { } void CheckBox::Toggle() { - if (toggle_) + if (toggle_) { *toggle_ = !(*toggle_); + UI::PlayUISound(*toggle_ ? UI::UISound::TOGGLE_ON : UI::UISound::TOGGLE_OFF); + } } bool CheckBox::Toggled() const { @@ -668,8 +675,14 @@ void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) con } void BitCheckBox::Toggle() { - if (bitfield_) + if (bitfield_) { *bitfield_ = *bitfield_ ^ bit_; + if (*bitfield_ & bit_) { + UI::PlayUISound(UI::UISound::TOGGLE_ON); + } else { + UI::PlayUISound(UI::UISound::TOGGLE_OFF); + } + } } bool BitCheckBox::Toggled() const { @@ -687,6 +700,14 @@ void Button::GetContentDimensions(const UIContext &dc, float &w, float &h) const // Add some internal padding to not look totally ugly w += paddingW_; h += paddingH_; + + w *= scale_; + h *= scale_; +} + +void Button::Click() { + Clickable::Click(); + UI::PlayUISound(UI::UISound::CONFIRM); } void Button::Draw(UIContext &dc) { @@ -700,12 +721,16 @@ void Button::Draw(UIContext &dc) { DrawBG(dc, style); float tw, th; dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &tw, &th); + tw *= scale_; + th *= scale_; + if (tw > bounds_.w || imageID_.isValid()) { dc.PushScissor(bounds_); } dc.SetFontStyle(dc.theme->uiFont); + dc.SetFontScale(scale_, scale_); if (imageID_.isValid() && text_.empty()) { - dc.Draw()->DrawImage(imageID_, bounds_.centerX(), bounds_.centerY(), 1.0f, 0xFFFFFFFF, ALIGN_CENTER); + dc.Draw()->DrawImage(imageID_, bounds_.centerX(), bounds_.centerY(), scale_, 0xFFFFFFFF, ALIGN_CENTER); } else if (!text_.empty()) { dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), style.fgColor, ALIGN_CENTER); if (imageID_.isValid()) { @@ -715,6 +740,8 @@ void Button::Draw(UIContext &dc) { } } } + dc.SetFontScale(1.0f, 1.0f); + if (tw > bounds_.w || imageID_.isValid()) { dc.PopScissor(); } diff --git a/ext/native/ui/view.h b/Common/UI/View.h similarity index 98% rename from ext/native/ui/view.h rename to Common/UI/View.h index 5cf1ad275c..97c5c10513 100644 --- a/ext/native/ui/view.h +++ b/Common/UI/View.h @@ -15,12 +15,12 @@ #include #include -#include "base/logging.h" -#include "base/basictypes.h" -#include "gfx/texture_atlas.h" -#include "math/lin/matrix4x4.h" -#include "math/math_util.h" -#include "math/geom2d.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Math/math_util.h" +#include "Common/Math/geom2d.h" + +#include "Common/Common.h" #undef small @@ -519,6 +519,7 @@ public: Button(const std::string &text, ImageID imageID, LayoutParams *layoutParams = 0) : Clickable(layoutParams), text_(text), imageID_(imageID) {} + void Click() override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; const std::string &GetText() const { return text_; } @@ -527,12 +528,18 @@ public: paddingH_ = h; } + // Needed an extra small button... + void SetScale(float f) { + scale_ = f; + } + private: Style style_; std::string text_; ImageID imageID_; int paddingW_ = 16; int paddingH_ = 8; + float scale_ = 1.0f; }; class Slider : public Clickable { @@ -647,6 +654,7 @@ public: Choice(ImageID image, LayoutParams *layoutParams = nullptr) : ClickableItem(layoutParams), atlasImage_(image), iconImage_(ImageID::invalid()), centered_(false), highlighted_(false), selected_(false) {} + void Click() override; virtual void HighlightChanged(bool highlighted); void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; void Draw(UIContext &dc) override; diff --git a/ext/native/ui/viewgroup.cpp b/Common/UI/ViewGroup.cpp similarity index 97% rename from ext/native/ui/viewgroup.cpp rename to Common/UI/ViewGroup.cpp index 7d188743f0..4c21baeb5e 100644 --- a/ext/native/ui/viewgroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1,19 +1,20 @@ +#include #include #include #include -#include "base/logging.h" -#include "base/stringutil.h" -#include "base/timeutil.h" -#include "input/keycodes.h" -#include "math/curves.h" -#include "ui/ui_context.h" -#include "ui/ui_tween.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "gfx_es2/draw_buffer.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Math/curves.h" +#include "Common/UI/Context.h" +#include "Common/UI/Tween.h" +#include "Common/UI/Root.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/Render/DrawBuffer.h" -#include +#include "Common/Log.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" namespace UI { @@ -69,9 +70,8 @@ void ViewGroup::PersistData(PersistStatus status, std::string anonId, PersistMap tag = anonId; } - ITOA stringify; for (size_t i = 0; i < views_.size(); i++) { - views_[i]->PersistData(status, tag + "/" + stringify.p((int)i), storage); + views_[i]->PersistData(status, tag + "/" + StringFromInt((int)i), storage); } } @@ -235,7 +235,7 @@ float GetDirectionScore(View *origin, View *destination, FocusDirection directio float horizOverlap = HorizontalOverlap(origin->GetBounds(), destination->GetBounds()); float vertOverlap = VerticalOverlap(origin->GetBounds(), destination->GetBounds()); if (horizOverlap == 1.0f && vertOverlap == 1.0f) { - ILOG("Contain overlap"); + INFO_LOG(SYSTEM, "Contain overlap"); return 0.0; } float originSize = 0.0f; @@ -272,7 +272,7 @@ float GetDirectionScore(View *origin, View *destination, FocusDirection directio break; case FOCUS_PREV: case FOCUS_NEXT: - ELOG("Invalid focus direction"); + ERROR_LOG(SYSTEM, "Invalid focus direction"); break; } @@ -1079,6 +1079,12 @@ void AnchorLayout::Layout() { } } +GridLayout::GridLayout(GridLayoutSettings settings, LayoutParams *layoutParams) + : ViewGroup(layoutParams), settings_(settings), numColumns_(1) { + if (settings.orientation != ORIENT_HORIZONTAL) + ERROR_LOG(SYSTEM, "GridLayout: Vertical layouts not yet supported"); +} + void GridLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) { MeasureSpecType measureType = settings_.fillCells ? EXACTLY : AT_MOST; @@ -1321,11 +1327,17 @@ void ChoiceStrip::HighlightChoice(unsigned int choice){ bool ChoiceStrip::Key(const KeyInput &input) { bool ret = false; if (input.flags & KEY_DOWN) { - if (IsTabLeftKey(input) && selected_ > 0) { - SetSelection(selected_ - 1); + if (IsTabLeftKey(input)) { + if (selected_ > 0) { + SetSelection(selected_ - 1); + UI::PlayUISound(UI::UISound::TOGGLE_OFF); // Maybe make specific sounds for this at some point? + } ret = true; - } else if (IsTabRightKey(input) && selected_ < (int)views_.size() - 1) { - SetSelection(selected_ + 1); + } else if (IsTabRightKey(input)) { + if (selected_ < (int)views_.size() - 1) { + SetSelection(selected_ + 1); + UI::PlayUISound(UI::UISound::TOGGLE_ON); + } ret = true; } } diff --git a/ext/native/ui/viewgroup.h b/Common/UI/ViewGroup.h similarity index 97% rename from ext/native/ui/viewgroup.h rename to Common/UI/ViewGroup.h index 286f922925..0d17642617 100644 --- a/ext/native/ui/viewgroup.h +++ b/Common/UI/ViewGroup.h @@ -5,10 +5,9 @@ #include #include -#include "base/logging.h" -#include "math/geom2d.h" -#include "input/gesture_detector.h" -#include "ui/view.h" +#include "Common/Math/geom2d.h" +#include "Common/Input/GestureDetector.h" +#include "Common/UI/View.h" namespace UI { @@ -209,11 +208,7 @@ struct GridLayoutSettings { class GridLayout : public ViewGroup { public: - GridLayout(GridLayoutSettings settings, LayoutParams *layoutParams = 0) - : ViewGroup(layoutParams), settings_(settings), numColumns_(1) { - if (settings.orientation != ORIENT_HORIZONTAL) - ELOG("GridLayout: Vertical layouts not yet supported"); - } + GridLayout(GridLayoutSettings settings, LayoutParams *layoutParams = 0); void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; diff --git a/Common/Vulkan/VulkanDebug.cpp b/Common/Vulkan/VulkanDebug.cpp deleted file mode 100644 index 55825f8209..0000000000 --- a/Common/Vulkan/VulkanDebug.cpp +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2016- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include -#include -#include - -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanDebug.h" -#include "base/logging.h" - -const char *ObjTypeToString(VkDebugReportObjectTypeEXT type) { - switch (type) { - case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT: return "Instance"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT: return "PhysicalDevice"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT: return "Device"; - case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT: return "Queue"; - case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT: return "CommandBuffer"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: return "DeviceMemory"; - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: return "Buffer"; - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: return "BufferView"; - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: return "Image"; - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: return "ImageView"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT: return "ShaderModule"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: return "Pipeline"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT: return "PipelineLayout"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: return "Sampler"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: return "DescriptorSet"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT: return "DescriptorSetLayout"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: return "DescriptorPool"; - case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT: return "Fence"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT: return "Semaphore"; - case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: return "Event"; - case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: return "QueryPool"; - case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: return "Framebuffer"; - case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: return "RenderPass"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT: return "PipelineCache"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT: return "SurfaceKHR"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: return "SwapChainKHR"; - case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: return "CommandPool"; - default: return ""; - } -} - -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; - - if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { - message << "ERROR: "; - } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - message << "WARNING: "; - } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { - message << "PERFORMANCE WARNING: "; - } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { - message << "INFO: "; - } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { - message << "DEBUG: "; - } - message << "[" << pLayerPrefix << "] " << ObjTypeToString(objType) << " Code " << msgCode << " : " << pMsg << "\n"; - - 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) - return false; // Not exactly a false positive, see https://github.com/KhronosGroup/glslang/issues/1418 -#ifdef _WIN32 - std::string msg = message.str(); - OutputDebugStringA(msg.c_str()); - if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { - if (options->breakOnError && IsDebuggerPresent()) { - DebugBreak(); - } - if (options->msgBoxOnError) { - MessageBoxA(NULL, message.str().c_str(), "Alert", MB_OK); - } - } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - if (options->breakOnWarning && IsDebuggerPresent()) { - DebugBreak(); - } - } -#else - ILOG("%s", message.str().c_str()); -#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; -} - -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; - - // Apparent bugs around timestamp validation in the validation layers - if (strstr(pMessage, "vkCmdBeginQuery(): VkQueryPool")) - return false; - if (strstr(pMessage, "vkGetQueryPoolResults() on VkQueryPool")) - return false; - - 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; -} diff --git a/Common/XboxCPUDetect.cpp b/Common/XboxCPUDetect.cpp deleted file mode 100644 index b9b502a71a..0000000000 --- a/Common/XboxCPUDetect.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - - -#include -#include "base/logging.h" -#include "base/basictypes.h" -#include "Common.h" -#include "CPUDetect.h" -#include "StringUtils.h" - -CPUInfo cpu_info; - -CPUInfo::CPUInfo() { - Detect(); -} - -// Detects the various cpu features -void CPUInfo::Detect() -{ - memset(this, 0, sizeof(*this)); - num_cores = 3; - strcpy(cpu_string, "Xenon"); - strcpy(brand_string, "Microsoft"); - - memset(cpu_string, 0, sizeof(cpu_string)); - - HTT = true; - logical_cpu_count = 2; -} - -// Turn the cpu info into a string we can show -std::string CPUInfo::Summarize() -{ - std::string sum; - if (num_cores == 1) - sum = StringFromFormat("%s, %i core", cpu_string, num_cores); - else - { - sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); - if (HTT) sum += StringFromFormat(" (%i logical threads per physical core)", logical_cpu_count); - } - if (bSSE) sum += ", SSE"; - if (bSSE2) sum += ", SSE2"; - if (bSSE3) sum += ", SSE3"; - if (bSSSE3) sum += ", SSSE3"; - if (bSSE4_1) sum += ", SSE4.1"; - if (bSSE4_2) sum += ", SSE4.2"; - if (HTT) sum += ", HTT"; - if (bAVX) sum += ", AVX"; - if (bAES) sum += ", AES"; - if (bLongMode) sum += ", 64-bit support"; - return sum; -} \ No newline at end of file diff --git a/Common/stdafx.cpp b/Common/stdafx.cpp deleted file mode 100644 index 0348c60f8d..0000000000 --- a/Common/stdafx.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// Common.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#ifdef _WIN32 - -#include "stdafx.h" - -#endif -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/Common/x64Analyzer.cpp b/Common/x64Analyzer.cpp index 1940416d6a..1a9d236db6 100644 --- a/Common/x64Analyzer.cpp +++ b/Common/x64Analyzer.cpp @@ -15,10 +15,13 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#include "x64Analyzer.h" +#include "Common/Log.h" +#include "Common/x64Analyzer.h" -bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType) +bool X86AnalyzeMOV(const unsigned char *codePtr, LSInstructionInfo &info) { + int accessType = 0; + unsigned const char *startCodePtr = codePtr; u8 rex = 0; u8 codeByte = 0; @@ -80,6 +83,12 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc modRMbyte = *codePtr++; hasModRM = true; } + + // TODO: Add more cases. + if ((codeByte & 0xF0) == 0x80) + accessType = 1; + if ((codeByte & 0xF0) == 0xC0) + accessType = 1; } else { @@ -135,7 +144,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc else info.displacement = *((s32 *)codePtr); codePtr += displacementSize; - if (accessType == 1) { @@ -176,8 +184,11 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc case MOVE_REG_TO_MEM: //move reg to memory break; + case MOVE_MEM_TO_REG: + break; + default: - PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid."); + ERROR_LOG(CPU, "Unhandled disasm case in write handler!\n\nPlease implement or avoid."); return false; } } diff --git a/Common/x64Analyzer.h b/Common/x64Analyzer.h index ad2fed886d..f9a35e785c 100644 --- a/Common/x64Analyzer.h +++ b/Common/x64Analyzer.h @@ -19,7 +19,7 @@ #include "Common.h" -struct InstructionInfo +struct LSInstructionInfo { int operandSize; //8, 16, 32, 64 int instructionSize; @@ -53,6 +53,7 @@ enum { MOVE_8BIT = 0xC6, //move 8-bit immediate MOVE_16_32BIT = 0xC7, //move 16 or 32-bit immediate MOVE_REG_TO_MEM = 0x89, //move reg to memory + MOVE_MEM_TO_REG = 0x8B, //move memory to reg }; enum AccessType { @@ -60,4 +61,4 @@ enum AccessType { OP_ACCESS_WRITE = 1 }; -bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType); +bool X86AnalyzeMOV(const unsigned char *codePtr, LSInstructionInfo &info); diff --git a/Common/x64Emitter.cpp b/Common/x64Emitter.cpp index df14332f13..82c790c36f 100644 --- a/Common/x64Emitter.cpp +++ b/Common/x64Emitter.cpp @@ -21,13 +21,9 @@ #include "ABI.h" #include "CPUDetect.h" #include "MemoryUtil.h" -#include "MsgHandler.h" #define PRIx64 "llx" -// Minimize the diff against Dolphin -#define DYNA_REC JIT - namespace Gen { @@ -148,7 +144,7 @@ const u8 *XEmitter::AlignCodePage() // causing a subtle JIT bug. void XEmitter::CheckFlags() { - _assert_msg_(DYNA_REC, !flags_locked, "Attempt to modify flags while flags locked!"); + _assert_msg_(!flags_locked, "Attempt to modify flags while flags locked!"); } void XEmitter::WriteModRM(int mod, int reg, int rm) @@ -182,16 +178,16 @@ void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const { emit->Write8(op); // Check the operation doesn't access AH, BH, CH, or DH. - _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 0x100) == 0); - _dbg_assert_(DYNA_REC, (customOp & 0x100) == 0); + _dbg_assert_((offsetOrBaseReg & 0x100) == 0); + _dbg_assert_((customOp & 0x100) == 0); } #else - _dbg_assert_(DYNA_REC, opBits != 64); - _dbg_assert_(DYNA_REC, (customOp & 8) == 0 || customOp == -1); - _dbg_assert_(DYNA_REC, (indexReg & 8) == 0); - _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 8) == 0); - _dbg_assert_(DYNA_REC, opBits != 8 || (customOp & 0x10c) != 4 || customOp == -1); - _dbg_assert_(DYNA_REC, scale == SCALE_ATREG || bits != 8 || (offsetOrBaseReg & 0x10c) != 4); + _dbg_assert_(opBits != 64); + _dbg_assert_((customOp & 8) == 0 || customOp == -1); + _dbg_assert_((indexReg & 8) == 0); + _dbg_assert_((offsetOrBaseReg & 8) == 0); + _dbg_assert_(opBits != 8 || (customOp & 0x10c) != 4 || customOp == -1); + _dbg_assert_(scale == SCALE_ATREG || bits != 8 || (offsetOrBaseReg & 0x10c) != 4); #endif } @@ -239,7 +235,7 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, #ifdef _M_X64 u64 ripAddr = (u64)emit->GetCodePointer() + 4 + extraBytes; s64 distance = (s64)offset - (s64)ripAddr; - _assert_msg_(DYNA_REC, + _assert_msg_( (distance < 0x80000000LL && distance >= -0x80000000LL) || !warn_64bit_offset, @@ -344,7 +340,7 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, case SCALE_NOBASE_4: ss = 2; break; case SCALE_NOBASE_8: ss = 3; break; case SCALE_ATREG: ss = 0; break; - default: _assert_msg_(DYNA_REC, 0, "Invalid scale for SIB byte"); ss = 0; break; + default: _assert_msg_(false, "Invalid scale for SIB byte"); ss = 0; break; } emit->Write8((u8)((ss << 6) | ((ireg&7)<<3) | (_offsetOrBaseReg&7))); } @@ -380,7 +376,7 @@ void XEmitter::JMP(const u8 *addr, bool force5Bytes) if (!force5Bytes) { s64 distance = (s64)(fn - ((u64)code + 2)); - _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, + _assert_msg_(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); //8 bits will do Write8(0xEB); @@ -390,8 +386,7 @@ void XEmitter::JMP(const u8 *addr, bool force5Bytes) { s64 distance = (s64)(fn - ((u64)code + 5)); - _assert_msg_(DYNA_REC, - distance >= -0x80000000LL && distance < 0x80000000LL, + _assert_msg_(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); Write8(0xE9); Write32((u32)(s32)distance); @@ -401,7 +396,7 @@ void XEmitter::JMP(const u8 *addr, bool force5Bytes) void XEmitter::JMPptr(const OpArg &arg2) { OpArg arg = arg2; - if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "JMPptr - Imm argument"); + if (arg.IsImm()) _assert_msg_(false, "JMPptr - Imm argument"); arg.operandReg = 4; arg.WriteRex(this, 0, 0); Write8(0xFF); @@ -418,7 +413,7 @@ void XEmitter::JMPself() void XEmitter::CALLptr(OpArg arg) { - if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "CALLptr - Imm argument"); + if (arg.IsImm()) _assert_msg_(false, "CALLptr - Imm argument"); arg.operandReg = 2; arg.WriteRex(this, 0, 0); Write8(0xFF); @@ -428,8 +423,7 @@ void XEmitter::CALLptr(OpArg arg) void XEmitter::CALL(const void *fnptr) { u64 distance = u64(fnptr) - (u64(code) + 5); - _assert_msg_(DYNA_REC, - distance < 0x0000000080000000ULL || + _assert_msg_(distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL, "CALL out of range (%p calls %p)", code, fnptr); Write8(0xE8); @@ -482,8 +476,7 @@ void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) if (distance < -0x80 || distance >= 0x80 || force5bytes) { distance = (s64)(fn - ((u64)code + 6)); - _assert_msg_(DYNA_REC, - distance >= -0x80000000LL && distance < 0x80000000LL, + _assert_msg_(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); Write8(0x0F); Write8(0x80 + conditionCode); @@ -501,13 +494,13 @@ void XEmitter::SetJumpTarget(const FixupBranch &branch) if (branch.type == 0) { s64 distance = (s64)(code - branch.ptr); - _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); + _assert_msg_(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); branch.ptr[-1] = (u8)(s8)distance; } else if (branch.type == 1) { s64 distance = (s64)(code - branch.ptr); - _assert_msg_(DYNA_REC, distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); + _assert_msg_(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); ((s32*)branch.ptr)[-1] = (s32)distance; } } @@ -518,7 +511,7 @@ void XEmitter::SetJumpTarget(const FixupBranch &branch) /* void XEmitter::INC(int bits, OpArg arg) { - if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "INC - Imm argument"); + if (arg.IsImm()) _assert_msg_(false, "INC - Imm argument"); arg.operandReg = 0; if (bits == 16) {Write8(0x66);} arg.WriteRex(this, bits, bits); @@ -527,7 +520,7 @@ void XEmitter::INC(int bits, OpArg arg) } void XEmitter::DEC(int bits, OpArg arg) { - if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "DEC - Imm argument"); + if (arg.IsImm()) _assert_msg_(false, "DEC - Imm argument"); arg.operandReg = 1; if (bits == 16) {Write8(0x66);} arg.WriteRex(this, bits, bits); @@ -545,7 +538,7 @@ void XEmitter::RET_FAST() {Write8(0xF3); Write8(0xC3);} //two-byte return (rep // The first sign of decadence: optimized NOPs. void XEmitter::NOP(size_t size) { - _dbg_assert_(DYNA_REC, (int)size > 0); + _dbg_assert_((int)size > 0); while (true) { switch (size) @@ -689,7 +682,7 @@ void XEmitter::PUSH(int bits, const OpArg ®) Write32((u32)reg.offset); break; default: - _assert_msg_(DYNA_REC, 0, "PUSH - Bad imm bits"); + _assert_msg_(false, "PUSH - Bad imm bits"); break; } } @@ -708,7 +701,7 @@ void XEmitter::POP(int /*bits*/, const OpArg ®) if (reg.IsSimpleReg()) POP(reg.GetSimpleReg()); else - _assert_msg_(DYNA_REC, 0, "POP - Unsupported encoding"); + _assert_msg_(false, "POP - Unsupported encoding"); } void XEmitter::BSWAP(int bits, X64Reg reg) @@ -727,7 +720,7 @@ void XEmitter::BSWAP(int bits, X64Reg reg) } else { - _assert_msg_(DYNA_REC, 0, "BSWAP - Wrong number of bits"); + _assert_msg_(false, "BSWAP - Wrong number of bits"); } } @@ -741,7 +734,7 @@ void XEmitter::UD2() void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) { - _assert_msg_(DYNA_REC, !arg.IsImm(), "PREFETCH - Imm argument"); + _assert_msg_(!arg.IsImm(), "PREFETCH - Imm argument"); arg.operandReg = (u8)level; arg.WriteRex(this, 0, 0); Write8(0x0F); @@ -751,7 +744,7 @@ void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) void XEmitter::SETcc(CCFlags flag, OpArg dest) { - _assert_msg_(DYNA_REC, !dest.IsImm(), "SETcc - Imm argument"); + _assert_msg_(!dest.IsImm(), "SETcc - Imm argument"); dest.operandReg = 0; dest.WriteRex(this, 0, 8); Write8(0x0F); @@ -761,8 +754,8 @@ void XEmitter::SETcc(CCFlags flag, OpArg dest) void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) { - _assert_msg_(DYNA_REC, !src.IsImm(), "CMOVcc - Imm argument"); - _assert_msg_(DYNA_REC, bits != 8, "CMOVcc - 8 bits unsupported"); + _assert_msg_(!src.IsImm(), "CMOVcc - Imm argument"); + _assert_msg_(bits != 8, "CMOVcc - 8 bits unsupported"); if (bits == 16) Write8(0x66); src.operandReg = dest; @@ -774,7 +767,7 @@ void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) { - _assert_msg_(DYNA_REC, !src.IsImm(), "WriteMulDivType - Imm argument"); + _assert_msg_(!src.IsImm(), "WriteMulDivType - Imm argument"); CheckFlags(); src.operandReg = ext; if (bits == 16) @@ -800,7 +793,7 @@ void XEmitter::NOT(int bits, OpArg src) {WriteMulDivType(bits, src, 2);} void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) { - _assert_msg_(DYNA_REC, !src.IsImm(), "WriteBitSearchType - Imm argument"); + _assert_msg_(!src.IsImm(), "WriteBitSearchType - Imm argument"); CheckFlags(); src.operandReg = (u8)dest; if (bits == 16) @@ -816,7 +809,7 @@ void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bo void XEmitter::MOVNTI(int bits, OpArg dest, X64Reg src) { if (bits <= 16) - _assert_msg_(DYNA_REC, 0, "MOVNTI - bits<=16"); + _assert_msg_(false, "MOVNTI - bits<=16"); WriteBitSearchType(bits, src, dest, 0xC3); } @@ -826,21 +819,19 @@ void XEmitter::BSR(int bits, X64Reg dest, OpArg src) {WriteBitSearchType(bits,de void XEmitter::TZCNT(int bits, X64Reg dest, OpArg src) { CheckFlags(); - if (!cpu_info.bBMI1) - PanicAlert("Trying to use BMI1 on a system that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bBMI1, "Trying to use BMI1 on a system that doesn't support it."); WriteBitSearchType(bits, dest, src, 0xBC, true); } void XEmitter::LZCNT(int bits, X64Reg dest, OpArg src) { CheckFlags(); - if (!cpu_info.bLZCNT) - PanicAlert("Trying to use LZCNT on a system that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bLZCNT, "Trying to use LZCNT on a system that doesn't support it."); WriteBitSearchType(bits, dest, src, 0xBD, true); } void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) { - _assert_msg_(DYNA_REC, !src.IsImm(), "MOVSX - Imm argument"); + _assert_msg_(!src.IsImm(), "MOVSX - Imm argument"); if (dbits == sbits) { MOV(dbits, R(dest), src); @@ -873,7 +864,7 @@ void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) { - _assert_msg_(DYNA_REC, !src.IsImm(), "MOVZX - Imm argument"); + _assert_msg_(!src.IsImm(), "MOVZX - Imm argument"); if (dbits == sbits) { MOV(dbits, R(dest), src); @@ -900,14 +891,14 @@ void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) } else { - _assert_msg_(DYNA_REC, 0, "MOVZX - Invalid size"); + _assert_msg_(false, "MOVZX - Invalid size"); } src.WriteRest(this); } void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) { - _assert_msg_(DYNA_REC, cpu_info.bMOVBE, "Generating MOVBE on a system that does not support it."); + _assert_msg_(cpu_info.bMOVBE, "Generating MOVBE on a system that does not support it."); if (bits == 8) { MOV(bits, dest, src); @@ -919,28 +910,28 @@ void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) if (dest.IsSimpleReg()) { - _assert_msg_(DYNA_REC, !src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem"); + _assert_msg_(!src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem"); src.WriteRex(this, bits, bits, dest.GetSimpleReg()); Write8(0x0F); Write8(0x38); Write8(0xF0); src.WriteRest(this, 0, dest.GetSimpleReg()); } else if (src.IsSimpleReg()) { - _assert_msg_(DYNA_REC, !dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem"); + _assert_msg_(!dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem"); dest.WriteRex(this, bits, bits, src.GetSimpleReg()); Write8(0x0F); Write8(0x38); Write8(0xF1); dest.WriteRest(this, 0, src.GetSimpleReg()); } else { - _assert_msg_(DYNA_REC, 0, "MOVBE: Not loading or storing to mem"); + _assert_msg_(false, "MOVBE: Not loading or storing to mem"); } } void XEmitter::LEA(int bits, X64Reg dest, OpArg src) { - _assert_msg_(DYNA_REC, !src.IsImm(), "LEA - Imm argument"); + _assert_msg_(!src.IsImm(), "LEA - Imm argument"); src.operandReg = (u8)dest; if (bits == 16) Write8(0x66); //TODO: performance warning @@ -956,11 +947,11 @@ void XEmitter::WriteShift(int bits, OpArg dest, OpArg &shift, int ext) bool writeImm = false; if (dest.IsImm()) { - _assert_msg_(DYNA_REC, 0, "WriteShift - can't shift imms"); + _assert_msg_(false, "WriteShift - can't shift imms"); } if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) { - _assert_msg_(DYNA_REC, 0, "WriteShift - illegal argument"); + _assert_msg_(false, "WriteShift - illegal argument"); } dest.operandReg = ext; if (bits == 16) @@ -1005,11 +996,11 @@ void XEmitter::WriteBitTest(int bits, OpArg &dest, OpArg &index, int ext) CheckFlags(); if (dest.IsImm()) { - _assert_msg_(DYNA_REC, 0, "WriteBitTest - can't test imms"); + _assert_msg_(false, "WriteBitTest - can't test imms"); } if ((index.IsImm() && index.GetImmBits() != 8)) { - _assert_msg_(DYNA_REC, 0, "WriteBitTest - illegal argument"); + _assert_msg_(false, "WriteBitTest - illegal argument"); } if (bits == 16) Write8(0x66); @@ -1040,15 +1031,15 @@ void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift) CheckFlags(); if (dest.IsImm()) { - _assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination"); + _assert_msg_(false, "SHRD - can't use imms as destination"); } if (!src.IsSimpleReg()) { - _assert_msg_(DYNA_REC, 0, "SHRD - must use simple register as source"); + _assert_msg_(false, "SHRD - must use simple register as source"); } if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) { - _assert_msg_(DYNA_REC, 0, "SHRD - illegal shift"); + _assert_msg_(false, "SHRD - illegal shift"); } if (bits == 16) Write8(0x66); @@ -1072,15 +1063,15 @@ void XEmitter::SHLD(int bits, OpArg dest, OpArg src, OpArg shift) CheckFlags(); if (dest.IsImm()) { - _assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination"); + _assert_msg_(false, "SHLD - can't use imms as destination"); } if (!src.IsSimpleReg()) { - _assert_msg_(DYNA_REC, 0, "SHLD - must use simple register as source"); + _assert_msg_(false, "SHLD - must use simple register as source"); } if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) { - _assert_msg_(DYNA_REC, 0, "SHLD - illegal shift"); + _assert_msg_(false, "SHLD - illegal shift"); } if (bits == 16) Write8(0x66); @@ -1116,7 +1107,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o X64Reg _operandReg; if (IsImm()) { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Imm argument, wrong order"); + _assert_msg_(false, "WriteNormalOp - Imm argument, wrong order"); } if (bits == 16) @@ -1130,7 +1121,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o if (!toRM) { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Writing to Imm (!toRM)"); + _assert_msg_(false, "WriteNormalOp - Writing to Imm (!toRM)"); } if (operand.scale == SCALE_IMM8 && bits == 8) @@ -1206,7 +1197,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o { if (scale) { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - MOV with 64-bit imm requres register destination"); + _assert_msg_(false, "WriteNormalOp - MOV with 64-bit imm requres register destination"); } // mov reg64, imm64 else if (op == nrmMOV) @@ -1215,11 +1206,11 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o emit->Write64((u64)operand.offset); return; } - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Only MOV can take 64-bit imm"); + _assert_msg_(false, "WriteNormalOp - Only MOV can take 64-bit imm"); } else { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case"); + _assert_msg_(false, "WriteNormalOp - Unhandled case"); } _operandReg = (X64Reg)normalops[op].ext; //pass extension in REG of ModRM } @@ -1253,7 +1244,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o emit->Write32((u32)operand.offset); break; default: - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case"); + _assert_msg_(false, "WriteNormalOp - Unhandled case"); } } @@ -1262,7 +1253,7 @@ void XEmitter::WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg if (a1.IsImm()) { //Booh! Can't write to an imm - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - a1 cannot be imm"); + _assert_msg_(false, "WriteNormalOp - a1 cannot be imm"); return; } if (a2.IsImm()) @@ -1277,7 +1268,7 @@ void XEmitter::WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg } else { - _assert_msg_(DYNA_REC, a2.IsSimpleReg() || a2.IsImm(), "WriteNormalOp - a1 and a2 cannot both be memory"); + _assert_msg_(a2.IsSimpleReg() || a2.IsImm(), "WriteNormalOp - a1 and a2 cannot both be memory"); a1.WriteNormalOp(emit, true, op, a2, bits); } } @@ -1293,7 +1284,7 @@ void XEmitter::XOR (int bits, const OpArg &a1, const OpArg &a2) {CheckFlags(); W void XEmitter::MOV (int bits, const OpArg &a1, const OpArg &a2) { if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) - ERROR_LOG(DYNA_REC, "Redundant MOV @ %p - bug in JIT?", code); + ERROR_LOG(JIT, "Redundant MOV @ %p - bug in JIT?", code); WriteNormalOp(this, bits, nrmMOV, a1, a2); } void XEmitter::TEST(int bits, const OpArg &a1, const OpArg &a2) {CheckFlags(); WriteNormalOp(this, bits, nrmTEST, a1, a2);} @@ -1305,19 +1296,19 @@ void XEmitter::IMUL(int bits, X64Reg regOp, OpArg a1, OpArg a2) CheckFlags(); if (bits == 8) { - _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!"); + _assert_msg_(false, "IMUL - illegal bit size!"); return; } if (a1.IsImm()) { - _assert_msg_(DYNA_REC, 0, "IMUL - second arg cannot be imm!"); + _assert_msg_(false, "IMUL - second arg cannot be imm!"); return; } if (!a2.IsImm()) { - _assert_msg_(DYNA_REC, 0, "IMUL - third arg must be imm!"); + _assert_msg_(false, "IMUL - third arg must be imm!"); return; } @@ -1348,7 +1339,7 @@ void XEmitter::IMUL(int bits, X64Reg regOp, OpArg a1, OpArg a2) } else { - _assert_msg_(DYNA_REC, 0, "IMUL - unhandled case!"); + _assert_msg_(false, "IMUL - unhandled case!"); } } } @@ -1358,7 +1349,7 @@ void XEmitter::IMUL(int bits, X64Reg regOp, OpArg a) CheckFlags(); if (bits == 8) { - _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!"); + _assert_msg_(false, "IMUL - illegal bit size!"); return; } @@ -1420,8 +1411,7 @@ static int GetVEXpp(u8 opPrefix) void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, OpArg arg, int extrabytes) { - if (!cpu_info.bAVX) - PanicAlert("Trying to use AVX on a system that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bAVX, "Trying to use AVX on a system that doesn't support it."); int mmmmm = GetVEXmmmmm(op); int pp = GetVEXpp(opPrefix); // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size here @@ -1433,8 +1423,7 @@ void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, OpA // Like the above, but more general; covers GPR-based VEX operations, like BMI1/2 void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, OpArg arg, int extrabytes) { - if (size != 32 && size != 64) - PanicAlert("VEX GPR instructions only support 32-bit and 64-bit modes!"); + _assert_msg_(size == 32 || size == 64, "VEX GPR instructions only support 32-bit and 64-bit modes!"); int mmmmm = GetVEXmmmmm(op); int pp = GetVEXpp(opPrefix); arg.WriteVex(this, regOp1, regOp2, 0, pp, mmmmm, size == 64); @@ -1445,16 +1434,14 @@ void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg r void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, OpArg arg, int extrabytes) { CheckFlags(); - if (!cpu_info.bBMI1) - PanicAlert("Trying to use BMI1 on a system that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bBMI1, "Trying to use BMI1 on a system that doesn't support it."); WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); } void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, OpArg arg, int extrabytes) { CheckFlags(); - if (!cpu_info.bBMI2) - PanicAlert("Trying to use BMI2 on a system that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bBMI2, "Trying to use BMI2 on a system that doesn't support it."); WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); } @@ -1508,7 +1495,7 @@ void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) void XEmitter::WriteMXCSR(OpArg arg, int ext) { if (arg.IsImm() || arg.IsSimpleReg()) - _assert_msg_(DYNA_REC, 0, "MXCSR - invalid operand"); + _assert_msg_(false, "MXCSR - invalid operand"); arg.operandReg = ext; arg.WriteRex(this, 0, 0); @@ -1748,15 +1735,13 @@ void XEmitter::PMULUDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0xF4, de void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes) { - if (!cpu_info.bSSSE3) - PanicAlert("Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bSSSE3, "Trying to use SSSE3 on a system that doesn't support it."); WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); } void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes) { - if (!cpu_info.bSSE4_1) - PanicAlert("Trying to use SSE4.1 on a system that doesn't support it. Bad programmer."); + _assert_msg_(cpu_info.bSSE4_1, "Trying to use SSE4.1 on a system that doesn't support it."); WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); } @@ -1968,13 +1953,13 @@ void XEmitter::FWAIT() void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, OpArg arg) { int mf = 0; - _assert_msg_(DYNA_REC, !(bits == 80 && op_80b == floatINVALID), "WriteFloatLoadStore: 80 bits not supported for this instruction"); + _assert_msg_(!(bits == 80 && op_80b == floatINVALID), "WriteFloatLoadStore: 80 bits not supported for this instruction"); switch (bits) { case 32: mf = 0; break; case 64: mf = 4; break; case 80: mf = 2; break; - default: _assert_msg_(DYNA_REC, 0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); + default: _assert_msg_(false, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); } Write8(0xd9 | mf); // x87 instructions use the reg field of the ModR/M byte as opcode: diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h index 30309f71ba..fe32fa0d6d 100644 --- a/Common/x64Emitter.h +++ b/Common/x64Emitter.h @@ -15,14 +15,15 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#ifndef _DOLPHIN_INTEL_CODEGEN_ -#define _DOLPHIN_INTEL_CODEGEN_ +#pragma once #include "ppsspp_config.h" #include -#include "Common.h" -#include "CodeBlock.h" + +#include "Common/Common.h" +#include "Common/Log.h" +#include "Common/CodeBlock.h" #if PPSSPP_ARCH(64BIT) #define PTRBITS 64 @@ -292,7 +293,7 @@ template<> inline u32 PtrOffsetTpl<8>(const void *ptr, const void* base) { if (distance >= 0x80000000LL || distance < -0x80000000LL) { - _assert_msg_(DYNA_REC, 0, "pointer offset out of range"); + _assert_msg_(false, "pointer offset out of range"); return 0; } @@ -1083,5 +1084,3 @@ public: }; } // namespace - -#endif diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 1786eede35..19cbcf1227 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -23,8 +23,7 @@ extern "C" { #endif -#include "Common/FileUtil.h" -#include "Common/MsgHandler.h" +#include "Common/File/FileUtil.h" #include "Common/ColorConv.h" #include "Core/Config.h" diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index d98611bcc8..c7c4cd6e75 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -15,7 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "file/ini_file.h" +#include + +#include "Common/Data/Format/IniFile.h" #include "Core/Compatibility.h" #include "Core/System.h" @@ -80,6 +82,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "MoreAccurateVMMUL", &flags_.MoreAccurateVMMUL); CheckSetting(iniFile, gameID, "ForceSoftwareRenderer", &flags_.ForceSoftwareRenderer); CheckSetting(iniFile, gameID, "DarkStalkersPresentHack", &flags_.DarkStalkersPresentHack); + CheckSetting(iniFile, gameID, "ReportSmallMemstick", &flags_.ReportSmallMemstick); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 0b9a3403f1..7a4ab421a2 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -80,6 +80,7 @@ struct CompatFlags { bool MoreAccurateVMMUL; bool ForceSoftwareRenderer; bool DarkStalkersPresentHack; + bool ReportSmallMemstick; }; class IniFile; diff --git a/Core/Config.cpp b/Core/Config.cpp index 2b4680bf5a..ff21343c4e 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -20,29 +20,34 @@ #include #include #include +#include -#include "base/display.h" -#include "base/NativeApp.h" -#include "file/ini_file.h" -#include "i18n/i18n.h" -#include "json/json_reader.h" -#include "gfx_es2/gpu_features.h" -#include "net/http_client.h" -#include "util/text/parsers.h" -#include "net/url.h" +#include "ppsspp_config.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Net/HTTPClient.h" +#include "Common/Net/URL.h" + +#include "Common/Log.h" +#include "Common/Data/Format/IniFile.h" +#include "Common/Data/Format/JSONReader.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Text/Parsers.h" #include "Common/CPUDetect.h" -#include "Common/FileUtil.h" -#include "Common/KeyMap.h" +#include "Common/File/FileUtil.h" #include "Common/LogManager.h" #include "Common/OSVersion.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" #include "Common/StringUtils.h" -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Loaders.h" +#include "Core/KeyMap.h" #include "Core/HLE/sceUtility.h" -#include "GPU/Common/FramebufferCommon.h" +#include "Core/Instance.h" +#include "GPU/Common/FramebufferManagerCommon.h" // TODO: Find a better place for this. http::Downloader g_DownloadManager; @@ -201,7 +206,7 @@ struct ConfigSetting { return type_ != TYPE_TERMINATOR; } - bool Get(IniFile::Section *section) { + bool Get(Section *section) { switch (type_) { case TYPE_BOOL: if (cb_.b) { @@ -249,12 +254,12 @@ struct ConfigSetting { } return true; default: - _dbg_assert_msg_(LOADER, false, "Unexpected ini setting type"); + _dbg_assert_msg_(false, "Unexpected ini setting type"); return false; } } - void Set(IniFile::Section *section) { + void Set(Section *section) { if (!save_) return; @@ -282,7 +287,7 @@ struct ConfigSetting { } return; default: - _dbg_assert_msg_(LOADER, false, "Unexpected ini setting type"); + _dbg_assert_msg_(false, "Unexpected ini setting type"); return; } } @@ -306,7 +311,7 @@ struct ConfigSetting { // Doesn't report. return; default: - _dbg_assert_msg_(LOADER, false, "Unexpected ini setting type"); + _dbg_assert_msg_(false, "Unexpected ini setting type"); return; } } @@ -375,6 +380,10 @@ std::string CreateRandMAC() { srand(time(nullptr)); for (int i = 0; i < 6; i++) { u32 value = rand() % 256; + if (i == 0) { + // Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo) + value &= 0xfc; + } if (value <= 15) randStream << '0' << std::hex << value; else @@ -387,11 +396,13 @@ std::string CreateRandMAC() { } static int DefaultNumWorkers() { - return cpu_info.num_cores; + // Let's cap the global thread pool at 16 threads. Nothing we do really should have much + // use for more... + return std::min(16, cpu_info.num_cores); } static int DefaultCpuCore() { -#if defined(ARM) || defined(ARM64) || defined(_M_IX86) || defined(_M_X64) +#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) || PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) return (int)CPUCore::JIT; #else return (int)CPUCore::INTERPRETER; @@ -399,7 +410,7 @@ static int DefaultCpuCore() { } static bool DefaultCodeGen() { -#if defined(ARM) || defined(ARM64) || defined(_M_IX86) || defined(_M_X64) +#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) || PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) return true; #else return false; @@ -436,6 +447,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("Language", &g_Config.sLanguageIni, &DefaultLangRegion), ConfigSetting("ForceLagSync2", &g_Config.bForceLagSync, false, true, true), ConfigSetting("DiscordPresence", &g_Config.bDiscordPresence, false, true, false), // Or maybe it makes sense to have it per-game? Race conditions abound... + ConfigSetting("UISound", &g_Config.bUISound, false, true, false), ReportedConfigSetting("NumWorkerThreads", &g_Config.iNumWorkerThreads, &DefaultNumWorkers, true, true), ConfigSetting("AutoLoadSaveState", &g_Config.iAutoLoadSaveState, 0, true, true), @@ -455,19 +467,19 @@ static ConfigSetting generalSettings[] = { ConfigSetting("EnableStateUndo", &g_Config.bEnableStateUndo, false/*&DefaultEnableStateUndo*/, true, true), ConfigSetting("RewindFlipFrequency", &g_Config.iRewindFlipFrequency, 0, true, true), - ConfigSetting("ShowRegionOnGameIcon", &g_Config.bShowRegionOnGameIcon, false, true, true), - ConfigSetting("ShowIDOnGameIcon", &g_Config.bShowIDOnGameIcon, false, true, true), - ConfigSetting("GameGridScale", &g_Config.fGameGridScale, 1.0, true, true), + ConfigSetting("ShowRegionOnGameIcon", &g_Config.bShowRegionOnGameIcon, false), + ConfigSetting("ShowIDOnGameIcon", &g_Config.bShowIDOnGameIcon, false), + ConfigSetting("GameGridScale", &g_Config.fGameGridScale, 1.0), ConfigSetting("GridView1", &g_Config.bGridView1, true), ConfigSetting("GridView2", &g_Config.bGridView2, true), ConfigSetting("GridView3", &g_Config.bGridView3, false), ConfigSetting("ComboMode", &g_Config.iComboMode, 0), - ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0), - ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0), - ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0), - ConfigSetting("RightAnalogRight", &g_Config.iRightAnalogRight, 0), - ConfigSetting("RightAnalogPress", &g_Config.iRightAnalogPress, 0), - ConfigSetting("RightAnalogCustom", &g_Config.bRightAnalogCustom, false), + ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0, true, true), + ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0, true, true), + ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0, true, true), + ConfigSetting("RightAnalogRight", &g_Config.iRightAnalogRight, 0, true, true), + ConfigSetting("RightAnalogPress", &g_Config.iRightAnalogPress, 0, true, true), + ConfigSetting("RightAnalogCustom", &g_Config.bRightAnalogCustom, false, true, true), // "default" means let emulator decide, "" means disable. ConfigSetting("ReportingHost", &g_Config.sReportHost, "default"), @@ -499,6 +511,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("FullscreenOnDoubleclick", &g_Config.bFullscreenOnDoubleclick, true, false, false), ReportedConfigSetting("MemStickInserted", &g_Config.bMemStickInserted, true, true, true), + ConfigSetting("LoadPlugins", &g_Config.bLoadPlugins, false, true, true), ConfigSetting(false), }; @@ -511,8 +524,9 @@ static ConfigSetting cpuSettings[] = { ReportedConfigSetting("CPUCore", &g_Config.iCpuCore, &DefaultCpuCore, true, true), ConfigSetting("VulkanMultithreading", &g_Config.bVulkanMultithreading, false, true, true), ReportedConfigSetting("SeparateSASThread", &g_Config.bSeparateSASThread, &DefaultSasThread, true, true), + ReportedConfigSetting("SeparateIOThread", &g_Config.bSeparateIOThread, true, true, true), ReportedConfigSetting("IOTimingMethod", &g_Config.iIOTimingMethod, IOTIMING_REALISTIC, true, true), - ConfigSetting("FastMemoryAccess", &g_Config.bFastMemory, false, true, true), + ConfigSetting("FastMemoryAccess", &g_Config.bFastMemory, true, true, true), ReportedConfigSetting("FuncReplacements", &g_Config.bFuncReplacements, true, true, true), ConfigSetting("HideSlowWarnings", &g_Config.bHideSlowWarnings, true, true, false), ConfigSetting("HideStateWarnings", &g_Config.bHideStateWarnings, false, true, false), @@ -524,22 +538,22 @@ static ConfigSetting cpuSettings[] = { }; static int DefaultInternalResolution() { - // Auto on Windows, 2x on large screens, 1x elsewhere. -#if defined(USING_WIN_UI) + // Auto on Windows and Linux, 2x on large screens, 1x elsewhere. +#if defined(USING_WIN_UI) || defined(USING_QT_UI) return 0; #else int longestDisplaySide = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)); int scale = longestDisplaySide >= 1000 ? 2 : 1; - ILOG("Longest display side: %d pixels. Choosing scale %d", longestDisplaySide, scale); + INFO_LOG(G3D, "Longest display side: %d pixels. Choosing scale %d", longestDisplaySide, scale); return scale; #endif } -static bool DefaultFrameskipUnthrottle() { -#if !PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(UWP) - return true; +static int DefaultUnthrottleMode() { +#if PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS) + return (int)UnthrottleMode::SKIP_DRAW; #else - return false; + return (int)UnthrottleMode::CONTINUOUS; #endif } @@ -711,6 +725,28 @@ struct ConfigTranslator { typedef ConfigTranslator GPUBackendTranslator; +static int UnthrottleModeFromString(const std::string &s) { + if (!strcasecmp(s.c_str(), "CONTINUOUS")) + return (int)UnthrottleMode::CONTINUOUS; + if (!strcasecmp(s.c_str(), "SKIP_DRAW")) + return (int)UnthrottleMode::SKIP_DRAW; + if (!strcasecmp(s.c_str(), "SKIP_FLIP")) + return (int)UnthrottleMode::SKIP_FLIP; + return DefaultUnthrottleMode(); +} + +std::string UnthrottleModeToString(int v) { + switch (UnthrottleMode(v)) { + case UnthrottleMode::CONTINUOUS: + return "CONTINUOUS"; + case UnthrottleMode::SKIP_DRAW: + return "SKIP_DRAW"; + case UnthrottleMode::SKIP_FLIP: + return "SKIP_FLIP"; + } + return "CONTINUOUS"; +} + static ConfigSetting graphicsSettings[] = { ConfigSetting("EnableCardboardVR", &g_Config.bEnableCardboardVR, false, true, true), ConfigSetting("CardboardScreenSize", &g_Config.iCardboardScreenSize, 50, true, true), @@ -740,7 +776,7 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true), - ConfigSetting("FrameSkipUnthrottle", &g_Config.bFrameSkipUnthrottle, &DefaultFrameskipUnthrottle, true, false), + ConfigSetting("UnthrottleMode", &g_Config.iUnthrottleMode, &DefaultUnthrottleMode, &UnthrottleModeToString, &UnthrottleModeFromString, true, true), #if defined(USING_WIN_UI) ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), #endif @@ -764,7 +800,9 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("SmallDisplayZoomLevel", &g_Config.fSmallDisplayZoomLevel, 1.0f, true, true), ConfigSetting("ImmersiveMode", &g_Config.bImmersiveMode, false, true, true), ConfigSetting("SustainedPerformanceMode", &g_Config.bSustainedPerformanceMode, false, true, true), + ConfigSetting("MipMap", &g_Config.bMipMap, true, true, true), + ConfigSetting("IgnoreScreenInsets", &g_Config.bIgnoreScreenInsets, true, true, false), ReportedConfigSetting("ReplaceTextures", &g_Config.bReplaceTextures, true, true, true), ReportedConfigSetting("SaveNewTextures", &g_Config.bSaveNewTextures, false, true, true), @@ -781,7 +819,8 @@ static ConfigSetting graphicsSettings[] = { // Not really a graphics setting... ReportedConfigSetting("SplineBezierQuality", &g_Config.iSplineBezierQuality, 2, true, true), ReportedConfigSetting("HardwareTessellation", &g_Config.bHardwareTessellation, false, true, true), - ReportedConfigSetting("PostShader", &g_Config.sPostShaderName, "Off", true, true), + ConfigSetting("TextureShader", &g_Config.sTextureShaderName, "Off", true, true), + ConfigSetting("ShaderChainRequires60FPS", &g_Config.bShaderChainRequires60FPS, false, true, true), ReportedConfigSetting("MemBlockTransferGPU", &g_Config.bBlockTransferGPU, true, true, true), ReportedConfigSetting("DisableSlowFramebufEffects", &g_Config.bDisableSlowFramebufEffects, false, true, true), @@ -794,6 +833,8 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("InflightFrames", &g_Config.iInflightFrames, 3, true, false), ConfigSetting("RenderDuplicateFrames", &g_Config.bRenderDuplicateFrames, false, true, true), + ConfigSetting("ClearFramebuffersOnFirstUseHack", &g_Config.bClearFramebuffersOnFirstUseHack, false, true, true), + ConfigSetting(false), }; @@ -943,6 +984,13 @@ static ConfigSetting controlSettings[] = { static ConfigSetting networkSettings[] = { ConfigSetting("EnableWlan", &g_Config.bEnableWlan, false, true, true), ConfigSetting("EnableAdhocServer", &g_Config.bEnableAdhocServer, false, true, true), + ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "localhost", true, true), + ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), + ConfigSetting("MinTimeout", &g_Config.iMinTimeout, 1, true, true), + ConfigSetting("TCPNoDelay", &g_Config.bTCPNoDelay, false, true, true), + ConfigSetting("EnableUPnP", &g_Config.bEnableUPnP, false, true, true), + ConfigSetting("UPnPUseOriginalPort", &g_Config.bUPnPUseOriginalPort, true, true, true), + ConfigSetting("EnableNetworkChat", &g_Config.bEnableNetworkChat, false, true, true), ConfigSetting("ChatButtonPosition",&g_Config.iChatButtonPosition,BOTTOM_LEFT,true,true), ConfigSetting("ChatScreenPosition",&g_Config.iChatScreenPosition,BOTTOM_LEFT,true,true), @@ -952,6 +1000,7 @@ static ConfigSetting networkSettings[] = { ConfigSetting("QuickChat3", &g_Config.sQuickChat2, "Quick Chat 3", true, true), ConfigSetting("QuickChat4", &g_Config.sQuickChat3, "Quick Chat 4", true, true), ConfigSetting("QuickChat5", &g_Config.sQuickChat4, "Quick Chat 5", true, true), + ConfigSetting(false), }; @@ -980,13 +1029,10 @@ static ConfigSetting systemParamSettings[] = { ReportedConfigSetting("PSPModel", &g_Config.iPSPModel, &DefaultPSPModel, true, true), ReportedConfigSetting("PSPFirmwareVersion", &g_Config.iFirmwareVersion, PSP_DEFAULT_FIRMWARE, true, true), ConfigSetting("NickName", &g_Config.sNickName, "PPSSPP", true, true), - ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "localhost", true, true), ConfigSetting("MacAddress", &g_Config.sMACAddress, "", true, true), - ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), - ConfigSetting("MOHH2hack", &g_Config.bMOHH2hack, false, true, true), ReportedConfigSetting("Language", &g_Config.iLanguage, &DefaultSystemParamLanguage, true, true), - ConfigSetting("TimeFormat", &g_Config.iTimeFormat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR, true, true), - ConfigSetting("DateFormat", &g_Config.iDateFormat, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD, true, true), + ConfigSetting("ParamTimeFormat", &g_Config.iTimeFormat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR, true, true), + ConfigSetting("ParamDateFormat", &g_Config.iDateFormat, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD, true, true), ConfigSetting("TimeZone", &g_Config.iTimeZone, 0, true, true), ConfigSetting("DayLightSavings", &g_Config.bDayLightSavings, (bool) PSP_SYSTEMPARAM_DAYLIGHTSAVINGS_STD, true, true), ReportedConfigSetting("ButtonPreference", &g_Config.iButtonPreference, PSP_SYSTEMPARAM_BUTTON_CROSS, true, true), @@ -1092,17 +1138,23 @@ static ConfigSectionSettings sections[] = { {"Theme", themeSettings}, }; -static void IterateSettings(IniFile &iniFile, std::function func) { +static void IterateSettings(IniFile &iniFile, std::function func) { for (size_t i = 0; i < ARRAY_SIZE(sections); ++i) { - IniFile::Section *section = iniFile.GetOrCreateSection(sections[i].section); + Section *section = iniFile.GetOrCreateSection(sections[i].section); for (auto setting = sections[i].settings; setting->HasMore(); ++setting) { func(section, setting); } } } -Config::Config() : bGameSpecific(false) { } -Config::~Config() { } +Config::Config() { +} + +Config::~Config() { + if (bUpdatedInstanceCounter) { + ShutdownInstanceCounter(); + } +} std::map> GetLangValuesMapping() { std::map> langValuesMapping; @@ -1126,8 +1178,8 @@ std::map> GetLangValuesMapping() { langCodeMapping["CHINESE_TRADITIONAL"] = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL; langCodeMapping["CHINESE_SIMPLIFIED"] = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED; - IniFile::Section *langRegionNames = mapping.GetOrCreateSection("LangRegionNames"); - IniFile::Section *systemLanguage = mapping.GetOrCreateSection("SystemLanguage"); + Section *langRegionNames = mapping.GetOrCreateSection("LangRegionNames"); + Section *systemLanguage = mapping.GetOrCreateSection("SystemLanguage"); for (size_t i = 0; i < keys.size(); i++) { std::string langName; @@ -1152,6 +1204,11 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { const bool useIniFilename = iniFileName != nullptr && strlen(iniFileName) > 0; iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : "ppsspp.ini"); + if (!bUpdatedInstanceCounter) { + InitInstanceCounter(); + bUpdatedInstanceCounter = true; + } + const bool useControllerIniFilename = controllerIniFilename != nullptr && strlen(controllerIniFilename) > 0; controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : "controls.ini"); @@ -1164,7 +1221,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { // Continue anyway to initialize the config. } - IterateSettings(iniFile, [](IniFile::Section *section, ConfigSetting *setting) { + IterateSettings(iniFile, [](Section *section, ConfigSetting *setting) { setting->Get(section); }); @@ -1172,7 +1229,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (!File::Exists(currentDirectory)) currentDirectory = ""; - IniFile::Section *log = iniFile.GetOrCreateSection(logSectionName); + Section *log = iniFile.GetOrCreateSection(logSectionName); bool debugDefaults = false; #ifdef _DEBUG @@ -1180,7 +1237,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { #endif LogManager::GetInstance()->LoadConfig(log, debugDefaults); - IniFile::Section *recent = iniFile.GetOrCreateSection("Recent"); + Section *recent = iniFile.GetOrCreateSection("Recent"); recent->Get("MaxRecent", &iMaxRecent, 1000); // Fix issue from switching from uint (hex in .ini) to int (dec) @@ -1217,6 +1274,14 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { mPostShaderSetting[it.first] = std::stof(it.second); } + auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + vPostShaderNames.clear(); + for (auto it : postShaderChain) { + vPostShaderNames.push_back(it.second); + } + if (vPostShaderNames.empty()) + vPostShaderNames.push_back("Off"); + // This caps the exponent 4 (so 16x.) if (iAnisotropyLevel > 4) { iAnisotropyLevel = 4; @@ -1226,7 +1291,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } // Check for an old dpad setting - IniFile::Section *control = iniFile.GetOrCreateSection("Control"); + Section *control = iniFile.GetOrCreateSection("Control"); float f; control->Get("DPadRadius", &f, 0.0f); if (f > 0.0f) { @@ -1282,9 +1347,23 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { jitForcedOff = true; g_Config.iCpuCore = (int)CPUCore::INTERPRETER; } + + // Automatically silence secondary instances. Could be an option I guess, but meh. + if (PPSSPP_ID > 1) { + g_Config.iGlobalVolume = 0; + } + + INFO_LOG(LOADER, "Config loaded: '%s'", iniFilename_.c_str()); } void Config::Save(const char *saveReason) { + if (!IsFirstInstance()) { + // TODO: Should we allow saving config if started from a different directory? + // How do we tell? + WARN_LOG(LOADER, "Not saving config - secondary instances don't."); + return; + } + if (jitForcedOff) { // if JIT has been forced off, we don't want to screw up the user's ppsspp.ini g_Config.iCpuCore = (int)CPUCore::JIT; @@ -1301,13 +1380,13 @@ void Config::Save(const char *saveReason) { // Need to do this somewhere... bFirstRun = false; - IterateSettings(iniFile, [&](IniFile::Section *section, ConfigSetting *setting) { + IterateSettings(iniFile, [&](Section *section, ConfigSetting *setting) { if (!bGameSpecific || !setting->perGame_) { setting->Set(section); } }); - IniFile::Section *recent = iniFile.GetOrCreateSection("Recent"); + Section *recent = iniFile.GetOrCreateSection("Recent"); recent->Set("MaxRecent", iMaxRecent); for (int i = 0; i < iMaxRecent; i++) { @@ -1320,7 +1399,7 @@ void Config::Save(const char *saveReason) { } } - IniFile::Section *pinnedPaths = iniFile.GetOrCreateSection("PinnedPaths"); + Section *pinnedPaths = iniFile.GetOrCreateSection("PinnedPaths"); pinnedPaths->Clear(); for (size_t i = 0; i < vPinnedPaths.size(); ++i) { char keyName[64]; @@ -1329,17 +1408,24 @@ void Config::Save(const char *saveReason) { } if (!bGameSpecific) { - IniFile::Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); + Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); postShaderSetting->Clear(); for (auto it = mPostShaderSetting.begin(), end = mPostShaderSetting.end(); it != end; ++it) { postShaderSetting->Set(it->first.c_str(), it->second); } + Section *postShaderChain = iniFile.GetOrCreateSection("PostShaderList"); + postShaderChain->Clear(); + for (size_t i = 0; i < vPostShaderNames.size(); ++i) { + char keyName[64]; + snprintf(keyName, sizeof(keyName), "PostShader%d", (int)i+1); + postShaderChain->Set(keyName, vPostShaderNames[i]); + } } - IniFile::Section *control = iniFile.GetOrCreateSection("Control"); + Section *control = iniFile.GetOrCreateSection("Control"); control->Delete("DPadRadius"); - IniFile::Section *log = iniFile.GetOrCreateSection(logSectionName); + Section *log = iniFile.GetOrCreateSection(logSectionName); if (LogManager::GetInstance()) LogManager::GetInstance()->SaveConfig(log); @@ -1576,21 +1662,29 @@ bool Config::saveGameConfig(const std::string &pGameId, const std::string &title IniFile iniFile; - IniFile::Section *top = iniFile.GetOrCreateSection(""); + Section *top = iniFile.GetOrCreateSection(""); top->AddComment(StringFromFormat("Game config for %s - %s", pGameId.c_str(), title.c_str())); - IterateSettings(iniFile, [](IniFile::Section *section, ConfigSetting *setting) { + IterateSettings(iniFile, [](Section *section, ConfigSetting *setting) { if (setting->perGame_) { setting->Set(section); } }); - IniFile::Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); + Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); postShaderSetting->Clear(); for (auto it = mPostShaderSetting.begin(), end = mPostShaderSetting.end(); it != end; ++it) { postShaderSetting->Set(it->first.c_str(), it->second); } + Section *postShaderChain = iniFile.GetOrCreateSection("PostShaderList"); + postShaderChain->Clear(); + for (size_t i = 0; i < vPostShaderNames.size(); ++i) { + char keyName[64]; + snprintf(keyName, sizeof(keyName), "PostShader%d", (int)i+1); + postShaderChain->Set(keyName, vPostShaderNames[i]); + } + KeyMap::SaveToIni(iniFile); iniFile.Save(fullIniFilePath); @@ -1615,7 +1709,15 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title mPostShaderSetting[it.first] = std::stof(it.second); } - IterateSettings(iniFile, [](IniFile::Section *section, ConfigSetting *setting) { + auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + vPostShaderNames.clear(); + for (auto it : postShaderChain) { + vPostShaderNames.push_back(it.second); + } + if (vPostShaderNames.empty()) + vPostShaderNames.push_back("Off"); + + IterateSettings(iniFile, [](Section *section, ConfigSetting *setting) { if (setting->perGame_) { setting->Get(section); } @@ -1633,7 +1735,7 @@ void Config::unloadGameConfig() { iniFile.Load(iniFilename_); // Reload game specific settings back to standard. - IterateSettings(iniFile, [](IniFile::Section *section, ConfigSetting *setting) { + IterateSettings(iniFile, [](Section *section, ConfigSetting *setting) { if (setting->perGame_) { setting->Get(section); } @@ -1645,6 +1747,14 @@ void Config::unloadGameConfig() { mPostShaderSetting[it.first] = std::stof(it.second); } + auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + vPostShaderNames.clear(); + for (auto it : postShaderChain) { + vPostShaderNames.push_back(it.second); + } + if (vPostShaderNames.empty()) + vPostShaderNames.push_back("Off"); + LoadStandardControllerIni(); } } diff --git a/Core/Config.h b/Core/Config.h index c92119b1b3..cee5c7ed75 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -62,7 +62,8 @@ public: // Whether to save the config on close. bool bSaveSettings; bool bFirstRun; - bool bGameSpecific; + bool bGameSpecific = false; + bool bUpdatedInstanceCounter = false; int iRunCount; // To be used to for example check for updates every 10 runs and things like that. @@ -100,6 +101,7 @@ public: // Core bool bIgnoreBadMemAccess; + bool bFastMemory; int iCpuCore; bool bSimpleUI; @@ -114,6 +116,7 @@ public: bool bVulkanMultithreading; bool bSeparateSASThread; + bool bSeparateIOThread; int iIOTimingMethod; int iIOManualDelay; int iLockedCPUSpeed; @@ -127,6 +130,7 @@ public: std::string sRemoteISOSubdir; bool bRemoteDebuggerOnStartup; bool bMemStickInserted; + bool bLoadPlugins; int iScreenRotation; // The rotation angle of the PPSSPP UI. Only supported on Android and possibly other mobile platforms. int iInternalScreenRotation; // The internal screen rotation angle. Useful for vertical SHMUPs and similar. @@ -147,6 +151,7 @@ public: std::string sVulkanDevice; std::string sD3D11Device; // Windows only std::string sCameraDevice; + std::string sMicDevice; bool bSoftwareRendering; bool bHardwareTransform; // only used in the GLES backend @@ -162,11 +167,13 @@ public: float fSmallDisplayZoomLevel; //This is used for zoom values, both in and out. bool bImmersiveMode; // Mode on Android Kitkat 4.4 that hides the back button etc. bool bSustainedPerformanceMode; // Android: Slows clocks down to avoid overheating/speed fluctuations. + bool bIgnoreScreenInsets; // Android: Center screen disregarding insets if this is enabled. bool bVSync; int iFrameSkip; int iFrameSkipType; + int iUnthrottleMode; // See UnthrottleMode in ConfigValues.h. bool bAutoFrameSkip; - bool bFrameSkipUnthrottle; + bool bClearFramebuffersOnFirstUseHack; bool bEnableCardboardVR; // Cardboard Master Switch int iCardboardScreenSize; // Screen Size (in %) @@ -201,6 +208,7 @@ public: int iMaxRecent; int iCurrentStateSlot; int iRewindFlipFrequency; + bool bUISound; bool bEnableStateUndo; int iAutoLoadSaveState; // 0 = off, 1 = oldest, 2 = newest, >2 = slot number + 3 bool bEnableCheats; @@ -213,8 +221,11 @@ public: bool bFragmentTestCache; int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High bool bHardwareTessellation; - std::string sPostShaderName; // Off for off. + + std::vector vPostShaderNames; // Off for chain end (only Off for no shader) std::map mPostShaderSetting; + bool bShaderChainRequires60FPS; + std::string sTextureShaderName; bool bGfxDebugOutput; bool bGfxDebugSplitSubmit; int iInflightFrames; @@ -404,10 +415,7 @@ public: // SystemParam std::string sNickName; - std::string proAdhocServer; std::string sMACAddress; - bool bMOHH2hack; - int iPortOffset; int iLanguage; int iTimeFormat; int iDateFormat; @@ -419,8 +427,14 @@ public: bool bSavedataUpgrade; // Networking + std::string proAdhocServer; bool bEnableWlan; bool bEnableAdhocServer; + bool bTCPNoDelay; + bool bEnableUPnP; + bool bUPnPUseOriginalPort; + int iPortOffset; + int iMinTimeout; int iWlanAdhocChannel; bool bWlanPowerSave; bool bEnableNetworkChat; diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 89c8598112..8936f63809 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -110,3 +110,9 @@ enum class AutoLoadSaveState { OLDEST = 1, NEWEST = 2, }; + +enum class UnthrottleMode { + CONTINUOUS = 0, + SKIP_DRAW = 1, + SKIP_FLIP = 2, +}; diff --git a/Core/Core.cpp b/Core/Core.cpp index 3f66794576..f3cdd9b624 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -22,13 +22,15 @@ #include #include -#include "base/NativeApp.h" -#include "base/display.h" -#include "base/timeutil.h" -#include "thread/threadutil.h" -#include "profiler/profiler.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/System/Display.h" +#include "Common/TimeUtil.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Profiler/Profiler.h" #include "Common/GraphicsContext.h" +#include "Common/Log.h" #include "Core/Core.h" #include "Core/Config.h" #include "Core/Host.h" @@ -44,7 +46,6 @@ #include "Windows/InputDevice.h" #endif - // Time until we stop considering the core active without user input. // Should this be configurable? 2 hours currently. static const double ACTIVITY_IDLE_TIMEOUT = 2.0 * 3600.0; @@ -63,6 +64,8 @@ static double lastKeepAwake = 0.0; static GraphicsContext *graphicsContext; static bool powerSaving = false; +static ExceptionInfo g_exceptionInfo; + void Core_SetGraphicsContext(GraphicsContext *ctx) { graphicsContext = ctx; PSP_CoreParameter().graphicsContext = graphicsContext; @@ -92,6 +95,7 @@ void Core_ListenStopRequest(CoreStopRequestFunc func) { } void Core_Stop() { + g_exceptionInfo.type = ExceptionType::NONE; Core_UpdateState(CORE_POWERDOWN); for (auto func : stopFuncs) { func(); @@ -187,7 +191,7 @@ bool UpdateScreenScale(int width, int height) { dp_yres = new_dp_yres; pixel_xres = width; pixel_yres = height; - DEBUG_LOG(SYSTEM, "pixel_res: %dx%d. Calling NativeResized()", pixel_xres, pixel_yres); + INFO_LOG(G3D, "pixel_res: %dx%d. Calling NativeResized()", pixel_xres, pixel_yres); NativeResized(); return true; } @@ -215,12 +219,10 @@ void Core_RunLoop(GraphicsContext *ctx) { while ((GetUIState() != UISTATE_INGAME || !PSP_IsInited()) && GetUIState() != UISTATE_EXIT) { // In case it was pending, we're not in game anymore. We won't get to Core_Run(). Core_StateProcessed(); - time_update(); double startTime = time_now_d(); UpdateRunLoop(); // Simple throttling to not burn the GPU in the menu. - time_update(); double diffTime = time_now_d() - startTime; int sleepTime = (int)(1000.0 / 60.0) - (int)(diffTime * 1000.0); if (sleepTime > 0) @@ -231,7 +233,6 @@ void Core_RunLoop(GraphicsContext *ctx) { } while ((coreState == CORE_RUNNING || coreState == CORE_STEPPING) && GetUIState() == UISTATE_INGAME) { - time_update(); UpdateRunLoop(); if (!windowHidden && !Core_IsStepping()) { ctx->SwapBuffers(); @@ -262,6 +263,7 @@ void Core_UpdateSingleStep() { } void Core_SingleStep() { + g_exceptionInfo.type = ExceptionType::NONE; currentMIPS->SingleStep(); if (coreState == CORE_STEPPING) steppingCounter++; @@ -339,7 +341,8 @@ void Core_Run(GraphicsContext *ctx) { case CORE_POWERUP: case CORE_POWERDOWN: - case CORE_ERROR: + case CORE_BOOT_ERROR: + case CORE_RUNTIME_ERROR: // Exit loop!! Core_StateProcessed(); @@ -358,12 +361,132 @@ void Core_EnableStepping(bool step) { steppingCounter++; } else { host->SetDebugMode(false); + // Clear the exception if we resume. + g_exceptionInfo.type = ExceptionType::NONE; coreState = CORE_RUNNING; coreStatePending = false; m_StepCond.notify_all(); } } +bool Core_NextFrame() { + if (coreState == CORE_RUNNING) { + coreState = CORE_NEXTFRAME; + return true; + } else { + return false; + } +} + int Core_GetSteppingCounter() { return steppingCounter; } + +const char *ExceptionTypeAsString(ExceptionType type) { + switch (type) { + case ExceptionType::MEMORY: return "Invalid Memory Access"; + case ExceptionType::BREAK: return "Break"; + case ExceptionType::BAD_EXEC_ADDR: return "Bad Execution Address"; + default: return "N/A"; + } +} + +const char *MemoryExceptionTypeAsString(MemoryExceptionType type) { + switch (type) { + case MemoryExceptionType::UNKNOWN: return "Unknown"; + case MemoryExceptionType::READ_WORD: return "Read Word"; + case MemoryExceptionType::WRITE_WORD: return "Write Word"; + case MemoryExceptionType::READ_BLOCK: return "Read Block"; + case MemoryExceptionType::WRITE_BLOCK: return "Read/Write Block"; + default: + return "N/A"; + } +} + +const char *ExecExceptionTypeAsString(ExecExceptionType type) { + switch (type) { + case ExecExceptionType::JUMP: return "CPU Jump"; + case ExecExceptionType::THREAD: return "Thread switch"; + default: + return "N/A"; + } +} + +void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) { + const char *desc = MemoryExceptionTypeAsString(type); + // In jit, we only flush PC when bIgnoreBadMemAccess is off. + if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) { + WARN_LOG(MEMMAP, "%s: Invalid address %08x", desc, address); + } else { + WARN_LOG(MEMMAP, "%s: Invalid address %08x PC %08x LR %08x", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + } + + if (!g_Config.bIgnoreBadMemAccess) { + ExceptionInfo &e = g_exceptionInfo; + e = {}; + e.type = ExceptionType::MEMORY; + e.info = ""; + e.memory_type = type; + e.address = address; + e.pc = pc; + Core_EnableStepping(true); + host->SetDebugMode(true); + } +} + +void Core_MemoryExceptionInfo(u32 address, u32 pc, MemoryExceptionType type, std::string additionalInfo) { + const char *desc = MemoryExceptionTypeAsString(type); + // In jit, we only flush PC when bIgnoreBadMemAccess is off. + if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) { + WARN_LOG(MEMMAP, "%s: Invalid address %08x. %s", desc, address, additionalInfo.c_str()); + } else { + WARN_LOG(MEMMAP, "%s: Invalid address %08x PC %08x LR %08x %s", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA], additionalInfo.c_str()); + } + + if (!g_Config.bIgnoreBadMemAccess) { + ExceptionInfo &e = g_exceptionInfo; + e = {}; + e.type = ExceptionType::MEMORY; + e.info = additionalInfo; + e.memory_type = type; + e.address = address; + e.pc = pc; + Core_EnableStepping(true); + host->SetDebugMode(true); + } +} + +void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) { + const char *desc = ExecExceptionTypeAsString(type); + WARN_LOG(MEMMAP, "%s: Invalid destination %08x PC %08x LR %08x", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + + if (!g_Config.bIgnoreBadMemAccess) { + ExceptionInfo &e = g_exceptionInfo; + e = {}; + e.type = ExceptionType::BAD_EXEC_ADDR; + e.info = ""; + e.exec_type = type; + e.address = address; + e.pc = pc; + Core_EnableStepping(true); + host->SetDebugMode(true); + } +} + +void Core_Break() { + ERROR_LOG(CPU, "BREAK!"); + + ExceptionInfo &e = g_exceptionInfo; + e = {}; + e.type = ExceptionType::BREAK; + e.info = ""; + + if (!g_Config.bIgnoreBadMemAccess) { + Core_EnableStepping(true); + host->SetDebugMode(true); + } +} + +const ExceptionInfo &Core_GetExceptionInfo() { + return g_exceptionInfo; +} diff --git a/Core/Core.h b/Core/Core.h index 69749f0d70..21facdb735 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -17,6 +17,8 @@ #pragma once +#include + #include "Core/System.h" #include "Core/CoreParameter.h" @@ -32,6 +34,8 @@ void Core_SetGraphicsContext(GraphicsContext *ctx); // called from gui void Core_EnableStepping(bool step); + +bool Core_NextFrame(); void Core_DoSingleStep(); void Core_UpdateSingleStep(); void Core_ProcessStepping(); @@ -76,3 +80,50 @@ void Core_NotifyActivity(); void Core_SetPowerSaving(bool mode); bool Core_GetPowerSaving(); + +enum class MemoryExceptionType { + NONE, + UNKNOWN, + READ_WORD, + WRITE_WORD, + READ_BLOCK, + WRITE_BLOCK, +}; +enum class ExecExceptionType { + JUMP, + THREAD, +}; + +// Separate one for without info, to avoid having to allocate a string +void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type); + +void Core_MemoryExceptionInfo(u32 address, u32 pc, MemoryExceptionType type, std::string additionalInfo); + +void Core_ExecException(u32 address, u32 pc, ExecExceptionType type); +void Core_Break(); + +enum class ExceptionType { + NONE, + MEMORY, + BREAK, + BAD_EXEC_ADDR, +}; + +struct ExceptionInfo { + ExceptionType type; + std::string info; + + // Memory exception info + MemoryExceptionType memory_type; + uint32_t pc; + uint32_t address; + + // Reuses pc and address from memory type, where address is the failed destination. + ExecExceptionType exec_type; +}; + +const ExceptionInfo &Core_GetExceptionInfo(); + +const char *ExceptionTypeAsString(ExceptionType type); +const char *MemoryExceptionTypeAsString(MemoryExceptionType type); +const char *ExecExceptionTypeAsString(ExecExceptionType type); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 5b675bd729..e91c514383 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -129,12 +129,17 @@ - + + + + + ResolveProjectReferences + Level3 - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext + _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) StreamingSIMDExtensions2 Precise true @@ -147,16 +152,17 @@ true - + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) Updating git-version.cpp - + Level3 - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext + _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) NotSet Precise false @@ -170,15 +176,16 @@ true - + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) Updating git-version.cpp - + Level3 - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\aarch64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\aarch64\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) NotSet Precise @@ -193,15 +200,16 @@ true - + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) Updating git-version.cpp - + Level3 - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\arm\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\arm\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_32=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) NotSet Precise @@ -217,10 +225,11 @@ true - + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) Updating git-version.cpp - + @@ -228,11 +237,11 @@ MaxSpeed true true - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext false StreamingSIMDExtensions2 Precise - USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_32=1;_M_IX86=1;_LIB;NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_32=1;_M_IX86=1;_LIB;NDEBUG;_UNICODE;UNICODE;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) Speed MultiThreaded true @@ -244,14 +253,14 @@ true true - - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - %(AdditionalDependencies) + + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) + Updating git-version.cpp + @@ -259,7 +268,7 @@ MaxSpeed true true - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext NotSet Precise false @@ -267,7 +276,7 @@ Speed false true - USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_64=1;_M_X64=1;_LIB;NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_64=1;_M_X64=1;_LIB;NDEBUG;_UNICODE;UNICODE;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) false MultiThreaded true @@ -278,10 +287,11 @@ true true - + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) Updating git-version.cpp - + @@ -289,7 +299,7 @@ MaxSpeed true true - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\aarch64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\aarch64\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext NotSet Precise false @@ -308,10 +318,11 @@ true true - + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) Updating git-version.cpp - + @@ -319,7 +330,7 @@ MaxSpeed true true - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\arm\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/native/ext/libpng17;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\arm\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext NotSet Precise false @@ -338,15 +349,77 @@ true true - + ../Windows/git-version-gen.cmd + ../git-version.cpp;%(Outputs) Updating git-version.cpp - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -366,16 +439,22 @@ + + + + + + @@ -819,6 +898,7 @@ + true @@ -833,6 +913,7 @@ + MaxSpeed @@ -865,11 +946,20 @@ + + + + + + + + + @@ -894,17 +984,22 @@ + + + + + @@ -1151,6 +1246,7 @@ + true @@ -1165,6 +1261,7 @@ + @@ -1172,6 +1269,10 @@ + + + + @@ -1182,16 +1283,20 @@ {129e5e2b-39c1-4d84-96fe-dfd22dbb4a25} + + {d8a71225-178b-424e-96c1-cc3be2c1b047} + {457f45d2-556f-47bc-a31d-aff0d15beaed} - - {C4DF647E-80EA-4111-A0A8-218B1B711E18} - {f761046e-6c38-4428-a5f1-38391a37bb34} + + + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index c95b6aa41f..76fac1fe88 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -73,6 +73,21 @@ {c21d9bb5-614d-451b-8c0b-3078b29122d8} + + {db010645-6b26-41a7-8d44-c53cb0533d7d} + + + {cf1a59fe-8509-48f0-84d0-27c71cb10dc3} + + + {d8c48d88-2e34-4a98-aa88-4277a3b8afea} + + + {6c6e0188-fabf-4203-aaa2-896c42be2c20} + + + {0201ff27-4fa8-4cf3-bbb9-accfdc0c7046} + @@ -713,6 +728,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket @@ -743,6 +761,210 @@ HLE\Kernel + + Core + + + Util + + + Core + + + HW + + + HLE + + + Ext\Snappy + + + Ext\Snappy + + + Ext\gason + + + Ext\city + + + Ext\sha1 + + + Ext\jpge + + + Ext\jpge + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Core + + + Core + @@ -1343,6 +1565,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket @@ -1379,10 +1604,75 @@ HLE\Kernel + + Core + + + Util + + + Core + + + HLE + + + Ext\gason + + + Ext\city + + + Ext\city + + + Ext\sha1 + + + Ext\jpge + + + Ext\jpge + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Core + + + Core + + + Ext\gason + + + Ext\city + + + Ext\city + + + Ext\libzip + - + + + Ext\sha1 + + + Ext\libzip + + + \ No newline at end of file diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 2f0016d511..ca30771568 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -20,10 +20,10 @@ #include #include -#include "base/logging.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" -#include "Common/MsgHandler.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeList.h" #include "Core/CoreTiming.h" #include "Core/Core.h" #include "Core/Config.h" @@ -31,7 +31,6 @@ #include "Core/HLE/sceDisplay.h" #include "Core/MIPS/MIPS.h" #include "Core/Reporting.h" -#include "Common/ChunkFile.h" static const int initialHz = 222000000; int CPU_HZ = 222000000; @@ -43,25 +42,17 @@ int CPU_HZ = 222000000; namespace CoreTiming { -struct EventType -{ - EventType() {} - - EventType(TimedCallback cb, const char *n) - : callback(cb), name(n) {} - +struct EventType { TimedCallback callback; const char *name; }; std::vector event_types; -struct BaseEvent -{ +struct BaseEvent { s64 time; u64 userdata; int type; -// Event *next; }; typedef LinkedListItem Event; @@ -97,6 +88,11 @@ void FireMhzChange() { } void SetClockFrequencyHz(int cpuHz) { + if (cpuHz <= 0) { + // Paranoid check, protecting against division by zero and similar nonsense. + return; + } + // When the mhz changes, we keep track of what "time" it was before hand. // This way, time always moves forward, even if mhz is changed. lastGlobalTimeUs = GetGlobalTimeUs(); @@ -166,7 +162,7 @@ void FreeTsEvent(Event* ev) int RegisterEvent(const char *name, TimedCallback callback) { - event_types.push_back(EventType(callback, name)); + event_types.push_back(EventType{ callback, name }); return (int)event_types.size() - 1; } @@ -178,17 +174,16 @@ void AntiCrashCallback(u64 userdata, int cyclesLate) void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback) { - _assert_msg_(CORETIMING, event_type >= 0, "Invalid event type %d", event_type) + _assert_msg_(event_type >= 0, "Invalid event type %d", event_type) if (event_type >= (int) event_types.size()) - event_types.resize(event_type + 1, EventType(AntiCrashCallback, "INVALID EVENT")); + event_types.resize(event_type + 1, EventType{ AntiCrashCallback, "INVALID EVENT" }); - event_types[event_type] = EventType(callback, name); + event_types[event_type] = EventType{ callback, name }; } void UnregisterAllEvents() { - if (first) - PanicAlert("Cannot unregister events with events pending"); + _dbg_assert_msg_(first == nullptr, "Unregistering events with events pending - this isn't good."); event_types.clear(); } @@ -567,7 +562,7 @@ void ForceCheck() slicelength = -1; #ifdef _DEBUG - _dbg_assert_msg_(CPU, cyclesExecuted >= 0, "Shouldn't have a negative cyclesExecuted"); + _dbg_assert_msg_( cyclesExecuted >= 0, "Shouldn't have a negative cyclesExecuted"); #endif } @@ -642,17 +637,18 @@ void Idle(int maxIdle) currentMIPS->downcount = -1; } -std::string GetScheduledEventsSummary() -{ +std::string GetScheduledEventsSummary() { Event *ptr = first; std::string text = "Scheduled events\n"; text.reserve(1000); - while (ptr) - { + while (ptr) { unsigned int t = ptr->type; - if (t >= event_types.size()) - PanicAlert("Invalid event type"); // %i", t); - const char *name = event_types[ptr->type].name; + if (t >= event_types.size()) { + _dbg_assert_msg_(false, "Invalid event type %d", t); + ptr = ptr->next; + continue; + } + const char *name = event_types[t].name; if (!name) name = "[unknown]"; char temp[512]; @@ -666,14 +662,14 @@ std::string GetScheduledEventsSummary() void Event_DoState(PointerWrap &p, BaseEvent *ev) { // There may be padding, so do each one individually. - p.Do(ev->time); - p.Do(ev->userdata); - p.Do(ev->type); + Do(p, ev->time); + Do(p, ev->userdata); + Do(p, ev->type); } void Event_DoStateOld(PointerWrap &p, BaseEvent *ev) { - p.Do(*ev); + Do(p, *ev); } void DoState(PointerWrap &p) @@ -685,26 +681,26 @@ void DoState(PointerWrap &p) return; int n = (int) event_types.size(); - p.Do(n); + Do(p, n); // These (should) be filled in later by the modules. - event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT")); + event_types.resize(n, EventType{ AntiCrashCallback, "INVALID EVENT" }); if (s >= 3) { - p.DoLinkedList(first, (Event **) NULL); - p.DoLinkedList(tsFirst, &tsLast); + DoLinkedList(p, first, (Event **) NULL); + DoLinkedList(p, tsFirst, &tsLast); } else { - p.DoLinkedList(first, (Event **) NULL); - p.DoLinkedList(tsFirst, &tsLast); + DoLinkedList(p, first, (Event **) NULL); + DoLinkedList(p, tsFirst, &tsLast); } - p.Do(CPU_HZ); - p.Do(slicelength); - p.Do(globalTimer); - p.Do(idledCycles); + Do(p, CPU_HZ); + Do(p, slicelength); + Do(p, globalTimer); + Do(p, idledCycles); if (s >= 2) { - p.Do(lastGlobalTimeTicks); - p.Do(lastGlobalTimeUs); + Do(p, lastGlobalTimeTicks); + Do(p, lastGlobalTimeUs); } else { lastGlobalTimeTicks = 0; lastGlobalTimeUs = 0; diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index bf66680122..be1edd7a23 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -1,11 +1,11 @@ #include -#include #include #include -#include "i18n/i18n.h" +#include "Common/Data/Text/I18n.h" #include "Common/StringUtils.h" -#include "Common/ChunkFile.h" -#include "Common/FileUtil.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/File/FileUtil.h" #include "Core/CoreTiming.h" #include "Core/CoreParameter.h" #include "Core/CwCheat.h" @@ -16,9 +16,10 @@ #include "Core/System.h" #include "Core/HLE/sceCtrl.h" #include "Core/MIPS/JitCommon/JitCommon.h" +#include "GPU/Common/PostShader.h" #ifdef _WIN32 -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #endif static int CheatEvent = -1; @@ -303,7 +304,7 @@ void __CheatDoState(PointerWrap &p) { return; } - p.Do(CheatEvent); + Do(p, CheatEvent); CoreTiming::RestoreRegisterEvent(CheatEvent, "CheatEvent", &hleCheat); if (s < 2) { @@ -421,6 +422,8 @@ enum class CheatOp { CopyBytesFrom, Vibration, VibrationFromMemory, + PostShader, + PostShaderFromMemory, Delay, Assert, @@ -475,6 +478,15 @@ struct CheatOperation { uint8_t vibrLTime; uint8_t vibrRTime; } vibrationValues; + struct { + union { + float f; + uint32_t u; + } value; + uint8_t shader; + uint8_t uniform; + uint8_t format; + } PostShaderUniform; }; }; @@ -620,6 +632,23 @@ CheatOperation CWCheatEngine::InterpretNextCwCheat(const CheatCode &cheat, size_ case 0x1: // 0x1 reads value for gamepad vibration from memory addr = line1.part2; return { CheatOp::VibrationFromMemory, addr }; + case 0x2: // 0x2 sets postprocessing shader uniform + { + CheatOperation op = { CheatOp::PostShader }; + op.PostShaderUniform.uniform = line1.part1 & 0x000000FF; + op.PostShaderUniform.shader = (line1.part1 >> 16) & 0x000000FF; + op.PostShaderUniform.value.u = line1.part2; + return op; + } + case 0x3: // 0x3 sets postprocessing shader uniform from memory + { + addr = line1.part2; + CheatOperation op = { CheatOp::PostShaderFromMemory, addr }; + op.PostShaderUniform.uniform = line1.part1 & 0x000000FF; + op.PostShaderUniform.format = (line1.part1 >> 8) & 0x000000FF; + op.PostShaderUniform.shader = (line1.part1 >> 16) & 0x000000FF; + return op; + } // Place for other PPSSPP specific cheats default: return { CheatOp::Invalid }; @@ -747,7 +776,7 @@ CheatOperation CWCheatEngine::InterpretNextCwCheat(const CheatCode &cheat, size_ CheatOperation CWCheatEngine::InterpretNextTempAR(const CheatCode &cheat, size_t &i) { // TODO - assert(false); + _assert_(false); return { CheatOp::Invalid }; } @@ -757,7 +786,7 @@ CheatOperation CWCheatEngine::InterpretNextOp(const CheatCode &cheat, size_t &i) else if (cheat.fmt == CheatCodeFormat::TEMPAR) return InterpretNextTempAR(cheat, i); else - assert(false); + _assert_(false); return { CheatOp::Invalid }; } @@ -919,6 +948,47 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, } break; + case CheatOp::PostShader: + { + auto shaderChain = GetFullPostShadersChain(g_Config.vPostShaderNames); + if (op.PostShaderUniform.shader < shaderChain.size()) { + std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section; + if (shaderName != "Off") + g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = op.PostShaderUniform.value.f; + } + } + break; + + case CheatOp::PostShaderFromMemory: + { + auto shaderChain = GetFullPostShadersChain(g_Config.vPostShaderNames); + if (Memory::IsValidAddress(op.addr) && op.PostShaderUniform.shader < shaderChain.size()) { + union { + float f; + uint32_t u; + } value; + value.u = Memory::Read_U32(op.addr); + std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section; + if (shaderName != "Off") { + switch (op.PostShaderUniform.format) { + case 0: + g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x000000FF; + break; + case 1: + g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x0000FFFF; + break; + case 2: + g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u; + break; + case 3: + g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.f; + break; + } + } + } + } + break; + case CheatOp::Delay: // TODO: Not supported. break; @@ -1107,7 +1177,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, break; default: - assert(false); + _assert_(false); } } diff --git a/Core/CwCheat.h b/Core/CwCheat.h index 578ffe7b98..686694e769 100644 --- a/Core/CwCheat.h +++ b/Core/CwCheat.h @@ -8,7 +8,6 @@ #include #include -#include "base/basictypes.h" #include "Core/MemMap.h" class PointerWrap; diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 96f52ae0ba..c988712be3 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -24,6 +24,7 @@ #include "Core/Debugger/Breakpoints.h" #include "Core/Debugger/SymbolMap.h" #include "Core/Host.h" +#include "Core/MemMap.h" #include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSDebugInterface.h" #include "Core/MIPS/JitCommon/JitCommon.h" @@ -65,7 +66,7 @@ BreakAction MemCheck::Action(u32 addr, bool write, int size, u32 pc) { int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ; if (cond & mask) { Log(addr, write, size, pc); - if (result & BREAK_ACTION_PAUSE) { + if ((result & BREAK_ACTION_PAUSE) && coreState != CORE_POWERUP) { Core_EnableStepping(true); host->SetDebugMode(true); } @@ -364,7 +365,7 @@ BreakAction CBreakPoints::ExecBreakPoint(u32 addr) { NOTICE_LOG(JIT, "BKP PC=%08x: %s", addr, formatted.c_str()); } } - if (info.result & BREAK_ACTION_PAUSE) { + if ((info.result & BREAK_ACTION_PAUSE) && coreState != CORE_POWERUP) { Core_EnableStepping(true); host->SetDebugMode(true); } @@ -689,17 +690,55 @@ bool CBreakPoints::EvaluateLogFormat(DebugInterface *cpu, const std::string &fmt if (expression.empty()) { result += "{}"; } else { + int type = 'x'; + if (expression.length() > 2 && expression[expression.length() - 2] == ':') { + switch (expression[expression.length() - 1]) { + case 'd': + case 'f': + case 'p': + case 's': + case 'x': + type = expression[expression.length() - 1]; + expression.resize(expression.length() - 2); + break; + + default: + // Assume a ternary. + break; + } + } + if (!cpu->initExpression(expression.c_str(), exp)) { return false; } - u32 expResult; - char resultString[32]; - if (!cpu->parseExpression(exp, expResult)) { + union { + int i; + u32 u; + float f; + } expResult; + char resultString[256]; + if (!cpu->parseExpression(exp, expResult.u)) { return false; } - snprintf(resultString, 32, "%08x", expResult); + switch (type) { + case 'd': + snprintf(resultString, sizeof(resultString), "%d", expResult.i); + break; + case 'f': + snprintf(resultString, sizeof(resultString), "%f", expResult.f); + break; + case 'p': + snprintf(resultString, sizeof(resultString), "%08x[%08x]", expResult.u, Memory::IsValidAddress(expResult.u) ? Memory::Read_U32(expResult.u) : 0); + break; + case 's': + snprintf(resultString, sizeof(resultString) - 1, "%s", Memory::IsValidAddress(expResult.u) ? Memory::GetCharPointer(expResult.u) : "(invalid)"); + break; + case 'x': + snprintf(resultString, sizeof(resultString), "%08x", expResult.u); + break; + } result += resultString; } diff --git a/Core/Debugger/DebugInterface.h b/Core/Debugger/DebugInterface.h index 0b98e1d512..6f48c7db0f 100644 --- a/Core/Debugger/DebugInterface.h +++ b/Core/Debugger/DebugInterface.h @@ -19,7 +19,7 @@ #include #include #include "Common/CommonTypes.h" -#include "math/expression_parser.h" +#include "Common/Math/expression_parser.h" struct MemMap; diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp index b04c40cc16..d05a0984b6 100644 --- a/Core/Debugger/DisassemblyManager.cpp +++ b/Core/Debugger/DisassemblyManager.cpp @@ -41,12 +41,12 @@ bool isInInterval(u32 start, u32 size, u32 value) } -static u32 computeHash(u32 address, u32 size) +static HashType computeHash(u32 address, u32 size) { #ifdef _M_X64 - return XXH64(Memory::GetPointer(address), size, 0xBACD7814BACD7814LL); + return XXH3_64bits(Memory::GetPointer(address), size); #else - return XXH32(Memory::GetPointer(address), size, 0xBACD7814); + return XXH3_64bits(Memory::GetPointer(address), size) & 0xFFFFFFFF; #endif } diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp index 5786898624..0efd301b0e 100644 --- a/Core/Debugger/SymbolMap.cpp +++ b/Core/Debugger/SymbolMap.cpp @@ -31,10 +31,12 @@ #include #include -#include "util/text/utf8.h" #include "zlib.h" + #include "Common/CommonTypes.h" -#include "Common/FileUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Log.h" +#include "Common/File/FileUtil.h" #include "Common/StringUtils.h" #include "Core/MemMap.h" #include "Core/Debugger/SymbolMap.h" diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp index 6175279363..418c81188d 100644 --- a/Core/Debugger/WebSocket.cpp +++ b/Core/Debugger/WebSocket.cpp @@ -17,7 +17,7 @@ #include #include -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" #include "Core/Debugger/WebSocket.h" #include "Core/Debugger/WebSocket/WebSocketUtils.h" #include "Core/MemMap.h" @@ -55,6 +55,7 @@ #include "Core/Debugger/WebSocket/GPUBufferSubscriber.h" #include "Core/Debugger/WebSocket/GPURecordSubscriber.h" #include "Core/Debugger/WebSocket/HLESubscriber.h" +#include "Core/Debugger/WebSocket/MemorySubscriber.h" #include "Core/Debugger/WebSocket/SteppingSubscriber.h" typedef DebuggerSubscriber *(*SubscriberInit)(DebuggerEventHandlerMap &map); @@ -66,6 +67,7 @@ static const std::vector subscribers({ &WebSocketGPUBufferInit, &WebSocketGPURecordInit, &WebSocketHLEInit, + &WebSocketMemoryInit, &WebSocketSteppingInit, }); diff --git a/Core/Debugger/WebSocket/DisasmSubscriber.cpp b/Core/Debugger/WebSocket/DisasmSubscriber.cpp index 6d2f76d746..172abf5f57 100644 --- a/Core/Debugger/WebSocket/DisasmSubscriber.cpp +++ b/Core/Debugger/WebSocket/DisasmSubscriber.cpp @@ -17,8 +17,10 @@ #include #include -#include "base/stringutil.h" -#include "util/text/utf8.h" + +#include "Common/Data/Encoding/Utf8.h" + +#include "Common/StringUtils.h" #include "Core/Debugger/Breakpoints.h" #include "Core/Debugger/DisassemblyManager.h" #include "Core/Debugger/WebSocket/DisasmSubscriber.h" diff --git a/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp b/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp index aff77aae30..155d70c70e 100644 --- a/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp +++ b/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp @@ -20,7 +20,7 @@ #include #include #endif -#include "data/base64.h" +#include "Common/Data/Encoding/Base64.h" #include "Common/StringUtils.h" #include "Core/Debugger/WebSocket/GPUBufferSubscriber.h" #include "Core/Debugger/WebSocket/WebSocketUtils.h" @@ -113,7 +113,7 @@ static bool StreamBufferToDataURI(DebuggerRequest &req, const GPUDebugBuffer &bu req.ws->AddFragment(false, Base64Encode(ctx->buf, ctx->bufSize)); ctx->bufSize = 0; } - assert(ctx->bufSize == 0 || length == 0); + _assert_(ctx->bufSize == 0 || length == 0); // Save bytes that would result in padding for next time. size_t toBuffer = length % 3; @@ -241,7 +241,7 @@ static void GenericStreamBuffer(DebuggerRequest &req, std::function #include + +#include "Common/Data/Text/Parsers.h" #include "Common/StringUtils.h" #include "Core/Debugger/WebSocket/WebSocketUtils.h" +inline void DebuggerJsonAddTicket(JsonWriter &writer, const JsonGet &data) { + const JsonNode *value = data.get("ticket"); + if (value) + writer.writeRaw("ticket", json_stringify(value)); +} + JsonWriter &DebuggerRequest::Respond() { writer_.begin(); writer_.writeString("event", name); diff --git a/Core/Debugger/WebSocket/WebSocketUtils.h b/Core/Debugger/WebSocket/WebSocketUtils.h index ac75838583..5caa28adaf 100644 --- a/Core/Debugger/WebSocket/WebSocketUtils.h +++ b/Core/Debugger/WebSocket/WebSocketUtils.h @@ -17,15 +17,15 @@ #pragma once -#include -#include -#include "json/json_reader.h" -#include "json/json_writer.h" -#include "net/websocket_server.h" -#include "Common/Log.h" - #include "ppsspp_config.h" +#include + +#include "Common/Log.h" +#include "Common/Data/Format/JSONReader.h" +#include "Common/Data/Format/JSONWriter.h" +#include "Common/Net/WebsocketServer.h" + #if PPSSPP_PLATFORM(UWP) // Enum name overlapped with UWP macro, quick hack to disable it #undef OPTIONAL @@ -33,12 +33,6 @@ using namespace json; -static inline void DebuggerJsonAddTicket(JsonWriter &writer, const JsonGet &data) { - const JsonNode *value = data.get("ticket"); - if (value) - writer.writeRaw("ticket", json_stringify(value)); -} - struct DebuggerErrorEvent { DebuggerErrorEvent(const std::string m, LogTypes::LOG_LEVELS l, const JsonGet data = JsonValue(JSON_NULL)) : message(m), level(l) { @@ -54,7 +48,7 @@ struct DebuggerErrorEvent { LogTypes::LOG_LEVELS level; std::string ticketRaw; - operator std::string() { + operator std::string() const { JsonWriter j; j.begin(); j.writeString("event", "error"); diff --git a/Core/Dialog/PSPDialog.cpp b/Core/Dialog/PSPDialog.cpp index 9ddc44f630..2a65cb03a7 100644 --- a/Core/Dialog/PSPDialog.cpp +++ b/Core/Dialog/PSPDialog.cpp @@ -15,9 +15,10 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "i18n/i18n.h" +#include "Common/Data/Text/I18n.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Common/StringUtils.h" #include "Core/CoreTiming.h" #include "Core/HLE/sceCtrl.h" @@ -137,26 +138,26 @@ void PSPDialog::DoState(PointerWrap &p) if (!s) return; - p.Do(status); - p.Do(lastButtons); - p.Do(buttons); - p.Do(fadeTimer); - p.Do(isFading); - p.Do(fadeIn); - p.Do(fadeValue); + Do(p, status); + Do(p, lastButtons); + Do(p, buttons); + Do(p, fadeTimer); + Do(p, isFading); + Do(p, fadeIn); + Do(p, fadeValue); // I don't think we should save these two... Let's just ignore them for now for compat. int okButtonImg = 0; - p.Do(okButtonImg); + Do(p, okButtonImg); int cancelButtonImg = 0; - p.Do(cancelButtonImg); + Do(p, cancelButtonImg); - p.Do(okButtonFlag); - p.Do(cancelButtonFlag); + Do(p, okButtonFlag); + Do(p, cancelButtonFlag); if (s >= 2) { - p.Do(pendingStatus); - p.Do(pendingStatusTicks); + Do(p, pendingStatus); + Do(p, pendingStatusTicks); } else { pendingStatusTicks = 0; } @@ -198,6 +199,16 @@ bool PSPDialog::IsButtonHeld(int checkButton, int &framesHeld, int framesHeldThr return false; } +PPGeStyle PSPDialog::FadedStyle(PPGeAlign align, float scale) { + PPGeStyle textStyle; + textStyle.align = align; + textStyle.scale = scale; + textStyle.color = CalcFadedColor(textStyle.color); + textStyle.hasShadow = true; + textStyle.shadowColor = CalcFadedColor(textStyle.shadowColor); + return textStyle; +} + void PSPDialog::DisplayButtons(int flags, const char *caption) { bool useCaption = false; @@ -207,6 +218,8 @@ void PSPDialog::DisplayButtons(int flags, const char *caption) truncate_cpy(safeCaption, caption); } + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_LEFT, FONT_SCALE); + auto di = GetI18NCategory("Dialog"); float x1 = 183.5f, x2 = 261.5f; if (GetCommonParam()->buttonSwap == 1) { @@ -215,16 +228,12 @@ void PSPDialog::DisplayButtons(int flags, const char *caption) } if (flags & DS_BUTTON_OK) { const char *text = useCaption ? safeCaption : di->T("Enter"); - PPGeDrawImage(okButtonImg, x2, 258, 11.5f, 11.5f, 0, CalcFadedColor(0x80000000)); - PPGeDrawImage(okButtonImg, x2, 256, 11.5f, 11.5f, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(text, x2 + 15.5f, 254, PPGE_ALIGN_LEFT, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawText(text, x2 + 14.5f, 252, PPGE_ALIGN_LEFT, FONT_SCALE, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(okButtonImg, x2, 256, 11.5f, 11.5f, textStyle); + PPGeDrawText(text, x2 + 14.5f, 252, textStyle); } if (flags & DS_BUTTON_CANCEL) { const char *text = useCaption ? safeCaption : di->T("Back"); - PPGeDrawText(text, x1 + 15.5f, 254, PPGE_ALIGN_LEFT, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawText(text, x1 + 14.5f, 252, PPGE_ALIGN_LEFT, FONT_SCALE, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawImage(cancelButtonImg, x1, 258, 11.5f, 11.5f, 0, CalcFadedColor(0x80000000)); - PPGeDrawImage(cancelButtonImg, x1, 256, 11.5f, 11.5f, 0, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(cancelButtonImg, x1, 256, 11.5f, 11.5f, textStyle); + PPGeDrawText(text, x1 + 14.5f, 252, textStyle); } } diff --git a/Core/Dialog/PSPDialog.h b/Core/Dialog/PSPDialog.h index 4de49d27f0..abf652f18c 100644 --- a/Core/Dialog/PSPDialog.h +++ b/Core/Dialog/PSPDialog.h @@ -17,11 +17,12 @@ #pragma once -#include "gfx/texture_atlas.h" +#include "Common/Render/TextureAtlas.h" #include "Common/Common.h" #include "Common/CommonTypes.h" #include "Common/Swap.h" +#include "Core/Util/PPGeDraw.h" class PointerWrap; @@ -83,6 +84,7 @@ public: void StartDraw(); void EndDraw(); protected: + PPGeStyle FadedStyle(PPGeAlign align, float scale); void UpdateButtons(); bool IsButtonPressed(int checkButton); bool IsButtonHeld(int checkButton, int &framesHeld, int framesHeldThreshold = 30, int framesHeldRepeatRate = 10); diff --git a/Core/Dialog/PSPGamedataInstallDialog.cpp b/Core/Dialog/PSPGamedataInstallDialog.cpp index 5210914309..319314fd20 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.cpp +++ b/Core/Dialog/PSPGamedataInstallDialog.cpp @@ -17,7 +17,8 @@ #include #include "Common/Common.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/ELF/ParamSFO.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" @@ -260,25 +261,25 @@ void PSPGamedataInstallDialog::DoState(PointerWrap &p) { // This was included in version 1 and higher. PSPDialog::DoState(p); - p.Do(request); + Do(p, request); // This was included in version 2 and higher, but for BC reasons we use 3+. if (s >= 3) { - p.Do(param.ptr); - p.Do(inFileNames); - p.Do(numFiles); - p.Do(readFiles); - p.Do(allFilesSize); - p.Do(allReadSize); - p.Do(progressValue); + Do(p, param.ptr); + Do(p, inFileNames); + Do(p, numFiles); + Do(p, readFiles); + Do(p, allFilesSize); + Do(p, allReadSize); + Do(p, progressValue); } else { param.ptr = 0; } if (s >= 4) { - p.Do(currentInputFile); - p.Do(currentInputBytesLeft); - p.Do(currentOutputFile); + Do(p, currentInputFile); + Do(p, currentInputBytesLeft); + Do(p, currentOutputFile); } else { currentInputFile = 0; currentInputBytesLeft = 0; diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index 20b3fb84a3..d68abaa9b5 100755 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -15,15 +15,18 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/StringUtils.h" #include "Core/Dialog/PSPMsgDialog.h" +#include "Core/Dialog/PSPSaveDialog.h" #include "Core/Util/PPGeDraw.h" #include "Core/HLE/sceCtrl.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" -#include "Common/ChunkFile.h" -#include "Common/StringUtils.h" -#include "i18n/i18n.h" -#include "util/text/utf8.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Encoding/Utf8.h" static const float FONT_SCALE = 0.65f; @@ -66,6 +69,9 @@ int PSPMsgDialog::Init(unsigned int paramAddr) { } flag = 0; + scrollPos_ = 0.0f; + framesUpHeld_ = 0; + framesDownHeld_ = 0; // Check request invalidity if(messageDialog.type == 0 && !(messageDialog.errorNum & 0x80000000)) @@ -129,7 +135,7 @@ int PSPMsgDialog::Init(unsigned int paramAddr) { } if (flag & DS_ERRORMSG) { - snprintf(msgText, 512, "Error code: %08x", messageDialog.errorNum); + FormatErrorCode(messageDialog.errorNum); } else { truncate_cpy(msgText, messageDialog.string); } @@ -141,74 +147,131 @@ int PSPMsgDialog::Init(unsigned int paramAddr) { return 0; } -void PSPMsgDialog::DisplayMessage(std::string text, bool hasYesNo, bool hasOK) -{ - float WRAP_WIDTH = 300.0f; - if (UTF8StringNonASCIICount(text.c_str()) > 3) - WRAP_WIDTH = 372.0f; - float y = 140.0f; - float h, sy, ey; - PPGeMeasureText(nullptr, &h, text.c_str(), FONT_SCALE, PPGE_LINE_WRAP_WORD, WRAP_WIDTH); - float h2 = h / 2.0f; - ey = y + h2 + 20.0f; +void PSPMsgDialog::FormatErrorCode(uint32_t code) { + auto di = GetI18NCategory("Dialog"); - if (hasYesNo) - { - auto di = GetI18NCategory("Dialog"); - const char *choiceText; - u32 yesColor, noColor; - float x, w; + switch (code) { + case SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN: + snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataDataBroken", "Save data was corrupt."), code); + break; + + case SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_MS: + case SCE_UTILITY_SAVEDATA_ERROR_RW_NO_MEMSTICK: + case SCE_UTILITY_SAVEDATA_ERROR_SAVE_NO_MS: + case SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_MS: + case SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_MS: + snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataNoMS", "Memory stick not inserted."), code); + break; + + case SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA: + case SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA: + case SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA: + case SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_DATA: + snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataNoData", "Warning: no save data was found."), code); + break; + + case SCE_UTILITY_SAVEDATA_ERROR_RW_MEMSTICK_FULL: + case SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE: + snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataMSFull", "Memory stick full. Check your storage space."), code); + break; + + default: + snprintf(msgText, 512, "%s %08x", di->T("MsgErrorCode", "Error code:"), code); + } +} + +void PSPMsgDialog::DisplayMessage(std::string text, bool hasYesNo, bool hasOK) { + auto di = GetI18NCategory("Dialog"); + + PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_CENTER, FONT_SCALE); + PPGeStyle messageStyle = FadedStyle(PPGeAlign::BOX_HCENTER, FONT_SCALE); + + // Without the scrollbar, we have 390 total pixels. + float WRAP_WIDTH = 340.0f; + if (UTF8StringNonASCIICount(text.c_str()) >= text.size() / 4) { + WRAP_WIDTH = 376.0f; + if (text.size() > 12) { + messageStyle.scale = 0.6f; + } + } + + float totalHeight = 0.0f; + PPGeMeasureText(nullptr, &totalHeight, text.c_str(), FONT_SCALE, PPGE_LINE_WRAP_WORD, WRAP_WIDTH); + // The PSP normally only shows about 8 lines at a time. + // For improved UX, we intentionally show part of the next line. + float visibleHeight = std::min(totalHeight, 175.0f); + float h2 = visibleHeight / 2.0f; + + float centerY = 135.0f; + float sy = centerY - h2 - 15.0f; + float ey = centerY + h2 + 20.0f; + float buttonY = centerY + h2 + 5.0f; + + auto drawSelectionBoxAndAdjust = [&](float x) { + // Box has a fixed size. + float w = 15.0f; + float h = 8.0f; + PPGeDrawRect(x - w, buttonY - h, x + w, buttonY + h, CalcFadedColor(0x6DCFCFCF)); + + centerY -= h + 5.0f; + sy -= h + 5.0f; + ey = buttonY + h * 2.0f + 5.0f; + }; + + if (hasYesNo) { if (yesnoChoice == 1) { - choiceText = di->T("Yes"); - x = 204.0f; - yesColor = 0xFFFFFFFF; - noColor = 0xFFFFFFFF; + drawSelectionBoxAndAdjust(204.0f); + } else { + drawSelectionBoxAndAdjust(273.0f); } - else { - choiceText = di->T("No"); - x = 273.0f; - yesColor = 0xFFFFFFFF; - noColor = 0xFFFFFFFF; - } - PPGeMeasureText(&w, &h, choiceText, FONT_SCALE); - w = 15.0f; - h = 8.0f; - float y2 = y + h2 + 8.0f; - h2 += h + 5.0f; - y = 135.0f - h; - PPGeDrawRect(x - w, y2 - h, x + w, y2 + h, CalcFadedColor(0x6DCFCFCF)); - PPGeDrawText(di->T("Yes"), 204.0f, y2 + 1.0f, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawText(di->T("Yes"), 203.0f, y2 - 1.0f, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(yesColor)); - PPGeDrawText(di->T("No"), 273.0f, y2 + 1.0f, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawText(di->T("No"), 272.0f, y2 - 1.0f, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(noColor)); + + PPGeDrawText(di->T("Yes"), 203.0f, buttonY - 1.0f, buttonStyle); + PPGeDrawText(di->T("No"), 272.0f, buttonY - 1.0f, buttonStyle); if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0) { yesnoChoice = 1; - } - else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1) { + } else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1) { yesnoChoice = 0; } - ey = y2 + 25.0f; + buttonY += 8.0f + 5.0f; } if (hasOK) { - auto di = GetI18NCategory("Dialog"); - float x, w; - x = 240.0f; - w = 15.0f; - h = 8.0f; - float y2 = y + h2 + 8.0f; - h2 += h + 5.0f; - y = 135.0f - h; - PPGeDrawRect(x - w, y2 - h, x + w, y2 + h, CalcFadedColor(0x6DCFCFCF)); - PPGeDrawText(di->T("OK"), 240.0f, y2 + 1.0f, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawText(di->T("OK"), 239.0f, y2 - 1.0f, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0xFFFFFFFF)); - ey = y2 + 25.0f; + drawSelectionBoxAndAdjust(240.0f); + + PPGeDrawText(di->T("OK"), 239.0f, buttonY - 1.0f, buttonStyle); + buttonY += 8.0f + 5.0f; + } + + PPGeScissor(0, (int)(centerY - h2 - 2), 480, (int)(centerY + h2 + 2)); + PPGeDrawTextWrapped(text.c_str(), 240.0f, centerY - h2 - scrollPos_, WRAP_WIDTH, 0, messageStyle); + PPGeScissorReset(); + + // Do we need a scrollbar? + if (visibleHeight < totalHeight) { + float scrollSpeed = 5.0f; + float scrollMax = totalHeight - visibleHeight; + + float bobHeight = (visibleHeight / totalHeight) * visibleHeight; + float bobOffset = (scrollPos_ / scrollMax) * (visibleHeight - bobHeight); + float bobY1 = centerY - h2 + bobOffset; + PPGeDrawRect(435.0f, bobY1, 440.0f, bobY1 + bobHeight, CalcFadedColor(0xFFCCCCCC)); + + auto buttonDown = [this](int btn, int &held) { + if (IsButtonPressed(btn)) { + held = 0; + return true; + } + return IsButtonHeld(btn, held, 1, 1); + }; + if (buttonDown(CTRL_DOWN, framesDownHeld_) && scrollPos_ < scrollMax) { + scrollPos_ = std::min(scrollMax, scrollPos_ + scrollSpeed); + } + if (buttonDown(CTRL_UP, framesUpHeld_) && scrollPos_ > 0.0f) { + scrollPos_ = std::max(0.0f, scrollPos_ - scrollSpeed); + } } - PPGeDrawTextWrapped(text.c_str(), 241.0f, y+2, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawTextWrapped(text.c_str(), 240.0f, y, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0xFFFFFFFF)); - sy = 125.0f - h2; PPGeDrawRect(40.0f, sy, 440.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF)); PPGeDrawRect(40.0f, ey, 440.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF)); } @@ -316,11 +379,18 @@ void PSPMsgDialog::DoState(PointerWrap &p) if (!s) return; - p.Do(flag); - p.Do(messageDialog); - p.Do(messageDialogAddr); - p.DoArray(msgText, sizeof(msgText)); - p.Do(yesnoChoice); + Do(p, flag); + Do(p, messageDialog); + Do(p, messageDialogAddr); + DoArray(p, msgText, sizeof(msgText)); + Do(p, yesnoChoice); + + // We don't save state this, you'll just have to scroll down again. + if (p.mode == p.MODE_READ) { + scrollPos_ = 0.0f; + framesUpHeld_ = 0; + framesDownHeld_ = 0; + } } pspUtilityDialogCommon *PSPMsgDialog::GetCommonParam() diff --git a/Core/Dialog/PSPMsgDialog.h b/Core/Dialog/PSPMsgDialog.h index 864420f0f0..78490393f8 100644 --- a/Core/Dialog/PSPMsgDialog.h +++ b/Core/Dialog/PSPMsgDialog.h @@ -74,7 +74,8 @@ protected: return false; } -private : +private: + void FormatErrorCode(uint32_t code); void DisplayMessage(std::string text, bool hasYesNo = false, bool hasOK = false); enum Flags @@ -98,5 +99,8 @@ private : char msgText[512]; int yesnoChoice; + float scrollPos_ = 0.0f; + int framesUpHeld_ = 0; + int framesDownHeld_ = 0; }; diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index a5c278bf06..3dfb8d45c7 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -15,15 +15,24 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "PSPNetconfDialog.h" -#include "ChunkFile.h" +#if defined(_WIN32) +#include "Common/CommonWindows.h" +#endif +#include +#include "Common/Data/Text/I18n.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Config.h" #include "Core/MemMapHelpers.h" -#include "Core/HLE/sceNetAdhoc.h" #include "Core/Util/PPGeDraw.h" +#include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceCtrl.h" #include "Core/HLE/sceUtility.h" -#include "i18n/i18n.h" +#include "Core/HLE/sceNet.h" +#include "Core/HLE/sceNetAdhoc.h" +#include "Core/Dialog/PSPNetconfDialog.h" +#include "Common/Data/Encoding/Utf8.h" + #define NETCONF_CONNECT_APNET 0 #define NETCONF_STATUS_APNET 1 @@ -32,9 +41,19 @@ #define NETCONF_CREATE_ADHOC 4 #define NETCONF_JOIN_ADHOC 5 +static const float FONT_SCALE = 0.65f; + // Needs testing. const static int NET_INIT_DELAY_US = 300000; -const static int NET_SHUTDOWN_DELAY_US = 26000; +const static int NET_SHUTDOWN_DELAY_US = 260000; +const static int NET_RUNNING_DELAY_US = 1000000; // KHBBS is showing adhoc dialog for about 3-4 seconds, but feels too long, so we're faking it to 1 sec instead to let players read the text +const static int NET_CONNECT_TIMEOUT = 15000000; // Using 15 secs to match the timeout on Adhoc Server side (SERVER_USER_TIMEOUT) + +struct ScanInfos { + s32_le sz; + SceNetAdhocctlScanInfoEmu si; +} PACK; + PSPNetconfDialog::PSPNetconfDialog() { } @@ -47,6 +66,7 @@ int PSPNetconfDialog::Init(u32 paramAddr) { if (status != SCE_UTILITY_STATUS_NONE) return SCE_ERROR_UTILITY_INVALID_STATUS; + requestAddr = paramAddr; int size = Memory::Read_U32(paramAddr); memset(&request, 0, sizeof(request)); // Only copy the right size to support different request format @@ -56,6 +76,22 @@ int PSPNetconfDialog::Init(u32 paramAddr) { // Eat any keys pressed before the dialog inited. UpdateButtons(); + okButtonImg = ImageID("I_CIRCLE"); + cancelButtonImg = ImageID("I_CROSS"); + okButtonFlag = CTRL_CIRCLE; + cancelButtonFlag = CTRL_CROSS; + if (request.common.buttonSwap == 1) + { + okButtonImg = ImageID("I_CROSS"); + cancelButtonImg = ImageID("I_CIRCLE"); + okButtonFlag = CTRL_CROSS; + cancelButtonFlag = CTRL_CIRCLE; + } + + connResult = -1; + scanInfosAddr = 0; + scanStep = 0; + startTime = (u64)(time_now_d() * 1000000.0); StartFade(true); return 0; @@ -63,12 +99,149 @@ int PSPNetconfDialog::Init(u32 paramAddr) { void PSPNetconfDialog::DrawBanner() { - PPGeDrawRect(0, 0, 480, 23, CalcFadedColor(0x65636358)); + PPGeDrawRect(0, 0, 480, 22, CalcFadedColor(0x65636358)); + + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f); + textStyle.hasShadow = false; // TODO: Draw a hexagon icon - PPGeDrawImage(10, 6, 12.0f, 12.0f, 1, 10, 1, 10, 10, 10, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(10, 5, 11.0f, 10.0f, 1, 10, 1, 10, 10, 10, CalcFadedColor(0xFFFFFFFF)); auto di = GetI18NCategory("Dialog"); - PPGeDrawText(di->T("Network Connection"), 30, 11, PPGE_ALIGN_VCENTER, 0.6f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText(di->T("Network Connection"), 31, 10, textStyle); +} + +void PSPNetconfDialog::DrawIndicator() { + + // TODO: Draw animated circle as processing indicator + PPGeDrawImage(456, 248, 20.0f, 20.0f, 1, 10, 1, 10, 10, 10, CalcFadedColor(0xFFFFFFFF)); +} + +void PSPNetconfDialog::DisplayMessage(std::string text1, std::string text2a, std::string text2b, std::string text3a, std::string text3b, bool hasYesNo, bool hasOK) { + auto di = GetI18NCategory("Dialog"); + + PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_CENTER, FONT_SCALE); + PPGeStyle messageStyle = FadedStyle(PPGeAlign::BOX_HCENTER, FONT_SCALE); + PPGeStyle messageStyleRight = FadedStyle(PPGeAlign::BOX_RIGHT, FONT_SCALE); + PPGeStyle messageStyleLeft = FadedStyle(PPGeAlign::BOX_LEFT, FONT_SCALE); + + std::string text2 = text2a + " " + text2b; + std::string text3 = text3a + " " + text3b; + + // Without the scrollbar, we have 350 total pixels. + float WRAP_WIDTH = 300.0f; + if (UTF8StringNonASCIICount(text1.c_str()) >= (int)text1.size() / 4) { + WRAP_WIDTH = 336.0f; + if (text1.size() > 12) { + messageStyle.scale = 0.6f; + } + } + + float totalHeight1 = 0.0f; + PPGeMeasureText(nullptr, &totalHeight1, text1.c_str(), FONT_SCALE, PPGE_LINE_WRAP_WORD, WRAP_WIDTH); + float totalHeight2 = 0.0f; + if (text2 != " ") + PPGeMeasureText(nullptr, &totalHeight2, text2.c_str(), FONT_SCALE, PPGE_LINE_USE_ELLIPSIS, WRAP_WIDTH); + float totalHeight3 = 0.0f; + if (text3 != " ") + PPGeMeasureText(nullptr, &totalHeight3, text3.c_str(), FONT_SCALE, PPGE_LINE_USE_ELLIPSIS, WRAP_WIDTH); + float marginTop = 0.0f; + if (text2 != " " || text3 != " ") + marginTop = 11.0f; + float totalHeight = totalHeight1 + totalHeight2 + totalHeight3 + marginTop; + // The PSP normally only shows about 8 lines at a time. + // For improved UX, we intentionally show part of the next line. + float visibleHeight = std::min(totalHeight, 175.0f); + float h2 = visibleHeight / 2.0f; + + float centerY = 135.0f; + float sy = centerY - h2 - 15.0f; + float ey = centerY + h2 + 20.0f; + float buttonY = centerY + h2 + 5.0f; + + auto drawSelectionBoxAndAdjust = [&](float x) { + // Box has a fixed size. + float w = 15.0f; + float h = 8.0f; + PPGeDrawRect(x - w, buttonY - h, x + w, buttonY + h, CalcFadedColor(0x6DCFCFCF)); + + centerY -= h + 5.0f; + sy -= h + 5.0f; + ey = buttonY + h * 2.0f + 5.0f; + }; + + if (hasYesNo) { + if (yesnoChoice == 1) { + drawSelectionBoxAndAdjust(204.0f); + } + else { + drawSelectionBoxAndAdjust(273.0f); + } + + PPGeDrawText(di->T("Yes"), 203.0f, buttonY - 1.0f, buttonStyle); + PPGeDrawText(di->T("No"), 272.0f, buttonY - 1.0f, buttonStyle); + if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0) { + yesnoChoice = 1; + } + else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1) { + yesnoChoice = 0; + } + buttonY += 8.0f + 5.0f; + } + + if (hasOK) { + drawSelectionBoxAndAdjust(240.0f); + + PPGeDrawText(di->T("OK"), 239.0f, buttonY - 1.0f, buttonStyle); + buttonY += 8.0f + 5.0f; + } + + PPGeScissor(0, (int)(centerY - h2 - 2), 480, (int)(centerY + h2 + 2)); + PPGeDrawTextWrapped(text1.c_str(), 240.0f, centerY - h2 - scrollPos_, WRAP_WIDTH, 0, messageStyle); + if (text2a != "") { + if (text2b != "") + PPGeDrawTextWrapped(text2a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleRight); + else + PPGeDrawTextWrapped(text2a.c_str(), 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyle); + } + if (text2b != "") + PPGeDrawTextWrapped(text2b.c_str(), 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleLeft); + if (text3a != "") { + if (text3b != "") + PPGeDrawTextWrapped(text3a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleRight); + else + PPGeDrawTextWrapped(text3a.c_str(), 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyle); + } + if (text3b != "") + PPGeDrawTextWrapped(text3b.c_str(), 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleLeft); + PPGeScissorReset(); + + // Do we need a scrollbar? + if (visibleHeight < totalHeight) { + float scrollSpeed = 5.0f; + float scrollMax = totalHeight - visibleHeight; + + float bobHeight = (visibleHeight / totalHeight) * visibleHeight; + float bobOffset = (scrollPos_ / scrollMax) * (visibleHeight - bobHeight); + float bobY1 = centerY - h2 + bobOffset; + PPGeDrawRect(415.0f, bobY1, 420.0f, bobY1 + bobHeight, CalcFadedColor(0xFFCCCCCC)); + + auto buttonDown = [this](int btn, int& held) { + if (IsButtonPressed(btn)) { + held = 0; + return true; + } + return IsButtonHeld(btn, held, 1, 1); + }; + if (buttonDown(CTRL_DOWN, framesDownHeld_) && scrollPos_ < scrollMax) { + scrollPos_ = std::min(scrollMax, scrollPos_ + scrollSpeed); + } + if (buttonDown(CTRL_UP, framesUpHeld_) && scrollPos_ > 0.0f) { + scrollPos_ = std::max(0.0f, scrollPos_ - scrollSpeed); + } + } + + PPGeDrawRect(60.0f, sy, 420.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawRect(60.0f, ey, 420.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF)); } int PSPNetconfDialog::Update(int animSpeed) { @@ -79,38 +252,228 @@ int PSPNetconfDialog::Update(int animSpeed) { UpdateButtons(); auto di = GetI18NCategory("Dialog"); auto err = GetI18NCategory("Error"); - const float WRAP_WIDTH = 254.0f; - const ImageID confirmBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CROSS") : ImageID("I_CIRCLE"); - const int confirmBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; - + u64 now = (u64)(time_now_d() * 1000000.0); + + // It seems JPCSP doesn't check for NETCONF_STATUS_APNET if (request.netAction == NETCONF_CONNECT_APNET || request.netAction == NETCONF_STATUS_APNET || request.netAction == NETCONF_CONNECT_APNET_LAST) { + int state = NetApctl_GetState(); + UpdateFade(animSpeed); StartDraw(); - DrawBanner(); - PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0x63636363)); - PPGeDrawTextWrapped(err->T("PPSSPPDoesNotSupportInternet", "PPSSPP currently does not support connecting to the Internet for DLC, PSN, or game updates."), 241, 132, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, 0.5f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawImage(confirmBtnImage, 195, 250, 20, 20, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(di->T("OK"), 225, 252, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); - if (IsButtonPressed(confirmBtn)) { - StartFade(false); - ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); - // TODO: When the dialog is aborted, does it really set the result to this? - // It seems to make Phantasy Star Portable 2 happy, so it should be okay for now. - request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT; + if (!hideNotice) { + const float WRAP_WIDTH = 254.0f; + const ImageID confirmBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CROSS") : ImageID("I_CIRCLE"); + const int confirmBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; + const ImageID cancelBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CIRCLE") : ImageID("I_CROSS"); + const int cancelBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS; + + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_CENTER, 0.5f); + PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f); + + PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0x63636363)); + DrawBanner(); + PPGeDrawTextWrapped(err->T("PPSSPPDoesNotSupportInternet", "PPSSPP currently does not support connecting to the Internet for DLC, PSN, or game updates.\nContinuing may cause unexpected behavior or freezes."), 241, 132, WRAP_WIDTH, 0, textStyle); + PPGeDrawImage(confirmBtnImage, 185, 240, 20, 20, buttonStyle); + PPGeDrawText(di->T("OK"), 215, 243, buttonStyle); + PPGeDrawImage(cancelBtnImage, 255, 240, 20, 20, buttonStyle); + PPGeDrawText(di->T("Cancel"), 285, 243, buttonStyle); + + // Since we don't support Infrastructure API yet.. Let the Player read the message first and choose to continue or not (ie. for testing networks API) + if (IsButtonPressed(cancelBtn)) { + StartFade(false); + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US); + // TODO: When the dialog is aborted, does it really set the result to this? + // It seems to make Phantasy Star Portable 2 happy, so it should be okay for now. + request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT; + } + else if (IsButtonPressed(confirmBtn)) { + hideNotice = true; + StartFade(true); + } + } + else { + PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0xC0C8B2AC)); + DrawBanner(); + DrawIndicator(); + + if (state == PSP_NET_APCTL_STATE_GOT_IP || state == PSP_NET_APCTL_STATE_GETTING_IP) { + DisplayMessage(di->T("ObtainingIP", "Obtaining IP address.\nPlease wait..."), di->T("ConnectionName", "Connection Name"), netApctlInfo.name, di->T("SSID"), netApctlInfo.ssid); + } + else { + // Skipping the Select Connection screen since we only have 1 fake profile + DisplayMessage(di->T("ConnectingAP", "Connecting to the access point.\nPlease wait..."), di->T("ConnectionName", "Connection Name"), netApctlInfo.name, di->T("SSID"), netApctlInfo.ssid); + } + DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel")); + + // The Netconf dialog stays visible until the network reaches + // the state PSP_NET_APCTL_STATE_GOT_IP. + if (state == PSP_NET_APCTL_STATE_GOT_IP) { + if (pendingStatus != SCE_UTILITY_STATUS_FINISHED) { + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_RUNNING_DELAY_US); + } + else if (GetStatus() == SCE_UTILITY_STATUS_FINISHED) { + // We are done! + StartFade(false); + } + } + + else if (state == PSP_NET_APCTL_STATE_GETTING_IP) { + // Switch to the next message + StartFade(true); + } + + else if (state == PSP_NET_APCTL_STATE_DISCONNECTED) { + // When connecting with infrastructure, simulate a connection + // using the first network configuration entry. + connResult = sceNetApctlConnect(1); + } } EndDraw(); - } else if (request.netAction == NETCONF_CONNECT_ADHOC || request.netAction == NETCONF_CREATE_ADHOC || request.netAction == NETCONF_JOIN_ADHOC) { - if (request.NetconfData.IsValid()) { - Shutdown(true); - if (sceNetAdhocctlCreate(request.NetconfData->groupName) == 0) { - ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); - return 0; - } - return -1; - } } + else if (request.netAction == NETCONF_CONNECT_ADHOC || request.netAction == NETCONF_CREATE_ADHOC || request.netAction == NETCONF_JOIN_ADHOC) { + int state = NetAdhocctl_GetState(); + bool timedout = (state == ADHOCCTL_STATE_DISCONNECTED && now - startTime > NET_CONNECT_TIMEOUT); + + UpdateFade(animSpeed); + StartDraw(); + PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0xC0C8B2AC)); + DrawBanner(); + DrawIndicator(); + + if (timedout) { + // FIXME: Do we need to show error message? + DisplayMessage(di->T("InternalError", "An internal error has occurred.") + StringFromFormat("\n(%08X)", connResult)); + DisplayButtons(DS_BUTTON_CANCEL, di->T("Back")); + } + else { + std::string channel = std::to_string(g_Config.iWlanAdhocChannel); + if (g_Config.iWlanAdhocChannel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) + channel = "Automatic"; + + DisplayMessage(di->T("ConnectingPleaseWait", "Connecting.\nPlease wait..."), di->T("Channel") + std::string(" ") + di->T(channel)); + + // Only Join mode is showing Cancel button on KHBBS and the button will fade out before the dialog is fading out, probably because it's already connected thus can't be canceled anymore + if (request.netAction == NETCONF_JOIN_ADHOC) + DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel")); + + // KHBBS will first enter the arena using NETCONF_CONNECT_ADHOC (auto-create group when not exist yet?), but when the event started the event's creator use NETCONF_CREATE_ADHOC while the joining players use NETCONF_JOIN_ADHOC + if (request.NetconfData.IsValid()) { + if (state == ADHOCCTL_STATE_DISCONNECTED) { + switch (request.netAction) + { + case NETCONF_CREATE_ADHOC: + if (connResult < 0) { + connResult = sceNetAdhocctlCreate(request.NetconfData->groupName); + } + break; + case NETCONF_JOIN_ADHOC: + // FIXME: Should we Scan for a matching group first before Joining a Group (like adhoc games normally do)? Or Is it really allowed to join non-existing group? + if (scanStep == 0) { + if (sceNetAdhocctlScan() >= 0) { + u32 structsz = sizeof(ScanInfos); + if (Memory::IsValidAddress(scanInfosAddr)) + userMemory.Free(scanInfosAddr); + scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo"); + Memory::Write_U32(sizeof(SceNetAdhocctlScanInfoEmu), scanInfosAddr); + scanStep = 1; + } + } + else if (scanStep == 1) { + s32 sz = Memory::Read_U32(scanInfosAddr); + // Get required buffer size + if (sceNetAdhocctlGetScanInfo(scanInfosAddr, 0) >= 0) { + s32 reqsz = Memory::Read_U32(scanInfosAddr); + if (reqsz > sz) { + sz = reqsz; + if (Memory::IsValidAddress(scanInfosAddr)) + userMemory.Free(scanInfosAddr); + u32 structsz = sz + sizeof(s32); + scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo"); + Memory::Write_U32(sz, scanInfosAddr); + } + if (reqsz > 0) { + if (sceNetAdhocctlGetScanInfo(scanInfosAddr, scanInfosAddr + sizeof(s32)) >= 0) { + ScanInfos* scanInfos = (ScanInfos*)Memory::GetPointer(scanInfosAddr); + int n = scanInfos->sz / sizeof(SceNetAdhocctlScanInfoEmu); + // Assuming returned SceNetAdhocctlScanInfoEmu(s) are contagious where next is pointing to current addr + sizeof(SceNetAdhocctlScanInfoEmu) + while (n > 0) { + SceNetAdhocctlScanInfoEmu* si = (SceNetAdhocctlScanInfoEmu*)Memory::GetPointer(scanInfosAddr + sizeof(s32) + sizeof(SceNetAdhocctlScanInfoEmu) * (n - 1LL)); + if (memcmp(si->group_name.data, request.NetconfData->groupName, ADHOCCTL_GROUPNAME_LEN) == 0) { + // Moving found group info to the front so we can use it on sceNetAdhocctlJoin easily + memcpy((char*)scanInfos + sizeof(s32), si, sizeof(SceNetAdhocctlScanInfoEmu)); + scanStep = 2; + break; + } + n--; + } + // Target group not found, try to scan again later + if (n <= 0) { + scanStep = 0; + } + } + } + // No group found, try to scan again later + else { + scanStep = 0; + } + } + } + else if (scanStep == 2) { + if (connResult < 0) { + connResult = sceNetAdhocctlJoin(scanInfosAddr + sizeof(s32)); + if (connResult >= 0) { + // We are done! + if (Memory::IsValidAddress(scanInfosAddr)) + userMemory.Free(scanInfosAddr); + scanInfosAddr = 0; + } + } + } + break; + default: + if (connResult < 0) { + connResult = sceNetAdhocctlConnect(request.NetconfData->groupName); + } + break; + } + } + } + } + + // The Netconf dialog stays visible until the network reaches + // the state ADHOCCTL_STATE_CONNECTED. + if (state == ADHOCCTL_STATE_CONNECTED) { + // Checking pendingStatus to make sure ChangeStatus not to continously extending the delay ticks on every call for eternity + if (pendingStatus != SCE_UTILITY_STATUS_FINISHED) { + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_RUNNING_DELAY_US); + } + // Start fading only when the actual status has changed + else if (GetStatus() == SCE_UTILITY_STATUS_FINISHED) { + StartFade(false); + } + // Let's not leaks any memory + if (Memory::IsValidAddress(scanInfosAddr)) + userMemory.Free(scanInfosAddr); + scanInfosAddr = 0; + } + + if ((request.netAction == NETCONF_JOIN_ADHOC || timedout) && IsButtonPressed(cancelButtonFlag)) { + StartFade(false); + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US); + request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT; + // Let's not leaks any memory + if (Memory::IsValidAddress(scanInfosAddr)) + userMemory.Free(scanInfosAddr); + scanInfosAddr = 0; + } + + EndDraw(); + } + + if (GetStatus() == SCE_UTILITY_STATUS_FINISHED || pendingStatus == SCE_UTILITY_STATUS_FINISHED) + Memory::Memcpy(requestAddr, &request, request.common.size); return 0; } @@ -130,9 +493,28 @@ int PSPNetconfDialog::Shutdown(bool force) { void PSPNetconfDialog::DoState(PointerWrap &p) { PSPDialog::DoState(p); - auto s = p.Section("PSPNetconfigDialog", 0, 1); + auto s = p.Section("PSPNetconfigDialog", 0, 2); if (!s) return; - p.Do(request); + Do(p, request); + if (s >= 2) { + Do(p, scanInfosAddr); + Do(p, scanStep); + Do(p, connResult); + } + else { + scanInfosAddr = 0; + scanStep = 0; + connResult = -1; + } + + if (p.mode == p.MODE_READ) { + startTime = 0; + } +} + +pspUtilityDialogCommon* PSPNetconfDialog::GetCommonParam() +{ + return &request.common; } diff --git a/Core/Dialog/PSPNetconfDialog.h b/Core/Dialog/PSPNetconfDialog.h index c3f891efd2..e02ebae5a0 100644 --- a/Core/Dialog/PSPNetconfDialog.h +++ b/Core/Dialog/PSPNetconfDialog.h @@ -18,7 +18,7 @@ #pragma once #include "Core/Dialog/PSPDialog.h" -#include "Core/MemMap.h" +#include "Core/MemMapHelpers.h" struct SceUtilityNetconfData { char groupName[8]; @@ -27,13 +27,14 @@ struct SceUtilityNetconfData { struct SceUtilityNetconfParam { pspUtilityDialogCommon common; - int netAction; + int netAction; // sets how to connect PSPPointer NetconfData; - int netHotspot; - int netHotspotConnected; - int netWifiSpot; + int netHotspot; // Flag to allow hotspot connections + int netHotspotConnected; // Flag to check if a hotspot connection is active + int netWifiSpot; // Flag to allow WIFI connections }; + class PSPNetconfDialog: public PSPDialog { public: PSPNetconfDialog(); @@ -43,6 +44,7 @@ public: virtual int Update(int animSpeed) override; virtual int Shutdown(bool force = false) override; virtual void DoState(PointerWrap &p) override; + virtual pspUtilityDialogCommon* GetCommonParam() override; protected: bool UseAutoStatus() override { @@ -50,6 +52,21 @@ protected: } private: + void DisplayMessage(std::string text1, std::string text2a = "", std::string text2b = "", std::string text3a = "", std::string text3b = "", bool hasYesNo = false, bool hasOK = false); void DrawBanner(); - SceUtilityNetconfParam request; + void DrawIndicator(); + + SceUtilityNetconfParam request = {}; + u32 requestAddr = 0; + int connResult = -1; + bool hideNotice = false; + + int yesnoChoice = 0; + float scrollPos_ = 0.0f; + int framesUpHeld_ = 0; + int framesDownHeld_ = 0; + + u32 scanInfosAddr = 0; + int scanStep = 0; + u64 startTime = 0; }; diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index a475d0ec36..c049225f02 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -16,10 +16,13 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "base/NativeApp.h" -#include "i18n/i18n.h" -#include "math/math_util.h" -#include "util/text/utf8.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Math/math_util.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/System/System.h" +#include "Common/Serialize/Serializer.h" #include "Core/Dialog/PSPOskDialog.h" #include "Core/Util/PPGeDraw.h" @@ -28,7 +31,6 @@ #include "Core/HLE/sceUtility.h" #include "Core/Config.h" #include "Core/Reporting.h" -#include "Common/ChunkFile.h" #include "GPU/GPUState.h" #ifndef _WIN32 @@ -766,7 +768,14 @@ void PSPOskDialog::RenderKeyboard() float previewLeftSide = (480.0f - (12.0f * drawLimit)) / 2.0f; float title = (480.0f - (0.5f * drawLimit)) / 2.0f; - PPGeDrawText(oskDesc.c_str(), title , 20, PPGE_ALIGN_CENTER, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeStyle descStyle = FadedStyle(PPGeAlign::BOX_CENTER, 0.5f); + PPGeDrawText(oskDesc.c_str(), title, 20, descStyle); + + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_HCENTER, 0.5f); + + PPGeStyle keyStyle = FadedStyle(PPGeAlign::BOX_HCENTER, 0.6f); + PPGeStyle selectedKeyStyle = FadedStyle(PPGeAlign::BOX_HCENTER, 0.6f); + selectedKeyStyle.color = CalcFadedColor(0xFF3060FF); std::u16string result; @@ -776,12 +785,11 @@ void PSPOskDialog::RenderKeyboard() drawIndex = result.size() == limit + 1 ? drawIndex - 1 : drawIndex; // When the length reached limit, the last character don't fade in and out. for (u32 i = 0; i < drawLimit; ++i, ++drawIndex) { - u32 color = CalcFadedColor(0xFFFFFFFF); if (drawIndex + 1 < result.size()) { temp[0] = result[drawIndex]; ConvertUCS2ToUTF8(buffer, temp); - PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, PPGE_ALIGN_HCENTER, 0.5f, color); + PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, textStyle); } else { @@ -794,25 +802,25 @@ void PSPOskDialog::RenderKeyboard() float animStep = (float)(__DisplayGetNumVblanks() % 40) / 20.0f; // Fade in and out the next character so they know it's not part of the string yet. u32 alpha = (0.5f - (cosf(animStep * M_PI) / 2.0f)) * 128 + 127; - color = CalcFadedColor((alpha << 24) | 0xFFFFFF); + PPGeStyle animStyle = textStyle; + animStyle.color = CalcFadedColor((alpha << 24) | 0x00FFFFFF); ConvertUCS2ToUTF8(buffer, temp); - PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, PPGE_ALIGN_HCENTER, 0.5f, color); + PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, animStyle); // Also draw the underline for the same reason. - color = CalcFadedColor(0xFFFFFFFF); - PPGeDrawText("_", previewLeftSide + (i * characterWidth), 40.0f, PPGE_ALIGN_HCENTER, 0.5f, color); + PPGeDrawText("_", previewLeftSide + (i * characterWidth), 40.0f, textStyle); } else { ConvertUCS2ToUTF8(buffer, temp); - PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, PPGE_ALIGN_HCENTER, 0.5f, color); + PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, textStyle); } } else { - PPGeDrawText("_", previewLeftSide + (i * characterWidth), 40.0f, PPGE_ALIGN_HCENTER, 0.5f, color); + PPGeDrawText("_", previewLeftSide + (i * characterWidth), 40.0f, textStyle); } } } @@ -821,17 +829,16 @@ void PSPOskDialog::RenderKeyboard() { for (int col = 0; col < numKeyCols[currentKeyboard]; ++col) { - u32 color = CalcFadedColor(0xFFFFFFFF); - if (selectedRow == row && col == selectedCol) - color = CalcFadedColor(0xFF3060FF); - temp[0] = oskKeys[currentKeyboard][row][col]; ConvertUCS2ToUTF8(buffer, temp); - PPGeDrawText(buffer.c_str(), keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), PPGE_ALIGN_HCENTER, 0.6f, color); - if (selectedRow == row && col == selectedCol) - PPGeDrawText("_", keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), PPGE_ALIGN_HCENTER, 0.6f, CalcFadedColor(0xFFFFFFFF)); + if (selectedRow == row && col == selectedCol) { + PPGeDrawText(buffer.c_str(), keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), selectedKeyStyle); + PPGeDrawText("_", keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), keyStyle); + } else { + PPGeDrawText(buffer.c_str(), keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), keyStyle); + } } } } @@ -944,22 +951,25 @@ int PSPOskDialog::Update(int animSpeed) { auto di = GetI18NCategory("Dialog"); - PPGeDrawImage(ImageID("I_SQUARE"), 365, 222, 16, 16, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(di->T("Space"), 390, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeStyle actionStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f); + PPGeStyle guideStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.6f); + + PPGeDrawImage(ImageID("I_SQUARE"), 365, 222, 16, 16, guideStyle); + PPGeDrawText(di->T("Space"), 390, 222, actionStyle); if (g_Config.iButtonPreference != PSP_SYSTEMPARAM_BUTTON_CIRCLE) { - PPGeDrawImage(ImageID("I_CROSS"), 45, 222, 16, 16, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawImage(ImageID("I_CIRCLE"), 45, 247, 16, 16, 0, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(ImageID("I_CROSS"), 45, 222, 16, 16, guideStyle); + PPGeDrawImage(ImageID("I_CIRCLE"), 45, 247, 16, 16, guideStyle); } else { - PPGeDrawImage(ImageID("I_CIRCLE"), 45, 222, 16, 16, 0, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawImage(ImageID("I_CROSS"), 45, 247, 16, 16, 0, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(ImageID("I_CIRCLE"), 45, 222, 16, 16, guideStyle); + PPGeDrawImage(ImageID("I_CROSS"), 45, 247, 16, 16, guideStyle); } - PPGeDrawText(di->T("Select"), 75, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(di->T("Delete"), 75, 247, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText(di->T("Select"), 75, 222, actionStyle); + PPGeDrawText(di->T("Delete"), 75, 247, actionStyle); - PPGeDrawText("Start", 135, 220, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(di->T("Finish"), 185, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Start", 135, 220, guideStyle); + PPGeDrawText(di->T("Finish"), 185, 222, actionStyle); auto lookupLangName = [&](int direction) { // First, find the valid one... @@ -983,20 +993,20 @@ int PSPOskDialog::Update(int animSpeed) { }; if (OskKeyboardNames[currentKeyboardLanguage] != "ko_KR" && IsKeyboardShiftValid(oskParams->fields[0].inputtype, currentKeyboardLanguage, currentKeyboard)) { - PPGeDrawText("Select", 135, 245, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(di->T("Shift"), 185, 247, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("Select", 135, 245, guideStyle); + PPGeDrawText(di->T("Shift"), 185, 247, actionStyle); } const char *prevLang = lookupLangName(-1); if (prevLang) { - PPGeDrawText("L", 235, 220, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(prevLang, 255, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("L", 235, 220, guideStyle); + PPGeDrawText(prevLang, 255, 222, actionStyle); } const char *nextLang = lookupLangName(1); if (nextLang) { - PPGeDrawText("R", 235, 245, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(nextLang, 255, 247, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawText("R", 235, 245, guideStyle); + PPGeDrawText(nextLang, 255, 247, actionStyle); } if (IsButtonPressed(CTRL_UP) || IsButtonHeld(CTRL_UP, upBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) { @@ -1127,17 +1137,17 @@ void PSPOskDialog::DoState(PointerWrap &p) if (!s) return; - p.Do(oskParams); - p.Do(oskDesc); - p.Do(oskIntext); - p.Do(oskOuttext); - p.Do(selectedChar); + Do(p, oskParams); + Do(p, oskDesc); + Do(p, oskIntext); + Do(p, oskOuttext); + Do(p, selectedChar); if (s >= 2) { - p.Do(inputChars); + Do(p, inputChars); } else { // Discard the wstring. std::wstring wstr; - p.Do(wstr); + Do(p, wstr); } // Don't need to save state native status or value. } diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 4e0de7f909..0266cd0d4a 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -21,14 +21,17 @@ #include -#include "i18n/i18n.h" -#include "thread/threadutil.h" - -#include "Common/ChunkFile.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/StringUtils.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/Util/PPGeDraw.h" #include "Core/HLE/sceCtrl.h" +#include "Core/HLE/sceUtility.h" #include "Core/MemMapHelpers.h" #include "Core/Config.h" #include "Core/Reporting.h" @@ -126,13 +129,21 @@ int PSPSaveDialog::Init(int paramAddr) break; } + if(!param.wouldHasMultiSaveName(param.GetPspParam())) + currentSelectedSave = 0; + switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode) { case SCE_UTILITY_SAVEDATA_TYPE_LOAD: DEBUG_LOG(SCEUTILITY, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); - if (param.GetFileInfo(0).size != 0) - display = DS_LOAD_CONFIRM; - else + if (param.GetFileInfo(0).size != 0) { + if (param.GetFileInfo(0).broken) { + param.GetPspParam()->common.result = SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN; + display = DS_LOAD_FAILED; + } else { + display = DS_LOAD_CONFIRM; + } + } else display = DS_LOAD_NODATA; break; case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: @@ -168,7 +179,7 @@ int PSPSaveDialog::Init(int paramAddr) DEBUG_LOG(SCEUTILITY, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); display = DS_SAVE_LIST_CHOICE; break; - case SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE: + case SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE: DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); if(param.GetFilenameCount() == 0) display = DS_DELETE_NODATA; @@ -179,7 +190,6 @@ int PSPSaveDialog::Init(int paramAddr) case SCE_UTILITY_SAVEDATA_TYPE_LIST: case SCE_UTILITY_SAVEDATA_TYPE_FILES: case SCE_UTILITY_SAVEDATA_TYPE_GETSIZE: - case SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE: case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA: case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: @@ -190,8 +200,26 @@ int PSPSaveDialog::Init(int paramAddr) display = DS_NONE; break; - case SCE_UTILITY_SAVEDATA_TYPE_DELETE: // When run on a PSP, displays a list of all saves on the PSP. Weird. (Not really, it's to let you free up space) - display = DS_DELETE_LIST_CHOICE; + case SCE_UTILITY_SAVEDATA_TYPE_DELETE: + DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + if (param.GetFileInfo(0).size != 0) { + yesnoChoice = 0; + display = DS_DELETE_CONFIRM; + } else + display = DS_DELETE_NODATA; + break; + + case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: + DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + display = DS_NONE; + break; + + case SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE: + DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + if (param.GetFilenameCount() == 0) + display = DS_DELETE_NODATA; + else + display = DS_DELETE_LIST_CHOICE; break; default: { @@ -255,6 +283,8 @@ const std::string PSPSaveDialog::GetSelectedSaveDirName() const case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: case SCE_UTILITY_SAVEDATA_TYPE_SAVE: case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE: + case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: + case SCE_UTILITY_SAVEDATA_TYPE_DELETE: return param.GetSaveDirName(param.GetPspParam()); case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: @@ -268,8 +298,6 @@ const std::string PSPSaveDialog::GetSelectedSaveDirName() const case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: return param.GetSaveDirName(param.GetPspParam()); - // TODO: Maybe also SINGLEDELETE/etc? - // SIZES ignores saveName it seems. default: @@ -282,6 +310,10 @@ void PSPSaveDialog::DisplayBanner(int which) { auto di = GetI18NCategory("Dialog"); PPGeDrawRect(0, 0, 480, 23, CalcFadedColor(0x65636358)); + + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f); + textStyle.hasShadow = false; + const char *title; switch (which) { @@ -299,8 +331,8 @@ void PSPSaveDialog::DisplayBanner(int which) break; } // TODO: Draw a hexagon icon - PPGeDrawImage(10, 6, 12.0f, 12.0f, 1, 10, 1, 10, 10, 10, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(title, 30, 11, PPGE_ALIGN_VCENTER, 0.6f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawImage(10, 6, 12.0f, 12.0f, 1, 10, 1, 10, 10, 10, textStyle.color); + PPGeDrawText(title, 30, 11, textStyle); } void PSPSaveDialog::DisplaySaveList(bool canMove) { @@ -390,76 +422,81 @@ void PSPSaveDialog::DisplaySaveIcon(bool checkExists) PPGeSetDefaultTexture(); } -void PSPSaveDialog::DisplaySaveDataInfo1() -{ +static void FormatSaveHourMin(char *hour_time, size_t sz, const tm &t) { + const char *am_pm = "AM"; + int hour = t.tm_hour; + switch (g_Config.iTimeFormat) { + case 1: + if (hour == 12) { + am_pm = "PM"; + } else if (hour > 12) { + am_pm = "PM"; + hour -= 12; + } else if (hour == 0) { + hour = 12; + } + snprintf(hour_time, sz, "%02d:%02d %s", hour, t.tm_min, am_pm); + break; + case 0: + default: + snprintf(hour_time, sz, "%02d:%02d", hour, t.tm_min); + break; + } +} + +static void FormatSaveDate(char *date, size_t sz, const tm &t) { + int year = t.tm_year + 1900; + int month = t.tm_mon + 1; + switch (g_Config.iDateFormat) { + case 1: + snprintf(date, sz, "%02d/%02d/%04d", month, t.tm_mday, year); + break; + case 2: + snprintf(date, sz, "%02d/%02d/%04d", t.tm_mday, month, year); + break; + case 0: + default: + snprintf(date, sz, "%04d/%02d/%02d", year, month, t.tm_mday); + break; + } +} + +void PSPSaveDialog::DisplaySaveDataInfo1() { std::lock_guard guard(paramLock); - if (param.GetFileInfo(currentSelectedSave).size == 0) { + const SaveFileInfo &saveInfo = param.GetFileInfo(currentSelectedSave); + + if (saveInfo.broken) { auto di = GetI18NCategory("Dialog"); - PPGeDrawText(di->T("NEW DATA"), 180, 136, PPGE_ALIGN_VCENTER, 0.6f, CalcFadedColor(0xFFFFFFFF)); + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f); + PPGeDrawText(di->T("Corrupted Data"), 180, 136, textStyle); + } else if (saveInfo.size == 0) { + auto di = GetI18NCategory("Dialog"); + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f); + PPGeDrawText(di->T("NEW DATA"), 180, 136, textStyle); } else { - char title[512]; - char time[512]; - char saveTitle[1024]; - char saveDetail[1024]; - - char am_pm[] = "AM"; char hour_time[32]; - int hour = param.GetFileInfo(currentSelectedSave).modif_time.tm_hour; - int min = param.GetFileInfo(currentSelectedSave).modif_time.tm_min; - switch (g_Config.iTimeFormat) { - case 1: - if (hour > 12) { - strcpy(am_pm, "PM"); - hour -= 12; - } - snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); - break; - case 2: - snprintf(hour_time, sizeof(hour_time), "%02d:%02d", hour, min); - break; - default: - if (hour > 12) { - strcpy(am_pm, "PM"); - hour -= 12; - } - snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); - } + FormatSaveHourMin(hour_time, sizeof(hour_time), saveInfo.modif_time); - snprintf(title, sizeof(title), "%s", param.GetFileInfo(currentSelectedSave).title); - int day = param.GetFileInfo(currentSelectedSave).modif_time.tm_mday; - int month = param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1; - int year = param.GetFileInfo(currentSelectedSave).modif_time.tm_year + 1900; - s64 sizeK = param.GetFileInfo(currentSelectedSave).size / 1024; - switch (g_Config.iDateFormat) { - case 1: - snprintf(time, sizeof(time), "%d/%02d/%02d %s %lld KB", year, month, day, hour_time, sizeK); - break; - case 2: - snprintf(time, sizeof(time), "%02d/%02d/%d %s %lld KB", month, day, year, hour_time, sizeK); - break; - case 3: - snprintf(time, sizeof(time), "%02d/%02d/%d %s %lld KB", day, month, year, hour_time, sizeK); - break; - default: - snprintf(time, sizeof(time), "%d/%02d/%02d %s %lld KB", year, month, day, hour_time, sizeK); - } - snprintf(saveTitle, sizeof(saveTitle), "%s", param.GetFileInfo(currentSelectedSave).saveTitle); - snprintf(saveDetail, sizeof(saveDetail), "%s", param.GetFileInfo(currentSelectedSave).saveDetail); + char date_year[32]; + FormatSaveDate(date_year, sizeof(date_year), saveInfo.modif_time); + + s64 sizeK = saveInfo.size / 1024; PPGeDrawRect(180, 136, 480, 137, CalcFadedColor(0xFFFFFFFF)); - std::string titleTxt = title; - std::string timeTxt = time; - std::string saveTitleTxt = saveTitle; - std::string saveDetailTxt = saveDetail; + std::string titleTxt = saveInfo.title; + std::string timeTxt = StringFromFormat("%s %s %lld KB", date_year, hour_time, sizeK); + std::string saveTitleTxt = saveInfo.saveTitle; + std::string saveDetailTxt = saveInfo.saveDetail; - PPGeDrawText(titleTxt.c_str(), 181, 138, PPGE_ALIGN_BOTTOM, 0.6f, CalcFadedColor(0x80000000)); - PPGeDrawText(titleTxt.c_str(), 180, 136, PPGE_ALIGN_BOTTOM, 0.6f, CalcFadedColor(0xFFC0C0C0)); - PPGeDrawText(timeTxt.c_str(), 181, 139, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0x80000000)); - PPGeDrawText(timeTxt.c_str(), 180, 137, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawText(saveTitleTxt.c_str(), 176, 162, PPGE_ALIGN_LEFT, 0.55f, CalcFadedColor(0x80000000)); - PPGeDrawText(saveTitleTxt.c_str(), 175, 159, PPGE_ALIGN_LEFT, 0.55f, CalcFadedColor(0xFFFFFFFF)); - PPGeDrawTextWrapped(saveDetailTxt.c_str(), 176, 183, 480 - 175, 250 - 183, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0x80000000)); - PPGeDrawTextWrapped(saveDetailTxt.c_str(), 175, 181, 480 - 175, 250 - 181, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeStyle titleStyle = FadedStyle(PPGeAlign::BOX_BOTTOM, 0.6f); + PPGeStyle saveTitleStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.55f); + titleStyle.color = CalcFadedColor(0xFFC0C0C0); + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f); + + PPGeDrawText(titleTxt.c_str(), 180, 136, titleStyle); + PPGeDrawText(timeTxt.c_str(), 180, 137, textStyle); + PPGeDrawText(saveTitleTxt.c_str(), 175, 159, saveTitleStyle); + PPGeDrawTextWrapped(saveDetailTxt.c_str(), 175, 181, 480 - 175, 250 - 181, textStyle); } } @@ -483,55 +520,23 @@ void PSPSaveDialog::DisplaySaveDataInfo2(bool showNewData) { data_size = param.GetFileInfo(currentSelectedSave).size; } - char date[256]; - char am_pm[] = "AM"; char hour_time[32]; - int hour = modif_time.tm_hour; - int min = modif_time.tm_min; - switch (g_Config.iTimeFormat) { - case 1: - if (hour > 12) { - strcpy(am_pm, "PM"); - hour -= 12; - } - snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); - break; - case 2: - snprintf(hour_time, sizeof(hour_time), "%02d:%02d", hour, min); - break; - default: - if (hour > 12) { - strcpy(am_pm, "PM"); - hour -= 12; - } - snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); - } + FormatSaveHourMin(hour_time, sizeof(hour_time), modif_time); + + char date_year[32]; + FormatSaveDate(date_year, sizeof(date_year), modif_time); - int day = modif_time.tm_mday; - int month = modif_time.tm_mon + 1; - int year = modif_time.tm_year + 1900; s64 sizeK = data_size / 1024; - switch (g_Config.iDateFormat) { - case 1: - snprintf(date, 256, "%d/%02d/%02d", year, month, day); - break; - case 2: - snprintf(date, 256, "%02d/%02d/%d", month, day, year); - break; - case 3: - snprintf(date, 256, "%02d/%02d/%d", day, month, year); - break; - default: - snprintf(date, 256, "%d/%02d/%02d", year, month, day); - } - std::string saveinfoTxt = StringFromFormat("%.128s\n%s %s\n%lld KB", save_title, date, hour_time, sizeK); - PPGeDrawText(saveinfoTxt.c_str(), 9, 202, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0x80000000)); - PPGeDrawText(saveinfoTxt.c_str(), 8, 200, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF)); + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f); + std::string saveinfoTxt = StringFromFormat("%.128s\n%s %s\n%lld KB", save_title, date_year, hour_time, sizeK); + PPGeDrawText(saveinfoTxt.c_str(), 8, 200, textStyle); } void PSPSaveDialog::DisplayMessage(std::string text, bool hasYesNo) { + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_CENTER, FONT_SCALE); + const float WRAP_WIDTH = 254.0f; float y = 136.0f, h; PPGeMeasureText(nullptr, &h, text.c_str(), FONT_SCALE, PPGE_LINE_WRAP_WORD, WRAP_WIDTH); @@ -540,19 +545,14 @@ void PSPSaveDialog::DisplayMessage(std::string text, bool hasYesNo) { auto di = GetI18NCategory("Dialog"); const char *choiceText; - u32 yesColor, noColor; float x, w; if (yesnoChoice == 1) { choiceText = di->T("Yes"); x = 302.0f; - yesColor = 0xFFFFFFFF; - noColor = 0xFFFFFFFF; } else { choiceText = di->T("No"); x = 366.0f; - yesColor = 0xFFFFFFFF; - noColor = 0xFFFFFFFF; } PPGeMeasureText(&w, &h, choiceText, FONT_SCALE); w = w / 2.0f + 5.5f; @@ -561,10 +561,8 @@ void PSPSaveDialog::DisplayMessage(std::string text, bool hasYesNo) h2 += h + 4.0f; y = 132.0f - h; PPGeDrawRect(x - w, y2 - h, x + w, y2 + h, CalcFadedColor(0x40C0C0C0)); - PPGeDrawText(di->T("Yes"), 303.0f, y2+2, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawText(di->T("Yes"), 302.0f, y2, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(yesColor)); - PPGeDrawText(di->T("No"), 367.0f, y2+2, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawText(di->T("No"), 366.0f, y2, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(noColor)); + PPGeDrawText(di->T("Yes"), 302.0f, y2, textStyle); + PPGeDrawText(di->T("No"), 366.0f, y2, textStyle); if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0) { yesnoChoice = 1; } @@ -572,8 +570,7 @@ void PSPSaveDialog::DisplayMessage(std::string text, bool hasYesNo) yesnoChoice = 0; } } - PPGeDrawTextWrapped(text.c_str(), 335.0f, y+2, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0x80000000)); - PPGeDrawTextWrapped(text.c_str(), 334.0f, y, WRAP_WIDTH, 0, PPGE_ALIGN_CENTER, FONT_SCALE, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawTextWrapped(text.c_str(), 334.0f, y, WRAP_WIDTH, 0, textStyle); float sy = 122.0f - h2, ey = 150.0f + h2; PPGeDrawRect(202.0f, sy, 466.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF)); PPGeDrawRect(202.0f, ey, 466.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF)); @@ -822,7 +819,7 @@ int PSPSaveDialog::Update(int animSpeed) DisplaySaveIcon(true); DisplaySaveDataInfo2(); - DisplayMessage(di->T("LoadingFailed", "Unable to load data.")); + DisplayMessage(di->T("LoadingFailed", "Load failed\nThe data is corrupted.")); DisplayButtons(DS_BUTTON_CANCEL); DisplayBanner(DB_LOAD); @@ -832,7 +829,6 @@ int PSPSaveDialog::Update(int animSpeed) if (param.GetPspParam()->mode != SCE_UTILITY_SAVEDATA_TYPE_LOAD) { display = DS_LOAD_LIST_CHOICE; } else { - param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL; StartFade(false); } } @@ -911,15 +907,16 @@ int PSPSaveDialog::Update(int animSpeed) DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL); DisplayBanner(DB_DELETE); - if (IsButtonPressed(cancelButtonFlag)) - display = DS_DELETE_LIST_CHOICE; - else if (IsButtonPressed(okButtonFlag)) { - if (yesnoChoice == 0) + if (IsButtonPressed(cancelButtonFlag) || (IsButtonPressed(okButtonFlag) && yesnoChoice == 0)) { + if(param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE || param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE) display = DS_DELETE_LIST_CHOICE; else { + param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL; + StartFade(false); + } + } else if (IsButtonPressed(okButtonFlag)) { display = DS_DELETE_DELETING; StartIOThread(); - } } EndDraw(); @@ -947,7 +944,10 @@ int PSPSaveDialog::Update(int animSpeed) DisplayBanner(DB_DELETE); if (IsButtonPressed(cancelButtonFlag)) { - display = DS_DELETE_LIST_CHOICE; + if (param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE || param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE) + display = DS_DELETE_LIST_CHOICE; + else + StartFade(false); } EndDraw(); @@ -967,8 +967,14 @@ int PSPSaveDialog::Update(int animSpeed) if (IsButtonPressed(cancelButtonFlag)) { if (param.GetFilenameCount() == 0) display = DS_DELETE_NODATA; - else + else if (param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE || param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE) { + if (currentSelectedSave > param.GetFilenameCount() - 1) + currentSelectedSave = param.GetFilenameCount() - 1; display = DS_DELETE_LIST_CHOICE; + } else { + param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_SUCCESS; + StartFade(false); + } } EndDraw(); @@ -1015,10 +1021,12 @@ int PSPSaveDialog::Update(int animSpeed) } void PSPSaveDialog::ExecuteIOAction() { + auto &result = param.GetPspParam()->common.result; std::lock_guard guard(paramLock); switch (display) { case DS_LOAD_LOADING: - if (param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave) == 0) { + result = param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave); + if (result == 0) { display = DS_LOAD_DONE; } else { display = DS_LOAD_FAILED; @@ -1032,9 +1040,11 @@ void PSPSaveDialog::ExecuteIOAction() { } break; case DS_DELETE_DELETING: - if (param.Delete(param.GetPspParam(),currentSelectedSave)) { + if (param.Delete(param.GetPspParam(), currentSelectedSave)) { + result = 0; display = DS_DELETE_DONE; } else { + //result = SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA;// What the result should be? display = DS_DELETE_FAILED; } break; @@ -1087,10 +1097,14 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() { break; case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: DEBUG_LOG(SCEUTILITY, "sceUtilitySavedata DELETEDATA: %s", param.GetPspParam()->saveName); - result = param.DeleteData(param.GetPspParam()); + if (param.Delete(param.GetPspParam(), param.GetSelectedSave())) { + result = 0; + } else { + result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; + } break; - //case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: - case SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE: + case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: + case SCE_UTILITY_SAVEDATA_TYPE_DELETE: if (param.Delete(param.GetPspParam(), param.GetSelectedSave())) { result = 0; } else { @@ -1111,15 +1125,13 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() { break; case SCE_UTILITY_SAVEDATA_TYPE_READDATA: case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: - if (!param.IsSaveDirectoryExist(param.GetPspParam())){ + result = param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave, param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE); + if(result == SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA) result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; - } else if (!param.IsSfoFileExist(param.GetPspParam())) { - result = SCE_UTILITY_SAVEDATA_ERROR_RW_DATA_BROKEN; - } else if (param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave, param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE) == 0) { - result = 0; - } else { - result = SCE_UTILITY_SAVEDATA_ERROR_RW_FILE_NOT_FOUND; - } + break; + case SCE_UTILITY_SAVEDATA_TYPE_ERASE: + case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE: + result = param.DeleteData(param.GetPspParam()); break; default: break; @@ -1174,20 +1186,20 @@ void PSPSaveDialog::DoState(PointerWrap &p) { return; } - p.Do(display); + Do(p, display); param.DoState(p); - p.Do(request); + Do(p, request); // Just reset it. bool hasParam = param.GetPspParam() != NULL; - p.Do(hasParam); + Do(p, hasParam); if (hasParam) { param.SetPspParam(&request); } - p.Do(requestAddr); - p.Do(currentSelectedSave); - p.Do(yesnoChoice); + Do(p, requestAddr); + Do(p, currentSelectedSave); + Do(p, yesnoChoice); if (s > 2) { - p.Do(ioThreadStatus); + Do(p, ioThreadStatus); } else { ioThreadStatus = SAVEIO_NONE; } diff --git a/Core/Dialog/PSPSaveDialog.h b/Core/Dialog/PSPSaveDialog.h index 888cc63d6e..fd1efa88d5 100644 --- a/Core/Dialog/PSPSaveDialog.h +++ b/Core/Dialog/PSPSaveDialog.h @@ -31,6 +31,7 @@ #define SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN (0x80110306) #define SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA (0x80110307) #define SCE_UTILITY_SAVEDATA_ERROR_LOAD_PARAM (0x80110308) +#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_FILE_NOT_FOUND (0x80110309) #define SCE_UTILITY_SAVEDATA_ERROR_LOAD_INTERNAL (0x8011030b) #define SCE_UTILITY_SAVEDATA_ERROR_RW_NO_MEMSTICK (0x80110321) diff --git a/Core/Dialog/PSPScreenshotDialog.cpp b/Core/Dialog/PSPScreenshotDialog.cpp index cb3abf9a71..acec8d08d4 100644 --- a/Core/Dialog/PSPScreenshotDialog.cpp +++ b/Core/Dialog/PSPScreenshotDialog.cpp @@ -15,7 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Dialog/PSPDialog.h" #include "Core/Dialog/PSPScreenshotDialog.h" #include "Core/HLE/sceKernel.h" @@ -123,8 +124,8 @@ void PSPScreenshotDialog::DoState(PointerWrap &p) { if (!s) return; - p.Do(mode); + Do(p, mode); if (s >= 2) { - p.Do(params_); + Do(p, params_); } } diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 484bb6e910..269eb3a33f 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -15,9 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "i18n/i18n.h" -#include "base/logging.h" -#include "Common/ChunkFile.h" +#include "Common/Log.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Format/ZIMLoad.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Host.h" @@ -33,8 +35,6 @@ #include "Core/HW/MemoryStick.h" #include "Core/Util/PPGeDraw.h" -#include "image/png_load.h" - #include static const std::string ICON0_FILENAME = "ICON0.PNG"; @@ -153,23 +153,23 @@ void SaveFileInfo::DoState(PointerWrap &p) if (!s) return; - p.Do(size); - p.Do(saveName); - p.Do(idx); + Do(p, size); + Do(p, saveName); + Do(p, idx); - p.DoArray(title, sizeof(title)); - p.DoArray(saveTitle, sizeof(saveTitle)); - p.DoArray(saveDetail, sizeof(saveDetail)); + DoArray(p, title, sizeof(title)); + DoArray(p, saveTitle, sizeof(saveTitle)); + DoArray(p, saveDetail, sizeof(saveDetail)); - p.Do(modif_time); + Do(p, modif_time); if (s <= 1) { u32 textureData; int textureWidth; int textureHeight; - p.Do(textureData); - p.Do(textureWidth); - p.Do(textureHeight); + Do(p, textureData); + Do(p, textureWidth); + Do(p, textureHeight); if (textureData != 0) { // Must be MODE_READ. @@ -178,7 +178,7 @@ void SaveFileInfo::DoState(PointerWrap &p) } } else { bool hasTexture = texture != NULL; - p.Do(hasTexture); + Do(p, hasTexture); if (hasTexture) { if (p.mode == p.MODE_READ) { delete texture; @@ -212,7 +212,7 @@ void SavedataParam::Init() if (handle >= 0) { pspFileSystem.CloseFile(handle); } else { - ELOG("Failed to create .nomedia file"); + ERROR_LOG(IO, "Failed to create .nomedia file"); } #endif } @@ -262,7 +262,11 @@ std::string SavedataParam::GetSaveFilePath(const SceUtilitySavedataParam *param, inline static std::string FixedToString(const char *str, size_t n) { - return std::string(str, strnlen(str, n)); + if (!str) { + return std::string(""); + } else { + return std::string(str, strnlen(str, n)); + } } std::string SavedataParam::GetGameName(const SceUtilitySavedataParam *param) const @@ -317,12 +321,12 @@ bool SavedataParam::Delete(SceUtilitySavedataParam* param, int saveId) { } // Sanity check, preventing full delete of savedata/ in MGS PW demo (!) - if (!strlen(param->gameName)) { + if (!strlen(param->gameName) && param->mode != SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE) { ERROR_LOG(SCEUTILITY, "Bad param with gameName empty - cannot delete save directory"); return false; } - std::string dirPath = GetSaveFilePath(param,saveId); + std::string dirPath = GetSaveFilePath(param, GetSaveDir(saveId)); if (dirPath.size() == 0) { ERROR_LOG(SCEUTILITY, "GetSaveFilePath returned empty - cannot delete save directory"); return false; @@ -336,25 +340,39 @@ bool SavedataParam::Delete(SceUtilitySavedataParam* param, int saveId) { return true; } -int SavedataParam::DeleteData(SceUtilitySavedataParam* param) { +int SavedataParam::DeleteData(SceUtilitySavedataParam* param) { if (!param) { - return SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA; - } - if (param->fileName[0] == '\0') { - return SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA; + return SCE_UTILITY_SAVEDATA_ERROR_RW_FILE_NOT_FOUND; } std::string subFolder = GetGameName(param) + GetSaveName(param); - std::string filename = savePath + subFolder + "/" + GetFileName(param); - if (!subFolder.size()) { - ERROR_LOG(SCEUTILITY, "Bad subfolder, ignoring delete of %s", filename.c_str()); + std::string fileName = GetFileName(param); + std::string dirPath = savePath + subFolder; + std::string filePath = dirPath + "/" + fileName; + std::string sfoPath = dirPath + "/" + SFO_FILENAME; + + if (!pspFileSystem.GetFileInfo(dirPath).exists) { + return SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; + } + + if (!pspFileSystem.GetFileInfo(sfoPath).exists) + return SCE_UTILITY_SAVEDATA_ERROR_RW_DATA_BROKEN; + + if (fileName != "" && !pspFileSystem.GetFileInfo(filePath).exists) { + return SCE_UTILITY_SAVEDATA_ERROR_RW_FILE_NOT_FOUND; + } + + if (fileName == "") { return 0; } - PSPFileInfo info = pspFileSystem.GetFileInfo(filename); - if (info.exists) { - pspFileSystem.RemoveFile(filename); + if (!subFolder.size()) { + ERROR_LOG(SCEUTILITY, "Bad subfolder, ignoring delete of %s", filePath.c_str()); + return 0; } + + pspFileSystem.RemoveFile(filePath); + return 0; } @@ -500,7 +518,8 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD if(param->dataBuf.IsValid()) // Can launch save without save data in mode 13 { - std::string filePath = dirPath+"/"+GetFileName(param); + std::string fileName = GetFileName(param); + std::string filePath = dirPath + "/" + fileName; u8 *data_ = 0; SceSize saveSize = 0; if(cryptedData == 0) // Save decrypted data @@ -522,13 +541,16 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD // copy back save name in request strncpy(param->saveName, saveDirName.c_str(), 20); - if (!WritePSPFile(filePath, data_, saveSize)) - { - ERROR_LOG(SCEUTILITY,"Error writing file %s",filePath.c_str()); + if (fileName == "") { delete[] cryptedData; - return SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE; - } - delete[] cryptedData; + } else { + if (!WritePSPFile(filePath, data_, saveSize)) { + ERROR_LOG(SCEUTILITY, "Error writing file %s", filePath.c_str()); + delete[] cryptedData; + return SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE; + } + delete[] cryptedData; + } } @@ -566,15 +588,23 @@ int SavedataParam::Load(SceUtilitySavedataParam *param, const std::string &saveD return SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA; } + bool isRWMode = param->mode == SCE_UTILITY_SAVEDATA_TYPE_READDATA || param->mode == SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE; + std::string dirPath = GetSaveFilePath(param, GetSaveDir(param, saveDirName)); - std::string filePath = dirPath + "/" + GetFileName(param); - if (!pspFileSystem.GetFileInfo(filePath).exists) { - return SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA; + std::string fileName = GetFileName(param); + std::string filePath = dirPath + "/" + fileName; + std::string sfoPath = dirPath + "/" + SFO_FILENAME; + + if (!pspFileSystem.GetFileInfo(dirPath).exists) { + return isRWMode ? SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA : SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA; } - int result = LoadSaveData(param, saveDirName, dirPath, secureMode); - if (result != 0) - return result; + if (!pspFileSystem.GetFileInfo(sfoPath).exists) + return isRWMode ? SCE_UTILITY_SAVEDATA_ERROR_RW_DATA_BROKEN : SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN; + + if (fileName != "" && !pspFileSystem.GetFileInfo(filePath).exists) { + return isRWMode ? SCE_UTILITY_SAVEDATA_ERROR_RW_FILE_NOT_FOUND : SCE_UTILITY_SAVEDATA_ERROR_LOAD_FILE_NOT_FOUND; + } LoadSFO(param, dirPath); // Load sfo @@ -592,6 +622,15 @@ int SavedataParam::Load(SceUtilitySavedataParam *param, const std::string &saveD // Load SND0.AT3 LoadFile(dirPath, SND0_FILENAME, ¶m->snd0FileData); + if (fileName == "") { + // Don't load savedata but return success. + return 0; + } + + int result = LoadSaveData(param, saveDirName, dirPath, secureMode); + if (result != 0) + return result; + return 0; } @@ -1029,8 +1068,9 @@ int SavedataParam::GetSizes(SceUtilitySavedataParam *param) } if (param->msData.IsValid()) { - const std::string gameName(param->msData->gameName, strnlen(param->msData->gameName, sizeof(param->msData->gameName))); - const std::string saveName(param->msData->saveName, strnlen(param->msData->saveName, sizeof(param->msData->saveName))); + const SceUtilitySavedataMsDataInfo *msData = param->msData; + const std::string gameName(msData->gameName, strnlen(msData->gameName, sizeof(msData->gameName))); + const std::string saveName(msData->saveName, strnlen(msData->saveName, sizeof(msData->saveName))); // TODO: How should <> be handled? std::string path = GetSaveFilePath(param, gameName + (saveName == "<>" ? "" : saveName)); PSPFileInfo finfo = pspFileSystem.GetFileInfo(path); @@ -1370,6 +1410,34 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) return 0; } + if (param->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE) { + Clear(); + int realCount = 0; + auto allSaves = pspFileSystem.GetDirListing(savePath); + saveDataListCount = (int)allSaves.size(); + saveDataList = new SaveFileInfo[saveDataListCount]; + for (auto save : allSaves) { + if (save.name == "." || save.name == "..") + continue; + std::string fileDataDir = savePath + save.name; + PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataDir); + auto allFiles = pspFileSystem.GetDirListing(fileDataDir); + bool firstFile = true; + for (auto file : allFiles) { + if (firstFile) { + // Use a file in save directory to determine the directory info. + info = file; + firstFile = false; + } else + info.size += file.size; + } + SetFileInfo(realCount, info, "", save.name); + realCount++; + } + saveNameListDataCount = realCount; + return 0; + } + bool listEmptyFile = true; if (param->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD || param->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE) @@ -1392,7 +1460,7 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) saveDataListCount++; } - if (saveDataListCount > 0) + if (saveDataListCount > 0 && wouldHasMultiSaveName(param)) { hasMultipleFileName = true; saveDataList = new SaveFileInfo[saveDataListCount]; @@ -1435,19 +1503,25 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) const std::string thisSaveName = FixedToString(saveNameListData[i], ARRAY_SIZE(saveNameListData[i])); DEBUG_LOG(SCEUTILITY, "Name : %s", thisSaveName.c_str()); - std::string fileDataPath = savePath + GetGameName(param) + thisSaveName + "/" + GetFileName(param); - PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataPath); - if (info.exists) - { + std::string fileDataDir = savePath + GetGameName(param) + thisSaveName; + PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataDir); + if (info.exists) { + auto allFiles = pspFileSystem.GetDirListing(fileDataDir); + bool firstFile = true; + for (auto file : allFiles) { + if (firstFile) { + // Use a file in save directory to determine the directory info. + info = file; + firstFile = false; + } else + info.size += file.size; + } SetFileInfo(realCount, info, thisSaveName); - DEBUG_LOG(SCEUTILITY,"%s Exist",fileDataPath.c_str()); + DEBUG_LOG(SCEUTILITY,"%s Exist",fileDataDir.c_str()); realCount++; - } - else - { - if (listEmptyFile) - { + } else { + if (listEmptyFile) { ClearFileInfo(saveDataList[realCount], thisSaveName); DEBUG_LOG(SCEUTILITY,"Don't Exist"); realCount++; @@ -1468,13 +1542,23 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) // get and stock file info for each file DEBUG_LOG(SCEUTILITY,"Name : %s",GetSaveName(param).c_str()); - std::string fileDataPath = savePath + GetGameName(param) + GetSaveName(param) + "/" + GetFileName(param); - PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataPath); + std::string fileDataDir = savePath + GetGameName(param) + GetSaveName(param); + PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataDir); if (info.exists) { + auto allFiles = pspFileSystem.GetDirListing(fileDataDir); + bool firstFile = true; + for (auto file : allFiles) { + if (firstFile) { + // Use a file in save directory to determine the directory info. + info = file; + firstFile = false; + } else + info.size += file.size; + } SetFileInfo(0, info, GetSaveName(param)); - DEBUG_LOG(SCEUTILITY,"%s Exist",fileDataPath.c_str()); + DEBUG_LOG(SCEUTILITY,"%s Exist",fileDataDir.c_str()); saveNameListDataCount = 1; } else @@ -1491,13 +1575,16 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) return 0; } -void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std::string saveName) +void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std::string saveName, std::string savrDir) { saveInfo.size = info.size; saveInfo.saveName = saveName; saveInfo.idx = 0; saveInfo.modif_time = info.mtime; + std::string saveDir = savrDir == "" ? GetGameName(pspParam) + saveName : savrDir; + saveInfo.saveDir = saveDir; + // Start with a blank slate. if (saveInfo.texture != NULL) { if (!noSaveIcon || saveInfo.texture != noSaveIcon->texture) { @@ -1511,31 +1598,31 @@ void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std:: // Search save image icon0 // TODO : If icon0 don't exist, need to use icon1 which is a moving icon. Also play sound - std::string fileDataPath2 = savePath + GetGameName(pspParam) + saveName + "/" + ICON0_FILENAME; + std::string fileDataPath2 = savePath + saveDir + "/" + ICON0_FILENAME; PSPFileInfo info2 = pspFileSystem.GetFileInfo(fileDataPath2); if (info2.exists) saveInfo.texture = new PPGeImage(fileDataPath2); // Load info in PARAM.SFO - fileDataPath2 = savePath + GetGameName(pspParam) + saveName + "/" + SFO_FILENAME; + fileDataPath2 = savePath + saveDir + "/" + SFO_FILENAME; info2 = pspFileSystem.GetFileInfo(fileDataPath2); - if (info2.exists) - { + if (info2.exists) { std::vector sfoData; pspFileSystem.ReadEntireFile(fileDataPath2, sfoData); ParamSFOData sfoFile; - if (sfoFile.ReadSFO(sfoData)) - { + if (sfoFile.ReadSFO(sfoData)) { SetStringFromSFO(sfoFile, "TITLE", saveInfo.title, sizeof(saveInfo.title)); SetStringFromSFO(sfoFile, "SAVEDATA_TITLE", saveInfo.saveTitle, sizeof(saveInfo.saveTitle)); SetStringFromSFO(sfoFile, "SAVEDATA_DETAIL", saveInfo.saveDetail, sizeof(saveInfo.saveDetail)); } + } else { + saveInfo.broken = true; } } -void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName) +void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName, std::string saveDir) { - SetFileInfo(saveDataList[idx], info, saveName); + SetFileInfo(saveDataList[idx], info, saveName, saveDir); saveDataList[idx].idx = idx; } @@ -1543,6 +1630,7 @@ void SavedataParam::ClearFileInfo(SaveFileInfo &saveInfo, const std::string &sav saveInfo.size = 0; saveInfo.saveName = saveName; saveInfo.idx = 0; + saveInfo.broken = false; if (saveInfo.texture != NULL) { if (!noSaveIcon || saveInfo.texture != noSaveIcon->texture) { delete saveInfo.texture; @@ -1583,11 +1671,16 @@ const SaveFileInfo& SavedataParam::GetFileInfo(int idx) { return saveDataList[idx]; } + std::string SavedataParam::GetFilename(int idx) const { return saveDataList[idx].saveName; } +std::string SavedataParam::GetSaveDir(int idx) const { + return saveDataList[idx].saveDir; +} + int SavedataParam::GetSelectedSave() { // The slot # of the same save on LOAD/SAVE lists can dismatch so this isn't right anyhow @@ -1718,6 +1811,29 @@ int SavedataParam::GetSaveNameIndex(SceUtilitySavedataParam* param) return 0; } +bool SavedataParam::wouldHasMultiSaveName(SceUtilitySavedataParam* param) { + switch ((SceUtilitySavedataType)(u32)param->mode) { + case SCE_UTILITY_SAVEDATA_TYPE_LOAD: + case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: + case SCE_UTILITY_SAVEDATA_TYPE_SAVE: + case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE: + case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA: + case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_READDATA: + case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA: + case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: + case SCE_UTILITY_SAVEDATA_TYPE_DELETE: + case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE: + case SCE_UTILITY_SAVEDATA_TYPE_ERASE: + case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: + return false; + default: + return true; + } +} + void SavedataParam::DoState(PointerWrap &p) { auto s = p.Section("SavedataParam", 1); @@ -1725,9 +1841,9 @@ void SavedataParam::DoState(PointerWrap &p) return; // pspParam is handled in PSPSaveDialog. - p.Do(selectedSave); - p.Do(saveDataListCount); - p.Do(saveNameListDataCount); + Do(p, selectedSave); + Do(p, saveDataListCount); + Do(p, saveNameListDataCount); if (p.mode == p.MODE_READ) { if (saveDataList != NULL) @@ -1735,13 +1851,13 @@ void SavedataParam::DoState(PointerWrap &p) if (saveDataListCount != 0) { saveDataList = new SaveFileInfo[saveDataListCount]; - p.DoArray(saveDataList, saveDataListCount); + DoArray(p, saveDataList, saveDataListCount); } else saveDataList = NULL; } else - p.DoArray(saveDataList, saveDataListCount); + DoArray(p, saveDataList, saveDataListCount); } int SavedataParam::GetSaveCryptMode(SceUtilitySavedataParam* param, const std::string &saveDirName) diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index e509463712..6e39fd30e1 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -17,6 +17,7 @@ #pragma once +#include #include "Common/CommonTypes.h" #include "Core/MemMap.h" #include "Core/HLE/sceRtc.h" @@ -38,11 +39,11 @@ enum SceUtilitySavedataType SCE_UTILITY_SAVEDATA_TYPE_SAVE = 3, SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD = 4, SCE_UTILITY_SAVEDATA_TYPE_LISTSAVE = 5, - SCE_UTILITY_SAVEDATA_TYPE_DELETE = 6, - SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 7, + SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 6, + SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE = 7,// When run on a PSP, displays a list of all saves on the PSP. Weird. (Not really, it's to let you free up space) SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8, SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE = 9, - SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE = 10, + SCE_UTILITY_SAVEDATA_TYPE_DELETE = 10, SCE_UTILITY_SAVEDATA_TYPE_LIST = 11, SCE_UTILITY_SAVEDATA_TYPE_FILES = 12, SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE = 13, @@ -64,11 +65,11 @@ static const char *const utilitySavedataTypeNames[] = { "SAVE", "LISTLOAD", "LISTSAVE", - "DELETE", "LISTDELETE", + "LISTALLDELETE", "SIZES", "AUTODELETE", - "SINGLEDELETE", + "DELETE", "LIST", "FILES", "MAKEDATASECURE", @@ -272,17 +273,20 @@ struct SaveFileInfo { s64 size; std::string saveName; + std::string saveDir; int idx; char title[128]; char saveTitle[128]; char saveDetail[1024]; + bool broken; + tm modif_time; PPGeImage *texture; - SaveFileInfo() : size(0), saveName(""), idx(0), texture(NULL) + SaveFileInfo() : size(0), saveName(""), idx(0), texture(NULL), broken(false) { memset(title, 0, 128); memset(saveTitle, 0, 128); @@ -338,6 +342,7 @@ public: int GetFilenameCount(); const SaveFileInfo& GetFileInfo(int idx); std::string GetFilename(int idx) const; + std::string GetSaveDir(int idx) const; int GetSelectedSave(); void SetSelectedSave(int idx); @@ -352,12 +357,14 @@ public: int GetLastEmptySave(); int GetSaveNameIndex(SceUtilitySavedataParam* param); + bool wouldHasMultiSaveName(SceUtilitySavedataParam* param); + void DoState(PointerWrap &p); private: void Clear(); - void SetFileInfo(int idx, PSPFileInfo &info, std::string saveName); - void SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std::string saveName); + void SetFileInfo(int idx, PSPFileInfo &info, std::string saveName, std::string saveDir = ""); + void SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std::string saveName, std::string saveDir = ""); void ClearFileInfo(SaveFileInfo &saveInfo, const std::string &saveName); int LoadSaveData(SceUtilitySavedataParam *param, const std::string &saveDirName, const std::string& dirPath, bool secureMode); diff --git a/Core/ELF/PBPReader.cpp b/Core/ELF/PBPReader.cpp index 41653bfcba..de9c4452bd 100644 --- a/Core/ELF/PBPReader.cpp +++ b/Core/ELF/PBPReader.cpp @@ -20,7 +20,7 @@ #include #include "Common/Log.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" #include "Core/Loaders.h" #include "Core/ELF/PBPReader.h" diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index 6c164db355..b12b508942 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -155,7 +155,7 @@ int ParamSFOData::GetDataOffset(const u8 *paramsfo, std::string dataName) { for (u32 i = 0; i < header->index_table_entries; i++) { const char *key = (const char *)(key_start + indexTables[i].key_table_offset); - if(std::string(key) == dataName) + if (!strcmp(key, dataName.c_str())) { return data_start + indexTables[i].data_table_offset; } diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index 940280bac3..aac91f12e7 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -22,6 +22,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/Log.h" class ParamSFOData { @@ -40,7 +41,9 @@ public: std::string GetDiscID() { const std::string discID = GetValueString("DISC_ID"); if (discID.empty()) { - return GenerateFakeID(); + std::string fakeID = GenerateFakeID(); + WARN_LOG(LOADER, "No DiscID found - generating a fake one: %s", fakeID.c_str()); + return fakeID; } return discID; } @@ -67,28 +70,18 @@ private: class ValueData { public: - ValueType type; - int max_size; + ValueType type = VT_INT; + int max_size = 0; std::string s_value; - int i_value; + int i_value = 0; - u8* u_value; - unsigned int u_size; + u8* u_value = nullptr; + unsigned int u_size = 0; void SetData(const u8* data, int size); - ValueData() - { - u_value = 0; - u_size = 0; - type = VT_INT; - max_size = 0; - i_value = 0; - } - - ~ValueData() - { - if(u_value) + ~ValueData() { + if (u_value) delete[] u_value; } }; diff --git a/Core/ELF/PrxDecrypter.cpp b/Core/ELF/PrxDecrypter.cpp index 5e6f6f5f26..bb0088cef5 100644 --- a/Core/ELF/PrxDecrypter.cpp +++ b/Core/ELF/PrxDecrypter.cpp @@ -8,6 +8,7 @@ extern "C" #include "ext/libkirk/SHA1.h" } #include "Common/Common.h" +#include "Common/Log.h" #include "Common/Swap.h" #include "Core/ELF/PrxDecrypter.h" @@ -741,7 +742,7 @@ static int pspDecryptType0(const u8 *inbuf, u8 *outbuf, u32 size) memcpy(reinterpret_cast(header)+sizeof(KIRK_CMD1_HEADER), type0.prxHeader, sizeof(type0.prxHeader)); decryptKirkHeaderType0(reinterpret_cast(header), type0.kirkBlock, xorbuf, pti->code); - if (sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) + if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) { return -4; } @@ -796,7 +797,7 @@ static int pspDecryptType1(const u8 *inbuf, u8 *outbuf, u32 size) memcpy(reinterpret_cast(header)+sizeof(KIRK_CMD1_HEADER), type1.prxHeader, sizeof(type1.prxHeader)); decryptKirkHeaderType0(reinterpret_cast(header), type1.kirkBlock, xorbuf, pti->code); - if (sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) + if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) { return -4; } @@ -860,7 +861,7 @@ static int pspDecryptType2(const u8 *inbuf, u8 *outbuf, u32 size) decryptKirkHeader(reinterpret_cast(header), type2.kirkHeader, xorbuf.cbegin()+0x10, pti->code); header->mode = 1; - if (sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) + if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) { return -4; } @@ -924,7 +925,7 @@ static int pspDecryptType5(const u8 *inbuf, u8 *outbuf, u32 size, const u8 *seed decryptKirkHeader(reinterpret_cast(header), type5.kirkHeader, xorbuf.cbegin()+0x10, pti->code); header->mode = 1; - if (sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) + if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) { return -4; } @@ -991,7 +992,7 @@ static int pspDecryptType6(const u8 *inbuf, u8 *outbuf, u32 size) header->mode = 1; header->ecdsa_hash = 1; - if (sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) + if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0) { return -4; } diff --git a/Core/FileLoaders/CachingFileLoader.cpp b/Core/FileLoaders/CachingFileLoader.cpp index f161574916..c4029d01e5 100644 --- a/Core/FileLoaders/CachingFileLoader.cpp +++ b/Core/FileLoaders/CachingFileLoader.cpp @@ -19,8 +19,8 @@ #include #include -#include "thread/threadutil.h" -#include "base/timeutil.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/TimeUtil.h" #include "Core/FileLoaders/CachingFileLoader.h" // Takes ownership of backend. diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index 62f733dc89..412f409a84 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -15,17 +15,19 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "ppsspp_config.h" + #include #include #include #include #include -#include "ppsspp_config.h" -#include "file/file_util.h" -#include "file/free.h" -#include "util/text/utf8.h" -#include "Common/FileUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/File/DiskFree.h" +#include "Common/File/DirListing.h" +#include "Common/File/FileUtil.h" +#include "Common/Log.h" #include "Common/CommonWindows.h" #include "Core/FileLoaders/DiskCachingFileLoader.h" #include "Core/System.h" @@ -398,7 +400,7 @@ u32 DiskCachingFileLoaderCache::AllocateBlock(u32 indexPos) { } } - _dbg_assert_msg_(LOADER, false, "Not enough free blocks"); + _dbg_assert_msg_(false, "Not enough free blocks"); return INVALID_BLOCK; } diff --git a/Core/FileLoaders/HTTPFileLoader.cpp b/Core/FileLoaders/HTTPFileLoader.cpp index 7d710dbe52..9cf2d653b6 100644 --- a/Core/FileLoaders/HTTPFileLoader.cpp +++ b/Core/FileLoaders/HTTPFileLoader.cpp @@ -17,8 +17,9 @@ #include -#include "base/stringutil.h" #include "Common/Common.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" #include "Core/FileLoaders/HTTPFileLoader.h" HTTPFileLoader::HTTPFileLoader(const std::string &filename) diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index cf3441df9c..d8cb6f3c47 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -20,9 +20,9 @@ #include #include -#include "net/http_client.h" -#include "net/resolve.h" -#include "net/url.h" +#include "Common/Net/HTTPClient.h" +#include "Common/Net/Resolve.h" +#include "Common/Net/URL.h" #include "Common/CommonTypes.h" #include "Core/Loaders.h" diff --git a/Core/FileLoaders/LocalFileLoader.cpp b/Core/FileLoaders/LocalFileLoader.cpp index 8e757b3315..1a6205bfab 100644 --- a/Core/FileLoaders/LocalFileLoader.cpp +++ b/Core/FileLoaders/LocalFileLoader.cpp @@ -18,9 +18,11 @@ #include #include "ppsspp_config.h" -#include "util/text/utf8.h" -#include "file/file_util.h" -#include "Common/FileUtil.h" + +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Log.h" +#include "Common/File/FileUtil.h" +#include "Common/File/DirListing.h" #include "Core/FileLoaders/LocalFileLoader.h" #ifdef _WIN32 diff --git a/Core/FileLoaders/RamCachingFileLoader.cpp b/Core/FileLoaders/RamCachingFileLoader.cpp index bc99ad80f0..73e0151b91 100644 --- a/Core/FileLoaders/RamCachingFileLoader.cpp +++ b/Core/FileLoaders/RamCachingFileLoader.cpp @@ -20,8 +20,8 @@ #include #include -#include "base/timeutil.h" -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/TimeUtil.h" #include "Core/FileLoaders/RamCachingFileLoader.h" #include "Common/Log.h" diff --git a/Core/FileSystems/BlobFileSystem.cpp b/Core/FileSystems/BlobFileSystem.cpp index 0f02bbd821..730dca7854 100644 --- a/Core/FileSystems/BlobFileSystem.cpp +++ b/Core/FileSystems/BlobFileSystem.cpp @@ -108,8 +108,8 @@ int BlobFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 out return -1; } -int BlobFileSystem::DevType(u32 handle) { - return -1; +PSPDevType BlobFileSystem::DevType(u32 handle) { + return PSPDevType::FILE; } bool BlobFileSystem::MkDir(const std::string &dirname) { diff --git a/Core/FileSystems/BlobFileSystem.h b/Core/FileSystems/BlobFileSystem.h index 2a877918d9..3657522ddd 100644 --- a/Core/FileSystems/BlobFileSystem.h +++ b/Core/FileSystems/BlobFileSystem.h @@ -43,8 +43,8 @@ public: PSPFileInfo GetFileInfo(std::string filename) override; bool OwnsHandle(u32 handle) override; int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; - int DevType(u32 handle) override; - int Flags() override { return 0; } + PSPDevType DevType(u32 handle) override; + FileSystemFlags Flags() override { return FileSystemFlags::FLASH; } bool MkDir(const std::string &dirname) override; bool RmDir(const std::string &dirname) override; diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index b8f2b4432b..9d4f85ee6a 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -18,8 +18,10 @@ #include #include #include -#include "i18n/i18n.h" -#include "Common/FileUtil.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/File/FileUtil.h" +#include "Common/Log.h" #include "Common/Swap.h" #include "Core/Loaders.h" #include "Core/Host.h" diff --git a/Core/FileSystems/BlockDevices.h b/Core/FileSystems/BlockDevices.h index 6e17aaa4ea..2db068c777 100644 --- a/Core/FileSystems/BlockDevices.h +++ b/Core/FileSystems/BlockDevices.h @@ -45,6 +45,7 @@ public: } int GetBlockSize() const { return 2048;} // forced, it cannot be changed by subclasses virtual u32 GetNumBlocks() = 0; + virtual bool IsDisc() = 0; u32 CalculateCRC(); void NotifyReadError(); @@ -60,6 +61,7 @@ public: bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) override; bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) override; u32 GetNumBlocks() override { return numBlocks; } + bool IsDisc() override { return true; } private: FileLoader *fileLoader_; @@ -83,6 +85,7 @@ public: bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) override; bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) override; u32 GetNumBlocks() override {return (u32)(filesize_ / GetBlockSize());} + bool IsDisc() override { return true; } private: FileLoader *fileLoader_; @@ -107,6 +110,7 @@ public: bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) override; u32 GetNumBlocks() override {return (u32)lbaSize;} + bool IsDisc() override { return false; } private: FileLoader *fileLoader_; diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index f5bbf8e03b..d6594ee52e 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -19,12 +19,15 @@ #include #include -#include "file/free.h" -#include "file/zip_read.h" -#include "i18n/i18n.h" -#include "util/text/utf8.h" -#include "Common/ChunkFile.h" -#include "Common/FileUtil.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" +#include "Common/File/DiskFree.h" +#include "Common/File/VFS/VFS.h" #include "Core/FileSystems/DirectoryFileSystem.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/HLE/sceKernel.h" @@ -150,7 +153,7 @@ bool FixPathCase(const std::string &basePath, std::string &path, FixPathCaseBeha #endif -DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath, int _flags) : basePath(_basePath), flags(_flags) { +DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath, FileSystemFlags _flags) : basePath(_basePath), flags(_flags) { File::CreateFullPath(basePath); hAlloc = _hAlloc; } @@ -663,8 +666,8 @@ int DirectoryFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u3 return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } -int DirectoryFileSystem::DevType(u32 handle) { - return PSP_DEV_TYPE_FILE; +PSPDevType DirectoryFileSystem::DevType(u32 handle) { + return PSPDevType::FILE; } size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { @@ -742,11 +745,6 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { File::FileDetails details; if (!File::GetFileDetails(fullName, &details)) { ERROR_LOG(FILESYS, "DirectoryFileSystem::GetFileInfo: GetFileDetails failed: %s", fullName.c_str()); - x.size = 0; - x.access = 0; - memset(&x.atime, 0, sizeof(x.atime)); - memset(&x.ctime, 0, sizeof(x.ctime)); - memset(&x.mtime, 0, sizeof(x.mtime)); } else { x.size = details.size; x.access = details.access; @@ -874,7 +872,9 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { entry.size = 4096; else entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32); - entry.name = SimulateVFATBug(ConvertWStringToUTF8(findData.cFileName)); + entry.name = ConvertWStringToUTF8(findData.cFileName); + if (Flags() & FileSystemFlags::SIMULATE_FAT32) + entry.name = SimulateVFATBug(entry.name); bool hideFile = false; if (hideISOFiles && (endsWithNoCase(entry.name, ".cso") || endsWithNoCase(entry.name, ".iso"))) { @@ -921,7 +921,9 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { else entry.type = FILETYPE_NORMAL; entry.access = s.st_mode & 0x1FF; - entry.name = SimulateVFATBug(dirp->d_name); + entry.name = dirp->d_name; + if (Flags() & FileSystemFlags::SIMULATE_FAT32) + entry.name = SimulateVFATBug(entry.name); entry.size = s.st_size; bool hideFile = false; @@ -977,41 +979,41 @@ void DirectoryFileSystem::DoState(PointerWrap &p) { // s64 current truncate position (v2+ only) u32 num = (u32) entries.size(); - p.Do(num); + Do(p, num); if (p.mode == p.MODE_READ) { CloseAll(); u32 key; OpenFileEntry entry; for (u32 i = 0; i < num; i++) { - p.Do(key); - p.Do(entry.guestFilename); - p.Do(entry.access); + Do(p, key); + Do(p, entry.guestFilename); + Do(p, entry.access); u32 err; if (!entry.hFile.Open(basePath,entry.guestFilename,entry.access, err)) { ERROR_LOG(FILESYS, "Failed to reopen file while loading state: %s", entry.guestFilename.c_str()); continue; } u32 position; - p.Do(position); + Do(p, position); if (position != entry.hFile.Seek(position, FILEMOVE_BEGIN)) { ERROR_LOG(FILESYS, "Failed to restore seek position while loading state: %s", entry.guestFilename.c_str()); continue; } if (s >= 2) { - p.Do(entry.hFile.needsTrunc_); + Do(p, entry.hFile.needsTrunc_); } entries[key] = entry; } } else { for (auto iter = entries.begin(); iter != entries.end(); ++iter) { u32 key = iter->first; - p.Do(key); - p.Do(iter->second.guestFilename); - p.Do(iter->second.access); + Do(p, key); + Do(p, iter->second.guestFilename); + Do(p, iter->second.access); u32 position = (u32)iter->second.hFile.Seek(0, FILEMOVE_CURRENT); - p.Do(position); - p.Do(iter->second.hFile.needsTrunc_); + Do(p, position); + Do(p, iter->second.hFile.needsTrunc_); } } } @@ -1090,6 +1092,7 @@ PSPFileInfo VFSFileSystem::GetFileInfo(std::string filename) { if (x.exists) { x.size = fo.size; x.type = fo.isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; + x.access = fo.isWritable ? 0666 : 0444; } } else { x.exists = false; @@ -1117,8 +1120,8 @@ int VFSFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outd return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } -int VFSFileSystem::DevType(u32 handle) { - return PSP_DEV_TYPE_FILE; +PSPDevType VFSFileSystem::DevType(u32 handle) { + return PSPDevType::FILE; } size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { @@ -1186,7 +1189,7 @@ void VFSFileSystem::DoState(PointerWrap &p) { return; u32 num = (u32) entries.size(); - p.Do(num); + Do(p, num); if (num != 0) { p.SetError(p.ERROR_WARNING); diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index e00a4c4946..84e51bbf32 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -20,8 +20,7 @@ // TODO: Remove the Windows-specific code, FILE is fine there too. #include - -#include "../Core/FileSystems/FileSystem.h" +#include "Core/FileSystems/FileSystem.h" #ifdef _WIN32 typedef void * HANDLE; @@ -85,7 +84,7 @@ struct DirectoryFileHandle { class DirectoryFileSystem : public IFileSystem { public: - DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath, int _flags = 0); + DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath, FileSystemFlags _flags = FileSystemFlags::NONE); ~DirectoryFileSystem(); void CloseAll(); @@ -102,14 +101,14 @@ public: PSPFileInfo GetFileInfo(std::string filename) override; bool OwnsHandle(u32 handle) override; int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; - int DevType(u32 handle) override; + PSPDevType DevType(u32 handle) override; bool MkDir(const std::string &dirname) override; bool RmDir(const std::string &dirname) override; int RenameFile(const std::string &from, const std::string &to) override; bool RemoveFile(const std::string &filename) override; bool GetHostPath(const std::string &inpath, std::string &outpath) override; - int Flags() override { return flags; } + FileSystemFlags Flags() override { return flags; } u64 FreeSpace(const std::string &path) override; private: @@ -123,7 +122,7 @@ private: EntryMap entries; std::string basePath; IHandleAllocator *hAlloc; - int flags; + FileSystemFlags flags; // In case of Windows: Translate slashes, etc. std::string GetLocalPath(std::string localpath); }; @@ -147,14 +146,14 @@ public: PSPFileInfo GetFileInfo(std::string filename) override; bool OwnsHandle(u32 handle) override; int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; - int DevType(u32 handle) override; + PSPDevType DevType(u32 handle) override; bool MkDir(const std::string &dirname) override; bool RmDir(const std::string &dirname) override; int RenameFile(const std::string &from, const std::string &to) override; bool RemoveFile(const std::string &filename) override; bool GetHostPath(const std::string &inpath, std::string &outpath) override; - int Flags() override { return 0; } + FileSystemFlags Flags() override { return FileSystemFlags::FLASH; } u64 FreeSpace(const std::string &path) override { return 0; } private: diff --git a/Core/FileSystems/FileSystem.cpp b/Core/FileSystems/FileSystem.cpp index b2130e2eda..40b527f562 100644 --- a/Core/FileSystems/FileSystem.cpp +++ b/Core/FileSystems/FileSystem.cpp @@ -15,7 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/FileSystems/FileSystem.h" void PSPFileInfo::DoState(PointerWrap &p) { @@ -23,17 +24,17 @@ void PSPFileInfo::DoState(PointerWrap &p) { if (!s) return; - p.Do(name); - p.Do(size); - p.Do(access); - p.Do(exists); - p.Do(type); - p.Do(atime); - p.Do(ctime); - p.Do(mtime); - p.Do(isOnSectorSystem); - p.Do(startSector); - p.Do(numSectors); - p.Do(sectorSize); + Do(p, name); + Do(p, size); + Do(p, access); + Do(p, exists); + Do(p, type); + Do(p, atime); + Do(p, ctime); + Do(p, mtime); + Do(p, isOnSectorSystem); + Do(p, startSector); + Do(p, numSectors); + Do(p, sectorSize); } diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 4f87736613..46cd7a6dbc 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -21,6 +21,7 @@ #include #include +#include "Common.h" #include "Core/HLE/sceKernel.h" enum FileAccess { @@ -44,15 +45,24 @@ enum FileType { FILETYPE_DIRECTORY = 2 }; -enum DevType { - PSP_DEV_TYPE_BLOCK = 0x04, - PSP_DEV_TYPE_FILE = 0x10, - PSP_DEV_TYPE_ALIAS = 0x20, +enum class PSPDevType { + INVALID = 0, + BLOCK = 0x04, + FILE = 0x10, + ALIAS = 0x20, + EMU_MASK = 0xFF, + EMU_LBN = 0x10000, }; +ENUM_CLASS_BITOPS(PSPDevType); -enum FileSystemFlags { - FILESYSTEM_SIMULATE_FAT32 = 1, +enum class FileSystemFlags { + NONE = 0, + SIMULATE_FAT32 = 1, + UMD = 2, + CARD = 4, + FLASH = 8, }; +ENUM_CLASS_BITOPS(FileSystemFlags); class IHandleAllocator { public: @@ -78,29 +88,25 @@ private: }; struct PSPFileInfo { - PSPFileInfo() - : size(0), access(0), exists(false), type(FILETYPE_NORMAL), isOnSectorSystem(false), startSector(0), numSectors(0), sectorSize(0) { - memset(&ctime, 0, sizeof(ctime)); - memset(&atime, 0, sizeof(atime)); - memset(&mtime, 0, sizeof(mtime)); + PSPFileInfo() { } void DoState(PointerWrap &p); std::string name; - s64 size; - u32 access; //unix 777 - bool exists; - FileType type; + s64 size = 0; + u32 access = 0; //unix 777 + bool exists = false; + FileType type = FILETYPE_NORMAL; - tm atime; - tm ctime; - tm mtime; + tm atime{}; + tm ctime{}; + tm mtime{}; - bool isOnSectorSystem; - u32 startSector; - u32 numSectors; - u32 sectorSize; + bool isOnSectorSystem = false; + u32 startSector = 0; + u32 numSectors = 0; + u32 sectorSize = 0; }; @@ -125,8 +131,8 @@ public: virtual bool RemoveFile(const std::string &filename) = 0; virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0; virtual int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) = 0; - virtual int DevType(u32 handle) = 0; - virtual int Flags() = 0; + virtual PSPDevType DevType(u32 handle) = 0; + virtual FileSystemFlags Flags() = 0; virtual u64 FreeSpace(const std::string &path) = 0; }; @@ -151,8 +157,8 @@ public: virtual bool RemoveFile(const std::string &filename) override {return false;} virtual bool GetHostPath(const std::string &inpath, std::string &outpath) override {return false;} virtual int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override {return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } - virtual int DevType(u32 handle) override { return 0; } - virtual int Flags() override { return 0; } + virtual PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; } + virtual FileSystemFlags Flags() override { return FileSystemFlags::NONE; } virtual u64 FreeSpace(const std::string &path) override { return 0; } }; diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index 39e54b8bb6..4484ac8110 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -22,7 +22,8 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/HLE/sceKernel.h" #include "Core/MemMap.h" @@ -323,7 +324,7 @@ ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(const std::string &path, bo return entry; } else { if (catchError) - ERROR_LOG(FILESYS,"File %s not found", path.c_str()); + ERROR_LOG(FILESYS, "File '%s' not found", path.c_str()); return 0; } @@ -336,7 +337,7 @@ int ISOFileSystem::OpenFile(std::string filename, FileAccess access, const char entry.isBlockSectorMode = false; if (access & FILEACCESS_WRITE) { - ERROR_LOG(FILESYS, "Can't open file %s with write access on an ISO partition", filename.c_str()); + ERROR_LOG(FILESYS, "Can't open file '%s' with write access on an ISO partition", filename.c_str()); return SCE_KERNEL_ERROR_ERRNO_INVALID_FLAG; } @@ -345,7 +346,7 @@ int ISOFileSystem::OpenFile(std::string filename, FileAccess access, const char u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF; parseLBN(filename, §orStart, &readSize); if (sectorStart > blockDevice->GetNumBlocks()) { - WARN_LOG(FILESYS, "Unable to open raw sector, out of range: %s, sector %08x, max %08x", filename.c_str(), sectorStart, blockDevice->GetNumBlocks()); + WARN_LOG(FILESYS, "Unable to open raw sector, out of range: '%s', sector %08x, max %08x", filename.c_str(), sectorStart, blockDevice->GetNumBlocks()); return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; } else if (sectorStart == blockDevice->GetNumBlocks()) @@ -353,7 +354,7 @@ int ISOFileSystem::OpenFile(std::string filename, FileAccess access, const char ERROR_LOG(FILESYS, "Should not be able to open the block after the last on disc! %08x", sectorStart); } - DEBUG_LOG(FILESYS, "Got a raw sector open: %s, sector %08x, size %08x", filename.c_str(), sectorStart, readSize); + DEBUG_LOG(FILESYS, "Got a raw sector open: '%s', sector %08x, size %08x", filename.c_str(), sectorStart, readSize); u32 newHandle = hAlloc->GetNewHandle(); entry.seekPos = 0; entry.file = 0; @@ -362,16 +363,16 @@ int ISOFileSystem::OpenFile(std::string filename, FileAccess access, const char entry.openSize = readSize; // when open as "umd1:/sce_lbn0x0_size0x6B49D200", that mean open umd1 as a block device. // the param in sceIoLseek and sceIoRead is lba mode. we must mark it. - if (strncmp(devicename, "umd0:", 5)==0 || strncmp(devicename, "umd1:", 5)==0) + if (strncmp(devicename, "umd0:", 5) == 0 || strncmp(devicename, "umd1:", 5) == 0) entry.isBlockSectorMode = true; entries[newHandle] = entry; return newHandle; } - // May return entireISO for "umd0:" - entry.file = GetFromPath(filename); - if (!entry.file){ + // May return entireISO for "umd0:". + entry.file = GetFromPath(filename, false); + if (!entry.file) { return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; } @@ -461,10 +462,18 @@ int ISOFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outd return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } -int ISOFileSystem::DevType(u32 handle) -{ +PSPDevType ISOFileSystem::DevType(u32 handle) { EntryMap::iterator iter = entries.find(handle); - return iter->second.isBlockSectorMode ? PSP_DEV_TYPE_BLOCK : PSP_DEV_TYPE_FILE; + PSPDevType type = iter->second.isBlockSectorMode ? PSPDevType::BLOCK : PSPDevType::FILE; + if (iter->second.isRawSector) + type |= PSPDevType::EMU_LBN; + return type; +} + +FileSystemFlags ISOFileSystem::Flags() { + // TODO: Here may be a good place to force things, in case users recompress games + // as PBP or CSO when they were originally the other type. + return blockDevice->IsDisc() ? FileSystemFlags::UMD : FileSystemFlags::CARD; } size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) @@ -515,7 +524,13 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { if ((s64)e.seekPos + size > fileSize) { // Clamp to the remaining size, but read what we can. const s64 newSize = fileSize - (s64)e.seekPos; - WARN_LOG(FILESYS, "Reading beyond end of file, clamping size %lld to %lld", size, newSize); + // Reading beyond the file is really quite normal behavior (if return value handled correctly), so + // not doing WARN here. Still, can potentially be useful to see so leaving at INFO. + if (newSize == 0) { + INFO_LOG(FILESYS, "Attempted read at end of file, 0-size read simulated"); + } else { + INFO_LOG(FILESYS, "Reading beyond end of file from seekPos %d, clamping size %lld to %lld", e.seekPos, size, newSize); + } size = newSize; } @@ -527,7 +542,9 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { u32 secNum = (u32)(positionOnIso / 2048); u8 theSector[2048]; - _dbg_assert_msg_(FILESYS, (middleSize & 2047) == 0, "Remaining size should be aligned"); + if ((middleSize & 2047) != 0) { + ERROR_LOG(FILESYS, "Remaining size should be aligned"); + } const u8 *const start = pointer; if (firstBlockSize > 0) { @@ -607,7 +624,9 @@ PSPFileInfo ISOFileSystem::GetFileInfo(std::string filename) { PSPFileInfo fileInfo; fileInfo.name = filename; fileInfo.exists = true; + fileInfo.type = FILETYPE_NORMAL; fileInfo.size = readSize; + fileInfo.access = 0444; fileInfo.startSector = sectorStart; fileInfo.isOnSectorSystem = true; fileInfo.numSectors = (readSize + sectorSize - 1) / sectorSize; @@ -616,12 +635,10 @@ PSPFileInfo ISOFileSystem::GetFileInfo(std::string filename) { TreeEntry *entry = GetFromPath(filename, false); PSPFileInfo x; - if (!entry) { - x.size = 0; - x.exists = false; - } else { + if (entry) { x.name = entry->name; - x.access = FILEACCESS_READ; + // Strangely, it seems to be executable even for files. + x.access = 0555; x.size = entry->size; x.exists = true; x.type = entry->isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; @@ -649,16 +666,14 @@ std::vector ISOFileSystem::GetDirListing(std::string path) { PSPFileInfo x; x.name = e->name; - x.access = FILEACCESS_READ; + // Strangely, it seems to be executable even for files. + x.access = 0555; x.size = e->size; x.type = e->isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; x.isOnSectorSystem = true; x.startSector = e->startingPosition/2048; x.sectorSize = sectorSize; x.numSectors = (u32)((e->size + sectorSize - 1) / sectorSize); - memset(&x.atime, 0, sizeof(x.atime)); - memset(&x.mtime, 0, sizeof(x.mtime)); - memset(&x.ctime, 0, sizeof(x.ctime)); myVector.push_back(x); } return myVector; @@ -702,7 +717,7 @@ void ISOFileSystem::DoState(PointerWrap &p) { return; int n = (int) entries.size(); - p.Do(n); + Do(p, n); if (p.mode == p.MODE_READ) { entries.clear(); @@ -710,18 +725,18 @@ void ISOFileSystem::DoState(PointerWrap &p) { u32 fd = 0; OpenFileEntry of; - p.Do(fd); - p.Do(of.seekPos); - p.Do(of.isRawSector); - p.Do(of.isBlockSectorMode); - p.Do(of.sectorStart); - p.Do(of.openSize); + Do(p, fd); + Do(p, of.seekPos); + Do(p, of.isRawSector); + Do(p, of.isBlockSectorMode); + Do(p, of.sectorStart); + Do(p, of.openSize); bool hasFile = false; - p.Do(hasFile); + Do(p, hasFile); if (hasFile) { std::string path; - p.Do(path); + Do(p, path); of.file = GetFromPath(path); } else { of.file = NULL; @@ -732,24 +747,24 @@ void ISOFileSystem::DoState(PointerWrap &p) { } else { for (EntryMap::iterator it = entries.begin(), end = entries.end(); it != end; ++it) { OpenFileEntry &of = it->second; - p.Do(it->first); - p.Do(of.seekPos); - p.Do(of.isRawSector); - p.Do(of.isBlockSectorMode); - p.Do(of.sectorStart); - p.Do(of.openSize); + Do(p, it->first); + Do(p, of.seekPos); + Do(p, of.isRawSector); + Do(p, of.isBlockSectorMode); + Do(p, of.sectorStart); + Do(p, of.openSize); bool hasFile = of.file != NULL; - p.Do(hasFile); + Do(p, hasFile); if (hasFile) { std::string path = EntryFullPath(of.file); - p.Do(path); + Do(p, path); } } } if (s >= 2) { - p.Do(lastReadBlock_); + Do(p, lastReadBlock_); } else { lastReadBlock_ = 0; } diff --git a/Core/FileSystems/ISOFileSystem.h b/Core/FileSystems/ISOFileSystem.h index 34b24bb081..273d845301 100644 --- a/Core/FileSystems/ISOFileSystem.h +++ b/Core/FileSystems/ISOFileSystem.h @@ -41,8 +41,8 @@ public: PSPFileInfo GetFileInfo(std::string filename) override; bool OwnsHandle(u32 handle) override; int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; - int DevType(u32 handle) override; - int Flags() override { return 0; } + PSPDevType DevType(u32 handle) override; + FileSystemFlags Flags() override; u64 FreeSpace(const std::string &path) override { return 0; } size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override; @@ -134,10 +134,10 @@ public: int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override { return isoFileSystem_->Ioctl(handle, cmd, indataPtr, inlen, outdataPtr, outlen, usec); } - int DevType(u32 handle) override { + PSPDevType DevType(u32 handle) override { return isoFileSystem_->DevType(handle); } - int Flags() override { return isoFileSystem_->Flags(); } + FileSystemFlags Flags() override { return isoFileSystem_->Flags(); } u64 FreeSpace(const std::string &path) override { return isoFileSystem_->FreeSpace(path); } size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override { diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 19bddf251e..31f7bf5689 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -18,7 +18,9 @@ #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Common/StringUtils.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/HLE/sceKernelThread.h" @@ -178,7 +180,7 @@ IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle) int MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath, MountPoint **system) { - int error = -1; + int error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; std::lock_guard guard(lock); std::string realpath; @@ -246,6 +248,8 @@ int MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath return error == SCE_KERNEL_ERROR_NOCWD ? error : 0; } } + + error = SCE_KERNEL_ERROR_NODEV; } DEBUG_LOG(FILESYS, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str()); @@ -256,8 +260,8 @@ std::string MetaFileSystem::NormalizePrefix(std::string prefix) const { // Let's apply some mapping here since it won't break savestates. if (prefix == "memstick:") prefix = "ms0:"; - // Seems like umd00: etc. work just fine... - if (startsWith(prefix, "umd")) + // Seems like umd00: etc. work just fine... avoid umd1/umd for tests. + if (startsWith(prefix, "umd") && prefix != "umd1:" && prefix != "umd:") prefix = "umd0:"; // Seems like umd00: etc. work just fine... if (startsWith(prefix, "host")) @@ -353,7 +357,7 @@ int MetaFileSystem::OpenFile(std::string filename, FileAccess access, const char if (error == 0) return mount->system->OpenFile(of, access, mount->prefix.c_str()); else - return error == -1 ? SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND : error; + return error; } PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) @@ -368,7 +372,7 @@ PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) } else { - PSPFileInfo bogus; // TODO + PSPFileInfo bogus; return bogus; } } @@ -536,13 +540,13 @@ int MetaFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 out return SCE_KERNEL_ERROR_ERROR; } -int MetaFileSystem::DevType(u32 handle) +PSPDevType MetaFileSystem::DevType(u32 handle) { std::lock_guard guard(lock); IFileSystem *sys = GetHandleOwner(handle); if (sys) return sys->DevType(handle); - return SCE_KERNEL_ERROR_ERROR; + return PSPDevType::INVALID; } void MetaFileSystem::CloseFile(u32 handle) @@ -639,13 +643,13 @@ void MetaFileSystem::DoState(PointerWrap &p) if (!s) return; - p.Do(current); + Do(p, current); // Save/load per-thread current directory map - p.Do(currentDir); + Do(p, currentDir); u32 n = (u32) fileSystems.size(); - p.Do(n); + Do(p, n); bool skipPfat0 = false; if (n != (u32) fileSystems.size()) { diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index c4bfd8d37f..8294ba16da 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -56,6 +56,10 @@ public: IFileSystem *GetSystem(const std::string &prefix); IFileSystem *GetSystemFromFilename(const std::string &filename); + FileSystemFlags FlagsFromFilename(const std::string &filename) { + IFileSystem *sys = GetSystemFromFilename(filename); + return sys ? sys->Flags() : FileSystemFlags::NONE; + } void ThreadEnded(int threadID); @@ -114,8 +118,8 @@ public: int RenameFile(const std::string &from, const std::string &to) override; bool RemoveFile(const std::string &filename) override; int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; - int DevType(u32 handle) override; - int Flags() override { return 0; } + PSPDevType DevType(u32 handle) override; + FileSystemFlags Flags() override { return FileSystemFlags::NONE; } u64 FreeSpace(const std::string &path) override; // Convenience helper - returns < 0 on failure. diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index 7ff3dc07ed..fde9808d8c 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -17,15 +17,15 @@ #include "ppsspp_config.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" #include "Common/StringUtils.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/FileSystems/VirtualDiscFileSystem.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/HLE/sceKernel.h" #include "Core/Reporting.h" -#include "file/zip_read.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #ifdef _WIN32 #include "Common/CommonWindows.h" @@ -167,18 +167,18 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p) int fileListSize = (int)fileList.size(); int entryCount = (int)entries.size(); - p.Do(fileListSize); - p.Do(entryCount); - p.Do(currentBlockIndex); + Do(p, fileListSize); + Do(p, entryCount); + Do(p, currentBlockIndex); FileListEntry dummy = {""}; fileList.resize(fileListSize, dummy); for (int i = 0; i < fileListSize; i++) { - p.Do(fileList[i].fileName); - p.Do(fileList[i].firstBlock); - p.Do(fileList[i].totalSize); + Do(p, fileList[i].fileName); + Do(p, fileList[i].firstBlock); + Do(p, fileList[i].totalSize); } if (p.mode == p.MODE_READ) @@ -190,12 +190,12 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p) u32 fd = 0; OpenFileEntry of; - p.Do(fd); - p.Do(of.fileIndex); - p.Do(of.type); - p.Do(of.curOffset); - p.Do(of.startOffset); - p.Do(of.size); + Do(p, fd); + Do(p, of.fileIndex); + Do(p, of.type); + Do(p, of.curOffset); + Do(p, of.startOffset); + Do(p, of.size); // open file if (of.type != VFILETYPE_ISO) { @@ -222,17 +222,17 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p) { OpenFileEntry &of = it->second; - p.Do(it->first); - p.Do(of.fileIndex); - p.Do(of.type); - p.Do(of.curOffset); - p.Do(of.startOffset); - p.Do(of.size); + Do(p, it->first); + Do(p, of.fileIndex); + Do(p, of.type); + Do(p, of.curOffset); + Do(p, of.startOffset); + Do(p, of.size); } } if (s >= 2) { - p.Do(lastReadBlock_); + Do(p, lastReadBlock_); } else { lastReadBlock_ = 0; } @@ -552,9 +552,12 @@ int VirtualDiscFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } -int VirtualDiscFileSystem::DevType(u32 handle) { +PSPDevType VirtualDiscFileSystem::DevType(u32 handle) { EntryMap::iterator iter = entries.find(handle); - return iter->second.type == VFILETYPE_ISO ? PSP_DEV_TYPE_BLOCK : PSP_DEV_TYPE_FILE; + PSPDevType type = iter->second.type == VFILETYPE_ISO ? PSPDevType::BLOCK : PSPDevType::FILE; + if (iter->second.type == VFILETYPE_LBN) + type |= PSPDevType::EMU_LBN; + return type; } PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { @@ -569,7 +572,9 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { PSPFileInfo fileInfo; fileInfo.name = filename; fileInfo.exists = true; + fileInfo.type = FILETYPE_NORMAL; fileInfo.size = readSize; + fileInfo.access = 0444; fileInfo.startSector = sectorStart; fileInfo.isOnSectorSystem = true; fileInfo.numSectors = (readSize + 2047) / 2048; @@ -581,6 +586,7 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { x.type = FILETYPE_NORMAL; x.isOnSectorSystem = true; x.startSector = fileList[fileIndex].firstBlock; + x.access = 0555; HandlerFileHandle temp = fileList[fileIndex].handler; if (temp.Open(basePath, filename, FILEACCESS_READ)) { @@ -609,6 +615,7 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; x.exists = true; + x.access = 0555; if (fileIndex != -1) { x.isOnSectorSystem = true; x.startSector = fileList[fileIndex].firstBlock; @@ -620,12 +627,8 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { ERROR_LOG(FILESYS, "DirectoryFileSystem::GetFileInfo: GetFileDetails failed: %s", fullName.c_str()); x.size = 0; x.access = 0; - memset(&x.atime, 0, sizeof(x.atime)); - memset(&x.ctime, 0, sizeof(x.ctime)); - memset(&x.mtime, 0, sizeof(x.mtime)); } else { x.size = details.size; - x.access = details.access; time_t atime = details.atime; time_t ctime = details.ctime; time_t mtime = details.mtime; @@ -690,7 +693,7 @@ std::vector VirtualDiscFileSystem::GetDirListing(std::string path) entry.type = FILETYPE_NORMAL; } - entry.access = FILEACCESS_READ; + entry.access = 0555; entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32); entry.name = ConvertWStringToUTF8(findData.cFileName); tmFromFiletime(entry.atime, findData.ftLastAccessTime); @@ -736,7 +739,7 @@ std::vector VirtualDiscFileSystem::GetDirListing(std::string path) entry.type = FILETYPE_DIRECTORY; else entry.type = FILETYPE_NORMAL; - entry.access = s.st_mode & 0x1FF; + entry.access = 0555; entry.name = dirp->d_name; entry.size = s.st_size; localtime_r((time_t*)&s.st_atime,&entry.atime); diff --git a/Core/FileSystems/VirtualDiscFileSystem.h b/Core/FileSystems/VirtualDiscFileSystem.h index b4ad72924b..cdf6a54ccd 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.h +++ b/Core/FileSystems/VirtualDiscFileSystem.h @@ -38,10 +38,10 @@ public: PSPFileInfo GetFileInfo(std::string filename) override; bool OwnsHandle(u32 handle) override; int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; - int DevType(u32 handle) override; + PSPDevType DevType(u32 handle) override; bool GetHostPath(const std::string &inpath, std::string &outpath) override; std::vector GetDirListing(std::string path) override; - int Flags() override { return 0; } + FileSystemFlags Flags() override { return FileSystemFlags::UMD; } u64 FreeSpace(const std::string &path) override { return 0; } // unsupported operations diff --git a/Core/FileSystems/tlzrc.cpp b/Core/FileSystems/tlzrc.cpp index 851e1c12e6..414fec0032 100644 --- a/Core/FileSystems/tlzrc.cpp +++ b/Core/FileSystems/tlzrc.cpp @@ -23,7 +23,8 @@ #include #include -#include "Common.h" +#include "Common/Common.h" +#include "Common/Log.h" /*************************************************************/ @@ -63,7 +64,7 @@ typedef struct{ static u8 rc_getbyte(LZRC_DECODE *rc) { if(rc->in_ptr == rc->in_len){ - _dbg_assert_msg_(LOADER, false, "LZRC: End of input!"); + _dbg_assert_msg_(false, "LZRC: End of input!"); } return rc->input[rc->in_ptr++]; @@ -72,7 +73,7 @@ static u8 rc_getbyte(LZRC_DECODE *rc) static void rc_putbyte(LZRC_DECODE *rc, u8 byte) { if(rc->out_ptr == rc->out_len){ - _dbg_assert_msg_(LOADER, false, "LZRC: Output overflow!"); + _dbg_assert_msg_(false, "LZRC: Output overflow!"); } rc->output[rc->out_ptr++] = byte; diff --git a/Core/Font/PGF.cpp b/Core/Font/PGF.cpp index 9113498425..ae3afa57b8 100644 --- a/Core/Font/PGF.cpp +++ b/Core/Font/PGF.cpp @@ -21,7 +21,8 @@ // Some parts, especially in this file, were simply copied, so I guess this really makes this file GPL3. #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/MemMap.h" #include "Core/Reporting.h" #include "Core/Font/PGF.h" @@ -37,7 +38,7 @@ static bool isJPCSPFont(const char *fontName) { // Gets a number of bits from an offset. static int getBits(int numBits, const u8 *buf, size_t pos) { - _dbg_assert_msg_(SCEFONT, numBits <= 32, "Unable to return more than 32 bits, %d requested", numBits); + _dbg_assert_msg_(numBits <= 32, "Unable to return more than 32 bits, %d requested", numBits); const size_t wordpos = pos >> 5; const u32 *wordbuf = (const u32 *)buf; @@ -128,12 +129,12 @@ void PGF::DoState(PointerWrap &p) { if (!s) return; - p.Do(header); - p.Do(rev3extra); + Do(p, header); + Do(p, rev3extra); // Don't savestate size_t directly, 32-bit and 64-bit are different. u32 fontDataSizeTemp = (u32)fontDataSize; - p.Do(fontDataSizeTemp); + Do(p, fontDataSizeTemp); fontDataSize = (size_t)fontDataSizeTemp; if (p.mode == p.MODE_READ) { if (fontData) { @@ -141,39 +142,39 @@ void PGF::DoState(PointerWrap &p) { } if (fontDataSize) { fontData = new u8[fontDataSize]; - p.DoArray(fontData, (int)fontDataSize); + DoArray(p, fontData, (int)fontDataSize); } } else if (fontDataSize) { - p.DoArray(fontData, (int)fontDataSize); + DoArray(p, fontData, (int)fontDataSize); } - p.Do(fileName); + Do(p, fileName); - p.DoArray(dimensionTable, ARRAY_SIZE(dimensionTable)); - p.DoArray(xAdjustTable, ARRAY_SIZE(xAdjustTable)); - p.DoArray(yAdjustTable, ARRAY_SIZE(yAdjustTable)); - p.DoArray(advanceTable, ARRAY_SIZE(advanceTable)); - p.DoArray(charmapCompressionTable1, ARRAY_SIZE(charmapCompressionTable1)); - p.DoArray(charmapCompressionTable2, ARRAY_SIZE(charmapCompressionTable2)); + DoArray(p, dimensionTable, ARRAY_SIZE(dimensionTable)); + DoArray(p, xAdjustTable, ARRAY_SIZE(xAdjustTable)); + DoArray(p, yAdjustTable, ARRAY_SIZE(yAdjustTable)); + DoArray(p, advanceTable, ARRAY_SIZE(advanceTable)); + DoArray(p, charmapCompressionTable1, ARRAY_SIZE(charmapCompressionTable1)); + DoArray(p, charmapCompressionTable2, ARRAY_SIZE(charmapCompressionTable2)); - p.Do(charmap_compr); - p.Do(charmap); + Do(p, charmap_compr); + Do(p, charmap); if (s == 1) { std::vector oldGlyphs; - p.Do(oldGlyphs); + Do(p, oldGlyphs); glyphs.resize(oldGlyphs.size()); for (size_t i = 0; i < oldGlyphs.size(); ++i) { glyphs[i] = oldGlyphs[i]; } - p.Do(oldGlyphs); + Do(p, oldGlyphs); shadowGlyphs.resize(oldGlyphs.size()); for (size_t i = 0; i < oldGlyphs.size(); ++i) { shadowGlyphs[i] = oldGlyphs[i]; } } else { - p.Do(glyphs); - p.Do(shadowGlyphs); + Do(p, glyphs); + Do(p, shadowGlyphs); } - p.Do(firstGlyph); + Do(p, firstGlyph); } bool PGF::ReadPtr(const u8 *ptr, size_t dataSize) { diff --git a/Core/Font/PGF.h b/Core/Font/PGF.h index 7b721726d4..a4e3f420d8 100644 --- a/Core/Font/PGF.h +++ b/Core/Font/PGF.h @@ -22,7 +22,6 @@ #include #include -#include "Common/Log.h" #include "Common/CommonTypes.h" class PointerWrap; diff --git a/Core/HDRemaster.cpp b/Core/HDRemaster.cpp index 33a9798279..d3d0ff16b9 100644 --- a/Core/HDRemaster.cpp +++ b/Core/HDRemaster.cpp @@ -15,7 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/basictypes.h" +#include "Common.h" #include "Core/HDRemaster.h" bool g_RemasterMode; diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index a19c170800..eb4575fea6 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -20,17 +20,17 @@ #include #include -#include "base/logging.h" -#include "base/timeutil.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Log.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" +#include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/Host.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" - -#include "Core/Core.h" -#include "Core/Host.h" #include "Core/System.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSCodeUtils.h" @@ -112,7 +112,7 @@ void hleDelayResultFinish(u64 userdata, int cycleslate) __KernelReSchedule("woke from hle delay"); } else - WARN_LOG(HLE, "Someone else woke up HLE-blocked thread?"); + WARN_LOG(HLE, "Someone else woke up HLE-blocked thread %d?", threadID); } void HLEInit() { @@ -128,19 +128,19 @@ void HLEDoState(PointerWrap &p) { // Can't be inside a syscall, reset this so errors aren't misleading. latestSyscall = nullptr; - p.Do(delayedResultEvent); + Do(p, delayedResultEvent); CoreTiming::RestoreRegisterEvent(delayedResultEvent, "HLEDelayedResult", hleDelayResultFinish); if (s >= 2) { int actions = (int)mipsCallActions.size(); - p.Do(actions); + Do(p, actions); if (actions != (int)mipsCallActions.size()) { mipsCallActions.resize(actions); } for (auto &action : mipsCallActions) { int actionTypeID = action != nullptr ? action->actionTypeID : -1; - p.Do(actionTypeID); + Do(p, actionTypeID); if (actionTypeID != -1) { if (p.mode == p.MODE_READ) action = __KernelCreateAction(actionTypeID); @@ -215,7 +215,7 @@ const HLEFunction *GetFunc(const char *moduleName, u32 nib) const char *GetFuncName(const char *moduleName, u32 nib) { - _dbg_assert_msg_(HLE, moduleName != NULL, "Invalid module name."); + _dbg_assert_msg_(moduleName != nullptr, "Invalid module name."); const HLEFunction *func = GetFunc(moduleName,nib); if (func) @@ -314,7 +314,7 @@ void hleCheckCurrentCallbacks() void hleReSchedule(const char *reason) { #ifdef _DEBUG - _dbg_assert_msg_(HLE, reason != nullptr && strlen(reason) < 256, "hleReSchedule: Invalid or too long reason."); + _dbg_assert_msg_(reason != nullptr && strlen(reason) < 256, "hleReSchedule: Invalid or too long reason."); #endif hleAfterSyscall |= HLE_AFTER_RESCHED; @@ -469,7 +469,7 @@ void HLEReturnFromMipsCall() { if ((stackData->nextOff & 0x0000000F) != 0 || !Memory::IsValidAddress(sp + stackData->nextOff)) { ERROR_LOG(HLE, "Corrupt stack on HLE mips call return: %08x", stackData->nextOff); - Core_UpdateState(CORE_ERROR); + Core_UpdateState(CORE_RUNTIME_ERROR); return; } @@ -482,9 +482,10 @@ void HLEReturnFromMipsCall() { while ((finalMarker->nextOff & 0x0000000F) == 0 && Memory::IsValidAddress(finalMarker.ptr + finalMarker->nextOff)) { finalMarker.ptr += finalMarker->nextOff; } + if (finalMarker->nextOff != 0xFFFFFFFF) { ERROR_LOG(HLE, "Corrupt stack on HLE mips call return action: %08x", finalMarker->nextOff); - Core_UpdateState(CORE_ERROR); + Core_UpdateState(CORE_RUNTIME_ERROR); return; } @@ -704,7 +705,6 @@ void CallSyscall(MIPSOpcode op) PROFILE_THIS_SCOPE("syscall"); double start = 0.0; // need to initialize to fix the race condition where coreCollectDebugStats is enabled in the middle of this func. if (coreCollectDebugStats) { - time_update(); start = time_now_d(); } @@ -728,7 +728,6 @@ void CallSyscall(MIPSOpcode op) } if (coreCollectDebugStats) { - time_update(); u32 callno = (op >> 6) & 0xFFFFF; //20 bits int funcnum = callno & 0xFFF; int modulenum = (callno & 0xFF000) >> 12; @@ -819,7 +818,7 @@ size_t hleFormatLogArgs(char *message, size_t sz, const char *argmask) { // TODO: Double? Does it ever happen? default: - _dbg_assert_msg_(HLE, false, "Invalid argmask character: %c", argmask[i]); + _dbg_assert_msg_(false, "Invalid argmask character: %c", argmask[i]); APPEND_FMT(" -- invalid arg format: %c -- %08x", argmask[i], regval); break; } @@ -843,7 +842,7 @@ void hleDoLogInternal(LogTypes::LOG_TYPE t, LogTypes::LOG_LEVELS level, u64 res, const char *funcName = "?"; u32 funcFlags = 0; if (latestSyscall) { - _dbg_assert_(HLE, latestSyscall->argmask != nullptr); + _dbg_assert_(latestSyscall->argmask != nullptr); hleFormatLogArgs(formatted_args, sizeof(formatted_args), latestSyscall->argmask); // This acts as an override (for error returns which are usually hex.) @@ -865,7 +864,7 @@ void hleDoLogInternal(LogTypes::LOG_TYPE t, LogTypes::LOG_LEVELS level, u64 res, // TODO: For now, floats are just shown as bits. fmt = "%s%08x=%s(%s)%s"; } else { - _dbg_assert_msg_(HLE, false, "Invalid return format: %c", retmask); + _dbg_assert_msg_(false, "Invalid return format: %c", retmask); fmt = "%s%08llx=%s(%s)%s"; } @@ -874,7 +873,7 @@ void hleDoLogInternal(LogTypes::LOG_TYPE t, LogTypes::LOG_LEVELS level, u64 res, if (reportTag != nullptr) { // A blank string means always log, not just once. - if (reportTag[0] == '\0' || Reporting::ShouldLogOnce(reportTag)) { + if (reportTag[0] == '\0' || Reporting::ShouldLogNTimes(reportTag, 1)) { // Here we want the original key, so that different args, etc. group together. std::string key = std::string(kernelFlag) + std::string("%08x=") + funcName + "(%s)"; if (reason != nullptr) diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 9fa4c16451..7a89618015 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -17,8 +17,10 @@ #pragma once +#include #include #include + #include "Common/CommonTypes.h" #include "Common/Log.h" #include "Core/MIPS/MIPS.h" diff --git a/Core/HLE/HLEHelperThread.cpp b/Core/HLE/HLEHelperThread.cpp index 36f9166813..a142820b92 100644 --- a/Core/HLE/HLEHelperThread.cpp +++ b/Core/HLE/HLEHelperThread.cpp @@ -15,7 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/HLE/HLE.h" @@ -73,8 +74,8 @@ void HLEHelperThread::DoState(PointerWrap &p) { return; } - p.Do(id_); - p.Do(entry_); + Do(p, id_); + Do(p, entry_); } void HLEHelperThread::Start(u32 a0, u32 a1) { diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index b4f0636f77..562fdbf931 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -158,7 +158,7 @@ const HLEFunction LoadCoreForKernel[] = {0XAE7C6E76, nullptr, "sceKernelRegisterModule", '?', "" }, {0X74CF001A, nullptr, "sceKernelReleaseModule", '?', "" }, {0XFB8AE27D, nullptr, "sceKernelFindModuleByAddress", '?', "" }, - {0XCCE4A157, nullptr, "sceKernelFindModuleByUID", '?', "" }, + {0XCCE4A157, &WrapU_U, "sceKernelFindModuleByUID", 'x', "x" , HLE_KERNEL_SYSCALL }, {0X82CE54ED, nullptr, "sceKernelModuleCount", '?', "" }, {0XC0584F0C, nullptr, "sceKernelGetModuleList", '?', "" }, {0XCF8A41B1, &WrapU_C, "sceKernelFindModuleByName", 'x', "s", HLE_KERNEL_SYSCALL }, @@ -302,7 +302,8 @@ void RegisterAllModules() { Register_KUBridge(); Register_sceUsbAcc(); Register_sceUsbMic(); - + Register_sceOpenPSID_driver(); + Register_semaphore(); // add new modules here. } diff --git a/Core/HLE/Plugins.cpp b/Core/HLE/Plugins.cpp new file mode 100644 index 0000000000..95e6c0efa5 --- /dev/null +++ b/Core/HLE/Plugins.cpp @@ -0,0 +1,214 @@ +// Copyright (c) 2020- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include + +#include "Common/Data/Format/IniFile.h" +#include "Common/File/FileUtil.h" +#include "Common/File/DirListing.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Core/Config.h" +#include "Core/MemMap.h" +#include "Core/System.h" +#include "Core/ELF/ParamSFO.h" +#include "Core/HLE/Plugins.h" +#include "Core/HLE/sceKernelModule.h" + +namespace HLEPlugins { + +static bool anyEnabled = false; +static std::vector prxPlugins; + +enum class PluginType { + INVALID = 0, + PRX, +}; + +struct PluginInfo { + PluginType type; + std::string filename; + int version; + uint32_t memory; +}; + +static PluginInfo ReadPluginIni(const std::string &subdir, IniFile &ini) { + PluginInfo info; + + auto options = ini.GetOrCreateSection("options"); + std::string value; + + if (options->Get("type", &value, "")) { + if (value == "prx") { + info.type = PluginType::PRX; + } + } + + if (options->Get("filename", &value, "")) { + info.filename = "ms0:/PSP/PLUGINS/" + subdir + "/" + value; + } else { + info.type = PluginType::INVALID; + } + + options->Get("version", &info.version, 0); + options->Get("memory", &info.memory, 0); + if (info.memory > 93) { + ERROR_LOG(SYSTEM, "Plugin memory too high, using 93 MB"); + info.memory = 93; + } + + if (info.version == 0) { + ERROR_LOG(SYSTEM, "Plugin without version ignored: %s", subdir.c_str()); + info.type = PluginType::INVALID; + info.memory = 0; + } else if (info.type == PluginType::INVALID && !info.filename.empty()) { + ERROR_LOG(SYSTEM, "Plugin without valid type: %s", subdir.c_str()); + } + + return info; +} + +static std::vector FindPlugins(const std::string &gameID, const std::string &lang) { + std::vector pluginDirs; + getFilesInDir(GetSysDirectory(DIRECTORY_PLUGINS).c_str(), &pluginDirs); + + std::vector found; + for (auto subdir : pluginDirs) { + if (!subdir.isDirectory || !File::Exists(subdir.fullName + "/plugin.ini")) + continue; + + IniFile ini; + if (!ini.Load(subdir.fullName + "/plugin.ini")) { + ERROR_LOG(SYSTEM, "Failed to load plugin ini: %s/plugin.ini", subdir.fullName.c_str()); + continue; + } + + std::set matches; + + std::string gameIni; + if (ini.GetOrCreateSection("games")->Get("ALL", &gameIni, "")) { + if (!strcasecmp(gameIni.c_str(), "true")) { + matches.insert("plugin.ini"); + } else if (!gameIni.empty()) { + matches.insert(gameIni); + } + } + + if (ini.GetOrCreateSection("games")->Get(gameID.c_str(), &gameIni, "")) { + if (!strcasecmp(gameIni.c_str(), "true")) { + matches.insert("plugin.ini"); + } else if (!gameIni.empty()) { + matches.insert(gameIni); + } + } + + std::set langMatches; + for (const std::string &subini : matches) { + if (!ini.Load(subdir.fullName + "/" + subini)) { + ERROR_LOG(SYSTEM, "Failed to load plugin ini: %s/%s", subdir.fullName.c_str(), subini.c_str()); + continue; + } + + found.push_back(ReadPluginIni(subdir.name, ini)); + + if (ini.GetOrCreateSection("lang")->Get(lang.c_str(), &gameIni, "")) { + if (!gameIni.empty() && matches.find(gameIni) == matches.end()) { + langMatches.insert(gameIni); + } + } + } + + for (const std::string &subini : langMatches) { + if (!ini.Load(subdir.fullName + "/" + subini)) { + ERROR_LOG(SYSTEM, "Failed to load plugin ini: %s/%s", subdir.fullName.c_str(), subini.c_str()); + continue; + } + + found.push_back(ReadPluginIni(subdir.name, ini)); + } + } + + return found; +} + +void Init() { + if (!g_Config.bLoadPlugins) { + return; + } + + std::vector plugins = FindPlugins(g_paramSFO.GetDiscID(), g_Config.sLanguageIni); + for (auto &plugin : plugins) { + if (plugin.memory << 20 > Memory::g_MemorySize) { + Memory::g_MemorySize = plugin.memory << 20; + anyEnabled = true; + } + + if (plugin.type == PluginType::PRX) { + prxPlugins.push_back(plugin.filename); + anyEnabled = true; + } + } +} + +bool Load() { + bool started = false; + for (const std::string &filename : prxPlugins) { + std::string error_string = ""; + SceUID module = KernelLoadModule(filename, &error_string); + if (!error_string.empty()) { + ERROR_LOG(SYSTEM, "Unable to load plugin %s: %s", filename.c_str(), error_string.c_str()); + continue; + } + if (module < 0) { + ERROR_LOG(SYSTEM, "Unable to load plugin %s: %08x", filename.c_str(), module); + continue; + } + + int ret = KernelStartModule(module, 0, 0, 0, nullptr, nullptr); + if (ret < 0) { + ERROR_LOG(SYSTEM, "Unable to start plugin %s: %08x", filename.c_str(), ret); + } + + INFO_LOG(SYSTEM, "Loaded plugin: %s", filename.c_str()); + started = true; + } + + return started; +} + +void Unload() { + // Nothing to do here, for now. +} + +void Shutdown() { + prxPlugins.clear(); + anyEnabled = false; +} + +void DoState(PointerWrap &p) { + auto s = p.Section("Plugins", 0, 1); + if (!s) + return; + + // Remember if any were enabled. + Do(p, anyEnabled); +} + +bool HasEnabled() { + return anyEnabled; +} + +}; diff --git a/Core/HLE/Plugins.h b/Core/HLE/Plugins.h new file mode 100644 index 0000000000..6db2966d98 --- /dev/null +++ b/Core/HLE/Plugins.h @@ -0,0 +1,34 @@ +// Copyright (c) 2020- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +class PointerWrap; + +namespace HLEPlugins { + +void Init(); +void Shutdown(); + +bool Load(); +void Unload(); + +void DoState(PointerWrap &p); + +bool HasEnabled(); + +}; diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index a1d9e25e5c..16b8ca7fe8 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -19,8 +19,7 @@ #include #include -#include "base/basictypes.h" -#include "base/logging.h" +#include "Common/Common.h" #include "Common/Log.h" #include "Core/Config.h" #include "Core/Debugger/Breakpoints.h" diff --git a/Core/HLE/ThreadQueueList.h b/Core/HLE/ThreadQueueList.h index 9111fff41d..72282e2a3f 100644 --- a/Core/HLE/ThreadQueueList.h +++ b/Core/HLE/ThreadQueueList.h @@ -18,7 +18,7 @@ #pragma once #include "Core/HLE/sceKernel.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" struct ThreadQueueList { // Number of queues (number of priority levels starting at 0.) @@ -82,7 +82,7 @@ struct ThreadQueueList { cur = cur->next; } - _dbg_assert_msg_(SCEKERNEL, false, "ThreadQueueList should not be empty."); + _dbg_assert_msg_(false, "ThreadQueueList should not be empty."); return 0; } @@ -127,7 +127,7 @@ struct ThreadQueueList { inline void remove(u32 priority, const SceUID threadID) { Queue *cur = &queues[priority]; - _dbg_assert_msg_(SCEKERNEL, cur->next != nullptr, "ThreadQueueList::Queue should already be linked up."); + _dbg_assert_msg_(cur->next != nullptr, "ThreadQueueList::Queue should already be linked up."); for (int i = cur->first; i < cur->end; ++i) { if (cur->data[i] == threadID) { @@ -148,7 +148,7 @@ struct ThreadQueueList { inline void rotate(u32 priority) { Queue *cur = &queues[priority]; - _dbg_assert_msg_(SCEKERNEL, cur->next != nullptr, "ThreadQueueList::Queue should already be linked up."); + _dbg_assert_msg_(cur->next != nullptr, "ThreadQueueList::Queue should already be linked up."); if (cur->size() > 1) { // Grab the front and push it on the end. @@ -184,7 +184,7 @@ struct ThreadQueueList { return; int numQueues = NUM_QUEUES; - p.Do(numQueues); + Do(p, numQueues); if (numQueues != NUM_QUEUES) { p.SetError(p.ERROR_FAILURE); ERROR_LOG(SCEKERNEL, "Savestate loading error: invalid data"); @@ -197,9 +197,9 @@ struct ThreadQueueList { for (int i = 0; i < NUM_QUEUES; ++i) { Queue *cur = &queues[i]; int size = cur->size(); - p.Do(size); + Do(p, size); int capacity = cur->capacity; - p.Do(capacity); + Do(p, capacity); if (capacity == 0) continue; @@ -211,7 +211,7 @@ struct ThreadQueueList { } if (size != 0) - p.DoArray(&cur->data[cur->first], size); + DoArray(p, &cur->data[cur->first], size); } } @@ -222,7 +222,7 @@ private: // Initialize a priority level and link to other queues. void link(u32 priority, int size) { - _dbg_assert_msg_(SCEKERNEL, queues[priority].data == nullptr, "ThreadQueueList::Queue should only be initialized once."); + _dbg_assert_msg_(queues[priority].data == nullptr, "ThreadQueueList::Queue should only be initialized once."); // Make sure we stay a multiple of INITIAL_CAPACITY. if (size <= INITIAL_CAPACITY) diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index e462a94efd..1f722d11d1 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -19,8 +19,9 @@ #include #include "Common/CommonTypes.h" -#include "Common/ChunkFile.h" -#include "Common/FixedSizeQueue.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Data/Collections/FixedSizeQueue.h" #ifdef _M_SSE #include @@ -51,6 +52,10 @@ StereoResampler resampler; // atomic locks are used on the lock. TODO: make this lock-free std::atomic_flag atomicLock_; +// We copy samples as they are written into this simple ring buffer. +// Might try something more efficient later. +FixedSizeQueue chanSampleQueues[PSP_AUDIO_CHANNEL_MAX + 1]; + int eventAudioUpdate = -1; int eventHostAudioUpdate = -1; int mixFrequency = 44100; @@ -114,8 +119,10 @@ void __AudioInit() { CoreTiming::ScheduleEvent(audioIntervalCycles, eventAudioUpdate, 0); CoreTiming::ScheduleEvent(audioHostIntervalCycles, eventHostAudioUpdate, 0); - for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) + for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) { + chans[i].index = i; chans[i].clear(); + } mixBuffer = new s32[hwBlockSize * 2]; clampedMixBuffer = new s16[hwBlockSize * 2]; @@ -130,14 +137,14 @@ void __AudioDoState(PointerWrap &p) { if (!s) return; - p.Do(eventAudioUpdate); + Do(p, eventAudioUpdate); CoreTiming::RestoreRegisterEvent(eventAudioUpdate, "AudioUpdate", &hleAudioUpdate); - p.Do(eventHostAudioUpdate); + Do(p, eventHostAudioUpdate); CoreTiming::RestoreRegisterEvent(eventHostAudioUpdate, "AudioUpdateHost", &hleHostAudioUpdate); - p.Do(mixFrequency); + Do(p, mixFrequency); if (s >= 2) { - p.Do(srcFrequency); + Do(p, srcFrequency); } else { // Assume that it was actually the SRC channel frequency. srcFrequency = mixFrequency; @@ -156,15 +163,17 @@ void __AudioDoState(PointerWrap &p) { } int chanCount = ARRAY_SIZE(chans); - p.Do(chanCount); + Do(p, chanCount); if (chanCount != ARRAY_SIZE(chans)) { ERROR_LOG(SCEAUDIO, "Savestate failure: different number of audio channels."); p.SetError(p.ERROR_FAILURE); return; } - for (int i = 0; i < chanCount; ++i) + for (int i = 0; i < chanCount; ++i) { + chans[i].index = i; chans[i].DoState(p); + } __AudioCPUMHzChange(); } @@ -174,8 +183,10 @@ void __AudioShutdown() { delete [] clampedMixBuffer; mixBuffer = 0; - for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) + for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) { + chans[i].index = i; chans[i].clear(); + } #ifndef MOBILE_DEVICE if (g_Config.bDumpAudio) { @@ -195,11 +206,11 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) { } // If there's anything on the queue at all, it should be busy, but we try to be a bit lax. - //if (chan.sampleQueue.size() > chan.sampleCount * 2 * chanQueueMaxSizeFactor || chan.sampleAddress == 0) { - if (chan.sampleQueue.size() > 0) { + //if (chanSampleQueues[chanNum].size() > chan.sampleCount * 2 * chanQueueMaxSizeFactor || chan.sampleAddress == 0) { + if (chanSampleQueues[chanNum].size() > 0) { if (blocking) { // TODO: Regular multichannel audio seems to block for 64 samples less? Or enqueue the first 64 sync? - int blockSamples = (int)chan.sampleQueue.size() / 2 / chanQueueMinSizeFactor; + int blockSamples = (int)chanSampleQueues[chanNum].size() / 2 / chanQueueMinSizeFactor; if (__KernelIsDispatchEnabled()) { AudioChannelWaitInfo waitInfo = {__KernelGetCurThread(), blockSamples}; @@ -234,7 +245,7 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) { const u32 totalSamples = chan.sampleCount * (chan.format == PSP_AUDIO_FORMAT_STEREO ? 2 : 1); s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; - chan.sampleQueue.pushPointers(totalSamples, &buf1, &sz1, &buf2, &sz2); + chanSampleQueues[chanNum].pushPointers(totalSamples, &buf1, &sz1, &buf2, &sz2); if (Memory::IsValidAddress(chan.sampleAddress + (totalSamples - 1) * sizeof(s16_le))) { Memory::Memcpy(buf1, chan.sampleAddress, (u32)sz1 * sizeof(s16)); @@ -256,7 +267,7 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) { if (Memory::IsValidAddress(chan.sampleAddress + (totalSamples - 1) * sizeof(s16_le))) { s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; - chan.sampleQueue.pushPointers(totalSamples, &buf1, &sz1, &buf2, &sz2); + chanSampleQueues[chanNum].pushPointers(totalSamples, &buf1, &sz1, &buf2, &sz2); AdjustVolumeBlock(buf1, sampleData, sz1, leftVol, rightVol); if (buf2) { AdjustVolumeBlock(buf2, sampleData + sz1, sz2, leftVol, rightVol); @@ -266,8 +277,8 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) { // Rare, so unoptimized. Expands to stereo. for (u32 i = 0; i < chan.sampleCount; i++) { s16 sample = (s16)Memory::Read_U16(chan.sampleAddress + 2 * i); - chan.sampleQueue.push(ApplySampleVolume(sample, leftVol)); - chan.sampleQueue.push(ApplySampleVolume(sample, rightVol)); + chanSampleQueues[chanNum].push(ApplySampleVolume(sample, leftVol)); + chanSampleQueues[chanNum].push(ApplySampleVolume(sample, rightVol)); } } } @@ -334,20 +345,20 @@ void __AudioUpdate(bool resetRecording) { __AudioWakeThreads(chans[i], 0, hwBlockSize); - if (!chans[i].sampleQueue.size()) { + if (!chanSampleQueues[i].size()) { continue; } bool needsResample = i == PSP_AUDIO_CHANNEL_SRC && srcFrequency != 0 && srcFrequency != mixFrequency; size_t sz = needsResample ? (hwBlockSize * 2 * srcFrequency) / mixFrequency : hwBlockSize * 2; - if (sz > chans[i].sampleQueue.size()) { - ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chans[i].sampleQueue.size() / 2, (int)sz / 2); + if (sz > chanSampleQueues[i].size()) { + ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chanSampleQueues[i].size() / 2, (int)sz / 2); } const s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; - chans[i].sampleQueue.popPointers(sz, &buf1, &sz1, &buf2, &sz2); + chanSampleQueues[i].popPointers(sz, &buf1, &sz1, &buf2, &sz2); if (needsResample) { auto read = [&](size_t i) { diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index d248c89e88..425bb63413 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -21,48 +21,70 @@ // This is a direct port of Coldbird's code from http://code.google.com/p/aemu/ // All credit goes to him! -#if !defined(_MSC_VER) -//#include +#if !defined(_WIN32) #include +#include +#include +#include +#include +#include +#endif + +#ifndef MSG_NOSIGNAL +// Default value to 0x00 (do nothing) in systems where it's not supported. +#define MSG_NOSIGNAL 0x00 #endif #include -#include "util/text/parsers.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Text/Parsers.h" + +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/TimeUtil.h" #include "Core/Core.h" #include "Core/Host.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelMemory.h" +#include "Core/HLE/sceNetAdhoc.h" +#include "Core/Instance.h" #include "proAdhoc.h" -#include "i18n/i18n.h" -uint16_t portOffset = g_Config.iPortOffset; +uint16_t portOffset; +uint32_t minSocketTimeoutUS; uint32_t fakePoolSize = 0; -bool isLocalServer = false; -uint8_t PPSSPP_ID = 0; -sockaddr localIP; SceNetAdhocMatchingContext * contexts = NULL; int one = 1; bool friendFinderRunning = false; SceNetAdhocctlPeerInfo * friends = NULL; SceNetAdhocctlScanInfo * networks = NULL; SceNetAdhocctlScanInfo * newnetworks = NULL; -int threadStatus = ADHOCCTL_STATE_DISCONNECTED; +u64 adhocctlStartTime = 0; +int adhocctlState = ADHOCCTL_STATE_DISCONNECTED; +int adhocctlCurrentMode = ADHOCCTL_MODE_NONE; +int adhocConnectionType = ADHOC_CONNECT; -bool IsAdhocctlInCB = false; +int gameModeSocket = (int)INVALID_SOCKET; // UDP/PDP socket? on Master only? +u8* gameModeBuffer = nullptr; +GameModeArea masterGameModeArea; +std::vector replicaGameModeAreas; +std::vector requiredGameModeMacs; +std::vector gameModeMacs; + +int actionAfterAdhocMipsCall; int actionAfterMatchingMipsCall; // Broadcast MAC uint8_t broadcastMAC[ETHER_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -int metasocket; +int metasocket = (int)INVALID_SOCKET; SceNetAdhocctlParameter parameter; SceNetAdhocctlAdhocId product_code; std::thread friendFinderThread; std::recursive_mutex peerlock; -SceNetAdhocPdpStat * pdp[255]; -SceNetAdhocPtpStat * ptp[255]; -uint32_t localip; +AdhocSocket* adhocSockets[MAX_SOCKET]; std::vector chatLog; std::string name = ""; std::string incoming = ""; @@ -70,46 +92,81 @@ std::string message = ""; bool chatScreenVisible = false; bool updateChatScreen = false; int newChat = 0; +bool isOriPort = false; +bool isLocalServer = false; +SockAddrIN4 g_adhocServerIP; +SockAddrIN4 g_localhostIP; +sockaddr LocalIP; +int defaultWlanChannel = PSP_SYSTEMPARAM_ADHOC_CHANNEL_11; // Don't put 0(Auto) here, it needed to be a valid/actual channel number -int isLocalMAC(const SceNetEtherAddr * addr) { +bool isMacMatch(const SceNetEtherAddr* addr1, const SceNetEtherAddr* addr2) { + // Ignoring the 1st byte since there are games (ie. Gran Turismo) who tamper with the 1st byte of OUI to change the unicast/multicast bit + return (memcmp(((const char*)addr1)+1, ((const char*)addr2)+1, ETHER_ADDR_LEN-1) == 0); +} + +bool isLocalMAC(const SceNetEtherAddr * addr) { SceNetEtherAddr saddr; getLocalMac(&saddr); - // Compare MAC Addresses - int match = memcmp((const void *)addr, (const void *)&saddr, ETHER_ADDR_LEN); - - // Return Result - return (match == 0); + return isMacMatch(addr, &saddr); } -int isPDPPortInUse(uint16_t port) { +bool isPDPPortInUse(uint16_t port) { // Iterate Elements - int i = 0; for (; i < 255; i++) if (pdp[i] != NULL && pdp[i]->lport == port) return 1; - + for (int i = 0; i < MAX_SOCKET; i++) { + auto sock = adhocSockets[i]; + if (sock != NULL && sock->type == SOCK_PDP) + if (sock->data.pdp.lport == port) + return true; + } // Unused Port - return 0; + return false; } -int isPTPPortInUse(uint16_t port) { +bool isPTPPortInUse(uint16_t port) { // Iterate Sockets - int i = 0; for(; i < 255; i++) if(ptp[i] != NULL && ptp[i]->lport == port) return 1; - + for (int i = 0; i < MAX_SOCKET; i++) { + auto sock = adhocSockets[i]; + if (sock != NULL && sock->type == SOCK_PTP) + if (sock->data.ptp.lport == port) + return true; + } // Unused Port - return 0; + return false; +} + +std::string mac2str(SceNetEtherAddr* mac) { + char str[18] = ":::::"; + + if (mac != NULL) { + snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); + } + + return std::string(str); } SceNetAdhocMatchingMemberInternal* addMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac) { if (context == NULL || mac == NULL) return NULL; SceNetAdhocMatchingMemberInternal * peer = findPeer(context, mac); + // Already existed + if (peer != NULL) { + WARN_LOG(SCENET, "Member Peer Already Existed! Updating [%s]", mac2str(mac).c_str()); + peer->state = 0; + peer->sending = 0; + peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); + } // Member is not added yet - if (peer == NULL) { + else { peer = (SceNetAdhocMatchingMemberInternal *)malloc(sizeof(SceNetAdhocMatchingMemberInternal)); if (peer != NULL) { memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal)); peer->mac = *mac; + peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); + peerlock.lock(); peer->next = context->peerlist; context->peerlist = peer; + peerlock.unlock(); } } return peer; @@ -124,14 +181,15 @@ void addFriend(SceNetAdhocctlConnectPacketS2C * packet) { SceNetAdhocctlPeerInfo * peer = findFriend(&packet->mac); // Already existed if (peer != NULL) { + u32 tmpip = packet->ip; + WARN_LOG(SCENET, "Friend Peer Already Existed! Updating [%s][%s][%s]", mac2str(&packet->mac).c_str(), inet_ntoa(*(struct in_addr*)&tmpip), packet->name.data); //inet_ntoa(*(in_addr*)&packet->ip) peer->nickname = packet->name; peer->mac_addr = packet->mac; peer->ip_addr = packet->ip; // Update TimeStamp peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); } - else - { + else { // Allocate Structure peer = (SceNetAdhocctlPeerInfo *)malloc(sizeof(SceNetAdhocctlPeerInfo)); // Allocated Structure @@ -168,18 +226,57 @@ SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC) { // Iterate Friends for (; peer != NULL; peer = peer->next) { - if (IsMatch(peer->mac_addr, *MAC)) break; + if (isMacMatch(&peer->mac_addr, MAC)) break; } // Return found friend return peer; } +SceNetAdhocctlPeerInfo* findFriendByIP(uint32_t ip) { + // Friends Reference + SceNetAdhocctlPeerInfo* peer = friends; + + // Iterate Friends + for (; peer != NULL; peer = peer->next) { + if (peer->ip_addr == ip) break; + } + + // Return found friend + return peer; +} + +int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode, int timeoutUS) { + fd_set readfds, writefds; + timeval tval; + + // Avoid getting Fatal signal 6 (SIGABRT) on linux/android + if (fd < 0) + return SOCKET_ERROR; + + FD_ZERO(&readfds); + writefds = readfds; + if (readfd) { + FD_SET(fd, &readfds); + } + if (writefd) { + FD_SET(fd, &writefds); + } + tval.tv_sec = timeoutUS / 1000000; + tval.tv_usec = timeoutUS % 1000000; + + int ret = select(fd + 1, readfd? &readfds: nullptr, writefd? &writefds: nullptr, nullptr, &tval); + if (errorcode != nullptr) + *errorcode = errno; + + return ret; +} + void changeBlockingMode(int fd, int nonblocking) { unsigned long on = 1; unsigned long off = 0; -#ifdef _WIN32 - if (nonblocking){ +#if defined(_WIN32) + if (nonblocking) { // Change to Non-Blocking Mode ioctlsocket(fd, FIONBIO, &on); } @@ -187,18 +284,35 @@ void changeBlockingMode(int fd, int nonblocking) { // Change to Blocking Mode ioctlsocket(fd, FIONBIO, &off); } +// If they have O_NONBLOCK, use the POSIX way to do it. On POSIX sockets Error code would be EINPROGRESS instead of EAGAIN +//#elif defined(O_NONBLOCK) #else - if(nonblocking == 1) fcntl(fd, F_SETFL, O_NONBLOCK); + int flags = fcntl(fd, F_GETFL, 0); + // Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. + if (flags == -1) + flags = 0; + if (nonblocking) { + // Set Non-Blocking Flag + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } else { - // Get Flags - int flags = fcntl(fd, F_GETFL); // Remove Non-Blocking Flag fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } +// Otherwise, use the old way of doing it (UNIX way). On UNIX sockets Error code would be EAGAIN instead of EINPROGRESS +/*#else + if (nonblocking) { + // Change to Non - Blocking Mode + ioctl(fd, FIONBIO, (char*)&on); + } + else { + // Change to Blocking Mode + ioctl(fd, FIONBIO, (char*)&off); + }*/ #endif } -int countAvailableNetworks(void) { +int countAvailableNetworks() { // Network Count int count = 0; @@ -220,7 +334,7 @@ SceNetAdhocctlScanInfo * findGroup(SceNetEtherAddr * MAC) { // Iterate Groups for (; group != NULL; group = group->next) { - if (IsMatch(group->bssid.mac_addr, *MAC)) break; + if (isMacMatch(&group->bssid.mac_addr, MAC)) break; } // Return found group @@ -236,40 +350,54 @@ void freeGroupsRecursive(SceNetAdhocctlScanInfo * node) { // Free Memory free(node); + node = NULL; } -void deleteAllPDP(void) { +void deleteAllAdhocSockets() { // Iterate Element - int i = 0; for (; i < 255; i++) { + for (int i = 0; i < MAX_SOCKET; i++) { // Active Socket - if (pdp[i] != NULL) { - // Close Socket - closesocket(pdp[i]->id); + if (adhocSockets[i] != NULL) { + auto sock = adhocSockets[i]; + int fd = -1; + if (sock->type == SOCK_PTP) + fd = sock->data.ptp.id; + else if (sock->type == SOCK_PDP) + fd = sock->data.pdp.id; + + if (fd > 0) { + // Close Socket + shutdown(fd, SD_BOTH); + closesocket(fd); + } // Free Memory - free(pdp[i]); + free(adhocSockets[i]); // Delete Reference - pdp[i] = NULL; + adhocSockets[i] = NULL; } } } -void deleteAllPTP(void) { - // Iterate Element - int i = 0; for (; i < 255; i++) { - // Active Socket - if (ptp[i] != NULL) { - // Close Socket - closesocket(ptp[i]->id); - - // Free Memory - free(ptp[i]); - - // Delete Reference - ptp[i] = NULL; +void deleteAllGMB() { + if (gameModeBuffer) { + free(gameModeBuffer); + gameModeBuffer = nullptr; + } + if (masterGameModeArea.data) { + free(masterGameModeArea.data); + masterGameModeArea = { 0 }; + } + for (auto& it : replicaGameModeAreas) { + if (it.data) { + free(it.data); + it.data = nullptr; } } + replicaGameModeAreas.clear(); + gameModeMacs.clear(); + requiredGameModeMacs.clear(); } void deleteFriendByIP(uint32_t ip) { @@ -283,36 +411,39 @@ void deleteFriendByIP(uint32_t ip) { for (; peer != NULL; peer = peer->next) { // Found Peer if (peer->ip_addr == ip) { - // Instead of removing it from the list we'll make it timeout since most Matching games are moving group and may still need the peer data - peer->last_recv = 0; - + // Multithreading Lock peerlock.lock(); // Unlink Left (Beginning) - if(prev == NULL)friends = peer->next; + /*if (prev == NULL) friends = peer->next; // Unlink Left (Other) else prev->next = peer->next; + */ + + u32 tmpip = peer->ip_addr; + INFO_LOG(SCENET, "Removing Friend Peer %s [%s]", mac2str(&peer->mac_addr).c_str(), inet_ntoa(*(struct in_addr *)&tmpip)); //inet_ntoa(*(in_addr*)&peer->ip_addr) + + // Free Memory + //free(peer); + //peer = NULL; + // Instead of removing it from the list we'll make it timed out since most Matching games are moving group and may still need the peer data thus not recognizing it as Unknown peer + peer->last_recv = 0; //CoreTiming::GetGlobalTimeUsScaled(); // Multithreading Unlock peerlock.unlock(); - // Free Memory - free(peer); - peer = NULL; - // Stop Search break; } // Set Previous Reference - // TODO: Should this be used by something? prev = peer; } } -int findFreeMatchingID(void) { +int findFreeMatchingID() { // Minimum Matching ID int min = 1; @@ -320,13 +451,15 @@ int findFreeMatchingID(void) { int max = 0; // Find highest Matching ID - SceNetAdhocMatchingContext * item = contexts; for (; item != NULL; item = item->next) { + SceNetAdhocMatchingContext * item = contexts; + for (; item != NULL; item = item->next) { // New Maximum if (max < item->id) max = item->id; } // Find unoccupied ID - int i = min; for (; i < max; i++) { + int i = min; + for (; i < max; i++) { // Found unoccupied ID if (findMatchingContext(i) == NULL) return i; } @@ -337,7 +470,8 @@ int findFreeMatchingID(void) { SceNetAdhocMatchingContext * findMatchingContext(int id) { // Iterate Matching Context List - SceNetAdhocMatchingContext * item = contexts; for (; item != NULL; item = item->next) { // Found Matching ID + SceNetAdhocMatchingContext * item = contexts; + for (; item != NULL; item = item->next) { // Found Matching ID if (item->id == id) return item; } @@ -353,7 +487,8 @@ SceNetAdhocMatchingContext * findMatchingContext(int id) { SceNetAdhocMatchingMemberInternal * findOutgoingRequest(SceNetAdhocMatchingContext * context) { // Iterate Peer List for Matching Target - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL; peer = peer->next) { // Found Peer in List if (peer->state == PSP_ADHOC_MATCHING_PEER_OUTGOING_REQUEST) return peer; @@ -369,6 +504,8 @@ SceNetAdhocMatchingMemberInternal * findOutgoingRequest(SceNetAdhocMatchingConte */ void postAcceptCleanPeerList(SceNetAdhocMatchingContext * context) { + int delcount = 0; + int peercount = 0; // Acquire Peer Lock peerlock.lock(); @@ -380,14 +517,20 @@ void postAcceptCleanPeerList(SceNetAdhocMatchingContext * context) SceNetAdhocMatchingMemberInternal * next = peer->next; // Unneeded Peer - if (peer->state != PSP_ADHOC_MATCHING_PEER_CHILD && peer->state != PSP_ADHOC_MATCHING_PEER_P2P && peer->state != PSP_ADHOC_MATCHING_PEER_PARENT) deletePeer(context, peer); + if (peer->state != PSP_ADHOC_MATCHING_PEER_CHILD && peer->state != PSP_ADHOC_MATCHING_PEER_P2P && peer->state != PSP_ADHOC_MATCHING_PEER_PARENT && peer->state != 0) { + deletePeer(context, peer); + delcount++; + } // Move to Next Peer peer = next; + peercount++; } // Free Peer Lock peerlock.unlock(); + + INFO_LOG(SCENET, "Removing Unneeded Peers (%i/%i)", delcount, peercount); } /** @@ -403,37 +546,52 @@ void postAcceptAddSiblings(SceNetAdhocMatchingContext * context, int siblingcoun // As the buffer of "siblings" isn't properly aligned I don't want to risk a crash. uint8_t * siblings_u8 = (uint8_t *)siblings; - // Iterate Siblings - int i = 0; for (; i < siblingcount; i++) + peerlock.lock(); + // Iterate Siblings. Reversed so these siblings are added into peerlist in the same order with the peerlist on host/parent side + for (int i = siblingcount - 1; i >= 0 ; i--) { - // Allocate Memory - SceNetAdhocMatchingMemberInternal * sibling = (SceNetAdhocMatchingMemberInternal *)malloc(sizeof(SceNetAdhocMatchingMemberInternal)); - - // Allocated Memory - if (sibling != NULL) - { - // Clear Memory - memset(sibling, 0, sizeof(SceNetAdhocMatchingMemberInternal)); - - // Save MAC Address - memcpy(&sibling->mac, siblings_u8 + sizeof(SceNetEtherAddr) * i, sizeof(SceNetEtherAddr)); + SceNetEtherAddr* mac = (SceNetEtherAddr*)(siblings_u8 + sizeof(SceNetEtherAddr) * i); + auto peer = findPeer(context, mac); + // Already exist + if (peer != NULL) { // Set Peer State - sibling->state = PSP_ADHOC_MATCHING_PEER_CHILD; + peer->state = PSP_ADHOC_MATCHING_PEER_CHILD; + peer->sending = 0; + peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); + WARN_LOG(SCENET, "Updating Sibling Peer %s", mac2str(mac).c_str()); + } + else { + // Allocate Memory + SceNetAdhocMatchingMemberInternal* sibling = (SceNetAdhocMatchingMemberInternal*)malloc(sizeof(SceNetAdhocMatchingMemberInternal)); - // Initialize Ping Timer - sibling->lastping = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; + // Allocated Memory + if (sibling != NULL) + { + // Clear Memory + memset(sibling, 0, sizeof(SceNetAdhocMatchingMemberInternal)); - // Link Peer, should check whether it's already added before - sibling->next = context->peerlist; - context->peerlist = sibling; + // Save MAC Address + memcpy(&sibling->mac, mac, sizeof(SceNetEtherAddr)); - // Spawn Established Event - spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL); + // Set Peer State + sibling->state = PSP_ADHOC_MATCHING_PEER_CHILD; - INFO_LOG(SCENET, "Accepting Peer %02X:%02X:%02X:%02X:%02X:%02X", sibling->mac.data[0], sibling->mac.data[1], sibling->mac.data[2], sibling->mac.data[3], sibling->mac.data[4], sibling->mac.data[5]); + // Initialize Ping Timer + sibling->lastping = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0; + + // Link Peer + sibling->next = context->peerlist; + context->peerlist = sibling; + + // Spawn Established Event. FIXME: ESTABLISHED event should only be triggered for Parent/P2P peer? + //spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL); + + INFO_LOG(SCENET, "Accepting Sibling Peer %s", mac2str(&sibling->mac).c_str()); + } } } + peerlock.unlock(); } /** @@ -441,14 +599,17 @@ void postAcceptAddSiblings(SceNetAdhocMatchingContext * context, int siblingcoun * @param context Matching Context Pointer * @return Number of Children */ -s32_le countChildren(SceNetAdhocMatchingContext * context) +s32_le countChildren(SceNetAdhocMatchingContext * context, const bool excludeTimedout) { // Children Counter s32_le count = 0; // Iterate Peer List for Matching Target - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL; peer = peer->next) { + // Exclude timedout members? + if (!excludeTimedout || peer->lastping != 0) // Increase Children Counter if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) count++; } @@ -466,10 +627,11 @@ s32_le countChildren(SceNetAdhocMatchingContext * context) SceNetAdhocMatchingMemberInternal * findPeer(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac) { // Iterate Peer List for Matching Target - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL; peer = peer->next) { // Found Peer in List - if (memcmp(&peer->mac, mac, sizeof(SceNetEtherAddr)) == 0) + if (isMacMatch(&peer->mac, mac)) { // Return Peer Pointer return peer; @@ -488,7 +650,8 @@ SceNetAdhocMatchingMemberInternal * findPeer(SceNetAdhocMatchingContext * contex SceNetAdhocMatchingMemberInternal * findParent(SceNetAdhocMatchingContext * context) { // Iterate Peer List for Matching Target - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL; peer = peer->next) { // Found Peer in List if (peer->state == PSP_ADHOC_MATCHING_PEER_PARENT) return peer; @@ -503,12 +666,14 @@ SceNetAdhocMatchingMemberInternal * findParent(SceNetAdhocMatchingContext * cont * @param context Matching Context Pointer * @return Internal Peer Reference or... NULL */ -SceNetAdhocMatchingMemberInternal * findP2P(SceNetAdhocMatchingContext * context) +SceNetAdhocMatchingMemberInternal * findP2P(SceNetAdhocMatchingContext * context, const bool excludeTimedout) { // Iterate Peer List for Matching Target SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) { + // Exclude timedout members? + if (!excludeTimedout || peer->lastping != 0) // Found Peer in List if (peer->state == PSP_ADHOC_MATCHING_PEER_P2P) return peer; } @@ -522,7 +687,7 @@ SceNetAdhocMatchingMemberInternal * findP2P(SceNetAdhocMatchingContext * context * @param context Matching Context Pointer * @param peer Internal Peer Reference */ -void deletePeer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer) +void deletePeer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal *& peer) { // Valid Arguments if (context != NULL && peer != NULL) @@ -550,7 +715,7 @@ void deletePeer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberI // Beginning Item else context->peerlist = item->next; - INFO_LOG(SCENET, "Removing Peer %02X:%02X:%02X:%02X:%02X:%02X", peer->mac.data[0], peer->mac.data[1], peer->mac.data[2], peer->mac.data[3], peer->mac.data[4], peer->mac.data[5]); + INFO_LOG(SCENET, "Removing Member Peer %s", mac2str(&peer->mac).c_str()); } // Free Peer Memory @@ -647,7 +812,8 @@ void sendGenericMessage(SceNetAdhocMatchingContext * context, int stack, SceNetE peerlock.lock(); // Out of Memory Emergency Delete - deletePeer(context, findPeer(context, mac)); + auto peer = findPeer(context, mac); + deletePeer(context, peer); peerlock.unlock(); } @@ -741,7 +907,7 @@ void sendDeathMessage(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingM * @param context Matching Context Pointer * @return Number of Connected Peers */ -uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context) +uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context, const bool excludeTimedout) { // Peer Count uint32_t count = 0; @@ -750,7 +916,7 @@ uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context) if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) { // Number of Children + 1 Parent (Self) - count = countChildren(context) + 1; + count = countChildren(context, excludeTimedout) + 1; } // Child Mode @@ -762,8 +928,8 @@ uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context) // Connected to Parent if (findParent(context) != NULL) { - // Add Number of Siblings + 1 Parents - count += countChildren(context) + 1; + // Add Number of Siblings + 1 Parent + count += countChildren(context, excludeTimedout) + 1; // Since count is already started from 1, Do we need to +1 here? Ys vs. Sora no Kiseki seems to show wrong number of players without +1 here } } @@ -774,7 +940,7 @@ uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context) count = 1; // Connected to another P2P Client - if (findP2P(context) != NULL) + if (findP2P(context, excludeTimedout) != NULL) { // Add P2P Brother count++; @@ -801,31 +967,36 @@ void spawnLocalEvent(SceNetAdhocMatchingContext * context, int event, SceNetEthe /** * Handle Timeouts in Matching Context -* @param context Matchi]ng Context Pointer +* @param context Matching Context Pointer */ void handleTimeout(SceNetAdhocMatchingContext * context) { peerlock.lock(); // Iterate Peer List - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; while (peer != NULL) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + while (peer != NULL && contexts != NULL && coreState != CORE_POWERDOWN) { // Get Next Pointer (to avoid crash on memory freeing) SceNetAdhocMatchingMemberInternal * next = peer->next; - u64_le now = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0 + u64_le now = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0 // Timeout! - if ((now - peer->lastping) >= context->timeout) + if (peer->state != 0 && (now - peer->lastping) > context->timeout) { // Spawn Timeout Event - if ((context->mode == PSP_ADHOC_MATCHING_MODE_CHILD && (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD || peer->state == PSP_ADHOC_MATCHING_PEER_PARENT)) || + if ((context->mode == PSP_ADHOC_MATCHING_MODE_CHILD && peer->state == PSP_ADHOC_MATCHING_PEER_PARENT) || (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT && peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) || - (context->mode == PSP_ADHOC_MATCHING_MODE_P2P && peer->state == PSP_ADHOC_MATCHING_PEER_P2P)) + (context->mode == PSP_ADHOC_MATCHING_MODE_P2P && peer->state == PSP_ADHOC_MATCHING_PEER_P2P)) { + // FIXME: TIMEOUT event should only be triggered on Parent/P2P mode and for Parent/P2P peer? spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_TIMEOUT, &peer->mac, 0, NULL); - INFO_LOG(SCENET, "TimedOut Peer %02X:%02X:%02X:%02X:%02X:%02X (%lldms)", peer->mac.data[0], peer->mac.data[1], peer->mac.data[2], peer->mac.data[3], peer->mac.data[4], peer->mac.data[5], (context->timeout/1000)); + INFO_LOG(SCENET, "TimedOut Member Peer %s (%lldms)", mac2str(&peer->mac).c_str(), (context->timeout / 1000)); - // Delete Peer from List - deletePeer(context, peer); + if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) + sendDeathMessage(context, peer); + else + sendCancelMessage(context, peer, 0, NULL); + } } // Move Pointer @@ -838,13 +1009,14 @@ void handleTimeout(SceNetAdhocMatchingContext * context) * Recursive Stack Cleaner * @param node Current Thread Message Node */ -void clearStackRecursive(ThreadMessage * node) +void clearStackRecursive(ThreadMessage *& node) { // Not End of List if (node != NULL) clearStackRecursive(node->next); // Free Last Existing Node of List (NULL is handled in _free) free(node); + node = NULL; } /** @@ -901,6 +1073,8 @@ void clearPeerList(SceNetAdhocMatchingContext * context) // Delete Peer free(peer); //deletePeer(context, peer); + // Instead of removing peer immediately, We should give a little time before removing the peer and let it timed out? just in case the game is in the middle of communicating with the peer on another thread so it won't recognize it as Unknown peer + //peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); // Move Pointer peer = context->peerlist; //peer = next; @@ -910,112 +1084,157 @@ void clearPeerList(SceNetAdhocMatchingContext * context) peerlock.unlock(); } -bool IsMatchingInCallback(SceNetAdhocMatchingContext * context) { - bool inCB = false; - if (context == NULL || context->eventlock == NULL) return inCB; - context->eventlock->lock(); //peerlock.lock(); - inCB = (/*context != NULL &&*/ context->IsMatchingInCB); - context->eventlock->unlock(); //peerlock.unlock(); - return inCB; -} - -void AfterMatchingMipsCall::run(MipsCall &call) { - if (context == NULL || context->eventlock == NULL) return; - context->eventlock->lock(); // There are times where context or the locks inside it has been freed at this point, thus accessing the lock causing an exception and crashes PPSSPP - DEBUG_LOG(SCENET, "Entering AfterMatchingMipsCall::run [ID=%i][Event=%d] [cbId: %u]", context->id, EventID, call.cbId); - //u32 v0 = currentMIPS->r[MIPS_REG_V0]; - if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", context->id, EventID); - //while (__IsInInterrupt()) sleep_ms(1); // Must not sleep inside callback handler - //context->eventlock->lock(); //peerlock.lock(); - //SceNetAdhocMatchingContext * context = findMatchingContext(ID); - //if (context != NULL) - { - if (!context->IsMatchingInCB) { - WARN_LOG(SCENET, "AfterMatchingMipsCall::run was Forced to End! [ID=%i][Event=%d] [retV0: %08x]", context->id, EventID, currentMIPS->r[MIPS_REG_V0]); - if (Memory::IsValidAddress(call.args[2])) userMemory.Free(call.args[2]); // This might failed if it's freed from a different thread than the one allocating it. - } - context->IsMatchingInCB = false; +void AfterMatchingMipsCall::DoState(PointerWrap & p) { + auto s = p.Section("AfterMatchingMipsCall", 1, 4); + if (!s) + return; + if (s >= 1) { + Do(p, EventID); + } else { + EventID = -1; + } + if (s >= 4) { + Do(p, contextID); + Do(p, bufAddr); + } else { + contextID = -1; + bufAddr = 0; } - //call.setReturnValue(v0); - DEBUG_LOG(SCENET, "Leaving AfterMatchingMipsCall::run [ID=%i][Event=%d] [retV0: %08x]", context->id, EventID, currentMIPS->r[MIPS_REG_V0]); - context->eventlock->unlock(); //peerlock.unlock(); } -void AfterMatchingMipsCall::SetContextID(u32 ContextID, u32 eventId) { +// It seems After Actions being called in reverse order of Mipscall order (ie. MipsCall order of ACCEPT(6)->ESTABLISH(7) getting AfterAction order of ESTABLISH(7)->ACCEPT(6) +void AfterMatchingMipsCall::run(MipsCall &call) { + if (context == NULL) { + peerlock.lock(); + context = findMatchingContext(contextID); + peerlock.unlock(); + } + u32 v0 = currentMIPS->r[MIPS_REG_V0]; + if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", contextID, EventID); + //SetMatchingInCallback(context, false); + DEBUG_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d][%s] [cbId: %u][retV0: %08x]", contextID, EventID, mac2str((SceNetEtherAddr*)Memory::GetPointer(bufAddr)).c_str(), call.cbId, v0); + if (Memory::IsValidAddress(bufAddr)) userMemory.Free(bufAddr); + //call.setReturnValue(v0); +} + +void AfterMatchingMipsCall::SetData(int ContextID, int eventId, u32_le BufAddr) { + contextID = ContextID; EventID = eventId; + bufAddr = BufAddr; peerlock.lock(); context = findMatchingContext(ContextID); peerlock.unlock(); } +bool SetMatchingInCallback(SceNetAdhocMatchingContext* context, bool IsInCB) { + if (context == NULL) return false; + context->eventlock->lock(); //peerlock.lock(); + context->IsMatchingInCB = IsInCB; + context->eventlock->unlock(); //peerlock.unlock(); + return IsInCB; +} + +bool IsMatchingInCallback(SceNetAdhocMatchingContext* context) { + bool inCB = false; + if (context == NULL) return inCB; + context->eventlock->lock(); //peerlock.lock(); + inCB = (context->IsMatchingInCB); + context->eventlock->unlock(); //peerlock.unlock(); + return inCB; +} + +void AfterAdhocMipsCall::DoState(PointerWrap & p) { + auto s = p.Section("AfterAdhocMipsCall", 1, 4); + if (!s) + return; + if (s >= 3) { + Do(p, HandlerID); + Do(p, EventID); + Do(p, argsAddr); + } else { + HandlerID = -1; + EventID = -1; + argsAddr = 0; + } +} + +void AfterAdhocMipsCall::run(MipsCall& call) { + u32 v0 = currentMIPS->r[MIPS_REG_V0]; + if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterAdhocMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", HandlerID, EventID); + SetAdhocctlInCallback(false); + DEBUG_LOG(SCENET, "AfterAdhocMipsCall::run [ID=%i][Event=%d] [cbId: %u][retV0: %08x]", HandlerID, EventID, call.cbId, v0); + //call.setReturnValue(v0); +} + +void AfterAdhocMipsCall::SetData(int handlerID, int eventId, u32_le ArgsAddr) { + HandlerID = handlerID; + EventID = eventId; + argsAddr = ArgsAddr; +} + +int SetAdhocctlInCallback(bool IsInCB) { + std::lock_guard adhocGuard(adhocEvtMtx); + IsAdhocctlInCB += (IsInCB?1:-1); + return IsAdhocctlInCB; +} + +int IsAdhocctlInCallback() { + std::lock_guard adhocGuard(adhocEvtMtx); + int inCB = IsAdhocctlInCB; + return inCB; +} + // Make sure MIPS calls have been fully executed before the next notifyAdhocctlHandlers void notifyAdhocctlHandlers(u32 flag, u32 error) { __UpdateAdhocctlHandlers(flag, error); - // TODO: We should use after action instead of guessing the time like this - sleep_ms(20); // Ugly workaround to give time for the mips callback to fully executed, usually only need <16ms } // Matching callback is void function: typedef void(*SceNetAdhocMatchingHandler)(int id, int event, SceNetEtherAddr * peer, int optlen, void * opt); // Important! The MIPS call need to be fully executed before the next MIPS call invoked, as the game (ie. DBZ Tag Team) may need to prepare something for the next callback event to use // Note: Must not lock peerlock within this function to prevent race-condition with other thread whos owning peerlock and trying to lock context->eventlock owned by this thread -void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * msg, void * opt, u32 &bufAddr, u32 &bufLen, u32_le * args) { - //u32_le args[5] = { 0, 0, 0, 0, 0 }; - /* - if ((s32)bufLen < (msg->optlen + 8)) { - bufLen = msg->optlen + 8; - if (Memory::IsValidAddress(bufAddr)) userMemory.Free(bufAddr); - bufAddr = userMemory.Alloc(bufLen); - INFO_LOG(SCENET, "MatchingHandler: Alloc(%i -> %i) = %08x", msg->optlen + 8, bufLen, bufAddr); - } - u8 * optPtr = Memory::GetPointer(bufAddr); - */ - - u32_le dataLen = msg->optlen + 8; - u32_le dataAddr = userMemory.Alloc(dataLen); - VERBOSE_LOG(SCENET, "MatchingHandler: Alloc(%i -> %i) = %08x", msg->optlen + 8, dataLen, dataAddr); - u8 * optPtr = Memory::GetPointer(dataAddr); - - memcpy(optPtr, &msg->mac, sizeof(msg->mac)); - if (msg->optlen > 0) memcpy(optPtr + 8, opt, msg->optlen); - args[0] = context->id; - args[1] = msg->opcode; - args[2] = dataAddr; //bufAddr; // PSP_GetScratchpadMemoryBase() + 0x6000; - args[3] = msg->optlen; - args[4] = args[2] + 8; - args[5] = context->handler.entryPoint; //not part of callback argument, just borrowing a space to store callback address so i don't need to search the context first later +void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * msg, void * opt, u32_le &bufAddr, u32_le &bufLen, u32_le * args) { + // Don't share buffer address space with other mipscall in the queue since mipscalls aren't immediately executed + MatchingArgs argsNew; + u32_le dataBufLen = msg->optlen + 8; //max(bufLen, msg->optlen + 8); + u32_le dataBufAddr = userMemory.Alloc(dataBufLen); // We will free this memory after returning from mipscall + uint8_t * dataPtr = Memory::GetPointer(dataBufAddr); + memcpy(dataPtr, &msg->mac, sizeof(msg->mac)); + if (msg->optlen > 0) + memcpy(dataPtr + 8, opt, msg->optlen); + argsNew.data[0] = context->id; + argsNew.data[1] = msg->opcode; + argsNew.data[2] = dataBufAddr; + argsNew.data[3] = msg->optlen; + argsNew.data[4] = dataBufAddr + 8; // OptData Addr + argsNew.data[5] = context->handler.entryPoint; //not part of callback argument, just borrowing a space to store callback address so i don't need to search the context first later - context->eventlock->lock(); - context->IsMatchingInCB = true; - context->eventlock->unlock(); // ScheduleEvent_Threadsafe_Immediate seems to get mixed up with interrupt (returning from mipscall inside an interrupt) and getting invalid address before returning from interrupt - __UpdateMatchingHandler((u64) args); - - // Make sure MIPS call have been fully executed before the next notifyMatchingHandler - int count = 0; - while (/*(after != NULL) &&*/ IsMatchingInCallback(context) && (count < 250)) { - sleep_ms(1); - count++; - } - if (count >= 250) { - ERROR_LOG(SCENET, "MatchingHandler: Callback Failed to Return within %dms!", count); - context->eventlock->lock(); - context->IsMatchingInCB = false; - context->eventlock->unlock(); - } else { - if (Memory::IsValidAddress(dataAddr)) userMemory.Free(dataAddr); - } - //sleep_ms(20); // Wait a little more (for context switching may be?) to prevent DBZ Tag Team from getting connection lost, but this will cause lags on Lord of Arcana + __UpdateMatchingHandler(argsNew); } -void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node) { +void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node, int32_t* count) { // End of List if (node == NULL) return; // Increase Recursion Depth - freeFriendsRecursive(node->next); + freeFriendsRecursive(node->next, count); // Free Memory free(node); + node = NULL; + if (count != NULL) (*count)++; +} + +void timeoutFriendsRecursive(SceNetAdhocctlPeerInfo * node, int32_t* count) { + // End of List + if (node == NULL) return; + + // Increase Recursion Depth + timeoutFriendsRecursive(node->next, count); + + // Set last timestamp + node->last_recv = 0; + if (count != NULL) (*count)++; } void sendChat(std::string chatString) { @@ -1031,12 +1250,14 @@ void sendChat(std::string chatString) { message = chatString.substr(0, 60); // 64 return chat variable corrupted is it out of memory? strcpy(chat.message, message.c_str()); //Send Chat Messages - int chatResult = send(metasocket, (const char *)&chat, sizeof(chat), 0); - NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message); - name = g_Config.sNickName.c_str(); - chatLog.push_back(name.substr(0, 8) + ": " + chat.message); - if (chatScreenVisible) { - updateChatScreen = true; + if (IsSocketReady(metasocket, false, true) > 0) { + int chatResult = send(metasocket, (const char*)&chat, sizeof(chat), MSG_NOSIGNAL); + NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message); + name = g_Config.sNickName.c_str(); + chatLog.push_back(name.substr(0, 8) + ": " + chat.message); + if (chatScreenVisible) { + updateChatScreen = true; + } } } } @@ -1058,6 +1279,8 @@ std::vector getChatLog() { } int friendFinder(){ + setCurrentThreadName("FriendFinder"); + auto n = GetI18NCategory("Networking"); // Receive Buffer int rxpos = 0; uint8_t rx[1024]; @@ -1077,201 +1300,321 @@ int friendFinder(){ // Log Startup INFO_LOG(SCENET, "FriendFinder: Begin of Friend Finder Thread"); + // Resolve and cache AdhocServer DNS + addrinfo* resolved = nullptr; + std::string err; + g_adhocServerIP.in.sin_addr.s_addr = INADDR_NONE; + if (!net::DNSResolve(g_Config.proAdhocServer, "", &resolved, err)) { + ERROR_LOG(SCENET, "DNS Error Resolving %s\n", g_Config.proAdhocServer.c_str()); + host->NotifyUserMessage(n->T("DNS Error Resolving ") + g_Config.proAdhocServer, 2.0f, 0x0000ff); + } + if (resolved) { + for (auto ptr = resolved; ptr != NULL; ptr = ptr->ai_next) { + switch (ptr->ai_family) { + case AF_INET: + g_adhocServerIP.in = *(sockaddr_in*)ptr->ai_addr; + break; + } + } + net::DNSResolveFree(resolved); + } + g_adhocServerIP.in.sin_port = htons(SERVER_PORT); + // Finder Loop while (friendFinderRunning) { // Acquire Network Lock //_acquireNetworkLock(); - // Ping Server - now = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; // should be in microseconds, but it seems real_time_now() returns in seconds - if (now - lastping >= PSP_ADHOCCTL_PING_TIMEOUT) { //100 // We need to use lower interval to prevent getting timeout at Pro Adhoc Server through internet - // original code : ((sceKernelGetSystemTimeWide() - lastping) >= ADHOCCTL_PING_TIMEOUT) - // Update Ping Time - lastping = now; - - // Prepare Packet - uint8_t opcode = OPCODE_PING; - - // Send Ping to Server, may failed with socket error 10054/10053 if someone else with the same IP already connected to AdHoc Server (the server might need to be modified to differentiate MAC instead of IP) - int iResult = send(metasocket, (const char *)&opcode, 1, 0); - /*if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", errno); - //friendFinderRunning = false; - }*/ - } - - // Wait for Incoming Data - int received = recv(metasocket, (char *)(rx + rxpos), sizeof(rx) - rxpos, 0); - - // Free Network Lock - //_freeNetworkLock(); - - // Received Data - if (received > 0) { - // Fix Position - rxpos += received; - - // Log Incoming Traffic - //printf("Received %d Bytes of Data from Server\n", received); - INFO_LOG(SCENET, "Received %d Bytes of Data from Adhoc Server", received); - } - - // Handle Packets - if (rxpos > 0) { - // BSSID Packet - if (rx[0] == OPCODE_CONNECT_BSSID) { - INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT_BSSID"); - // Enough Data available - if(g_Config.bMOHH2hack) // Really bad, but works around MOHH2 timing issue - sleep_ms(666*10); // Don't hurry, be happy, 5s wasn't enough, let's use a safe number - if (rxpos >= (int)sizeof(SceNetAdhocctlConnectBSSIDPacketS2C)) { - // Cast Packet - SceNetAdhocctlConnectBSSIDPacketS2C * packet = (SceNetAdhocctlConnectBSSIDPacketS2C *)rx; - // Update BSSID - parameter.bssid.mac_addr = packet->mac; - // Change State - threadStatus = ADHOCCTL_STATE_CONNECTED; - // Notify Event Handlers - notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0); - - // Move RX Buffer - memmove(rx, rx + sizeof(SceNetAdhocctlConnectBSSIDPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectBSSIDPacketS2C)); - - // Fix RX Buffer Length - rxpos -= sizeof(SceNetAdhocctlConnectBSSIDPacketS2C); + // Reconnect when disconnected while Adhocctl is still inited + if (metasocket == (int)INVALID_SOCKET && netAdhocctlInited) { + if (g_Config.bEnableWlan) { + if (initNetwork(&product_code) == 0) { + networkInited = true; + INFO_LOG(SCENET, "FriendFinder: Network [RE]Initialized"); + } + else { + networkInited = false; + shutdown(metasocket, SD_BOTH); + closesocket(metasocket); + metasocket = (int)INVALID_SOCKET; } } + } - // Chat Packet - else if (rx[0] == OPCODE_CHAT) { - INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CHAT"); - // Enough Data available - if (rxpos >= (int)sizeof(SceNetAdhocctlChatPacketS2C)) { - // Cast Packet - SceNetAdhocctlChatPacketS2C * packet = (SceNetAdhocctlChatPacketS2C *)rx; - // Add Incoming Chat to HUD - NOTICE_LOG(SCENET, "Received chat message %s", packet->base.message); - incoming = ""; - name = (char *)packet->name.data; - incoming.append(name.substr(0, 8)); - incoming.append(": "); - incoming.append((char *)packet->base.message); - chatLog.push_back(incoming); - //im new to pointer btw :( doesn't know its safe or not this should update the chat screen when data coming - if (chatScreenVisible) { - updateChatScreen = true; - } - else { - if (newChat < 50) { - newChat += 1; + if (networkInited) { + // Ping Server + now = time_now_d() * 1000000.0; // Use time_now_d()*1000000.0 instead of CoreTiming::GetGlobalTimeUsScaled() if the game gets disconnected from AdhocServer too soon when FPS wasn't stable + // original code : ((sceKernelGetSystemTimeWide() - lastping) >= ADHOCCTL_PING_TIMEOUT) + if (now - lastping >= PSP_ADHOCCTL_PING_TIMEOUT) { // We may need to use lower interval to prevent getting timeout at Pro Adhoc Server through internet + // Prepare Packet + uint8_t opcode = OPCODE_PING; + + // Send Ping to Server, may failed with socket error 10054/10053 if someone else with the same IP already connected to AdHoc Server (the server might need to be modified to differentiate MAC instead of IP) + if (IsSocketReady(metasocket, false, true) > 0) { + int iResult = send(metasocket, (const char*)&opcode, 1, MSG_NOSIGNAL); + int error = errno; + // KHBBS seems to be getting error 10053 often + if (iResult == SOCKET_ERROR) { + ERROR_LOG(SCENET, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", error); + if (error != EAGAIN && error != EWOULDBLOCK) { + networkInited = false; + shutdown(metasocket, SD_BOTH); + closesocket(metasocket); + metasocket = (int)INVALID_SOCKET; + host->NotifyUserMessage(std::string(n->T("Disconnected from AdhocServer")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(error) + ")", 2.0, 0x0000ff); + // Mark all friends as timedout since we won't be able to detects disconnected friends anymore without being connected to Adhoc Server + timeoutFriendsRecursive(friends); } } - // Move RX Buffer - memmove(rx, rx + sizeof(SceNetAdhocctlChatPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlChatPacketS2C)); - - // Fix RX Buffer Length - rxpos -= sizeof(SceNetAdhocctlChatPacketS2C); + else { + // Update Ping Time + lastping = now; + DEBUG_LOG(SCENET, "FriendFinder: Sending OPCODE_PING (%llu)", static_cast(now)); + } } } - // Connect Packet - else if (rx[0] == OPCODE_CONNECT) { - DEBUG_LOG(SCENET, "FriendFinder: OPCODE_CONNECT"); - // Enough Data available - if (rxpos >= (int)sizeof(SceNetAdhocctlConnectPacketS2C)) { - // Log Incoming Peer - INFO_LOG(SCENET, "Incoming Peer Data..."); + // Check for Incoming Data + if (IsSocketReady(metasocket, true, false) > 0) { + int received = recv(metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, MSG_NOSIGNAL); - // Cast Packet - SceNetAdhocctlConnectPacketS2C * packet = (SceNetAdhocctlConnectPacketS2C *)rx; + // Free Network Lock + //_freeNetworkLock(); - // Add User - addFriend(packet); - incoming = ""; - incoming.append((char *)packet->name.data); - incoming.append(" Joined "); - //do we need ip? - //joined.append((char *)packet->ip); - chatLog.push_back(incoming); - //im new to pointer btw :( doesn't know its safe or not this should update the chat screen when data coming - if (chatScreenVisible) { - updateChatScreen = true; + // Received Data + if (received > 0) { + // Fix Position + rxpos += received; + + // Log Incoming Traffic + //printf("Received %d Bytes of Data from Server\n", received); + INFO_LOG(SCENET, "Received %d Bytes of Data from Adhoc Server", received); + } + } + + // Handle Packets + if (rxpos > 0) { + // BSSID Packet + if (rx[0] == OPCODE_CONNECT_BSSID) { + // Enough Data available + if (rxpos >= (int)sizeof(SceNetAdhocctlConnectBSSIDPacketS2C)) { + // Cast Packet + SceNetAdhocctlConnectBSSIDPacketS2C* packet = (SceNetAdhocctlConnectBSSIDPacketS2C*)rx; + + INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT_BSSID [%s]", mac2str(&packet->mac).c_str()); + // Update User BSSID + parameter.bssid.mac_addr = packet->mac; // This packet seems to contains Adhoc Group Creator's BSSID (similar to AP's BSSID) so it shouldn't get mixed up with local MAC address + + // From JPCSP: Some games have problems when the PSP_ADHOCCTL_EVENT_CONNECTED is sent too quickly after connecting to a network. The connection will be set CONNECTED with a small delay (200ms or 200us?) + // Notify Event Handlers + if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) { + SceNetEtherAddr localMac; + getLocalMac(&localMac); + if (std::find_if(gameModeMacs.begin(), gameModeMacs.end(), + [localMac](SceNetEtherAddr const& e) { + return IsMatch(e, localMac); + }) == gameModeMacs.end()) { + // Arrange the order to be consistent on all players (Host on top), Starting from our self the rest of new players will be added to the back + gameModeMacs.push_back(localMac); + } + else + WARN_LOG(SCENET, "GameMode SelfMember [%s] Already Existed!", mac2str(&localMac).c_str()); + + if (gameModeMacs.size() >= requiredGameModeMacs.size()) { + //adhocctlState = ADHOCCTL_STATE_GAMEMODE; + notifyAdhocctlHandlers(ADHOCCTL_EVENT_GAME, 0); + } + } + else { + //adhocctlState = ADHOCCTL_STATE_CONNECTED; + notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0); + } + + // Give time a little time + //sceKernelDelayThread(adhocEventDelayMS * 1000); + //sleep_ms(adhocEventDelayMS); + + // Move RX Buffer + memmove(rx, rx + sizeof(SceNetAdhocctlConnectBSSIDPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectBSSIDPacketS2C)); + + // Fix RX Buffer Length + rxpos -= sizeof(SceNetAdhocctlConnectBSSIDPacketS2C); } - // Update HUD User Count + } + + // Chat Packet + else if (rx[0] == OPCODE_CHAT) { + // Enough Data available + if (rxpos >= (int)sizeof(SceNetAdhocctlChatPacketS2C)) { + // Cast Packet + SceNetAdhocctlChatPacketS2C* packet = (SceNetAdhocctlChatPacketS2C*)rx; + INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CHAT"); + + // Fix strings with null-terminated + packet->name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; + packet->base.message[ADHOCCTL_MESSAGE_LEN - 1] = 0; + + // Add Incoming Chat to HUD + NOTICE_LOG(SCENET, "Received chat message %s", packet->base.message); + incoming = ""; + name = (char*)packet->name.data; + incoming.append(name.substr(0, 8)); + incoming.append(": "); + incoming.append((char*)packet->base.message); + chatLog.push_back(incoming); + //im new to pointer btw :( doesn't know its safe or not this should update the chat screen when data coming + if (chatScreenVisible) { + updateChatScreen = true; + } + else { + if (newChat < 50) { + newChat += 1; + } + } + + // Move RX Buffer + memmove(rx, rx + sizeof(SceNetAdhocctlChatPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlChatPacketS2C)); + + // Fix RX Buffer Length + rxpos -= sizeof(SceNetAdhocctlChatPacketS2C); + } + } + + // Connect Packet + else if (rx[0] == OPCODE_CONNECT) { + // Enough Data available + if (rxpos >= (int)sizeof(SceNetAdhocctlConnectPacketS2C)) { + // Cast Packet + SceNetAdhocctlConnectPacketS2C* packet = (SceNetAdhocctlConnectPacketS2C*)rx; + + // Fix strings with null-terminated + packet->name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; + + // Log Incoming Peer + u32_le ipaddr = packet->ip; + INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT [%s][%s][%s]", mac2str(&packet->mac).c_str(), inet_ntoa(*(in_addr*)&ipaddr), packet->name.data); + + // Add User + addFriend(packet); + + // Make sure GameMode participants are all joined (including self MAC) + if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) { + if (std::find_if(gameModeMacs.begin(), gameModeMacs.end(), + [packet](SceNetEtherAddr const& e) { + return IsMatch(e, packet->mac); + }) == gameModeMacs.end()) { + // Arrange the order to be consistent on all players (Host on top), Existing players are sent in reverse by AdhocServer + SceNetEtherAddr localMac; + getLocalMac(&localMac); + auto it = std::find_if(gameModeMacs.begin(), gameModeMacs.end(), + [localMac](SceNetEtherAddr const& e) { + return IsMatch(e, localMac); + }); + // Starting from our self the rest of new players will be added to the back + if (it != gameModeMacs.end()) { + gameModeMacs.push_back(packet->mac); + } + else { + it = gameModeMacs.begin() + 1; + gameModeMacs.insert(it, packet->mac); + } + } + else + WARN_LOG(SCENET, "GameMode Member [%s] Already Existed!", mac2str(&packet->mac).c_str()); + + // From JPCSP: Join complete when all the required MACs have joined + if (requiredGameModeMacs.size() > 0 && gameModeMacs.size() >= requiredGameModeMacs.size()) { + // TODO: Should we replace gameModeMacs contents with requiredGameModeMacs contents to make sure they are in the same order with macs from sceNetAdhocctlCreateEnterGameMode? But may not be consistent with the list on client side! + //gameModeMacs = requiredGameModeMacs; + //adhocctlState = ADHOCCTL_STATE_GAMEMODE; + notifyAdhocctlHandlers(ADHOCCTL_EVENT_GAME, 0); + } + } + + // Update HUD User Count + incoming = ""; + incoming.append((char*)packet->name.data); + incoming.append(" Joined "); + //do we need ip? + //joined.append((char *)packet->ip); + chatLog.push_back(incoming); + //im new to pointer btw :( doesn't know its safe or not this should update the chat screen when data coming + if (chatScreenVisible) { + updateChatScreen = true; + } + #ifdef LOCALHOST_AS_PEER - setUserCount(getActivePeerCount()); + setUserCount(getActivePeerCount()); #else - // setUserCount(getActivePeerCount()+1); + // setUserCount(getActivePeerCount()+1); #endif // Move RX Buffer - memmove(rx, rx + sizeof(SceNetAdhocctlConnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectPacketS2C)); + memmove(rx, rx + sizeof(SceNetAdhocctlConnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectPacketS2C)); - // Fix RX Buffer Length - rxpos -= sizeof(SceNetAdhocctlConnectPacketS2C); + // Fix RX Buffer Length + rxpos -= sizeof(SceNetAdhocctlConnectPacketS2C); + } } - } - // Disconnect Packet - else if (rx[0] == OPCODE_DISCONNECT) { - DEBUG_LOG(SCENET, "FriendFinder: OPCODE_DISCONNECT"); - // Enough Data available - if (rxpos >= (int)sizeof(SceNetAdhocctlDisconnectPacketS2C)) { - // Log Incoming Peer Delete Request - INFO_LOG(SCENET, "FriendFinder: Incoming Peer Data Delete Request..."); + // Disconnect Packet + else if (rx[0] == OPCODE_DISCONNECT) { + // Enough Data available + if (rxpos >= (int)sizeof(SceNetAdhocctlDisconnectPacketS2C)) { + // Cast Packet + SceNetAdhocctlDisconnectPacketS2C* packet = (SceNetAdhocctlDisconnectPacketS2C*)rx; - // Cast Packet - SceNetAdhocctlDisconnectPacketS2C * packet = (SceNetAdhocctlDisconnectPacketS2C *)rx; + DEBUG_LOG(SCENET, "FriendFinder: OPCODE_DISCONNECT"); - // Delete User by IP, should delete by MAC since IP can be shared (behind NAT) isn't? - deleteFriendByIP(packet->ip); + // Log Incoming Peer Delete Request + INFO_LOG(SCENET, "FriendFinder: Incoming Peer Data Delete Request..."); - // Update HUD User Count + /*if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) { + auto peer = findFriendByIP(packet->ip); + gameModeMacs.erase(std::remove_if(gameModeMacs.begin(), gameModeMacs.end(), + [peer](auto const& e) { + return IsMatch(e, peer->mac_addr); + }), gameModeMacs.end()); + }*/ + + // Delete User by IP, should delete by MAC since IP can be shared (behind NAT) isn't? + deleteFriendByIP(packet->ip); + + // Update HUD User Count #ifdef LOCALHOST_AS_PEER - setUserCount(_getActivePeerCount()); + setUserCount(_getActivePeerCount()); #else //setUserCount(_getActivePeerCount()+1); #endif // Move RX Buffer - memmove(rx, rx + sizeof(SceNetAdhocctlDisconnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlDisconnectPacketS2C)); + memmove(rx, rx + sizeof(SceNetAdhocctlDisconnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlDisconnectPacketS2C)); - // Fix RX Buffer Length - rxpos -= sizeof(SceNetAdhocctlDisconnectPacketS2C); - } - } - - // Scan Packet - else if (rx[0] == OPCODE_SCAN) { - DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN"); - // Enough Data available - if (rxpos >= (int)sizeof(SceNetAdhocctlScanPacketS2C)) { - // Log Incoming Network Information - INFO_LOG(SCENET, "Incoming Group Information..."); - // Cast Packet - SceNetAdhocctlScanPacketS2C * packet = (SceNetAdhocctlScanPacketS2C *)rx; - - // Multithreading Lock - peerlock.lock(); - - // Should only add non-existing group (or replace an existing group) to prevent Ford Street Racing from showing a strange game session list - SceNetAdhocctlScanInfo * group = findGroup(&packet->mac); - - if (group != NULL) { - // Copy Group Name - group->group_name = packet->group; - - // Set Group Host - group->bssid.mac_addr = packet->mac; + // Fix RX Buffer Length + rxpos -= sizeof(SceNetAdhocctlDisconnectPacketS2C); } - else - { + } + + // Scan Packet + else if (rx[0] == OPCODE_SCAN) { + // Enough Data available + if (rxpos >= (int)sizeof(SceNetAdhocctlScanPacketS2C)) { + // Cast Packet + SceNetAdhocctlScanPacketS2C* packet = (SceNetAdhocctlScanPacketS2C*)rx; + + DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN"); + + // Log Incoming Network Information + INFO_LOG(SCENET, "Incoming Group Information..."); + + // Multithreading Lock + peerlock.lock(); + // Allocate Structure Data - SceNetAdhocctlScanInfo * group = (SceNetAdhocctlScanInfo *)malloc(sizeof(SceNetAdhocctlScanInfo)); + SceNetAdhocctlScanInfo* group = (SceNetAdhocctlScanInfo*)malloc(sizeof(SceNetAdhocctlScanInfo)); // Allocated Structure Data - if (group != NULL) - { + if (group != NULL) { // Clear Memory, should this be done only when allocating new group? memset(group, 0, sizeof(SceNetAdhocctlScanInfo)); @@ -1284,64 +1627,63 @@ int friendFinder(){ // Set Group Host group->bssid.mac_addr = packet->mac; + // Set group parameters + // Since 0 is not a valid active channel we fake the channel for Automatic Channel (JPCSP use 11 as default). Ridge Racer 2 will ignore any groups with channel 0 or that doesn't matched with channel value returned from sceUtilityGetSystemParamInt (which mean sceUtilityGetSystemParamInt must not return channel 0 when connected to a network?) + group->channel = parameter.channel; //(parameter.channel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) ? defaultWlanChannel : parameter.channel; + group->mode = adhocctlCurrentMode; + // Link into Group List newnetworks = group; } - } - // Multithreading Unlock + // Multithreading Unlock + peerlock.unlock(); + + // Move RX Buffer + memmove(rx, rx + sizeof(SceNetAdhocctlScanPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlScanPacketS2C)); + + // Fix RX Buffer Length + rxpos -= sizeof(SceNetAdhocctlScanPacketS2C); + } + } + + // Scan Complete Packet + else if (rx[0] == OPCODE_SCAN_COMPLETE) { + DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN_COMPLETE"); + // Log Scan Completion + INFO_LOG(SCENET, "FriendFinder: Incoming Scan complete response..."); + + // Reset current networks to prevent disbanded host to be listed again + peerlock.lock(); + if (networks != newnetworks) { + freeGroupsRecursive(networks); + networks = newnetworks; + } + newnetworks = NULL; peerlock.unlock(); + // Notify Event Handlers + notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0); + // Move RX Buffer - memmove(rx, rx + sizeof(SceNetAdhocctlScanPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlScanPacketS2C)); + memmove(rx, rx + 1, sizeof(rx) - 1); // Fix RX Buffer Length - rxpos -= sizeof(SceNetAdhocctlScanPacketS2C); + rxpos -= 1; } } - - // Scan Complete Packet - else if (rx[0] == OPCODE_SCAN_COMPLETE) { - DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN_COMPLETE"); - // Log Scan Completion - INFO_LOG(SCENET, "FriendFinder: Incoming Scan complete response..."); - - // Reset current networks to prevent leaving host to be listed again - peerlock.lock(); - freeGroupsRecursive(networks); - networks = newnetworks; - newnetworks = NULL; - peerlock.unlock(); - - // Change State - threadStatus = ADHOCCTL_STATE_DISCONNECTED; - - // Notify Event Handlers - notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0); - //int i = 0; for(; i < ADHOCCTL_MAX_HANDLER; i++) - //{ - // // Active Handler - // if(_event_handler[i] != NULL) _event_handler[i](ADHOCCTL_EVENT_SCAN, 0, _event_args[i]); - //} - - // Move RX Buffer - memmove(rx, rx + 1, sizeof(rx) - 1); - - // Fix RX Buffer Length - rxpos -= 1; - } } - // Original value was 10 ms, I think 100 is just fine - sleep_ms(1); // Using 1ms for faster response just like AdhocServer + // This delay time should be 100ms when there is an event otherwise 500ms ? + sleep_ms(10); // Using 1ms for faster response just like AdhocServer? // Don't do anything if it's paused, otherwise the log will be flooded - while (Core_IsStepping() && friendFinderRunning) sleep_ms(1); + while (Core_IsStepping() && coreState != CORE_POWERDOWN && friendFinderRunning) sleep_ms(10); } // Groups/Networks should be deallocated isn't? // Prevent the games from having trouble to reInitiate Adhoc (the next NetInit -> PdpCreate after NetTerm) - threadStatus = ADHOCCTL_STATE_DISCONNECTED; + adhocctlState = ADHOCCTL_STATE_DISCONNECTED; // Log Shutdown INFO_LOG(SCENET, "FriendFinder: End of Friend Finder Thread"); @@ -1350,7 +1692,7 @@ int friendFinder(){ return 0; } -int getActivePeerCount(void) { +int getActivePeerCount(const bool excludeTimedout) { // Counter int count = 0; @@ -1364,50 +1706,101 @@ int getActivePeerCount(void) { // Iterate Peers for (; peer != NULL; peer = peer->next) { - // Increase Counter - count++; + // Increase Counter, Should we exclude peers pending for timed out? + if (!excludeTimedout || peer->last_recv != 0) + count++; } // Return Result return count; } -int getLocalIp(sockaddr_in * SocketAddress){ +int getLocalIp(sockaddr_in* SocketAddress) { + if (metasocket != (int)INVALID_SOCKET) { + struct sockaddr_in localAddr; + localAddr.sin_addr.s_addr = INADDR_ANY; + socklen_t addrLen = sizeof(localAddr); + int ret = getsockname(metasocket, (struct sockaddr*)&localAddr, &addrLen); + if (SOCKET_ERROR != ret) { + if (isLocalServer) { + localAddr.sin_addr = g_localhostIP.in.sin_addr; + } + SocketAddress->sin_addr = localAddr.sin_addr; + return 0; + } + } + +// Fallback if not connected to AdhocServer #if defined(_WIN32) // Get local host name - char szHostName[256] = ""; //128 + char szHostName[256] = ""; - if(::gethostname(szHostName, sizeof(szHostName))) { + if (::gethostname(szHostName, sizeof(szHostName))) { // Error handling } // Get local IP addresses - struct hostent *pHost = 0; - pHost = ::gethostbyname(szHostName); - if(pHost) { + struct hostent* pHost = 0; + pHost = ::gethostbyname(szHostName); // On Non-Windows (UNIX/POSIX) gethostbyname("localhost") will always returns a useless 127.0.0.1, while on Windows it returns LAN IP when available + if (pHost) { memcpy(&SocketAddress->sin_addr, pHost->h_addr_list[0], pHost->h_length); - if (/*PPSSPP_ID > 1 && SocketAddress->sin_addr.S_un.S_un_b.s_b1 == 0x7f*/isLocalServer) { - //SocketAddress->sin_addr.S_un.S_un_b.s_b4 = PPSSPP_ID; - SocketAddress->sin_addr = ((sockaddr_in *)&localIP)->sin_addr; + if (isLocalServer) { + SocketAddress->sin_addr = g_localhostIP.in.sin_addr; } return 0; } return -1; -#else - //memcpy(&SocketAddress->sin_addr, &localip, sizeof(uint32_t)); - //return 0; - char szHostName[256] = ""; - gethostname(szHostName, sizeof(szHostName)); - struct hostent *pHost = 0; - pHost = gethostbyname(szHostName); - if (pHost) { - memcpy(&SocketAddress->sin_addr, pHost->h_addr_list[0], pHost->h_length); - if (/*PPSSPP_ID > 1 && SocketAddress->sin_addr.S_un.S_un_b.s_b1 == 0x7f*/isLocalServer) { - //SocketAddress->sin_addr.S_un.S_un_b.s_b4 = PPSSPP_ID; - SocketAddress->sin_addr = ((sockaddr_in *)&localIP)->sin_addr; + +#elif defined(getifaddrs) // On Android: Requires __ANDROID_API__ >= 24 + struct ifaddrs* ifAddrStruct = NULL; + struct ifaddrs* ifa = NULL; + + getifaddrs(&ifAddrStruct); + if (ifAddrStruct != NULL) { + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) { + continue; + } + if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 + // is a valid IP4 Address + SocketAddress->sin_addr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr; + break; + } + } + freeifaddrs(ifAddrStruct); + if (isLocalServer) { + SocketAddress->sin_addr = g_localhostIP.in.sin_addr; } return 0; } - //SocketAddress->sin_addr.s_addr = inet_addr("127.0.0.1"); //192.168.12.1 + return -1; + +#else // Alternative way + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock != SOCKET_ERROR) { + const char* kGoogleDnsIp = "8.8.8.8"; // Needs to be an IP string so it can be resolved as fast as possible to IP, doesn't need to be reachable + uint16_t kDnsPort = 53; + struct sockaddr_in serv; + memset(&serv, 0, sizeof(serv)); + serv.sin_family = AF_INET; + serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp); + serv.sin_port = htons(kDnsPort); + + int err = connect(sock, (const sockaddr*)&serv, sizeof(serv)); + if (err != SOCKET_ERROR) { + sockaddr_in name; + socklen_t namelen = sizeof(name); + err = getsockname(sock, (sockaddr*)&name, &namelen); + if (err != SOCKET_ERROR) { + SocketAddress->sin_addr = name.sin_addr; // May be we should cache this so it doesn't need to use connect all the time, or even better cache it when connecting to adhoc server to get an accurate IP + closesocket(sock); + if (isLocalServer) { + SocketAddress->sin_addr = g_localhostIP.in.sin_addr; + } + return 0; + } + } + closesocket(sock); + } return -1; #endif } @@ -1417,20 +1810,51 @@ uint32_t getLocalIp(int sock) { localAddr.sin_addr.s_addr = INADDR_ANY; socklen_t addrLen = sizeof(localAddr); getsockname(sock, (struct sockaddr*)&localAddr, &addrLen); - if (/*PPSSPP_ID > 1 && localAddr.sin_addr.S_un.S_un_b.s_b1 == 0x7f*/isLocalServer) { - //localAddr.sin_addr.S_un.S_un_b.s_b4 = PPSSPP_ID; - localAddr.sin_addr = ((sockaddr_in *)&localIP)->sin_addr; + if (isLocalServer) { + localAddr.sin_addr = g_localhostIP.in.sin_addr; } return localAddr.sin_addr.s_addr; } +static std::vector> InitPrivateIPRanges() { + struct sockaddr_in saNet, saMask; + std::vector> ip_ranges; + + if (1 == inet_pton(AF_INET, "192.168.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.255.0.0", &(saMask.sin_addr))) + ip_ranges.push_back({saNet.sin_addr.s_addr, saMask.sin_addr.s_addr}); + if (1 == inet_pton(AF_INET, "172.16.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.240.0.0", &(saMask.sin_addr))) + ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr }); + if (1 == inet_pton(AF_INET, "10.0.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.0.0.0", &(saMask.sin_addr))) + ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr }); + if (1 == inet_pton(AF_INET, "127.0.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.0.0.0", &(saMask.sin_addr))) + ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr }); + if (1 == inet_pton(AF_INET, "169.254.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.255.0.0", &(saMask.sin_addr))) + ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr }); + + return ip_ranges; +} + +bool isPrivateIP(uint32_t ip) { + static const std::vector> ip_ranges = InitPrivateIPRanges(); + for (auto ipRange : ip_ranges) { + if ((ip & ipRange.second) == (ipRange.first & ipRange.second)) // We can just use ipRange.first directly if it's already correctly formatted + return true; + } + return false; +} + void getLocalMac(SceNetEtherAddr * addr){ // Read MAC Address from config uint8_t mac[ETHER_ADDR_LEN] = {0}; if (PPSSPP_ID > 1) { memset(&mac, PPSSPP_ID, sizeof(mac)); - } else if (!ParseMacAddress(g_Config.sMACAddress.c_str(), mac)) { + // Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo) + mac[0] &= 0xfc; + } + else + if (!ParseMacAddress(g_Config.sMACAddress.c_str(), mac)) { ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); + memset(&mac, 0, sizeof(mac)); } memcpy(addr, mac, ETHER_ADDR_LEN); } @@ -1443,8 +1867,27 @@ uint16_t getLocalPort(int sock) { return ntohs(localAddr.sin_port); } +u_long getAvailToRecv(int sock) { + u_long n = 0; // Typical MTU size is 1500 +#if defined(_WIN32) // May not be available on all platform + ioctlsocket(sock, FIONREAD, &n); +#else + ioctl(sock, FIONREAD, &n); +#endif + return n; +} + +int getSockMaxSize(int udpsock) { + int n = PSP_ADHOC_PDP_MTU; // Typical MTU size is 1500 +#if defined(SO_MAX_MSG_SIZE) // May not be available on all platform + socklen_t m = sizeof(n); + getsockopt(udpsock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*)&n, &m); +#endif + return n; +} + int getSockBufferSize(int sock, int opt) { // opt = SO_RCVBUF/SO_SNDBUF - int n = 16384; + int n = PSP_ADHOC_PDP_MFS; // 16384; socklen_t m = sizeof(n); getsockopt(sock, SOL_SOCKET, opt, (char *)&n, &m); // in linux the value is twice of the value being set using setsockopt return (n/2); @@ -1455,6 +1898,73 @@ int setSockBufferSize(int sock, int opt, int size) { // opt = SO_RCVBUF/SO_SNDBU return setsockopt(sock, SOL_SOCKET, opt, (char *)&n, sizeof(n)); } +int setSockTimeout(int sock, int opt, unsigned long timeout_usec) { // opt = SO_SNDTIMEO/SO_RCVTIMEO + if (timeout_usec > 0 && timeout_usec < minSocketTimeoutUS) timeout_usec = minSocketTimeoutUS; // Override timeout for high latency multiplayer +#if defined(_WIN32) + unsigned long optval = timeout_usec / 1000UL; + if (timeout_usec > 0 && optval == 0) optval = 1; // Since there are games that use 100 usec timeout, we should set it to minimum value on Windows (1 msec) instead of using 0 (0 = indefinitely timeout) +#elif defined(__APPLE__) + struct timeval optval; + optval.tv_sec = static_cast(timeout_usec) / 1000000L; + optval.tv_usec = static_cast(timeout_usec) % 1000000L; +#else + struct timeval optval = { static_cast(timeout_usec) / 1000000L, static_cast(timeout_usec) % 1000000L }; +#endif + return setsockopt(sock, SOL_SOCKET, opt, (char*)&optval, sizeof(optval)); +} + +int getSockNoDelay(int tcpsock) { + int opt = 0; + socklen_t optlen = sizeof(opt); + getsockopt(tcpsock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, &optlen); + return opt; +} + +int setSockNoDelay(int tcpsock, int flag) { + int opt = flag; + return setsockopt(tcpsock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); +} + +int setSockNoSIGPIPE(int sock, int flag) { + // Set SIGPIPE when supported (ie. BSD/MacOS X) + int opt = flag; +#if defined(SO_NOSIGPIPE) + return setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)); +#endif + return -1; +} + +int setSockReuseAddrPort(int sock) { + int opt = 1; + // Should we set SO_BROADCAST too for SO_REUSEADDR to works like SO_REUSEPORT ? + // Set SO_REUSEPORT also when supported (ie. Android) +#if defined(SO_REUSEPORT) + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&opt, sizeof(opt)); +#endif + return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)); +} + +#if !defined(TCP_KEEPIDLE) +#define TCP_KEEPIDLE TCP_KEEPALIVE //TCP_KEEPIDLE on Linux is equivalent to TCP_KEEPALIVE on macOS +#endif +int setSockKeepAlive(int sock, bool keepalive, const int keepinvl, const int keepcnt, const int keepidle) { + int optval = keepalive ? 1 : 0; + int optlen = sizeof(optval); + int result = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, optlen); + if (result == 0 && keepalive) { + if (getsockopt(sock, SOL_SOCKET, SO_TYPE, (char*)&optval, (socklen_t*)&optlen) == 0 && optval == SOCK_STREAM) { + optlen = sizeof(optval); + optval = keepidle; //180 sec + setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&optval, optlen); + optval = keepinvl; //60 sec + setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&optval, optlen); + optval = keepcnt; //20 + setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (char*)&optval, optlen); + } + } + return result; +} + /** * Return the Number of Players with the chosen Nickname in the Local Users current Network * @param nickname To-be-searched Nickname @@ -1466,7 +1976,7 @@ int getNicknameCount(const char * nickname) int count = 0; // Local Nickname Matches - if (strcmp((char *)parameter.nickname.data, nickname) == 0) count++; + if (strncmp((char *)¶meter.nickname.data, nickname, ADHOCCTL_NICKNAME_LEN) == 0) count++; // Peer Reference SceNetAdhocctlPeerInfo * peer = friends; @@ -1475,7 +1985,7 @@ int getNicknameCount(const char * nickname) for (; peer != NULL; peer = peer->next) { // Match found - if (strcmp((char *)peer->nickname.data, nickname) == 0) count++; + if (strncmp((char *)&peer->nickname.data, nickname, ADHOCCTL_NICKNAME_LEN) == 0) count++; } // Return Result @@ -1486,104 +1996,101 @@ int getNicknameCount(const char * nickname) * PDP Socket Counter * @return Number of internal PDP Sockets */ -int getPDPSocketCount(void) +int getPDPSocketCount() { // Socket Counter int counter = 0; // Count Sockets - int i = 0; for (; i < 255; i++) if (pdp[i] != NULL) counter++; + for (int i = 0; i < MAX_SOCKET; i++) + if (adhocSockets[i] != NULL && adhocSockets[i]->type == SOCK_PDP) + counter++; // Return Socket Count return counter; } -int getPTPSocketCount(void) { +int getPTPSocketCount() { // Socket Counter int counter = 0; // Count Sockets - int i = 0; for (; i < 255; i++) if (ptp[i] != NULL) counter++; + for (int i = 0; i < MAX_SOCKET; i++) + if (adhocSockets[i] != NULL && adhocSockets[i]->type == SOCK_PTP) + counter++; // Return Socket Count return counter; } int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ + auto n = GetI18NCategory("Networking"); int iResult = 0; metasocket = (int)INVALID_SOCKET; metasocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (metasocket == INVALID_SOCKET){ ERROR_LOG(SCENET, "Invalid socket"); - return -1; + return SOCKET_ERROR; } - struct sockaddr_in server_addr; - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(SERVER_PORT); //27312 // Maybe read this from config too + setSockKeepAlive(metasocket, true); + // Disable Nagle Algo to prevent delaying small packets + setSockNoDelay(metasocket, 1); + // Switch to Nonblocking Behaviour + changeBlockingMode(metasocket, 1); - // Resolve dns - addrinfo * resultAddr; - addrinfo * ptr; - in_addr serverIp; - serverIp.s_addr = INADDR_NONE; - - iResult = getaddrinfo(g_Config.proAdhocServer.c_str(),0,NULL,&resultAddr); - if (iResult != 0) { - ERROR_LOG(SCENET, "DNS Error (%s)\n", g_Config.proAdhocServer.c_str()); - host->NotifyUserMessage("DNS Error connecting to " + g_Config.proAdhocServer, 8.0f); - return iResult; - } - for (ptr = resultAddr; ptr != NULL; ptr = ptr->ai_next) { - switch (ptr->ai_family) { - case AF_INET: - serverIp = ((sockaddr_in *)ptr->ai_addr)->sin_addr; - break; - } - } - - freeaddrinfo(resultAddr); - - // If Server is at localhost Try to Bind socket to specific adapter before connecting + // If Server is at localhost Try to Bind socket to specific adapter before connecting to prevent 2nd instance being recognized as already existing 127.0.0.1 by AdhocServer // (may not works in WinXP/2003 for IPv4 due to "Weak End System" model) - if ((serverIp.s_addr & 0xff) == 0x7f) { //serverIp.S_un.S_un_b.s_b1 == 0x7f + if (((uint8_t*)&g_adhocServerIP.in.sin_addr.s_addr)[0] == 0x7f) { // (serverIp.S_un.S_un_b.s_b1 == 0x7f) int on = 1; - setsockopt(metasocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); setsockopt(metasocket, SOL_SOCKET, SO_DONTROUTE, (const char*)&on, sizeof(on)); - // Prepare Local Address Information - /* - struct sockaddr_in local; - memset(&local, 0, sizeof(local)); - local.sin_family = AF_INET; - local.sin_addr = serverIp; - local.sin_addr.S_un.S_un_b.s_b4 = PPSSPP_ID; - //local.sin_port = 0; - */ - ((struct sockaddr_in *)&localIP)->sin_port = 0; + setSockReuseAddrPort(metasocket); + + g_localhostIP.in.sin_port = 0; // Bind Local Address to Socket - iResult = bind(metasocket, (struct sockaddr *)&localIP, sizeof(sockaddr)); + iResult = bind(metasocket, &g_localhostIP.addr, sizeof(sockaddr)); if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "Bind to alternate localhost[%s] failed(%i).", inet_ntoa(((struct sockaddr_in *)&localIP)->sin_addr), iResult); + ERROR_LOG(SCENET, "Bind to alternate localhost[%s] failed(%i).", inet_ntoa(g_localhostIP.in.sin_addr), iResult); + host->NotifyUserMessage(std::string(n->T("Failed to Bind Localhost IP")) + " " + inet_ntoa(g_localhostIP.in.sin_addr), 2.0, 0x0000ff); } - //serverIp = local.sin_addr; } + // Default/Initial Network Parameters memset(¶meter, 0, sizeof(parameter)); - strcpy((char *)¶meter.nickname.data, g_Config.sNickName.c_str()); - parameter.channel = 1; // Fake Channel 1 + strncpy((char *)¶meter.nickname.data, g_Config.sNickName.c_str(), ADHOCCTL_NICKNAME_LEN); + parameter.nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; + parameter.channel = g_Config.iWlanAdhocChannel; + // Assign a Valid Channel when connected to AP/Adhoc if it's Auto. JPCSP use 11 as default for Auto (Commonly for Auto: 1, 6, 11) + if (parameter.channel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) parameter.channel = defaultWlanChannel; // Faked Active channel to default channel getLocalMac(¶meter.bssid.mac_addr); + + // Default ProductId + product_code.type = adhoc_id->type; + memcpy(product_code.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN); - server_addr.sin_addr = serverIp; - iResult = connect(metasocket,(sockaddr *)&server_addr,sizeof(server_addr)); - if (iResult == SOCKET_ERROR) { - uint8_t * sip = (uint8_t *)&server_addr.sin_addr.s_addr; - char buffer[512]; - snprintf(buffer, sizeof(buffer), "Socket error (%i) when connecting to %s/%u.%u.%u.%u:%u", errno, g_Config.proAdhocServer.c_str(), sip[0], sip[1], sip[2], sip[3], ntohs(server_addr.sin_port)); - ERROR_LOG(SCENET, "%s", buffer); - host->NotifyUserMessage(buffer, 8.0f); - return iResult; + // Don't need to connect if AdhocServer DNS was not resolved + if (g_adhocServerIP.in.sin_addr.s_addr == INADDR_NONE) + return -1; + + // Connect to Adhoc Server + int errorcode = 0; + int cnt = 0; + iResult = connect(metasocket, &g_adhocServerIP.addr, sizeof(g_adhocServerIP)); + errorcode = errno; + + if (iResult == SOCKET_ERROR && errorcode != EISCONN) { + u64 startTime = (u64)(time_now_d() * 1000.0); + while (IsSocketReady(metasocket, false, true) <= 0) { + u64 now = (u64)(time_now_d() * 1000.0); + if (coreState == CORE_POWERDOWN) return iResult; + if (now - startTime > adhocDefaultTimeout) break; + sleep_ms(10); + } + if (IsSocketReady(metasocket, false, true) <= 0) { + ERROR_LOG(SCENET, "Socket error (%i) when connecting to AdhocServer [%s/%s:%u]", errorcode, g_Config.proAdhocServer.c_str(), inet_ntoa(g_adhocServerIP.in.sin_addr), ntohs(g_adhocServerIP.in.sin_port)); + host->NotifyUserMessage(n->T("Failed to connect to Adhoc Server"), 1.0f, 0x0000ff); + return iResult; + } } - //grab local ip for later use better than constant ip on non windows platform - localip = getLocalIp(metasocket); // Prepare Login Packet SceNetAdhocctlLoginPacketC2S packet; @@ -1591,25 +2098,30 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ SceNetEtherAddr addres; getLocalMac(&addres); packet.mac = addres; - strcpy((char *)packet.name.data, g_Config.sNickName.c_str()); + strncpy((char *)&packet.name.data, g_Config.sNickName.c_str(), ADHOCCTL_NICKNAME_LEN); + packet.name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN); - int sent = send(metasocket, (char*)&packet, sizeof(packet), 0); - changeBlockingMode(metasocket, 1); // Change to non-blocking + + IsSocketReady(metasocket, false, true, nullptr, adhocDefaultTimeout * 1000); + int sent = send(metasocket, (char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (sent > 0) { - auto n = GetI18NCategory("Networking"); + socklen_t addrLen = sizeof(LocalIP); + memset(&LocalIP, 0, addrLen); + getsockname(metasocket, &LocalIP, &addrLen); host->NotifyUserMessage(n->T("Network Initialized"), 1.0); return 0; } else{ - return -1; + return SOCKET_ERROR; } } +bool isZeroMAC(const SceNetEtherAddr* addr) { + return (memcmp(addr->data, "\x00\x00\x00\x00\x00\x00", ETHER_ADDR_LEN) == 0); +} + bool isBroadcastMAC(const SceNetEtherAddr * addr) { - // Broadcast MAC - if (memcmp(addr->data, "\xFF\xFF\xFF\xFF\xFF\xFF", ETHER_ADDR_LEN) == 0) return true; - // Normal MAC - return false; + return (memcmp(addr->data, "\xFF\xFF\xFF\xFF\xFF\xFF", ETHER_ADDR_LEN) == 0); } bool resolveIP(uint32_t ip, SceNetEtherAddr * mac) { @@ -1617,7 +2129,7 @@ bool resolveIP(uint32_t ip, SceNetEtherAddr * mac) { getLocalIp(&addr); uint32_t localIp = addr.sin_addr.s_addr; - if (ip == localIp || ip == ((sockaddr_in *)&localIP)->sin_addr.s_addr) { + if (ip == localIp || ip == g_localhostIP.in.sin_addr.s_addr) { getLocalMac(mac); return true; } @@ -1655,7 +2167,7 @@ bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) { SceNetEtherAddr localMac; getLocalMac(&localMac); // Local MAC Requested - if (memcmp(&localMac, mac, sizeof(SceNetEtherAddr)) == 0) { + if (isMacMatch(&localMac, mac)) { // Get Local IP Address sockaddr_in sockAddr; getLocalIp(&sockAddr); @@ -1672,7 +2184,7 @@ bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) { // Iterate Peers for (; peer != NULL; peer = peer->next) { // Found Matching Peer - if (memcmp(&peer->mac_addr, mac, sizeof(SceNetEtherAddr)) == 0) { + if (isMacMatch(&peer->mac_addr, mac)) { // Copy Data *ip = peer->ip_addr; @@ -1692,7 +2204,7 @@ bool validNetworkName(const SceNetAdhocctlGroupName * group_name) { // Name given if (group_name != NULL) { // Iterate Name Characters - int i = 0; for (; i < ADHOCCTL_GROUPNAME_LEN && valid; i++) { + for (int i = 0; i < ADHOCCTL_GROUPNAME_LEN && valid; i++) { // End of Name if (group_name->data[i] == 0) break; diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 070ea6f00f..d5997025d5 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -17,25 +17,6 @@ #pragma once -#include -#include - -#include "base/timeutil.h" -#include "net/resolve.h" -#include "Common/ChunkFile.h" - -#include "Core/Config.h" -#include "Core/CoreTiming.h" -#include "Core/MemMap.h" -#include "Core/HLE/HLE.h" -#include "Core/HLE/sceNetAdhoc.h" -#include "Core/HLE/sceKernelThread.h" -#include "Core/HLE/sceKernel.h" -#include "Core/HLE/sceKernelMutex.h" -#include "Core/HLE/sceUtility.h" - -class PointerWrap; - // Net stuff #if defined(_WIN32) #include @@ -57,6 +38,22 @@ class PointerWrap; #define PACK __attribute__((packed)) #endif +#include +#include + +#include "Common/Net/Resolve.h" +#include "Common/Serialize/Serializer.h" + +#include "Core/Config.h" +#include "Core/CoreTiming.h" +#include "Core/MemMap.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/HLEHelperThread.h" +#include "Core/HLE/sceKernelThread.h" +#include "Core/HLE/sceKernel.h" +#include "Core/HLE/sceKernelMutex.h" +#include "Core/HLE/sceUtility.h" + #ifdef _WIN32 #undef errno #undef ECONNABORTED @@ -66,6 +63,7 @@ class PointerWrap; #undef EINPROGRESS #undef EISCONN #undef EALREADY +#undef ETIMEDOUT #define errno WSAGetLastError() #define ECONNABORTED WSAECONNABORTED #define ECONNRESET WSAECONNRESET @@ -74,12 +72,13 @@ class PointerWrap; #define EINPROGRESS WSAEWOULDBLOCK #define EISCONN WSAEISCONN #define EALREADY WSAEALREADY -inline bool connectInProgress(int errcode){ return (errcode == WSAEWOULDBLOCK || errcode == WSAEINVAL || errcode == WSAEALREADY); } +#define ETIMEDOUT WSAETIMEDOUT +inline bool connectInProgress(int errcode){ return (errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS || errcode == WSAEALREADY); } #else #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define closesocket close -inline bool connectInProgress(int errcode){ return (errcode == EINPROGRESS || errcode == EALREADY); } +inline bool connectInProgress(int errcode){ return (errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EALREADY); } #endif #ifndef POLL_ERR @@ -96,25 +95,48 @@ inline bool connectInProgress(int errcode){ return (errcode == EINPROGRESS || er #define POLLPRI POLL_PRI #endif +#ifndef SD_BOTH +#define SD_BOTH SHUT_RDWR //0x02 +#endif + #define IsMatch(buf1, buf2) (memcmp(&buf1, &buf2, sizeof(buf1)) == 0) // Server Listening Port #define SERVER_PORT 27312 +// Default GameMode Port +#define ADHOC_GAMEMODE_PORT 31000 + +#define GAMEMODE_UPDATE_INTERVAL 12000 // usec, based on JPCSP +#define GAMEMODE_BUFFER_SIZE 0x8000 + // psp strutcs and definitions -#define ADHOCCTL_MODE_ADHOC 0 -#define ADHOCCTL_MODE_GAMEMODE 1 +#define ADHOCCTL_MODE_NONE -1 +#define ADHOCCTL_MODE_NORMAL 0 // ADHOCCTL_MODE_ADHOC +#define ADHOCCTL_MODE_GAMEMODE 1 // Event Types for Event Handler +#define ADHOCCTL_EVENT_ERROR 0 #define ADHOCCTL_EVENT_CONNECT 1 #define ADHOCCTL_EVENT_DISCONNECT 2 #define ADHOCCTL_EVENT_SCAN 3 +#define ADHOCCTL_EVENT_GAME 4 +#define ADHOCCTL_EVENT_DISCOVER 5 +#define ADHOCCTL_EVENT_WOL 6 +#define ADHOCCTL_EVENT_WOL_INTERRUPT 7 // Internal Thread States #define ADHOCCTL_STATE_DISCONNECTED 0 #define ADHOCCTL_STATE_CONNECTED 1 #define ADHOCCTL_STATE_SCANNING 2 #define ADHOCCTL_STATE_GAMEMODE 3 +#define ADHOCCTL_STATE_DISCOVER 4 +#define ADHOCCTL_STATE_WOL 5 + +// ProductType ( extracted from SSID along with ProductId & GroupName, Pattern = "PSP_([AXS])(.........)_([LG])_(.*)" ) +#define PSP_ADHOCCTL_TYPE_COMMERCIAL 0 +#define PSP_ADHOCCTL_TYPE_DEBUG 1 +#define PSP_ADHOCCTL_TYPE_SYSTEM 2 // Kernel Utility Netconf Adhoc Types #define UTILITY_NETCONF_TYPE_CONNECT_ADHOC 2 @@ -187,8 +209,8 @@ extern uint8_t broadcastMAC[ETHER_ADDR_LEN]; // Malloc Pool Information typedef struct SceNetMallocStat { - s32_le pool; // Pointer to the pool? - s32_le maximum; // Maximum size of the pool? + s32_le pool; // Pointer to the pool? // This should be the poolSize isn't? + s32_le maximum; // Maximum size of the pool? Maximum usage (ie. pool- free) ? s32_le free; // How much memory is free } PACK SceNetMallocStat; @@ -228,22 +250,24 @@ typedef struct SceNetAdhocctlNickname { uint8_t data[ADHOCCTL_NICKNAME_LEN]; } PACK SceNetAdhocctlNickname; -// Active Virtual Network Information +// Active Virtual Network Information (Adhoc Group Host/Creator's device info, similar to AP?) typedef struct SceNetAdhocctlParameter { s32_le channel; - SceNetAdhocctlGroupName group_name; - SceNetAdhocctlBSSId bssid; - SceNetAdhocctlNickname nickname; + SceNetAdhocctlGroupName group_name; // This group name is probably similar to SSID name on AP + SceNetAdhocctlNickname nickname; // According to the old PSPSDK this is the bssid, but according to the dumped content when using newer firmware this is the nickname (this is also the nickname on VitaSDK) + SceNetAdhocctlBSSId bssid; // FIXME: bssid and nickname position might be swapped on older/newer firmware? } PACK SceNetAdhocctlParameter; -// Peer Information +// Peer Information (internal use only) typedef struct SceNetAdhocctlPeerInfo { SceNetAdhocctlPeerInfo * next; SceNetAdhocctlNickname nickname; SceNetEtherAddr mac_addr; - u32_le ip_addr; - uint8_t padding[2]; + u16_le padding; + u32_le flags; u64_le last_recv; // Need to use the same method with sceKernelGetSystemTimeWide (ie. CoreTiming::GetGlobalTimeUsScaled) to prevent timing issue (ie. in game timeout) + + u32_le ip_addr; // internal use only } PACK SceNetAdhocctlPeerInfo; // Peer Information with u32 pointers @@ -251,8 +275,8 @@ typedef struct SceNetAdhocctlPeerInfoEmu { u32_le next; // Changed the pointer to u32 SceNetAdhocctlNickname nickname; SceNetEtherAddr mac_addr; - u32_le ip_addr; //jpcsp wrote 6bytes of 0x11 for this & padding - u16 padding; // Changed the padding to u16 + u16_le padding; //00 00 + u32_le flags; //00 04 00 00 on KHBBS and FF FF FF FF on Ys vs. Sora no Kiseki // State of the peer? Or related to sceNetAdhocAuth_CF4D9BED ? u64_le last_recv; // Need to use the same method with sceKernelGetSystemTimeWide (ie. CoreTiming::GetGlobalTimeUsScaled) to prevent timing issue (ie. in game timeout) } PACK SceNetAdhocctlPeerInfoEmu; @@ -274,9 +298,27 @@ typedef struct SceNetAdhocMatchingMemberInfoEmu { #define ADHOCCTL_GAMEMODE_MAX_MEMBERS 16 typedef struct SceNetAdhocctlGameModeInfo { s32_le num; - SceNetEtherAddr member[ADHOCCTL_GAMEMODE_MAX_MEMBERS]; + SceNetEtherAddr members[ADHOCCTL_GAMEMODE_MAX_MEMBERS]; } PACK SceNetAdhocctlGameModeInfo; +// GameModeUpdateInfo +typedef struct GameModeUpdateInfo { + s32_le updated; + u64_le timeStamp; +} PACK GameModeUpdateInfo; + +// GameModeArea (Internal use only) +typedef struct GameModeArea { + int id; // started from 1 for replica? master = 0 or -1? + int size; + u32 addr; + //int socket; // PDP socket? + u64 updateTimestamp; + int dataUpdated; + SceNetEtherAddr mac; + u8* data; // upto "size" bytes started from "addr" ? +} PACK GameModeArea; + // Socket Polling Event Listener typedef struct SceNetAdhocPollSd{ s32_le id; @@ -285,27 +327,42 @@ typedef struct SceNetAdhocPollSd{ } PACK SceNetAdhocPollSd; // PDP Socket Status -typedef struct SceNetAdhocPdpStat{ - u32_le next; // struct SceNetAdhocPdpStat * next; - s32_le id; - SceNetEtherAddr laddr; - u16_le lport; - u32_le rcv_sb_cc; +typedef struct SceNetAdhocPdpStat { + u32_le next; + s32_le id; // posix socket id + SceNetEtherAddr laddr; + u16_le lport; + u32_le rcv_sb_cc; // Obscure The Aftermath will check if this is 0 or not before calling PdpRecv, Might to be number of bytes available to be Received? } PACK SceNetAdhocPdpStat; // PTP Socket Status typedef struct SceNetAdhocPtpStat { - u32_le next; // Changed the pointer to u32 - s32_le id; - SceNetEtherAddr laddr; - SceNetEtherAddr paddr; - u16_le lport; - u16_le pport; - s32_le snd_sb_cc; - s32_le rcv_sb_cc; - s32_le state; + u32_le next; // Changed the pointer to u32 + s32_le id; // posix socket id + SceNetEtherAddr laddr; + SceNetEtherAddr paddr; + u16_le lport; + u16_le pport; + s32_le snd_sb_cc; // Number of bytes existed in buffer to be sent/flushed? + s32_le rcv_sb_cc; // Number of bytes available in buffer to be received? + s32_le state; } PACK SceNetAdhocPtpStat; +// PDP & PTP Socket Union (Internal use only) +typedef struct AdhocSocket { + s32_le type; // SOCK_PDP/SOCK_PTP + s32_le flags; // Socket Alert Flags + s32_le alerted_flags; // Socket Alerted Flags + u32 send_timeout; // default connect timeout + u32 recv_timeout; // default accept timeout + s32 retry_count; // combined with timeout to be used on keepalive + s32 attemptCount; // connect/accept attempts + union { + SceNetAdhocPdpStat pdp; + SceNetAdhocPtpStat ptp; + } data; +} PACK AdhocSocket; + // Gamemode Optional Peer Buffer Data typedef struct SceNetAdhocGameModeOptData { u32_le size; @@ -322,9 +379,6 @@ typedef struct SceNetAdhocGameModeBufferStat { u32_le master; SceNetAdhocGameModeOptData opt; } PACK SceNetAdhocGameModeBufferStat; -#ifdef _MSC_VER -#pragma pack(pop) -#endif // Adhoc ID (Game Product Key) #define ADHOCCTL_ADHOCID_LEN 9 @@ -332,7 +386,11 @@ typedef struct SceNetAdhocctlAdhocId { s32_le type; uint8_t data[ADHOCCTL_ADHOCID_LEN]; uint8_t padding[3]; -} SceNetAdhocctlAdhocId; // should this be packed? +} PACK SceNetAdhocctlAdhocId; // should this be packed? +#ifdef _MSC_VER +#pragma pack(pop) +#endif + // Internal Matching Peer Information typedef struct SceNetAdhocMatchingMemberInternal { @@ -444,7 +502,7 @@ typedef struct SceNetAdhocMatchingContext { SceNetAdhocMatchingHandler handler; // Event Handler Args - u32_le handlerArgs[6]; // actual arguments only 5, the 6th one is just for borrowing a space to store the callback address to use later + u32_le handlerArgs[6]; //MatchingArgs handlerArgs; // actual arguments only 5, the 6th one is just for borrowing a space to store the callback address to use later //SceNetAdhocMatchingHandlerArgs handlerArgs; // Hello Data Length @@ -461,15 +519,17 @@ typedef struct SceNetAdhocMatchingContext { // Helper Thread (fake PSP Thread) needed to execute callback //HLEHelperThread *matchingThread; - //SceUID matching_thid; + int matching_thid; // Event Caller Thread - std::thread eventThread; // s32_le event_thid; + std::thread eventThread; + //s32_le event_thid; bool eventRunning = false; bool IsMatchingInCB = false; // IO Handler Thread - std::thread inputThread; // s32_le input_thid; + std::thread inputThread; + //s32_le input_thid; bool inputRunning = false; // Event Caller Thread Message Stack @@ -626,10 +686,10 @@ enum { #define PSP_ADHOC_MATCHING_EVENT_DENY 4 #define PSP_ADHOC_MATCHING_EVENT_CANCEL 5 #define PSP_ADHOC_MATCHING_EVENT_ACCEPT 6 -#define PSP_ADHOC_MATCHING_EVENT_ESTABLISHED 7 -#define PSP_ADHOC_MATCHING_EVENT_TIMEOUT 8 +#define PSP_ADHOC_MATCHING_EVENT_ESTABLISHED 7 // Should only be triggered on Parent/P2P mode and for Parent/P2P peer ? +#define PSP_ADHOC_MATCHING_EVENT_TIMEOUT 8 // Should only be triggered on Parent/P2P mode and for Parent/P2P peer ? #define PSP_ADHOC_MATCHING_EVENT_ERROR 9 -#define PSP_ADHOC_MATCHING_EVENT_BYE 10 +#define PSP_ADHOC_MATCHING_EVENT_BYE 10 // Should only be triggered on Parent/P2P mode and for Parent/P2P peer ? #define PSP_ADHOC_MATCHING_EVENT_DATA 11 #define PSP_ADHOC_MATCHING_EVENT_DATA_ACK 12 #define PSP_ADHOC_MATCHING_EVENT_DATA_TIMEOUT 13 @@ -705,10 +765,11 @@ typedef struct { SceNetAdhocctlGroupName group; } PACK SceNetAdhocctlConnectPacketC2S; +#define ADHOCCTL_MESSAGE_LEN 64 // C2S Chat Packet typedef struct { SceNetAdhocctlPacketBase base; - char message[64]; + char message[ADHOCCTL_MESSAGE_LEN]; } PACK SceNetAdhocctlChatPacketC2S; // S2C Connect Packet @@ -764,77 +825,131 @@ typedef struct { #pragma pack(pop) #endif +class PointerWrap; + +class AfterAdhocMipsCall : public PSPAction { +public: + AfterAdhocMipsCall() {} + static PSPAction* Create() { return new AfterAdhocMipsCall(); } + void DoState(PointerWrap& p) override; + void run(MipsCall& call) override; + void SetData(int handlerID, int eventId, u32_le argsAddr); + +private: + int HandlerID = -1; + int EventID = -1; + u32_le argsAddr = 0; +}; + class AfterMatchingMipsCall : public PSPAction { public: AfterMatchingMipsCall() {} static PSPAction *Create() { return new AfterMatchingMipsCall(); } - void DoState(PointerWrap &p) override { - auto s = p.Section("AfterMatchingMipsCall", 1, 2); - if (!s) - return; - - p.Do(EventID); - //context = NULL; - } + void DoState(PointerWrap &p) override; void run(MipsCall &call) override; - void SetContextID(u32 ContextID, u32 eventId); - void SetContext(SceNetAdhocMatchingContext *Context, u32 eventId) { context = Context; EventID = eventId; } + void SetData(int ContextID, int eventId, u32_le BufAddr); private: - u32 EventID; - SceNetAdhocMatchingContext *context; + int contextID = -1; + int EventID = -1; + u32_le bufAddr = 0; + SceNetAdhocMatchingContext* context = nullptr; }; +extern int actionAfterAdhocMipsCall; extern int actionAfterMatchingMipsCall; -extern bool IsAdhocctlInCB; +#define MAX_SOCKET 255 // FIXME: PSP might not allows more than 255 sockets? Hotshots Tennis doesn't seems to works with socketId > 255 +#define SOCK_PDP 1 +#define SOCK_PTP 2 // Aux vars extern int metasocket; extern SceNetAdhocctlParameter parameter; extern SceNetAdhocctlAdhocId product_code; extern std::thread friendFinderThread; extern std::recursive_mutex peerlock; -extern SceNetAdhocPdpStat * pdp[255]; -extern SceNetAdhocPtpStat * ptp[255]; -extern std::map adhocctlHandlers; +extern AdhocSocket* adhocSockets[MAX_SOCKET]; + +union SockAddrIN4 { + sockaddr addr; + sockaddr_in in; +}; extern bool isLocalServer; extern uint8_t PPSSPP_ID; extern sockaddr localIP; extern uint16_t portOffset; +extern uint32_t minSocketTimeoutUS; +extern bool isOriPort; +extern bool isLocalServer; +extern SockAddrIN4 g_adhocServerIP; // Resolved Adhoc Server IP so we don't need to repeatedly resolve the DNS again later +extern SockAddrIN4 g_localhostIP; // Used to differentiate localhost IP on multiple-instance +extern sockaddr LocalIP; // IP of Network Adapter used to connect to Adhoc Server (LAN/WAN) +extern int defaultWlanChannel; // Default WLAN Channel for Auto, JPCSP uses 11 + extern uint32_t fakePoolSize; extern SceNetAdhocMatchingContext * contexts; extern int one; extern bool friendFinderRunning; extern SceNetAdhocctlPeerInfo * friends; -extern SceNetAdhocctlScanInfo * networks; -extern int threadStatus; +extern SceNetAdhocctlScanInfo * networks; +extern u64 adhocctlStartTime; +extern int adhocctlState; +extern int adhocctlCurrentMode; +extern int adhocConnectionType; + +extern int gameModeSocket; +extern u8* gameModeBuffer; +extern GameModeArea masterGameModeArea; +extern std::vector replicaGameModeAreas; +extern std::vector requiredGameModeMacs; +extern std::vector gameModeMacs; // End of Aux vars +enum AdhocConnectionType : int +{ + ADHOC_CONNECT = 0, + ADHOC_CREATE = 1, + ADHOC_JOIN = 2, +}; + // Check if Matching callback is running bool IsMatchingInCallback(SceNetAdhocMatchingContext * context); +bool SetMatchingInCallback(SceNetAdhocMatchingContext* context, bool IsInCB); + +int IsAdhocctlInCallback(); +int SetAdhocctlInCallback(bool IsInCB); + +/** + * Compare MAC Addresses + * @param addr1 & addr2 To-be-compared MAC Address + * @return True if both matched + */ +bool isMacMatch(const SceNetEtherAddr* addr1, const SceNetEtherAddr* addr2); /** * Local MAC Check * @param saddr To-be-checked MAC Address - * @return 1 if valid or... 0 + * @return True if it's local mac */ -int isLocalMAC(const SceNetEtherAddr * addr); +bool isLocalMAC(const SceNetEtherAddr * addr); /** * PDP Port Check * @param port To-be-checked Port * @return 1 if in use or... 0 */ -int isPDPPortInUse(uint16_t port); +bool isPDPPortInUse(uint16_t port); /** * Check whether PTP Port is in use or not * @param port To-be-checked Port Number * @return 1 if in use or... 0 */ -int isPTPPortInUse(uint16_t port); +bool isPTPPortInUse(uint16_t port); + +std::string mac2str(SceNetEtherAddr* mac); /* * Matching Members @@ -866,6 +981,19 @@ extern int newChat; */ SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC); +/* + * Find a Peer/Friend by IP address + */ +SceNetAdhocctlPeerInfo* findFriendByIP(uint32_t ip); + +/** + * Get the Readability(ie. recv) and/or Writability(ie. send) of a socket + * @param fd File Descriptor of the socket + * @param timeout in usec (micro seconds), 0 = non-blocking + * @return > 0 = ready, 0 = timeout, -1 = error (errorcode only represent error of select and doesn't represent error of the socket) + */ +int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode = nullptr, int timeoutUS = 0); + /** * Changes the Blocking Mode of the socket * @param fd File Descriptor of the socket @@ -890,14 +1018,14 @@ SceNetAdhocctlScanInfo * findGroup(SceNetEtherAddr * MAC); void freeGroupsRecursive(SceNetAdhocctlScanInfo * node); /** - * Closes & Deletes all PDP Sockets + * Closes & Deletes all PDP & PTP Sockets */ -void deleteAllPDP(void); +void deleteAllAdhocSockets(); -/** - * Closes & Deletes all PTP sockets - */ -void deleteAllPTP(void); +/* +* Deletes all GameMode Buffers +*/ +void deleteAllGMB(); /** * Delete Friend from Local List @@ -909,7 +1037,9 @@ void deleteFriendByIP(uint32_t ip); * Recursive Memory Freeing-Helper for Friend-Structures * @param node Current Node in List */ -void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node); +void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node, int32_t* count = nullptr); + +void timeoutFriendsRecursive(SceNetAdhocctlPeerInfo * node, int32_t* count = nullptr); /** * Friend Finder Thread (Receives Peer Information) @@ -923,7 +1053,7 @@ int friendFinder(); * Find Free Matching ID * @return First unoccupied Matching ID */ -int findFreeMatchingID(void); +int findFreeMatchingID(); /** * Find Internal Matching Context for Matching ID @@ -935,7 +1065,7 @@ SceNetAdhocMatchingContext * findMatchingContext(int id); /* * Notify Matching Event Handler */ -void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * msg, void * opt, u32 &bufAddr, u32 &bufLen, u32_le * args); +void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * msg, void * opt, u32_le &bufAddr, u32_le &bufLen, u32_le * args); // Notifiy Adhocctl Handlers void notifyAdhocctlHandlers(u32 flag, u32 error); @@ -1032,14 +1162,14 @@ void sendDeathMessage(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingM * @param context Matching Context Pointer * @return Number of Children */ -s32_le countChildren(SceNetAdhocMatchingContext * context); +s32_le countChildren(SceNetAdhocMatchingContext * context, const bool excludeTimedout = false); /** * Delete Peer from List * @param context Matching Context Pointer * @param peer Internal Peer Reference */ -void deletePeer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer); +void deletePeer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal *& peer); /** * Find Peer in Context by MAC @@ -1061,14 +1191,14 @@ SceNetAdhocMatchingMemberInternal * findParent(SceNetAdhocMatchingContext * cont * @param context Matching Context Pointer * @return Internal Peer Reference or... NULL */ -SceNetAdhocMatchingMemberInternal * findP2P(SceNetAdhocMatchingContext * context); +SceNetAdhocMatchingMemberInternal * findP2P(SceNetAdhocMatchingContext * context, const bool excludeTimedout = false); /** * Return Number of Connected Peers * @param context Matching Context Pointer * @return Number of Connected Peers */ -uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context); +uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context, const bool excludeTimedout = false); /** * Spawn Local Event for Event Thread @@ -1095,15 +1225,30 @@ void spawnLocalEvent(SceNetAdhocMatchingContext * context, int event, SceNetEthe * Return Number of active Peers in the same Network as the Local Player * @return Number of active Peers */ -int getActivePeerCount(void); +int getActivePeerCount(const bool excludeTimedout = true); /** - * Returns the locall Ip of this machine, TODO: Implement the linux version + * Returns the locall Ip of this machine * @param SocketAddres OUT: local ip */ int getLocalIp(sockaddr_in * SocketAddress); uint32_t getLocalIp(int sock); +/* + * Check if an IP (big-endian/network order) is Private or Public IP + */ +bool isPrivateIP(uint32_t ip); + +/* + * Get Number of bytes available in buffer to be Received + */ +u_long getAvailToRecv(int sock); + +/* + * Get UDP Socket Max Message Size + */ +int getSockMaxSize(int udpsock); + /* * Get Socket Buffer Size (opt = SO_RCVBUF/SO_SNDBUF) */ @@ -1114,6 +1259,36 @@ int getSockBufferSize(int sock, int opt); */ int setSockBufferSize(int sock, int opt, int size); +/* +* Set Socket TimeOut (opt = SO_SNDTIMEO/SO_RCVTIMEO) +*/ +int setSockTimeout(int sock, int opt, unsigned long timeout_usec); + +/* + * Get TCP Socket TCP_NODELAY (Nagle Algo) + */ +int getSockNoDelay(int tcpsock); + +/* +* Set TCP Socket TCP_NODELAY (Nagle Algo) +*/ +int setSockNoDelay(int tcpsock, int flag); + +/* +* Set Socket SO_NOSIGPIPE when supported +*/ +int setSockNoSIGPIPE(int sock, int flag); + +/* +* Set Socket SO_REUSEADDR and SO_REUSEPORT when supported +*/ +int setSockReuseAddrPort(int sock); + +/* +* Set Socket KeepAlive (opt = SO_KEEPALIVE) +*/ +int setSockKeepAlive(int sock, bool keepalive, const int keepinvl = 60, const int keepcnt = 20, const int keepidle = 180); + /** * Return the Number of Players with the chosen Nickname in the Local Users current Network * @param nickname To-be-searched Nickname @@ -1140,8 +1315,8 @@ u64 join32(u32 num1, u32 num2); void split64(u64 num, int buff[]); /** - * Returns the local mac, TODO: Read from Config file - * @param addr OUT: Local Mac + * Returns the local mac + * @param addr OUT: 6-bytes of Local Mac */ void getLocalMac(SceNetEtherAddr * addr); @@ -1154,13 +1329,13 @@ uint16_t getLocalPort(int sock); * PDP Socket Counter * @return Number of internal PDP Sockets */ -int getPDPSocketCount(void); +int getPDPSocketCount(); /** * PTP Socket Counter * @return Number of internal PTP Sockets */ -int getPTPSocketCount(void); +int getPTPSocketCount(); /** * Initialize Networking Components for Adhocctl Emulator @@ -1170,6 +1345,13 @@ int getPTPSocketCount(void); */ int initNetwork(SceNetAdhocctlAdhocId *adhocid); +/** + * Zero MAC Check + * @param addr To-be-checked MAC Address + * @return true if MAC is all zeroes + */ +bool isZeroMAC(const SceNetEtherAddr* addr); + /** * Broadcast MAC Check * @param addr To-be-checked MAC Address diff --git a/Core/HLE/proAdhocServer.cpp b/Core/HLE/proAdhocServer.cpp index 84dc131564..4a2750f20f 100644 --- a/Core/HLE/proAdhocServer.cpp +++ b/Core/HLE/proAdhocServer.cpp @@ -37,15 +37,27 @@ #else #include #include +#include #endif #include #include //#include -#include "Common/FileUtil.h" -#include "Core/Core.h" -#include "Core/HLE/proAdhocServer.h" +#ifndef MSG_NOSIGNAL +// Default value to 0x00 (do nothing) in systems where it's not supported. +#define MSG_NOSIGNAL 0x00 +#endif + +#include "Common/Data/Text/I18n.h" +#include "Common/Thread/ThreadUtil.h" + +#include "Common/File/FileUtil.h" +#include "Common/TimeUtil.h" +#include "Core/Util/PortManager.h" +#include "Core/Core.h" +#include "Core/Host.h" +#include "Core/HLE/proAdhocServer.h" // User Count uint32_t _db_user_count = 0; @@ -487,6 +499,8 @@ const char * strcpyxml(char * out, const char * in, uint32_t size); // Function Prototypes void interrupt(int sig); void enable_address_reuse(int fd); +void enable_keepalive(int fd); +void change_nodelay_mode(int fd, int flag); void change_blocking_mode(int fd, int nonblocking); int create_listen_socket(uint16_t port); int server_loop(int server); @@ -507,13 +521,12 @@ void login_user_stream(int fd, uint32_t ip) // Enough Space available if(_db_user_count < SERVER_USER_MAXIMUM) { - // Check IP Duplication as current AdhocServer doesn't receives/broadcasts binded port information having more than 1 players using the same IP will only cause communication interference (sometimes clients bind to specific port on some games) since Reusable port will share the socket buffer when one already read the data the other can't read it anymore (no longer in buffer) + // Check IP Duplication SceNetAdhocctlUserNode * u = _db_user; while(u != NULL && u->resolver.ip != ip) u = u->next; if (u != NULL) { // IP Already existed - uint8_t * ip4 = (uint8_t *)&u->resolver.ip; - WARN_LOG(SCENET, "AdhocServer: Already Existing IP: %u.%u.%u.%u\n", ip4[0], ip4[1], ip4[2], ip4[3]); + WARN_LOG(SCENET, "AdhocServer: Already Existing IP: %s\n", inet_ntoa(*(in_addr*)&u->resolver.ip)); } // Unique IP Address @@ -543,8 +556,7 @@ void login_user_stream(int fd, uint32_t ip) user->last_recv = time(NULL); // Notify User - uint8_t * ipa = (uint8_t *)&user->resolver.ip; - INFO_LOG(SCENET, "AdhocServer: New Connection from %u.%u.%u.%u", ipa[0], ipa[1], ipa[2], ipa[3]); + INFO_LOG(SCENET, "AdhocServer: New Connection from %s", inet_ntoa(*(in_addr*)&user->resolver.ip)); // Fix User Counter _db_user_count++; @@ -558,7 +570,7 @@ void login_user_stream(int fd, uint32_t ip) } } - // Duplicate IP/MAC, Allocation Error or not enough space - Close Stream + // Duplicate IP, Allocation Error or not enough space - Close Stream closesocket(fd); } @@ -583,26 +595,11 @@ void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S if(valid_product_code == 1 && memcmp(&data->mac, "\xFF\xFF\xFF\xFF\xFF\xFF", sizeof(data->mac)) != 0 && memcmp(&data->mac, "\x00\x00\x00\x00\x00\x00", sizeof(data->mac)) != 0 && data->name.data[0] != 0) { // Check for duplicated MAC as most games identify Players by MAC - SceNetAdhocctlUserNode * u = _db_user; + SceNetAdhocctlUserNode* u = _db_user; while (u != NULL && !IsMatch(u->resolver.mac, data->mac)) u = u->next; - if (u != NULL) { // MAC Already existed - /* - u32_le sip = user->resolver.ip; - // 127.0.0.1 should be replaced with LAN/WAN IP whenever available to make sure remote players can communicate with current (local) player - // It might be better if the client connects to AdhocServer using the correct interface instead of automatically changing the IP which might not be accurate on multihomed computer. - if (sip == 0x0100007f) { - char str[256]; - gethostname(str, 256); - u8 *pip = (u8*)&sip; - struct hostent *pHost = 0; - pHost = gethostbyname(str); - if (pHost->h_addrtype == AF_INET && pHost->h_addr_list[0] != NULL) pip = (u8*)pHost->h_addr_list[0]; - user->resolver.ip = *(u32_le*)pip; - WARN_LOG(SCENET, "AdhocServer: Replacing IP %u.%u.%u.%u with %u.%u.%u.%u", ((u8*)&sip)[0], ((u8*)&sip)[1], ((u8*)&sip)[2], ((u8*)&sip)[3], pip[0], pip[1], pip[2], pip[3]); - } - */ - uint8_t * ip4 = (uint8_t *)&u->resolver.ip; - WARN_LOG(SCENET, "AdhocServer: Already Existing MAC: %02X:%02X:%02X:%02X:%02X:%02X [%u.%u.%u.%u]\n", data->mac.data[0], data->mac.data[1], data->mac.data[2], data->mac.data[3], data->mac.data[4], data->mac.data[5], ip4[0], ip4[1], ip4[2], ip4[3]); + + if (u != NULL) { // MAC Already existed + WARN_LOG(SCENET, "AdhocServer: Already Existing MAC: %02x:%02x:%02x:%02x:%02x:%02x [%s]\n", data->mac.data[0], data->mac.data[1], data->mac.data[2], data->mac.data[3], data->mac.data[4], data->mac.data[5], inet_ntoa(*(in_addr*)&u->resolver.ip)); } // Game Product Override @@ -650,11 +647,10 @@ void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S user->game = game; // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) started playing %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr); + INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) started playing %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr); // Update Status Log update_status(); @@ -668,8 +664,7 @@ void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; - INFO_LOG(SCENET, "AdhocServer: Invalid Login Packet Contents from %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + WARN_LOG(SCENET, "AdhocServer: Invalid Login Packet Contents from %s", inet_ntoa(*(in_addr*)&user->resolver.ip)); } // Logout User - Out of Memory or Invalid Arguments @@ -701,11 +696,10 @@ void logout_user(SceNetAdhocctlUserNode * user) if(user->game != NULL) { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) stopped playing %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr); + INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) stopped playing %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr); // Fix Game Player Count user->game->playercount--; @@ -725,10 +719,13 @@ void logout_user(SceNetAdhocctlUserNode * user) // Free Game Node Memory free(user->game); } - } else { // Unidentified User + } + + // Unidentified User + else + { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; - INFO_LOG(SCENET, "AdhocServer: Dropped Connection to %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + WARN_LOG(SCENET, "AdhocServer: Dropped Connection to %s", inet_ntoa(*(in_addr*)&user->resolver.ip)); } // Free Memory @@ -744,7 +741,7 @@ void logout_user(SceNetAdhocctlUserNode * user) /** * Free Database Memory */ -void free_database(void) +void free_database() { // There are users playing if(_db_user_count > 0) @@ -871,7 +868,7 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group packet.ip = user->resolver.ip; // Send Data - int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), 0); + int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: connect_user[send peer] (Socket error %d)", errno); // Set Player Name @@ -884,7 +881,7 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group packet.ip = peer->resolver.ip; // Send Data - iResult = send(user->stream, (const char*)&packet, sizeof(packet), 0); + iResult = send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: connect_user[send user] (Socket error %d)", errno); // Set BSSID @@ -906,18 +903,17 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group g->playercount++; // Send Network BSSID to User - int iResult = send(user->stream, (const char*)&bssid, sizeof(bssid), 0); + int iResult = send(user->stream, (const char*)&bssid, sizeof(bssid), MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: connect_user[send user bssid] (Socket error %d)", errno); // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) joined %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr, safegroupstr); + INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) joined %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr, safegroupstr); // Update Status Log update_status(); @@ -931,7 +927,6 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); @@ -941,7 +936,7 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group char safegroupstr2[9]; memset(safegroupstr2, 0, sizeof(safegroupstr2)); strncpy(safegroupstr2, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to join %s group %s without disconnecting from %s first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr, safegroupstr, safegroupstr2); + WARN_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to join %s group %s without disconnecting from %s first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr, safegroupstr, safegroupstr2); } } @@ -949,14 +944,13 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)group->data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to join invalid %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr, safegroupstr); + WARN_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to join invalid %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr, safegroupstr); } // Invalid State, Out of Memory or Invalid Group Name @@ -1001,7 +995,7 @@ void disconnect_user(SceNetAdhocctlUserNode * user) packet.ip = user->resolver.ip; // Send Data - int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), 0); + int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: disconnect_user[send peer] (Socket error %d)", errno); // Move Pointer @@ -1009,14 +1003,13 @@ void disconnect_user(SceNetAdhocctlUserNode * user) } // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) left %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr, safegroupstr); + INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) left %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr, safegroupstr); // Empty Group if(user->group->playercount == 0) @@ -1053,11 +1046,10 @@ void disconnect_user(SceNetAdhocctlUserNode * user) else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to leave %s group without joining one first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr); + WARN_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to leave %s group without joining one first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr); } // Delete User @@ -1102,21 +1094,20 @@ void send_scan_results(SceNetAdhocctlUserNode * user) } // Send Group Packet - int iResult = send(user->stream, (const char*)&packet, sizeof(packet), 0); + int iResult = send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: send_scan_result[send user] (Socket error %d)", errno); } // Notify Player of End of Scan uint8_t opcode = OPCODE_SCAN_COMPLETE; - int iResult = send(user->stream, (const char*)&opcode, 1, 0); + int iResult = send(user->stream, (const char*)&opcode, 1, MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: send_scan_result[send peer complete] (Socket error %d)", errno); // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) requested information on %d %s groups", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], user->game->groupcount, safegamestr); + INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) requested information on %d %s groups", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), user->game->groupcount, safegamestr); // Exit Function return; @@ -1126,14 +1117,13 @@ void send_scan_results(SceNetAdhocctlUserNode * user) else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to scan for %s groups without disconnecting from %s first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr, safegroupstr); + WARN_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to scan for %s groups without disconnecting from %s first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr, safegroupstr); } // Delete User @@ -1169,7 +1159,7 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) strcpy(packet.base.message, message); // Send Data - int iResult = send(user->stream, (const char*)&packet, sizeof(packet), 0); + int iResult = send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: spread_message[send user chat] (Socket error %d)", errno); } } @@ -1211,7 +1201,7 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) packet.name = user->resolver.name; // Send Data - int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), 0); + int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: spread_message[send peer chat] (Socket error %d)", errno); // Move Pointer @@ -1225,14 +1215,13 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) if(counter > 0) { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) sent \"%s\" to %d players in %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], message, counter, safegamestr, safegroupstr); + INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) sent \"%s\" to %d players in %s group %s", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), message, counter, safegamestr, safegroupstr); } // Exit Function @@ -1243,11 +1232,10 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to send a text message without joining a %s group first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3], safegamestr); + WARN_LOG(SCENET, "AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to send a text message without joining a %s group first", (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip), safegamestr); } // Delete User @@ -1442,7 +1430,7 @@ void game_product_override(SceNetAdhocctlProductCode * product) /** * Update Status Logfile */ -void update_status(void) +void update_status() { // Open Logfile FILE * log = File::OpenCFile(SERVER_STATUS_XMLOUT, "w"); @@ -1697,6 +1685,7 @@ const char * strcpyxml(char * out, const char * in, uint32_t size) */ int proAdhocServerThread(int port) // (int argc, char * argv[]) { + setCurrentThreadName("AdhocServer"); // Result int result = 0; @@ -1712,14 +1701,20 @@ int proAdhocServerThread(int port) // (int argc, char * argv[]) int server = create_listen_socket(port); //SERVER_PORT // Created Listening Socket - if(server != -1) + if(server != SOCKET_ERROR) { // Notify User INFO_LOG(SCENET, "AdhocServer: Listening for Connections on TCP Port %u", port); //SERVER_PORT + // Port forward + UPnP_Add(IP_PROTOCOL_TCP, port); // g_PortManager.Add(IP_PROTOCOL_TCP, port); + // Enter Server Loop result = server_loop(server); + // Remove Port mapping + UPnP_Remove(IP_PROTOCOL_TCP, port); // g_PortManager.Remove(IP_PROTOCOL_TCP, port); + // Notify User INFO_LOG(SCENET, "AdhocServer: Shutdown complete"); } @@ -1752,12 +1747,33 @@ void interrupt(int sig) * @param fd Socket */ void enable_address_reuse(int fd) +{ + // Enable Port Reuse + setSockReuseAddrPort(fd); +} + +/** + * Enable KeepAlive on Socket + * @param fd Socket + */ +void enable_keepalive(int fd) { // Enable Value int on = 1; // Enable Port Reuse - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on)); +} + +/** + * Change TCP Socket TCP_NODELAY (Nagle Algo) mode + * @param fd Socket + * @param nonblocking 1 for Nonblocking, 0 for Blocking + */ +void change_nodelay_mode(int fd, int flag) +{ + int opt = flag; + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); } /** @@ -1807,23 +1823,29 @@ int create_listen_socket(uint16_t port) // Created Socket if(fd != -1) { + // Enable KeepAlive + enable_keepalive(fd); + // Enable Address Reuse enable_address_reuse(fd); // Shouldn't Reuse the port for built-in AdhocServer to prevent conflict with Dedicated AdhocServer // Make Socket Nonblocking change_blocking_mode(fd, 1); + // Make TCP Socket send immediately + change_nodelay_mode(fd, 1); + // Prepare Local Address Information struct sockaddr_in local; memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; - local.sin_addr.s_addr = INADDR_ANY; // bind to all network adapter + local.sin_addr.s_addr = INADDR_ANY; local.sin_port = htons(port); //Should only bind to specific IP for the 2nd or more instance of PPSSPP to prevent communication interference issue when sharing the same port. Doesn't work well when PPSSPP_ID reseted everytime emulation restarted. /* if (PPSSPP_ID > 1) { - local.sin_addr = ((sockaddr_in *)&localIP)->sin_addr; + local.sin_addr = g_localhostIP.in.sin_addr; } */ @@ -1831,7 +1853,7 @@ int create_listen_socket(uint16_t port) int bindresult = bind(fd, (struct sockaddr *)&local, sizeof(local)); // Bound Local Address to Socket - if(bindresult != -1) + if(bindresult != SOCKET_ERROR) { // Switch Socket into Listening Mode listen(fd, SERVER_LISTEN_BACKLOG); @@ -1841,7 +1863,11 @@ int create_listen_socket(uint16_t port) } // Notify User - else ERROR_LOG(SCENET, "AdhocServer: Bind returned %i (Socket error %d)", bindresult, errno); + else { + ERROR_LOG(SCENET, "AdhocServer: Bind returned %i (Socket error %d)", bindresult, errno); + auto n = GetI18NCategory("Networking"); + host->NotifyUserMessage(std::string(n->T("AdhocServer Failed to Bind Port")) + " " + std::to_string(port), 3.0, 0x0000ff); + } // Close Socket closesocket(fd); @@ -1898,16 +1924,14 @@ int server_loop(int server) // Login User (Stream) if (loginresult != -1) { u32_le sip = addr.sin_addr.s_addr; - /* + /* // Replacing 127.0.0.x with Ethernet IP will cause issue with multiple-instance of localhost (127.0.0.x) if (sip == 0x0100007f) { //127.0.0.1 should be replaced with LAN/WAN IP whenever available - char str[256]; - gethostname(str, 256); + char str[100]; + gethostname(str, 100); u8 *pip = (u8*)&sip; - struct hostent *pHost = 0; - pHost = gethostbyname(str); - if (pHost->h_addrtype == AF_INET && pHost->h_addr_list[0] != NULL) pip = (u8*)pHost->h_addr_list[0]; + if (gethostbyname(str)->h_addrtype == AF_INET && gethostbyname(str)->h_addr_list[0] != NULL) pip = (u8*)gethostbyname(str)->h_addr_list[0]; sip = *(u32_le*)pip; - WARN_LOG(SCENET, "AdhocServer: Replacing IP %s with %u.%u.%u.%u", inet_ntoa(addr.sin_addr), pip[0], pip[1], pip[2], pip[3]); + WARN_LOG(SCENET, "AdhocServer: Replacing IP %s with %s", inet_ntoa(addr.sin_addr), inet_ntoa(*(in_addr*)&pip)); } */ login_user_stream(loginresult, sip); @@ -1923,7 +1947,7 @@ int server_loop(int server) SceNetAdhocctlUserNode * next = user->next; // Receive Data from User - int recvresult = recv(user->stream, (char*)user->rx + user->rxpos, sizeof(user->rx) - user->rxpos, 0); + int recvresult = recv(user->stream, (char*)user->rx + user->rxpos, sizeof(user->rx) - user->rxpos, MSG_NOSIGNAL); // Connection Closed or Timed Out if(recvresult == 0 || (recvresult == -1 && errno != EAGAIN && errno != EWOULDBLOCK) || get_user_state(user) == USER_STATE_TIMED_OUT) @@ -1969,8 +1993,7 @@ int server_loop(int server) else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; - INFO_LOG(SCENET, "AdhocServer: Invalid Opcode 0x%02X in Waiting State from %u.%u.%u.%u", user->rx[0], ip[0], ip[1], ip[2], ip[3]); + WARN_LOG(SCENET, "AdhocServer: Invalid Opcode 0x%02X in Waiting State from %s", user->rx[0], inet_ntoa(*(in_addr*)&user->resolver.ip)); // Logout User logout_user(user); @@ -2053,8 +2076,7 @@ int server_loop(int server) else { // Notify User - uint8_t * ip = (uint8_t *)&user->resolver.ip; - INFO_LOG(SCENET, "AdhocServer: Invalid Opcode 0x%02X in Logged-In State from %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u)", user->rx[0], (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], ip[0], ip[1], ip[2], ip[3]); + WARN_LOG(SCENET, "AdhocServer: Invalid Opcode 0x%02X in Logged-In State from %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s)", user->rx[0], (char *)user->resolver.name.data, user->resolver.mac.data[0], user->resolver.mac.data[1], user->resolver.mac.data[2], user->resolver.mac.data[3], user->resolver.mac.data[4], user->resolver.mac.data[5], inet_ntoa(*(in_addr*)&user->resolver.ip)); // Logout User logout_user(user); @@ -2067,10 +2089,10 @@ int server_loop(int server) } // Prevent needless CPU Overload (1ms Sleep) - sleep_ms(1); + sleep_ms(10); // Don't do anything if it's paused, otherwise the log will be flooded - while (adhocServerRunning && Core_IsStepping()) sleep_ms(1); + while (adhocServerRunning && Core_IsStepping() && coreState != CORE_POWERDOWN) sleep_ms(10); } // Free User Database Memory diff --git a/Core/HLE/proAdhocServer.h b/Core/HLE/proAdhocServer.h index c86e33cf6f..3773749eea 100644 --- a/Core/HLE/proAdhocServer.h +++ b/Core/HLE/proAdhocServer.h @@ -46,7 +46,7 @@ #define SERVER_STATUS_XMLOUT "www/status.xml" // Server Shutdown Message -#define SERVER_SHUTDOWN_MESSAGE "PROMETHEUS HUB IS SHUTTING DOWN!" +#define SERVER_SHUTDOWN_MESSAGE "ADHOC SERVER HUB IS SHUTTING DOWN!" typedef struct db_crosslink{ char id_from[PRODUCT_CODE_LENGTH + 1]; //SceNetAdhocctlProductCode id_from; @@ -298,7 +298,7 @@ void logout_user(SceNetAdhocctlUserNode * user); /** * Free Database Memory */ -void free_database(void); +void free_database(); /** * Connect User to Game Group @@ -358,7 +358,7 @@ void game_product_override(SceNetAdhocctlProductCode * product); /** * Update Status Logfile */ -void update_status(void); +void update_status(); /** * Server Entry Point diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 34e2bc5e2d..8590570a35 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -17,6 +17,8 @@ #include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MIPS/MIPS.h" @@ -27,7 +29,6 @@ #include "Core/Debugger/Breakpoints.h" #include "Core/HW/MediaEngine.h" #include "Core/HW/BufferQueue.h" -#include "Common/ChunkFile.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceUtility.h" @@ -236,65 +237,65 @@ struct Atrac { if (!s) return; - p.Do(channels_); - p.Do(outputChannels_); + Do(p, channels_); + Do(p, outputChannels_); if (s >= 5) { - p.Do(jointStereo_); + Do(p, jointStereo_); } - p.Do(atracID_); - p.Do(first_); - p.Do(bufferMaxSize_); - p.Do(codecType_); + Do(p, atracID_); + Do(p, first_); + Do(p, bufferMaxSize_); + Do(p, codecType_); - p.Do(currentSample_); - p.Do(endSample_); - p.Do(firstSampleOffset_); + Do(p, currentSample_); + Do(p, endSample_); + Do(p, firstSampleOffset_); if (s >= 3) { - p.Do(dataOff_); + Do(p, dataOff_); } else { dataOff_ = firstSampleOffset_; } u32 hasDataBuf = dataBuf_ != nullptr; - p.Do(hasDataBuf); + Do(p, hasDataBuf); if (hasDataBuf) { if (p.mode == p.MODE_READ) { if (dataBuf_) delete [] dataBuf_; dataBuf_ = new u8[first_.filesize]; } - p.DoArray(dataBuf_, first_.filesize); + DoArray(p, dataBuf_, first_.filesize); } - p.Do(second_); + Do(p, second_); - p.Do(decodePos_); + Do(p, decodePos_); if (s < 9) { u32 oldDecodeEnd = 0; - p.Do(oldDecodeEnd); + Do(p, oldDecodeEnd); } if (s >= 4) { - p.Do(bufferPos_); + Do(p, bufferPos_); } else { bufferPos_ = decodePos_; } - p.Do(bitrate_); - p.Do(bytesPerFrame_); + Do(p, bitrate_); + Do(p, bytesPerFrame_); - p.Do(loopinfo_); + Do(p, loopinfo_); if (s < 9) { int oldLoopInfoNum = 42; - p.Do(oldLoopInfoNum); + Do(p, oldLoopInfoNum); } - p.Do(loopStartSample_); - p.Do(loopEndSample_); - p.Do(loopNum_); + Do(p, loopStartSample_); + Do(p, loopEndSample_); + Do(p, loopNum_); - p.Do(context_); + Do(p, context_); if (s >= 6) { - p.Do(bufferState_); + Do(p, bufferState_); } else { if (dataBuf_ == nullptr) { bufferState_ = ATRAC_STATUS_NO_DATA; @@ -304,14 +305,14 @@ struct Atrac { } if (s >= 7) { - p.Do(ignoreDataBuf_); + Do(p, ignoreDataBuf_); } else { ignoreDataBuf_ = false; } if (s >= 9) { - p.Do(bufferValidBytes_); - p.Do(bufferHeaderSize_); + Do(p, bufferValidBytes_); + Do(p, bufferHeaderSize_); } else { bufferHeaderSize_ = dataOff_; bufferValidBytes_ = std::min(first_.size - dataOff_, StreamBufferEnd() - dataOff_); @@ -333,7 +334,7 @@ struct Atrac { if (s >= 2 && s < 9) { bool oldResetBuffer = false; - p.Do(oldResetBuffer); + Do(p, oldResetBuffer); } } @@ -645,18 +646,18 @@ void __AtracDoState(PointerWrap &p) { if (!s) return; - p.Do(atracInited); + Do(p, atracInited); for (int i = 0; i < PSP_NUM_ATRAC_IDS; ++i) { bool valid = atracIDs[i] != NULL; - p.Do(valid); + Do(p, valid); if (valid) { - p.Do(atracIDs[i]); + Do(p, atracIDs[i]); } else { delete atracIDs[i]; atracIDs[i] = NULL; } } - p.DoArray(atracIDTypes, PSP_NUM_ATRAC_IDS); + DoArray(p, atracIDTypes, PSP_NUM_ATRAC_IDS); } void __AtracShutdown() { diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index f3c355b655..aa247385d4 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -15,7 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Data/Collections/FixedSizeQueue.h" #include "Core/MIPS/MIPS.h" #include "Core/Host.h" #include "Core/CoreTiming.h" @@ -23,6 +25,7 @@ #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceAudio.h" +#include "Core/HLE/sceUsbMic.h" #include "Core/HLE/__sceAudio.h" #include "Core/Reporting.h" @@ -33,24 +36,29 @@ const int AUDIO_ROUTING_SPEAKER_ON = 1; int defaultRoutingMode = AUDIO_ROUTING_SPEAKER_ON; int defaultRoutingVolMode = AUDIO_ROUTING_SPEAKER_ON; +extern FixedSizeQueue chanSampleQueues[PSP_AUDIO_CHANNEL_MAX + 1]; + +// The extra channel is for SRC/Output2/Vaudio. +AudioChannel chans[PSP_AUDIO_CHANNEL_MAX + 1]; + void AudioChannel::DoState(PointerWrap &p) { auto s = p.Section("AudioChannel", 1, 2); if (!s) return; - p.Do(reserved); - p.Do(sampleAddress); - p.Do(sampleCount); - p.Do(leftVolume); - p.Do(rightVolume); - p.Do(format); - p.Do(waitingThreads); + Do(p, reserved); + Do(p, sampleAddress); + Do(p, sampleCount); + Do(p, leftVolume); + Do(p, rightVolume); + Do(p, format); + Do(p, waitingThreads); if (s >= 2) { - p.Do(defaultRoutingMode); - p.Do(defaultRoutingVolMode); + Do(p, defaultRoutingMode); + Do(p, defaultRoutingVolMode); } - sampleQueue.DoState(p); + chanSampleQueues[index].DoState(p); } void AudioChannel::reset() @@ -67,22 +75,15 @@ void AudioChannel::clear() format = 0; sampleAddress = 0; sampleCount = 0; - sampleQueue.clear(); + chanSampleQueues[index].clear(); waitingThreads.clear(); } -// There's a second Audio api called Audio2 that only has one channel, I guess the 8 channel api was overkill. -// We simply map it to an extra channel after the 8 channels, since they can be used concurrently. - -// The extra channel is for SRC/Output2/Vaudio. -AudioChannel chans[PSP_AUDIO_CHANNEL_MAX + 1]; - -// Enqueues the buffer pointer on the channel. If channel buffer queue is full (2 items?) will block until it isn't. -// For solid audio output we'll need a queue length of 2 buffers at least, we'll try that first. +// Enqueues the buffer pointed to on the channel. If channel buffer queue is full (2 items?) will block until it isn't. +// For solid audio output we'll need a queue length of 2 buffers at least. // Not sure about the range of volume, I often see 0x800 so that might be either // max or 50%? - static u32 sceAudioOutputBlocking(u32 chan, int vol, u32 samplePtr) { if (vol > 0xFFFF) { ERROR_LOG(SCEAUDIO, "sceAudioOutputBlocking() - invalid volume"); @@ -181,7 +182,7 @@ static int sceAudioGetChannelRestLen(u32 chan) { ERROR_LOG(SCEAUDIO, "sceAudioGetChannelRestLen(%08x) - bad channel", chan); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } - int remainingSamples = (int)chans[chan].sampleQueue.size() / 2; + int remainingSamples = (int)chanSampleQueues[chan].size() / 2; VERBOSE_LOG(SCEAUDIO, "%d=sceAudioGetChannelRestLen(%08x)", remainingSamples, chan); return remainingSamples; } @@ -191,7 +192,7 @@ static int sceAudioGetChannelRestLength(u32 chan) { ERROR_LOG(SCEAUDIO, "sceAudioGetChannelRestLength(%08x) - bad channel", chan); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } - int remainingSamples = (int)chans[chan].sampleQueue.size() / 2; + int remainingSamples = (int)chanSampleQueues[chan].size() / 2; VERBOSE_LOG(SCEAUDIO, "%d=sceAudioGetChannelRestLength(%08x)", remainingSamples, chan); return remainingSamples; } @@ -369,7 +370,7 @@ static u32 sceAudioOutput2GetRestSample() { if (!chan.reserved) { return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); } - u32 size = (u32)chan.sampleQueue.size() / 2; + u32 size = (u32)chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].size() / 2; if (size > chan.sampleCount) { // If ChangeLength reduces the size, it still gets output but this return is clamped. size = chan.sampleCount; @@ -381,7 +382,7 @@ static u32 sceAudioOutput2Release() { auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; if (!chan.reserved) return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); - if (!chan.sampleQueue.empty()) + if (!chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].empty()) return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); chan.reset(); @@ -442,7 +443,7 @@ static u32 sceAudioSRCChRelease() { auto &chan = chans[PSP_AUDIO_CHANNEL_SRC]; if (!chan.reserved) return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); - if (!chan.sampleQueue.empty()) + if (!chanSampleQueues[PSP_AUDIO_CHANNEL_SRC].empty()) return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); chan.reset(); @@ -471,6 +472,11 @@ static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) { return hleLogSuccessI(SCEAUDIO, result); } +static int sceAudioInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) { + ERROR_LOG(HLE, "UNIMPL sceAudioInputBlocking: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); + return __MicInputBlocking(maxSamples, sampleRate, bufAddr); +} + static u32 sceAudioRoutingSetMode(u32 mode) { ERROR_LOG_REPORT(SCEAUDIO, "sceAudioRoutingSetMode(%08x)", mode); int previousMode = defaultRoutingMode; @@ -535,7 +541,7 @@ const HLEFunction sceAudio[] = {0X7DE61688, nullptr, "sceAudioInputInit", '?', "" }, {0XE926D3FB, nullptr, "sceAudioInputInitEx", '?', "" }, {0X6D4BEC68, nullptr, "sceAudioInput", '?', "" }, - {0X086E5895, nullptr, "sceAudioInputBlocking", '?', "" }, + {0X086E5895, &WrapI_UUU, "sceAudioInputBlocking", 'i', "xxx" }, {0XA708C6A6, nullptr, "sceAudioGetInputLength", '?', "" }, {0XA633048E, nullptr, "sceAudioPollInputEnd", '?', "" }, {0X87B2E651, nullptr, "sceAudioWaitInputEnd", '?', "" }, diff --git a/Core/HLE/sceAudio.h b/Core/HLE/sceAudio.h index bf8af1e62b..def23ebb02 100644 --- a/Core/HLE/sceAudio.h +++ b/Core/HLE/sceAudio.h @@ -21,7 +21,6 @@ #include "CommonTypes.h" #include "sceKernel.h" -#include "FixedSizeQueue.h" class PointerWrap; @@ -48,37 +47,24 @@ const int PSP_AUDIO_CHANNEL_SRC = 8; const int PSP_AUDIO_CHANNEL_OUTPUT2 = 8; const int PSP_AUDIO_CHANNEL_VAUDIO = 8; -struct AudioChannelWaitInfo -{ +struct AudioChannelWaitInfo { SceUID threadID; int numSamples; }; -struct AudioChannel -{ - AudioChannel() { - clear(); - } - - // PSP side - - bool reserved; +struct AudioChannel { + int index = 0; + bool reserved = false; // last sample address - u32 sampleAddress; - u32 sampleCount; // Number of samples written in each OutputBlocking - u32 leftVolume; - u32 rightVolume; - u32 format; + u32 sampleAddress = 0; + u32 sampleCount = 0; // Number of samples written in each OutputBlocking + u32 leftVolume = 0; + u32 rightVolume = 0; + u32 format = 0; std::vector waitingThreads; - // PC side - should probably split out - - // We copy samples as they are written into this simple ring buffer. - // Might try something more efficient later. - FixedSizeQueue sampleQueue; - void DoState(PointerWrap &p); void reset(); diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp index 83d70dc343..21d643e1fc 100644 --- a/Core/HLE/sceAudiocodec.cpp +++ b/Core/HLE/sceAudiocodec.cpp @@ -15,13 +15,14 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceAudiocodec.h" #include "Core/MemMap.h" #include "Core/Reporting.h" #include "Core/HW/SimpleAudioDec.h" -#include "Common/ChunkFile.h" // Following kaien_fr's sample code https://github.com/hrydgard/ppsspp/issues/5620#issuecomment-37086024 // Should probably store the EDRAM get/release status somewhere within here, etc. @@ -171,7 +172,7 @@ void __sceAudiocodecDoState(PointerWrap &p){ } int count = (int)audioList.size(); - p.Do(count); + Do(p, count); if (count > 0) { if (p.mode == PointerWrap::MODE_READ) { @@ -182,13 +183,21 @@ void __sceAudiocodecDoState(PointerWrap &p){ auto ctxPtr_ = new u32[count]; // These sizeof(pointers) are wrong, but kept to avoid breaking on old saves. // They're not used in new savestates. - p.DoArray(codec_, s >= 2 ? count : (int)ARRAY_SIZE(codec_)); - p.DoArray(ctxPtr_, s >= 2 ? count : (int)ARRAY_SIZE(ctxPtr_)); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wsizeof-pointer-div" +#endif + DoArray(p, codec_, s >= 2 ? count : (int)ARRAY_SIZE(codec_)); + DoArray(p, ctxPtr_, s >= 2 ? count : (int)ARRAY_SIZE(ctxPtr_)); for (int i = 0; i < count; i++) { auto decoder = new SimpleAudio(codec_[i]); decoder->SetCtxPtr(ctxPtr_[i]); audioList[ctxPtr_[i]] = decoder; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif delete[] codec_; delete[] ctxPtr_; } @@ -205,8 +214,8 @@ void __sceAudiocodecDoState(PointerWrap &p){ ctxPtr_[i] = decoder->GetCtxPtr(); i++; } - p.DoArray(codec_, count); - p.DoArray(ctxPtr_, count); + DoArray(p, codec_, count); + DoArray(p, ctxPtr_, count); delete[] codec_; delete[] ctxPtr_; } diff --git a/Core/HLE/sceCcc.cpp b/Core/HLE/sceCcc.cpp index 71cbfa6e40..51da548291 100644 --- a/Core/HLE/sceCcc.cpp +++ b/Core/HLE/sceCcc.cpp @@ -15,11 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "util/text/utf8.h" -#include "util/text/utf16.h" -#include "util/text/shiftjis.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Encoding/Utf16.h" +#include "Common/Data/Encoding/Shiftjis.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Debugger/Breakpoints.h" #include "Core/MemMap.h" #include "Core/HLE/HLE.h" @@ -55,11 +56,11 @@ void __CccDoState(PointerWrap &p) if (!s) return; - p.Do(errorUTF8); - p.Do(errorUTF16); - p.Do(errorSJIS); - p.Do(ucs2jisTable); - p.Do(jis2ucsTable); + Do(p, errorUTF8); + Do(p, errorUTF16); + Do(p, errorSJIS); + Do(p, ucs2jisTable); + Do(p, jis2ucsTable); } static u32 __CccUCStoJIS(u32 c, u32 alt) diff --git a/Core/HLE/sceChnnlsv.cpp b/Core/HLE/sceChnnlsv.cpp index 5fc9c4c965..475e2ed8d2 100644 --- a/Core/HLE/sceChnnlsv.cpp +++ b/Core/HLE/sceChnnlsv.cpp @@ -99,7 +99,7 @@ static int kirkSendCmd(u8* data, int length, int num, bool encrypt) *(int*)(data+12) = num; *(int*)(data+16) = length; - if (sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_0 : KIRK_CMD_DECRYPT_IV_0)) + if (kirk_sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_0 : KIRK_CMD_DECRYPT_IV_0)) return -257; return 0; @@ -114,7 +114,7 @@ static int kirkSendFuseCmd(u8* data, int length, bool encrypt) *(int*)(data+16) = length; // Note: CMD 5 and 8 are not available, will always return -1 - if (sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_FUSE : KIRK_CMD_DECRYPT_IV_FUSE)) + if (kirk_sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_FUSE : KIRK_CMD_DECRYPT_IV_FUSE)) return -258; return 0; @@ -209,7 +209,7 @@ static int sub_1510(u8* data, int size, u8* result , int num) static int sub_17A8(u8* data) { - if (sceUtilsBufferCopyWithRange(data, 20, 0, 0, 14) == 0) + if (kirk_sceUtilsBufferCopyWithRange(data, 20, 0, 0, 14) == 0) return 0; return -261; } diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 17ab7084cd..a87cba554f 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -18,13 +18,14 @@ #include #include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MIPS/MIPS.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/Replay.h" -#include "Common/ChunkFile.h" #include "Core/Util/AudioFormat.h" // for clamp_u8 #include "Core/HLE/sceCtrl.h" #include "Core/HLE/sceDisplay.h" @@ -306,7 +307,7 @@ static void __CtrlVblank() static void __CtrlTimerUpdate(u64 userdata, int cyclesLate) { // This only runs in timer mode (ctrlCycle > 0.) - _dbg_assert_msg_(SCECTRL, ctrlCycle > 0, "Ctrl: sampling cycle should be > 0"); + _dbg_assert_msg_(ctrlCycle > 0, "Ctrl: sampling cycle should be > 0"); CoreTiming::ScheduleEvent(usToCycles(ctrlCycle) - cyclesLate, ctrlTimer, 0); @@ -350,33 +351,33 @@ void __CtrlDoState(PointerWrap &p) if (!s) return; - p.Do(analogEnabled); - p.Do(ctrlLatchBufs); - p.Do(ctrlOldButtons); + Do(p, analogEnabled); + Do(p, ctrlLatchBufs); + Do(p, ctrlOldButtons); p.DoVoid(ctrlBufs, sizeof(ctrlBufs)); if (s <= 2) { CtrlData dummy = {0}; - p.Do(dummy); + Do(p, dummy); } - p.Do(ctrlBuf); - p.Do(ctrlBufRead); - p.Do(latch); + Do(p, ctrlBuf); + Do(p, ctrlBufRead); + Do(p, latch); if (s == 1) { dialogBtnMake = 0; } else { - p.Do(dialogBtnMake); + Do(p, dialogBtnMake); } - p.Do(ctrlIdleReset); - p.Do(ctrlIdleBack); + Do(p, ctrlIdleReset); + Do(p, ctrlIdleBack); - p.Do(ctrlCycle); + Do(p, ctrlCycle); SceUID dv = 0; - p.Do(waitingThreads, dv); + Do(p, waitingThreads, dv); - p.Do(ctrlTimer); + Do(p, ctrlTimer); CoreTiming::RestoreRegisterEvent(ctrlTimer, "CtrlSampleTimer", __CtrlTimerUpdate); } diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index f362f65f52..cf733955b6 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -26,22 +26,19 @@ #include #endif -// TODO: Move the relevant parts into common. Don't want the core -// to be dependent on "native", I think. Or maybe should get rid of common -// and move everything into native... -#include "base/logging.h" -#include "base/timeutil.h" -#include "i18n/i18n.h" -#include "profiler/profiler.h" - -#include "gfx_es2/gpu_features.h" - -#include "Common/ChunkFile.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Profiler/Profiler.h" +#include "Common/System/System.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/CoreTiming.h" #include "Core/CoreParameter.h" #include "Core/Host.h" #include "Core/Reporting.h" +#include "Core/Core.h" #include "Core/System.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" @@ -54,7 +51,7 @@ #include "GPU/GPU.h" #include "GPU/GPUState.h" #include "GPU/GPUInterface.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PostShader.h" #include "GPU/Debugger/Record.h" @@ -76,8 +73,8 @@ struct WaitVBlankInfo { if (!s) return; - p.Do(threadID); - p.Do(vcountUnblock); + Do(p, threadID); + Do(p, vcountUnblock); } }; @@ -193,7 +190,7 @@ static void ScheduleLagSync(int over = 0) { over = 0; } CoreTiming::ScheduleEvent(usToCycles(1000 + over), lagSyncEvent, 0); - lastLagSync = real_time_now(); + lastLagSync = time_now_d(); } } @@ -260,44 +257,44 @@ void __DisplayDoState(PointerWrap &p) { if (!s) return; - p.Do(framebuf); - p.Do(latchedFramebuf); - p.Do(framebufIsLatched); - p.Do(frameStartTicks); - p.Do(vCount); + Do(p, framebuf); + Do(p, latchedFramebuf); + Do(p, framebufIsLatched); + Do(p, frameStartTicks); + Do(p, vCount); if (s <= 2) { double oldHCountBase; - p.Do(oldHCountBase); + Do(p, oldHCountBase); hCountBase = (int) oldHCountBase; } else { - p.Do(hCountBase); + Do(p, hCountBase); } - p.Do(isVblank); - p.Do(hasSetMode); - p.Do(mode); - p.Do(resumeMode); - p.Do(holdMode); + Do(p, isVblank); + Do(p, hasSetMode); + Do(p, mode); + Do(p, resumeMode); + Do(p, holdMode); if (s >= 4) { - p.Do(brightnessLevel); + Do(p, brightnessLevel); } - p.Do(width); - p.Do(height); + Do(p, width); + Do(p, height); WaitVBlankInfo wvi(0); - p.Do(vblankWaitingThreads, wvi); - p.Do(vblankPausedWaits); + Do(p, vblankWaitingThreads, wvi); + Do(p, vblankPausedWaits); - p.Do(enterVblankEvent); + Do(p, enterVblankEvent); CoreTiming::RestoreRegisterEvent(enterVblankEvent, "EnterVBlank", &hleEnterVblank); - p.Do(leaveVblankEvent); + Do(p, leaveVblankEvent); CoreTiming::RestoreRegisterEvent(leaveVblankEvent, "LeaveVBlank", &hleLeaveVblank); - p.Do(afterFlipEvent); + Do(p, afterFlipEvent); CoreTiming::RestoreRegisterEvent(afterFlipEvent, "AfterFlip", &hleAfterFlip); if (s >= 5) { - p.Do(lagSyncEvent); - p.Do(lagSyncScheduled); + Do(p, lagSyncEvent); + Do(p, lagSyncScheduled); CoreTiming::RestoreRegisterEvent(lagSyncEvent, "LagSync", &hleLagSync); - lastLagSync = real_time_now(); + lastLagSync = time_now_d(); if (lagSyncScheduled != g_Config.bForceLagSync) { ScheduleLagSync(); } @@ -306,7 +303,7 @@ void __DisplayDoState(PointerWrap &p) { ScheduleLagSync(); } - p.Do(gstate); + Do(p, gstate); // TODO: GPU stuff is really not the responsibility of sceDisplay. // Display just displays the buffers the GPU has drawn, they are really completely distinct. @@ -316,11 +313,12 @@ void __DisplayDoState(PointerWrap &p) { if (s < 2) { // This shouldn't have been savestated anyway, but it was. // It's unlikely to overlap with the first value in gpuStats. - p.ExpectVoid(&gl_extensions.gpuVendor, sizeof(gl_extensions.gpuVendor)); + int gpuVendorTemp = 0; + p.ExpectVoid(&gpuVendorTemp, sizeof(gpuVendorTemp)); } if (s < 6) { GPUStatistics_v0 oldStats; - p.Do(oldStats); + Do(p, oldStats); } if (s < 7) { @@ -328,8 +326,8 @@ void __DisplayDoState(PointerWrap &p) { lastFlipCycles = now; nextFlipCycles = now; } else { - p.Do(lastFlipCycles); - p.Do(nextFlipCycles); + Do(p, lastFlipCycles); + Do(p, nextFlipCycles); } gpu->DoState(p); @@ -452,7 +450,6 @@ static bool IsRunningSlow() { } static void CalculateFPS() { - time_update(); double now = time_now_d(); if (now >= lastFpsTime + 1.0) { @@ -560,7 +557,7 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { // we have nothing to do here. bool doFrameSkip = g_Config.iFrameSkip != 0; - bool unthrottleNeedsSkip = g_Config.bFrameSkipUnthrottle; + bool unthrottleNeedsSkip = g_Config.iUnthrottleMode == (int)UnthrottleMode::SKIP_DRAW; if (g_Config.bVSync && GetGPUBackend() == GPUBackend::VULKAN) { // Vulkan doesn't support the interval setting, so we force frameskip. unthrottleNeedsSkip = true; @@ -581,8 +578,6 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { if (!throttle && !doFrameSkip) return; - time_update(); - float scaledTimestep = timestep; if (fpsLimit > 0 && fpsLimit != 60) { scaledTimestep *= 60.0f / fpsLimit; @@ -637,7 +632,6 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { const double left = nextFrameTime - curFrameTime; usleep((long)(left * 1000000)); #endif - time_update(); } } curFrameTime = time_now_d(); @@ -653,8 +647,6 @@ static void DoFrameIdleTiming() { return; } - time_update(); - double before = time_now_d(); double dist = before - lastFrameTime; // Ignore if the distance is just crazy. May mean wrap or pause. @@ -682,7 +674,6 @@ static void DoFrameIdleTiming() { const double left = goal - time_now_d(); usleep((long)(left * 1000000)); #endif - time_update(); } if (g_Config.bDrawFrameGraph) { @@ -752,15 +743,19 @@ void __DisplayFlip(int cyclesLate) { // But, let's flip at least once every 10 vblanks, to update fps, etc. const bool noRecentFlip = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && numVBlanksSinceFlip >= 10; // Also let's always flip for animated shaders. - const ShaderInfo *shaderInfo = g_Config.sPostShaderName == "Off" ? nullptr : GetPostShaderInfo(g_Config.sPostShaderName); bool postEffectRequiresFlip = false; + + bool duplicateFrames = g_Config.bRenderDuplicateFrames && g_Config.iFrameSkip == 0; + + bool unthrottleNeedsSkip = g_Config.iUnthrottleMode != (int)UnthrottleMode::CONTINUOUS; + if (g_Config.bVSync && GetGPUBackend() == GPUBackend::VULKAN) { + // Vulkan doesn't support the interval setting, so we force frameskip. + unthrottleNeedsSkip = true; + } + // postEffectRequiresFlip is not compatible with frameskip unthrottling, see #12325. - if (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !(g_Config.bFrameSkipUnthrottle && !FrameTimingThrottled())) { - if (shaderInfo) { - postEffectRequiresFlip = (shaderInfo->requires60fps || g_Config.bRenderDuplicateFrames); - } else { - postEffectRequiresFlip = g_Config.bRenderDuplicateFrames; - } + if (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !(unthrottleNeedsSkip && !FrameTimingThrottled())) { + postEffectRequiresFlip = duplicateFrames || g_Config.bShaderChainRequires60FPS; } const bool fbDirty = gpu->FramebufferDirty(); @@ -784,12 +779,24 @@ void __DisplayFlip(int cyclesLate) { hasNotifiedSlow = true; } + bool forceNoFlip = false; + // Alternative to frameskip unthrottle, where we draw everything. + // Useful if skipping a frame breaks graphics or for checking drawing speed. + if (g_Config.iUnthrottleMode == (int)UnthrottleMode::SKIP_FLIP && !FrameTimingThrottled()) { + static double lastFlip = 0; + double now = time_now_d(); + if ((now - lastFlip) < 1.0f / System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE)) { + forceNoFlip = true; + } else { + lastFlip = now; + } + } + // Setting CORE_NEXTFRAME causes a swap. const bool fbReallyDirty = gpu->FramebufferReallyDirty(); if (fbReallyDirty || noRecentFlip || postEffectRequiresFlip) { // Check first though, might've just quit / been paused. - if (coreState == CORE_RUNNING) { - coreState = CORE_NEXTFRAME; + if (!forceNoFlip && Core_NextFrame()) { gpu->CopyDisplayToOutput(fbReallyDirty); if (fbReallyDirty) { actualFlips++; @@ -831,7 +838,7 @@ void __DisplayFlip(int cyclesLate) { if (g_Config.bDrawFrameGraph) { // Track how long we sleep (whether vsync or sleep_ms.) - frameSleepHistory[frameSleepPos] += real_time_now() - lastFrameTimeHistory; + frameSleepHistory[frameSleepPos] += time_now_d() - lastFrameTimeHistory; } } else { // Okay, there's no new frame to draw. But audio may be playing, so we need to time still. @@ -879,23 +886,23 @@ void hleLagSync(u64 userdata, int cyclesLate) { } const double goal = lastLagSync + (scale / 1000.0f); - time_update(); double before = time_now_d(); // Don't lag too long ever, if they leave it paused. - while (time_now_d() < goal && goal < time_now_d() + 0.01) { + double now = before; + while (now < goal && goal < now + 0.01) { #ifndef _WIN32 const double left = goal - time_now_d(); usleep((long)(left * 1000000)); #endif - time_update(); + now = time_now_d(); } const int emuOver = (int)cyclesToUs(cyclesLate); - const int over = (int)((time_now_d() - goal) * 1000000); + const int over = (int)((now - goal) * 1000000); ScheduleLagSync(over - emuOver); if (g_Config.bDrawFrameGraph) { - frameSleepHistory[frameTimeHistoryPos] += time_now_d() - before; + frameSleepHistory[frameTimeHistoryPos] += now - before; } } diff --git a/Core/HLE/sceDmac.cpp b/Core/HLE/sceDmac.cpp index da48432e8b..4f186facfe 100644 --- a/Core/HLE/sceDmac.cpp +++ b/Core/HLE/sceDmac.cpp @@ -15,7 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" @@ -40,7 +41,7 @@ void __DmacDoState(PointerWrap &p) { return; } - p.Do(dmacMemcpyDeadline); + Do(p, dmacMemcpyDeadline); } static int __DmacMemcpy(u32 dst, u32 src, u32 size) { diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 1e1300858d..dbf0bebf34 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -1,13 +1,15 @@ #include "sceFont.h" -#include "base/timeutil.h" +#include "Common/TimeUtil.h" #include #include #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceFont.h" @@ -89,30 +91,31 @@ struct FontRegistryEntry { int expireDate; int shadow_option; u32 fontFileSize; + u32 stingySize; // for the FONT_OPEN_INTERNAL_STINGY mode, from pspautotests. bool ignoreIfMissing; }; static const FontRegistryEntry fontRegistry[] = { // This was added for Chinese translations and is not normally loaded on a PSP. - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_DB, 0, FONT_LANGUAGE_CHINESE, 0, 1, "zh_gb.pgf", "FTT-NewRodin Pro DB", 0, 0, 1581700, true }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_DB, 0, FONT_LANGUAGE_JAPANESE, 0, 1, "jpn0.pgf", "FTT-NewRodin Pro DB", 0, 0, 1581700 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn0.pgf", "FTT-NewRodin Pro Latin", 0, 0, 69108 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn1.pgf", "FTT-Matisse Pro Latin", 0, 0, 65124 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn2.pgf", "FTT-NewRodin Pro Latin", 0, 0, 72948 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn3.pgf", "FTT-Matisse Pro Latin", 0, 0, 67700}, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn4.pgf", "FTT-NewRodin Pro Latin", 0, 0, 72828 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn5.pgf", "FTT-Matisse Pro Latin", 0, 0, 68220 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn6.pgf", "FTT-NewRodin Pro Latin", 0, 0, 77032 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn7.pgf", "FTT-Matisse Pro Latin", 0, 0, 71144 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn8.pgf", "FTT-NewRodin Pro Latin", 0, 0, 41000 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn9.pgf", "FTT-Matisse Pro Latin", 0, 0, 40164 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn10.pgf", "FTT-NewRodin Pro Latin", 0, 0, 42692 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn11.pgf", "FTT-Matisse Pro Latin", 0, 0, 41488 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn12.pgf", "FTT-NewRodin Pro Latin", 0, 0, 43136 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn13.pgf", "FTT-Matisse Pro Latin", 0, 0, 41772 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn14.pgf", "FTT-NewRodin Pro Latin", 0, 0, 45184 }, - { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn15.pgf", "FTT-Matisse Pro Latin", 0, 0, 43044 }, - { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_KOREAN, 0, 3, "kr0.pgf", "AsiaNHH(512Johab)", 0, 0, 394192 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_DB, 0, FONT_LANGUAGE_CHINESE, 0, 1, "zh_gb.pgf", "FTT-NewRodin Pro DB", 0, 0, 1581700, 145844, true }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_DB, 0, FONT_LANGUAGE_JAPANESE, 0, 1, "jpn0.pgf", "FTT-NewRodin Pro DB", 0, 0, 1581700, 145844 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn0.pgf", "FTT-NewRodin Pro Latin", 0, 0, 69108, 16680 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn1.pgf", "FTT-Matisse Pro Latin", 0, 0, 65124, 16920 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn2.pgf", "FTT-NewRodin Pro Latin", 0, 0, 72948, 16872 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn3.pgf", "FTT-Matisse Pro Latin", 0, 0, 67700, 17112 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn4.pgf", "FTT-NewRodin Pro Latin", 0, 0, 72828, 16648 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn5.pgf", "FTT-Matisse Pro Latin", 0, 0, 68220, 16928 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn6.pgf", "FTT-NewRodin Pro Latin", 0, 0, 77032, 16792 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn7.pgf", "FTT-Matisse Pro Latin", 0, 0, 71144, 17160 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn8.pgf", "FTT-NewRodin Pro Latin", 0, 0, 41000, 16192 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn9.pgf", "FTT-Matisse Pro Latin", 0, 0, 40164, 16476 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn10.pgf", "FTT-NewRodin Pro Latin", 0, 0, 42692, 16300 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn11.pgf", "FTT-Matisse Pro Latin", 0, 0, 41488, 16656 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn12.pgf", "FTT-NewRodin Pro Latin", 0, 0, 43136, 16176 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn13.pgf", "FTT-Matisse Pro Latin", 0, 0, 41772, 16436 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn14.pgf", "FTT-NewRodin Pro Latin", 0, 0, 45184, 16272 }, + { 0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn15.pgf", "FTT-Matisse Pro Latin", 0, 0, 43044, 16704 }, + { 0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_KOREAN, 0, 3, "kr0.pgf", "AsiaNHH(512Johab)", 0, 0, 394192, 51856 }, }; static const float pointDPI = 72.f; @@ -212,6 +215,7 @@ public: PGF *GetPGF() { return &pgf_; } const PGF *GetPGF() const { return &pgf_; } u32 getSize() const { return dataSize_; } + u32 getStingySize() const { return stingySize_; } bool IsValid() const { return valid_; } void DoState(PointerWrap &p) { @@ -219,12 +223,12 @@ public: if (!s) return; - p.Do(pgf_); - p.Do(style_); + Do(p, pgf_); + Do(p, style_); if (s < 2) { valid_ = true; } else { - p.Do(valid_); + Do(p, valid_); } } @@ -237,6 +241,7 @@ private: style_.fontHRes = (float)pgf_.header.hResolution / 64.0f; style_.fontVRes = (float)pgf_.header.vResolution / 64.0f; this->dataSize_ = (u32)dataSize; + this->stingySize_ = 0; // Unused } void Init(const u8 *data, size_t dataSize, const FontRegistryEntry &entry) { @@ -257,12 +262,14 @@ private: style_.fontAttributes = entry.extraAttributes; style_.fontExpire = entry.expireDate; this->dataSize_ = entry.fontFileSize; + this->stingySize_ = entry.stingySize; } PGF pgf_; PGFFontStyle style_; bool valid_; u32 dataSize_; + u32 stingySize_; DISALLOW_COPY_AND_ASSIGN(Font); }; @@ -312,29 +319,29 @@ public: return; int numInternalFonts = (int)internalFonts.size(); - p.Do(numInternalFonts); + Do(p, numInternalFonts); if (numInternalFonts != (int)internalFonts.size()) { ERROR_LOG(SCEFONT, "Unable to load state: different internal font count."); p.SetError(p.ERROR_FAILURE); return; } - p.Do(fontLibID_); + Do(p, fontLibID_); int internalFont = GetInternalFontIndex(font_); - p.Do(internalFont); + Do(p, internalFont); if (internalFont == -1) { - p.Do(font_); + Do(p, font_); } else if (p.mode == p.MODE_READ) { font_ = internalFonts[internalFont]; } - p.Do(handle_); + Do(p, handle_); if (s >= 2) { - p.Do(open_); + Do(p, open_); } else { open_ = fontLibID_ != (u32)-1; } if (s >= 3) { - p.Do(mode_); + Do(p, mode_); } else { mode_ = FONT_OPEN_INTERNAL_FULL; } @@ -358,9 +365,11 @@ public: if (!s) return; - p.Do(fontLibID_); + Do(p, fontLibID_); if (s >= 2) { - p.Do(errorCodePtr_); + Do(p, errorCodePtr_); + } else { + errorCodePtr_ = 0; } } void run(MipsCall &call) override; @@ -380,7 +389,7 @@ public: if (!s) return; - p.Do(fontLibID_); + Do(p, fontLibID_); } void run(MipsCall &call) override; void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } @@ -398,9 +407,9 @@ public: if (!s) return; - p.Do(fontLibID_); - p.Do(fontHandle_); - p.Do(fontIndex_); + Do(p, fontLibID_); + Do(p, fontHandle_); + Do(p, fontIndex_); } void run(MipsCall &call) override; void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } @@ -421,7 +430,7 @@ public: if (!s) return; - p.Do(fontLibID_); + Do(p, fontLibID_); } void run(MipsCall &call) override; void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } @@ -439,8 +448,8 @@ public: if (!s) return; - p.Do(fontLibID_); - p.Do(charInfo_); + Do(p, fontLibID_); + Do(p, charInfo_); } void run(MipsCall &call) override; void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } @@ -611,7 +620,7 @@ public: u32 allocSize = 12; if (mode == FONT_OPEN_INTERNAL_STINGY) { - allocSize = 0x239B4; + allocSize = loadedFont->GetFont()->getStingySize(); } else if (mode == FONT_OPEN_INTERNAL_FULL) { allocSize += loadedFont->GetFont()->getSize(); } @@ -655,23 +664,23 @@ public: if (!s) return; - p.Do(fonts_); - p.Do(isfontopen_); - p.Do(params_); - p.Do(fontHRes_); - p.Do(fontVRes_); - p.Do(fileFontHandle_); - p.Do(handle_); - p.Do(altCharCode_); + Do(p, fonts_); + Do(p, isfontopen_); + Do(p, params_); + Do(p, fontHRes_); + Do(p, fontVRes_); + Do(p, fileFontHandle_); + Do(p, handle_); + Do(p, altCharCode_); if (s >= 2) { - p.Do(nfl_); + Do(p, nfl_); } else { nfl_ = 0; } if (s >= 3) { - p.Do(openAllocatedAddresses_); - p.Do(charInfoBitmapAddress_); + Do(p, openAllocatedAddresses_); + Do(p, charInfoBitmapAddress_); } else { openAllocatedAddresses_.resize(params_.numFonts); charInfoBitmapAddress_ = 0; @@ -721,7 +730,8 @@ void PostAllocCallback::run(MipsCall &call) { u32 v0 = currentMIPS->r[MIPS_REG_V0]; if (v0 == 0) { // TODO: Who deletes fontLib? - Memory::Write_U32(ERROR_FONT_OUT_OF_MEMORY, errorCodePtr_); + if (errorCodePtr_) + Memory::Write_U32(ERROR_FONT_OUT_OF_MEMORY, errorCodePtr_); call.setReturnValue(0); } else { FontLib *fontLib = fontLibList[fontLibID_]; @@ -909,20 +919,20 @@ void __FontDoState(PointerWrap &p) { __LoadInternalFonts(); - p.Do(fontLibList); - p.Do(fontLibMap); - p.Do(fontMap); + Do(p, fontLibList); + Do(p, fontLibMap); + Do(p, fontMap); - p.Do(actionPostAllocCallback); + Do(p, actionPostAllocCallback); __KernelRestoreActionType(actionPostAllocCallback, PostAllocCallback::Create); - p.Do(actionPostOpenCallback); + Do(p, actionPostOpenCallback); __KernelRestoreActionType(actionPostOpenCallback, PostOpenCallback::Create); if (s >= 2) { - p.Do(actionPostOpenAllocCallback); + Do(p, actionPostOpenAllocCallback); __KernelRestoreActionType(actionPostOpenAllocCallback, PostOpenAllocCallback::Create); - p.Do(actionPostCharInfoAllocCallback); + Do(p, actionPostCharInfoAllocCallback); __KernelRestoreActionType(actionPostCharInfoAllocCallback, PostCharInfoAllocCallback::Create); - p.Do(actionPostCharInfoFreeCallback); + Do(p, actionPostCharInfoFreeCallback); __KernelRestoreActionType(actionPostCharInfoFreeCallback, PostCharInfoFreeCallback::Create); } else { useAllocCallbacks = false; diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index dafa5d09b1..8c27ed16c6 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -19,8 +19,11 @@ #include #include -#include "Common/ChunkFile.h" -#include "Common/ThreadSafeList.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeList.h" +#include "Common/Serialize/SerializeMap.h" +#include "Common/Data/Collections/ThreadSafeList.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MIPS/MIPS.h" @@ -219,14 +222,14 @@ void __GeDoState(PointerWrap &p) { if (!s) return; - p.DoArray(ge_callback_data, ARRAY_SIZE(ge_callback_data)); - p.DoArray(ge_used_callbacks, ARRAY_SIZE(ge_used_callbacks)); + DoArray(p, ge_callback_data, ARRAY_SIZE(ge_callback_data)); + DoArray(p, ge_used_callbacks, ARRAY_SIZE(ge_used_callbacks)); if (s >= 2) { - p.Do(ge_pending_cb); + Do(p, ge_pending_cb); } else { std::list old; - p.Do(old); + Do(p, old); ge_pending_cb.clear(); for (auto it = old.begin(), end = old.end(); it != end; ++it) { GeInterruptData intrdata = {it->listid, it->pc}; @@ -235,15 +238,15 @@ void __GeDoState(PointerWrap &p) { } } - p.Do(geSyncEvent); + Do(p, geSyncEvent); CoreTiming::RestoreRegisterEvent(geSyncEvent, "GeSyncEvent", &__GeExecuteSync); - p.Do(geInterruptEvent); + Do(p, geInterruptEvent); CoreTiming::RestoreRegisterEvent(geInterruptEvent, "GeInterruptEvent", &__GeExecuteInterrupt); - p.Do(geCycleEvent); + Do(p, geCycleEvent); CoreTiming::RestoreRegisterEvent(geCycleEvent, "GeCycleEvent", &__GeCheckCycles); - p.Do(listWaitingThreads); - p.Do(drawWaitingThreads); + Do(p, listWaitingThreads); + Do(p, drawWaitingThreads); // Everything else is done in sceDisplay. } @@ -340,10 +343,9 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optP if ((int)listID >= 0) listID = LIST_ID_MAGIC ^ listID; - DEBUG_LOG(SCEGE, "List %i enqueued.", listID); hleEatCycles(490); CoreTiming::ForceCheck(); - return listID; + return hleLogSuccessX(SCEGE, listID); } u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr) { @@ -353,13 +355,12 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 auto optParam = PSPPointer::Create(optParamAddr); u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), optParam, true); - if ((int)listID >= 0) { + if ((int)listID >= 0) listID = LIST_ID_MAGIC ^ listID; - DEBUG_LOG(SCEGE, "List %i enqueued at head.", listID); - } + hleEatCycles(480); CoreTiming::ForceCheck(); - return listID; + return hleLogSuccessX(SCEGE, listID); } static int sceGeListDeQueue(u32 listID) { @@ -594,8 +595,8 @@ static u32 sceGeEdramSetAddrTranslation(int new_size) { const HLEFunction sceGe_user[] = { {0XE47E40E4, &WrapU_V, "sceGeEdramGetAddr", 'x', "" }, - {0XAB49E76A, &WrapU_UUIU, "sceGeListEnQueue", 'x', "xxix"}, - {0X1C0D95A6, &WrapU_UUIU, "sceGeListEnQueueHead", 'x', "xxix"}, + {0XAB49E76A, &WrapU_UUIU, "sceGeListEnQueue", 'x', "xxip"}, + {0X1C0D95A6, &WrapU_UUIU, "sceGeListEnQueueHead", 'x', "xxip"}, {0XE0D68148, &WrapI_UU, "sceGeListUpdateStallAddr", 'i', "xx" }, {0X03444EB4, &WrapI_UU, "sceGeListSync", 'i', "xx" }, {0XB287BD61, &WrapU_U, "sceGeDrawSync", 'x', "x" }, diff --git a/Core/HLE/sceHeap.cpp b/Core/HLE/sceHeap.cpp index 5a70358e34..e1c802b149 100644 --- a/Core/HLE/sceHeap.cpp +++ b/Core/HLE/sceHeap.cpp @@ -15,7 +15,10 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/MemMap.h" #include "Core/Reporting.h" #include "Core/HLE/HLE.h" @@ -23,10 +26,9 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceHeap.h" #include "Core/Util/BlockAllocator.h" -#include struct Heap { - Heap():alloc(4) {} + Heap() : alloc(4) {} u32 size; u32 address; @@ -34,14 +36,14 @@ struct Heap { BlockAllocator alloc; void DoState (PointerWrap &p) { - p.Do(size); - p.Do(address); - p.Do(fromtop); - p.Do(alloc); + Do(p, size); + Do(p, address); + Do(p, fromtop); + Do(p, alloc); } }; -std::map heapList; +static std::map heapList; static Heap *getHeap(u32 addr) { auto found = heapList.find(addr); @@ -57,7 +59,7 @@ void __HeapDoState(PointerWrap &p) { return; if (s >= 2) { - p.Do(heapList); + Do(p, heapList); } } diff --git a/Core/HLE/sceHttp.cpp b/Core/HLE/sceHttp.cpp index e592ef6178..6d13b6f1f2 100644 --- a/Core/HLE/sceHttp.cpp +++ b/Core/HLE/sceHttp.cpp @@ -19,7 +19,7 @@ #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceHttp.h" -#include "net/http_client.h" +#include "Common/Net/HTTPClient.h" // If http isn't loaded (seems unlikely), most functions should return SCE_KERNEL_ERROR_LIBRARY_NOTFOUND diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index 9ef9af254a..086cc83c17 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceImpose.h" @@ -22,7 +24,6 @@ #include "Core/MIPS/MIPS.h" #include "Core/Config.h" #include "Core/MemMap.h" -#include "Common/ChunkFile.h" const int PSP_UMD_POPUP_DISABLE = 0; const int PSP_UMD_POPUP_ENABLE = 1; @@ -50,10 +51,10 @@ void __ImposeDoState(PointerWrap &p) if (!s) return; - p.Do(language); - p.Do(buttonValue); - p.Do(umdPopup); - p.Do(backlightOffTime); + Do(p, language); + Do(p, buttonValue); + Do(p, umdPopup); + Do(p, backlightOffTime); } static u32 sceImposeGetBatteryIconStatus(u32 chargingPtr, u32 iconStatusPtr) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 567f0c069a..a12ba039f9 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -19,9 +19,13 @@ #include #include -#include "thread/threadutil.h" -#include "profiler/profiler.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Profiler/Profiler.h" +#include "Common/File/FileUtil.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" +#include "Common/Serialize/SerializeSet.h" #include "Core/Core.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -129,7 +133,7 @@ static MemStickFatState lastMemStickFatState; static AsyncIOManager ioManager; static bool ioManagerThreadEnabled = false; -static std::thread ioManagerThread; +static std::thread *ioManagerThread; // TODO: Is it better to just put all on the thread? // Let's try. (was 256) @@ -209,7 +213,8 @@ public: pgd_close(pgdInfo); } const char *GetName() override { return fullpath.c_str(); } - const char *GetTypeName() override { return "OpenFile"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "OpenFile"; } void GetQuickInfo(char *ptr, int size) override { sprintf(ptr, "Seekpos: %08x", (u32)pspFileSystem.GetSeekPos(handle)); } @@ -226,22 +231,22 @@ public: if (!s) return; - p.Do(fullpath); - p.Do(handle); - p.Do(callbackID); - p.Do(callbackArg); - p.Do(asyncResult); - p.Do(hasAsyncResult); - p.Do(pendingAsyncResult); - p.Do(sectorBlockMode); - p.Do(closePending); - p.Do(info); - p.Do(openMode); + Do(p, fullpath); + Do(p, handle); + Do(p, callbackID); + Do(p, callbackArg); + Do(p, asyncResult); + Do(p, hasAsyncResult); + Do(p, pendingAsyncResult); + Do(p, sectorBlockMode); + Do(p, closePending); + Do(p, info); + Do(p, openMode); - p.Do(npdrm); - p.Do(pgd_offset); + Do(p, npdrm); + Do(p, pgd_offset); bool hasPGD = pgdInfo != NULL; - p.Do(hasPGD); + Do(p, hasPGD); if (hasPGD) { if (p.mode == p.MODE_READ) { pgdInfo = (PGD_DESC*) malloc(sizeof(PGD_DESC)); @@ -252,11 +257,11 @@ public: } } - p.Do(waitingThreads); + Do(p, waitingThreads); if (s >= 2) { - p.Do(waitingSyncThreads); + Do(p, waitingSyncThreads); } - p.Do(pausedWaits); + Do(p, pausedWaits); } std::string fullpath; @@ -555,7 +560,7 @@ static VFSFileSystem *flash0System = nullptr; static void __IoManagerThread() { setCurrentThreadName("IO"); - while (ioManagerThreadEnabled && coreState != CORE_ERROR && coreState != CORE_POWERDOWN) { + while (ioManagerThreadEnabled && coreState != CORE_BOOT_ERROR && coreState != CORE_RUNTIME_ERROR && coreState != CORE_POWERDOWN) { ioManager.RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000)); } } @@ -621,9 +626,9 @@ void __IoInit() { asyncNotifyEvent = CoreTiming::RegisterEvent("IoAsyncNotify", __IoAsyncNotify); syncNotifyEvent = CoreTiming::RegisterEvent("IoSyncNotify", __IoSyncNotify); - memstickSystem = new DirectoryFileSystem(&pspFileSystem, g_Config.memStickDirectory, FILESYSTEM_SIMULATE_FAT32); + memstickSystem = new DirectoryFileSystem(&pspFileSystem, g_Config.memStickDirectory, FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD); #if defined(USING_WIN_UI) || defined(APPLE) - flash0System = new DirectoryFileSystem(&pspFileSystem, g_Config.flash0Directory); + flash0System = new DirectoryFileSystem(&pspFileSystem, g_Config.flash0Directory, FileSystemFlags::FLASH); #else flash0System = new VFSFileSystem(&pspFileSystem, "flash0"); #endif @@ -637,7 +642,7 @@ void __IoInit() { const std::string gameId = g_paramSFO.GetValueString("DISC_ID"); const std::string exdataPath = g_Config.memStickDirectory + "exdata/" + gameId + "/"; if (File::Exists(exdataPath)) { - exdataSystem = new DirectoryFileSystem(&pspFileSystem, exdataPath, FILESYSTEM_SIMULATE_FAT32); + exdataSystem = new DirectoryFileSystem(&pspFileSystem, exdataPath, FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD); pspFileSystem.Mount("exdata0:", exdataSystem); INFO_LOG(SCEIO, "Mounted exdata/%s/ under memstick for exdata0:/", gameId.c_str()); } else { @@ -649,10 +654,12 @@ void __IoInit() { memset(fds, 0, sizeof(fds)); - ioManagerThreadEnabled = true; + ioManagerThreadEnabled = g_Config.bSeparateIOThread; ioManager.SetThreadEnabled(ioManagerThreadEnabled); - Core_ListenLifecycle(&__IoWakeManager); - ioManagerThread = std::thread(&__IoManagerThread); + if (ioManagerThreadEnabled) { + Core_ListenLifecycle(&__IoWakeManager); + ioManagerThread = new std::thread(&__IoManagerThread); + } __KernelRegisterWaitTypeFuncs(WAITTYPE_ASYNCIO, __IoAsyncBeginCallback, __IoAsyncEndCallback); @@ -667,10 +674,10 @@ void __IoDoState(PointerWrap &p) { return; ioManager.DoState(p); - p.DoArray(fds, ARRAY_SIZE(fds)); - p.Do(asyncNotifyEvent); + DoArray(p, fds, ARRAY_SIZE(fds)); + Do(p, asyncNotifyEvent); CoreTiming::RestoreRegisterEvent(asyncNotifyEvent, "IoAsyncNotify", __IoAsyncNotify); - p.Do(syncNotifyEvent); + Do(p, syncNotifyEvent); CoreTiming::RestoreRegisterEvent(syncNotifyEvent, "IoSyncNotify", __IoSyncNotify); if (s < 2) { std::set legacy; @@ -678,22 +685,22 @@ void __IoDoState(PointerWrap &p) { memStickFatCallbacks.clear(); // Convert from set to vector. - p.Do(legacy); + Do(p, legacy); for (SceUID id : legacy) { memStickCallbacks.push_back(id); } - p.Do(legacy); + Do(p, legacy); for (SceUID id : legacy) { memStickFatCallbacks.push_back(id); } } else { - p.Do(memStickCallbacks); - p.Do(memStickFatCallbacks); + Do(p, memStickCallbacks); + Do(p, memStickFatCallbacks); } if (s >= 3) { - p.Do(lastMemStickState); - p.Do(lastMemStickFatState); + Do(p, lastMemStickState); + Do(p, lastMemStickFatState); } for (int i = 0; i < PSP_COUNT_FDS; ++i) { @@ -707,11 +714,11 @@ void __IoDoState(PointerWrap &p) { if (s >= 4) { p.DoVoid(&asyncParams[i], (int)sizeof(IoAsyncParams)); bool hasThread = asyncThreads[i] != nullptr; - p.Do(hasThread); + Do(p, hasThread); if (hasThread) { if (p.GetMode() == p.MODE_READ) clearThread(); - p.DoClass(asyncThreads[i]); + DoClass(p, asyncThreads[i]); } else if (!hasThread) { clearThread(); } @@ -723,7 +730,7 @@ void __IoDoState(PointerWrap &p) { } if (s >= 5) { - p.Do(asyncDefaultPriority); + Do(p, asyncDefaultPriority); } else { asyncDefaultPriority = -1; } @@ -733,8 +740,12 @@ void __IoShutdown() { ioManagerThreadEnabled = false; ioManager.SyncThread(); ioManager.FinishEventLoop(); - ioManagerThread.join(); - ioManager.Shutdown(); + if (ioManagerThread != nullptr) { + ioManagerThread->join(); + delete ioManagerThread; + ioManagerThread = nullptr; + ioManager.Shutdown(); + } for (int i = 0; i < PSP_COUNT_FDS; ++i) { asyncParams[i].op = IoAsyncOp::NONE; @@ -956,6 +967,8 @@ static u32 npdrmRead(FileNode *f, u8 *data, int size) { block = pgd->file_offset/pgd->block_size; offset = pgd->file_offset%pgd->block_size; + if (size > (int)pgd->data_size) + size = (int)pgd->data_size; remain_size = size; while(remain_size){ @@ -1245,7 +1258,7 @@ static u32 sceIoWriteAsync(int id, u32 data_addr, int size) { static u32 sceIoGetDevType(int id) { if (id == PSP_STDOUT || id == PSP_STDERR || id == PSP_STDIN) { DEBUG_LOG(SCEIO, "sceIoGetDevType(%d)", id); - return PSP_DEV_TYPE_FILE; + return (u32)PSPDevType::FILE; } u32 error; @@ -1254,7 +1267,7 @@ static u32 sceIoGetDevType(int id) { if (f) { // TODO: When would this return PSP_DEV_TYPE_ALIAS? WARN_LOG(SCEIO, "sceIoGetDevType(%d - %s)", id, f->fullpath.c_str()); - result = pspFileSystem.DevType(f->handle); + result = (u32)pspFileSystem.DevType(f->handle) & (u32)PSPDevType::EMU_MASK; } else { ERROR_LOG(SCEIO, "sceIoGetDevType: unknown id %d", id); result = SCE_KERNEL_ERROR_BADF; @@ -1423,8 +1436,7 @@ static u32 sceIoLseek32Async(int id, int offset, int whence) { return 0; } -static FileNode *__IoOpen(int &error, const char* filename, int flags, int mode) { - //memory stick filename +static FileNode *__IoOpen(int &error, const char *filename, int flags, int mode) { int access = FILEACCESS_NONE; if (flags & PSP_O_RDONLY) access |= FILEACCESS_READ; @@ -1463,41 +1475,49 @@ static FileNode *__IoOpen(int &error, const char* filename, int flags, int mode) } static u32 sceIoOpen(const char *filename, int flags, int mode) { - if (!__KernelIsDispatchEnabled()) - return -1; + hleEatCycles(18000); + + if (!__KernelIsDispatchEnabled()) { + hleEatCycles(48000); + return hleLogError(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + } int error; FileNode *f = __IoOpen(error, filename, flags, mode); - if (f == NULL) - { - // Timing is not accurate, aiming low for now. - if (error == (int)SCE_KERNEL_ERROR_NOCWD) - { - ERROR_LOG(SCEIO, "SCE_KERNEL_ERROR_NOCWD=sceIoOpen(%s, %08x, %08x) - no current working directory", filename, flags, mode); - return hleDelayResult(SCE_KERNEL_ERROR_NOCWD, "no cwd", 10000); - } - else if (error != 0) - { - ERROR_LOG(SCEIO, "%08x=sceIoOpen(%s, %08x, %08x)", error, filename, flags, mode); - return hleDelayResult(error, "file opened", 10000); - } - else - { - ERROR_LOG(SCEIO, "ERROR_ERRNO_FILE_NOT_FOUND=sceIoOpen(%s, %08x, %08x) - file not found", filename, flags, mode); - return hleDelayResult(SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "file opened", 10000); + if (!f) { + _assert_(error != 0); + if (error == (int)SCE_KERNEL_ERROR_NOCWD) { + // TODO: Timing is not accurate. + return hleLogError(SCEIO, hleDelayResult(error, "file opened", 10000), "no current working directory"); + } else if (error == (int)SCE_KERNEL_ERROR_NODEV) { + return hleLogError(SCEIO, error, "device not found"); + } else if (error == (int)SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND) { + // UMD: Varies between 5-10ms, could take longer if disc spins up. + // TODO: Bad filename at root (disc0:/no.exist) should take ~200us. + // Card: Path depth matters, but typically between 10-13ms on a standard Pro Duo. + // TODO: If a UMD and spun down, this can easily take 1s+. + int delay = pspFileSystem.FlagsFromFilename(filename) & FileSystemFlags::UMD ? 6000 : 10000; + return hleLogWarning(SCEIO, hleDelayResult(error, "file opened", delay), "file not found"); + } else { + return hleLogError(SCEIO, hleDelayResult(error, "file opened", 10000)); } } int id = __IoAllocFd(f); if (id < 0) { - ERROR_LOG(SCEIO, "%08x=sceIoOpen(%s, %08x, %08x): out of fds", id, filename, flags, mode); kernelObjects.Destroy(f->GetUID()); - return id; + return hleLogError(SCEIO, hleDelayResult(id, "file opened", 1000), "out of fds"); } else { - DEBUG_LOG(SCEIO, "%i=sceIoOpen(%s, %08x, %08x)", id, filename, flags, mode); asyncParams[id].priority = asyncDefaultPriority; - // Timing is not accurate, aiming low for now. - return hleDelayResult(id, "file opened", 100); + IFileSystem *sys = pspFileSystem.GetSystemFromFilename(filename); + if (sys && (sys->DevType(f->handle) & (PSPDevType::BLOCK | PSPDevType::EMU_LBN))) { + // These are fast to open, no delay or even rescheduling happens. + return hleLogSuccessI(SCEIO, id); + } + // UMD: Speed varies from 1-6ms. + // Card: Path depth matters, but typically between 10-13ms on a standard Pro Duo. + int delay = pspFileSystem.FlagsFromFilename(filename) & FileSystemFlags::UMD ? 4000 : 10000; + return hleLogSuccessI(SCEIO, hleDelayResult(id, "file opened", delay)); } } @@ -2032,8 +2052,9 @@ static u32 sceIoSetAsyncCallback(int id, u32 clbckId, u32 clbckArg) } } -static u32 sceIoOpenAsync(const char *filename, int flags, int mode) -{ +static u32 sceIoOpenAsync(const char *filename, int flags, int mode) { + hleEatCycles(18000); + // TOOD: Use an internal method so as not to pollute the log? // Intentionally does not work when interrupts disabled. if (!__KernelIsDispatchEnabled()) @@ -2044,8 +2065,9 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode) // We have to return an fd here, which may have been destroyed when we reach Wait if it failed. if (f == nullptr) { - if (error == 0) - error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; + _assert_(error != 0); + if (error == SCE_KERNEL_ERROR_NODEV) + return hleLogError(SCEIO, error, "device not found"); f = new FileNode(); f->handle = kernelObjects.Create(f); @@ -2057,7 +2079,7 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode) int fd = __IoAllocFd(f); if (fd < 0) { kernelObjects.Destroy(f->GetUID()); - return hleLogError(SCEIO, fd, "out of fds"); + return hleLogError(SCEIO, hleDelayResult(fd, "file opened", 1000), "out of fds"); } auto ¶ms = asyncParams[fd]; @@ -2217,7 +2239,8 @@ static u32 sceIoPollAsync(int id, u32 address) { class DirListing : public KernelObject { public: const char *GetName() override { return name.c_str(); } - const char *GetTypeName() override { return "DirListing"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "DirListing"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_BADF; } static int GetStaticIDType() { return PPSSPP_KERNEL_TMID_DirList; } int GetIDType() const override { return PPSSPP_KERNEL_TMID_DirList; } @@ -2227,12 +2250,12 @@ public: if (!s) return; - p.Do(name); - p.Do(index); + Do(p, name); + Do(p, index); // TODO: Is this the right way for it to wake up? int count = (int) listing.size(); - p.Do(count); + Do(p, count); listing.resize(count); for (int i = 0; i < count; ++i) { listing[i].DoState(p); @@ -2293,13 +2316,7 @@ static u32 sceIoDread(int id, u32 dirent_addr) { strncpy(entry->d_name, info.name.c_str(), 256); entry->d_name[255] = '\0'; - bool isFAT = false; - IFileSystem *sys = pspFileSystem.GetSystemFromFilename(dir->name); - if (sys && (sys->Flags() & FILESYSTEM_SIMULATE_FAT32)) - isFAT = true; - else - isFAT = false; - + bool isFAT = pspFileSystem.FlagsFromFilename(dir->name) & FileSystemFlags::SIMULATE_FAT32; // Only write d_private for memory stick if (isFAT) { // write d_private for supporting Custom BGM @@ -2712,10 +2729,24 @@ static int IoAsyncFinish(int id) { break; case IoAsyncOp::OPEN: - // TODO: Timing is very inconsistent. From ms0, 10ms - 20ms depending on filesize/dir depth? From umd, can take > 1s. - // For now let's aim low. - us = 100; + { + // See notes on timing in sceIoOpen. + const std::string filename = Memory::GetCharPointer(params.open.filenameAddr); + IFileSystem *sys = pspFileSystem.GetSystemFromFilename(filename); + if (sys) { + if (f->asyncResult == (int)SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND) { + us = sys->Flags() & FileSystemFlags::UMD ? 6000 : 10000; + } else if (sys->DevType(f->handle) & (PSPDevType::BLOCK | PSPDevType::EMU_LBN)) { + // These are fast to open, no delay or even rescheduling happens. + us = 80; + } else { + us = sys->Flags() & FileSystemFlags::UMD ? 4000 : 10000; + } + } else { + us = 80; + } break; + } case IoAsyncOp::CLOSE: f->asyncResult = 0; @@ -2865,7 +2896,7 @@ const HLEFunction StdioForKernel[] = { {0X2CCF071A, nullptr, "fdprintf", '?', "" }, {0XD97C8CB9, nullptr, "puts", '?', "" }, {0X172D316E, nullptr, "sceKernelStdin", '?', "" }, - {0XA6BAB2E9, nullptr, "sceKernelStdout", '?', "" }, + {0XA6BAB2E9, &WrapU_V, "sceKernelStdout", 'i', "" ,HLE_KERNEL_SYSCALL }, {0XF78BA90A, nullptr, "sceKernelStderr", '?', "" }, }; diff --git a/Core/HLE/sceJpeg.cpp b/Core/HLE/sceJpeg.cpp index f532233203..4230675599 100644 --- a/Core/HLE/sceJpeg.cpp +++ b/Core/HLE/sceJpeg.cpp @@ -15,10 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "ext/jpge/jpgd.h" #include "Common/Common.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceJpeg.h" @@ -27,13 +29,19 @@ #include "Core/MemMap.h" #include "Core/Reporting.h" -//Uncomment if you want to dump JPEGs loaded through sceJpeg to a file -//#define JPEG_DEBUG +// Uncomment if you want to dump JPEGs loaded through sceJpeg to a file +// #define JPEG_DEBUG #ifdef JPEG_DEBUG #include "ext/xxhash.h" #endif -#include +struct u24_be { + unsigned char value[3]; + + operator unsigned int() { + return 0x00000000 | (value[0] << 16) | (value[1] << 8) | (value[2] << 0); + } +}; static int mjpegWidth, mjpegHeight; @@ -47,8 +55,8 @@ void __JpegDoState(PointerWrap &p) { if (!s) return; - p.Do(mjpegWidth); - p.Do(mjpegHeight); + Do(p, mjpegWidth); + Do(p, mjpegHeight); } static int getWidthHeight(int width, int height) { diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 520295f2d9..971a9c728b 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/LogManager.h" #include "Core/Core.h" #include "Core/Config.h" #include "Core/CwCheat.h" @@ -26,7 +28,6 @@ #include "Core/MIPS/MIPSInt.h" #include "Core/MIPS/JitCommon/JitCommon.h" -#include "Common/LogManager.h" #include "Core/FileSystems/FileSystem.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/PSPLoaders.h" @@ -77,12 +78,13 @@ #include "sceImpose.h" #include "sceUsb.h" #include "sceUsbGps.h" +#include "sceUsbCam.h" +#include "sceUsbMic.h" #include "scePspNpDrm_user.h" #include "sceVaudio.h" #include "sceHeap.h" #include "sceDmac.h" #include "sceMp4.h" -#include "sceUsbCam.h" #include "../Util/PPGeDraw.h" @@ -105,6 +107,7 @@ void __KernelInit() ERROR_LOG(SCEKERNEL, "Can't init kernel when kernel is running"); return; } + INFO_LOG(SCEKERNEL, "Initializing kernel..."); __KernelTimeInit(); __InterruptsInit(); @@ -146,6 +149,7 @@ void __KernelInit() __VideoPmpInit(); __UsbGpsInit(); __UsbCamInit(); + __UsbMicInit(); SaveState::Init(); // Must be after IO, as it may create a directory Reporting::Init(); @@ -170,6 +174,7 @@ void __KernelShutdown() kernelObjects.Clear(); __UsbCamShutdown(); + __UsbMicShutdown(); __UsbGpsShutdown(); __AudioCodecShutdown(); @@ -214,11 +219,11 @@ void __KernelDoState(PointerWrap &p) if (!s) return; - p.Do(kernelRunning); + Do(p, kernelRunning); kernelObjects.DoState(p); if (s >= 2) - p.Do(registeredExitCbId); + Do(p, registeredExitCbId); } { @@ -278,6 +283,7 @@ void __KernelDoState(PointerWrap &p) __VideoPmpDoState(p); __AACDoState(p); __UsbGpsDoState(p); + __UsbMicDoState(p); // IMPORTANT! Add new sections last! } @@ -297,6 +303,12 @@ bool __KernelIsRunning() { return kernelRunning; } +std::string __KernelStateSummary() { + std::string threadSummary = __KernelThreadingSummary(); + return StringFromFormat("%s", threadSummary.c_str()); +} + + void sceKernelExitGame() { INFO_LOG(SCEKERNEL, "sceKernelExitGame"); @@ -532,7 +544,7 @@ void KernelObjectPool::DoState(PointerWrap &p) { return; int _maxCount = maxCount; - p.Do(_maxCount); + Do(p, _maxCount); if (_maxCount != maxCount) { p.SetError(p.ERROR_FAILURE); @@ -545,15 +557,15 @@ void KernelObjectPool::DoState(PointerWrap &p) { kernelObjects.Clear(); } - p.Do(nextID); - p.DoArray(occupied, maxCount); + Do(p, nextID); + DoArray(p, occupied, maxCount); for (int i = 0; i < maxCount; ++i) { if (!occupied[i]) continue; int type; if (p.mode == p.MODE_READ) { - p.Do(type); + Do(p, type); pool[i] = CreateByIDType(type); // Already logged an error. @@ -563,7 +575,7 @@ void KernelObjectPool::DoState(PointerWrap &p) { pool[i]->uid = i + handleOffset; } else { type = pool[i]->GetIDType(); - p.Do(type); + Do(p, type); } pool[i]->DoState(p); if (p.error >= p.ERROR_FAILURE) @@ -733,8 +745,8 @@ const HLEFunction ThreadManForUser[] = {0X1181E963, &WrapI_U, "sceKernelDelaySysClockThreadCB", 'i', "P", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, {0XCEADEB47, &WrapI_U, "sceKernelDelayThread", 'i', "x", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, {0X68DA9E36, &WrapI_U, "sceKernelDelayThreadCB", 'i', "x", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, - {0XAA73C935, &WrapV_I, "sceKernelExitThread", 'v', "i" }, - {0X809CE29B, &WrapV_I, "sceKernelExitDeleteThread", 'v', "i" }, + {0XAA73C935, &WrapI_I, "sceKernelExitThread", 'i', "i" }, + {0X809CE29B, &WrapI_I, "sceKernelExitDeleteThread", 'i', "i" }, {0x94aa61ee, &WrapI_V, "sceKernelGetThreadCurrentPriority", 'i', "" }, {0X293B45B8, &WrapI_V, "sceKernelGetThreadId", 'i', "", HLE_NOT_IN_INTERRUPT }, {0X3B183E26, &WrapI_I, "sceKernelGetThreadExitStatus", 'i', "i" }, @@ -863,6 +875,11 @@ const HLEFunction ThreadManForUser[] = // Shouldn't hook this up. No games should import this function manually and call it. // {0x6E9EA350, _sceKernelReturnFromCallback,"_sceKernelReturnFromCallback"}, + {0X71EC4271, &WrapU_UU, "sceKernelLibcGettimeofday", 'x', "xx" }, + {0X79D1C3FA, &WrapI_V, "sceKernelDcacheWritebackAll", 'i', "" }, + {0X91E4F6A7, &WrapU_V, "sceKernelLibcClock", 'x', "" }, + {0XB435DEC5, &WrapI_V, "sceKernelDcacheWritebackInvalidateAll", 'i', "" }, + }; const HLEFunction ThreadManForKernel[] = @@ -870,6 +887,14 @@ const HLEFunction ThreadManForKernel[] = {0xCEADEB47, &WrapI_U, "sceKernelDelayThread", 'i', "x", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED | HLE_KERNEL_SYSCALL }, {0x446D8DE6, &WrapI_CUUIUU, "sceKernelCreateThread", 'i', "sxxixx", HLE_NOT_IN_INTERRUPT | HLE_KERNEL_SYSCALL }, {0xF475845D, &WrapI_IIU, "sceKernelStartThread", 'i', "iix", HLE_NOT_IN_INTERRUPT | HLE_KERNEL_SYSCALL }, + {0X9FA03CD3, &WrapI_I, "sceKernelDeleteThread", 'i', "i", HLE_KERNEL_SYSCALL }, + {0XAA73C935, &WrapI_I, "sceKernelExitThread", 'i', "i", HLE_KERNEL_SYSCALL }, + {0X809CE29B, &WrapI_I, "sceKernelExitDeleteThread", 'i', "i", HLE_KERNEL_SYSCALL }, + {0X9944F31F, &WrapI_I, "sceKernelSuspendThread", 'i', "i", HLE_KERNEL_SYSCALL }, + {0X75156E8F, &WrapI_I, "sceKernelResumeThread", 'i', "i", HLE_KERNEL_SYSCALL }, + {0X94416130, &WrapU_UUUU, "sceKernelGetThreadmanIdList", 'x', "xxxx", HLE_KERNEL_SYSCALL }, + {0X28B6489C, &WrapI_I, "sceKernelDeleteSema", 'i', "i", HLE_KERNEL_SYSCALL }, + {0XEF9E4C70, &WrapU_I, "sceKernelDeleteEventFlag", 'x', "i", HLE_KERNEL_SYSCALL }, }; void Register_ThreadManForUser() @@ -898,6 +923,7 @@ const HLEFunction LoadExecForKernel[] = {0x4AC57943, &WrapI_I, "sceKernelRegisterExitCallback", 'i', "i", HLE_KERNEL_SYSCALL }, {0XA3D5E142, nullptr, "LoadExecForKernel_a3d5e142", '?', "" }, {0X28D0D249, &WrapI_CU, "sceKernelLoadExec_28D0D249", 'i', "sx" }, + {0x6D302D3D, &WrapV_V, "sceKernelExitVSHKernel", 'v', "x", HLE_KERNEL_SYSCALL },// when called in game mode it will have the same effect that sceKernelExitGame }; void Register_LoadExecForKernel() diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 96e94cb760..ca9bdfc2d1 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -18,13 +18,15 @@ #pragma once #include +#include #include "Common/Common.h" +#include "Common/Log.h" #include "Common/Swap.h" class PointerWrap; -enum { +enum : u32 { SCE_KERNEL_ERROR_OK = 0, SCE_KERNEL_ERROR_ALREADY = 0x80000020, SCE_KERNEL_ERROR_BUSY = 0x80000021, @@ -374,6 +376,9 @@ void __KernelDoState(PointerWrap &p); bool __KernelIsRunning(); bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param); +// For crash reporting. +std::string __KernelStateSummary(); + int sceKernelLoadExec(const char *filename, u32 paramPtr); void sceKernelExitGame(); @@ -414,13 +419,12 @@ public: virtual int GetIDType() const = 0; virtual void GetQuickInfo(char *ptr, int size); - // Implement this in all subclasses: + // Implement the following in all subclasses: // static u32 GetMissingErrorCode() // static int GetStaticIDType() - virtual void DoState(PointerWrap &p) - { - _dbg_assert_msg_(SCEKERNEL, false, "Unable to save state: bad kernel object."); + virtual void DoState(PointerWrap &p) { + _dbg_assert_msg_(false, "Unable to save state: bad kernel object."); } }; @@ -455,17 +459,17 @@ public: if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset]) { // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP if (handle != 0 && (u32)handle != 0x80020001) { - WARN_LOG(SCEKERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); + WARN_LOG(SCEKERNEL, "Kernel: Bad %s handle %d (%08x)", T::GetStaticTypeName(), handle, handle); } outError = T::GetMissingErrorCode(); return 0; } else { // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, - // it just acted as a static case and everything worked. This means that we will never + // it just acted as a static cast and everything worked. This means that we will never // see the Wrong type object error below, but we'll just have to live with that danger. T* t = static_cast(pool[handle - handleOffset]); - if (t == 0 || t->GetIDType() != T::GetStaticIDType()) { - WARN_LOG(SCEKERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); + if (t == nullptr || t->GetIDType() != T::GetStaticIDType()) { + WARN_LOG(SCEKERNEL, "Kernel: Wrong object type for %d (%08x), was %s, should have been %s", handle, handle, t ? t->GetTypeName() : "null", T::GetStaticTypeName()); outError = T::GetMissingErrorCode(); return 0; } @@ -478,7 +482,7 @@ public: template T *GetFast(SceUID handle) { const SceUID realHandle = handle - handleOffset; - _dbg_assert_(SCEKERNEL, realHandle >= 0 && realHandle < maxCount && occupied[realHandle]); + _dbg_assert_(realHandle >= 0 && realHandle < maxCount && occupied[realHandle]); return static_cast(pool[realHandle]); } diff --git a/Core/HLE/sceKernelAlarm.cpp b/Core/HLE/sceKernelAlarm.cpp index de9c5435ff..d6b12703df 100644 --- a/Core/HLE/sceKernelAlarm.cpp +++ b/Core/HLE/sceKernelAlarm.cpp @@ -15,14 +15,16 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeList.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelAlarm.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/HLE.h" #include "Core/CoreTiming.h" #include "Core/MemMap.h" -#include "Common/ChunkFile.h" -#include const int NATIVEALARM_SIZE = 20; @@ -39,7 +41,8 @@ struct NativeAlarm struct PSPAlarm : public KernelObject { const char *GetName() override {return "[Alarm]";} - const char *GetTypeName() override {return "Alarm";} + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Alarm"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_ALMID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Alarm; } int GetIDType() const override { return SCE_KERNEL_TMID_Alarm; } @@ -49,7 +52,7 @@ struct PSPAlarm : public KernelObject { if (!s) return; - p.Do(alm); + Do(p, alm); } NativeAlarm alm; @@ -135,8 +138,8 @@ void __KernelAlarmDoState(PointerWrap &p) if (!s) return; - p.Do(alarmTimer); - p.Do(triggeredAlarm); + Do(p, alarmTimer); + Do(p, triggeredAlarm); CoreTiming::RestoreRegisterEvent(alarmTimer, "Alarm", __KernelTriggerAlarm); } diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index 47fb2c05e3..b4c28732b6 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -15,12 +15,14 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/HLE.h" #include "Core/MIPS/MIPS.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" -#include "Common/ChunkFile.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelThread.h" @@ -53,7 +55,8 @@ struct EventFlagTh { class EventFlag : public KernelObject { public: const char *GetName() override { return nef.name; } - const char *GetTypeName() override { return "EventFlag"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "EventFlag"; } void GetQuickInfo(char *ptr, int size) override { sprintf(ptr, "init=%08x cur=%08x numwait=%i", nef.initPattern, @@ -72,10 +75,10 @@ public: if (!s) return; - p.Do(nef); + Do(p, nef); EventFlagTh eft = { 0 }; - p.Do(waitingThreads, eft); - p.Do(pausedWaits); + Do(p, waitingThreads, eft); + Do(p, pausedWaits); } NativeEventFlag nef; @@ -120,7 +123,7 @@ void __KernelEventFlagDoState(PointerWrap &p) { if (!s) return; - p.Do(eventFlagWaitTimer); + Do(p, eventFlagWaitTimer); CoreTiming::RestoreRegisterEvent(eventFlagWaitTimer, "EventFlagTimeout", __KernelEventFlagTimeout); } diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 7b99eca184..af2cbdff1d 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -1,6 +1,7 @@ #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceKernel.h" @@ -8,10 +9,14 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/Util/BlockAllocator.h" -static const u32 HEAP_BLOCK_HEADER_SIZE = 8; +static const u32 KERNEL_HEAP_BLOCK_HEADER_SIZE = 8; static const bool g_fromBottom = false; -struct Heap : public KernelObject { +// This object and the functions here are available for kernel code only, not game code. +// This differs from code like sceKernelMutex, which is available for games. +// This exists in PPSSPP mainly because certain game patches use these kernel modules. + +struct KernelHeap : public KernelObject { int uid = 0; int partitionId = 0; u32 size = 0; @@ -23,15 +28,17 @@ struct Heap : public KernelObject { static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_UID; } static int GetStaticIDType() { return PPSSPP_KERNEL_TMID_Heap; } int GetIDType() const override { return PPSSPP_KERNEL_TMID_Heap; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Heap"; } void DoState(PointerWrap &p) override { - p.Do(uid); - p.Do(partitionId); - p.Do(size); - p.Do(flags); - p.Do(address); - p.Do(name); - p.Do(alloc); + Do(p, uid); + Do(p, partitionId); + Do(p, size); + Do(p, flags); + Do(p, address); + Do(p, name); + Do(p, alloc); } }; @@ -45,7 +52,7 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char return SCE_KERNEL_ERROR_NO_MEMORY; // Blind guess } - Heap *heap = new Heap(); + KernelHeap *heap = new KernelHeap(); SceUID uid = kernelObjects.Create(heap); heap->partitionId = partitionId; @@ -60,10 +67,10 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char static int sceKernelAllocHeapMemory(int heapId, int size) { u32 error; - Heap *heap = kernelObjects.Get(heapId, error); + KernelHeap *heap = kernelObjects.Get(heapId, error); if (heap) { // There's 8 bytes at the end of every block, reserved. - u32 memSize = HEAP_BLOCK_HEADER_SIZE + size; + u32 memSize = KERNEL_HEAP_BLOCK_HEADER_SIZE + size; u32 addr = heap->alloc.Alloc(memSize, true); return hleLogSuccessInfoX(SCEKERNEL, addr); } else { @@ -73,20 +80,48 @@ static int sceKernelAllocHeapMemory(int heapId, int size) { static int sceKernelDeleteHeap(int heapId) { u32 error; - Heap *heap = kernelObjects.Get(heapId, error); + KernelHeap *heap = kernelObjects.Get(heapId, error); if (heap) { userMemory.Free(heap->address); - kernelObjects.Destroy(heap->uid); + kernelObjects.Destroy(heap->uid); return hleLogSuccessInfoX(SCEKERNEL, 0); } else { return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId); } } +static u32 sceKernelPartitionTotalFreeMemSize(int partitionId) { + ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionTotalFreeMemSize(%d)", partitionId); + //Need more work #13021 + ///We ignore partitionId for now + return userMemory.GetTotalFreeBytes(); +} + +static u32 sceKernelPartitionMaxFreeMemSize(int partitionId) { + ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionMaxFreeMemSize(%d)", partitionId); + //Need more work #13021 + ///We ignore partitionId for now + return userMemory.GetLargestFreeBlockSize(); +} + +static u32 SysMemForKernel_536AD5E1() +{ + ERROR_LOG(SCEKERNEL, "UNIMP SysMemForKernel_536AD5E1"); + return 0; +} + + const HLEFunction SysMemForKernel[] = { - { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'x', "ii" }, - { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'i', "i" }, - { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'i', "iixs" }, + { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'x', "ii", HLE_KERNEL_SYSCALL }, + { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'i', "i" , HLE_KERNEL_SYSCALL }, + { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'i', "iixs", HLE_KERNEL_SYSCALL }, + { 0X237DBD4F, &WrapI_ICIUU, "sceKernelAllocPartitionMemory", 'i', "isixx", HLE_KERNEL_SYSCALL }, + { 0XB6D61D02, &WrapI_I, "sceKernelFreePartitionMemory", 'i', "i", HLE_KERNEL_SYSCALL }, + { 0X9D9A5BA1, &WrapU_I, "sceKernelGetBlockHeadAddr", 'x', "i", HLE_KERNEL_SYSCALL }, + { 0x9697CD32, &WrapU_I, "sceKernelPartitionTotalFreeMemSize", 'x', "i",HLE_KERNEL_SYSCALL }, + { 0xE6581468, &WrapU_I, "sceKernelPartitionMaxFreeMemSize", 'x', "i",HLE_KERNEL_SYSCALL }, + { 0X3FC9AE6A, &WrapU_V, "sceKernelDevkitVersion", 'x', "" ,HLE_KERNEL_SYSCALL }, + { 0x536AD5E1, &WrapU_V, "SysMemForKernel_536AD5E1", 'i', "i" ,HLE_KERNEL_SYSCALL }, }; void Register_SysMemForKernel() { diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 6ec86f99af..8d8e4124db 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -19,12 +19,15 @@ #include #include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeList.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MIPS/MIPS.h" -#include "Common/ChunkFile.h" #include "Core/Debugger/Breakpoints.h" #include "Core/HLE/sceKernel.h" @@ -59,7 +62,7 @@ public: if (!s) return; - p.Do(savedCpu); + Do(p, savedCpu); } PSPThreadContext savedCpu; @@ -213,8 +216,8 @@ void IntrHandler::DoState(PointerWrap &p) if (!s) return; - p.Do(intrNumber); - p.Do(subIntrHandlers); + Do(p, intrNumber); + Do(p, subIntrHandlers); } void PendingInterrupt::DoState(PointerWrap &p) @@ -223,8 +226,8 @@ void PendingInterrupt::DoState(PointerWrap &p) if (!s) return; - p.Do(intr); - p.Do(subintr); + Do(p, intr); + Do(p, subintr); } void __InterruptsInit() @@ -244,7 +247,7 @@ void __InterruptsDoState(PointerWrap &p) return; int numInterrupts = PSP_NUMBER_INTERRUPTS; - p.Do(numInterrupts); + Do(p, numInterrupts); if (numInterrupts != PSP_NUMBER_INTERRUPTS) { p.SetError(p.ERROR_FAILURE); @@ -254,10 +257,10 @@ void __InterruptsDoState(PointerWrap &p) intState.DoState(p); PendingInterrupt pi(0, 0); - p.Do(pendingInterrupts, pi); - p.Do(interruptsEnabled); - p.Do(inInterrupt); - p.Do(threadBeforeInterrupt); + Do(p, pendingInterrupts, pi); + Do(p, interruptsEnabled); + Do(p, inInterrupt); + Do(p, threadBeforeInterrupt); } void __InterruptsDoStateLate(PointerWrap &p) @@ -678,10 +681,11 @@ const HLEFunction Kernel_Library[] = {0XD13BDE95, &WrapI_V, "sceKernelCheckThreadStack", 'i', "" }, {0X1839852A, &WrapU_UUU, "sceKernelMemcpy", 'x', "xxx" }, {0XFA835CDE, &WrapI_I, "sceKernelGetTlsAddr", 'i', "i" }, + {0X05572A5F, &WrapV_V, "sceKernelExitGame", 'v', "" }, + {0X4AC57943, &WrapI_I, "sceKernelRegisterExitCallback", 'i', "i" }, }; -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); +static u32 sysclib_memcpy(u32 dst, u32 src, u32 size) { if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) { memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size); } @@ -753,6 +757,38 @@ static u32 sysclib_memset(u32 destAddr, int data, int size) { return 0; } +static int sysclib_strstr(u32 s1, u32 s2) { + ERROR_LOG(SCEKERNEL, "Untested sysclib_strstr(%08x, %08x)", s1, s2); + if (Memory::IsValidAddress(s1) && Memory::IsValidAddress(s2)) { + std::string str1 = Memory::GetCharPointer(s1); + std::string str2 = Memory::GetCharPointer(s2); + size_t index = str1.find(str2); + if (index == str1.npos) { + return 0; + } + return s1 + (uint32_t)index; + } + return 0; +} + +static int sysclib_strncmp(u32 s1, u32 s2, u32 size) { + ERROR_LOG(SCEKERNEL, "Untested sysclib_strncmp(%08x, %08x, %08x)", s1, s2, size); + if (Memory::IsValidAddress(s1) && Memory::IsValidAddress(s2)) { + const char * str1 = Memory::GetCharPointer(s1); + const char * str2 = Memory::GetCharPointer(s2); + return strncmp(str1, str2, size); + } + return 0; +} + +static u32 sysclib_memmove(u32 dst, u32 src, u32 size) { + ERROR_LOG(SCEKERNEL, "Untested sysclib_memmove(%08x, %08x, %08x)", dst, src, size); + if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) { + memmove(Memory::GetPointer(dst), Memory::GetPointer(src), size); + } + return 0; +} + const HLEFunction SysclibForKernel[] = { {0xAB7592FF, &WrapU_UUU, "memcpy", 'x', "xxx", HLE_KERNEL_SYSCALL }, @@ -763,6 +799,9 @@ const HLEFunction SysclibForKernel[] = {0x81D0D1F7, &WrapI_UUU, "memcmp", 'i', "xxx", HLE_KERNEL_SYSCALL }, {0x7661E728, &WrapI_UU, "sprintf", 'i', "xx", HLE_KERNEL_SYSCALL }, {0x10F3BB61, &WrapU_UII, "memset", 'x', "xii", HLE_KERNEL_SYSCALL }, + {0x0D188658, &WrapI_UU, "strstr", 'i', "xx", HLE_KERNEL_SYSCALL }, + {0x7AB35214, &WrapI_UUU, "strncmp", 'i', "xxx", HLE_KERNEL_SYSCALL }, + {0xA48D2592, &WrapU_UUU, "memmove", 'x', "xxx", HLE_KERNEL_SYSCALL }, }; void Register_Kernel_Library() diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 4f9b497c02..29ff672e2a 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -17,7 +17,9 @@ #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelMbx.h" @@ -61,7 +63,8 @@ struct NativeMbx struct Mbx : public KernelObject { const char *GetName() override { return nmb.name; } - const char *GetTypeName() override { return "Mbx"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Mbx"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MBXID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Mbox; } int GetIDType() const override { return SCE_KERNEL_TMID_Mbox; } @@ -165,10 +168,10 @@ struct Mbx : public KernelObject if (!s) return; - p.Do(nmb); + Do(p, nmb); MbxWaitingThread mwt = {0}; - p.Do(waitingThreads, mwt); - p.Do(pausedWaits); + Do(p, waitingThreads, mwt); + Do(p, pausedWaits); } NativeMbx nmb; @@ -193,7 +196,7 @@ void __KernelMbxDoState(PointerWrap &p) if (!s) return; - p.Do(mbxWaitTimer); + Do(p, mbxWaitTimer); CoreTiming::RestoreRegisterEvent(mbxWaitTimer, "MbxTimeout", __KernelMbxTimeout); } @@ -273,7 +276,7 @@ static void __KernelWaitMbx(Mbx *m, u32 timeoutPtr) static std::vector::iterator __KernelMbxFindPriority(std::vector &waiting) { - _dbg_assert_msg_(SCEKERNEL, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); + _dbg_assert_msg_(!waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); std::vector::iterator iter, end, best = waiting.end(); u32 best_prio = 0xFFFFFFFF; @@ -287,7 +290,7 @@ static std::vector::iterator __KernelMbxFindPriority(std::vect } } - _dbg_assert_msg_(SCEKERNEL, best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread."); + _dbg_assert_msg_(best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread."); return best; } diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 40cccaa03d..8ceb699fad 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -20,7 +20,9 @@ #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/System.h" @@ -93,7 +95,8 @@ struct FPL : public KernelObject } } const char *GetName() override { return nf.name; } - const char *GetTypeName() override { return "FPL"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "FPL"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_FPLID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Fpl; } int GetIDType() const override { return SCE_KERNEL_TMID_Fpl; } @@ -129,16 +132,16 @@ struct FPL : public KernelObject if (!s) return; - p.Do(nf); + Do(p, nf); if (p.mode == p.MODE_READ) blocks = new bool[nf.numBlocks]; - p.DoArray(blocks, nf.numBlocks); - p.Do(address); - p.Do(alignedSize); - p.Do(nextBlock); + DoArray(p, blocks, nf.numBlocks); + Do(p, address); + Do(p, alignedSize); + Do(p, nextBlock); FplWaitingThread dv = {0}; - p.Do(waitingThreads, dv); - p.Do(pausedWaits); + Do(p, waitingThreads, dv); + Do(p, pausedWaits); } NativeFPL nf; @@ -302,11 +305,11 @@ struct SceKernelVplHeader { inline void Validate() { auto lastBlock = LastBlock(); - _dbg_assert_msg_(SCEKERNEL, nextFreeBlock_->next.ptr != SentinelPtr(), "Next free block should not be allocated."); - _dbg_assert_msg_(SCEKERNEL, nextFreeBlock_->next.ptr != sentinel_, "Next free block should not point to sentinel."); - _dbg_assert_msg_(SCEKERNEL, lastBlock->sizeInBlocks == 0, "Last block should have size of 0."); - _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr != SentinelPtr(), "Last block should not be allocated."); - _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr != sentinel_, "Last block should not point to sentinel."); + _dbg_assert_msg_(nextFreeBlock_->next.ptr != SentinelPtr(), "Next free block should not be allocated."); + _dbg_assert_msg_(nextFreeBlock_->next.ptr != sentinel_, "Next free block should not point to sentinel."); + _dbg_assert_msg_(lastBlock->sizeInBlocks == 0, "Last block should have size of 0."); + _dbg_assert_msg_(lastBlock->next.ptr != SentinelPtr(), "Last block should not be allocated."); + _dbg_assert_msg_(lastBlock->next.ptr != sentinel_, "Last block should not point to sentinel."); auto b = PSPPointer::Create(FirstBlockPtr()); bool sawFirstFree = false; @@ -314,22 +317,22 @@ struct SceKernelVplHeader { bool isFree = b->next.ptr != SentinelPtr(); if (isFree) { if (!sawFirstFree) { - _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr == b.ptr, "Last block should point to first free block."); + _dbg_assert_msg_(lastBlock->next.ptr == b.ptr, "Last block should point to first free block."); sawFirstFree = true; } - _dbg_assert_msg_(SCEKERNEL, b->next.ptr != SentinelPtr(), "Free blocks should only point to other free blocks."); - _dbg_assert_msg_(SCEKERNEL, b->next.ptr > b.ptr, "Free blocks should be in order."); - _dbg_assert_msg_(SCEKERNEL, b + b->sizeInBlocks < b->next || b->next.ptr == lastBlock.ptr, "Two free blocks should not be next to each other."); + _dbg_assert_msg_(b->next.ptr != SentinelPtr(), "Free blocks should only point to other free blocks."); + _dbg_assert_msg_(b->next.ptr > b.ptr, "Free blocks should be in order."); + _dbg_assert_msg_(b + b->sizeInBlocks < b->next || b->next.ptr == lastBlock.ptr, "Two free blocks should not be next to each other."); } else { - _dbg_assert_msg_(SCEKERNEL, b->next.ptr == SentinelPtr(), "Allocated blocks should point to the sentinel."); + _dbg_assert_msg_(b->next.ptr == SentinelPtr(), "Allocated blocks should point to the sentinel."); } - _dbg_assert_msg_(SCEKERNEL, b->sizeInBlocks != 0, "Only the last block should have a size of 0."); + _dbg_assert_msg_(b->sizeInBlocks != 0, "Only the last block should have a size of 0."); b += b->sizeInBlocks; } if (!sawFirstFree) { - _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr == lastBlock.ptr, "Last block should point to itself when full."); + _dbg_assert_msg_(lastBlock->next.ptr == lastBlock.ptr, "Last block should point to itself when full."); } - _dbg_assert_msg_(SCEKERNEL, b.ptr == lastBlock.ptr, "Blocks should not extend outside vpl."); + _dbg_assert_msg_(b.ptr == lastBlock.ptr, "Blocks should not extend outside vpl."); } void ListBlocks() { @@ -375,7 +378,8 @@ struct SceKernelVplHeader { struct VPL : public KernelObject { const char *GetName() override { return nv.name; } - const char *GetTypeName() override { return "VPL"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "VPL"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VPLID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Vpl; } int GetIDType() const override { return SCE_KERNEL_TMID_Vpl; } @@ -390,15 +394,15 @@ struct VPL : public KernelObject return; } - p.Do(nv); - p.Do(address); + Do(p, nv); + Do(p, address); VplWaitingThread dv = {0}; - p.Do(waitingThreads, dv); + Do(p, waitingThreads, dv); alloc.DoState(p); - p.Do(pausedWaits); + Do(p, pausedWaits); if (s >= 2) { - p.Do(header); + Do(p, header); } } @@ -422,8 +426,10 @@ void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId); void __KernelMemoryInit() { - kernelMemory.Init(PSP_GetKernelMemoryBase(), PSP_GetKernelMemoryEnd()-PSP_GetKernelMemoryBase()); - userMemory.Init(PSP_GetUserMemoryBase(), PSP_GetUserMemoryEnd()-PSP_GetUserMemoryBase()); + kernelMemory.Init(PSP_GetKernelMemoryBase(), PSP_GetKernelMemoryEnd() - PSP_GetKernelMemoryBase()); + userMemory.Init(PSP_GetUserMemoryBase(), PSP_GetUserMemoryEnd() - PSP_GetUserMemoryBase()); + Memory::Memset(PSP_GetKernelMemoryBase(), 0, PSP_GetKernelMemoryEnd() - PSP_GetKernelMemoryBase()); + Memory::Memset(PSP_GetUserMemoryBase(), 0, PSP_GetUserMemoryEnd() - PSP_GetUserMemoryBase()); INFO_LOG(SCEKERNEL, "Kernel and user memory pools initialized"); vplWaitTimer = CoreTiming::RegisterEvent("VplTimeout", __KernelVplTimeout); @@ -454,16 +460,16 @@ void __KernelMemoryDoState(PointerWrap &p) kernelMemory.DoState(p); userMemory.DoState(p); - p.Do(vplWaitTimer); + Do(p, vplWaitTimer); CoreTiming::RestoreRegisterEvent(vplWaitTimer, "VplTimeout", __KernelVplTimeout); - p.Do(fplWaitTimer); + Do(p, fplWaitTimer); CoreTiming::RestoreRegisterEvent(fplWaitTimer, "FplTimeout", __KernelFplTimeout); - p.Do(flags_); - p.Do(sdkVersion_); - p.Do(compilerVersion_); - p.DoArray(tlsplUsedIndexes, ARRAY_SIZE(tlsplUsedIndexes)); + Do(p, flags_); + Do(p, sdkVersion_); + Do(p, compilerVersion_); + DoArray(p, tlsplUsedIndexes, ARRAY_SIZE(tlsplUsedIndexes)); if (s >= 2) { - p.Do(tlsplThreadEndChecks); + Do(p, tlsplThreadEndChecks); } } @@ -899,7 +905,8 @@ class PartitionMemoryBlock : public KernelObject { public: const char *GetName() override { return name; } - const char *GetTypeName() override { return "MemoryPart"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "MemoryPart"; } void GetQuickInfo(char *ptr, int size) override { int sz = alloc->GetBlockSizeFromAddress(address); @@ -946,8 +953,8 @@ public: if (!s) return; - p.Do(address); - p.DoArray(name, sizeof(name)); + Do(p, address); + DoArray(p, name, sizeof(name)); } u32 address; @@ -969,7 +976,7 @@ static u32 sceKernelTotalFreeMemSize() return retVal; } -static int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 size, u32 addr) +int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 size, u32 addr) { if (name == NULL) { @@ -1019,14 +1026,14 @@ static int sceKernelAllocPartitionMemory(int partition, const char *name, int ty return uid; } -static int sceKernelFreePartitionMemory(SceUID id) +int sceKernelFreePartitionMemory(SceUID id) { DEBUG_LOG(SCEKERNEL,"sceKernelFreePartitionMemory(%d)",id); return kernelObjects.Destroy(id); } -static u32 sceKernelGetBlockHeadAddr(SceUID id) +u32 sceKernelGetBlockHeadAddr(SceUID id) { u32 error; PartitionMemoryBlock *block = kernelObjects.Get(id, error); @@ -1869,7 +1876,8 @@ struct NativeTlspl struct TLSPL : public KernelObject { const char *GetName() override { return ntls.name; } - const char *GetTypeName() override { return "TLS"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "TLS"; } static u32 GetMissingErrorCode() { return PSP_ERROR_UNKNOWN_TLSPL_ID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Tlspl; } int GetIDType() const override { return SCE_KERNEL_TMID_Tlspl; } @@ -1882,15 +1890,15 @@ struct TLSPL : public KernelObject if (!s) return; - p.Do(ntls); - p.Do(address); + Do(p, ntls); + Do(p, address); if (s >= 2) - p.Do(alignment); + Do(p, alignment); else alignment = 4; - p.Do(waitingThreads); - p.Do(next); - p.Do(usage); + Do(p, waitingThreads); + Do(p, next); + Do(p, usage); } NativeTlspl ntls; diff --git a/Core/HLE/sceKernelMemory.h b/Core/HLE/sceKernelMemory.h index dce6df77e0..29d7356d00 100644 --- a/Core/HLE/sceKernelMemory.h +++ b/Core/HLE/sceKernelMemory.h @@ -67,3 +67,7 @@ int sceKernelFreeTlspl(SceUID uid); int sceKernelReferTlsplStatus(SceUID uid, u32 infoPtr); void Register_SysMemUserForUser(); + +int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 size, u32 addr); +int sceKernelFreePartitionMemory(SceUID id); +u32 sceKernelGetBlockHeadAddr(SceUID id); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 1d37b3c802..4952f9be31 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -21,15 +21,17 @@ #include "zlib.h" -#include "base/stringutil.h" -#include "Common/ChunkFile.h" -#include "Common/FileUtil.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeSet.h" +#include "Common/File/FileUtil.h" #include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Core.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/HLETables.h" +#include "Core/HLE/Plugins.h" #include "Core/HLE/ReplaceTables.h" #include "Core/Reporting.h" #include "Core/Host.h" @@ -66,10 +68,11 @@ #include "GPU/GPUState.h" enum { - PSP_THREAD_ATTR_USER = 0x80000000 + PSP_THREAD_ATTR_KERNEL = 0x00001000, + PSP_THREAD_ATTR_USER = 0x80000000, }; -enum { +enum : u32 { // Function exports. NID_MODULE_START = 0xD632ACDB, NID_MODULE_STOP = 0xCEE8593C, @@ -151,7 +154,7 @@ void ImportVarSymbol(const VarSymbolImport &var); void ExportVarSymbol(const VarSymbolExport &var); void UnexportVarSymbol(const VarSymbolExport &var); -void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting); +void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting, const char *importingModule); void ExportFuncSymbol(const FuncSymbolExport &func); void UnexportFuncSymbol(const FuncSymbolExport &func); @@ -243,7 +246,8 @@ public: } } const char *GetName() override { return nm.name; } - const char *GetTypeName() override { return "Module"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Module"; } void GetQuickInfo(char *ptr, int size) override { // ignore size @@ -263,14 +267,14 @@ public: if (!s) return; - p.Do(nm); - p.Do(memoryBlockAddr); - p.Do(memoryBlockSize); - p.Do(isFake); + Do(p, nm); + Do(p, memoryBlockAddr); + Do(p, memoryBlockSize); + Do(p, isFake); if (s < 2) { bool isStarted = false; - p.Do(isStarted); + Do(p, isStarted); if (isStarted) nm.status = MODULE_STATUS_STARTED; else @@ -278,24 +282,24 @@ public: } if (s >= 3) { - p.Do(textStart); - p.Do(textEnd); + Do(p, textStart); + Do(p, textEnd); } if (s >= 4) { - p.Do(libstub); - p.Do(libstubend); + Do(p, libstub); + Do(p, libstubend); } ModuleWaitingThread mwt = {0}; - p.Do(waitingThreads, mwt); + Do(p, waitingThreads, mwt); FuncSymbolExport fsx = {{0}}; - p.Do(exportedFuncs, fsx); + Do(p, exportedFuncs, fsx); FuncSymbolImport fsi = {{0}}; - p.Do(importedFuncs, fsi); + Do(p, importedFuncs, fsi); VarSymbolExport vsx = {{0}}; - p.Do(exportedVars, vsx); + Do(p, exportedVars, vsx); VarSymbolImport vsi = {{0}}; - p.Do(importedVars, vsi); + Do(p, importedVars, vsi); if (p.mode == p.MODE_READ) { // On load state, we re-examine in case our syscall ids changed. @@ -327,6 +331,8 @@ public: } } + HLEPlugins::DoState(p); + RebuildImpExpModuleNames(); } @@ -349,7 +355,7 @@ public: // Keep track and actually hook it up if possible. importedFuncs.push_back(func); impExpModuleNames.insert(func.moduleName); - ImportFuncSymbol(func, reimporting); + ImportFuncSymbol(func, reimporting, GetName()); } void ImportVar(const VarSymbolImport &var) { @@ -435,8 +441,8 @@ public: if (!s) return; - p.Do(moduleID_); - p.Do(retValAddr); + Do(p, moduleID_); + Do(p, retValAddr); } static PSPAction *Create() { return new AfterModuleEntryCall; @@ -496,11 +502,11 @@ void __KernelModuleDoState(PointerWrap &p) if (!s) return; - p.Do(actionAfterModule); + Do(p, actionAfterModule); __KernelRestoreActionType(actionAfterModule, AfterModuleEntryCall::Create); if (s >= 2) { - p.Do(loadedModules); + Do(p, loadedModules); } if (p.mode == p.MODE_READ) { @@ -525,6 +531,7 @@ void __KernelModuleShutdown() { loadedModules.clear(); MIPSAnalyst::Reset(); + HLEPlugins::Unload(); } // Sometimes there are multiple LO16's or HI16's per pair, even though the ABI says nothing of this. @@ -709,7 +716,7 @@ void UnexportVarSymbol(const VarSymbolExport &var) { } } -void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting) { +void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting, const char *importingModule) { // Prioritize HLE implementations. // TODO: Or not? if (FuncImportIsSyscall(func.moduleName, func.nid)) { @@ -746,9 +753,10 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting) { // It hasn't been exported yet, but hopefully it will later. bool isKnownModule = GetModuleIndex(func.moduleName) != -1; if (isKnownModule) { - WARN_LOG_REPORT(LOADER, "Unknown syscall in known module '%s': 0x%08x", func.moduleName, func.nid); + // We used to report this, but I don't think it's very interesting anymore. + WARN_LOG(LOADER, "Unknown syscall from known module '%s': 0x%08x (import for '%s')", func.moduleName, func.nid, importingModule); } else { - INFO_LOG(LOADER, "Function (%s,%08x) unresolved, storing for later resolving", func.moduleName, func.nid); + INFO_LOG(LOADER, "Function (%s,%08x) unresolved in '%s', storing for later resolving", func.moduleName, func.nid, importingModule); } if (isKnownModule || !reimporting) { WriteFuncMissingStub(func.stubAddr, func.nid); @@ -758,8 +766,8 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting) { void ExportFuncSymbol(const FuncSymbolExport &func) { if (FuncImportIsSyscall(func.moduleName, func.nid)) { - // Oops, HLE covers this. - WARN_LOG_REPORT(LOADER, "Ignoring func export %s/%08x, already implemented in HLE.", func.moduleName, func.nid); + // HLE covers this already - let's ignore the function. + WARN_LOG(LOADER, "Ignoring func export %s/%08x, already implemented in HLE.", func.moduleName, func.nid); return; } @@ -1536,6 +1544,27 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load return module; } +SceUID KernelLoadModule(const std::string &filename, std::string *error_string) { + PSPFileInfo info = pspFileSystem.GetFileInfo(filename); + if (!info.exists) + return SCE_KERNEL_ERROR_NOFILE; + + std::vector buffer; + buffer.resize((size_t)info.size); + + u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); + pspFileSystem.ReadFile(handle, &buffer[0], info.size); + pspFileSystem.CloseFile(handle); + + u32 error = SCE_KERNEL_ERROR_ILLEGAL_OBJECT; + u32 magic; + PSPModule *module = __KernelLoadELFFromPtr(&buffer[0], buffer.size(), 0, false, error_string, &magic, error); + + if (module == nullptr) + return error; + return module->GetUID(); +} + static PSPModule *__KernelLoadModule(u8 *fileptr, size_t fileSize, SceKernelLMOption *options, std::string *error_string) { PSPModule *module = nullptr; // Check for PBP @@ -1595,6 +1624,11 @@ static void __KernelStartModule(PSPModule *m, int args, const char *argp, SceKer SceUID threadID = __KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute); __KernelSetThreadRA(threadID, NID_MODULERETURN); + + if (HLEPlugins::Load()) { + KernelRotateThreadReadyQueue(0); + __KernelReSchedule("Started plugins"); + } } @@ -1608,6 +1642,16 @@ u32 __KernelGetModuleGP(SceUID uid) { } } +bool KernelModuleIsKernelMode(SceUID uid) { + u32 error; + PSPModule *module = kernelObjects.Get(uid, error); + if (module) { + return (module->nm.attribute & 0x1000) != 0; + } else { + return false; + } +} + void __KernelLoadReset() { // Wipe kernel here, loadexec should reset the entire system if (__KernelIsRunning()) { @@ -1639,7 +1683,7 @@ void __KernelLoadReset() { bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string) { SceKernelLoadExecParam param; - PSP_SetLoading("Loading game..."); + PSP_SetLoading("Loading exec..."); if (paramPtr) Memory::ReadStruct(paramPtr, ¶m); @@ -1698,6 +1742,8 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str return false; } + host->NotifySymbolMapUpdated(); + mipsr4k.pc = module->nm.entry_addr; INFO_LOG(LOADER, "Module entry: %08x", mipsr4k.pc); @@ -1784,7 +1830,7 @@ void __KernelGPUReplay() { // Special ABI: s0 and s1 are the "args". Not null terminated. const char *filenamep = Memory::GetCharPointer(currentMIPS->r[MIPS_REG_S1]); if (!filenamep) { - ERROR_LOG(SYSTEM, "Failed to load dump filename"); + ERROR_LOG(G3D, "Failed to load dump filename"); Core_Stop(); return; } @@ -1826,7 +1872,7 @@ int sceKernelLoadExec(const char *filename, u32 paramPtr) std::string error_string; if (!__KernelLoadExec(exec_filename.c_str(), paramPtr, &error_string)) { ERROR_LOG(SCEMODULE, "sceKernelLoadExec failed: %s", error_string.c_str()); - Core_UpdateState(CORE_ERROR); + Core_UpdateState(CORE_RUNTIME_ERROR); return -1; } if (gpu) { @@ -1945,12 +1991,71 @@ static u32 sceKernelLoadModuleNpDrm(const char *name, u32 flags, u32 optionAddr) return sceKernelLoadModule(name, flags, optionAddr); } +int KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, SceKernelSMOption *smoption, bool *needsWait) { + if (needsWait) { + *needsWait = false; + } + + u32 error; + PSPModule *module = kernelObjects.Get(moduleId, error); + if (!module) { + return error; + } + + u32 priority = 0x20; + u32 stacksize = 0x40000; + int attribute = module->nm.attribute; + u32 entryAddr = module->nm.entry_addr; + + if (module->nm.module_start_func != 0 && module->nm.module_start_func != (u32)-1) { + entryAddr = module->nm.module_start_func; + if (module->nm.module_start_thread_attr != 0) + attribute = module->nm.module_start_thread_attr; + } else if (entryAddr == (u32)-1 || entryAddr == module->memoryBlockAddr - 1) { + if (smoption) { + // TODO: Does sceKernelStartModule() really give an error when no entry only if you pass options? + attribute = smoption->attribute; + } else { + // TODO: Why are we just returning the module ID in this case? + WARN_LOG(SCEMODULE, "sceKernelStartModule(): module has no start or entry func"); + module->nm.status = MODULE_STATUS_STARTED; + return moduleId; + } + } + + if (Memory::IsValidAddress(entryAddr)) { + if (smoption && smoption->priority > 0) { + priority = smoption->priority; + } else if (module->nm.module_start_thread_priority > 0) { + priority = module->nm.module_start_thread_priority; + } + + if (smoption && smoption->stacksize > 0) { + stacksize = smoption->stacksize; + } else if (module->nm.module_start_thread_stacksize > 0) { + stacksize = module->nm.module_start_thread_stacksize; + } + + SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0, (module->nm.attribute & 0x1000) != 0); + __KernelStartThreadValidate(threadID, argsize, argAddr); + __KernelSetThreadRA(threadID, NID_MODULERETURN); + + if (needsWait) { + *needsWait = true; + } + } else if (entryAddr == 0) { + INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): no entry address", moduleId, argsize, argAddr, returnValueAddr); + module->nm.status = MODULE_STATUS_STARTED; + } else { + ERROR_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): invalid entry address", moduleId, argsize, argAddr, returnValueAddr); + return -1; + } + + return moduleId; +} + static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr) { - u32 priority = 0x20; - u32 stacksize = 0x40000; - u32 attr = 0; - int stackPartition = 0; SceKernelSMOption smoption = {0}; if (optionAddr) { Memory::ReadStruct(optionAddr, &smoption); @@ -1979,71 +2084,19 @@ static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 ret INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)", moduleId,argsize,argAddr,returnValueAddr,optionAddr); - int attribute = module->nm.attribute; - u32 entryAddr = module->nm.entry_addr; + bool needsWait; + int ret = KernelStartModule(moduleId, argsize, argAddr, returnValueAddr, optionAddr ? &smoption : nullptr, &needsWait); - if (module->nm.module_start_func != 0 && module->nm.module_start_func != (u32)-1) - { - entryAddr = module->nm.module_start_func; - if (module->nm.module_start_thread_attr != 0) - attribute = module->nm.module_start_thread_attr; - } - else if ((entryAddr == (u32)-1) || entryAddr == module->memoryBlockAddr - 1) - { - if (optionAddr) - { - // TODO: Does sceKernelStartModule() really give an error when no entry only if you pass options? - attribute = smoption.attribute; - } - else - { - // TODO: Why are we just returning the module ID in this case? - WARN_LOG(SCEMODULE, "sceKernelStartModule(): module has no start or entry func"); - module->nm.status = MODULE_STATUS_STARTED; - RETURN(moduleId); - return; - } - } - - if (Memory::IsValidAddress(entryAddr)) - { - if ((optionAddr) && smoption.priority > 0) { - priority = smoption.priority; - } else if (module->nm.module_start_thread_priority > 0) { - priority = module->nm.module_start_thread_priority; - } - - if ((optionAddr) && (smoption.stacksize > 0)) { - stacksize = smoption.stacksize; - } else if (module->nm.module_start_thread_stacksize > 0) { - stacksize = module->nm.module_start_thread_stacksize; - } - - SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0, (module->nm.attribute & 0x1000) != 0); - __KernelStartThreadValidate(threadID, argsize, argAddr); - __KernelSetThreadRA(threadID, NID_MODULERETURN); + if (needsWait) { __KernelWaitCurThread(WAITTYPE_MODULE, moduleId, 1, 0, false, "started module"); const ModuleWaitingThread mwt = {__KernelGetCurThread(), returnValueAddr}; module->nm.status = MODULE_STATUS_STARTING; module->waitingThreads.push_back(mwt); } - else if (entryAddr == 0) - { - INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): no entry address", - moduleId,argsize,argAddr,returnValueAddr,optionAddr); - module->nm.status = MODULE_STATUS_STARTED; - } - else - { - ERROR_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): invalid entry address", - moduleId,argsize,argAddr,returnValueAddr,optionAddr); - RETURN(-1); - return; - } - } - RETURN(moduleId); + RETURN(ret); + } } static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 returnValueAddr, u32 optionAddr) @@ -2312,16 +2365,18 @@ static u32 sceKernelGetModuleId() return __KernelGetCurThreadModuleId(); } +u32 sceKernelFindModuleByUID(u32 uid) +{ + ERROR_LOG(SCEMODULE, "UNIMPL sceKernelFindModuleByUID(%d)", uid); + return 0; +} + u32 sceKernelFindModuleByName(const char *name) { - ERROR_LOG_REPORT(SCEMODULE, "UNIMPL sceKernelFindModuleByName(%s)", name); - int index = GetModuleIndex(name); - - if (index == -1) - return 0; - - return 1; + u32 temp = index + 1; + INFO_LOG(SCEMODULE, "%d = sceKernelFindModuleByName(%s)", temp, name); + return temp; } static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) @@ -2533,8 +2588,11 @@ const HLEFunction ModuleMgrForKernel[] = {0x50F0C1EC, &WrapV_UUUUU, "sceKernelStartModule", 'v', "xxxxx", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED | HLE_KERNEL_SYSCALL }, {0x977DE386, &WrapU_CUU, "sceKernelLoadModule", 'x', "sxx", HLE_KERNEL_SYSCALL }, {0xA1A78C58, &WrapU_CUU, "sceKernelLoadModuleForLoadExecVSHDisc", 'x', "sxx", HLE_KERNEL_SYSCALL }, //fix for tiger x dragon + {0xCC1D3699, &WrapU_UUU, "sceKernelSelfStopUnloadModule", 'x', "xxx", HLE_KERNEL_SYSCALL }, // used in Dissidia final fantasy chinese patch + {0XD1FF982A, &WrapU_UUUUU, "sceKernelStopModule", 'x', "xxxxx", HLE_KERNEL_SYSCALL | HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, // used in Dissidia final fantasy chinese patch {0x748CBED9, &WrapU_UU, "sceKernelQueryModuleInfo", 'x', "xx", HLE_KERNEL_SYSCALL }, {0x644395E2, &WrapU_UUU, "sceKernelGetModuleIdList", 'x', "xxx", HLE_KERNEL_SYSCALL }, + {0X2E0911AA, &WrapU_U, "sceKernelUnloadModule", 'x', "x" , HLE_KERNEL_SYSCALL }, }; void Register_ModuleMgrForUser() diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 232c71d23f..a227153477 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -33,17 +33,22 @@ struct PspModuleInfo { }; class PointerWrap; +struct SceKernelSMOption; KernelObject *__KernelModuleObject(); void __KernelModuleDoState(PointerWrap &p); void __KernelModuleShutdown(); u32 __KernelGetModuleGP(SceUID module); +bool KernelModuleIsKernelMode(SceUID module); bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_string); bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string); void __KernelGPUReplay(); void __KernelReturnFromModuleFunc(); +SceUID KernelLoadModule(const std::string &filename, std::string *error_string); +int KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, SceKernelSMOption *smoption, bool *needsWait); u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr, bool WithStatus); +u32 sceKernelFindModuleByUID(u32 uid); void Register_ModuleMgrForUser(); void Register_ModuleMgrForKernel(); diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index a521c680a1..2df1f2d105 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -17,6 +17,9 @@ #include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/Reporting.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" @@ -27,7 +30,6 @@ #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/KernelWaitHelpers.h" -#include "Common/ChunkFile.h" #define SCE_KERNEL_MPA_THFIFO_S 0x0000 #define SCE_KERNEL_MPA_THPRI_S 0x0100 @@ -131,7 +133,8 @@ static bool __KernelMsgPipeThreadSortPriority(MsgPipeWaitingThread thread1, MsgP struct MsgPipe : public KernelObject { const char *GetName() override { return nmp.name; } - const char *GetTypeName() override { return "MsgPipe"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "MsgPipe"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MPPID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Mpipe; } int GetIDType() const override { return SCE_KERNEL_TMID_Mpipe; } @@ -277,13 +280,13 @@ struct MsgPipe : public KernelObject if (!s) return; - p.Do(nmp); + Do(p, nmp); MsgPipeWaitingThread mpwt1 = {0}, mpwt2 = {0}; - p.Do(sendWaitingThreads, mpwt1); - p.Do(receiveWaitingThreads, mpwt2); - p.Do(pausedSendWaits); - p.Do(pausedReceiveWaits); - p.Do(buffer); + Do(p, sendWaitingThreads, mpwt1); + Do(p, receiveWaitingThreads, mpwt2); + Do(p, pausedSendWaits); + Do(p, pausedReceiveWaits); + Do(p, buffer); } NativeMsgPipe nmp; @@ -661,7 +664,7 @@ void __KernelMsgPipeDoState(PointerWrap &p) if (!s) return; - p.Do(waitTimer); + Do(p, waitTimer); CoreTiming::RestoreRegisterEvent(waitTimer, "MsgPipeTimeout", __KernelMsgPipeTimeout); } diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 38b4583c9b..1b6b314764 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -18,7 +18,9 @@ #include #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/MemMapHelpers.h" #include "Core/HLE/HLE.h" #include "Core/MIPS/MIPS.h" @@ -65,7 +67,8 @@ struct NativeMutex struct PSPMutex : public KernelObject { const char *GetName() override { return nm.name; } - const char *GetTypeName() override { return "Mutex"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Mutex"; } static u32 GetMissingErrorCode() { return PSP_MUTEX_ERROR_NO_SUCH_MUTEX; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Mutex; } int GetIDType() const override { return SCE_KERNEL_TMID_Mutex; } @@ -76,10 +79,10 @@ struct PSPMutex : public KernelObject if (!s) return; - p.Do(nm); + Do(p, nm); SceUID dv = 0; - p.Do(waitingThreads, dv); - p.Do(pausedWaits); + Do(p, waitingThreads, dv); + Do(p, pausedWaits); } NativeMutex nm; @@ -130,7 +133,8 @@ struct NativeLwMutex struct LwMutex : public KernelObject { const char *GetName() override { return nm.name; } - const char *GetTypeName() override { return "LwMutex"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "LwMutex"; } static u32 GetMissingErrorCode() { return PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX; } static int GetStaticIDType() { return SCE_KERNEL_TMID_LwMutex; } int GetIDType() const override { return SCE_KERNEL_TMID_LwMutex; } @@ -141,10 +145,10 @@ struct LwMutex : public KernelObject if (!s) return; - p.Do(nm); + Do(p, nm); SceUID dv = 0; - p.Do(waitingThreads, dv); - p.Do(pausedWaits); + Do(p, waitingThreads, dv); + Do(p, pausedWaits); } NativeLwMutex nm; @@ -180,11 +184,11 @@ void __KernelMutexDoState(PointerWrap &p) if (!s) return; - p.Do(mutexWaitTimer); + Do(p, mutexWaitTimer); CoreTiming::RestoreRegisterEvent(mutexWaitTimer, "MutexTimeout", __KernelMutexTimeout); - p.Do(lwMutexWaitTimer); + Do(p, lwMutexWaitTimer); CoreTiming::RestoreRegisterEvent(lwMutexWaitTimer, "LwMutexTimeout", __KernelLwMutexTimeout); - p.Do(mutexHeldLocks); + Do(p, mutexHeldLocks); } KernelObject *__KernelMutexObject() @@ -206,7 +210,7 @@ static void __KernelMutexAcquireLock(PSPMutex *mutex, int count, SceUID thread) #if defined(_DEBUG) auto locked = mutexHeldLocks.equal_range(thread); for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) - _dbg_assert_msg_(SCEKERNEL, (*iter).second != mutex->GetUID(), "Thread %d / mutex %d wasn't removed from mutexHeldLocks properly.", thread, mutex->GetUID()); + _dbg_assert_msg_((*iter).second != mutex->GetUID(), "Thread %d / mutex %d wasn't removed from mutexHeldLocks properly.", thread, mutex->GetUID()); #endif mutexHeldLocks.insert(std::make_pair(thread, mutex->GetUID())); @@ -238,7 +242,7 @@ static void __KernelMutexEraseLock(PSPMutex *mutex) { static std::vector::iterator __KernelMutexFindPriority(std::vector &waiting) { - _dbg_assert_msg_(SCEKERNEL, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); + _dbg_assert_msg_(!waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); std::vector::iterator iter, end, best = waiting.end(); u32 best_prio = 0xFFFFFFFF; @@ -252,7 +256,7 @@ static std::vector::iterator __KernelMutexFindPriority(std::vector +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/HLE.h" #include "Core/MIPS/MIPS.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" -#include "Common/ChunkFile.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelSemaphore.h" #include "Core/HLE/KernelWaitHelpers.h" +#include "Core/HLE/FunctionWrappers.h" #define PSP_SEMA_ATTR_FIFO 0 #define PSP_SEMA_ATTR_PRIORITY 0x100 @@ -55,7 +58,8 @@ struct NativeSemaphore struct PSPSemaphore : public KernelObject { const char *GetName() override { return ns.name; } - const char *GetTypeName() override { return "Semaphore"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Semaphore"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_SEMID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Semaphore; } @@ -67,10 +71,10 @@ struct PSPSemaphore : public KernelObject { if (!s) return; - p.Do(ns); + Do(p, ns); SceUID dv = 0; - p.Do(waitingThreads, dv); - p.Do(pausedWaits); + Do(p, waitingThreads, dv); + Do(p, pausedWaits); } NativeSemaphore ns; @@ -96,7 +100,7 @@ void __KernelSemaDoState(PointerWrap &p) if (!s) return; - p.Do(semaWaitTimer); + Do(p, semaWaitTimer); CoreTiming::RestoreRegisterEvent(semaWaitTimer, "SemaphoreTimeout", __KernelSemaTimeout); } @@ -456,3 +460,34 @@ int sceKernelPollSema(SceUID id, int wantedCount) } } +// The below functions don't really belong to sceKernelSemaphore. They are the core crypto functionality, +// exposed through the confusingly named "sceUtilsBufferCopyWithRange" name, which Sony placed in the +// not-at-all-suspicious "semaphore" library, which has nothing to do with semaphores. + +static u32 sceUtilsBufferCopyWithRange(u32 outAddr, int outSize, u32 inAddr, int inSize, int cmd) +{ + u8 *outAddress = Memory::IsValidRange(outAddr, outSize) ? Memory::GetPointer(outAddr) : nullptr; + const u8 *inAddress = Memory::IsValidRange(inAddr, inSize) ? Memory::GetPointer(inAddr) : nullptr; + int temp = kirk_sceUtilsBufferCopyWithRange(outAddress, outSize, inAddress, inSize, cmd); + if (temp != 0) { + ERROR_LOG(SCEKERNEL, "hleUtilsBufferCopyWithRange: Failed with %d", temp); + } + return 0; +} + +// Note sure what difference there is between this and sceUtilsBufferCopyWithRange. +static int sceUtilsBufferCopyByPollingWithRange(u32 outAddr, int outSize, u32 inAddr, int inSize, int cmd) +{ + u8 *outAddress = Memory::IsValidRange(outAddr, outSize) ? Memory::GetPointer(outAddr) : nullptr; + const u8 *inAddress = Memory::IsValidRange(inAddr, inSize) ? Memory::GetPointer(inAddr) : nullptr; + return kirk_sceUtilsBufferCopyWithRange(outAddress, outSize, inAddress, inSize, cmd); +} + +const HLEFunction semaphore[] = { + {0x4C537C72, &WrapU_UIUII, "sceUtilsBufferCopyWithRange", 'x', "xixii" }, + {0x77E97079, &WrapI_UIUII, "sceUtilsBufferCopyByPollingWithRange", 'i', "xixii" }, +}; + +void Register_semaphore() { + RegisterModule("semaphore", ARRAY_SIZE(semaphore), semaphore); +} diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index 14df34cbed..0165c0c739 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -31,3 +31,10 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate); void __KernelSemaInit(); void __KernelSemaDoState(PointerWrap &p); KernelObject *__KernelSemaphoreObject(); + +void Register_semaphore(); + +extern "C" +{ +#include "ext/libkirk/kirk_engine.h" +} \ No newline at end of file diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 1239187659..bb255c3c56 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -16,27 +16,30 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include #include #include -#include -#include "base/logging.h" - -#include "Common/LogManager.h" #include "Common/CommonTypes.h" +#include "Common/LogManager.h" +#include "Common/StringUtils.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeList.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/HLE.h" #include "Core/HLE/HLETables.h" #include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSDebugInterface.h" +#include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/Reporting.h" #include "Core/System.h" -#include "Common/ChunkFile.h" #include "Core/HLE/sceAudio.h" #include "Core/HLE/sceKernel.h" @@ -79,6 +82,8 @@ const WaitTypeNames waitTypeNames[] = { { WAITTYPE_TLSPL, "TLS" }, { WAITTYPE_VMEM, "Volatile Mem" }, { WAITTYPE_ASYNCIO, "AsyncIO" }, + { WAITTYPE_MICINPUT, "Microphone input"}, + { WAITTYPE_NET, "Network"}, }; const char *getWaitTypeName(WaitType type) @@ -138,7 +143,8 @@ struct NativeCallback class PSPCallback : public KernelObject { public: const char *GetName() override { return nc.name; } - const char *GetTypeName() override { return "CallBack"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "CallBack"; } void GetQuickInfo(char *ptr, int size) override { sprintf(ptr, "thread=%i, argument= %08x", @@ -160,14 +166,14 @@ public: if (!s) return; - p.Do(nc); + Do(p, nc); // Saved values were moved to mips call, ignoring here. u32 legacySaved = 0; - p.Do(legacySaved); - p.Do(legacySaved); - p.Do(legacySaved); - p.Do(legacySaved); - p.Do(legacySaved); + Do(p, legacySaved); + Do(p, legacySaved); + Do(p, legacySaved); + Do(p, legacySaved); + Do(p, legacySaved); } NativeCallback nc; @@ -279,8 +285,8 @@ public: if (!s) return; - p.Do(calls_); - p.Do(idGen_); + Do(p, calls_); + Do(p, idGen_); } private: @@ -310,18 +316,18 @@ public: if (!s) return; - p.Do(threadID); - p.Do(status); - p.Do(waitType); - p.Do(waitID); - p.Do(waitInfo); - p.Do(isProcessingCallbacks); - p.Do(currentCallbackId); + Do(p, threadID); + Do(p, status); + Do(p, waitType); + Do(p, waitID); + Do(p, waitInfo); + Do(p, isProcessingCallbacks); + Do(p, currentCallbackId); int chainedActionType = 0; if (chainedAction != NULL) chainedActionType = chainedAction->actionTypeID; - p.Do(chainedActionType); + Do(p, chainedActionType); if (chainedActionType != 0) { @@ -365,7 +371,7 @@ public: if (!s) return; - p.Do(cbId); + Do(p, cbId); } SceUID cbId; @@ -373,10 +379,12 @@ public: class PSPThread : public KernelObject { public: + PSPThread() : debug(currentMIPS, context) {} + const char *GetName() override { return nt.name; } - const char *GetTypeName() override { return "Thread"; } - void GetQuickInfo(char *ptr, int size) override - { + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Thread"; } + void GetQuickInfo(char *ptr, int size) override { sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )", context.pc, context.r[MIPS_REG_SP], (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "", @@ -395,7 +403,7 @@ public: int GetIDType() const override { return SCE_KERNEL_TMID_Thread; } bool AllocateStack(u32 &stackSize) { - _assert_msg_(SCEKERNEL, stackSize >= 0x200, "thread stack should be 256 bytes or larger"); + _assert_msg_(stackSize >= 0x200, "thread stack should be 256 bytes or larger"); FreeStack(); @@ -492,10 +500,6 @@ public: return true; } - PSPThread() : debug(currentMIPS, context) { - currentStack.start = 0; - } - // Can't use a destructor since savestates will call that too. void Cleanup() { @@ -532,15 +536,15 @@ public: if (!s) return; - p.Do(nt); - p.Do(waitInfo); - p.Do(moduleId); - p.Do(isProcessingCallbacks); - p.Do(currentMipscallId); - p.Do(currentCallbackId); + Do(p, nt); + Do(p, waitInfo); + Do(p, moduleId); + Do(p, isProcessingCallbacks); + Do(p, currentMipscallId); + Do(p, currentCallbackId); // TODO: If we want to "version" a DoState method here, we can just use minVer = 0. - p.Do(context); + Do(p, context); if (s <= 3) { @@ -561,27 +565,27 @@ public: if (s <= 4) std::swap(context.hi, context.lo); - p.Do(callbacks); + Do(p, callbacks); - p.Do(pendingMipsCalls); - p.Do(pushedStacks); - p.Do(currentStack); + Do(p, pendingMipsCalls); + Do(p, pushedStacks); + Do(p, currentStack); if (s >= 2) { - p.Do(waitingThreads); - p.Do(pausedWaits); + Do(p, waitingThreads); + Do(p, pausedWaits); } } - NativeThread nt; + NativeThread nt{}; - ThreadWaitInfo waitInfo; - SceUID moduleId; + ThreadWaitInfo waitInfo{}; + SceUID moduleId = -1; - bool isProcessingCallbacks; - u32 currentMipscallId; - SceUID currentCallbackId; + bool isProcessingCallbacks = false; + u32 currentMipscallId = -1; + SceUID currentCallbackId = -1; PSPThreadContext context; KernelThreadDebugInterface debug; @@ -598,7 +602,7 @@ public: // These are stacks that aren't "active" right now, but will pop off once the func returns. std::vector pushedStacks; - StackInfo currentStack; + StackInfo currentStack{}; // For thread end. std::vector waitingThreads; @@ -681,6 +685,7 @@ int __KernelRegisterActionType(ActionCreator creator) void __KernelRestoreActionType(int actionType, ActionCreator creator) { + _assert_(actionType >= 0); mipsCalls.restoreActionType(actionType, creator); } @@ -695,26 +700,26 @@ void MipsCall::DoState(PointerWrap &p) if (!s) return; - p.Do(entryPoint); - p.Do(cbId); - p.DoArray(args, ARRAY_SIZE(args)); - p.Do(numArgs); + Do(p, entryPoint); + Do(p, cbId); + DoArray(p, args, ARRAY_SIZE(args)); + Do(p, numArgs); // No longer used. u32 legacySavedIdRegister = 0; - p.Do(legacySavedIdRegister); + Do(p, legacySavedIdRegister); u32 legacySavedRa = 0; - p.Do(legacySavedRa); - p.Do(savedPc); - p.Do(savedV0); - p.Do(savedV1); - p.Do(tag); - p.Do(savedId); - p.Do(reschedAfter); + Do(p, legacySavedRa); + Do(p, savedPc); + Do(p, savedV0); + Do(p, savedV1); + Do(p, tag); + Do(p, savedId); + Do(p, reschedAfter); int actionTypeID = 0; if (doAfter != NULL) actionTypeID = doAfter->actionTypeID; - p.Do(actionTypeID); + Do(p, actionTypeID); if (actionTypeID != 0) { if (p.mode == p.MODE_READ) @@ -970,48 +975,48 @@ void __KernelThreadingDoState(PointerWrap &p) if (!s) return; - p.Do(g_inCbCount); - p.Do(currentCallbackThreadID); - p.Do(readyCallbacksCount); - p.Do(idleThreadHackAddr); - p.Do(threadReturnHackAddr); - p.Do(cbReturnHackAddr); - p.Do(intReturnHackAddr); - p.Do(extendReturnHackAddr); - p.Do(moduleReturnHackAddr); + Do(p, g_inCbCount); + Do(p, currentCallbackThreadID); + Do(p, readyCallbacksCount); + Do(p, idleThreadHackAddr); + Do(p, threadReturnHackAddr); + Do(p, cbReturnHackAddr); + Do(p, intReturnHackAddr); + Do(p, extendReturnHackAddr); + Do(p, moduleReturnHackAddr); if (s >= 4) { - p.Do(hleReturnHackAddr); + Do(p, hleReturnHackAddr); } else { hleReturnHackAddr = 0; } - p.Do(currentThread); + Do(p, currentThread); SceUID dv = 0; - p.Do(threadqueue, dv); - p.DoArray(threadIdleID, ARRAY_SIZE(threadIdleID)); - p.Do(dispatchEnabled); + Do(p, threadqueue, dv); + DoArray(p, threadIdleID, ARRAY_SIZE(threadIdleID)); + Do(p, dispatchEnabled); - p.Do(threadReadyQueue); + Do(p, threadReadyQueue); - p.Do(eventScheduledWakeup); + Do(p, eventScheduledWakeup); CoreTiming::RestoreRegisterEvent(eventScheduledWakeup, "ScheduledWakeup", &hleScheduledWakeup); - p.Do(eventThreadEndTimeout); + Do(p, eventThreadEndTimeout); CoreTiming::RestoreRegisterEvent(eventThreadEndTimeout, "ThreadEndTimeout", &hleThreadEndTimeout); - p.Do(actionAfterMipsCall); + Do(p, actionAfterMipsCall); __KernelRestoreActionType(actionAfterMipsCall, ActionAfterMipsCall::Create); - p.Do(actionAfterCallback); + Do(p, actionAfterCallback); __KernelRestoreActionType(actionAfterCallback, ActionAfterCallback::Create); - p.Do(pausedDelays); + Do(p, pausedDelays); __SetCurrentThread(kernelObjects.GetFast(currentThread), currentThread, __KernelGetThreadName(currentThread)); lastSwitchCycles = CoreTiming::GetTicks(); if (s >= 2) - p.Do(threadEventHandlers); + Do(p, threadEventHandlers); if (s >= 3) - p.Do(pendingDeleteThreads); + Do(p, pendingDeleteThreads); } void __KernelThreadingDoStateLate(PointerWrap &p) @@ -1048,7 +1053,7 @@ static void __KernelFireThreadEnd(SceUID threadID) // TODO: Use __KernelChangeThreadState instead? It has other affects... static void __KernelChangeReadyState(PSPThread *thread, SceUID threadID, bool ready) { // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc. - _dbg_assert_msg_(SCEKERNEL, thread->GetUID() == threadID, "Incorrect threadID"); + _dbg_assert_msg_(thread->GetUID() == threadID, "Incorrect threadID"); int prio = thread->nt.currentPriority; if (thread->isReady()) @@ -1145,6 +1150,10 @@ bool __KernelSwitchToThread(SceUID threadID, const char *reason) if (current && current->isRunning()) __KernelChangeReadyState(current, currentThread, true); + if (!Memory::IsValidAddress(t->context.pc)) { + Core_ExecException(t->context.pc, currentMIPS->pc, ExecExceptionType::THREAD); + } + __KernelSwitchContext(t, reason); return true; } @@ -1185,6 +1194,11 @@ void __KernelThreadingShutdown() { pendingDeleteThreads.clear(); } +std::string __KernelThreadingSummary() { + PSPThread *t = __GetCurrentThread(); + return StringFromFormat("Cur thread: %s (attr %08x)", t ? t->GetName() : "(null)", t ? t->nt.attr : 0); +} + const char *__KernelGetThreadName(SceUID threadID) { u32 error; @@ -1415,7 +1429,7 @@ u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 i break; default: - _dbg_assert_msg_(SCEKERNEL, false, "Unexpected type %d", type); + _dbg_assert_msg_(false, "Unexpected type %d", type); } for (size_t i = 0; i < threadqueue.size(); i++) { @@ -1461,6 +1475,10 @@ void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled) { memcpy(currentMIPS->vfpuCtrl, ctx->vfpuCtrl, sizeof(ctx->vfpuCtrl)); } + if (!Memory::IsValidAddress(ctx->pc)) { + Core_ExecException(ctx->pc, currentMIPS->pc, ExecExceptionType::THREAD); + } + memcpy(currentMIPS->other, ctx->other, sizeof(ctx->other)); if (MIPSComp::jit) { // When thread switching, we must update the rounding mode if cached in the jit. @@ -1515,7 +1533,7 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time } PSPThread *thread = __GetCurrentThread(); - assert(thread != nullptr); + _assert_(thread != nullptr); thread->nt.waitID = waitID; thread->nt.waitType = type; __KernelChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->nt.status & THREADSTATUS_SUSPEND))); @@ -1910,6 +1928,10 @@ SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int strcpy(thread->nt.name, "root"); + if (!Memory::IsValidAddress(thread->context.pc)) { + Core_ExecException(thread->context.pc, currentMIPS->pc, ExecExceptionType::THREAD); + } + __KernelLoadContext(&thread->context, (attr & PSP_THREAD_ATTR_VFPU) != 0); currentMIPS->r[MIPS_REG_A0] = args; currentMIPS->r[MIPS_REG_SP] -= (args + 0xf) & ~0xf; @@ -1960,9 +1982,13 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 // Some are USB/VSH specific, probably removes when they are from the wrong module? attr &= ~PSP_THREAD_ATTR_USER_ERASE; - // We're assuming all threads created are user threads. - if ((attr & PSP_THREAD_ATTR_KERNEL) == 0) - attr |= PSP_THREAD_ATTR_USER; + if ((attr & PSP_THREAD_ATTR_KERNEL) == 0) { + if (allowKernel && (attr & PSP_THREAD_ATTR_USER) == 0) { + attr |= PSP_THREAD_ATTR_KERNEL; + } else { + attr |= PSP_THREAD_ATTR_USER; + } + } SceUID id = __KernelCreateThreadInternal(threadName, moduleID, entry, prio, stacksize, attr); if ((u32)id == SCE_KERNEL_ERROR_NO_MEMORY) @@ -1987,8 +2013,9 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr) { PSPThread *cur = __GetCurrentThread(); - bool allowKernel = cur ? (cur->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0 : false; - return __KernelCreateThread(threadName, __KernelGetCurThreadModuleId(), entry, prio, stacksize, attr, optionAddr, allowKernel); + SceUID module = __KernelGetCurThreadModuleId(); + bool allowKernel = KernelModuleIsKernelMode(module) || hleIsKernelMode() || (cur ? (cur->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0 : false); + return __KernelCreateThread(threadName, module, entry, prio, stacksize, attr, optionAddr, allowKernel); } int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bool forceArgs) { @@ -2034,6 +2061,9 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo // Smaller is better for priority. Only switch if the new thread is better. if (cur && cur->nt.currentPriority > startThread->nt.currentPriority) { + if (!Memory::IsValidAddress(startThread->context.pc)) { + Core_ExecException(startThread->context.pc, currentMIPS->pc, ExecExceptionType::THREAD); + } __KernelChangeReadyState(cur, currentThread, true); hleReSchedule("thread started"); } @@ -2109,7 +2139,7 @@ void __KernelReturnFromThread() int exitStatus = currentMIPS->r[MIPS_REG_V0]; PSPThread *thread = __GetCurrentThread(); - _dbg_assert_msg_(SCEKERNEL, thread != NULL, "Returned from a NULL thread."); + _dbg_assert_msg_(thread != NULL, "Returned from a NULL thread."); DEBUG_LOG(SCEKERNEL, "__KernelReturnFromThread: %d", exitStatus); __KernelStopThread(currentThread, exitStatus, "thread returned"); @@ -2122,11 +2152,16 @@ void __KernelReturnFromThread() // The stack will be deallocated when the thread is deleted. } -void sceKernelExitThread(int exitStatus) { +int sceKernelExitThread(int exitStatus) { + if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); PSPThread *thread = __GetCurrentThread(); - _dbg_assert_msg_(SCEKERNEL, thread != NULL, "Exited from a NULL thread."); + _dbg_assert_msg_(thread != NULL, "Exited from a NULL thread."); INFO_LOG(SCEKERNEL, "sceKernelExitThread(%d)", exitStatus); + if (exitStatus < 0) { + exitStatus = SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; + } __KernelStopThread(currentThread, exitStatus, "thread exited"); hleReSchedule("thread exited"); @@ -2135,11 +2170,12 @@ void sceKernelExitThread(int exitStatus) { __KernelThreadTriggerEvent((thread->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0, thread->GetUID(), THREADEVENT_EXIT); // The stack will be deallocated when the thread is deleted. + return 0; } void _sceKernelExitThread(int exitStatus) { PSPThread *thread = __GetCurrentThread(); - _dbg_assert_msg_(SCEKERNEL, thread != NULL, "_Exited from a NULL thread."); + _dbg_assert_msg_(thread != NULL, "_Exited from a NULL thread."); ERROR_LOG_REPORT(SCEKERNEL, "_sceKernelExitThread(%d): should not be called directly", exitStatus); __KernelStopThread(currentThread, exitStatus, "thread _exited"); @@ -2152,7 +2188,9 @@ void _sceKernelExitThread(int exitStatus) { // The stack will be deallocated when the thread is deleted. } -void sceKernelExitDeleteThread(int exitStatus) { +int sceKernelExitDeleteThread(int exitStatus) { + if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); PSPThread *thread = __GetCurrentThread(); if (thread) { @@ -2170,6 +2208,7 @@ void sceKernelExitDeleteThread(int exitStatus) { } else ERROR_LOG_REPORT(SCEKERNEL, "sceKernelExitDeleteThread(%d) ERROR - could not find myself!", exitStatus); + return 0; } u32 sceKernelSuspendDispatchThread() @@ -2209,10 +2248,7 @@ bool __KernelIsDispatchEnabled() return dispatchEnabled && __InterruptsEnabled(); } -int sceKernelRotateThreadReadyQueue(int priority) -{ - VERBOSE_LOG(SCEKERNEL, "sceKernelRotateThreadReadyQueue(%x)", priority); - +int KernelRotateThreadReadyQueue(int priority) { PSPThread *cur = __GetCurrentThread(); // 0 is special, it means "my current priority." @@ -2222,11 +2258,9 @@ int sceKernelRotateThreadReadyQueue(int priority) if (priority <= 0x07 || priority > 0x77) return SCE_KERNEL_ERROR_ILLEGAL_PRIORITY; - if (!threadReadyQueue.empty(priority)) - { + if (!threadReadyQueue.empty(priority)) { // In other words, yield to everyone else. - if (cur->nt.currentPriority == priority) - { + if (cur->nt.currentPriority == priority) { threadReadyQueue.push_back(priority, currentThread); cur->nt.status = (cur->nt.status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; } @@ -2235,11 +2269,18 @@ int sceKernelRotateThreadReadyQueue(int priority) threadReadyQueue.rotate(priority); } - hleReSchedule("rotatethreadreadyqueue"); - hleEatCycles(250); return 0; } +int sceKernelRotateThreadReadyQueue(int priority) { + int result = KernelRotateThreadReadyQueue(priority); + if (result == 0) { + hleReSchedule("rotatethreadreadyqueue"); + hleEatCycles(250); + } + return hleLogSuccessVerboseI(SCEKERNEL, result); +} + int sceKernelDeleteThread(int threadID) { if (threadID == 0 || threadID == currentThread) { ERROR_LOG(SCEKERNEL, "sceKernelDeleteThread(%i): cannot delete current thread", threadID); @@ -2269,6 +2310,8 @@ int sceKernelTerminateDeleteThread(int threadID) ERROR_LOG(SCEKERNEL, "sceKernelTerminateDeleteThread(%i): cannot terminate current thread", threadID); return SCE_KERNEL_ERROR_ILLEGAL_THID; } + if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); u32 error; PSPThread *t = kernelObjects.Get(threadID, error); @@ -2300,6 +2343,8 @@ int sceKernelTerminateThread(SceUID threadID) { if (__IsInInterrupt() && sceKernelGetCompiledSdkVersion() >= 0x03080000) { return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt"); } + if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); if (threadID == 0 || threadID == currentThread) { return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_THID, "cannot terminate current thread"); } @@ -2770,6 +2815,7 @@ int sceKernelResumeThread(SceUID threadID) // If it was dormant, waiting, etc. before we don't flip its ready state. if (t->nt.status == 0) __KernelChangeReadyState(t, threadID, true); + hleReSchedule("resume thread from suspend"); return 0; } else @@ -2901,6 +2947,10 @@ u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter) Memory::Write_U32(currentMIPS->r[MIPS_REG_SP], thread->currentStack.end - 8); Memory::Write_U32(currentMIPS->pc, thread->currentStack.end - 12); + if (!Memory::IsValidAddress(entryAddr)) { + Core_ExecException(entryAddr, currentMIPS->pc, ExecExceptionType::THREAD); + } + currentMIPS->pc = entryAddr; currentMIPS->r[MIPS_REG_A0] = entryParameter; currentMIPS->r[MIPS_REG_RA] = extendReturnHackAddr; @@ -2933,6 +2983,10 @@ void __KernelReturnFromExtendStack() return; } + if (!Memory::IsValidAddress(restorePC)) { + Core_ExecException(restorePC, currentMIPS->pc, ExecExceptionType::THREAD); + } + DEBUG_LOG(SCEKERNEL, "__KernelReturnFromExtendStack()"); currentMIPS->r[MIPS_REG_RA] = restoreRA; currentMIPS->r[MIPS_REG_SP] = restoreSP; @@ -3101,12 +3155,13 @@ static bool __CanExecuteCallbackNow(PSPThread *thread) { return currentCallbackThreadID == 0 && g_inCbCount == 0; } +// Takes ownership of afterAction. void __KernelCallAddress(PSPThread *thread, u32 entryPoint, PSPAction *afterAction, const u32 args[], int numargs, bool reschedAfter, SceUID cbId) { if (!thread || thread->isStopped()) { WARN_LOG_REPORT(SCEKERNEL, "Running mipscall on dormant thread"); } - _dbg_assert_msg_(SCEKERNEL, numargs <= 6, "MipsCalls can only take 6 args."); + _dbg_assert_msg_(numargs <= 6, "MipsCalls can only take 6 args."); if (thread) { ActionAfterMipsCall *after = (ActionAfterMipsCall *) __KernelCreateAction(actionAfterMipsCall); @@ -3212,6 +3267,10 @@ bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter) call->savedId = cur->currentMipscallId; call->reschedAfter = reschedAfter; + if (!Memory::IsValidAddress(call->entryPoint)) { + Core_ExecException(call->entryPoint, currentMIPS->pc, ExecExceptionType::THREAD); + } + // Set up the new state currentMIPS->pc = call->entryPoint; currentMIPS->r[MIPS_REG_RA] = __KernelCallbackReturnAddress(); @@ -3245,11 +3304,11 @@ void __KernelReturnFromMipsCall() u32 retVal = currentMIPS->r[MIPS_REG_V0]; DEBUG_LOG(SCEKERNEL, "__KernelReturnFromMipsCall(), returned %08x", retVal); - // Should also save/restore wait state here. - if (call->doAfter) - { + // TODO: Should also save/restore wait state here? + if (call->doAfter) { call->doAfter->run(*call); delete call->doAfter; + call->doAfter = nullptr; } u32 &sp = currentMIPS->r[MIPS_REG_SP]; @@ -3261,6 +3320,10 @@ void __KernelReturnFromMipsCall() currentMIPS->r[MIPS_REG_RA] = Memory::Read_U32(sp + MIPS_REG_RA * 4); sp += 32 * 4; + if (!Memory::IsValidAddress(call->savedPc)) { + Core_ExecException(call->savedPc, currentMIPS->pc, ExecExceptionType::THREAD); + } + currentMIPS->pc = call->savedPc; // This is how we set the return value. currentMIPS->r[MIPS_REG_V0] = call->savedV0; @@ -3303,7 +3366,7 @@ void __KernelReturnFromMipsCall() // First arg must be current thread, passed to avoid perf cost of a lookup. bool __KernelExecutePendingMipsCalls(PSPThread *thread, bool reschedAfter) { - _dbg_assert_msg_(SCEKERNEL, thread->GetUID() == __KernelGetCurThread(), "__KernelExecutePendingMipsCalls() should be called only with the current thread."); + _dbg_assert_msg_(thread->GetUID() == __KernelGetCurThread(), "__KernelExecutePendingMipsCalls() should be called only with the current thread."); if (thread->pendingMipsCalls.empty()) { // Nothing to do @@ -3623,18 +3686,19 @@ struct NativeThreadEventHandler { }; struct ThreadEventHandler : public KernelObject { - const char *GetName() { return nteh.name; } - const char *GetTypeName() { return "ThreadEventHandler"; } + const char *GetName() override { return nteh.name; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "ThreadEventHandler"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_TEID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_ThreadEventHandler; } - int GetIDType() const { return SCE_KERNEL_TMID_ThreadEventHandler; } + int GetIDType() const override { return SCE_KERNEL_TMID_ThreadEventHandler; } - virtual void DoState(PointerWrap &p) { + void DoState(PointerWrap &p) override { auto s = p.Section("ThreadEventHandler", 1); if (!s) return; - p.Do(nteh); + Do(p, nteh); } NativeThreadEventHandler nteh; diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 73ba3474ba..65dce5ff54 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -40,8 +40,8 @@ int sceKernelDelaySysClockThreadCB(u32 sysclockAddr); void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason); u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason); int sceKernelDeleteThread(int threadHandle); -void sceKernelExitDeleteThread(int exitStatus); -void sceKernelExitThread(int exitStatus); +int sceKernelExitDeleteThread(int exitStatus); +int sceKernelExitThread(int exitStatus); void _sceKernelExitThread(int exitStatus); SceUID sceKernelGetThreadId(); int sceKernelGetThreadCurrentPriority(); @@ -57,6 +57,7 @@ u32 sceKernelReferThreadRunStatus(u32 uid, u32 statusPtr); int sceKernelReleaseWaitThread(SceUID threadID); int sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr); int sceKernelRotateThreadReadyQueue(int priority); +int KernelRotateThreadReadyQueue(int priority); int sceKernelCheckThreadStack(); int sceKernelSuspendThread(SceUID threadID); int sceKernelResumeThread(SceUID threadID); @@ -106,6 +107,8 @@ enum WaitType : int WAITTYPE_TLSPL = 21, WAITTYPE_VMEM = 22, WAITTYPE_ASYNCIO = 23, + WAITTYPE_MICINPUT = 24, // fake + WAITTYPE_NET = 25, // fake NUM_WAITTYPES }; @@ -155,6 +158,9 @@ void __KernelThreadingInit(); void __KernelThreadingDoState(PointerWrap &p); void __KernelThreadingDoStateLate(PointerWrap &p); void __KernelThreadingShutdown(); + +std::string __KernelThreadingSummary(); + KernelObject *__KernelThreadObject(); KernelObject *__KernelCallbackObject(); @@ -219,6 +225,7 @@ int sceKernelReferCallbackStatus(SceUID cbId, u32 statusAddr); class PSPAction; // Not an official Callback object, just calls a mips function on the current thread. +// Takes ownership of afterAction. void __KernelDirectMipsCall(u32 entryPoint, PSPAction *afterAction, u32 args[], int numargs, bool reschedAfter); void __KernelReturnFromMipsCall(); // Called as HLE function diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 2e16ba9237..8bfa812e30 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -23,7 +23,8 @@ #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/CoreTiming.h" #include "Core/HLE/HLE.h" #include "Core/HLE/sceKernel.h" @@ -48,10 +49,10 @@ void __KernelTimeDoState(PointerWrap &p) return; if (s < 2) { - p.Do(start_time); + Do(p, start_time); } else { u64 t = start_time; - p.Do(t); + Do(p, t); start_time = (time_t)t; } } diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 276f5db13d..245db8a395 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -16,6 +16,10 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeList.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" @@ -24,7 +28,6 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceKernelVTimer.h" #include "Core/HLE/HLE.h" -#include "Common/ChunkFile.h" static int vtimerTimer = -1; static SceUID runningVTimer = 0; @@ -43,7 +46,8 @@ struct NativeVTimer { struct VTimer : public KernelObject { const char *GetName() override { return nvt.name; } - const char *GetTypeName() override { return "VTimer"; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "VTimer"; } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VTID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_VTimer; } int GetIDType() const override { return SCE_KERNEL_TMID_VTimer; } @@ -53,10 +57,10 @@ struct VTimer : public KernelObject { if (!s) return; - p.Do(nvt); + Do(p, nvt); if (s < 2) { u32 memoryPtr; - p.Do(memoryPtr); + Do(p, memoryPtr); } } @@ -191,12 +195,12 @@ void __KernelVTimerDoState(PointerWrap &p) { if (!s) return; - p.Do(vtimerTimer); - p.Do(vtimers); + Do(p, vtimerTimer); + Do(p, vtimers); CoreTiming::RestoreRegisterEvent(vtimerTimer, "VTimer", __KernelTriggerVTimer); if (s >= 2) - p.Do(runningVTimer); + Do(p, runningVTimer); else runningVTimer = 0; } diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 3dab28d418..b3bdcb9b18 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -18,6 +18,8 @@ #include #include +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/Config.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" @@ -70,24 +72,24 @@ public: if (!s) return; - p.Do(mp3StreamStart); - p.Do(mp3StreamEnd); - p.Do(mp3Buf); - p.Do(mp3BufSize); - p.Do(mp3PcmBuf); - p.Do(mp3PcmBufSize); - p.Do(readPosition); - p.Do(bufferRead); - p.Do(bufferWrite); - p.Do(bufferAvailable); - p.Do(mp3DecodedBytes); - p.Do(mp3LoopNum); - p.Do(mp3MaxSamples); - p.Do(mp3SumDecodedSamples); - p.Do(mp3Channels); - p.Do(mp3Bitrate); - p.Do(mp3SamplingRate); - p.Do(mp3Version); + Do(p, mp3StreamStart); + Do(p, mp3StreamEnd); + Do(p, mp3Buf); + Do(p, mp3BufSize); + Do(p, mp3PcmBuf); + Do(p, mp3PcmBufSize); + Do(p, readPosition); + Do(p, bufferRead); + Do(p, bufferWrite); + Do(p, bufferAvailable); + Do(p, mp3DecodedBytes); + Do(p, mp3LoopNum); + Do(p, mp3MaxSamples); + Do(p, mp3SumDecodedSamples); + Do(p, mp3Channels); + Do(p, mp3Bitrate); + Do(p, mp3SamplingRate); + Do(p, mp3Version); }; }; @@ -114,10 +116,10 @@ void __Mp3DoState(PointerWrap &p) { return; if (s >= 2) { - p.Do(mp3Map); + Do(p, mp3Map); } else { std::map mp3Map_old; - p.Do(mp3Map_old); // read old map + Do(p, mp3Map_old); // read old map for (auto it = mp3Map_old.begin(), end = mp3Map_old.end(); it != end; ++it) { auto mp3 = new AuCtx; u32 id = it->first; @@ -147,7 +149,7 @@ void __Mp3DoState(PointerWrap &p) { } if (s >= 3) { - p.Do(resourceInited); + Do(p, resourceInited); } else { // Previous behavior acted as if it was already inited. resourceInited = true; diff --git a/Core/HLE/sceMp4.cpp b/Core/HLE/sceMp4.cpp index ca2c3d3e11..376c4adeaf 100644 --- a/Core/HLE/sceMp4.cpp +++ b/Core/HLE/sceMp4.cpp @@ -17,6 +17,8 @@ #include +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/Reporting.h" @@ -43,7 +45,7 @@ void __AACDoState(PointerWrap &p) { if (!s) return; - p.Do(aacMap); + Do(p, aacMap); } static u32 sceMp4Init() diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index dfaa2ca825..6a10183fab 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -20,6 +20,8 @@ #include #include +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Common/Swap.h" #include "Core/HLE/sceMpeg.h" #include "Core/HLE/sceKernelModule.h" @@ -176,35 +178,35 @@ struct MpegContext { if (!s) return; - p.DoArray(mpegheader, 2048); - p.Do(defaultFrameWidth); - p.Do(videoFrameCount); - p.Do(audioFrameCount); - p.Do(endOfAudioReached); - p.Do(endOfVideoReached); - p.Do(videoPixelMode); - p.Do(mpegMagic); - p.Do(mpegVersion); - p.Do(mpegRawVersion); - p.Do(mpegOffset); - p.Do(mpegStreamSize); - p.Do(mpegFirstTimestamp); - p.Do(mpegLastTimestamp); - p.Do(mpegFirstDate); - p.Do(mpegLastDate); - p.Do(mpegRingbufferAddr); - p.DoArray(esBuffers, MPEG_DATA_ES_BUFFERS); - p.Do(avc); - p.Do(avcRegistered); - p.Do(atracRegistered); - p.Do(pcmRegistered); - p.Do(dataRegistered); - p.Do(ignoreAtrac); - p.Do(ignorePcm); - p.Do(ignoreAvc); - p.Do(isAnalyzed); - p.Do(streamMap); - p.DoClass(mediaengine); + DoArray(p, mpegheader, 2048); + Do(p, defaultFrameWidth); + Do(p, videoFrameCount); + Do(p, audioFrameCount); + Do(p, endOfAudioReached); + Do(p, endOfVideoReached); + Do(p, videoPixelMode); + Do(p, mpegMagic); + Do(p, mpegVersion); + Do(p, mpegRawVersion); + Do(p, mpegOffset); + Do(p, mpegStreamSize); + Do(p, mpegFirstTimestamp); + Do(p, mpegLastTimestamp); + Do(p, mpegFirstDate); + Do(p, mpegLastDate); + Do(p, mpegRingbufferAddr); + DoArray(p, esBuffers, MPEG_DATA_ES_BUFFERS); + Do(p, avc); + Do(p, avcRegistered); + Do(p, atracRegistered); + Do(p, pcmRegistered); + Do(p, dataRegistered); + Do(p, ignoreAtrac); + Do(p, ignorePcm); + Do(p, ignoreAvc); + Do(p, isAnalyzed); + Do(p, streamMap); + DoClass(p, mediaengine); ringbufferNeedsReverse = s < 2; } @@ -365,7 +367,7 @@ public: if (!s) return; - p.Do(ringAddr_); + Do(p, ringAddr_); } void run(MipsCall &call) override; private: @@ -392,20 +394,20 @@ void __MpegDoState(PointerWrap &p) { if (s < 2) { int oldLastMpeg = -1; bool oldIsMpegAnalyzed = false; - p.Do(oldLastMpeg); - p.Do(streamIdGen); - p.Do(oldIsMpegAnalyzed); + Do(p, oldLastMpeg); + Do(p, streamIdGen); + Do(p, oldIsMpegAnalyzed); // Let's assume the oldest version. mpegLibVersion = 0x0101; } else { - p.Do(streamIdGen); - p.Do(mpegLibVersion); + Do(p, streamIdGen); + Do(p, mpegLibVersion); } - p.Do(isMpegInit); - p.Do(actionPostPut); + Do(p, isMpegInit); + Do(p, actionPostPut); __KernelRestoreActionType(actionPostPut, PostPutAction::Create); - p.Do(mpegMap); + Do(p, mpegMap); } void __MpegShutdown() { @@ -1054,8 +1056,8 @@ void __VideoPmpDoState(PointerWrap &p){ return; } - p.Do(pmp_videoSource); - p.Do(pmp_nBlocks); + Do(p, pmp_videoSource); + Do(p, pmp_nBlocks); if (p.mode == PointerWrap::MODE_READ){ // for loadstate, we will reinitialize the pmp codec __VideoPmpShutdown(); @@ -1882,11 +1884,11 @@ static u32 sceMpegAvcCopyYCbCr(u32 mpeg, u32 sourceAddr, u32 YCbCrAddr) MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, sourceAddr, YCbCrAddr); + ERROR_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, sourceAddr, YCbCrAddr); return -1; } - ERROR_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x)", mpeg, sourceAddr, YCbCrAddr); + WARN_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x)", mpeg, sourceAddr, YCbCrAddr); return 0; } @@ -1951,8 +1953,16 @@ static u32 sceMpegAvcCsc(u32 mpeg, u32 sourceAddr, u32 rangeAddr, int frameWidth int y = Memory::Read_U32(rangeAddr + 4); int width = Memory::Read_U32(rangeAddr + 8); int height = Memory::Read_U32(rangeAddr + 12); - int destSize = ctx->mediaengine->writeVideoImageWithRange(destAddr, frameWidth, ctx->videoPixelMode, x, y, width, height); + if (((x | y | width | height) & 0xF) != 0) { + WARN_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x) returning ERROR_MPEG_INVALID_VALUE", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); + return ERROR_MPEG_INVALID_VALUE; + } + if (x < 0 || y < 0 || width < 0 || height < 0) { + WARN_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x) returning ERROR_INVALID_VALUE", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); + return SCE_KERNEL_ERROR_INVALID_VALUE; + } + int destSize = ctx->mediaengine->writeVideoImageWithRange(destAddr, frameWidth, ctx->videoPixelMode, x, y, width, height); gpu->NotifyVideoUpload(destAddr, destSize, frameWidth, ctx->videoPixelMode); // Do not use avcDecodeDelayMs 's value diff --git a/Core/HLE/sceMt19937.cpp b/Core/HLE/sceMt19937.cpp index a402bb5757..cc56df502b 100644 --- a/Core/HLE/sceMt19937.cpp +++ b/Core/HLE/sceMt19937.cpp @@ -28,23 +28,21 @@ static u32 sceMt19937Init(u32 mt19937Addr, u32 seed) { - WARN_LOG(HLE, "sceMt19937Init(%08x, %08x)", mt19937Addr, seed); if (!Memory::IsValidAddress(mt19937Addr)) - return -1; + return hleLogError(HLE, -1); void *ptr = Memory::GetPointer(mt19937Addr); // This is made to match the memory layout of a PSP MT structure exactly. // Let's just construct it in place with placement new. Elite C++ hackery FTW. new (ptr) MersenneTwister(seed); - return 0; + return hleLogSuccessInfoI(HLE, 0); } static u32 sceMt19937UInt(u32 mt19937Addr) { - WARN_LOG(HLE, "sceMt19937UInt(%08x)", mt19937Addr); if (!Memory::IsValidAddress(mt19937Addr)) - return -1; + return hleLogError(HLE, -1); MersenneTwister *mt = (MersenneTwister *)Memory::GetPointer(mt19937Addr); - return mt->R32(); + return hleLogSuccessVerboseX(HLE, mt->R32()); } const HLEFunction sceMt19937[] = diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 4373ec0e72..74d01aa789 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -15,23 +15,26 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#if (defined(__linux__) && !defined(ANDROID)) || defined(__APPLE__) +#if __linux__ || __APPLE__ #include #include #include #include #endif -#include "net/resolve.h" -#include "util/text/parsers.h" +#include "Common/Net/Resolve.h" +#include "Common/Data/Text/Parsers.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceKernelMemory.h" #include "Core/MIPS/MIPS.h" #include "Core/Config.h" #include "Core/MemMapHelpers.h" +#include "Core/Util/PortManager.h" #include "sceKernel.h" #include "sceKernelThread.h" @@ -41,11 +44,13 @@ #include "Core/HLE/proAdhoc.h" #include "Core/HLE/sceNetAdhoc.h" #include "Core/HLE/sceNet.h" +#include "Core/HLE/sceNp.h" #include "Core/Reporting.h" +#include "Core/Instance.h" static bool netInited; -static bool netInetInited; -static bool netApctlInited; +bool netInetInited; + u32 netDropRate = 0; u32 netDropDuration = 0; u32 netPoolAddr = 0; @@ -56,224 +61,427 @@ static struct SceNetMallocStat netMallocStat; static std::map apctlHandlers; +SceNetApctlInfoInternal netApctlInfo; -#ifdef _WIN32 -static HANDLE hIDMapFile = NULL; -#elif (__linux__ && !defined(ANDROID)) || __APPLE__ -static int hIDMapFile = 0; -#endif -static int32_t* pIDBuf = NULL; -#define ID_SHM_NAME "PPSSPP_ID" +bool netApctlInited; +u32 netApctlState; +u32 apctlThreadHackAddr = 0; +u32_le apctlThreadCode[3]; +SceUID apctlThreadID = 0; +int actionAfterApctlMipsCall; +std::recursive_mutex apctlEvtMtx; +std::deque apctlEvents; -// Get current number of instance of PPSSPP running. -static uint8_t getInstanceNumber() { -#ifdef _WIN32 - uint32_t BUF_SIZE = 4096; - SYSTEM_INFO sysInfo; +u32 Net_Term(); +int NetApctl_Term(); +void NetApctl_InitInfo(); - GetSystemInfo(&sysInfo); - int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; - BUF_SIZE = (BUF_SIZE + gran - 1) & ~(gran - 1); - hIDMapFile = CreateFileMapping( - INVALID_HANDLE_VALUE, // use paging file - NULL, // default security - PAGE_READWRITE, // read/write access - 0, // maximum object size (high-order DWORD) - BUF_SIZE, // maximum object size (low-order DWORD) - TEXT(ID_SHM_NAME)); // name of mapping object - DWORD lasterr = GetLastError(); - if (hIDMapFile == NULL) { - ERROR_LOG(SCENET, "Could not create %s file mapping object (%d).", ID_SHM_NAME, lasterr); - return 1; +void AfterApctlMipsCall::DoState(PointerWrap & p) { + auto s = p.Section("AfterApctlMipsCall", 1, 1); + if (!s) + return; + // Just in case there are "s" corruption in the future where s.ver is a negative number + if (s >= 1) { + Do(p, handlerID); + Do(p, oldState); + Do(p, newState); + Do(p, event); + Do(p, error); + Do(p, argsAddr); + } else { + handlerID = -1; + oldState = 0; + newState = 0; + event = 0; + error = 0; + argsAddr = 0; } - pIDBuf = (int32_t*)MapViewOfFile(hIDMapFile, // handle to map object - FILE_MAP_ALL_ACCESS, // read/write permission - 0, - 0, - sizeof(int32_t)); //BUF_SIZE - if (pIDBuf == NULL) { - ERROR_LOG(SCENET, "Could not map view of file %s (%d).", ID_SHM_NAME, GetLastError()); - //CloseHandle(hIDMapFile); - return 1; - } - (*pIDBuf) = max(1, ((*pIDBuf) + 1) % 256); //std::max - int id = *pIDBuf; - UnmapViewOfFile(pIDBuf); - //CloseHandle(hIDMapFile); //Should be called when program exits - //hIDMapFile = NULL; - return id; -#elif (__linux__ && !defined(ANDROID)) || __APPLE__ - long BUF_SIZE = 4096; - //caddr_t pIDBuf; - int status; - - // Create shared memory object - hIDMapFile = shm_open(ID_SHM_NAME, O_CREAT | O_RDWR, 0); - BUF_SIZE = BUF_SIZE < sysconf(_SC_PAGE_SIZE) ? sysconf(_SC_PAGE_SIZE) : BUF_SIZE; - - if ((ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size - ERROR_LOG(SCENET, "ftruncate(%s) failure.", ID_SHM_NAME); - return 1; - } - - pIDBuf = (int32_t*)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0); - if (pIDBuf == MAP_FAILED) { // Set the size - ERROR_LOG(SCENET, "mmap(%s) failure.", ID_SHM_NAME); - pIDBuf = NULL; - return 1; - } - - int id = 1; - if (mlock(pIDBuf, BUF_SIZE) == 0) { - (*pIDBuf) = std::max(1, ((*pIDBuf) + 1) % 256); - id = *pIDBuf; - munlock(pIDBuf, BUF_SIZE); - } - - status = munmap(pIDBuf, BUF_SIZE); // Unmap the page - //status = close(hIDMapFile); // Close file, should be called when program exits? - //status = shm_unlink(ID_SHM_NAME); // Unlink [& delete] shared-memory object, should be called when program exits - return id; -#else - return 1; -#endif } -static void PPSSPPIDCleanup() { -#ifdef _WIN32 - if (hIDMapFile != NULL) { - CloseHandle(hIDMapFile); // If program exited(or crashed?) or the last handle reference closed the shared memory object will be deleted. - hIDMapFile = NULL; - } -#elif (__linux__ && !defined(ANDROID)) || __APPLE__ - // TODO : This unlink should be called when program exits instead of everytime the game reset. - if (hIDMapFile != 0) { - close(hIDMapFile); - //shm_unlink(ID_SHM_NAME); // If program exited or crashed before unlinked the shared memory object and it's contents will persist. - hIDMapFile = 0; - } -#endif +void AfterApctlMipsCall::run(MipsCall& call) { + u32 v0 = currentMIPS->r[MIPS_REG_V0]; + DEBUG_LOG(SCENET, "AfterApctlMipsCall::run [ID=%i][OldState=%d][NewState=%d][Event=%d][Error=%d][ArgsPtr=%08x] [cbId: %u][retV0: %08x]", handlerID, oldState, newState, event, error, argsAddr, call.cbId, v0); + //call.setReturnValue(v0); } -static int InitLocalIP() { - // find local IP - addrinfo *localAddr; - addrinfo * ptr; - char ipstr[256]; - sprintf(ipstr, "127.0.0.%u", PPSSPP_ID); - int iResult = getaddrinfo(ipstr, 0, NULL, &localAddr); - if (iResult != 0) { - ERROR_LOG(SCENET, "DNS Error (%s) result: %d\n", ipstr, iResult); - //osm.Show("DNS Error, can't resolve client bind " + ipstr, 8.0f); - ((sockaddr_in *)&localIP)->sin_family = AF_INET; - ((sockaddr_in *)&localIP)->sin_addr.s_addr = inet_addr(ipstr); //"127.0.0.1" - ((sockaddr_in *)&localIP)->sin_port = 0; - return iResult; - } - for (ptr = localAddr; ptr != NULL; ptr = ptr->ai_next) { - switch (ptr->ai_family) { - case AF_INET: - memcpy(&localIP, ptr->ai_addr, sizeof(sockaddr)); - break; - } - } - ((sockaddr_in *)&localIP)->sin_port = 0; - freeaddrinfo(localAddr); - - // Resolve server dns - addrinfo * resultAddr; - in_addr serverIp; - serverIp.s_addr = INADDR_NONE; - iResult = getaddrinfo(g_Config.proAdhocServer.c_str(), 0, NULL, &resultAddr); - if (iResult != 0) { - ERROR_LOG(SCENET, "DNS Error (%s)\n", g_Config.proAdhocServer.c_str()); - return iResult; - } - for (ptr = resultAddr; ptr != NULL; ptr = ptr->ai_next) { - switch (ptr->ai_family) { - case AF_INET: - serverIp = ((sockaddr_in *)ptr->ai_addr)->sin_addr; - break; - } - } - freeaddrinfo(resultAddr); -#if defined(_WIN32) || (defined(__linux__) && !defined(ANDROID)) || defined(__APPLE__) - isLocalServer = ((serverIp.s_addr & 0xff) == 0x7f); -#else - isLocalServer = false; -#endif - return 0; +void AfterApctlMipsCall::SetData(int HandlerID, int OldState, int NewState, int Event, int Error, u32_le ArgsAddr) { + handlerID = HandlerID; + oldState = OldState; + newState = NewState; + event = Event; + error = Error; + argsAddr = ArgsAddr; } +void InitLocalhostIP() { + // The entire 127.*.*.* is reserved for loopback. + uint32_t localIP = 0x7F000001 + PPSSPP_ID - 1; + + g_localhostIP.in.sin_family = AF_INET; + g_localhostIP.in.sin_addr.s_addr = htonl(localIP); + g_localhostIP.in.sin_port = 0; + + std::string serverStr = StripSpaces(g_Config.proAdhocServer); + isLocalServer = (!strcasecmp(serverStr.c_str(), "localhost") || serverStr.find("127.") == 0); +} + +void __NetApctlInit() { + netApctlInited = false; + netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED; + apctlHandlers.clear(); + memset(&netApctlInfo, 0, sizeof(netApctlInfo)); +} static void __ResetInitNetLib() { netInited = false; - netApctlInited = false; netInetInited = false; memset(&netMallocStat, 0, sizeof(netMallocStat)); + memset(¶meter, 0, sizeof(parameter)); +} + +void __NetCallbackInit() { + // Init Network Callbacks + dummyThreadHackAddr = __CreateHLELoop(dummyThreadCode, "sceNetAdhoc", "__NetTriggerCallbacks", "dummythreadhack"); + matchingThreadHackAddr = __CreateHLELoop(matchingThreadCode, "sceNetAdhocMatching", "__NetMatchingCallbacks", "matchingThreadHack"); + apctlThreadHackAddr = __CreateHLELoop(apctlThreadCode, "sceNetApctl", "__NetApctlCallbacks", "apctlThreadHack"); + + // Newer one should be placed last to prevent callbacks going to the wrong after action after loading from old save state + actionAfterMatchingMipsCall = __KernelRegisterActionType(AfterMatchingMipsCall::Create); + actionAfterAdhocMipsCall = __KernelRegisterActionType(AfterAdhocMipsCall::Create); + actionAfterApctlMipsCall = __KernelRegisterActionType(AfterApctlMipsCall::Create); } void __NetInit() { + // Windows: Assuming WSAStartup already called beforehand portOffset = g_Config.iPortOffset; - //if (PPSSPP_ID == 0) { // Each instance should use the same ID (and IP) once it's automatically assigned for consistency reason, But doesn't work well if PPSSPP_ID reseted everytime emulation restarted - PPSSPP_ID = getInstanceNumber(); // This should be called when program started instead of when the game started/reseted - //} - InitLocalIP(); - INFO_LOG(SCENET, "LocalHost IP will be %s", inet_ntoa(((sockaddr_in *)&localIP)->sin_addr)); - //net::Init(); + isOriPort = g_Config.bEnableUPnP && g_Config.bUPnPUseOriginalPort; + minSocketTimeoutUS = g_Config.iMinTimeout * 1000UL; + + // Init Default AdhocServer struct + g_adhocServerIP.in.sin_family = AF_INET; + g_adhocServerIP.in.sin_port = htons(SERVER_PORT); //27312 // Maybe read this from config too + g_adhocServerIP.in.sin_addr.s_addr = INADDR_NONE; + + InitLocalhostIP(); + + SceNetEtherAddr mac; + getLocalMac(&mac); + NOTICE_LOG(SCENET, "LocalHost IP will be %s [%s]", inet_ntoa(g_localhostIP.in.sin_addr), mac2str(&mac).c_str()); + + // TODO: May be we should initialize & cleanup somewhere else than here for PortManager to be used as general purpose for whatever port forwarding PPSSPP needed + __UPnPInit(); + __ResetInitNetLib(); + __NetApctlInit(); + __NetCallbackInit(); +} + +void __NetApctlShutdown() { + if (apctlThreadHackAddr) { + kernelMemory.Free(apctlThreadHackAddr); + apctlThreadHackAddr = 0; + } } void __NetShutdown() { + // Network Cleanup + Net_Term(); + + __NetApctlShutdown(); __ResetInitNetLib(); - //net::Shutdown(); -#ifdef _MSC_VER - WSACleanup(); -#endif - PPSSPPIDCleanup(); //This should be called when program exited, otherwise everytime emulation restarted PPSSPP_ID will reset causing more than one instance might have the same ID and IP. + + // Since PortManager supposed to be general purpose for whatever port forwarding PPSSPP needed, may be we shouldn't clear & restore ports in here? it will be cleared and restored by PortManager's destructor when exiting PPSSPP anyway + __UPnPShutdown(); } -static void __UpdateApctlHandlers(int oldState, int newState, int flag, int error) { - u32 args[5] = { 0, 0, 0, 0, 0 }; - args[0] = oldState; - args[1] = newState; - args[2] = flag; - args[3] = error; +static void __UpdateApctlHandlers(u32 oldState, u32 newState, u32 flag, u32 error) { + std::lock_guard apctlGuard(apctlEvtMtx); + apctlEvents.push_back({ oldState, newState, flag, error }); +} - for(std::map::iterator it = apctlHandlers.begin(); it != apctlHandlers.end(); ++it) { - args[4] = it->second.argument; - hleEnqueueCall(it->second.entryPoint, 5, args); +// Make sure MIPS calls have been fully executed before the next notifyApctlHandlers +void notifyApctlHandlers(int oldState, int newState, int flag, int error) { + __UpdateApctlHandlers(oldState, newState, flag, error); +} + +void netValidateLoopMemory() { + // Allocate Memory if it wasn't valid/allocated after loaded from old SaveState + if (!apctlThreadHackAddr || (apctlThreadHackAddr && strcmp("apctlThreadHack", kernelMemory.GetBlockTag(apctlThreadHackAddr)) != 0)) { + u32 blockSize = sizeof(apctlThreadCode); + apctlThreadHackAddr = kernelMemory.Alloc(blockSize, false, "apctlThreadHack"); + if (apctlThreadHackAddr) Memory::Memcpy(apctlThreadHackAddr, apctlThreadCode, sizeof(apctlThreadCode)); } } // This feels like a dubious proposition, mostly... void __NetDoState(PointerWrap &p) { - auto s = p.Section("sceNet", 1, 3); + auto s = p.Section("sceNet", 1, 4); if (!s) return; - p.Do(netInited); - p.Do(netInetInited); - p.Do(netApctlInited); - p.Do(apctlHandlers); - p.Do(netMallocStat); + auto cur_netInited = netInited; + auto cur_netInetInited = netInetInited; + auto cur_netApctlInited = netApctlInited; + + Do(p, netInited); + Do(p, netInetInited); + Do(p, netApctlInited); + Do(p, apctlHandlers); + Do(p, netMallocStat); if (s < 2) { netDropRate = 0; netDropDuration = 0; } else { - p.Do(netDropRate); - p.Do(netDropDuration); + Do(p, netDropRate); + Do(p, netDropDuration); } if (s < 3) { netPoolAddr = 0; netThread1Addr = 0; netThread2Addr = 0; } else { - p.Do(netPoolAddr); - p.Do(netThread1Addr); - p.Do(netThread2Addr); + Do(p, netPoolAddr); + Do(p, netThread1Addr); + Do(p, netThread2Addr); } + if (s >= 4) { + Do(p, netApctlState); + Do(p, netApctlInfo); + Do(p, actionAfterApctlMipsCall); + if (actionAfterApctlMipsCall != -1) { + __KernelRestoreActionType(actionAfterApctlMipsCall, AfterApctlMipsCall::Create); + } + Do(p, apctlThreadHackAddr); + Do(p, apctlThreadID); + } + else { + actionAfterApctlMipsCall = -1; + apctlThreadHackAddr = 0; + apctlThreadID = 0; + } + + if (p.mode == p.MODE_READ) { + // Let's not change "Inited" value when Loading SaveState in the middle of multiplayer to prevent memory & port leaks + netApctlInited = cur_netApctlInited; + netInetInited = cur_netInetInited; + netInited = cur_netInited; + + // Discard leftover events + apctlEvents.clear(); + } +} + +template std::string num2hex(I w, size_t hex_len) { + static const char* digits = "0123456789ABCDEF"; + std::string rc(hex_len, '0'); + for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4) + rc[i] = digits[(w >> j) & 0x0f]; + return rc; +} + +std::string error2str(u32 errorCode) { + std::string str = ""; + if (((errorCode >> 31) & 1) != 0) + str += "ERROR "; + if (((errorCode >> 30) & 1) != 0) + str += "CRITICAL "; + switch ((errorCode >> 16) & 0xfff) { + case 0x41: + str += "NET "; + break; + default: + str += "UNK"+num2hex(u16((errorCode >> 16) & 0xfff), 3)+" "; + } + switch ((errorCode >> 8) & 0xff) { + case 0x00: + str += "COMMON "; + break; + case 0x01: + str += "CORE "; + break; + case 0x02: + str += "INET "; + break; + case 0x03: + str += "POECLIENT "; + break; + case 0x04: + str += "RESOLVER "; + break; + case 0x05: + str += "DHCP "; + break; + case 0x06: + str += "ADHOC_AUTH "; + break; + case 0x07: + str += "ADHOC "; + break; + case 0x08: + str += "ADHOC_MATCHING "; + break; + case 0x09: + str += "NETCNF "; + break; + case 0x0a: + str += "APCTL "; + break; + case 0x0b: + str += "ADHOCCTL "; + break; + case 0x0c: + str += "UNKNOWN1 "; + break; + case 0x0d: + str += "WLAN "; + break; + case 0x0e: + str += "EAPOL "; + break; + case 0x0f: + str += "8021x "; + break; + case 0x10: + str += "WPA "; + break; + case 0x11: + str += "UNKNOWN2 "; + break; + case 0x12: + str += "TRANSFER "; + break; + case 0x13: + str += "ADHOC_DISCOVER "; + break; + case 0x14: + str += "ADHOC_DIALOG "; + break; + case 0x15: + str += "WISPR "; + break; + default: + str += "UNKNOWN"+num2hex(u8((errorCode >> 8) & 0xff))+" "; + } + str += num2hex(u8(errorCode & 0xff)); + return str; +} + +void __NetApctlCallbacks() +{ + std::lock_guard apctlGuard(apctlEvtMtx); + int delayus = 10000; + + // How AP works probably like this: Game use sceNetApctl function -> sceNetApctl let the hardware know and do their's thing and have a new State -> Let the game know the resulting State through Event on their handler + if (!apctlEvents.empty()) + { + auto args = apctlEvents.front(); + auto oldState = &args.data[0]; + auto newState = &args.data[1]; + auto event = &args.data[2]; + auto error = &args.data[3]; + apctlEvents.pop_front(); + + // Adjust delay according to current event. Added an extra delay to prevent I/O Timing method from causing disconnection + if (*event == PSP_NET_APCTL_EVENT_CONNECT_REQUEST || *event == PSP_NET_APCTL_EVENT_GET_IP || *event == PSP_NET_APCTL_EVENT_SCAN_REQUEST) + delayus = (adhocEventDelayMS + 2 * adhocExtraPollDelayMS) * 1000; + else + delayus = (adhocEventPollDelayMS + 2 * adhocExtraPollDelayMS) * 1000; + + // Do we need to change the oldState? even if there was error? + //if (*error == 0) + *oldState = netApctlState; + + // Need to make sure netApctlState is updated before calling the callback's mipscall so the game can GetState()/GetInfo() within their handler's subroutine and make use the new State/Info + // Should we update NewState & Error accordingly to Event before executing the mipscall ? sceNetApctl* functions might want to set the error value tho, so we probably should leave it untouched + //*error = 0; + switch (*event) { + case PSP_NET_APCTL_EVENT_CONNECT_REQUEST: + netApctlState = PSP_NET_APCTL_STATE_JOINING; // Should we set the State to PSP_NET_APCTL_STATE_DISCONNECTED if there was error? + if (*error == 0) apctlEvents.push_front({ netApctlState, netApctlState, PSP_NET_APCTL_EVENT_ESTABLISHED, 0 }); // Should we use PSP_NET_APCTL_EVENT_EAP_AUTH if securityType is not NONE? + break; + + case PSP_NET_APCTL_EVENT_ESTABLISHED: + netApctlState = PSP_NET_APCTL_STATE_GETTING_IP; + if (*error == 0) apctlEvents.push_front({ netApctlState, netApctlState, PSP_NET_APCTL_EVENT_GET_IP, 0 }); + break; + + case PSP_NET_APCTL_EVENT_GET_IP: + netApctlState = PSP_NET_APCTL_STATE_GOT_IP; + NetApctl_InitInfo(); + break; + + case PSP_NET_APCTL_EVENT_DISCONNECT_REQUEST: + netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED; + break; + + case PSP_NET_APCTL_EVENT_SCAN_REQUEST: + netApctlState = PSP_NET_APCTL_STATE_SCANNING; + if (*error == 0) apctlEvents.push_front({ netApctlState, netApctlState, PSP_NET_APCTL_EVENT_SCAN_COMPLETE, 0 }); + break; + + case PSP_NET_APCTL_EVENT_SCAN_COMPLETE: + netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED; + break; + + case PSP_NET_APCTL_EVENT_EAP_AUTH: // Is this suppose to happen between JOINING and ESTABLISHED ? + netApctlState = PSP_NET_APCTL_STATE_EAP_AUTH; + if (*error == 0) apctlEvents.push_front({ netApctlState, netApctlState, PSP_NET_APCTL_EVENT_KEY_EXCHANGE, 0 }); // not sure if KEY_EXCHANGE is the next step after AUTH or not tho + break; + + case PSP_NET_APCTL_EVENT_KEY_EXCHANGE: // Is this suppose to happen between JOINING and ESTABLISHED ? + netApctlState = PSP_NET_APCTL_STATE_KEY_EXCHANGE; + if (*error == 0) apctlEvents.push_front({ netApctlState, netApctlState, PSP_NET_APCTL_EVENT_ESTABLISHED, 0 }); + break; + + case PSP_NET_APCTL_EVENT_RECONNECT: + netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED; + if (*error == 0) apctlEvents.push_front({ netApctlState, netApctlState, PSP_NET_APCTL_EVENT_CONNECT_REQUEST, 0 }); + break; + } + // Do we need to change the newState? even if there were error? + //if (*error == 0) + *newState = netApctlState; + + // Since 0 is a valid index to types_ we use -1 to detects if it was loaded from an old save state + if (actionAfterApctlMipsCall < 0) { + actionAfterApctlMipsCall = __KernelRegisterActionType(AfterApctlMipsCall::Create); + } + + // Run mipscall. Should we skipped executing the mipscall if oldState == newState? + for (std::map::iterator it = apctlHandlers.begin(); it != apctlHandlers.end(); ++it) { + DEBUG_LOG(SCENET, "ApctlCallback [ID=%i][OldState=%d][NewState=%d][Event=%d][Error=%d][ArgsPtr=%08x]", it->first, *oldState, *newState, *event, *error, it->second.argument); + args.data[4] = it->second.argument; + AfterApctlMipsCall* after = (AfterApctlMipsCall*)__KernelCreateAction(actionAfterApctlMipsCall); + after->SetData(it->first, *oldState, *newState, *event, *error, it->second.argument); + hleEnqueueCall(it->second.entryPoint, 5, args.data, after); + } + } + + // We are temporarily borrowing APctl thread for NpAuth callbacks for testing to simulate authentication + if (!npAuthEvents.empty()) + { + auto args = npAuthEvents.front(); + auto id = &args.data[0]; + auto result = &args.data[1]; + auto argAddr = &args.data[2]; + npAuthEvents.pop_front(); + + delayus = (adhocEventDelayMS + 2 * adhocExtraPollDelayMS) * 1000; + + int handlerID = *id - 1; + for (std::map::iterator it = npAuthHandlers.begin(); it != npAuthHandlers.end(); ++it) { + if (it->first == handlerID) { + DEBUG_LOG(SCENET, "NpAuthCallback [HandlerID=%i][RequestID=%d][Result=%d][ArgsPtr=%08x]", it->first, *id, *result, it->second.argument); + // TODO: Update result / args.data[1] with the actual ticket length (or error code?) + hleEnqueueCall(it->second.entryPoint, 3, args.data); + } + } + } + + // Must be delayed long enough whenever there is a pending callback. + sceKernelDelayThread(delayus); + hleSkipDeadbeef(); } static inline u32 AllocUser(u32 size, bool fromTop, const char *name) { @@ -289,26 +497,62 @@ static inline void FreeUser(u32 &addr) { addr = 0; } -static u32 sceNetTerm() { - //May also need to Terminate netAdhocctl and netAdhoc since the game (ie. GTA:VCS, Wipeout Pulse, etc) might not called them before calling sceNetTerm and causing them to behave strangely on the next sceNetInit+sceNetAdhocInit - if (netAdhocctlInited) sceNetAdhocctlTerm(); - if (netAdhocInited) sceNetAdhocTerm(); +u32 Net_Term() { + // May also need to Terminate netAdhocctl and netAdhoc to free some resources & threads, since the game (ie. GTA:VCS, Wipeout Pulse, etc) might not called them before calling sceNetTerm and causing them to behave strangely on the next sceNetInit & sceNetAdhocInit + NetAdhocctl_Term(); + NetAdhoc_Term(); + + // TODO: Not implemented yet + NetApctl_Term(); + //NetInet_Term(); + + // Library is initialized + if (netInited) { + // Delete Adhoc Sockets + deleteAllAdhocSockets(); + + // Delete GameMode Buffer + //deleteAllGMB(); + + // Terminate Internet Library + //sceNetInetTerm(); + + // Unload Internet Modules (Just keep it in memory... unloading crashes?!) + // if (_manage_modules != 0) sceUtilityUnloadModule(PSP_MODULE_NET_INET); + // Library shutdown + } - WARN_LOG(SCENET, "sceNetTerm()"); - netInited = false; FreeUser(netPoolAddr); FreeUser(netThread1Addr); FreeUser(netThread2Addr); + netInited = false; return 0; } -// TODO: should that struct actually be initialized here? +static u32 sceNetTerm() { + WARN_LOG(SCENET, "sceNetTerm()"); + int retval = Net_Term(); + + // Give time to make sure everything are cleaned up + hleDelayResult(retval, "give time to init/cleanup", adhocEventDelayMS * 1000); + return retval; +} + +/* +Parameters: + poolsize - Memory pool size (appears to be for the whole of the networking library). + calloutprio - Priority of the SceNetCallout thread. + calloutstack - Stack size of the SceNetCallout thread (defaults to 4096 on non 1.5 firmware regardless of what value is passed). + netintrprio - Priority of the SceNetNetintr thread. + netintrstack - Stack size of the SceNetNetintr thread (defaults to 4096 on non 1.5 firmware regardless of what value is passed). +*/ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netinitPri, u32 netinitStack) { + // TODO: Create Network Threads using given priority & stack // TODO: The correct behavior is actually to allocate more and leak the other threads/pool. // But we reset here for historic reasons (GTA:VCS potentially triggers this.) if (netInited) - sceNetTerm(); + Net_Term(); // This cleanup attempt might not worked when SaveState were loaded in the middle of multiplayer game and re-entering multiplayer, thus causing memory leaks & wasting binded ports. May be we shouldn't save/load "Inited" vars on SaveState? if (poolSize == 0) { return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid pool size"); @@ -340,13 +584,31 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini WARN_LOG(SCENET, "sceNetInit(poolsize=%d, calloutpri=%i, calloutstack=%d, netintrpri=%i, netintrstack=%d) at %08x", poolSize, calloutPri, calloutStack, netinitPri, netinitStack, currentMIPS->pc); netInited = true; - netMallocStat.maximum = poolSize; - netMallocStat.free = poolSize; - netMallocStat.pool = 0; + netMallocStat.pool = poolSize; // This should be the poolSize isn't? + netMallocStat.maximum = poolSize/2; // According to JPCSP's sceNetGetMallocStat this is Currently Used size = (poolSize - free), faked to half the pool + netMallocStat.free = poolSize - netMallocStat.maximum; + + // Clear Socket Translator Memory + memset(&adhocSockets, 0, sizeof(adhocSockets)); return hleLogSuccessI(SCENET, 0); } +// Free(delete) thread info / data. +// Normal usage: sceKernelDeleteThread followed by sceNetFreeThreadInfo with the same threadID as argument +static int sceNetFreeThreadinfo(SceUID thid) { + ERROR_LOG(SCENET, "UNIMPL sceNetFreeThreadinfo(%i)", thid); + + return 0; +} + +// Abort a thread. +static int sceNetThreadAbort(SceUID thid) { + ERROR_LOG(SCENET, "UNIMPL sceNetThreadAbort(%i)", thid); + + return 0; +} + static u32 sceWlanGetEtherAddr(u32 addrAddr) { if (!Memory::IsValidRange(addrAddr, 6)) { // More correctly, it should crash. @@ -354,11 +616,14 @@ static u32 sceWlanGetEtherAddr(u32 addrAddr) { } u8 *addr = Memory::GetPointer(addrAddr); - // Read MAC Address from config - uint8_t mac[6] = {0}; if (PPSSPP_ID > 1) { - memset(&mac, PPSSPP_ID, sizeof(mac)); - } else if (!ParseMacAddress(g_Config.sMACAddress.c_str(), addr)) { + Memory::Memset(addrAddr, PPSSPP_ID, 6); + // Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo) + addr[0] &= 0xfc; + } + else + // Read MAC Address from config + if (!ParseMacAddress(g_Config.sMACAddress.c_str(), addr)) { ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); Memory::Memset(addrAddr, 0, 6); } else { @@ -381,19 +646,18 @@ static u32 sceWlanGetSwitchState() { } // Probably a void function, but often returns a useful value. -static int sceNetEtherNtostr(u32 macPtr, u32 bufferPtr) { - DEBUG_LOG(SCENET, "sceNetEtherNtostr(%08x, %08x)", macPtr, bufferPtr); +static void sceNetEtherNtostr(u32 macPtr, u32 bufferPtr) { + DEBUG_LOG(SCENET, "sceNetEtherNtostr(%08x, %08x) at %08x", macPtr, bufferPtr, currentMIPS->pc); if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) { char *buffer = (char *)Memory::GetPointer(bufferPtr); const u8 *mac = Memory::GetPointer(macPtr); // MAC address is always 6 bytes / 48 bits. - return sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", + sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - } else { - // Possibly a void function, seems to return this on bad args. - return 0x09d40000; + + VERBOSE_LOG(SCENET, "sceNetEtherNtostr - [%s]", buffer); } } @@ -408,7 +672,7 @@ static int hex_to_digit(int c) { } // Probably a void function, but sometimes returns a useful-ish value. -static int sceNetEtherStrton(u32 bufferPtr, u32 macPtr) { +static void sceNetEtherStrton(u32 bufferPtr, u32 macPtr) { DEBUG_LOG(SCENET, "sceNetEtherStrton(%08x, %08x)", bufferPtr, macPtr); if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) { @@ -439,18 +703,16 @@ static int sceNetEtherStrton(u32 bufferPtr, u32 macPtr) { } } + VERBOSE_LOG(SCENET, "sceNetEtherStrton - [%s]", mac2str((SceNetEtherAddr*)Memory::GetPointer(macPtr)).c_str()); // Seems to maybe kinda return the last value. Probably returns void. - return value; - } else { - // Possibly a void function, seems to return this on bad args (or crash.) - return 0; + //return value; } } // Write static data since we don't actually manage any memory for sceNet* yet. static int sceNetGetMallocStat(u32 statPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetGetMallocStat(%x)", statPtr); + VERBOSE_LOG(SCENET, "UNTESTED sceNetGetMallocStat(%x)", statPtr); if(Memory::IsValidAddress(statPtr)) Memory::WriteStruct(statPtr, &netMallocStat); else @@ -467,32 +729,178 @@ static int sceNetInetInit() { return 0; } -static int sceNetInetTerm() { +int sceNetInetTerm() { ERROR_LOG(SCENET, "UNIMPL sceNetInetTerm()"); netInetInited = false; return 0; } -static int sceNetApctlInit() { - ERROR_LOG(SCENET, "UNIMPL sceNetApctlInit()"); +void NetApctl_InitInfo() { + memset(&netApctlInfo, 0, sizeof(netApctlInfo)); + // Set dummy/fake values, these probably not suppose to have valid info before connected to an AP, right? + std::string APname = "Wifi"; // fake AP/hotspot + truncate_cpy(netApctlInfo.name, sizeof(netApctlInfo.name), APname.c_str()); + truncate_cpy(netApctlInfo.ssid, sizeof(netApctlInfo.ssid), APname.c_str()); + memcpy(netApctlInfo.bssid, "\1\1\2\2\3\3", sizeof(netApctlInfo.bssid)); // fake AP's mac address + netApctlInfo.ssidLength = static_cast(APname.length()); + netApctlInfo.strength = 99; + netApctlInfo.channel = g_Config.iWlanAdhocChannel; + if (netApctlInfo.channel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) netApctlInfo.channel = defaultWlanChannel; + // Get Local IP Address + sockaddr_in sockAddr; + getLocalIp(&sockAddr); // This will be valid IP, we probably not suppose to have a valid IP before connected to any AP, right? + char ipstr[INET_ADDRSTRLEN] = "127.0.0.1"; // Patapon 3 seems to try to get current IP using ApctlGetInfo() right after ApctlInit(), what kind of IP should we use as default before ApctlConnect()? it shouldn't be a valid IP, right? + inet_ntop(AF_INET, &sockAddr.sin_addr, ipstr, sizeof(ipstr)); + truncate_cpy(netApctlInfo.ip, sizeof(netApctlInfo.ip), ipstr); + // Change the last number to 1 to indicate a common dns server/internet gateway + ((u8*)&sockAddr.sin_addr.s_addr)[3] = 1; + inet_ntop(AF_INET, &sockAddr.sin_addr, ipstr, sizeof(ipstr)); + truncate_cpy(netApctlInfo.gateway, sizeof(netApctlInfo.gateway), ipstr); + truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), ipstr); + truncate_cpy(netApctlInfo.secondaryDns, sizeof(netApctlInfo.secondaryDns), "8.8.8.8"); + truncate_cpy(netApctlInfo.subNetMask, sizeof(netApctlInfo.subNetMask), "255.255.255.0"); +} + +static int sceNetApctlInit(int stackSize, int initPriority) { + WARN_LOG(SCENET, "UNTESTED %s(%i, %i)", __FUNCTION__, stackSize, initPriority); if (netApctlInited) return ERROR_NET_APCTL_ALREADY_INITIALIZED; + + apctlEvents.clear(); + netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED; + + // Set default value before connected to an AP + memset(&netApctlInfo, 0, sizeof(netApctlInfo)); // NetApctl_InitInfo(); + std::string APname = "Wifi"; // fake AP/hotspot + truncate_cpy(netApctlInfo.name, sizeof(netApctlInfo.name), APname.c_str()); + truncate_cpy(netApctlInfo.ssid, sizeof(netApctlInfo.ssid), APname.c_str()); + memcpy(netApctlInfo.bssid, "\1\1\2\2\3\3", sizeof(netApctlInfo.bssid)); // fake AP's mac address + netApctlInfo.ssidLength = static_cast(APname.length()); + truncate_cpy(netApctlInfo.ip, sizeof(netApctlInfo.ip), "0.0.0.0"); + truncate_cpy(netApctlInfo.gateway, sizeof(netApctlInfo.gateway), "0.0.0.0"); + truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), "0.0.0.0"); + truncate_cpy(netApctlInfo.secondaryDns, sizeof(netApctlInfo.secondaryDns), "0.0.0.0"); + truncate_cpy(netApctlInfo.subNetMask, sizeof(netApctlInfo.subNetMask), "0.0.0.0"); + + // Create APctl fake-Thread + netValidateLoopMemory(); + apctlThreadID = __KernelCreateThread("ApctlThread", __KernelGetCurThreadModuleId(), apctlThreadHackAddr, initPriority, stackSize, PSP_THREAD_ATTR_USER, 0, true); + if (apctlThreadID > 0) { + __KernelStartThread(apctlThreadID, 0, 0); + } + netApctlInited = true; return 0; } -static int sceNetApctlTerm() { - ERROR_LOG(SCENET, "UNIMPL sceNeApctlTerm()"); +int NetApctl_Term() { + // Cleanup Apctl resources + // Delete fake PSP Thread + if (apctlThreadID != 0) { + __KernelStopThread(apctlThreadID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "ApctlThread stopped"); + __KernelDeleteThread(apctlThreadID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "ApctlThread deleted"); + apctlThreadID = 0; + } + netApctlInited = false; - + netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED; + return 0; } -// TODO: How many handlers can the PSP actually have for Apctl? -// TODO: Should we allow the same handler to be added more than once? -static u32 sceNetApctlAddHandler(u32 handlerPtr, u32 handlerArg) { +int sceNetApctlTerm() { + WARN_LOG(SCENET, "UNTESTED %s()", __FUNCTION__); + return NetApctl_Term(); +} + +static int sceNetApctlGetInfo(int code, u32 pInfoAddr) { + WARN_LOG(SCENET, "UNTESTED %s(%i, %08x)", __FUNCTION__, code, pInfoAddr); + + if (!netApctlInited) + return hleLogError(SCENET, ERROR_NET_APCTL_NOT_IN_BSS, "apctl not in bss"); // Only have valid info after joining an AP and got an IP, right? + + if (!Memory::IsValidAddress(pInfoAddr)) + return hleLogError(SCENET, -1, "apctl invalid arg"); + + u8* info = Memory::GetPointer(pInfoAddr); // FIXME: Points to a union instead of a struct thus each field have the same address + + switch (code) { + case PSP_NET_APCTL_INFO_PROFILE_NAME: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.name); + DEBUG_LOG(SCENET, "ApctlInfo - ProfileName: %s", netApctlInfo.name); + break; + case PSP_NET_APCTL_INFO_BSSID: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.bssid); + DEBUG_LOG(SCENET, "ApctlInfo - BSSID: %s", mac2str((SceNetEtherAddr*)&netApctlInfo.bssid).c_str()); + break; + case PSP_NET_APCTL_INFO_SSID: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.ssid); + DEBUG_LOG(SCENET, "ApctlInfo - SSID: %s", netApctlInfo.ssid); + break; + case PSP_NET_APCTL_INFO_SSID_LENGTH: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.ssidLength); + break; + case PSP_NET_APCTL_INFO_SECURITY_TYPE: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.securityType); + break; + case PSP_NET_APCTL_INFO_STRENGTH: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.strength); + break; + case PSP_NET_APCTL_INFO_CHANNEL: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.channel); + break; + case PSP_NET_APCTL_INFO_POWER_SAVE: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.powerSave); + break; + case PSP_NET_APCTL_INFO_IP: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.ip); + DEBUG_LOG(SCENET, "ApctlInfo - IP: %s", netApctlInfo.ip); + break; + case PSP_NET_APCTL_INFO_SUBNETMASK: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.subNetMask); + DEBUG_LOG(SCENET, "ApctlInfo - SubNet Mask: %s", netApctlInfo.subNetMask); + break; + case PSP_NET_APCTL_INFO_GATEWAY: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.gateway); + DEBUG_LOG(SCENET, "ApctlInfo - Gateway IP: %s", netApctlInfo.gateway); + break; + case PSP_NET_APCTL_INFO_PRIMDNS: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.primaryDns); + DEBUG_LOG(SCENET, "ApctlInfo - Primary DNS: %s", netApctlInfo.primaryDns); + break; + case PSP_NET_APCTL_INFO_SECDNS: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.secondaryDns); + DEBUG_LOG(SCENET, "ApctlInfo - Secondary DNS: %s", netApctlInfo.secondaryDns); + break; + case PSP_NET_APCTL_INFO_USE_PROXY: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.useProxy); + break; + case PSP_NET_APCTL_INFO_PROXY_URL: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.proxyUrl); + DEBUG_LOG(SCENET, "ApctlInfo - Proxy URL: %s", netApctlInfo.proxyUrl); + break; + case PSP_NET_APCTL_INFO_PROXY_PORT: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.proxyPort); + break; + case PSP_NET_APCTL_INFO_8021_EAP_TYPE: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.eapType); + break; + case PSP_NET_APCTL_INFO_START_BROWSER: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.startBrowser); + break; + case PSP_NET_APCTL_INFO_WIFISP: + Memory::WriteStruct(pInfoAddr, &netApctlInfo.wifisp); + break; + default: + return hleLogError(SCENET, ERROR_NET_APCTL_INVALID_CODE, "apctl invalid code"); + } + + return hleLogSuccessI(SCENET, 0); +} + +int NetApctl_AddHandler(u32 handlerPtr, u32 handlerArg) { bool foundHandler = false; u32 retval = 0; struct ApctlHandler handler; @@ -504,41 +912,53 @@ static u32 sceNetApctlAddHandler(u32 handlerPtr, u32 handlerArg) { handler.entryPoint = handlerPtr; handler.argument = handlerArg; - for(std::map::iterator it = apctlHandlers.begin(); it != apctlHandlers.end(); it++) { - if(it->second.entryPoint == handlerPtr) { + for (std::map::iterator it = apctlHandlers.begin(); it != apctlHandlers.end(); it++) { + if (it->second.entryPoint == handlerPtr) { foundHandler = true; break; } } - if(!foundHandler && Memory::IsValidAddress(handlerPtr)) { - if(apctlHandlers.size() >= MAX_APCTL_HANDLERS) { - ERROR_LOG(SCENET, "UNTESTED sceNetApctlAddHandler(%x, %x): Too many handlers", handlerPtr, handlerArg); + if (!foundHandler && Memory::IsValidAddress(handlerPtr)) { + if (apctlHandlers.size() >= MAX_APCTL_HANDLERS) { + ERROR_LOG(SCENET, "Failed to Add handler(%x, %x): Too many handlers", handlerPtr, handlerArg); retval = ERROR_NET_ADHOCCTL_TOO_MANY_HANDLERS; // TODO: What's the proper error code for Apctl's TOO_MANY_HANDLERS? return retval; } apctlHandlers[retval] = handler; - WARN_LOG(SCENET, "UNTESTED sceNetApctlAddHandler(%x, %x): added handler %d", handlerPtr, handlerArg, retval); + WARN_LOG(SCENET, "Added Apctl handler(%x, %x): %d", handlerPtr, handlerArg, retval); } else { - ERROR_LOG(SCENET, "UNTESTED sceNetApctlAddHandler(%x, %x): Same handler already exists", handlerPtr, handlerArg); + ERROR_LOG(SCENET, "Existing Apctl handler(%x, %x)", handlerPtr, handlerArg); } // The id to return is the number of handlers currently registered return retval; } -static int sceNetApctlDelHandler(u32 handlerID) { - if(apctlHandlers.find(handlerID) != apctlHandlers.end()) { +// TODO: How many handlers can the PSP actually have for Apctl? +// TODO: Should we allow the same handler to be added more than once? +static u32 sceNetApctlAddHandler(u32 handlerPtr, u32 handlerArg) { + INFO_LOG(SCENET, "%s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); + return NetApctl_AddHandler(handlerPtr, handlerArg); +} + +int NetApctl_DelHandler(u32 handlerID) { + if (apctlHandlers.find(handlerID) != apctlHandlers.end()) { apctlHandlers.erase(handlerID); - WARN_LOG(SCENET, "UNTESTED sceNetapctlDelHandler(%d): deleted handler %d", handlerID, handlerID); + WARN_LOG(SCENET, "Deleted Apctl handler: %d", handlerID); } else { - ERROR_LOG(SCENET, "UNTESTED sceNetapctlDelHandler(%d): asked to delete invalid handler %d", handlerID, handlerID); + ERROR_LOG(SCENET, "Invalid Apctl handler: %d", handlerID); } return 0; } +static int sceNetApctlDelHandler(u32 handlerID) { + INFO_LOG(SCENET, "%s(%d)", __FUNCTION__, handlerID); + return NetApctl_DelHandler(handlerID); +} + static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { ERROR_LOG(SCENET, "UNIMPL sceNetInetInetAton(%s, %08x)", hostname, addrPtr); return -1; @@ -548,7 +968,7 @@ int sceNetInetPoll(void *fds, u32 nfds, int timeout) { // timeout in miliseconds DEBUG_LOG(SCENET, "UNTESTED sceNetInetPoll(%p, %d, %i) at %08x", fds, nfds, timeout, currentMIPS->pc); int retval = -1; SceNetInetPollfd *fdarray = (SceNetInetPollfd *)fds; // SceNetInetPollfd/pollfd, sceNetInetPoll() have similarity to BSD poll() but pollfd have different size on 64bit -//#ifdef _MSC_VER +//#ifdef _WIN32 //WSAPoll only available for Vista or newer, so we'll use an alternative way for XP since Windows doesn't have poll function like *NIX if (nfds > FD_SETSIZE) return -1; fd_set readfds, writefds, exceptfds; @@ -640,20 +1060,198 @@ static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLen return -1; } +int sceNetApctlConnect(int connIndex) { + WARN_LOG(SCENET, "UNTESTED %s(%i)", __FUNCTION__, connIndex); + // Is this connIndex is the index to the scanning's result data or sceNetApctlGetBSSDescIDListUser result? + __UpdateApctlHandlers(0, 0, PSP_NET_APCTL_EVENT_CONNECT_REQUEST, 0); + //hleDelayResult(0, "give time to init/cleanup", adhocEventDelayMS * 1000); + return 0; +} + static int sceNetApctlDisconnect() { ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); // Like its 'sister' function sceNetAdhocctlDisconnect, we need to alert Apctl handlers that a disconnect took place // or else games like Phantasy Star Portable 2 will hang at certain points (e.g. returning to the main menu after trying to connect to PSN). + __UpdateApctlHandlers(0, 0, PSP_NET_APCTL_EVENT_DISCONNECT_REQUEST, 0); return 0; } +int NetApctl_GetState() { + return netApctlState; +} + +static int sceNetApctlGetState(u32 pStateAddr) { + //if (!netApctlInited) return hleLogError(SCENET, ERROR_NET_APCTL_NOT_IN_BSS, "apctl not in bss"); + + // Valid Arguments + if (Memory::IsValidAddress(pStateAddr)) { + // Return Thread Status + Memory::Write_U32(NetApctl_GetState(), pStateAddr); + // Return Success + return hleLogSuccessI(SCENET, 0); + } + + return hleLogError(SCENET, -1, "apctl invalid arg"); +} + +int NetApctl_ScanUser() { + // Scan probably only works when not in connected state, right? + if (netApctlState != PSP_NET_APCTL_STATE_DISCONNECTED) + return hleLogError(SCENET, ERROR_NET_APCTL_NOT_DISCONNECTED, "apctl not disconnected"); + + __UpdateApctlHandlers(0, 0, PSP_NET_APCTL_EVENT_SCAN_REQUEST, 0); + return 0; +} + +static int sceNetApctlScanUser() { + ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + return NetApctl_ScanUser(); +} + +static int sceNetApctlGetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) { + WARN_LOG(SCENET, "UNTESTED %s(%08x, %08x)", __FUNCTION__, sizeAddr, bufAddr); + + const int userInfoSize = 8; + int entries = 1; + if (!Memory::IsValidAddress(sizeAddr)) + hleLogError(SCENET, -1, "apctl invalid arg"); + + int size = Memory::Read_U32(sizeAddr); + // Return size required + Memory::Write_U32(entries * userInfoSize, sizeAddr); + + if (bufAddr != 0 && Memory::IsValidAddress(sizeAddr)) { + int offset = 0; + for (int i = 0; i < entries; i++) { + // Check if enough space available to write the next structure + if (offset + userInfoSize > size) { + break; + } + + DEBUG_LOG(SCENET, "%s returning %d at %08x", __FUNCTION__, i, bufAddr + offset); + + // Pointer to next Network structure in list + Memory::Write_U32((i+1)*userInfoSize + bufAddr, bufAddr + offset); + offset += 4; + + // Entry ID + Memory::Write_U32(i, bufAddr + offset); + offset += 4; + } + // Fix the last Pointer + if (offset > 0) + Memory::Write_U32(0, bufAddr + offset - userInfoSize); + } + + return hleLogWarning(SCENET, 0, "untested"); +} + +static int sceNetApctlGetBSSDescEntryUser(int entryId, int infoId, u32 resultAddr) { + WARN_LOG(SCENET, "UNTESTED %s(%i, %i, %08x)", __FUNCTION__, entryId, infoId, resultAddr); + + if (!Memory::IsValidAddress(resultAddr)) + hleLogError(SCENET, -1, "apctl invalid arg"); + + switch (infoId) { + case PSP_NET_APCTL_DESC_IBSS: // IBSS, 6 bytes + Memory::WriteStruct(resultAddr, &netApctlInfo.bssid); + break; + case PSP_NET_APCTL_DESC_SSID_NAME: + // Return 32 bytes + Memory::WriteStruct(resultAddr, &netApctlInfo.ssid); + break; + case PSP_NET_APCTL_DESC_SSID_NAME_LENGTH: + // Return one 32-bit value + Memory::WriteStruct(resultAddr, &netApctlInfo.ssidLength); + break; + case PSP_NET_APCTL_DESC_SIGNAL_STRENGTH: + // Return 1 byte + Memory::WriteStruct(resultAddr, &netApctlInfo.strength); + break; + case PSP_NET_APCTL_DESC_SECURITY: + // Return one 32-bit value + Memory::WriteStruct(resultAddr, &netApctlInfo.securityType); + break; + default: + return hleLogError(SCENET, ERROR_NET_APCTL_INVALID_CODE, "unknown info id"); + } + + return hleLogWarning(SCENET, 0, "untested"); +} + +static int sceNetApctlScanSSID2() { + ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + return NetApctl_ScanUser(); +} + +static int sceNetApctlGetBSSDescIDList2(u32 Arg1, u32 Arg2, u32 Arg3, u32 Arg4) { + return hleLogError(SCENET, 0, "unimplemented"); +} + +static int sceNetApctlGetBSSDescEntry2(u32 Arg1, u32 Arg2, u32 Arg3, u32 Arg4) { + return hleLogError(SCENET, 0, "unimplemented"); +} + static int sceNetResolverInit() { ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); return 0; } +static int sceNetApctlAddInternalHandler(u32 handlerPtr, u32 handlerArg) { + ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); + // This seems to be a 2nd kind of handler + return NetApctl_AddHandler(handlerPtr, handlerArg); +} + +static int sceNetApctlDelInternalHandler(u32 handlerID) { + ERROR_LOG(SCENET, "UNIMPL %s(%i)", __FUNCTION__, handlerID); + // This seems to be a 2nd kind of handler + return NetApctl_DelHandler(handlerID); +} + +static int sceNetApctl_A7BB73DF(u32 handlerPtr, u32 handlerArg) { + ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); + // This seems to be a 3rd kind of handler + return sceNetApctlAddHandler(handlerPtr, handlerArg); +} + +static int sceNetApctl_6F5D2981(u32 handlerID) { + ERROR_LOG(SCENET, "UNIMPL %s(%i)", __FUNCTION__, handlerID); + // This seems to be a 3rd kind of handler + return sceNetApctlDelHandler(handlerID); +} + +static int sceNetApctl_lib2_69745F0A(int handlerId) { + return hleLogError(SCENET, 0, "unimplemented"); +} + +static int sceNetApctl_lib2_4C19731F(int code, u32 pInfoAddr) { + ERROR_LOG(SCENET, "UNIMPL %s(%i, %08x)", __FUNCTION__, code, pInfoAddr); + return sceNetApctlGetInfo(code, pInfoAddr); +} + +static int sceNetApctlScan() { + ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + return NetApctl_ScanUser(); +} + +static int sceNetApctlGetBSSDescIDList(u32 sizeAddr, u32 bufAddr) { + ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x)", __FUNCTION__, sizeAddr, bufAddr); + return sceNetApctlGetBSSDescIDListUser(sizeAddr, bufAddr); +} + +static int sceNetApctlGetBSSDescEntry(int entryId, int infoId, u32 resultAddr) { + ERROR_LOG(SCENET, "UNIMPL %s(%i, %i, %08x)", __FUNCTION__, entryId, infoId, resultAddr); + return sceNetApctlGetBSSDescEntryUser(entryId, infoId, resultAddr); +} + +static int sceNetApctl_lib2_C20A144C(int connIndex, u32 ps3MacAddressPtr) { + ERROR_LOG(SCENET, "UNIMPL %s(%i, %08x)", __FUNCTION__, connIndex, ps3MacAddressPtr); + return sceNetApctlConnect(connIndex); +} + static int sceNetUpnpInit(int unknown1,int unknown2) { @@ -702,12 +1300,12 @@ static int sceNetSetDropRate(u32 dropRate, u32 dropDuration) const HLEFunction sceNet[] = { {0X39AF39A6, &WrapI_UUUUU, "sceNetInit", 'i', "xxxxx"}, {0X281928A9, &WrapU_V, "sceNetTerm", 'x', "" }, - {0X89360950, &WrapI_UU, "sceNetEtherNtostr", 'i', "xx" }, - {0XD27961C9, &WrapI_UU, "sceNetEtherStrton", 'i', "xx" }, + {0X89360950, &WrapV_UU, "sceNetEtherNtostr", 'v', "xx" }, + {0XD27961C9, &WrapV_UU, "sceNetEtherStrton", 'v', "xx" }, {0X0BF0A3AE, &WrapU_U, "sceNetGetLocalEtherAddr", 'x', "x" }, - {0X50647530, nullptr, "sceNetFreeThreadinfo", '?', "" }, + {0X50647530, &WrapI_I, "sceNetFreeThreadinfo", 'i', "i" }, {0XCC393E48, &WrapI_U, "sceNetGetMallocStat", 'i', "x" }, - {0XAD6844C6, nullptr, "sceNetThreadAbort", '?', "" }, + {0XAD6844C6, &WrapI_I, "sceNetThreadAbort", 'i', "i" }, }; const HLEFunction sceNetResolver[] = { @@ -759,20 +1357,32 @@ const HLEFunction sceNetInet[] = { }; const HLEFunction sceNetApctl[] = { - {0XCFB957C6, nullptr, "sceNetApctlConnect", '?', "" }, + {0XCFB957C6, &WrapI_I, "sceNetApctlConnect", 'i', "i" }, {0X24FE91A1, &WrapI_V, "sceNetApctlDisconnect", 'i', "" }, - {0X5DEAC81B, nullptr, "sceNetApctlGetState", '?', "" }, + {0X5DEAC81B, &WrapI_U, "sceNetApctlGetState", 'i', "x" }, {0X8ABADD51, &WrapU_UU, "sceNetApctlAddHandler", 'x', "xx" }, - {0XE2F91F9B, &WrapI_V, "sceNetApctlInit", 'i', "" }, + {0XE2F91F9B, &WrapI_II, "sceNetApctlInit", 'i', "ii" }, {0X5963991B, &WrapI_U, "sceNetApctlDelHandler", 'i', "x" }, {0XB3EDD0EC, &WrapI_V, "sceNetApctlTerm", 'i', "" }, - {0X2BEFDF23, nullptr, "sceNetApctlGetInfo", '?', "" }, - {0XA3E77E13, nullptr, "sceNetApctlScanSSID2", '?', "" }, - {0XE9B2E5E6, nullptr, "sceNetApctlScanUser", '?', "" }, - {0XF25A5006, nullptr, "sceNetApctlGetBSSDescIDList2", '?', "" }, - {0X2935C45B, nullptr, "sceNetApctlGetBSSDescEntry2", '?', "" }, - {0X04776994, nullptr, "sceNetApctlGetBSSDescEntryUser", '?', "" }, - {0X6BDDCB8C, nullptr, "sceNetApctlGetBSSDescIDListUser", '?', "" }, + {0X2BEFDF23, &WrapI_IU, "sceNetApctlGetInfo", 'i', "ix" }, + {0XA3E77E13, &WrapI_V, "sceNetApctlScanSSID2", 'i', "" }, + {0XE9B2E5E6, &WrapI_V, "sceNetApctlScanUser", 'i', "" }, + {0XF25A5006, &WrapI_UUUU, "sceNetApctlGetBSSDescIDList2", 'i', "xxxx" }, + {0X2935C45B, &WrapI_UUUU, "sceNetApctlGetBSSDescEntry2", 'i', "xxxx" }, + {0X04776994, &WrapI_IIU, "sceNetApctlGetBSSDescEntryUser", 'i', "iix" }, + {0X6BDDCB8C, &WrapI_UU, "sceNetApctlGetBSSDescIDListUser", 'i', "xx" }, + {0X7CFAB990, &WrapI_UU, "sceNetApctlAddInternalHandler", 'i', "xx" }, + {0XE11BAFAB, &WrapI_U, "sceNetApctlDelInternalHandler", 'i', "x" }, + {0XA7BB73DF, &WrapI_UU, "sceNetApctl_A7BB73DF", 'i', "xx" }, + {0X6F5D2981, &WrapI_U, "sceNetApctl_6F5D2981", 'i', "x" }, + {0X69745F0A, &WrapI_I, "sceNetApctl_lib2_69745F0A", 'i', "i" }, + {0X4C19731F, &WrapI_IU, "sceNetApctl_lib2_4C19731F", 'i', "ix" }, + {0XB3CF6849, &WrapI_V, "sceNetApctlScan", 'i', "" }, + {0X0C7FFA5C, &WrapI_UU, "sceNetApctlGetBSSDescIDList", 'i', "xx" }, + {0X96BEB231, &WrapI_IIU, "sceNetApctlGetBSSDescEntry", 'i', "iix" }, + {0XC20A144C, &WrapI_IU, "sceNetApctl_lib2_C20A144C", 'i', "ix" }, + // Fake function for PPSSPP's use. + {0X756E6F10, &WrapV_V<__NetApctlCallbacks>, "__NetApctlCallbacks", 'v', "" }, }; const HLEFunction sceWlanDrv[] = { diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index f5cec1206c..8374a878ff 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -17,8 +17,17 @@ #pragma once +#include #include "Core/HLE/proAdhoc.h" +// Using constants instead of numbers for readability reason, since PSP_THREAD_ATTR_KERNEL/USER is located in sceKernelThread.cpp instead of sceKernelThread.h +#ifndef PSP_THREAD_ATTR_KERNEL +#define PSP_THREAD_ATTR_KERNEL 0x00001000 +#endif +#ifndef PSP_THREAD_ATTR_USER +#define PSP_THREAD_ATTR_USER 0x80000000 +#endif + // Option Names #define PSP_SO_REUSEPORT 0x0200 #define PSP_SO_NBIO 0x1009 @@ -49,18 +58,83 @@ enum { ERROR_NET_RESOLVER_INVALID_HOST = 0x80410414, ERROR_NET_APCTL_ALREADY_INITIALIZED = 0x80410a01, + ERROR_NET_APCTL_INVALID_CODE = 0x80410a02, + ERROR_NET_APCTL_INVALID_IP = 0x80410a03, + ERROR_NET_APCTL_NOT_DISCONNECTED = 0x80410a04, + ERROR_NET_APCTL_NOT_IN_BSS = 0x80410a05, + ERROR_NET_APCTL_WLAN_SWITCH_OFF = 0x80410a06, + ERROR_NET_APCTL_WLAN_BEACON_LOST = 0x80410a07, + ERROR_NET_APCTL_WLAN_DISASSOCIATION = 0x80410a08, + ERROR_NET_APCTL_INVALID_ID = 0x80410a09, + ERROR_NET_APCTL_WLAN_SUSPENDED = 0x80410a0a, + ERROR_NET_APCTL_TIMEOUT = 0x80410a0b, }; enum { - PSP_NET_APCTL_EVENT_DISCONNECT_REQUEST = 5, + PSP_NET_APCTL_STATE_DISCONNECTED = 0, + PSP_NET_APCTL_STATE_SCANNING = 1, + PSP_NET_APCTL_STATE_JOINING = 2, + PSP_NET_APCTL_STATE_GETTING_IP = 3, + PSP_NET_APCTL_STATE_GOT_IP = 4, + PSP_NET_APCTL_STATE_EAP_AUTH = 5, + PSP_NET_APCTL_STATE_KEY_EXCHANGE = 6 }; +enum { + PSP_NET_APCTL_EVENT_CONNECT_REQUEST = 0, + PSP_NET_APCTL_EVENT_SCAN_REQUEST = 1, + PSP_NET_APCTL_EVENT_SCAN_COMPLETE = 2, + PSP_NET_APCTL_EVENT_ESTABLISHED = 3, + PSP_NET_APCTL_EVENT_GET_IP = 4, + PSP_NET_APCTL_EVENT_DISCONNECT_REQUEST = 5, + PSP_NET_APCTL_EVENT_ERROR = 6, + PSP_NET_APCTL_EVENT_INFO = 7, + PSP_NET_APCTL_EVENT_EAP_AUTH = 8, + PSP_NET_APCTL_EVENT_KEY_EXCHANGE = 9, + PSP_NET_APCTL_EVENT_RECONNECT = 10 +}; + +#define PSP_NET_APCTL_INFO_PROFILE_NAME 0 +#define PSP_NET_APCTL_INFO_BSSID 1 +#define PSP_NET_APCTL_INFO_SSID 2 +#define PSP_NET_APCTL_INFO_SSID_LENGTH 3 +#define PSP_NET_APCTL_INFO_SECURITY_TYPE 4 +#define PSP_NET_APCTL_INFO_STRENGTH 5 +#define PSP_NET_APCTL_INFO_CHANNEL 6 +#define PSP_NET_APCTL_INFO_POWER_SAVE 7 +#define PSP_NET_APCTL_INFO_IP 8 +#define PSP_NET_APCTL_INFO_SUBNETMASK 9 +#define PSP_NET_APCTL_INFO_GATEWAY 10 +#define PSP_NET_APCTL_INFO_PRIMDNS 11 +#define PSP_NET_APCTL_INFO_SECDNS 12 +#define PSP_NET_APCTL_INFO_USE_PROXY 13 +#define PSP_NET_APCTL_INFO_PROXY_URL 14 +#define PSP_NET_APCTL_INFO_PROXY_PORT 15 +#define PSP_NET_APCTL_INFO_8021_EAP_TYPE 16 +#define PSP_NET_APCTL_INFO_START_BROWSER 17 +#define PSP_NET_APCTL_INFO_WIFISP 18 + +#define PSP_NET_APCTL_INFO_SECURITY_TYPE_NONE 0 +#define PSP_NET_APCTL_INFO_SECURITY_TYPE_WEP 1 +#define PSP_NET_APCTL_INFO_SECURITY_TYPE_WPA 2 +#define PSP_NET_APCTL_INFO_SECURITY_TYPE_UNSUPPORTED 3 +#define PSP_NET_APCTL_INFO_SECURITY_TYPE_WPA_AES 4 + +#define PSP_NET_APCTL_DESC_IBSS 0 +#define PSP_NET_APCTL_DESC_SSID_NAME 1 +#define PSP_NET_APCTL_DESC_SSID_NAME_LENGTH 2 +#define PSP_NET_APCTL_DESC_SIGNAL_STRENGTH 4 +#define PSP_NET_APCTL_DESC_SECURITY 5 + +#ifdef _MSC_VER +#pragma pack(push,1) +#endif // Sockaddr typedef struct SceNetInetSockaddr { uint8_t sa_len; uint8_t sa_family; uint8_t sa_data[14]; -} SceNetInetSockaddr; +} PACK SceNetInetSockaddr; // Sockaddr_in typedef struct SceNetInetSockaddrIn { @@ -69,27 +143,87 @@ typedef struct SceNetInetSockaddrIn { u16_le sin_port; //uint16_t u32_le sin_addr; //uint32_t uint8_t sin_zero[8]; -} SceNetInetSockaddrIn; +} PACK SceNetInetSockaddrIn; // Polling Event Field typedef struct SceNetInetPollfd { //similar format to pollfd in 32bit (pollfd in 64bit have different size) s32_le fd; s16_le events; s16_le revents; -} SceNetInetPollfd; +} PACK SceNetInetPollfd; -struct ProductStruct { +typedef struct ProductStruct { // Similar to SceNetAdhocctlAdhocId ? s32_le unknown; // Unknown, set to 0 // Product Type ? char product[PRODUCT_CODE_LENGTH]; // Game ID (Example: ULUS10000) -}; +} PACK ProductStruct; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +typedef void(*sceNetApctlHandler)(int oldState, int newState, int event, int error, void* pArg); + +#define APCTL_PROFILENAME_MAXLEN 64 +#define APCTL_SSID_MAXLEN 32 +#define APCTL_IPADDR_MAXLEN 16 +#define APCTL_URL_MAXLEN 128 +typedef struct SceNetApctlInfoInternal { // Using struct instead of union for internal use + char name[APCTL_PROFILENAME_MAXLEN]; + u8 bssid[ETHER_ADDR_LEN]; + char ssid[APCTL_SSID_MAXLEN]; + unsigned int ssidLength; // ssid string length (excluding null terminator) + unsigned int securityType; // a value of PSP_NET_APCTL_INFO_SECURITY_TYPE_NONE..PSP_NET_APCTL_INFO_SECURITY_TYPE_WPA? + u8 strength; // Signal strength in % + u8 channel; + u8 powerSave; // 1 on, 0 off + char ip[APCTL_IPADDR_MAXLEN]; // PSP's IP + char subNetMask[APCTL_IPADDR_MAXLEN]; + char gateway[APCTL_IPADDR_MAXLEN]; + char primaryDns[APCTL_IPADDR_MAXLEN]; + char secondaryDns[APCTL_IPADDR_MAXLEN]; + unsigned int useProxy; // 1 for proxy, 0 for no proxy + char proxyUrl[APCTL_URL_MAXLEN]; + unsigned short proxyPort; + unsigned int eapType; // 0 is none, 1 is EAP-MD5 + unsigned int startBrowser; // 1 = start browser + unsigned int wifisp; // 1 if connection is for Wifi service providers (WISP) for sharing internet connection +} SceNetApctlInfoInternal; struct ApctlHandler { u32 entryPoint; u32 argument; }; +struct ApctlArgs { + u32_le data[5]; // OldState, NewState, Event, Error, ArgsAddr +}; + class PointerWrap; +class AfterApctlMipsCall : public PSPAction { +public: + AfterApctlMipsCall() {} + static PSPAction* Create() { return new AfterApctlMipsCall(); } + void DoState(PointerWrap& p) override; + void run(MipsCall& call) override; + void SetData(int HandlerID, int OldState, int NewState, int Event, int Error, u32_le ArgsAddr); + +private: + int handlerID = -1; + int oldState = 0; + int newState = 0; + int event = 0; + int error = 0; + u32_le argsAddr = 0; +}; + +extern bool netInetInited; +extern bool netApctlInited; +extern SceNetApctlInfoInternal netApctlInfo; + +template std::string num2hex(I w, size_t hex_len = sizeof(I) << 1); +std::string error2str(u32 errorcode); + void Register_sceNet(); void Register_sceWlanDrv(); void Register_sceNetUpnp(); @@ -100,4 +234,9 @@ void __NetInit(); void __NetShutdown(); void __NetDoState(PointerWrap &p); -int sceNetInetPoll(void *fds, u32 nfds, int timeout); \ No newline at end of file +int NetApctl_GetState(); + +int sceNetApctlConnect(int connIndex); +int sceNetInetPoll(void *fds, u32 nfds, int timeout); +int sceNetInetTerm(); +int sceNetApctlTerm(); diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index f2879257ce..770302556f 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -15,57 +15,100 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#if defined(_WIN32) +#include "Common/CommonWindows.h" +#endif + +#if !defined(_WIN32) +#include +#endif + +#ifndef MSG_NOSIGNAL +// Default value to 0x00 (do nothing) in systems where it's not supported. +#define MSG_NOSIGNAL 0x00 +#endif + #include +#include "Common/Thread/ThreadUtil.h" // sceNetAdhoc // This is a direct port of Coldbird's code from http://code.google.com/p/aemu/ // All credit goes to him! #include "Core/Core.h" +#include "Core/Host.h" +#include "Core/Reporting.h" #include "Core/MemMapHelpers.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" +#include "Common/TimeUtil.h" #include "Core/MIPS/MIPSCodeUtils.h" +#include "Core/Util/PortManager.h" #include "Core/HLE/HLEHelperThread.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceKernelThread.h" -#include "Core/HLE/sceNetAdhoc.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceKernelModule.h" #include "Core/HLE/sceKernelInterrupt.h" -#include "Core/HLE/proAdhoc.h" +#include "Core/HLE/sceNetAdhoc.h" #include "Core/HLE/sceNet.h" #include "Core/HLE/proAdhocServer.h" +#include "Core/HLE/KernelWaitHelpers.h" +#include "Common/Data/Text/I18n.h" + // shared in sceNetAdhoc.h since it need to be used from sceNet.cpp also // TODO: Make accessor functions instead, and throw all this state in a struct. bool netAdhocInited; bool netAdhocctlInited; -bool networkInited; +bool networkInited = false; -static bool netAdhocMatchingInited; +bool netAdhocGameModeEntered; + +bool netAdhocMatchingInited; int netAdhocMatchingStarted = 0; +int adhocDefaultTimeout = 2000; //5000 ms +int adhocExtraPollDelayMS = 10; //10 +int adhocEventPollDelayMS = 100; //100; Seems to be the same with PSP_ADHOCCTL_RECV_TIMEOUT +int adhocMatchingEventDelayMS = 30; //30 +int adhocEventDelayMS = 300; //500; This will affect the duration of "Connecting..." dialog/message box in .Hack//Link and Naruto Ultimate Ninja Heroes 3 SceUID threadAdhocID; -std::mutex adhocEvtMtx; -std::vector> adhocctlEvents; -std::vector matchingEvents; +std::recursive_mutex adhocEvtMtx; +std::deque> adhocctlEvents; +std::deque matchingEvents; +std::map adhocctlHandlers; +std::vector matchingThreads; +int IsAdhocctlInCB = 0; + +int adhocctlNotifyEvent = -1; +int adhocSocketNotifyEvent = -1; +std::map adhocctlRequests; +std::map adhocSocketRequests; +std::map sendTargetPeers; + +int gameModeNotifyEvent = -1; + u32 dummyThreadHackAddr = 0; u32_le dummyThreadCode[3]; - -std::map adhocctlHandlers; +u32 matchingThreadHackAddr = 0; +u32_le matchingThreadCode[3]; int matchingEventThread(int matchingId); int matchingInputThread(int matchingId); +int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEtherAddr* addr, u16_le* port); +int PollAdhocSocket(SceNetAdhocPollSd* sds, int count, int timeout); +int FlushPtpSocket(int socketId); +int NetAdhocctl_ExitGameMode(); +static int sceNetAdhocPdpSend(int id, const char* mac, u32 port, void* data, int len, int timeout, int flag); +static int sceNetAdhocPdpRecv(int id, void* addr, void* port, void* buf, void* dataLength, u32 timeout, int flag); -int sceNetAdhocTerm(); -int sceNetAdhocctlTerm(); -int sceNetAdhocMatchingTerm(); -int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAddr); void __NetAdhocShutdown() { - //Kill AdhocServer Thread + // Kill AdhocServer Thread if (adhocServerRunning) { adhocServerRunning = false; if (adhocServerThread.joinable()) { @@ -74,68 +117,811 @@ void __NetAdhocShutdown() { } // Checks to avoid confusing logspam if (netAdhocMatchingInited) { - sceNetAdhocMatchingTerm(); + NetAdhocMatching_Term(); } if (netAdhocctlInited) { - sceNetAdhocctlTerm(); + NetAdhocctl_Term(); } if (netAdhocInited) { - // Should not really call HLE funcs from shutdown. - // Prevent attempting to delete the thread, already deleted by shutdown. - threadAdhocID = 0; - sceNetAdhocTerm(); + NetAdhoc_Term(); } if (dummyThreadHackAddr) { kernelMemory.Free(dummyThreadHackAddr); dummyThreadHackAddr = 0; } + if (matchingThreadHackAddr) { + kernelMemory.Free(matchingThreadHackAddr); + matchingThreadHackAddr = 0; + } +} + +bool IsGameModeActive() { + return netAdhocGameModeEntered && gameModeBuffer != nullptr && gameModeSocket > 0 && adhocSockets[gameModeSocket - 1] != nullptr; +} + +static void __GameModeNotify(u64 userdata, int cyclesLate) { + SceUID threadID = userdata >> 32; + int uid = (int)(userdata & 0xFFFFFFFF); + + // TODO: May be we should check for timeout too? since EnterGammeMode have timeout arg + if (IsGameModeActive()) { + auto sock = adhocSockets[gameModeSocket - 1]; + + // Send Master data + if (masterGameModeArea.dataUpdated) { + for (auto& gma : replicaGameModeAreas) { + if (IsGameModeActive() && IsSocketReady(sock->data.pdp.id, false, true) > 0) { + int sent = sceNetAdhocPdpSend(gameModeSocket, (const char*)&gma.mac, ADHOC_GAMEMODE_PORT, masterGameModeArea.data, masterGameModeArea.size, 0, ADHOC_F_NONBLOCK); + if (sent >= 0) { + masterGameModeArea.dataUpdated = 0; + DEBUG_LOG(SCENET, "GameMode Sent %d bytes to %s", masterGameModeArea.size, mac2str(&gma.mac).c_str()); + } + } + } + } + + // Recv new Replica data + while (IsGameModeActive() && IsSocketReady(sock->data.pdp.id, true, false) > 0) { + SceNetEtherAddr sendermac; + s32_le senderport = ADHOC_GAMEMODE_PORT; + s32_le bufsz = GAMEMODE_BUFFER_SIZE; + int ret = sceNetAdhocPdpRecv(gameModeSocket, &sendermac, &senderport, gameModeBuffer, &bufsz, 0, ADHOC_F_NONBLOCK); + if (ret >= 0 && bufsz > 0) { + for (auto& gma : replicaGameModeAreas) { + if (IsMatch(gma.mac, sendermac)) { + DEBUG_LOG(SCENET, "GameMode Received %d bytes of new Data for Area [%s]", bufsz, mac2str(&sendermac).c_str()); + memcpy(gma.data, gameModeBuffer, std::min(gma.size, bufsz)); + gma.dataUpdated = 1; + gma.updateTimestamp = CoreTiming::GetGlobalTimeUsScaled(); + break; + } + } + } + } + + // ReSchedule + CoreTiming::ScheduleEvent(usToCycles(GAMEMODE_UPDATE_INTERVAL) - cyclesLate, gameModeNotifyEvent, userdata); + return; + } + INFO_LOG(SCENET, "GameMode Scheduler (%d) has finished", uid); +} + +static void __AdhocctlNotify(u64 userdata, int cyclesLate) { + SceUID threadID = userdata >> 32; + int uid = (int)(userdata & 0xFFFFFFFF); + + s64 result = 0; + u32 error = 0; + + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error); + if (waitID == 0 || error != 0) + return; + + // Socket not found?! Should never happened! but if it ever happen should we just exit here or need to wake the thread first? + if (adhocctlRequests.find(uid) == adhocctlRequests.end()) { + WARN_LOG(SCENET, "sceNetAdhocctl Socket WaitID(%i) not found!", uid); + //__KernelResumeThreadFromWait(threadID, ERROR_NET_ADHOCCTL_BUSY); + return; + } + + AdhocctlRequest& req = adhocctlRequests[uid]; + int len = 0; + + SceNetAdhocctlConnectPacketC2S packet; + memset(&packet, 0, sizeof(packet)); + packet.base.opcode = req.opcode; + packet.group = req.group; + + switch (req.opcode) + { + case OPCODE_CONNECT: + len = sizeof(packet); + break; + case OPCODE_SCAN: + case OPCODE_DISCONNECT: + len = 1; + break; + } + + // Send Packet if it wasn't succesfully sent before + if (len > 0) { + if (IsSocketReady(metasocket, false, true) > 0) { + int ret = send(metasocket, (const char*)&packet, len, MSG_NOSIGNAL); + int sockerr = errno; + + if (ret > 0 || (ret == SOCKET_ERROR && sockerr != EAGAIN && sockerr != EWOULDBLOCK)) { + // Prevent from sending again + req.opcode = 0; + if (ret == SOCKET_ERROR) + DEBUG_LOG(SCENET, "sceNetAdhocctl[%i]: Socket Error (%i)", uid, sockerr); + } + } + } + + // Now we just need to wait for replies from adhoc server and the change of state + int waitVal = __KernelGetWaitValue(threadID, error); + if (adhocctlState != waitVal && error == 0) { + // Detecting Adhocctl Initialization using waitVal < 0 + if (waitVal >= 0 || (waitVal < 0 && (g_Config.bEnableWlan && !networkInited))) { + u64 now = (u64)(time_now_d() * 1000.0); + if (now - adhocctlStartTime <= adhocDefaultTimeout) { + // Try again in another 0.5ms until state matched or timedout. + CoreTiming::ScheduleEvent(usToCycles(500) - cyclesLate, adhocctlNotifyEvent, userdata); + return; + } + else + result = 0; // ERROR_NET_ADHOCCTL_BUSY + } + else + result = 0; // Faking successfully connected to adhoc server + } + + __KernelResumeThreadFromWait(threadID, result); + DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %d) Result (%08x) of sceNetAdhocctl - State: %d", waitID, error, (int)result, adhocctlState); + + // We are done with this request + adhocctlRequests.erase(uid); +} + +int WaitAdhocctlState(AdhocctlRequest request, int state, int usec, const char* reason) { + int uid = (state < 0) ? 1 : metasocket; + + if (adhocctlRequests.find(uid) != adhocctlRequests.end()) { + WARN_LOG(SCENET, "sceNetAdhocctl - WaitID[%d] already existed, Socket is busy!", uid); + return ERROR_NET_ADHOCCTL_BUSY; + } + + if (adhocctlNotifyEvent < 0) + adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify); + + u64 param = ((u64)__KernelGetCurThread()) << 32 | uid; + adhocctlStartTime = (u64)(time_now_d() * 1000.0); + adhocctlRequests[uid] = request; + CoreTiming::ScheduleEvent(usToCycles(usec), adhocctlNotifyEvent, param); + __KernelWaitCurThread(WAITTYPE_NET, uid, state, 0, false, reason); + + // faked success + return 0; +} + +int StartGameModeScheduler() { + if (gameModeSocket < 0) + return -1; + + if (gameModeNotifyEvent < 0) + gameModeNotifyEvent = CoreTiming::RegisterEvent("__GameModeNotify", __GameModeNotify); + + INFO_LOG(SCENET, "GameMode Scheduler (%d) has started", gameModeSocket); + u64 param = ((u64)__KernelGetCurThread()) << 32 | gameModeSocket; + CoreTiming::ScheduleEvent(usToCycles(GAMEMODE_UPDATE_INTERVAL), gameModeNotifyEvent, param); + + return 0; +} + +int DoBlockingPdpRecv(int uid, AdhocSocketRequest& req, s64& result) { + sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + socklen_t sinlen = sizeof(sin); + + int ret = recvfrom(uid, (char*)req.buffer, *req.length, MSG_PEEK | MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen); + int sockerr = errno; + + // Note: UDP must not be received partially, otherwise leftover data in socket's buffer will be discarded + if (ret >= 0 && ret <= *req.length) { + ret = recvfrom(uid, (char*)req.buffer, *req.length, MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen); + // UDP can also receives 0 data, while on TCP receiving 0 data = connection gracefully closed, but not sure whether PDP can send/recv 0 data or not tho + if (ret > 0) { + DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %s:%u\n", req.id, getLocalPort(uid), ret, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + + // Peer MAC + SceNetEtherAddr mac; + + // Find Peer MAC + if (resolveIP(sin.sin_addr.s_addr, &mac)) { + // Provide Sender Information + *req.remoteMAC = mac; + *req.remotePort = ntohs(sin.sin_port) - portOffset; + + // Save Length + *req.length = ret; + + // Update last recv timestamp + peerlock.lock(); + auto peer = findFriend(&mac); + if (peer != NULL) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + peerlock.unlock(); + } + // Unknown Peer + else { + *req.length = ret; + *req.remotePort = ntohs(sin.sin_port) - portOffset; + + WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %i bytes from Unknown Peer %s:%u", req.id, getLocalPort(uid), ret, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + } + } + result = 0; + } + // On Windows: recvfrom on UDP can get error WSAECONNRESET when previous sendto's destination is unreachable (or destination port is not bound yet), may need to disable SIO_UDP_CONNRESET error + else if (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ECONNRESET || sockerr == ETIMEDOUT) { + u64 now = (u64)(time_now_d() * 1000000.0); + auto sock = adhocSockets[req.id - 1]; + if (sock->flags & ADHOC_F_ALERTRECV) { + result = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTRECV; + sock->alerted_flags |= ADHOC_F_ALERTRECV; + } + else if (req.timeout == 0 || now - req.startTime <= req.timeout) { + // Try again later + return -1; + } + else + result = ERROR_NET_ADHOC_TIMEOUT; + } + else + result = ERROR_NET_ADHOC_INVALID_ARG; // ERROR_NET_ADHOC_DISCONNECTED + + if (ret == SOCKET_ERROR) + DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i]: Socket Error (%i)", req.id, sockerr); + + return 0; +} + +int DoBlockingPdpSend(int uid, AdhocSocketRequest& req, s64& result, AdhocSendTargets& targetPeers) { + auto sock = adhocSockets[req.id - 1]; + auto& pdpsocket = sock->data.pdp; + + result = 0; + bool retry = false; + for (auto peer = targetPeers.peers.begin(); peer != targetPeers.peers.end(); ) { + // Fill in Target Structure + sockaddr_in target; + target.sin_family = AF_INET; + target.sin_addr.s_addr = peer->ip; + target.sin_port = htons(peer->port + ((isOriPort && !isPrivateIP(peer->ip)) ? 0 : portOffset)); + + int ret = sendto(pdpsocket.id, (const char*)req.buffer, targetPeers.length, MSG_NOSIGNAL, (sockaddr*)&target, sizeof(target)); + int sockerr = errno; + + if (ret >= 0) { + DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](B): Sent %u bytes to %s:%u\n", uid, getLocalPort(pdpsocket.id), ret, inet_ntoa(target.sin_addr), ntohs(target.sin_port)); + // Remove successfully sent to peer to prevent sending the same data again during a retry + peer = targetPeers.peers.erase(peer); + } + else { + if (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ETIMEDOUT)) { + u64 now = (u64)(time_now_d() * 1000000.0); + if (sock->flags & ADHOC_F_ALERTSEND) { + result = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTSEND; + sock->alerted_flags |= ADHOC_F_ALERTSEND; + break; + } + else if (req.timeout == 0 || now - req.startTime <= req.timeout) { + retry = true; + } + else + // FIXME: Does Broadcast always success? even with timeout/blocking? + result = ERROR_NET_ADHOC_TIMEOUT; + } + ++peer; + } + + if (ret == SOCKET_ERROR) + DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u](B) [size=%i]", sockerr, uid, getLocalPort(pdpsocket.id), ntohs(target.sin_port), targetPeers.length); + } + + if (retry) + return -1; + + return 0; +} + +int DoBlockingPtpSend(int uid, AdhocSocketRequest& req, s64& result) { + auto sock = adhocSockets[req.id - 1]; + auto& ptpsocket = sock->data.ptp; + + // Send Data + int ret = send(uid, (const char*)req.buffer, *req.length, MSG_NOSIGNAL); + int sockerr = errno; + + // Success + if (ret > 0) { + // Save Length + *req.length = ret; + + DEBUG_LOG(SCENET, "sceNetAdhocPtpSend[%i:%u]: Sent %u bytes to %s:%u\n", req.id, ptpsocket.lport, ret, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); + + // Return Success + result = 0; + } + else if (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ETIMEDOUT)) { + u64 now = (u64)(time_now_d() * 1000000.0); + if (sock->flags & ADHOC_F_ALERTSEND) { + result = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTSEND; + sock->alerted_flags |= ADHOC_F_ALERTSEND; + } + else if (req.timeout == 0 || now - req.startTime <= req.timeout) { + return -1; + } + else + result = ERROR_NET_ADHOC_TIMEOUT; + } + + // Change Socket State. // FIXME: Does Alerted Socket should be closed too? + ptpsocket.state = ADHOC_PTP_STATE_CLOSED; + + // Disconnected + result = ERROR_NET_ADHOC_DISCONNECTED; + + if (ret == SOCKET_ERROR) + DEBUG_LOG(SCENET, "sceNetAdhocPtpSend[%i]: Socket Error (%i)", req.id, sockerr); + + return 0; +} + +int DoBlockingPtpRecv(int uid, AdhocSocketRequest& req, s64& result) { + auto sock = adhocSockets[req.id - 1]; + auto& ptpsocket = sock->data.ptp; + + int ret = recv(uid, (char*)req.buffer, *req.length, MSG_NOSIGNAL); + int sockerr = errno; + + // Received Data. POSIX: May received 0 bytes when the remote peer already closed the connection. + if (ret > 0) { + DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i:%u]: Received %u bytes from %s:%u\n", req.id, ptpsocket.lport, ret, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); + // Save Length + *req.length = ret; + + // Update last recv timestamp + peerlock.lock(); + auto peer = findFriend(&ptpsocket.paddr); + if (peer != NULL) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + peerlock.unlock(); + + result = 0; + } + else if (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ETIMEDOUT)) { + u64 now = (u64)(time_now_d() * 1000000.0); + if (sock->flags & ADHOC_F_ALERTRECV) { + result = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTRECV; + sock->alerted_flags |= ADHOC_F_ALERTRECV; + } + else if (req.timeout == 0 || now - req.startTime <= req.timeout) { + return -1; + } + else + result = ERROR_NET_ADHOC_TIMEOUT; + } + else { + // Change Socket State. // FIXME: Does Alerted Socket should be closed too? + ptpsocket.state = ADHOC_PTP_STATE_CLOSED; + + // Disconnected + result = ERROR_NET_ADHOC_DISCONNECTED; // ERROR_NET_ADHOC_INVALID_ARG + } + + if (ret == SOCKET_ERROR) + DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i]: Socket Error (%i)", req.id, sockerr); + + return 0; +} + +int DoBlockingPtpAccept(int uid, AdhocSocketRequest& req, s64& result) { + auto sock = adhocSockets[req.id - 1]; + auto& ptpsocket = sock->data.ptp; + sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + socklen_t sinlen = sizeof(sin); + int ret, sockerr; + + // Check if listening socket is ready to accept + ret = IsSocketReady(uid, true, false, &sockerr); + if (ret > 0) { + // Accept Connection + ret = accept(uid, (sockaddr*)&sin, &sinlen); + sockerr = errno; + } + + // Accepted New Connection + if (ret > 0) { + int newid = AcceptPtpSocket(req.id, ret, sin, req.remoteMAC, req.remotePort); + if (newid > 0) + result = newid; + } + else if (ret == 0 || (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ETIMEDOUT))) { + u64 now = (u64)(time_now_d() * 1000000.0); + if (sock->flags & ADHOC_F_ALERTACCEPT) { + result = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTACCEPT; + sock->alerted_flags |= ADHOC_F_ALERTACCEPT; + } + else if (req.timeout == 0 || now - req.startTime <= req.timeout) { + return -1; + } + else + result = ERROR_NET_ADHOC_TIMEOUT; + } + else + result = ERROR_NET_ADHOC_INVALID_ARG; //ERROR_NET_ADHOC_TIMEOUT + + if (ret == SOCKET_ERROR) + DEBUG_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Socket Error (%i)", req.id, sockerr); + + return 0; +} + +int DoBlockingPtpConnect(int uid, AdhocSocketRequest& req, s64& result) { + auto sock = adhocSockets[req.id - 1]; + auto& ptpsocket = sock->data.ptp; + int sockerr; + + // Wait for Connection (assuming "connect" has been called before) + int ret = IsSocketReady(uid, false, true, &sockerr); + + // Connection is ready + if (ret > 0) { + sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + socklen_t sinlen = sizeof(sin); + getpeername(uid, (sockaddr*)&sin, &sinlen); + + // Set Connected State + ptpsocket.state = ADHOC_PTP_STATE_ESTABLISHED; + + INFO_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Established (%s:%u)", req.id, ptpsocket.lport, inet_ntoa(sin.sin_addr), ptpsocket.pport); + + // Success + result = 0; + } + // Timeout + else if (ret == 0) { + u64 now = (u64)(time_now_d() * 1000000.0); + if (sock->flags & ADHOC_F_ALERTCONNECT) { + result = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTCONNECT; + sock->alerted_flags |= ADHOC_F_ALERTCONNECT; + } + else if (req.timeout == 0 || now - req.startTime <= req.timeout) { + return -1; + } + else + result = ERROR_NET_ADHOC_TIMEOUT; + } + else + result = ERROR_NET_ADHOC_CONNECTION_REFUSED; // ERROR_NET_ADHOC_TIMEOUT; + + if (ret == SOCKET_ERROR) + DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i]: Socket Error (%i)", req.id, sockerr); + + return 0; +} + +int DoBlockingPtpFlush(int uid, AdhocSocketRequest& req, s64& result) { + auto sock = adhocSockets[req.id - 1]; + auto& ptpsocket = sock->data.ptp; + + // Try Sending Empty Data + int sockerr = FlushPtpSocket(uid); + + if (sockerr >= 0) { + result = 0; + return 0; + } + else if (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ETIMEDOUT) { + u64 now = (u64)(time_now_d() * 1000000.0); + if (sock->flags & ADHOC_F_ALERTFLUSH) { + result = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTFLUSH; + sock->alerted_flags |= ADHOC_F_ALERTFLUSH; + } + else if (req.timeout == 0 || now - req.startTime <= req.timeout) { + return -1; + } + else + result = ERROR_NET_ADHOC_TIMEOUT; + } + + // Change Socket State. // FIXME: Does Alerted Socket should be closed too? + ptpsocket.state = ADHOC_PTP_STATE_CLOSED; + + // Disconnected + result = ERROR_NET_ADHOC_DISCONNECTED; + + return 0; +} + +int DoBlockingAdhocPollSocket(int uid, AdhocSocketRequest& req, s64& result) { + SceNetAdhocPollSd* sds = (SceNetAdhocPollSd*)req.buffer; + int ret = PollAdhocSocket(sds, req.id, 0); + if (ret <= 0) { + u64 now = (u64)(time_now_d() * 1000000.0); + if (req.timeout == 0 || now - req.startTime <= req.timeout) { + return -1; + } + else if (ret == 0) + ret = ERROR_NET_ADHOC_TIMEOUT; + else + ret = ERROR_NET_ADHOC_EXCEPTION_EVENT; + if (ret == ERROR_NET_ADHOC_WOULD_BLOCK) + ret = ERROR_NET_ADHOC_TIMEOUT; + } + result = ret; + + return 0; +} + +static void __AdhocSocketNotify(u64 userdata, int cyclesLate) { + SceUID threadID = userdata >> 32; + int uid = (int)(userdata & 0xFFFFFFFF); // fd/socket id + + s64 result = -1; + u32 error = 0; + int delayUS = 500; + + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error); + if (waitID == 0 || error != 0) + return; + + // Socket not found?! Should never happened! but if it ever happen should we just exit here or need to wake the thread first? + if (adhocSocketRequests.find(userdata) == adhocSocketRequests.end()) { + WARN_LOG(SCENET, "sceNetAdhoc Socket WaitID(%i) on Thread(%i) not found!", uid, threadID); + //__KernelResumeThreadFromWait(threadID, ERROR_NET_ADHOC_TIMEOUT); + return; + } + + AdhocSocketRequest req = adhocSocketRequests[userdata]; + + switch (req.type) { + case PDP_SEND: + if (sendTargetPeers.find(userdata) == sendTargetPeers.end()) { + // No destination peers? + result = 0; + break; + } + if (DoBlockingPdpSend(uid, req, result, sendTargetPeers[userdata])) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + sendTargetPeers.erase(userdata); + break; + + case PDP_RECV: + if (DoBlockingPdpRecv(uid, req, result)) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + break; + + case PTP_SEND: + if (DoBlockingPtpSend(uid, req, result)) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + break; + + case PTP_RECV: + if (DoBlockingPtpRecv(uid, req, result)) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + break; + + case PTP_ACCEPT: + if (DoBlockingPtpAccept(uid, req, result)) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + break; + + case PTP_CONNECT: + if (DoBlockingPtpConnect(uid, req, result)) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + break; + + case PTP_FLUSH: + if (DoBlockingPtpFlush(uid, req, result)) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + break; + + case ADHOC_POLL_SOCKET: + if (DoBlockingAdhocPollSocket(uid, req, result)) { + // Try again in another 0.5ms until data available or timedout. + CoreTiming::ScheduleEvent(usToCycles(delayUS) - cyclesLate, adhocSocketNotifyEvent, userdata); + return; + } + break; + } + + __KernelResumeThreadFromWait(threadID, result); + DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %d) Result (%08x) of sceNetAdhoc - SocketID: %d", waitID, error, (int)result, req.id); + + // We are done with this socket + adhocSocketRequests.erase(userdata); +} + +// input threadSocketId = ((u64)__KernelGetCurThread()) << 32 | socketId; +int WaitBlockingAdhocSocket(u64 threadSocketId, int type, int pspSocketId, void* buffer, s32_le* len, u32 timeoutUS, SceNetEtherAddr* remoteMAC, u16_le* remotePort, const char* reason) { + int uid = (int)(threadSocketId & 0xFFFFFFFF); + if (adhocSocketRequests.find(threadSocketId) != adhocSocketRequests.end()) { + WARN_LOG(SCENET, "sceNetAdhoc - WaitID[%d] already existed, Socket[%d] is busy!", uid, pspSocketId); + return ERROR_NET_ADHOC_BUSY; + } + + if (adhocSocketNotifyEvent < 0) + adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify); + + //changeBlockingMode(socketId, 1); + + u32 tmout = timeoutUS; + if (tmout > 0) + tmout = std::max(tmout, minSocketTimeoutUS); + + u64 startTime = (u64)(time_now_d() * 1000000.0); + adhocSocketRequests[threadSocketId] = { type, pspSocketId, buffer, len, tmout, startTime, remoteMAC, remotePort }; + // Some games (ie. Power Stone Collection) are using as small as 100 usec timeout + CoreTiming::ScheduleEvent(usToCycles(100), adhocSocketNotifyEvent, threadSocketId); + __KernelWaitCurThread(WAITTYPE_NET, uid, 0, 0, false, reason); + + // Fallback return value + return ERROR_NET_ADHOC_TIMEOUT; +} + +void netAdhocValidateLoopMemory() { + // Allocate Memory if it wasn't valid/allocated after loaded from old SaveState + if (!dummyThreadHackAddr || (dummyThreadHackAddr && strcmp("dummythreadhack", kernelMemory.GetBlockTag(dummyThreadHackAddr)) != 0)) { + u32 blockSize = sizeof(dummyThreadCode); + dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, "dummythreadhack"); + if (dummyThreadHackAddr) Memory::Memcpy(dummyThreadHackAddr, dummyThreadCode, sizeof(dummyThreadCode)); + } + if (!matchingThreadHackAddr || (matchingThreadHackAddr && strcmp("matchingThreadHack", kernelMemory.GetBlockTag(matchingThreadHackAddr)) != 0)) { + u32 blockSize = sizeof(matchingThreadCode); + matchingThreadHackAddr = kernelMemory.Alloc(blockSize, false, "matchingThreadHack"); + if (matchingThreadHackAddr) Memory::Memcpy(matchingThreadHackAddr, matchingThreadCode, sizeof(matchingThreadCode)); + } } void __NetAdhocDoState(PointerWrap &p) { - auto s = p.Section("sceNetAdhoc", 1, 2); + auto s = p.Section("sceNetAdhoc", 1, 6); if (!s) return; - p.Do(netAdhocInited); - p.Do(netAdhocctlInited); - p.Do(netAdhocMatchingInited); - p.Do(adhocctlHandlers); + auto cur_netAdhocInited = netAdhocInited; + auto cur_netAdhocctlInited = netAdhocctlInited; + auto cur_netAdhocMatchingInited = netAdhocMatchingInited; + + Do(p, netAdhocInited); + Do(p, netAdhocctlInited); + Do(p, netAdhocMatchingInited); + Do(p, adhocctlHandlers); if (s >= 2) { - p.Do(actionAfterMatchingMipsCall); - __KernelRestoreActionType(actionAfterMatchingMipsCall, AfterMatchingMipsCall::Create); + Do(p, actionAfterMatchingMipsCall); + if (actionAfterMatchingMipsCall != -1) { + __KernelRestoreActionType(actionAfterMatchingMipsCall, AfterMatchingMipsCall::Create); + } - p.Do(dummyThreadHackAddr); - } else if (p.mode == p.MODE_READ) { - // Previously, this wasn't being saved. It needs its own space. - if (strcmp("dummythreadhack", kernelMemory.GetBlockTag(dummyThreadHackAddr)) != 0) { - u32 blockSize = sizeof(dummyThreadCode); - dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, "dummythreadhack"); + Do(p, dummyThreadHackAddr); + } + else { + actionAfterMatchingMipsCall = -1; + dummyThreadHackAddr = 0; + } + if (s >= 3) { + Do(p, actionAfterAdhocMipsCall); + if (actionAfterAdhocMipsCall != -1) { + __KernelRestoreActionType(actionAfterAdhocMipsCall, AfterAdhocMipsCall::Create); + } + + Do(p, matchingThreadHackAddr); + } + else { + actionAfterAdhocMipsCall = -1; + matchingThreadHackAddr = 0; + } + if (s >= 4) { + Do(p, threadAdhocID); + Do(p, matchingThreads); + } + else { + threadAdhocID = 0; + for (auto& it : matchingThreads) { + it = 0; } } - if (dummyThreadHackAddr) { - Memory::Memcpy(dummyThreadHackAddr, dummyThreadCode, sizeof(dummyThreadCode)); + if (s >= 5) { + Do(p, adhocConnectionType); + Do(p, adhocctlState); + Do(p, adhocctlNotifyEvent); + if (adhocctlNotifyEvent != -1) { + CoreTiming::RestoreRegisterEvent(adhocctlNotifyEvent, "__AdhocctlNotify", __AdhocctlNotify); + } + Do(p, adhocSocketNotifyEvent); + if (adhocSocketNotifyEvent != -1) { + CoreTiming::RestoreRegisterEvent(adhocSocketNotifyEvent, "__AdhocSocketNotify", __AdhocSocketNotify); + } + } + else { + adhocConnectionType = ADHOC_CONNECT; + adhocctlState = ADHOCCTL_STATE_DISCONNECTED; + adhocctlNotifyEvent = -1; + adhocSocketNotifyEvent = -1; + } + if (s >= 6) { + Do(p, gameModeNotifyEvent); + if (gameModeNotifyEvent != -1) { + CoreTiming::RestoreRegisterEvent(gameModeNotifyEvent, "__GameModeNotify", __GameModeNotify); + } + } + else { + gameModeNotifyEvent = -1; + } + + if (p.mode == p.MODE_READ) { + // Discard leftover events + adhocctlEvents.clear(); + matchingEvents.clear(); + adhocctlRequests.clear(); + adhocSocketRequests.clear(); + sendTargetPeers.clear(); + + // Let's not change "Inited" value when Loading SaveState to prevent memory & port leaks + netAdhocMatchingInited = cur_netAdhocMatchingInited; + netAdhocctlInited = cur_netAdhocctlInited; + netAdhocInited = cur_netAdhocInited; } } void __UpdateAdhocctlHandlers(u32 flag, u32 error) { - std::lock_guard adhocGuard(adhocEvtMtx); + std::lock_guard adhocGuard(adhocEvtMtx); adhocctlEvents.push_back({ flag, error }); } -// TODO: MipsCall needs to be called from it's own PSP Thread instead of from any random PSP Thread -void __UpdateMatchingHandler(u64 ArgsPtr) { - std::lock_guard adhocGuard(adhocEvtMtx); +void __UpdateMatchingHandler(MatchingArgs ArgsPtr) { + std::lock_guard adhocGuard(adhocEvtMtx); matchingEvents.push_back(ArgsPtr); } -static int getBlockingFlag(int id) { -#ifdef _WIN32 - return 0; -#else - int sockflag = fcntl(id, F_GETFL, O_NONBLOCK); - return sockflag & O_NONBLOCK; -#endif +u32_le __CreateHLELoop(u32_le *loopAddr, const char *sceFuncName, const char *hleFuncName, const char *tagName) { + if (loopAddr == NULL || sceFuncName == NULL || hleFuncName == NULL) + return 0; + + loopAddr[0] = MIPS_MAKE_SYSCALL(sceFuncName, hleFuncName); + loopAddr[1] = MIPS_MAKE_B(-2); + loopAddr[2] = MIPS_MAKE_NOP(); + u32 blockSize = sizeof(u32_le)*3; + u32_le dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, tagName); // blockSize will be rounded to 256 granularity + Memory::Memcpy(dummyThreadHackAddr, loopAddr, sizeof(u32_le) * 3); // This area will be cleared again after loading an old savestate :( + return dummyThreadHackAddr; +} + +void __AdhocNotifInit() { + adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify); + adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify); + gameModeNotifyEvent = CoreTiming::RegisterEvent("__GameModeNotify", __GameModeNotify); + + adhocctlRequests.clear(); + adhocSocketRequests.clear(); + sendTargetPeers.clear(); } void __NetAdhocInit() { @@ -144,14 +930,9 @@ void __NetAdhocInit() { netAdhocctlInited = false; netAdhocMatchingInited = false; adhocctlHandlers.clear(); + __AdhocNotifInit(); __AdhocServerInit(); - dummyThreadCode[0] = MIPS_MAKE_SYSCALL("sceNetAdhoc", "__NetTriggerCallbacks"); - dummyThreadCode[1] = MIPS_MAKE_B(-2); - dummyThreadCode[2] = MIPS_MAKE_NOP(); - u32 blockSize = sizeof(dummyThreadCode); - dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, "dummythreadhack"); - Memory::Memcpy(dummyThreadHackAddr, dummyThreadCode, sizeof(dummyThreadCode)); // This area will be cleared again after loading an old savestate :( - actionAfterMatchingMipsCall = __KernelRegisterActionType(AfterMatchingMipsCall::Create); + // Create built-in AdhocServer Thread if (g_Config.bEnableWlan && g_Config.bEnableAdhocServer) { adhocServerRunning = true; @@ -161,22 +942,9 @@ void __NetAdhocInit() { u32 sceNetAdhocInit() { if (!netAdhocInited) { - // Clear Translator Memory - memset(&pdp, 0, sizeof(pdp)); - memset(&ptp, 0, sizeof(ptp)); - // Library initialized netAdhocInited = true; - // Create fake PSP Thread for callback - // TODO: Should use a separated threads for friendFinder, matchingEvent, and matchingInput and created on AdhocctlInit & AdhocMatchingStart instead of here - #define PSP_THREAD_ATTR_KERNEL 0x00001000 // PSP_THREAD_ATTR_KERNEL is located in sceKernelThread.cpp instead of sceKernelThread.h :( - // TODO: This should probably be a user thread, but maybe from sceNetAdhocctlInit? - threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x10, 0x1000, PSP_THREAD_ATTR_KERNEL, 0, true); - if (threadAdhocID > 0) { - __KernelStartThread(threadAdhocID, 0, 0); - } - // Return Success return hleLogSuccessInfoI(SCENET, 0, "at %08x", currentMIPS->pc); } @@ -189,41 +957,60 @@ static u32 sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) { if (netAdhocctlInited) return ERROR_NET_ADHOCCTL_ALREADY_INITIALIZED; - - if(g_Config.bEnableWlan) { - if (initNetwork((SceNetAdhocctlAdhocId *)Memory::GetPointer(productAddr)) == 0) { - if (!friendFinderRunning) { - friendFinderRunning = true; - friendFinderThread = std::thread(friendFinder); - } - networkInited = true; - } else { - WARN_LOG(SCENET, "sceNetAdhocctlInit: Failed to init the network but faking success"); - networkInited = false; // TODO: What needs to check this? Pretty much everything? Maybe we should just set netAdhocctlInited to false.. - } + + if (Memory::IsValidAddress(productAddr)) { + Memory::ReadStruct(productAddr, &product_code); } + adhocctlEvents.clear(); netAdhocctlInited = true; //needed for cleanup during AdhocctlTerm even when it failed to connect to Adhoc Server (since it's being faked as success) + + // Create fake PSP Thread for callback + // TODO: Should use a separated threads for friendFinder, matchingEvent, and matchingInput and created on AdhocctlInit & AdhocMatchingStart instead of here + netAdhocValidateLoopMemory(); + threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, prio, stackSize, PSP_THREAD_ATTR_USER, 0, true); + if (threadAdhocID > 0) { + __KernelStartThread(threadAdhocID, 0, 0); + } + + // TODO: Merging friendFinder (real) thread to AdhocThread (fake) thread on PSP side + if (!friendFinderRunning) { + friendFinderRunning = true; + friendFinderThread = std::thread(friendFinder); + } + + // Need to make sure to be connected to adhoc server before returning to prevent GTA VCS failed to create/join a group and unable to see any game room + int us = adhocExtraPollDelayMS * 1000; + if (g_Config.bEnableWlan && !networkInited) { + AdhocctlRequest dummyreq = { OPCODE_LOGIN, {0} }; + return WaitAdhocctlState(dummyreq, -1, us, "adhocctl init"); + } + // Give a little time for friendFinder thread to be ready before the game use the next sceNet functions, should've checked for friendFinderRunning status instead of guessing the time? + else + hleDelayResult(0, "give some time", us); + return 0; } -static int sceNetAdhocctlGetState(u32 ptrToStatus) { - // Library initialized - if (netAdhocctlInited) { - // Valid Arguments - if (Memory::IsValidAddress(ptrToStatus)) { - // Return Thread Status - Memory::Write_U32(threadStatus, ptrToStatus); - // Return Success - return 0; - } - - // Invalid Arguments - return ERROR_NET_ADHOCCTL_INVALID_ARG; - } - +int NetAdhocctl_GetState() { + return adhocctlState; +} + +int sceNetAdhocctlGetState(u32 ptrToStatus) { // Library uninitialized - return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; + if (!netAdhocctlInited) + return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; + + // Invalid Arguments + if (!Memory::IsValidAddress(ptrToStatus)) + return ERROR_NET_ADHOCCTL_INVALID_ARG; + + int state = NetAdhocctl_GetState(); + // Output Adhocctl State + Memory::Write_U32(state, ptrToStatus); + + // Return Success + return hleLogSuccessVerboseI(SCENET, 0, "state = %d", state); } /** @@ -235,8 +1022,8 @@ static int sceNetAdhocctlGetState(u32 ptrToStatus) { * @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_SOCKET_ID_NOT_AVAIL, ADHOC_INVALID_ADDR, ADHOC_PORT_NOT_AVAIL, ADHOC_INVALID_PORT, ADHOC_PORT_IN_USE, NET_NO_SPACE */ // When choosing AdHoc menu in Wipeout Pulse sometimes it's saying that "WLAN is turned off" on game screen and getting "kUnityCommandCode_MediaDisconnected" error in the Log Console when calling sceNetAdhocPdpCreate, probably it needed to wait something from the thread before calling this (ie. need to receives 7 bytes from adhoc server 1st?) -static int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown) { - INFO_LOG(SCENET, "sceNetAdhocPdpCreate(%s, %u, %u, %u) at %08x", mac, port, bufferSize, unknown, currentMIPS->pc); +static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 unknown) { + INFO_LOG(SCENET, "sceNetAdhocPdpCreate(%s, %u, %u, %u) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), port, bufferSize, unknown, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -247,6 +1034,12 @@ static int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 u if (netAdhocInited) { // Valid Arguments are supplied if (mac != NULL && bufferSize > 0) { + //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this + if (port == 0) port = -(int)portOffset; + // Some games (ie. DBZ Shin Budokai 2) might be getting the saddr/srcmac content from SaveState and causing problems :( So we try to fix it here + if (saddr != NULL) { + getLocalMac(saddr); + } // Valid MAC supplied if (isLocalMAC(saddr)) { //// Unused Port supplied @@ -259,58 +1052,75 @@ static int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 u int usocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Valid Socket produced if (usocket != INVALID_SOCKET) { - // Change socket buffer size when necessary - if (getSockBufferSize(usocket, SO_SNDBUF) < bufferSize) setSockBufferSize(usocket, SO_SNDBUF, bufferSize); - if (getSockBufferSize(usocket, SO_RCVBUF) < bufferSize) setSockBufferSize(usocket, SO_RCVBUF, bufferSize); + // Change socket buffer size. + int pdpbufsize = std::max(bufferSize, PSP_ADHOC_PDP_MFS); //bufferSize*10; + // Send Buffer should be smaller than Recv Buffer to prevent faster device from flooding slower device too much. + setSockBufferSize(usocket, SO_SNDBUF, pdpbufsize); + // Recv Buffer should be equal or larger than Send Buffer. Using larger Recv Buffer might helped reduces dropped packets during a slowdown, but too large may cause slow performance on Warriors Orochi 2. + setSockBufferSize(usocket, SO_RCVBUF, pdpbufsize*10); + + // Enable KeepAlive + setSockKeepAlive(usocket, true); + + // Ignore SIGPIPE when supported (ie. BSD/MacOS) + setSockNoSIGPIPE(usocket, 1); // Enable Port Re-use, this will allow binding to an already used port, but only one of them can read the data (shared receive buffer?) - int one = 1; - setsockopt(usocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one)); // NO idea if we need this + setSockReuseAddrPort(usocket); + // Binding Information for local Port sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; - if (/*PPSSPP_ID > 1*/isLocalServer) { + if (isLocalServer) { getLocalIp(&addr); } - //if (port < 7) addr.sin_port = htons(port + 1341); else // <= 443 - addr.sin_port = htons(port + portOffset ); // This not safe in any way... + addr.sin_port = htons(port + portOffset); // The port might be under 1024 (ie. GTA:VCS use port 1, Ford Street Racing use port 0 (UNUSED_PORT), etc) and already used by other application/host OS, should we add 1024 to the port whenever it tried to use an already used port? // Bound Socket to local Port int iResult = bind(usocket, (sockaddr *)&addr, sizeof(addr)); - /*if (iResult == SOCKET_ERROR && errno == 10048) { //Forcing PdpCreate to be successfull using a different Port might not works and might affect other players sharing the same IP due to "deleteFriendByIP" (should delete by MAC instead of IP) - addr.sin_port = 0; //UNUSED_PORT - iResult = bind(usocket, (sockaddr *)&addr, sizeof(addr)); - WARN_LOG(SCENET, "Port %u is already used, replaced with UNUSED_PORT(%u)", port, ntohs(addr.sin_port)); - }*/ + if (iResult == 0) { + // Update sport with the port assigned internal->lport = ntohs(local.sin_port) + socklen_t len = sizeof(addr); + if (getsockname(usocket, (sockaddr*)&addr, &len) == 0) { + port = ntohs(addr.sin_port) - portOffset; + } + // Allocate Memory for Internal Data - SceNetAdhocPdpStat * internal = (SceNetAdhocPdpStat *)malloc(sizeof(SceNetAdhocPdpStat)); + AdhocSocket * internal = (AdhocSocket*)malloc(sizeof(AdhocSocket)); // Allocated Memory if (internal != NULL) { - // Clear Memory - memset(internal, 0, sizeof(SceNetAdhocPdpStat)); - // Find Free Translator Index - int i = 0; for (; i < 255; i++) if (pdp[i] == NULL) break; + int i = 0; + for (; i < MAX_SOCKET; i++) if (adhocSockets[i] == NULL) break; // Found Free Translator Index - if (i < 255) { + if (i < MAX_SOCKET) { + // Clear Memory + memset(internal, 0, sizeof(AdhocSocket)); + + // Socket Type + internal->type = SOCK_PDP; + // Fill in Data - internal->id = usocket; - internal->laddr = *saddr; - internal->lport = getLocalPort(usocket) - portOffset; //should use the port given to the socket (in case it's UNUSED_PORT port) isn't? - internal->rcv_sb_cc = bufferSize; + internal->data.pdp.id = usocket; + internal->data.pdp.laddr = *saddr; + internal->data.pdp.lport = port; //getLocalPort(usocket) - portOffset; // Link Socket to Translator ID - pdp[i] = internal; + adhocSockets[i] = internal; // Forward Port on Router - //sceNetPortOpen("UDP", sport); // I need to figure out how to use this in windows/linux + //sceNetPortOpen("UDP", port); + UPnP_Add(IP_PROTOCOL_UDP, isOriPort ? port : port + portOffset, port + portOffset); // g_PortManager.Add(IP_PROTOCOL_UDP, isOriPort ? port : port + portOffset, port + portOffset); + // Switch to non-blocking for futher usage + changeBlockingMode(usocket, 1); + // Success return i + 1; } @@ -324,6 +1134,8 @@ static int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 u retval = ERROR_NET_ADHOC_PORT_IN_USE; if (iResult == SOCKET_ERROR) { ERROR_LOG(SCENET, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port)); + auto n = GetI18NCategory("Networking"); + host->NotifyUserMessage(std::string(n->T("Failed to Bind Port")) + " " + std::to_string(port + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")), 3.0, 0x0000ff); } } @@ -353,7 +1165,10 @@ static int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 u * @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG */ static int sceNetAdhocctlGetParameter(u32 paramAddr) { - DEBUG_LOG(SCENET, "sceNetAdhocctlGetParameter(%08x)",paramAddr); + char grpName[9] = { 0 }; + memcpy(grpName, parameter.group_name.data, ADHOCCTL_GROUPNAME_LEN); + parameter.nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; + DEBUG_LOG(SCENET, "sceNetAdhocctlGetParameter(%08x) [Ch=%i][Group=%s][BSSID=%s][name=%s]", paramAddr, parameter.channel, grpName, mac2str(¶meter.bssid.mac_addr).c_str(), parameter.nickname.data); if (!g_Config.bEnableWlan) { return ERROR_NET_ADHOCCTL_DISCONNECTED; } @@ -383,12 +1198,16 @@ static int sceNetAdhocctlGetParameter(u32 paramAddr) { * @param dport Target Port * @param data Data Payload * @param len Payload Length - * @param timeout Send Timeout + * @param timeout Send Timeout (microseconds) * @param flag Nonblocking Flag * @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT, ADHOC_INVALID_DATALEN, ADHOC_SOCKET_ALERTED, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_WOULD_BLOCK, NET_NO_SPACE, NET_INTERNAL */ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, int timeout, int flag) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i)", id, mac, port, data, len, timeout, flag); + if (flag == 0) { // Prevent spamming Debug Log with retries of non-bocking socket + DEBUG_LOG(SCENET, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i) at %08x", id, mac2str((SceNetEtherAddr*)mac).c_str(), port, data, len, timeout, flag, currentMIPS->pc); + } else { + VERBOSE_LOG(SCENET, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i) at %08x", id, mac2str((SceNetEtherAddr*)mac).c_str(), port, data, len, timeout, flag, currentMIPS->pc); + } if (!g_Config.bEnableWlan) { return -1; } @@ -406,9 +1225,10 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int // Valid Data Length if (len >= 0) { // should we allow 0 size packet (for ping) ? // Valid Socket ID - if (id > 0 && id <= 255 && pdp[id - 1] != NULL) { + if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { // Cast Socket - SceNetAdhocPdpStat * socket = pdp[id - 1]; + auto socket = adhocSockets[id - 1]; + auto& pdpsocket = socket->data.pdp; // Valid Data Buffer if (data != NULL) { @@ -416,10 +1236,11 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int if (daddr != NULL) { // Log Destination // Schedule Timeout Removal - if (flag) timeout = 0; + //if (flag) timeout = 0; // Apply Send Timeout Settings to Socket - setsockopt(socket->id, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout)); + if (timeout > 0) + setSockTimeout(pdpsocket.id, SO_SNDTIMEO, timeout); // Single Target if (!isBroadcastMAC(daddr)) { @@ -430,36 +1251,54 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int // Get Peer IP if (resolveMAC((SceNetEtherAddr *)daddr, (uint32_t *)&target.sin_addr.s_addr)) { + // Some games (ie. PSP2) might try to talk to it's self, not sure if they talked through WAN or LAN when using public Adhoc Server tho + target.sin_port = htons(dport + ((isOriPort && !isPrivateIP(target.sin_addr.s_addr)) ? 0 : portOffset)); + // Acquire Network Lock //_acquireNetworkLock(); - // Send Data - changeBlockingMode(socket->id, flag); - int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target)); + // Send Data. UDP are guaranteed to be sent as a whole or nothing(failed if len > SO_MAX_MSG_SIZE), and never be partially sent/recv + int sent = sendto(pdpsocket.id, (const char *)data, len, MSG_NOSIGNAL, (sockaddr *)&target, sizeof(target)); int error = errno; + if (sent == SOCKET_ERROR) { - DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u] (size=%i)", error, id, getLocalPort(socket->id), ntohs(target.sin_port), len); + // Simulate blocking behaviour with non-blocking socket + if (!flag && (error == EAGAIN || error == EWOULDBLOCK || error == ETIMEDOUT)) { + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | pdpsocket.id; + if (sendTargetPeers.find(threadSocketId) != sendTargetPeers.end()) { + DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Socket(%d) is Busy!", id, getLocalPort(pdpsocket.id), pdpsocket.id); + return ERROR_NET_ADHOC_BUSY; + } + + AdhocSendTargets dest = { len, {}, false }; + dest.peers.push_back({ target.sin_addr.s_addr, dport }); + sendTargetPeers[threadSocketId] = dest; + return WaitBlockingAdhocSocket(threadSocketId, PDP_SEND, id, data, nullptr, timeout, nullptr, nullptr, "pdp send"); + } + + DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u] (size=%i)", error, id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), len); } - changeBlockingMode(socket->id, 0); + //changeBlockingMode(socket->id, 0); // Free Network Lock //_freeNetworkLock(); - uint8_t * sip = (uint8_t *)&target.sin_addr.s_addr; // Sent Data - if (sent == len) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Sent %u bytes to %u.%u.%u.%u:%u\n", id, getLocalPort(socket->id), sent, sip[0], sip[1], sip[2], sip[3], ntohs(target.sin_port)); + if (sent >= 0) { + DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Sent %u bytes to %s:%u\n", id, getLocalPort(pdpsocket.id), sent, inet_ntoa(target.sin_addr), ntohs(target.sin_port)); // Success - return 0; + return 0; // sent; // MotorStorm will try to resend if return value is not 0 } - // Blocking Situation - if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; + // Non-Blocking + if (flag) + return ERROR_NET_ADHOC_WOULD_BLOCK; - // Timeout - return ERROR_NET_ADHOC_TIMEOUT; //-1; + // Does PDP can Timeout? There is no concept of Timeout when sending UDP due to no ACK, but might happen if the socket buffer is full, not sure about PDP since some games did use the timeout arg + return ERROR_NET_ADHOC_TIMEOUT; // ERROR_NET_ADHOC_INVALID_ADDR; } + //VERBOSE_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Unknown Target Peer %s:%u\n", id, getLocalPort(pdpsocket.id), mac2str(daddr, tmpmac), ntohs(target.sin_port)); } // Broadcast Target @@ -483,41 +1322,60 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int // Acquire Peer Lock peerlock.lock(); - + AdhocSendTargets dest = { len, {}, true }; // Iterate Peers - SceNetAdhocctlPeerInfo * peer = friends; + SceNetAdhocctlPeerInfo* peer = friends; for (; peer != NULL; peer = peer->next) { - // Skip timed out friends - if (peer->last_recv == 0) continue; + // Does Skipping sending to timed out friends could cause desync when players moving group at the time MP game started? + if (peer->last_recv == 0) + continue; - // Fill in Target Structure - sockaddr_in target; - target.sin_family = AF_INET; - target.sin_addr.s_addr = peer->ip_addr; - target.sin_port = htons(dport + portOffset); + dest.peers.push_back({ peer->ip_addr, dport }); + } + // Free Peer Lock + peerlock.unlock(); - // Send Data - changeBlockingMode(socket->id, flag); - int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target)); - int error = errno; - if (sent == SOCKET_ERROR) { - DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u](BC) [size=%i]", error, id, getLocalPort(socket->id), ntohs(target.sin_port), len); + // Send Data + // Simulate blocking behaviour with non-blocking socket + if (!flag) { + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | pdpsocket.id; + if (sendTargetPeers.find(threadSocketId) != sendTargetPeers.end()) { + DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](BC): Socket(%d) is Busy!", id, getLocalPort(pdpsocket.id), pdpsocket.id); + return ERROR_NET_ADHOC_BUSY; } - changeBlockingMode(socket->id, 0); - if (sent >= 0) { - uint8_t * sip = (uint8_t *)&target.sin_addr.s_addr; - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](BC): Sent %u bytes to %u.%u.%u.%u:%u\n", id, getLocalPort(socket->id), sent, sip[0], sip[1], sip[2], sip[3], ntohs(target.sin_port)); + + sendTargetPeers[threadSocketId] = dest; + return WaitBlockingAdhocSocket(threadSocketId, PDP_SEND, id, data, nullptr, timeout, nullptr, nullptr, "pdp send broadcast"); + } + // Non-blocking + else { + // Iterate Peers + for (auto peer : dest.peers) { + // Fill in Target Structure + sockaddr_in target; + target.sin_family = AF_INET; + target.sin_addr.s_addr = peer.ip; + target.sin_port = htons(dport + ((isOriPort && !isPrivateIP(peer.ip)) ? 0 : portOffset)); + + int sent = sendto(pdpsocket.id, (const char*)data, len, MSG_NOSIGNAL, (sockaddr*)&target, sizeof(target)); + int error = errno; + if (sent == SOCKET_ERROR) { + DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u](BC) [size=%i]", error, id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), len); + } + + if (sent >= 0) { + DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](BC): Sent %u bytes to %s:%u\n", id, getLocalPort(pdpsocket.id), sent, inet_ntoa(target.sin_addr), ntohs(target.sin_port)); + } } } - // Free Peer Lock - peerlock.unlock(); + //changeBlockingMode(socket->id, 0); // Free Network Lock //_freeNetworkLock(); // Success, Broadcast never fails! - return 0; + return 0; // len; } } @@ -546,20 +1404,24 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int } - /** * Adhoc Emulator PDP Receive Call * @param id Socket File Descriptor * @param saddr OUT: Source MAC Address * @param sport OUT: Source Port - * @param buf OUT: Received Data + * @param buf OUT: Received Data. The caller has to provide enough space (the whole socket buffer size?) to fully read the available packet. * @param len IN: Buffer Size OUT: Received Data Length * @param timeout Receive Timeout * @param flag Nonblocking Flag - * @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_ENOUGH_SPACE, ADHOC_THREAD_ABORTED, NET_INTERNAL + * @return 0 (or Number of bytes received?) on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_ENOUGH_SPACE, ADHOC_THREAD_ABORTED, NET_INTERNAL */ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLength, u32 timeout, int flag) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc); + if (flag == 0) { // Prevent spamming Debug Log with retries of non-bocking socket + DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc); + } else { + VERBOSE_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc); + } + if (!g_Config.bEnableWlan) { return -1; } @@ -569,21 +1431,22 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * int * len = (int *)dataLength; if (netAdhocInited) { // Valid Socket ID - if (id > 0 && id <= 255 && pdp[id - 1] != NULL) { + if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { // Cast Socket - SceNetAdhocPdpStat * socket = pdp[id - 1]; + auto socket = adhocSockets[id - 1]; + auto& pdpsocket = socket->data.pdp; // Valid Arguments if (saddr != NULL && port != NULL && buf != NULL && len != NULL && *len > 0) { #ifndef PDP_DIRTY_MAGIC // Schedule Timeout Removal - if (flag == 1) timeout = 0; + //if (flag == 1) timeout = 0; #else // Nonblocking Simulator int wouldblock = 0; // Minimum Timeout - uint32_t mintimeout = 250000; + uint32_t mintimeout = minSocketTimeoutUS; // 250000; // Nonblocking Call if (flag == 1) { @@ -598,8 +1461,9 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * } #endif - // Apply Receive Timeout Settings to Socket - setsockopt(socket->id, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)); + // Apply Receive Timeout Settings to Socket. Let's not wait forever (0 = indefinitely) + if (timeout > 0) + setSockTimeout(pdpsocket.id, SO_RCVTIMEO, timeout); // Sender Address sockaddr_in sin; @@ -611,19 +1475,54 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * // Acquire Network Lock //_acquireNetworkLock(); - // Receive Data - changeBlockingMode(socket->id, flag); - int received = recvfrom(socket->id, (char *)buf, *len,0,(sockaddr *)&sin, &sinlen); - int error = errno; - if (received == SOCKET_ERROR) { - VERBOSE_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpRecv [size=%i]", error, *len); - } - changeBlockingMode(socket->id, 0); + // TODO: Use a different thread (similar to sceIo) for recvfrom, recv & accept to prevent blocking-socket from blocking emulation (ie. Hot Shots Tennis:GaG) + int received = 0; + int error = 0; + + // Receive Data. PDP always sent in full size or nothing(failed), recvfrom will always receive in full size as requested (blocking) or failed (non-blocking). If available UDP data is larger than buffer, excess data is lost. + // Should peek first for the available data size if it's more than len return ERROR_NET_ADHOC_NOT_ENOUGH_SPACE along with required size in len to prevent losing excess data + received = recvfrom(pdpsocket.id, (char*)buf, *len, MSG_PEEK | MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen); + if (received != SOCKET_ERROR && *len < received) { + WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, *len, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + *len = received; - // Received Data - if (received >= 0) { - uint8_t * sip = (uint8_t *)&sin.sin_addr.s_addr; - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %u.%u.%u.%u:%u\n", id, getLocalPort(socket->id), received, sip[0], sip[1], sip[2], sip[3], ntohs(sin.sin_port)); + // Peer MAC + SceNetEtherAddr mac; + + // Find Peer MAC + if (resolveIP(sin.sin_addr.s_addr, &mac)) { + // Provide Sender Information + *saddr = mac; + *sport = ntohs(sin.sin_port) - portOffset; + + // Update last recv timestamp, may cause disconnection not detected properly tho + peerlock.lock(); + auto peer = findFriend(&mac); + if (peer != NULL) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + peerlock.unlock(); + } + + // Free Network Lock + //_freeNetworkLock(); + + return ERROR_NET_ADHOC_NOT_ENOUGH_SPACE; //received; + } + received = recvfrom(pdpsocket.id, (char*)buf, *len, MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen); + error = errno; + + if (received == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK)) { + if (flag == 0) { + // Simulate blocking behaviour with non-blocking socket + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | pdpsocket.id; + return WaitBlockingAdhocSocket(threadSocketId, PDP_RECV, id, buf, len, timeout, saddr, sport, "pdp recv"); + } + + VERBOSE_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpRecv[%i:%u] [size=%i]", error, id, pdpsocket.lport, *len); + } + + // Received Data. UDP can also receives 0 data, while on TCP 0 data = connection gracefully closed, but not sure about PDP tho + if (received > 0) { + DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); // Peer MAC SceNetEtherAddr mac; @@ -635,19 +1534,30 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * *sport = ntohs(sin.sin_port) - portOffset; // Save Length - *len = received; + *len = received; // Kurok homebrew seems to use the new value of len than returned value as data length + + // Update last recv timestamp, may cause disconnection not detected properly tho + peerlock.lock(); + auto peer = findFriend(&mac); + if (peer != NULL) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + peerlock.unlock(); // Free Network Lock //_freeNetworkLock(); - // Return Success - return 0; + // Return Success. According to pspsdk-1.0+beta2 returned value is Number of bytes received, but JPCSP returning 0? + return 0; //received; // Returning number of bytes received will cause KH BBS unable to see the game event/room + } + // Unknown Peer, let's not give any data + else { + //*len = 0; // received; // Is this going to be okay since saddr may not be valid? + WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %i bytes from Unknown Peer %s:%u", id, getLocalPort(pdpsocket.id), received, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); } - WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %i bytes from Unknown Peer %u.%u.%u.%u:%u [%02X:%02X:%02X:%02X:%02X:%02X]", id, getLocalPort(socket->id), received, sip[0], sip[1], sip[2], sip[3], ntohs(sin.sin_port), mac.data[0], mac.data[1], mac.data[2], mac.data[3], mac.data[4], mac.data[5]); - // Free Network Lock //_freeNetworkLock(); + //free(tmpbuf); + //Receiving data from unknown peer, ignore it ? //return ERROR_NET_ADHOC_WOULD_BLOCK; //ERROR_NET_ADHOC_NO_DATA_AVAILABLE } @@ -660,9 +1570,17 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * if (wouldblock) flag = 1; #endif - // Nothing received - if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; - return ERROR_NET_ADHOC_TIMEOUT; + // Nothing received. On Windows: recvfrom on UDP can get error WSAECONNRESET when previous sendto's destination is unreachable (or destination port is not bound), may need to disable SIO_UDP_CONNRESET + if (received == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || error == ECONNRESET || error == ETIMEDOUT)) { + // Blocking Situation + if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; + + // Timeout + return ERROR_NET_ADHOC_TIMEOUT; + } + + // Disconnected + return ERROR_NET_ADHOC_DISCONNECTED; } // Invalid Argument @@ -677,16 +1595,96 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * return ERROR_NET_ADHOC_NOT_INITIALIZED; } +int NetAdhoc_SetSocketAlert(int id, s32_le flag) { + if (id < 1 || id > MAX_SOCKET || adhocSockets[id - 1] == NULL) + return ERROR_NET_ADHOC_INVALID_SOCKET_ID; + + // FIXME: Should we check for valid Alert Flags and/or Mask them? Should we return an error if we found an invalid flag? + s32_le flg = flag & ADHOC_F_ALERTALL; + + adhocSockets[id - 1]->flags = flg; + adhocSockets[id - 1]->alerted_flags = 0; + + return 0; +} + // Flags seems to be bitmasks of ADHOC_F_ALERT... int sceNetAdhocSetSocketAlert(int id, int flag) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocSetSocketAlert(%d, %08x)", id, flag); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocSetSocketAlert(%d, %08x) at %08x", id, flag, currentMIPS->pc); - return 0; //Dummy Result + return NetAdhoc_SetSocketAlert(id, flag); +} + +int PollAdhocSocket(SceNetAdhocPollSd* sds, int count, int timeout) { + //WSAPoll only available for Vista or newer, so we'll use an alternative way for XP since Windows doesn't have poll function like *NIX + fd_set readfds, writefds, exceptfds; + int fd; + int maxfd = 0; + FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); + + for (int i = 0; i < count; i++) { + sds[i].revents = 0; + // Fill in Socket ID + if (sds[i].id > 0 && sds[i].id <= MAX_SOCKET && adhocSockets[sds[i].id - 1] != NULL) { + auto sock = adhocSockets[sds[i].id - 1]; + if (sock->type == SOCK_PTP) { + fd = sock->data.ptp.id; + if (sock->data.ptp.state == ADHOC_PTP_STATE_LISTEN) + sds[i].revents |= ADHOC_EV_ACCEPT; + else if (sock->data.ptp.state == ADHOC_PTP_STATE_CLOSED) + sds[i].revents |= ADHOC_EV_CONNECT; + } + else { + fd = sock->data.pdp.id; + } + if (fd > maxfd) maxfd = fd; + if (sds[i].events & ADHOC_EV_RECV) FD_SET(fd, &readfds); + if (sds[i].events & ADHOC_EV_SEND) FD_SET(fd, &writefds); + //if (sds[i].events & ADHOC_EV_ALERT) + FD_SET(fd, &exceptfds); // Does Alert can be raised on revents regardless of events bitmask? + } + } + timeval tmout; + tmout.tv_sec = timeout / 1000000; // seconds + tmout.tv_usec = (timeout % 1000000); // microseconds + int affectedsockets = select(maxfd + 1, &readfds, &writefds, &exceptfds, &tmout); + if (affectedsockets > 0) { + affectedsockets = 0; + for (int i = 0; i < count; i++) { + if (sds[i].id > 0 && sds[i].id <= MAX_SOCKET && adhocSockets[sds[i].id - 1] != NULL) { + auto sock = adhocSockets[sds[i].id - 1]; + if (sock->type == SOCK_PTP) { + fd = sock->data.ptp.id; + } + else { + fd = sock->data.pdp.id; + } + if (FD_ISSET(fd, &readfds)) + sds[i].revents |= ADHOC_EV_RECV; + if (FD_ISSET(fd, &writefds)) + sds[i].revents |= ADHOC_EV_SEND; + if (FD_ISSET(fd, &exceptfds) || sock->alerted_flags) + sds[i].revents |= ADHOC_EV_ALERT; + sds[i].revents &= sds[i].events; + if (sds[i].revents) affectedsockets++; + + if (sock->flags & ADHOC_F_ALERTPOLL) { + affectedsockets = ERROR_NET_ADHOC_SOCKET_ALERTED; + // FIXME: Should we clear the flag after alert signaled? + sock->flags &= ~ADHOC_F_ALERTPOLL; + sock->alerted_flags |= ADHOC_F_ALERTPOLL; + break; + } + } + } + } + else if (affectedsockets < 0) { + affectedsockets = ERROR_NET_ADHOC_WOULD_BLOCK; + } + return affectedsockets; } int sceNetAdhocPollSocket(u32 socketStructAddr, int count, int timeout, int nonblock) { // timeout in microseconds - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocPollSocket(%08x, %i, %i, %i) at %08x", socketStructAddr, count, timeout, nonblock, currentMIPS->pc); - // Library is initialized if (netAdhocInited) { @@ -697,87 +1695,94 @@ int sceNetAdhocPollSocket(u32 socketStructAddr, int count, int timeout, int nonb if (sds != NULL && count > 0) { // Socket Check - int i = 0; for (; i < count; i++) - { + for (int i = 0; i < count; i++) { // Invalid Socket - if (sds[i].id < 1 || sds[i].id > 255 || (pdp[sds[i].id - 1] == NULL && ptp[sds[i].id - 1] == NULL)) return ERROR_NET_ADHOC_INVALID_SOCKET_ID; + if (sds[i].id < 1 || sds[i].id > MAX_SOCKET || adhocSockets[sds[i].id - 1] == NULL) + return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Nonblocking Mode - if (nonblock) timeout = 0; + if (nonblock) + timeout = 0; - // Prevent Nonblocking Mode - else - if (timeout == 0) timeout = 1; + // Blocking Mode + else + // Does timeout = 0 means undefinite on PSP? + if (timeout == 0) + timeout = adhocDefaultTimeout * 1000; // minSocketTimeoutUS; - int affectedsockets = 0; - if (count > (int)FD_SETSIZE) count = FD_SETSIZE; // return affectedsockets; + if (count > (int)FD_SETSIZE) + count = FD_SETSIZE; // return 0; //ERROR_NET_ADHOC_INVALID_ARG // Acquire Network Lock //acquireNetworkLock(); // Poll Sockets //int affectedsockets = sceNetInetPoll(isds, count, timeout); + int affectedsockets = 0; + if (nonblock) + affectedsockets = PollAdhocSocket(sds, count, timeout); + else { + // Simulate blocking behaviour with non-blocking socket + // Borrowing some arguments to pass some parameters. The dummy WaitID(count+1) might not be unique thus have duplicate possibilities if there are multiple thread trying to poll the same numbers of socket at the same time + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | (count + 1ULL); + return WaitBlockingAdhocSocket(threadSocketId, ADHOC_POLL_SOCKET, count, sds, nullptr, timeout, nullptr, nullptr, "adhoc pollsocket"); + } - //WSAPoll only available for Vista or newer, so we'll use an alternative way for XP since Windows doesn't have poll function like *NIX - fd_set readfds, writefds, exceptfds; - int fd; - FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); - // TODO: PDP and PTP should share the same indexing to prevent identical PDP & PTP socket id - for (int i = 0; i < count; i++) { - sds[i].revents = 0; - // Fill in Socket ID - if (ptp[sds[i].id - 1] != NULL) { - fd = ptp[sds[i].id - 1]->id; - if (ptp[sds[i].id - 1]->state == ADHOC_PTP_STATE_LISTEN) sds[i].revents |= ADHOC_EV_ACCEPT; - else - if (ptp[sds[i].id - 1]->state == ADHOC_PTP_STATE_CLOSED) sds[i].revents |= ADHOC_EV_CONNECT; - } - else { - fd = pdp[sds[i].id - 1]->id; - } - if (sds[i].events & ADHOC_EV_RECV) FD_SET(fd, &readfds); - if (sds[i].events & ADHOC_EV_SEND) FD_SET(fd, &writefds); - //if (sds[i].events & ADHOC_EV_ALERT) - FD_SET(fd, &exceptfds); - } - timeval tmout; - tmout.tv_sec = timeout / 1000000; // seconds - tmout.tv_usec = (timeout % 1000000); // microseconds - affectedsockets = select(count, &readfds, &writefds, &exceptfds, &tmout); - if (affectedsockets > 0) { - affectedsockets = 0; - for (int i = 0; i < count; i++) { - if (ptp[sds[i].id - 1] != NULL) { - fd = ptp[sds[i].id - 1]->id; - } - else { - fd = pdp[sds[i].id - 1]->id; - } - if (FD_ISSET(fd, &readfds)) sds[i].revents |= ADHOC_EV_RECV; - if (FD_ISSET(fd, &writefds)) sds[i].revents |= ADHOC_EV_SEND; // Data can always be sent ? - sds[i].revents &= sds[i].events; - if (FD_ISSET(fd, &exceptfds)) sds[i].revents |= ADHOC_EV_ALERT; // can be raised on revents regardless of events bitmask? - if (sds[i].revents) affectedsockets++; - } - } // Free Network Lock //freeNetworkLock(); - // Blocking Mode (Nonblocking Mode returns 0, even on Success) - if (!nonblock) - { - // Success - if (affectedsockets >= 0) return affectedsockets; // (affectedsockets > 0) + // No Events generated + // Non-blocking mode + // Bleach 7 seems to use nonblocking and check the return value > 0, or 0x80410709 (ERROR_NET_ADHOC_WOULD_BLOCK), also 0x80410717 (ERROR_NET_ADHOC_EXCEPTION_EVENT), when using prx files on JPCSP it can return 0 + if (affectedsockets >= 0) { + DEBUG_LOG(SCENET, "%08x=sceNetAdhocPollSocket(%08x, %i, %i, %i) at %08x", affectedsockets, socketStructAddr, count, timeout, nonblock, currentMIPS->pc); + return affectedsockets; + } + else if (nonblock && affectedsockets < 0) + return hleLogDebug(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); - // Timeout - return ERROR_NET_ADHOC_TIMEOUT; + return hleLogDebug(SCENET, ERROR_NET_ADHOC_EXCEPTION_EVENT, "exception event"); + } + + // Invalid Argument + return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + } + + // Library is uninitialized + return hleLogDebug(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); +} + +int NetAdhocPdp_Delete(int id, int unknown) { + // Library is initialized + if (netAdhocInited) { + // Valid Arguments + if (id > 0 && id <= MAX_SOCKET) { + // Cast Socket + auto sock = adhocSockets[id - 1]; + + // Valid Socket + if (sock != NULL && sock->type == SOCK_PDP) { + // Close Connection + shutdown(sock->data.pdp.id, SD_BOTH); + closesocket(sock->data.pdp.id); + + // Remove Port Forward from Router + //sceNetPortClose("UDP", sock->lport); + //g_PortManager.Remove(IP_PROTOCOL_UDP, isOriPort ? sock->lport : sock->lport + portOffset); // Let's not remove mapping in real-time as it could cause lags/disconnection when joining a room with slow routers + + // Free Memory + free(sock); + + // Free Translation Slot + adhocSockets[id - 1] = NULL; + + // Success + return 0; } - // No Events generated - if (affectedsockets >= 0) return 0; - - return ERROR_NET_ADHOC_WOULD_BLOCK; // Bleach 7 seems to use nonblocking and check the return value against 0 and 0x80410709 (also 0x80410717 ?) + // Invalid Socket ID + return ERROR_NET_ADHOC_INVALID_SOCKET_ID; } // Invalid Argument @@ -803,41 +1808,7 @@ static int sceNetAdhocPdpDelete(int id, int unknown) { } */ - // Library is initialized - if (netAdhocInited) { - // Valid Arguments - if (id > 0 && id <= 255) { - // Cast Socket - SceNetAdhocPdpStat * sock = pdp[id - 1]; - - // Valid Socket - if (sock != NULL) { - // Close Connection - closesocket(sock->id); - - // Remove Port Forward from Router - //sceNetPortClose("UDP", sock->lport); - - // Free Memory - // free(sock); - - // Free Translation Slot - pdp[id - 1] = NULL; - - // Success - return 0; - } - - // Invalid Socket ID - return ERROR_NET_ADHOC_INVALID_SOCKET_ID; - } - - // Invalid Argument - return ERROR_NET_ADHOC_INVALID_ARG; - } - - // Library is uninitialized - return ERROR_NET_ADHOC_NOT_INITIALIZED; + return NetAdhocPdp_Delete(id, unknown); } static int sceNetAdhocctlGetAdhocId(u32 productStructAddr) { @@ -866,56 +1837,73 @@ static int sceNetAdhocctlGetAdhocId(u32 productStructAddr) { return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; } -static int sceNetAdhocctlScan() { +// FIXME: Scan probably not a blocking function since there is ADHOCCTL_STATE_SCANNING state that can be polled by the game, right? But apparently it need to be delayed for Naruto Shippuden Ultimate Ninja Heroes 3 +int sceNetAdhocctlScan() { INFO_LOG(SCENET, "sceNetAdhocctlScan() at %08x", currentMIPS->pc); + if (!g_Config.bEnableWlan) { + return -1; + } // Library initialized if (netAdhocctlInited) { - // Not connected - if (threadStatus == ADHOCCTL_STATE_DISCONNECTED) { - threadStatus = ADHOCCTL_STATE_SCANNING; + int us = adhocEventPollDelayMS * 1000; + + // Only scan when in Disconnected state, otherwise AdhocServer will kick you out + if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED) { + adhocctlState = ADHOCCTL_STATE_SCANNING; + + // Reset Networks/Group list to prevent other threads from using these soon to be replaced networks + peerlock.lock(); + freeGroupsRecursive(networks); + networks = NULL; + peerlock.unlock(); // Prepare Scan Request Packet uint8_t opcode = OPCODE_SCAN; // Send Scan Request Packet, may failed with socket error 10054/10053 if someone else with the same IP already connected to AdHoc Server (the server might need to be modified to differentiate MAC instead of IP) - int iResult = send(metasocket, (char *)&opcode, 1, 0); - if (iResult == SOCKET_ERROR) { - int error = errno; - ERROR_LOG(SCENET, "Socket error (%i) when sending", error); - threadStatus = ADHOCCTL_STATE_DISCONNECTED; - //if (error == ECONNABORTED || error == ECONNRESET || error == ENOTCONN) return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; // A case where it need to reconnect to AdhocServer - return ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY - } + int iResult = send(metasocket, (char *)&opcode, 1, MSG_NOSIGNAL); + int error = errno; - // Wait for Status to be connected to prevent Ford Street Racing from Failed to find game session - if (friendFinderRunning) { - int cnt = 0; - while ((threadStatus == ADHOCCTL_STATE_SCANNING) && (cnt < 5000)) { - sleep_ms(1); - cnt++; + if (iResult == SOCKET_ERROR) { + if (error != EAGAIN && error != EWOULDBLOCK) { + ERROR_LOG(SCENET, "Socket error (%i) when sending", error); + adhocctlState = ADHOCCTL_STATE_DISCONNECTED; + //if (error == ECONNABORTED || error == ECONNRESET || error == ENOTCONN) return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; // A case where it need to reconnect to AdhocServer + return ERROR_NET_ADHOCCTL_BUSY; + } + else if (friendFinderRunning) { + AdhocctlRequest req = { OPCODE_SCAN, {0} }; + return WaitAdhocctlState(req, ADHOCCTL_STATE_DISCONNECTED, us, "adhocctl scan"); } } - - // Return Success - return 0; + else { + // Return Success and let friendFinder thread to notify the handler when scan completed + // Not delaying here may cause Naruto Shippuden Ultimate Ninja Heroes 3 to get disconnected when the mission started + return hleDelayResult(0, "give a little time to be ready to receive the callback", us); + } } + else if (adhocctlState == ADHOCCTL_STATE_SCANNING) + return ERROR_NET_ADHOCCTL_BUSY; - // Library is busy - return ERROR_NET_ADHOCCTL_BUSY; // ERROR_NET_ADHOCCTL_BUSY may trigger the game (ie. Ford Street Racing) to call sceNetAdhocctlDisconnect + // Already connected to a group. Should we fake a success? + // We need to notify the handler on success, even if it was faked + notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0); + // FIXME: returning ERROR_NET_ADHOCCTL_BUSY may trigger the game (ie. Ford Street Racing) to call sceNetAdhocctlDisconnect, But Not returning a Success(0) will cause Valhalla Knights 2 not working properly + return hleDelayResult(0, "give a little time to be ready to receive the callback", us); } // Library uninitialized return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; } -static int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { +int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { s32_le *buflen = NULL; if (Memory::IsValidAddress(sizeAddr)) buflen = (s32_le *)Memory::GetPointer(sizeAddr); SceNetAdhocctlScanInfoEmu *buf = NULL; if (Memory::IsValidAddress(bufAddr)) buf = (SceNetAdhocctlScanInfoEmu *)Memory::GetPointer(bufAddr); - INFO_LOG(SCENET, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x)", sizeAddr, buflen ? *buflen : -1, bufAddr); + INFO_LOG(SCENET, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x)", sizeAddr, Memory::Read_U32(sizeAddr), bufAddr); if (!g_Config.bEnableWlan) { return 0; } @@ -931,8 +1919,11 @@ static int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { peerlock.lock(); // Length Returner Mode - if (buf == NULL) *buflen = countAvailableNetworks() * sizeof(SceNetAdhocctlScanInfoEmu); - + if (buf == NULL) { + int availNetworks = countAvailableNetworks(); + *buflen = availNetworks * sizeof(SceNetAdhocctlScanInfoEmu); + DEBUG_LOG(SCENET, "NetworkList [Available: %i]", availNetworks); + } // Normal Information Mode else { // Clear Memory @@ -960,18 +1951,15 @@ static int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { // Exchange Adhoc Channel // sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL, &buf[discovered].channel); - // Fake Channel Number 1 on Automatic Channel - // if (buf[discovered].channel == 0) buf[discovered].channel = 1; - - //Always Fake Channel 1 - buf[discovered].channel = 1; + // Fake Channel Number 1 on Automatic Channel (JPCSP use 11 as default). Ridge Racer 2 will ignore any groups with channel 0 or that doesn't matched with channel value returned from sceUtilityGetSystemParamInt (which mean sceUtilityGetSystemParamInt must not return channel 0 when connected to a network?) + buf[discovered].channel = group->channel; //parameter.channel // Increase Discovery Counter discovered++; } // Link List - int i = 0; for (; i < discovered - 1; i++) { + for (int i = 0; i < discovered - 1; i++) { // Link Network buf[i].next = bufAddr + (sizeof(SceNetAdhocctlScanInfoEmu)*i) + sizeof(SceNetAdhocctlScanInfoEmu); // buf[i].next = &buf[i + 1]; } @@ -982,6 +1970,7 @@ static int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { // Fix Size *buflen = discovered * sizeof(SceNetAdhocctlScanInfoEmu); + DEBUG_LOG(SCENET, "NetworkList [Requested: %i][Discovered: %i]", requestcount, discovered); } // Multithreading Unlock @@ -1001,10 +1990,11 @@ static int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { // TODO: How many handlers can the PSP actually have for Adhocctl? // TODO: Should we allow the same handler to be added more than once? +// FIXME: Do all Adhocctl HLE returning 0 and expecting error code through callback handler if there were error, instead of returning error code through the HLE ? static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) { bool foundHandler = false; u32 retval = 0; - struct AdhocctlHandler handler; + AdhocctlHandler handler; memset(&handler, 0, sizeof(handler)); while (adhocctlHandlers.find(retval) != adhocctlHandlers.end()) @@ -1040,25 +2030,16 @@ static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) { return retval; } -static u32 sceNetAdhocctlDisconnect() { - // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right? - INFO_LOG(SCENET, "sceNetAdhocctlDisconnect() at %08x [group=%s]", currentMIPS->pc, parameter.group_name.data); - /* - if (!g_Config.bEnableWlan) { - return 0; - } - */ - +u32 NetAdhocctl_Disconnect() { // Library initialized if (netAdhocctlInited) { + int iResult, error; + int us = adhocEventPollDelayMS * 1000; // Connected State (Adhoc Mode) - if (threadStatus != ADHOCCTL_STATE_DISCONNECTED) { // (threadStatus == ADHOCCTL_STATE_CONNECTED) + if (adhocctlState != ADHOCCTL_STATE_DISCONNECTED) { // (threadStatus == ADHOCCTL_STATE_CONNECTED) // Clear Network Name memset(¶meter.group_name, 0, sizeof(parameter.group_name)); - // Set Disconnected State - threadStatus = ADHOCCTL_STATE_DISCONNECTED; - // Set HUD Connection Status //setConnectionStatus(0); @@ -1069,55 +2050,123 @@ static u32 sceNetAdhocctlDisconnect() { //_acquireNetworkLock(); // Send Disconnect Request Packet - int iResult = send(metasocket, (const char *)&opcode, 1, 0); + iResult = send(metasocket, (const char*)&opcode, 1, MSG_NOSIGNAL); + error = errno; + + // Sending may get socket error 10053 if the AdhocServer is already shutted down if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "Socket error (%i) when sending", errno); + if (error != EAGAIN && error != EWOULDBLOCK) { + ERROR_LOG(SCENET, "Socket error (%i) when sending", error); + // Set Disconnected State + adhocctlState = ADHOCCTL_STATE_DISCONNECTED; + } + else if (friendFinderRunning) { + AdhocctlRequest req = { OPCODE_DISCONNECT, {0} }; + WaitAdhocctlState(req, ADHOCCTL_STATE_DISCONNECTED, us, "adhocctl disconnect"); + } + else { + // Set Disconnected State + //adhocctlState = ADHOCCTL_STATE_DISCONNECTED; + return ERROR_NET_ADHOCCTL_BUSY; + } } // Free Network Lock //_freeNetworkLock(); - - // Multithreading Lock - //peerlock.lock(); - - if (!PSP_CoreParameter().compat.flags().AdhocHackStopFriendClear) { - // Clear Peer List - freeFriendsRecursive(friends); - INFO_LOG(SCENET, "Cleared Peer List."); - - // Delete Peer Reference - friends = NULL; - } - - // Clear Group List - //freeGroupsRecursive(networks); - - // Delete Group Reference - //networks = NULL; - - // Multithreading Unlock - //peerlock.unlock(); } - + + // Multithreading Lock + //peerlock.lock(); + + // Clear Peer List, since games are moving to a different a group when the mission started may be we shouldn't free all peers yet + int32_t peercount = 0; + timeoutFriendsRecursive(friends, &peercount); + INFO_LOG(SCENET, "Marked for Timedout Peer List (%i)", peercount); + // Delete Peer Reference + //friends = NULL; + + // Clear Group List + //freeGroupsRecursive(networks); + + // Delete Group Reference + //networks = NULL; + + // Multithreading Unlock + //peerlock.unlock(); + + adhocctlCurrentMode = ADHOCCTL_MODE_NONE; // Notify Event Handlers (even if we weren't connected, not doing this will freeze games like God Eater, which expect this behaviour) - { - std::lock_guard adhocGuard(adhocEvtMtx); - adhocctlEvents.push_back({ ADHOCCTL_EVENT_DISCONNECT, 0 }); - } + notifyAdhocctlHandlers(ADHOCCTL_EVENT_DISCONNECT, 0); + //hleCheckCurrentCallbacks(); + // Return Success, some games might ignore returned value and always treat it as success, otherwise repeatedly calling this function return 0; } // Library uninitialized - return 0; //ERROR_NET_ADHOC_NOT_INITIALIZED; // Wipeout Pulse will repeatedly calling this function if returned value is ERROR_NET_ADHOC_NOT_INITIALIZED + return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; +} + +static u32 sceNetAdhocctlDisconnect() { + // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right? + char grpName[9] = { 0 }; + memcpy(grpName, parameter.group_name.data, ADHOCCTL_GROUPNAME_LEN); // Copied to null-terminated var to prevent unexpected behaviour on Logs + int ret = NetAdhocctl_Disconnect(); + INFO_LOG(SCENET, "%08x=sceNetAdhocctlDisconnect() at %08x [group=%s]", ret, currentMIPS->pc, grpName); + + return ret; } static u32 sceNetAdhocctlDelHandler(u32 handlerID) { + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "adhocctl not initialized"); + if (adhocctlHandlers.find(handlerID) != adhocctlHandlers.end()) { adhocctlHandlers.erase(handlerID); - WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlDelHandler(%d): deleted handler %d", handlerID, handlerID); + INFO_LOG(SCENET, "sceNetAdhocctlDelHandler(%d)", handlerID); } else { - ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlDelHandler(%d): asked to delete invalid handler %d", handlerID, handlerID); + WARN_LOG(SCENET, "sceNetAdhocctlDelHandler(%d): Invalid Handler ID", handlerID); + } + + return 0; +} + +int NetAdhocctl_Term() { + if (netAdhocctlInited) { + if (adhocctlState != ADHOCCTL_STATE_DISCONNECTED) { + if (netAdhocGameModeEntered) + NetAdhocctl_ExitGameMode(); + else + NetAdhocctl_Disconnect(); + } + + // Terminate Adhoc Threads + friendFinderRunning = false; + if (friendFinderThread.joinable()) { + friendFinderThread.join(); + } + + // Clear Peer List + int32_t peercount = 0; + freeFriendsRecursive(friends, &peercount); + INFO_LOG(SCENET, "Cleared Peer List (%i)", peercount); + // Delete Peer Reference + friends = NULL; + //May also need to clear Handlers + adhocctlHandlers.clear(); + // Free stuff here + networkInited = false; + shutdown(metasocket, SD_BOTH); + closesocket(metasocket); + metasocket = (int)INVALID_SOCKET; + // Delete fake PSP Thread + if (threadAdhocID != 0) { + __KernelStopThread(threadAdhocID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocThread stopped"); + __KernelDeleteThread(threadAdhocID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocThread deleted"); + threadAdhocID = 0; + } + adhocctlCurrentMode = ADHOCCTL_MODE_NONE; + netAdhocctlInited = false; } return 0; @@ -1127,47 +2176,33 @@ int sceNetAdhocctlTerm() { // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right? INFO_LOG(SCENET, "sceNetAdhocctlTerm()"); - if (netAdhocMatchingInited) sceNetAdhocMatchingTerm(); + //if (netAdhocMatchingInited) NetAdhocMatching_Term(); - if (netAdhocctlInited) { - netAdhocctlInited = false; - friendFinderRunning = false; - if (friendFinderThread.joinable()) { - friendFinderThread.join(); - } - //May also need to clear Handlers - adhocctlHandlers.clear(); - // Free stuff here - closesocket(metasocket); - metasocket = (int)INVALID_SOCKET; -/*#ifdef _MSC_VER - WSACleanup(); // Might be better to call WSAStartup/WSACleanup from sceNetInit/sceNetTerm isn't? since it's the first/last network function being used, even better to put it in __NetInit/__NetShutdown as it's only called once -#endif*/ - } - - return 0; + return NetAdhocctl_Term(); } static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocctlGetNameByAddr(%s, %08x)", mac, nameAddr); + DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocctlGetNameByAddr(%s, %08x) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), nameAddr, currentMIPS->pc); // Library initialized if (netAdhocctlInited) { // Valid Arguments - if (mac != NULL && nameAddr != 0) + if (mac != NULL && Memory::IsValidAddress(nameAddr)) { - SceNetAdhocctlNickname * nickname = NULL; - if (Memory::IsValidAddress(nameAddr)) nickname = (SceNetAdhocctlNickname *)Memory::GetPointer(nameAddr); + SceNetAdhocctlNickname * nickname = (SceNetAdhocctlNickname *)Memory::GetPointer(nameAddr); // Get Local MAC Address - SceNetEtherAddr localmac; getLocalMac(&localmac); + SceNetEtherAddr localmac; + getLocalMac(&localmac); // Local MAC Matches - if (memcmp(&localmac, mac, sizeof(SceNetEtherAddr)) == 0) + if (isMacMatch(&localmac, (const SceNetEtherAddr*)mac)) { // Write Data *nickname = parameter.nickname; + DEBUG_LOG(SCENET, "sceNetAdhocctlGetNameByAddr - [PlayerName:%s]", (char*)nickname); + // Return Success return 0; } @@ -1182,7 +2217,7 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { for (; peer != NULL; peer = peer->next) { // Match found - if (memcmp(&peer->mac_addr, mac, sizeof(SceNetEtherAddr)) == 0) + if (isMacMatch(&peer->mac_addr, (const SceNetEtherAddr*)mac)) { // Write Data *nickname = peer->nickname; @@ -1190,6 +2225,8 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { // Multithreading Unlock peerlock.unlock(); + DEBUG_LOG(SCENET, "sceNetAdhocctlGetNameByAddr - [PeerName:%s]", (char*)nickname); + // Return Success return 0; } @@ -1198,6 +2235,7 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { // Multithreading Unlock peerlock.unlock(); + DEBUG_LOG(SCENET, "sceNetAdhocctlGetNameByAddr - PlayerName not found"); // Player not found return ERROR_NET_ADHOC_NO_ENTRY; } @@ -1210,35 +2248,8 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; } -static int sceNetAdhocctlJoin(u32 scanInfoAddr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlJoin(%08x) at %08x", scanInfoAddr, currentMIPS->pc); - if (!g_Config.bEnableWlan) { - return -1; - } - - // Library initialized - if (netAdhocctlInited) - { - // Valid Argument - if (Memory::IsValidAddress(scanInfoAddr)) - { - SceNetAdhocctlScanInfoEmu * sinfo = (SceNetAdhocctlScanInfoEmu *)Memory::GetPointer(scanInfoAddr); - //while (true) sleep_ms(1); - - // We can ignore minor connection process differences here - return sceNetAdhocctlCreate((const char*)&sinfo->group_name); - } - - // Invalid Argument - return ERROR_NET_ADHOCCTL_INVALID_ARG; - } - - // Uninitialized Library - return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; -} - int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { - VERBOSE_LOG(SCENET, "sceNetAdhocctlGetPeerInfo(%s, %i, %08x) at %08x", mac, size, peerInfoAddr, currentMIPS->pc); + VERBOSE_LOG(SCENET, "sceNetAdhocctlGetPeerInfo(%s, %i, %08x) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), size, peerInfoAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -1256,18 +2267,16 @@ int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { // Local MAC if (isLocalMAC(maddr)) { - sockaddr_in addr; SceNetAdhocctlNickname nickname; - getLocalIp(&addr); - strcpy((char*)nickname.data, g_Config.sNickName.c_str()); - //buf->next = 0; + truncate_cpy((char*)&nickname.data, ADHOCCTL_NICKNAME_LEN, g_Config.sNickName.c_str()); + buf->next = 0; buf->nickname = nickname; buf->nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; // last char need to be null-terminated char buf->mac_addr = *maddr; - buf->ip_addr = addr.sin_addr.s_addr; // 0x11111111; - //buf->padding = 0x1111; //0; - buf->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + buf->flags = 0x0400; + buf->padding = 0; + buf->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; // Success retval = 0; @@ -1281,15 +2290,16 @@ int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { SceNetAdhocctlPeerInfo * peer = findFriend(maddr); if (peer != NULL) { // Fake Receive Time - if (peer->last_recv != 0) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + if (peer->last_recv != 0) + peer->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; //buf->next = 0; buf->nickname = peer->nickname; buf->nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; // last char need to be null-terminated char buf->mac_addr = *maddr; - buf->ip_addr = peer->ip_addr; // 0x11111111; - //buf->padding = /*0;*/ 0x1111; - buf->last_recv = peer->last_recv; //CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; //(uint64_t)time(NULL); //This timestamp is important issue on Dissidia 012 + buf->flags = 0x0400; //peer->ip_addr; + buf->padding = 0; + buf->last_recv = peer->last_recv; //CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0; //(uint64_t)time(NULL); //This timestamp is important issue on Dissidia 012 // Success retval = 0; @@ -1305,24 +2315,14 @@ int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; } -/** - * Create and / or Join a Virtual Network of the specified Name - * @param group_name Virtual Network Name - * @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG, ADHOCCTL_BUSY - */ -int sceNetAdhocctlCreate(const char *groupName) { - INFO_LOG(SCENET, "sceNetAdhocctlCreate(%s) at %08x", groupName, currentMIPS->pc); - if (!g_Config.bEnableWlan) { - return -1; - } - - const SceNetAdhocctlGroupName * groupNameStruct = (const SceNetAdhocctlGroupName *)groupName; +int NetAdhocctl_Create(const char* groupName) { + const SceNetAdhocctlGroupName* groupNameStruct = (const SceNetAdhocctlGroupName*)groupName; // Library initialized if (netAdhocctlInited) { // Valid Argument if (validNetworkName(groupNameStruct)) { // Disconnected State, may also need to check for Scanning state to prevent some games from failing to host a game session - if ((threadStatus == ADHOCCTL_STATE_DISCONNECTED) || (threadStatus == ADHOCCTL_STATE_SCANNING)) { + if ((adhocctlState == ADHOCCTL_STATE_DISCONNECTED) || (adhocctlState == ADHOCCTL_STATE_SCANNING)) { // Set Network Name if (groupNameStruct != NULL) parameter.group_name = *groupNameStruct; @@ -1344,15 +2344,23 @@ int sceNetAdhocctlCreate(const char *groupName) { // Acquire Network Lock // Send Packet - int iResult = send(metasocket, (const char *)&packet, sizeof(packet), 0); - if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "Socket error (%i) when sending", errno); + int iResult = send(metasocket, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); + int error = errno; + + if (iResult == SOCKET_ERROR && error != EAGAIN && error != EWOULDBLOCK) { + ERROR_LOG(SCENET, "Socket error (%i) when sending", error); //return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; // ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY; //Faking success, to prevent Full Auto 2 from freezing while Initializing Network - threadStatus = ADHOCCTL_STATE_CONNECTED; - // Notify Event Handlers, Needed for the Nickname to be shown on the screen when success is faked - // Might be better not to notify the game when faking success (failed to connect to adhoc server), at least the player will know that it failed to connect - //__UpdateAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0); //CoreTiming::ScheduleEvent_Threadsafe_Immediate(eventAdhocctlHandlerUpdate, join32(ADHOCCTL_EVENT_CONNECT, 0)); + if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) { + adhocctlState = ADHOCCTL_STATE_GAMEMODE; + notifyAdhocctlHandlers(ADHOCCTL_EVENT_GAME, 0); + } + else { + adhocctlState = ADHOCCTL_STATE_CONNECTED; + // Notify Event Handlers, Needed for the Nickname to be shown on the screen when success is faked + // Connected Event's mipscall need be executed before returning from sceNetAdhocctlCreate (or before the next sceNet function?) + notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0); //CoreTiming::ScheduleEvent_Threadsafe_Immediate(eventAdhocctlHandlerUpdate, join32(ADHOCCTL_EVENT_CONNECT, 0)); + } } // Free Network Lock @@ -1361,22 +2369,24 @@ int sceNetAdhocctlCreate(const char *groupName) { //setConnectionStatus(1); // Wait for Status to be connected to prevent Ford Street Racing from Failed to create game session - if (friendFinderRunning) { - int cnt = 0; - while ((threadStatus != ADHOCCTL_STATE_CONNECTED) && (cnt < 5000)) { - sleep_ms(1); - cnt++; - } + int us = adhocEventDelayMS * 1000; + if (adhocctlState != ADHOCCTL_STATE_CONNECTED && iResult == SOCKET_ERROR && friendFinderRunning) { + AdhocctlRequest req = { OPCODE_CONNECT, {0} }; + if (groupNameStruct != NULL) req.group = *groupNameStruct; + return WaitAdhocctlState(req, ADHOCCTL_STATE_CONNECTED, us, "adhocctl connect"); } + // Giving time for Naruto Shippuden Ninja Heroes 3 to close down the "Connecting..." dialog, otherwise the dialog will stuck there. + else if (adhocctlState == ADHOCCTL_STATE_CONNECTED || iResult != SOCKET_ERROR) + hleDelayResult(0, "give time to init/cleanup", us); // Return Success return 0; } - + // Connected State return ERROR_NET_ADHOCCTL_BUSY; // ERROR_NET_ADHOCCTL_BUSY may trigger the game (ie. Ford Street Racing) to call sceNetAdhocctlDisconnect } - + // Invalid Argument return ERROR_NET_ADHOC_INVALID_ARG; } @@ -1384,23 +2394,159 @@ int sceNetAdhocctlCreate(const char *groupName) { return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; } -static int sceNetAdhocctlConnect(u32 ptrToGroupName) { - if (Memory::IsValidAddress(ptrToGroupName)) { - INFO_LOG(SCENET, "sceNetAdhocctlConnect(groupName=%s) at %08x", Memory::GetCharPointer(ptrToGroupName), currentMIPS->pc); - return sceNetAdhocctlCreate(Memory::GetCharPointer(ptrToGroupName)); - } - - return ERROR_NET_ADHOC_INVALID_ARG; // ERROR_NET_ADHOC_INVALID_ADDR; +/** + * Create and / or Join a Virtual Network of the specified Name + * @param group_name Virtual Network Name + * @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG, ADHOCCTL_BUSY + */ +int sceNetAdhocctlCreate(const char *groupName) { + char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; + if (groupName) + memcpy(grpName, groupName, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated + INFO_LOG(SCENET, "sceNetAdhocctlCreate(%s) at %08x", grpName, currentMIPS->pc); + if (!g_Config.bEnableWlan) { + return -1; + } + + adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL; + adhocConnectionType = ADHOC_CREATE; + return NetAdhocctl_Create(groupName); } -static int sceNetAdhocctlCreateEnterGameMode(const char *groupName, int unknown, int playerNum, u32 macsAddr, int timeout, int unknown2) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlCreateEnterGameMode(%s, %i, %i, %08x, %i, %i) at %08x", groupName, unknown, playerNum, macsAddr, timeout, unknown2, currentMIPS->pc); - return -1; +int sceNetAdhocctlConnect(const char* groupName) { + char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; + if (groupName) + memcpy(grpName, groupName, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated + INFO_LOG(SCENET, "sceNetAdhocctlConnect(%s) at %08x", grpName, currentMIPS->pc); + if (!g_Config.bEnableWlan) { + return -1; + } + + adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL; + adhocConnectionType = ADHOC_CONNECT; + return NetAdhocctl_Create(groupName); } -static int sceNetAdhocctlJoinEnterGameMode(const char *groupName, const char *macAddr, int timeout, int unknown2) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlJoinEnterGameMode(%s, %s, %i, %i) at %08x", groupName, macAddr, timeout, unknown2, currentMIPS->pc); - return -1; +int sceNetAdhocctlJoin(u32 scanInfoAddr) { + INFO_LOG(SCENET, "sceNetAdhocctlJoin(%08x) at %08x", scanInfoAddr, currentMIPS->pc); + if (!g_Config.bEnableWlan) { + return -1; + } + + // Library initialized + if (netAdhocctlInited) + { + // Valid Argument + if (Memory::IsValidAddress(scanInfoAddr)) + { + SceNetAdhocctlScanInfoEmu* sinfo = (SceNetAdhocctlScanInfoEmu*)Memory::GetPointer(scanInfoAddr); + char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; + memcpy(grpName, sinfo->group_name.data, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated + DEBUG_LOG(SCENET, "sceNetAdhocctlJoin - Group: %s", grpName); + + // We can ignore minor connection process differences here + // TODO: Adhoc Server may need to be changed to differentiate between Host/Create and Join, otherwise it can't support multiple Host using the same Group name, thus causing one of the Host to be confused being treated as Join. + adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL; + adhocConnectionType = ADHOC_JOIN; + return NetAdhocctl_Create(grpName); + } + + // Invalid Argument + return ERROR_NET_ADHOCCTL_INVALID_ARG; + } + + // Uninitialized Library + return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; +} + +int NetAdhocctl_CreateEnterGameMode(const char* group_name, int game_type, int num_members, u32 membersAddr, u32 timeout, int flag) { + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + + if (!Memory::IsValidAddress(membersAddr)) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + + if (game_type <= 0 || game_type > 3 || num_members < 2 || num_members > 16 || (game_type == 1 && num_members > 4)) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + + if (gameModeBuffer) + free(gameModeBuffer); + gameModeBuffer = (u8*)malloc(GAMEMODE_BUFFER_SIZE); + + SceNetEtherAddr* addrs = PSPPointer::Create(membersAddr); // List of participating MAC addresses (started from host) + gameModeMacs.clear(); + requiredGameModeMacs.clear(); + for (int i = 0; i < num_members; i++) { + requiredGameModeMacs.push_back(*addrs); + DEBUG_LOG(SCENET, "GameMode macAddress#%d=%s", i, mac2str(addrs).c_str()); + addrs++; + } + // Add local MAC (Host) first + SceNetEtherAddr localMac; + getLocalMac(&localMac); + gameModeMacs.push_back(localMac); + + // We have to wait for all the MACs to have joined to go into CONNECTED state + adhocctlCurrentMode = ADHOCCTL_MODE_GAMEMODE; + adhocConnectionType = ADHOC_CREATE; + netAdhocGameModeEntered = true; + return NetAdhocctl_Create(group_name); +} + +/** +* Connect to the Adhoc control game mode (as a host) +* +* @param group_name - The name of the connection (maximum 8 alphanumeric characters). +* @param game_type - Pass 1. +* @param num_members - The total number of players (including the host). +* @param membersmacAddr - A pointer to a list of the participating mac addresses, host first, then clients. +* @param timeout - Timeout in microseconds. +* @param flag - pass 0. +* +* @return 0 on success, < 0 on error. +*/ +static int sceNetAdhocctlCreateEnterGameMode(const char * group_name, int game_type, int num_members, u32 membersAddr, int timeout, int flag) { + char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; + if (group_name) + memcpy(grpName, group_name, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated + WARN_LOG_REPORT_ONCE(sceNetAdhocctlCreateEnterGameMode, SCENET, "UNTESTED sceNetAdhocctlCreateEnterGameMode(%s, %i, %i, %08x, %i, %i) at %08x", grpName, game_type, num_members, membersAddr, timeout, flag, currentMIPS->pc); + + return NetAdhocctl_CreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag); +} + +/** +* Connect to the Adhoc control game mode (as a client) +* +* @param group_name - The name of the connection (maximum 8 alphanumeric characters). +* @param hostmacAddr - The mac address of the host. +* @param timeout - Timeout in microseconds. +* @param flag - pass 0. +* +* @return 0 on success, < 0 on error. +*/ +static int sceNetAdhocctlJoinEnterGameMode(const char * group_name, const char *hostMac, int timeout, int flag) { + char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; + if (group_name) + memcpy(grpName, group_name, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated + WARN_LOG_REPORT_ONCE(sceNetAdhocctlJoinEnterGameMode, SCENET, "UNTESTED sceNetAdhocctlJoinEnterGameMode(%s, %s, %i, %i) at %08x", grpName, mac2str((SceNetEtherAddr*)hostMac).c_str(), timeout, flag, currentMIPS->pc); + + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + + if (!hostMac) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + + if (gameModeBuffer) + free(gameModeBuffer); + gameModeBuffer = (u8*)malloc(GAMEMODE_BUFFER_SIZE); + + // Add host mac first + gameModeMacs.push_back(*(SceNetEtherAddr*)hostMac); + + adhocctlCurrentMode = ADHOCCTL_MODE_GAMEMODE; + adhocConnectionType = ADHOC_JOIN; + netAdhocGameModeEntered = true; + return NetAdhocctl_Create(group_name); } /** @@ -1414,34 +2560,29 @@ static int sceNetAdhocctlJoinEnterGameMode(const char *groupName, const char *ma * @param flag Unused Bitflags * @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG, ADHOCCTL_BUSY, ADHOCCTL_CHANNEL_NOT_AVAILABLE */ -int sceNetAdhocctlCreateEnterGameModeMin(const char *group_name, int game_type, int min_members, int num_members, u32 membersAddr, u32 timeout, int flag) -{ - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlCreateEnterGameModeMin(%s, %i, %i, %i, %08x, %d, %i) at %08x", group_name, game_type, min_members, num_members, membersAddr, timeout, flag, currentMIPS->pc); +int sceNetAdhocctlCreateEnterGameModeMin(const char *group_name, int game_type, int min_members, int num_members, u32 membersAddr, u32 timeout, int flag) { + char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; + if (group_name) + memcpy(grpName, group_name, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated + WARN_LOG_REPORT_ONCE(sceNetAdhocctlCreateEnterGameModeMin, SCENET, "UNTESTED sceNetAdhocctlCreateEnterGameModeMin(%s, %i, %i, %i, %08x, %d, %i) at %08x", grpName, game_type, min_members, num_members, membersAddr, timeout, flag, currentMIPS->pc); // We don't really need the Minimum User Check - return sceNetAdhocctlCreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag); + return NetAdhocctl_CreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag); } -int sceNetAdhocTerm() { - // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup all the sockets right? - - if (netAdhocctlInited) sceNetAdhocctlTerm(); +int NetAdhoc_Term() { + // Since Adhocctl & AdhocMatching uses Sockets & Threads we should terminate them also to release their resources + if (netAdhocMatchingInited) + NetAdhocMatching_Term(); + if (netAdhocctlInited) + NetAdhocctl_Term(); // Library is initialized if (netAdhocInited) { - // Delete fake PSP Thread - if (threadAdhocID != 0) { - __KernelStopThread(threadAdhocID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocThread stopped"); - __KernelDeleteThread(threadAdhocID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocThread deleted"); - } + // Delete Adhoc Sockets + deleteAllAdhocSockets(); - // Delete PDP Sockets - deleteAllPDP(); - - // Delete PTP Sockets - deleteAllPTP(); - - // Delete Gamemode Buffer - //deleteAllGMB(); + // Delete GameMode Buffers + deleteAllGMB(); // Terminate Internet Library //sceNetInetTerm(); @@ -1449,17 +2590,27 @@ int sceNetAdhocTerm() { // Unload Internet Modules (Just keep it in memory... unloading crashes?!) // if (_manage_modules != 0) sceUtilityUnloadModule(PSP_MODULE_NET_INET); // Library shutdown + netAdhocInited = false; - return hleLogSuccessInfoI(SCENET, 0); - } else { + //return hleLogSuccessInfoI(SCENET, 0); + } + /*else { // TODO: Reportedly returns SCE_KERNEL_ERROR_LWMUTEX_NOT_FOUND in some cases? // Only seen returning 0 in tests. return hleLogWarning(SCENET, 0, "already uninitialized"); - } + }*/ + + return 0; +} + +int sceNetAdhocTerm() { + // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup all the sockets right? + + return hleLogSuccessInfoI(SCENET, NetAdhoc_Term()); } static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { - VERBOSE_LOG(SCENET, "UNTESTED sceNetAdhocGetPdpStat(%08x, %08x) at %08x", structSize, structAddr, currentMIPS->pc); + VERBOSE_LOG(SCENET, "sceNetAdhocGetPdpStat(%08x, %08x) at %08x", structSize, structAddr, currentMIPS->pc); // Library is initialized if (netAdhocInited) @@ -1469,11 +2620,15 @@ static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { SceNetAdhocPdpStat *buf = NULL; if (Memory::IsValidAddress(structAddr)) buf = (SceNetAdhocPdpStat *)Memory::GetPointer(structAddr); + // Socket Count + int socketcount = getPDPSocketCount(); + // Length Returner Mode if (buflen != NULL && buf == NULL) { // Return Required Size - *buflen = sizeof(SceNetAdhocPdpStat) * getPDPSocketCount(); + *buflen = sizeof(SceNetAdhocPdpStat) * socketcount; + VERBOSE_LOG(SCENET, "PDP Socket Count: %d", socketcount); // Success return 0; @@ -1482,9 +2637,6 @@ static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { // Status Returner Mode else if (buflen != NULL && buf != NULL) { - // Socket Count - int socketcount = getPDPSocketCount(); - // Figure out how many Sockets we will return int count = *buflen / sizeof(SceNetAdhocPdpStat); if (count > socketcount) count = socketcount; @@ -1493,23 +2645,32 @@ static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { int i = 0; // Iterate Translation Table - int j = 0; for (; j < 255 && i < count; j++) + for (int j = 0; j < MAX_SOCKET && i < count; j++) { // Valid Socket Entry - if (pdp[j] != NULL) - { + auto sock = adhocSockets[j]; + if (sock != NULL && sock->type == SOCK_PDP) { // Copy Socket Data from Internal Memory - buf[i] = *pdp[j]; + memcpy(&buf[i], &sock->data.pdp, sizeof(SceNetAdhocPdpStat)); // Fix Client View Socket ID buf[i].id = j + 1; + // Set available bytes to be received. With FIOREAD There might be lingering 1 byte in recv buffer when remote peer's socket got closed + u32 avail = 0; + if (IsSocketReady(sock->data.pdp.id, true, false) > 0) { + avail = getAvailToRecv(sock->data.pdp.id); + } + buf[i].rcv_sb_cc = avail; + // Write End of List Reference buf[i].next = 0; // Link Previous Element if (i > 0) - buf[i - 1].next = structAddr + ((i - 1) * sizeof(SceNetAdhocPdpStat)) + sizeof(SceNetAdhocPdpStat); //buf[i - 1].next = &buf[i]; + buf[i - 1].next = structAddr + (i * sizeof(SceNetAdhocPdpStat)); + + VERBOSE_LOG(SCENET, "PDP Socket Id: %d, LPort: %d, RecvSbCC: %d", buf[i].id, buf[i].lport, buf[i].rcv_sb_cc); // Increment Counter i++; @@ -1549,10 +2710,14 @@ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { // Library is initialized if (netAdhocInited) { + // Socket Count + int socketcount = getPTPSocketCount(); + // Length Returner Mode if (buflen != NULL && buf == NULL) { // Return Required Size - *buflen = sizeof(SceNetAdhocPtpStat) * getPTPSocketCount(); + *buflen = sizeof(SceNetAdhocPtpStat) * socketcount; + VERBOSE_LOG(SCENET, "PTP Socket Count: %d", socketcount); // Success return 0; @@ -1560,9 +2725,6 @@ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { // Status Returner Mode else if (buflen != NULL && buf != NULL) { - // Socket Count - int socketcount = getPTPSocketCount(); - // Figure out how many Sockets we will return int count = *buflen / sizeof(SceNetAdhocPtpStat); if (count > socketcount) count = socketcount; @@ -1571,21 +2733,27 @@ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { int i = 0; // Iterate Sockets - int j = 0; for (; j < 255 && i < count; j++) { - // Active Socket - if (ptp[j] != NULL) { + for (int j = 0; j < MAX_SOCKET && i < count; j++) { + // Valid Socket Entry + auto sock = adhocSockets[j]; + if ( sock != NULL && sock->type == SOCK_PTP) { // Copy Socket Data from internal Memory - buf[i] = *ptp[j]; + memcpy(&buf[i], &sock->data.ptp, sizeof(SceNetAdhocPtpStat)); // Fix Client View Socket ID buf[i].id = j + 1; + + // Set available bytes to be received + buf[i].rcv_sb_cc = getAvailToRecv(sock->data.ptp.id); // Write End of List Reference buf[i].next = 0; // Link previous Element to this one if (i > 0) - buf[i - 1].next = structAddr + ((i - 1) * sizeof(SceNetAdhocPtpStat)) + sizeof(SceNetAdhocPtpStat); + buf[i - 1].next = structAddr + (i * sizeof(SceNetAdhocPtpStat)); + + VERBOSE_LOG(SCENET, "PTP Socket Id: %d, LPort: %d, RecvSbCC: %d", buf[i].id, buf[i].lport, buf[i].rcv_sb_cc); // Increment Counter i++; @@ -1621,123 +2789,243 @@ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { * @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT */ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, int dport, int bufsize, int rexmt_int, int rexmt_cnt, int unknown) { - INFO_LOG(SCENET, "sceNetAdhocPtpOpen(%s,%d,%s,%d,%d,%d,%d,%d)", srcmac, sport, dstmac,dport,bufsize, rexmt_int, rexmt_cnt, unknown); + INFO_LOG(SCENET, "sceNetAdhocPtpOpen(%s, %d, %s, %d, %d, %d, %d, %d) at %08x", mac2str((SceNetEtherAddr*)srcmac).c_str(), sport, mac2str((SceNetEtherAddr*)dstmac).c_str(),dport,bufsize, rexmt_int, rexmt_cnt, unknown, currentMIPS->pc); if (!g_Config.bEnableWlan) { return 0; } - SceNetEtherAddr * saddr = (SceNetEtherAddr *)srcmac; - SceNetEtherAddr * daddr = (SceNetEtherAddr *)dstmac; + SceNetEtherAddr* saddr = (SceNetEtherAddr*)srcmac; + SceNetEtherAddr* daddr = (SceNetEtherAddr*)dstmac; + bool isClient = false; // Library is initialized if (netAdhocInited) { + // Some games (ie. DBZ Shin Budokai 2) might be getting the saddr/srcmac content from SaveState and causing problems if current MAC is different :( So we try to fix it here + if (saddr != NULL) { + getLocalMac(saddr); + } // Valid Addresses if (saddr != NULL && isLocalMAC(saddr) && daddr != NULL && !isBroadcastMAC(daddr)) { // Random Port required if (sport == 0) { - // Find unused Port - // while (sport == 0 || _IsPTPPortInUse(sport)) { - // // Generate Port Number - // sport = (uint16_t)_getRandomNumber(65535); - // } + isClient = true; + //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this + sport = -(int)portOffset; } - // Valid Ports - if (!isPTPPortInUse(sport) /*&& dport != 0*/) { - if(PSP_CoreParameter().compat.flags().AdhocHackPhantasyStarOffset) { - //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this - if (sport == 0) sport = -(int)portOffset; - } - // Valid Arguments - if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0) { - // Create Infrastructure Socket - int tcpsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - // Valid Socket produced - if (tcpsocket > 0) { - // Change socket buffer size when necessary - if (getSockBufferSize(tcpsocket, SO_SNDBUF) < bufsize) setSockBufferSize(tcpsocket, SO_SNDBUF, bufsize); - if (getSockBufferSize(tcpsocket, SO_RCVBUF) < bufsize) setSockBufferSize(tcpsocket, SO_RCVBUF, bufsize); + // Valid Arguments + if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0) { + // Create Infrastructure Socket + int tcpsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - // Enable Port Re-use - setsockopt(tcpsocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one)); - - // Binding Information for local Port - sockaddr_in addr; - // addr.sin_len = sizeof(addr); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - if (/*PPSSPP_ID > 1*/isLocalServer) { - getLocalIp(&addr); - } - addr.sin_port = htons(sport + portOffset); - - // Bound Socket to local Port - if (bind(tcpsocket, (sockaddr *)&addr, sizeof(addr)) == 0) { - // Update sport with the port assigned binternal->lport = ntohs(local.sin_port)y bind - socklen_t len = sizeof(addr); - if (getsockname(tcpsocket, (sockaddr *)&addr, &len) == 0) { - sport = ntohs(addr.sin_port) - portOffset; - } - - // Allocate Memory - SceNetAdhocPtpStat * internal = (SceNetAdhocPtpStat *)malloc(sizeof(SceNetAdhocPtpStat)); - - // Allocated Memory - if (internal != NULL) { - // Find Free Translator ID - int i = 0; for (; i < 255; i++) if (ptp[i] == NULL) break; - - // Found Free Translator ID - if (i < 255) { - // Clear Memory - memset(internal, 0, sizeof(SceNetAdhocPtpStat)); - - // Copy Infrastructure Socket ID - internal->id = tcpsocket; - - // Copy Address Information - internal->laddr = *saddr; - internal->paddr = *daddr; - internal->lport = sport; - internal->pport = dport; - - // Set Buffer Size - internal->rcv_sb_cc = bufsize; - - // Link PTP Socket - ptp[i] = internal; - - // Add Port Forward to Router - // sceNetPortOpen("TCP", sport); - - // Return PTP Socket Pointer - return i + 1; - } - - // Free Memory - free(internal); - } - } - - // Close Socket - closesocket(tcpsocket); + // Valid Socket produced + if (tcpsocket > 0) { + // Change socket buffer size to be consistent on all platforms. + int ptpbufsize = std::max(bufsize, PSP_ADHOC_PTP_MSS); + setSockBufferSize(tcpsocket, SO_SNDBUF, ptpbufsize); + setSockBufferSize(tcpsocket, SO_RCVBUF, ptpbufsize*10); + + // Enable KeepAlive + setSockKeepAlive(tcpsocket, true, rexmt_int / 1000000L, rexmt_cnt); + + // Ignore SIGPIPE when supported (ie. BSD/MacOS) + setSockNoSIGPIPE(tcpsocket, 1); + + // Enable Port Re-use + setSockReuseAddrPort(tcpsocket); + + // Apply Default Send Timeout Settings to Socket + setSockTimeout(tcpsocket, SO_SNDTIMEO, rexmt_int); + + // Disable Nagle Algo to send immediately. Or may be we shouldn't disable Nagle since there is PtpFlush function? + if (g_Config.bTCPNoDelay) + setSockNoDelay(tcpsocket, 1); + + // Binding Information for local Port + sockaddr_in addr; + // addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if (isLocalServer) { + getLocalIp(&addr); } + addr.sin_port = htons(sport + portOffset); + + // Bound Socket to local Port + if (bind(tcpsocket, (sockaddr*)&addr, sizeof(addr)) == 0) { + // Update sport with the port assigned internal->lport = ntohs(local.sin_port) + socklen_t len = sizeof(addr); + if (getsockname(tcpsocket, (sockaddr*)&addr, &len) == 0) { + sport = ntohs(addr.sin_port) - portOffset; + } + + // Allocate Memory + AdhocSocket* internal = (AdhocSocket*)malloc(sizeof(AdhocSocket)); + + // Allocated Memory + if (internal != NULL) { + // Find Free Translator ID + int i = 0; + for (; i < MAX_SOCKET; i++) if (adhocSockets[i] == NULL) break; + + // Found Free Translator ID + if (i < MAX_SOCKET) { + // Clear Memory + memset(internal, 0, sizeof(AdhocSocket)); + + // Socket Type + internal->type = SOCK_PTP; + internal->send_timeout = rexmt_int; + internal->retry_count = rexmt_cnt; + + // Copy Infrastructure Socket ID + internal->data.ptp.id = tcpsocket; + + // Copy Address Information + internal->data.ptp.laddr = *saddr; + internal->data.ptp.paddr = *daddr; + internal->data.ptp.lport = sport; + internal->data.ptp.pport = dport; + + // Link PTP Socket + adhocSockets[i] = internal; + + // Add Port Forward to Router. We may not even need to forward this local port, since PtpOpen usually have port 0 (any port) as source port and followed by PtpConnect (which mean acting as Client), right? + //sceNetPortOpen("TCP", sport); + if (!isClient) + UPnP_Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset); + + // Switch to non-blocking for futher usage + changeBlockingMode(tcpsocket, 1); + + // Return PTP Socket Pointer + return i + 1; + } + + // Free Memory + free(internal); + } + } + else { + ERROR_LOG(SCENET, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port)); + auto n = GetI18NCategory("Networking"); + host->NotifyUserMessage(std::string(n->T("Failed to Bind Port")) + " " + std::to_string(sport + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")), 3.0, 0x0000ff); + } + + // Close Socket + closesocket(tcpsocket); + + // Port not available (exclusively in use?) + return ERROR_NET_ADHOC_INVALID_PORT; // ERROR_NET_ADHOC_PORT_IN_USE; // ERROR_NET_ADHOC_PORT_NOT_AVAIL; } - - // Invalid Arguments - return ERROR_NET_ADHOC_INVALID_ARG; } - - // Invalid Ports - return ERROR_NET_ADHOC_INVALID_PORT; + + // Invalid Arguments + return ERROR_NET_ADHOC_INVALID_ARG; } // Invalid Addresses - return ERROR_NET_ADHOC_INVALID_ADDR; + return ERROR_NET_ADHOC_INVALID_ARG; // ERROR_NET_ADHOC_INVALID_ADDR; } return 0; } +int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEtherAddr* addr, u16_le* port) { + // Cast Socket + auto socket = adhocSockets[ptpId - 1]; + auto& ptpsocket = socket->data.ptp; + + // Ignore SIGPIPE when supported (ie. BSD/MacOS) + setSockNoSIGPIPE(newsocket, 1); + + // Enable Port Re-use + setSockReuseAddrPort(newsocket); + + // Enable KeepAlive + setSockKeepAlive(newsocket, true, socket->recv_timeout / 1000000L, socket->retry_count); + + // Disable Nagle Algo to send immediately. Or may be we shouldn't disable Nagle since there is PtpFlush function? + if (g_Config.bTCPNoDelay) + setSockNoDelay(newsocket, 1); + + // Local Address Information + sockaddr_in local; + memset(&local, 0, sizeof(local)); + socklen_t locallen = sizeof(local); + + // Grab Local Address + if (getsockname(newsocket, (sockaddr*)&local, &locallen) == 0) { + // Peer MAC + SceNetEtherAddr mac; + + // Find Peer MAC + if (resolveIP(peeraddr.sin_addr.s_addr, &mac)) { + // Allocate Memory + AdhocSocket* internal = (AdhocSocket*)malloc(sizeof(AdhocSocket)); + + // Allocated Memory + if (internal != NULL) { + // Find Free Translator ID + int i = 0; + for (; i < MAX_SOCKET; i++) if (adhocSockets[i] == NULL) break; + + // Found Free Translator ID + if (i < MAX_SOCKET) { + // Clear Memory + memset(internal, 0, sizeof(AdhocSocket)); + + // Socket Type + internal->type = SOCK_PTP; + + // Copy Socket Descriptor to Structure + internal->data.ptp.id = newsocket; + + // Set Default Buffer Size + setSockBufferSize(newsocket, SO_SNDBUF, PSP_ADHOC_PTP_MSS); + setSockBufferSize(newsocket, SO_RCVBUF, PSP_ADHOC_PTP_MSS*10); + + // Copy Local Address Data to Structure + getLocalMac(&internal->data.ptp.laddr); + internal->data.ptp.lport = ntohs(local.sin_port) - portOffset; + + // Copy Peer Address Data to Structure + internal->data.ptp.paddr = mac; + internal->data.ptp.pport = ntohs(peeraddr.sin_port) - portOffset; + + // Set Connected State + internal->data.ptp.state = ADHOC_PTP_STATE_ESTABLISHED; + + // Return Peer Address Information + *addr = internal->data.ptp.paddr; + if (port != NULL) *port = internal->data.ptp.pport; + + // Link PTP Socket + adhocSockets[i] = internal; + + // Add Port Forward to Router. Or may be doesn't need to be forwarded since local port already accessible from outside if others were able to connect & get accepted at this point, right? + //sceNetPortOpen("TCP", internal->lport); + //g_PortManager.Add(IP_PROTOCOL_TCP, internal->lport + portOffset); + + // Switch to non-blocking for futher usage + changeBlockingMode(newsocket, 1); + + INFO_LOG(SCENET, "sceNetAdhocPtpAccept[%i->%i:%u]: Established (%s:%u)", ptpId, i + 1, internal->data.ptp.lport, inet_ntoa(peeraddr.sin_addr), internal->data.ptp.pport); + + // Return Socket + return i + 1; + } + + // Free Memory + free(internal); + } + } + } + + // Close Socket + closesocket(newsocket); + + ERROR_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Failed (Socket Closed)", ptpId); + return -1; +} /** * Adhoc Emulator PTP Connection Acceptor @@ -1758,169 +3046,86 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int if (Memory::IsValidAddress(peerPortPtr)) { port = (uint16_t *)Memory::GetPointer(peerPortPtr); } - - DEBUG_LOG(SCENET, "sceNetAdhocPtpAccept(%d,%08x,[%08x]=%u,%d,%u) at %08x", id, peerMacAddrPtr, peerPortPtr, port ? *port : -1, timeout, flag, currentMIPS->pc); + if (flag == 0) { // Prevent spamming Debug Log with retries of non-bocking socket + DEBUG_LOG(SCENET, "sceNetAdhocPtpAccept(%d, [%08x]=%s, [%08x]=%u, %d, %u) at %08x", id, peerMacAddrPtr, mac2str(addr).c_str(), peerPortPtr, port ? *port : -1, timeout, flag, currentMIPS->pc); + } else { + VERBOSE_LOG(SCENET, "sceNetAdhocPtpAccept(%d, [%08x]=%s, [%08x]=%u, %d, %u) at %08x", id, peerMacAddrPtr, mac2str(addr).c_str(), peerPortPtr, port ? *port : -1, timeout, flag, currentMIPS->pc); + } if (!g_Config.bEnableWlan) { return 0; } // Library is initialized if (netAdhocInited) { - // Valid Socket - if (id > 0 && id <= 255 && ptp[id - 1] != NULL) { - // Cast Socket - SceNetAdhocPtpStat * socket = ptp[id - 1]; - - // Listener Socket - if (socket->state == ADHOC_PTP_STATE_LISTEN) { - // Valid Arguments - if (addr != NULL /*&& port != NULL*/) { //GTA:VCS seems to use 0 for the portPtr + // Valid Arguments + if (addr != NULL) { //GTA:VCS seems to use 0 for the portPtr + // Valid Socket + if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { + // Cast Socket + auto socket = adhocSockets[id - 1]; + auto& ptpsocket = socket->data.ptp; + + // Listener Socket + if (ptpsocket.state == ADHOC_PTP_STATE_LISTEN) { // Address Information sockaddr_in peeraddr; memset(&peeraddr, 0, sizeof(peeraddr)); socklen_t peeraddrlen = sizeof(peeraddr); - // Local Address Information - sockaddr_in local; - memset(&local, 0, sizeof(local)); - socklen_t locallen = sizeof(local); - - // Grab Nonblocking Flag - uint32_t nbio = getBlockingFlag(socket->id); - // Switch to Nonblocking Behaviour - if (nbio == 0) { - // Overwrite Socket Option - changeBlockingMode(socket->id,1); + int error; + + // Check if listening socket is ready to accept + int newsocket = IsSocketReady(ptpsocket.id, true, false, &error); + if (newsocket > 0) { + // Accept Connection + newsocket = accept(ptpsocket.id, (sockaddr*)&peeraddr, &peeraddrlen); + error = errno; } - - // Accept Connection - int newsocket = accept(socket->id, (sockaddr *)&peeraddr, &peeraddrlen); - - // Blocking Behaviour - if (!flag && newsocket == -1) { - // Get Start Time - uint32_t starttime = (uint32_t)(CoreTiming::GetGlobalTimeUsScaled()); - - // Retry until Timeout hits - while ((timeout == 0 ||((uint32_t)(CoreTiming::GetGlobalTimeUsScaled()) - starttime) < (uint32_t)timeout) && newsocket == -1) { - // Accept Connection - newsocket = accept(socket->id, (sockaddr *)&peeraddr, &peeraddrlen); - - // Wait a bit... - sleep_ms(1); + + if (newsocket == 0 || (newsocket == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || error == ETIMEDOUT))) { + socket->attemptCount++; + if (flag == 0) { + // Simulate blocking behaviour with non-blocking socket + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; + return WaitBlockingAdhocSocket(threadSocketId, PTP_ACCEPT, id, nullptr, nullptr, (flag) ? socket->recv_timeout : timeout, addr, port, "ptp accept"); + } + // Prevent spamming Debug Log with retries of non-bocking socket + else { + VERBOSE_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Socket Error (%i)", id, error); } } - if (newsocket == SOCKET_ERROR) { - int error = errno; - DEBUG_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Socket Error (%i)", id, error); - } - - // Restore Blocking Behaviour - if (nbio == 0) { - // Restore Socket Option - changeBlockingMode(socket->id,0); - } - // Accepted New Connection if (newsocket > 0) { - // Do we need to Change socket buffer size to match the listener buffer size? - - // Enable Port Re-use - setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one)); - - // Grab Local Address - if (getsockname(newsocket, (sockaddr *)&local, &locallen) == 0) { - // Peer MAC - SceNetEtherAddr mac; - - // Find Peer MAC - if (resolveIP(peeraddr.sin_addr.s_addr, &mac)) { - // Allocate Memory - SceNetAdhocPtpStat * internal = (SceNetAdhocPtpStat *)malloc(sizeof(SceNetAdhocPtpStat)); - - // Allocated Memory - if (internal != NULL) { - // Find Free Translator ID - int i = 0; for (; i < 255; i++) if (ptp[i] == NULL) break; - - // Found Free Translator ID - if (i < 255) { - // Clear Memory - memset(internal, 0, sizeof(SceNetAdhocPtpStat)); - - // Copy Socket Descriptor to Structure - internal->id = newsocket; - - // Set Buffer Size - if (getSockBufferSize(newsocket, SO_RCVBUF) < socket->rcv_sb_cc) setSockBufferSize(newsocket, SO_RCVBUF, socket->rcv_sb_cc); - if (getSockBufferSize(newsocket, SO_SNDBUF) < socket->snd_sb_cc) setSockBufferSize(newsocket, SO_SNDBUF, socket->snd_sb_cc); - internal->rcv_sb_cc = socket->rcv_sb_cc; - internal->snd_sb_cc = socket->snd_sb_cc; - - // Copy Local Address Data to Structure - getLocalMac(&internal->laddr); - internal->lport = ntohs(local.sin_port) - portOffset; - - // Copy Peer Address Data to Structure - internal->paddr = mac; - internal->pport = ntohs(peeraddr.sin_port) - portOffset; - - // Set Connected State - internal->state = ADHOC_PTP_STATE_ESTABLISHED; - - // Return Peer Address Information - *addr = internal->paddr; - if (port != NULL) *port = internal->pport; - - // Link PTP Socket - ptp[i] = internal; - - // Add Port Forward to Router - // sceNetPortOpen("TCP", internal->lport); - - uint8_t * pip = (uint8_t *)&peeraddr.sin_addr.s_addr; - INFO_LOG(SCENET, "sceNetAdhocPtpAccept[%i->%i:%u]: Established (%u.%u.%u.%u:%u)", id, i+1, internal->lport, pip[0], pip[1], pip[2], pip[3], internal->pport); - - // Return Socket - return i + 1; - } - - // Free Memory - free(internal); - } - } - } - - // Close Socket - closesocket(newsocket); - - ERROR_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Failed (Socket Closed)", id); + socket->attemptCount++; + int newid = AcceptPtpSocket(id, newsocket, peeraddr, addr, port); + if (newid >= 0) + return newid; } - + // Action would block - if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; - + if (flag) + return ERROR_NET_ADHOC_WOULD_BLOCK; + // Timeout return ERROR_NET_ADHOC_TIMEOUT; } - - // Invalid Arguments - return ERROR_NET_ADHOC_INVALID_ARG; + + // Client Socket + return ERROR_NET_ADHOC_NOT_LISTENED; } - - // Client Socket - return ERROR_NET_ADHOC_NOT_LISTENED; + + // Invalid Socket + return ERROR_NET_ADHOC_INVALID_SOCKET_ID; } - - // Invalid Socket - return ERROR_NET_ADHOC_INVALID_SOCKET_ID; + + // Invalid Arguments + return ERROR_NET_ADHOC_INVALID_ARG; } // Library is uninitialized return ERROR_NET_ADHOC_NOT_INITIALIZED; } - /** * Adhoc Emulator PTP Connection Opener * @param id Socket File Descriptor @@ -1929,7 +3134,7 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_CONNECTION_REFUSED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_OPENED, ADHOC_THREAD_ABORTED, NET_INTERNAL */ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) { - INFO_LOG(SCENET, "sceNetAdhocPtpConnect(%i, %i, %08x) at %08x", id, timeout, flag, currentMIPS->pc); + INFO_LOG(SCENET, "sceNetAdhocPtpConnect(%i, %i, %i) at %08x", id, timeout, flag, currentMIPS->pc); if (!g_Config.bEnableWlan) { return 0; } @@ -1938,12 +3143,17 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) { if (netAdhocInited) { // Valid Socket - if (id > 0 && id <= 255 && ptp[id - 1] != NULL) { + if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { // Cast Socket - SceNetAdhocPtpStat * socket = ptp[id - 1]; - + auto socket = adhocSockets[id - 1]; + auto& ptpsocket = socket->data.ptp; + + // Phantasy Star Portable 2 will try to reconnect even when previous connect already success, so we should return success too if it's already connected + if (ptpsocket.state == ADHOC_PTP_STATE_ESTABLISHED) + return 0; + // Valid Client Socket - if (socket->state == 0) { + if (ptpsocket.state == ADHOC_PTP_STATE_CLOSED) { // Target Address sockaddr_in sin; memset(&sin, 0, sizeof(sin)); @@ -1951,84 +3161,61 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) { // Setup Target Address // sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; - sin.sin_port = htons(socket->pport + portOffset); + sin.sin_port = htons(ptpsocket.pport + portOffset); // Grab Peer IP - if (resolveMAC(&socket->paddr, (uint32_t *)&sin.sin_addr.s_addr)) { + if (resolveMAC(&ptpsocket.paddr, (uint32_t *)&sin.sin_addr.s_addr)) { + // Some games (ie. PSP2) might try to talk to it's self, not sure if they talked through WAN or LAN when using public Adhoc Server tho + sin.sin_port = htons(ptpsocket.pport + ((isOriPort && !isPrivateIP(sin.sin_addr.s_addr)) ? 0 : portOffset)); + // Grab Nonblocking Flag - uint32_t nbio = getBlockingFlag(socket->id); - // Switch to Nonblocking Behaviour - if (nbio == 0 && !PSP_CoreParameter().compat.flags().AdhocHackDisableNBSwitch) { - // Overwrite Socket Option - changeBlockingMode(socket->id, 1); - } - - // Connect Socket to Peer (Nonblocking) - int connectresult = connect(socket->id, (sockaddr *)&sin, sizeof(sin)); + //uint32_t nbio = getNonBlockingFlag(socket->id); + + // Connect Socket to Peer + // NOTE: Based on what i read at stackoverflow, The First Non-blocking POSIX connect will always returns EAGAIN/EWOULDBLOCK because it returns without waiting for ACK/handshake, But GvG Next Plus is treating non-blocking PtpConnect just like blocking connect, May be on a real PSP the first non-blocking sceNetAdhocPtpConnect can be successfull? + // TODO: Keep track number of Connect attempts so we can simulate blocking on first attempt (getNonBlockingFlag can't be used to get non-blocking flag on Windows thus can't be used to keep track) + int connectresult = connect(ptpsocket.id, (sockaddr *)&sin, sizeof(sin)); // Grab Error Code int errorcode = errno; if (connectresult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "sceNetAdhocPtpConnect[%i]: Socket Error (%i)", id, errorcode); + ERROR_LOG(SCENET, "sceNetAdhocPtpConnect[%i]: Socket Error (%i) to %s:%u", id, errorcode, inet_ntoa(sin.sin_addr), ptpsocket.pport); } - - // Restore Blocking Behaviour - if (nbio == 0) { - // Restore Socket Option - changeBlockingMode(socket->id,0); - } - + // Instant Connection (Lucky!) - if (connectresult == 0 || (connectresult == -1 && (errorcode == EISCONN /*|| errorcode == EALREADY)*/))) { + if (connectresult != SOCKET_ERROR || errorcode == EISCONN) { + socket->attemptCount++; // Set Connected State - socket->state = ADHOC_PTP_STATE_ESTABLISHED; + ptpsocket.state = ADHOC_PTP_STATE_ESTABLISHED; - INFO_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Already Connected", id, socket->lport); + INFO_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Already Connected to %s:%u", id, ptpsocket.lport, inet_ntoa(sin.sin_addr), ptpsocket.pport); // Success return 0; } // Connection in Progress - else if (connectresult == -1 && connectInProgress(errorcode)) { - // Nonblocking Mode - if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; - + else if (connectresult == SOCKET_ERROR && connectInProgress(errorcode)) { + socket->attemptCount++; + // Nonblocking Mode. First attempt need to be blocking for GvG Next Plus to work, even though it used non-blocking flag but only try to connect once per socket, which mean treating it just like blocking socket instead of non-blocking :( + if (flag && socket->attemptCount > 1) { + //if (errorcode == EALREADY) return ERROR_NET_ADHOC_BUSY; + return ERROR_NET_ADHOC_WOULD_BLOCK; + } // Blocking Mode else { - // Grab Connection Start Time - uint32_t starttime = (uint32_t)(CoreTiming::GetGlobalTimeUsScaled()); - - // Peer Information (for Connection-Polling) - sockaddr_in peer; - memset(&peer, 0, sizeof(peer)); - socklen_t peerlen = sizeof(peer); - // Wait for Connection - while ((timeout == 0 || ( (uint32_t)(CoreTiming::GetGlobalTimeUsScaled()) - starttime) < (uint32_t)timeout) && getpeername(socket->id, (sockaddr *)&peer, &peerlen) != 0) { - // Wait 1ms - sleep_ms(1); - } - - // Connected in Time - if (sin.sin_addr.s_addr == peer.sin_addr.s_addr/* && sin.sin_port == peer.sin_port*/) { - // Set Connected State - socket->state = ADHOC_PTP_STATE_ESTABLISHED; - - uint8_t * pip = (uint8_t *)&peer.sin_addr.s_addr; - INFO_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Established (%u.%u.%u.%u:%u)", id, socket->lport, pip[0], pip[1], pip[2], pip[3], socket->pport); - - // Success - return 0; - } - - // Timeout occured - return ERROR_NET_ADHOC_TIMEOUT; + // Simulate blocking behaviour with non-blocking socket + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; + return WaitBlockingAdhocSocket(threadSocketId, PTP_CONNECT, id, nullptr, nullptr, (flag)? socket->send_timeout: timeout, nullptr, nullptr, "ptp connect"); } } } // Peer not found - return ERROR_NET_ADHOC_CONNECTION_REFUSED; + if (flag) + return ERROR_NET_ADHOC_WOULD_BLOCK; + + return ERROR_NET_ADHOC_CONNECTION_REFUSED; // ERROR_NET_ADHOC_TIMEOUT; } // Not a valid Client Socket @@ -2043,6 +3230,44 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) { return ERROR_NET_ADHOC_NOT_INITIALIZED; } +int NetAdhocPtp_Close(int id, int unknown) { + // Library is initialized + if (netAdhocInited) { + // Valid Arguments + if (id > 0 && id <= MAX_SOCKET) { + // Cast Socket + auto socket = adhocSockets[id - 1]; + + // Valid Socket + if (socket != NULL && socket->type == SOCK_PTP) { + // Close Connection + shutdown(socket->data.ptp.id, SD_BOTH); + closesocket(socket->data.ptp.id); + + // Remove Port Forward from Router + //sceNetPortClose("TCP", socket->lport); + //g_PortManager.Remove(IP_PROTOCOL_TCP, isOriPort ? socket->lport : socket->lport + portOffset); // Let's not remove mapping in real-time as it could cause lags/disconnection when joining a room with slow routers + + // Free Memory + free(socket); + + // Free Reference + adhocSockets[id - 1] = NULL; + + // Success + return 0; + } + + return ERROR_NET_ADHOC_INVALID_SOCKET_ID; + } + + // Invalid Argument + return ERROR_NET_ADHOC_INVALID_ARG; + } + + // Library is uninitialized + return ERROR_NET_ADHOC_NOT_INITIALIZED; +} /** * Adhoc Emulator PTP Socket Closer @@ -2052,38 +3277,11 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) { */ static int sceNetAdhocPtpClose(int id, int unknown) { INFO_LOG(SCENET,"sceNetAdhocPtpClose(%d,%d) at %08x",id,unknown,currentMIPS->pc); - if (!g_Config.bEnableWlan) { + /*if (!g_Config.bEnableWlan) { return 0; - } - // Library is initialized - if (netAdhocInited) { - // Valid Arguments & Atleast one Socket - if (id > 0 && id <= 255 && ptp[id - 1] != NULL) { - // Cast Socket - SceNetAdhocPtpStat * socket = ptp[id - 1]; - - // Close Connection - closesocket(socket->id); - - // Remove Port Forward from Router - // sceNetPortClose("TCP", socket->lport); - - // Free Memory - free(socket); - - // Free Reference - ptp[id - 1] = NULL; - - // Success - return 0; - } - - // Invalid Argument - return ERROR_NET_ADHOC_INVALID_SOCKET_ID; - } + }*/ - // Library is uninitialized - return ERROR_NET_ADHOC_NOT_INITIALIZED; + return NetAdhocPtp_Close(id, unknown); } @@ -2099,121 +3297,144 @@ static int sceNetAdhocPtpClose(int id, int unknown) { * @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT, ADHOC_SOCKET_ID_NOT_AVAIL, ADHOC_PORT_NOT_AVAIL, ADHOC_PORT_IN_USE, NET_NO_SPACE */ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int rexmt_int, int rexmt_cnt, int backlog, int unk) { - INFO_LOG(SCENET, "sceNetAdhocPtpListen(%s,%d,%d,%d,%d,%d,%d)",srcmac,sport,bufsize,rexmt_int,rexmt_cnt,backlog,unk); + INFO_LOG(SCENET, "sceNetAdhocPtpListen(%s, %d, %d, %d, %d, %d, %d) at %08x", mac2str((SceNetEtherAddr*)srcmac).c_str(), sport,bufsize,rexmt_int,rexmt_cnt,backlog,unk, currentMIPS->pc); if (!g_Config.bEnableWlan) { return 0; } // Library is initialized SceNetEtherAddr * saddr = (SceNetEtherAddr *)srcmac; if (netAdhocInited) { + // Some games (ie. DBZ Shin Budokai 2) might be getting the saddr/srcmac content from SaveState and causing problems :( So we try to fix it here + if (saddr != NULL) { + getLocalMac(saddr); + } // Valid Address - if (saddr != NULL && isLocalMAC(saddr)) - { + if (saddr != NULL && isLocalMAC(saddr)) { // Random Port required if (sport == 0) { - // Find unused Port - // while (sport == 0 || __IsPTPPortInUse(sport)) - // { - // // Generate Port Number - // sport = (uint16_t)_getRandomNumber(65535); - // } + //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this + sport = -(int)portOffset; } - // Valid Ports - if (!isPTPPortInUse(sport)) { - // Valid Arguments - if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0 && backlog > 0) - { - // Create Infrastructure Socket - int tcpsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - // Valid Socket produced - if (tcpsocket > 0) { - // Change socket buffer size when necessary - if (getSockBufferSize(tcpsocket, SO_SNDBUF) < bufsize) setSockBufferSize(tcpsocket, SO_SNDBUF, bufsize); - if (getSockBufferSize(tcpsocket, SO_RCVBUF) < bufsize) setSockBufferSize(tcpsocket, SO_RCVBUF, bufsize); + // Valid Arguments + if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0 && backlog > 0) + { + // Create Infrastructure Socket + int tcpsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - // Enable Port Re-use - setsockopt(tcpsocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one)); - - // Binding Information for local Port - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - if (/*PPSSPP_ID > 1*/isLocalServer) { - getLocalIp(&addr); + // Valid Socket produced + if (tcpsocket > 0) { + // Change socket buffer size to be consistent on all platforms. + int ptpbufsize = std::max(bufsize, PSP_ADHOC_PTP_MSS); + setSockBufferSize(tcpsocket, SO_SNDBUF, ptpbufsize); + setSockBufferSize(tcpsocket, SO_RCVBUF, ptpbufsize*10); + + // Enable KeepAlive + setSockKeepAlive(tcpsocket, true, rexmt_int / 1000000L, rexmt_cnt); + + // Ignore SIGPIPE when supported (ie. BSD/MacOS) + setSockNoSIGPIPE(tcpsocket, 1); + + // Enable Port Re-use + setSockReuseAddrPort(tcpsocket); + + // Apply Default Receive Timeout Settings to Socket + setSockTimeout(tcpsocket, SO_RCVTIMEO, rexmt_int); + + // Disable Nagle Algo to send immediately. Or may be we shouldn't disable Nagle since there is PtpFlush function? + if (g_Config.bTCPNoDelay) + setSockNoDelay(tcpsocket, 1); + + // Binding Information for local Port + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if (isLocalServer) { + getLocalIp(&addr); + } + addr.sin_port = htons(sport + portOffset); + + int iResult = 0; + // Bound Socket to local Port + if ((iResult = bind(tcpsocket, (sockaddr*)&addr, sizeof(addr))) == 0) { + // Update sport with the port assigned internal->lport = ntohs(local.sin_port) + socklen_t len = sizeof(addr); + if (getsockname(tcpsocket, (sockaddr*)&addr, &len) == 0) { + sport = ntohs(addr.sin_port) - portOffset; } - addr.sin_port = htons(sport + portOffset); - - int iResult = 0; - // Bound Socket to local Port - if ((iResult = bind(tcpsocket, (sockaddr *)&addr, sizeof(addr))) == 0) { - // Switch into Listening Mode - if ((iResult = listen(tcpsocket, backlog)) == 0) { - // Allocate Memory - SceNetAdhocPtpStat * internal = (SceNetAdhocPtpStat *)malloc(sizeof(SceNetAdhocPtpStat)); - - // Allocated Memory - if (internal != NULL) { - // Find Free Translator ID - int i = 0; for (; i < 255; i++) if (ptp[i] == NULL) break; - - // Found Free Translator ID - if (i < 255) { - // Clear Memory - memset(internal, 0, sizeof(SceNetAdhocPtpStat)); - - // Copy Infrastructure Socket ID - internal->id = tcpsocket; - - // Copy Address Information - internal->laddr = *saddr; - internal->lport = sport; - - // Flag Socket as Listener - internal->state = ADHOC_PTP_STATE_LISTEN; - - // Set Buffer Size - internal->rcv_sb_cc = bufsize; - - // Link PTP Socket - ptp[i] = internal; - - // Add Port Forward to Router - // sceNetPortOpen("TCP", sport); - - // Return PTP Socket Pointer - return i + 1; - } - - // Free Memory - free(internal); + // Switch into Listening Mode + if ((iResult = listen(tcpsocket, backlog)) == 0) { + // Allocate Memory + AdhocSocket* internal = (AdhocSocket*)malloc(sizeof(AdhocSocket)); + + // Allocated Memory + if (internal != NULL) { + // Find Free Translator ID + int i = 0; + for (; i < MAX_SOCKET; i++) if (adhocSockets[i] == NULL) break; + + // Found Free Translator ID + if (i < MAX_SOCKET) { + // Clear Memory + memset(internal, 0, sizeof(AdhocSocket)); + + // Socket Type + internal->type = SOCK_PTP; + internal->recv_timeout = rexmt_int; + internal->retry_count = rexmt_cnt; + + // Copy Infrastructure Socket ID + internal->data.ptp.id = tcpsocket; + + // Copy Address Information + internal->data.ptp.laddr = *saddr; + internal->data.ptp.lport = sport; + + // Flag Socket as Listener + internal->data.ptp.state = ADHOC_PTP_STATE_LISTEN; + + // Link PTP Socket + adhocSockets[i] = internal; + + // Add Port Forward to Router + //sceNetPortOpen("TCP", sport); + UPnP_Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset); + + // Switch to non-blocking for futher usage + changeBlockingMode(tcpsocket, 1); + + // Return PTP Socket Pointer + return i + 1; } + + // Free Memory + free(internal); } } - - if (iResult == SOCKET_ERROR) { - int error = errno; - ERROR_LOG(SCENET, "sceNetAdhocPtpListen[%i]: Socket Error (%i)", sport, error); - } - - // Close Socket - closesocket(tcpsocket); - - // Port not available (exclusively in use?) - return ERROR_NET_ADHOC_PORT_NOT_AVAIL; } - - // Socket not available - return ERROR_NET_ADHOC_SOCKET_ID_NOT_AVAIL; + else { + auto n = GetI18NCategory("Networking"); + host->NotifyUserMessage(std::string(n->T("Failed to Bind Port")) + " " + std::to_string(sport + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")), 3.0, 0x0000ff); + } + + if (iResult == SOCKET_ERROR) { + int error = errno; + ERROR_LOG(SCENET, "sceNetAdhocPtpListen[%i]: Socket Error (%i)", sport, error); + } + + // Close Socket + closesocket(tcpsocket); + + // Port not available (exclusively in use?) + return ERROR_NET_ADHOC_INVALID_PORT; //ERROR_NET_ADHOC_PORT_IN_USE; // ERROR_NET_ADHOC_PORT_NOT_AVAIL; } - - // Invalid Arguments - return ERROR_NET_ADHOC_INVALID_ARG; + + // Socket not available + return ERROR_NET_ADHOC_SOCKET_ID_NOT_AVAIL; } - - // Invalid Ports - return ERROR_NET_ADHOC_PORT_IN_USE; + + // Invalid Arguments + return ERROR_NET_ADHOC_INVALID_ARG; } // Invalid Addresses @@ -2243,28 +3464,28 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou // Library is initialized if (netAdhocInited) { // Valid Socket - if (id > 0 && id <= 255 && ptp[id - 1] != NULL) { + if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { // Cast Socket - SceNetAdhocPtpStat * socket = ptp[id - 1]; + auto socket = adhocSockets[id - 1]; + auto& ptpsocket = socket->data.ptp; // Connected Socket - if (socket->state == ADHOC_PTP_STATE_ESTABLISHED) { + if (ptpsocket.state == ADHOC_PTP_STATE_ESTABLISHED) { // Valid Arguments if (data != NULL && len != NULL && *len > 0) { // Schedule Timeout Removal - if (flag) timeout = 0; + //if (flag) timeout = 0; // JPCSP seems to always Send PTP as blocking, also a possibility to send to multiple destination? // Apply Send Timeout Settings to Socket - setsockopt(socket->id, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout)); + if (timeout > 0) + setSockTimeout(ptpsocket.id, SO_SNDTIMEO, timeout); // Acquire Network Lock // _acquireNetworkLock(); // Send Data - changeBlockingMode(socket->id, flag); - int sent = send(socket->id, data, *len, 0); + int sent = send(ptpsocket.id, data, *len, MSG_NOSIGNAL); int error = errno; - changeBlockingMode(socket->id, 0); // Free Network Lock // _freeNetworkLock(); @@ -2274,24 +3495,25 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou // Save Length *len = sent; - uint8_t * smac = (uint8_t *)&socket->paddr; - INFO_LOG(SCENET, "sceNetAdhocPtpSend[%i:%u]: Sent %u bytes to %02X:%02X:%02X:%02X:%02X:%02X:%u", id, socket->lport, sent, smac[0], smac[1], smac[2], smac[3], smac[4], smac[5], socket->pport); + DEBUG_LOG(SCENET, "sceNetAdhocPtpSend[%i:%u]: Sent %u bytes to %s:%u\n", id, ptpsocket.lport, sent, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); // Return Success return 0; } // Non-Critical Error - else if (sent == -1 && error == EAGAIN) { - // Blocking Situation - if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; + else if (sent == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || error == ETIMEDOUT)) { + // Non-Blocking + if (flag) + return ERROR_NET_ADHOC_WOULD_BLOCK; - // Timeout - return ERROR_NET_ADHOC_TIMEOUT; + // Simulate blocking behaviour with non-blocking socket + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; + return WaitBlockingAdhocSocket(threadSocketId, PTP_SEND, id, (void*)data, len, timeout, nullptr, nullptr, "ptp send"); } // Change Socket State - socket->state = ADHOC_PTP_STATE_CLOSED; + ptpsocket.state = ADHOC_PTP_STATE_CLOSED; // Disconnected return ERROR_NET_ADHOC_DISCONNECTED; @@ -2313,7 +3535,6 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou return ERROR_NET_ADHOC_NOT_INITIALIZED; } - /** * Adhoc Emulator PTP Receiver * @param id Socket File Descriptor @@ -2324,7 +3545,7 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_DISCONNECTED, NET_INTERNAL */ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeout, int flag) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv(%d,%08x,%08x,%d,%d)", id, dataAddr, dataSizeAddr, timeout, flag); + DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv(%d,%08x,%08x,%d,%d) at %08x", id, dataAddr, dataSizeAddr, timeout, flag, currentMIPS->pc); if (!g_Config.bEnableWlan) { return 0; } @@ -2332,71 +3553,114 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou int * len = (int *)Memory::GetPointer(dataSizeAddr); // Library is initialized if (netAdhocInited) { - // Valid Socket - if (id > 0 && id <= 255 && ptp[id - 1] != NULL && ptp[id - 1]->state == ADHOC_PTP_STATE_ESTABLISHED) { - // Cast Socket - SceNetAdhocPtpStat * socket = ptp[id - 1]; - - // Valid Arguments - if (buf != NULL && len != NULL && *len > 0) { - // Schedule Timeout Removal - if (flag) timeout = 0; - - // Apply Send Timeout Settings to Socket - setsockopt(socket->id, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)); - - // Acquire Network Lock - // _acquireNetworkLock(); - - // Receive Data - changeBlockingMode(socket->id, flag); - int received = recv(socket->id, (char *)buf, *len, 0); - int error = errno; - changeBlockingMode(socket->id, 0); - - // Free Network Lock - // _freeNetworkLock(); - - // Received Data - if (received > 0) { - // Save Length - *len = received; + // Valid Arguments + if (buf != NULL && len != NULL && *len > 0) { + // Valid Socket + if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { + // Cast Socket + auto socket = adhocSockets[id - 1]; + auto& ptpsocket = socket->data.ptp; - uint8_t * smac = (uint8_t *)&socket->paddr; - INFO_LOG(SCENET, "sceNetAdhocPtpRecv[%i:%u]: Received %u bytes from %02X:%02X:%02X:%02X:%02X:%02X:%u", id, socket->lport, received, smac[0], smac[1], smac[2], smac[3], smac[4], smac[5], socket->pport); - - // Return Success - return 0; + if (ptpsocket.state == ADHOC_PTP_STATE_ESTABLISHED) { + // Schedule Timeout Removal + //if (flag) timeout = 0; + + // Apply Receive Timeout Settings to Socket. Let's not wait forever (0 = indefinitely) + if (timeout > 0) + setSockTimeout(ptpsocket.id, SO_RCVTIMEO, timeout); + + // Acquire Network Lock + // _acquireNetworkLock(); + + // TODO: Use a different thread (similar to sceIo) for recvfrom, recv & accept to prevent blocking-socket from blocking emulation + int received = 0; + int error = 0; + + // Receive Data. POSIX: May received 0 bytes when the remote peer already closed the connection. + received = recv(ptpsocket.id, (char*)buf, *len, MSG_NOSIGNAL); + error = errno; + + if (received == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK)) { + if (flag == 0) { + // Simulate blocking behaviour with non-blocking socket + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; + return WaitBlockingAdhocSocket(threadSocketId, PTP_RECV, id, buf, len, timeout, nullptr, nullptr, "ptp recv"); + } + + VERBOSE_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPtpRecv[%i:%u] [size=%i]", error, id, ptpsocket.lport, *len); + } + + // Free Network Lock + // _freeNetworkLock(); + + // Received Data + if (received > 0) { + // Save Length + *len = received; + + // Update last recv timestamp, may cause disconnection not detected properly tho + peerlock.lock(); + auto peer = findFriend(&ptpsocket.paddr); + if (peer != NULL) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + peerlock.unlock(); + + DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i:%u]: Received %u bytes from %s:%u\n", id, ptpsocket.lport, received, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); + + // Return Success + return 0; + } + + // Non-Critical Error + else if (received == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || error == ETIMEDOUT)) { + // Blocking Situation + if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; + + // Timeout + return hleLogError(SCENET, ERROR_NET_ADHOC_TIMEOUT, "ptp recv timeout"); + } + DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i:%u]: Result:%i (Error:%i)", id, ptpsocket.lport, received, error); + + // Change Socket State + ptpsocket.state = ADHOC_PTP_STATE_CLOSED; + + // Disconnected + return hleLogError(SCENET, ERROR_NET_ADHOC_DISCONNECTED, "ptp recv disconnected"); } - - // Non-Critical Error - else if (received == -1 && error == EAGAIN) { - // Blocking Situation - if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; - - // Timeout - return ERROR_NET_ADHOC_TIMEOUT; - } - - // Change Socket State - socket->state = ADHOC_PTP_STATE_CLOSED; - - // Disconnected - return ERROR_NET_ADHOC_DISCONNECTED; + + return ERROR_NET_ADHOC_NOT_CONNECTED; } - - // Invalid Arguments - return ERROR_NET_ADHOC_INVALID_ARG; + + // Invalid Socket + return ERROR_NET_ADHOC_INVALID_SOCKET_ID; } - - // Invalid Socket - return ERROR_NET_ADHOC_INVALID_SOCKET_ID; + + // Invalid Arguments + return ERROR_NET_ADHOC_INVALID_ARG; } // Library is uninitialized return ERROR_NET_ADHOC_NOT_INITIALIZED; } +int FlushPtpSocket(int socketId) { + // Get original Nagle algo value + int n = getSockNoDelay(socketId); + + // Disable Nagle Algo to send immediately + setSockNoDelay(socketId, 1); + + // Send Empty Data just to trigger Nagle on/off effect to flush the send buffer, Do we need to trigger this at all or is it automatically flushed? + //changeBlockingMode(socket->id, nonblock); + int ret = send(socketId, nullptr, 0, MSG_NOSIGNAL); + if (ret == SOCKET_ERROR) ret = errno; + //changeBlockingMode(socket->id, 1); + + // Restore/Enable Nagle Algo + setSockNoDelay(socketId, n); + + return ret; +} + /** * Adhoc Emulator PTP Flusher * @param id Socket File Descriptor @@ -2413,8 +3677,31 @@ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { // Library initialized if (netAdhocInited) { // Valid Socket - if (id > 0 && id <= 255 && ptp[id - 1] != NULL) { - // Dummy Result + if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { + // Cast Socket + auto socket = adhocSockets[id - 1]; + auto& ptpsocket = socket->data.ptp; + + // Connected Socket + if (ptpsocket.state == ADHOC_PTP_STATE_ESTABLISHED) { + // There are two ways to flush, you can either set TCP_NODELAY to 1 or TCP_CORK to 0. + // Apply Send Timeout Settings to Socket + setSockTimeout(ptpsocket.id, SO_SNDTIMEO, timeout); + + int error = FlushPtpSocket(ptpsocket.id); + + if (error == EAGAIN || error == EWOULDBLOCK || error == ETIMEDOUT) { + // Non-Blocking + if (nonblock) + return ERROR_NET_ADHOC_WOULD_BLOCK; + + // Simulate blocking behaviour with non-blocking socket + u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; + return WaitBlockingAdhocSocket(threadSocketId, PTP_FLUSH, id, nullptr, nullptr, timeout, nullptr, nullptr, "ptp flush"); + } + } + + // Dummy Result, Always success? return 0; } @@ -2425,57 +3712,213 @@ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { return ERROR_NET_ADHOC_NOT_INITIALIZED; } -static int sceNetAdhocGameModeCreateMaster(u32 data, int size) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateMaster(%08x, %i) at %08x", data, size, currentMIPS->pc); - return -1; +/** +* Create own game object type data. +* +* @param dataAddr - A pointer to the game object data. +* @param size - Size of the game data. +* +* @return 0 on success, < 0 on error. +*/ +static int sceNetAdhocGameModeCreateMaster(u32 dataAddr, int size) { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeCreateMaster(%08x, %i) at %08x", dataAddr, size, currentMIPS->pc); + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + + if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) + return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); + + if (!netAdhocGameModeEntered) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); + + if (size < 0 || !Memory::IsValidAddress(dataAddr)) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + + SceNetEtherAddr localMac; + getLocalMac(&localMac); + u8* data = (u8*)malloc(size); + if (data) { + Memory::Memcpy(data, dataAddr, size); + gameModeSocket = sceNetAdhocPdpCreate((const char*)&localMac, ADHOC_GAMEMODE_PORT, GAMEMODE_BUFFER_SIZE, 0); + masterGameModeArea = { 0, size, dataAddr, CoreTiming::GetGlobalTimeUsScaled(), 1, localMac, data }; + StartGameModeScheduler(); + } + + return 0; // returned an id just like CreateReplica? always return 0? } -static int sceNetAdhocGameModeCreateReplica(const char *mac, u32 data, int size) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateReplica(%s, %08x, %i) at %08x", mac, data, size, currentMIPS->pc); - return -1; +/** +* Create peer game object type data. +* +* @param mac - The mac address of the peer. +* @param dataAddr - A pointer to the game object data. +* @param size - Size of the game data. +* +* @return The id of the replica on success, < 0 on error. +*/ +static int sceNetAdhocGameModeCreateReplica(const char *mac, u32 dataAddr, int size) { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeCreateReplica(%s, %08x, %i) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), dataAddr, size, currentMIPS->pc); + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + + if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) + return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); + + if (!netAdhocGameModeEntered) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); + + if (mac == nullptr || size < 0 || !Memory::IsValidAddress(dataAddr)) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + + int maxid = 0; + auto it = std::find_if(replicaGameModeAreas.begin(), replicaGameModeAreas.end(), + [mac, &maxid](GameModeArea const& e) { + if (e.id > maxid) maxid = e.id; + return IsMatch(e.mac, mac); + }); + // MAC address already existed! + if (it != replicaGameModeAreas.end()) { + WARN_LOG(SCENET, "sceNetAdhocGameModeCreateReplica - [%s] is already existed (id: %d)", mac2str((SceNetEtherAddr*)mac).c_str(), it->id); + return it->id; + } + + int ret = 0; + u8* data = (u8*)malloc(size); + if (data) { + Memory::Memcpy(data, dataAddr, size); + //int sock = sceNetAdhocPdpCreate(mac, ADHOC_GAMEMODE_PORT, GAMEMODE_BUFFER_SIZE, 0); + GameModeArea gma = { maxid + 1, size, dataAddr, CoreTiming::GetGlobalTimeUsScaled(), 0, *(SceNetEtherAddr*)mac, data }; + replicaGameModeAreas.push_back(gma); + ret = gma.id; + } + return hleLogSuccessInfoI(SCENET, ret, "success"); // valid id for replica started from 1? } static int sceNetAdhocGameModeUpdateMaster() { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateMaster()"); - return -1; -} + DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocGameModeUpdateMaster()"); + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); -static int sceNetAdhocGameModeDeleteMaster() { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteMaster()"); - return -1; -} + if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) + return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); -static int sceNetAdhocGameModeUpdateReplica(int id, u32 infoAddr) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateReplica(%i, %08x)", id, infoAddr); - return -1; -} + if (!netAdhocGameModeEntered) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); -static int sceNetAdhocGameModeDeleteReplica(int id) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteReplica(%i)", id); - return -1; -} - -int sceNetAdhocGetSocketAlert(int id, u32 flagPtr) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGetSocketAlert(%i, %08x)", id, flagPtr); - - // Dummy Value - if (Memory::IsValidAddress(flagPtr)) { - s32_le * flag = (s32_le*)Memory::GetPointer(flagPtr); - *flag = 0; + if (masterGameModeArea.data) { + Memory::Memcpy(masterGameModeArea.data, masterGameModeArea.addr, masterGameModeArea.size); + masterGameModeArea.dataUpdated = 1; + masterGameModeArea.updateTimestamp = CoreTiming::GetGlobalTimeUsScaled(); } - // Dummy Result return 0; } -int sceNetAdhocMatchingStop(int matchingId) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStop(%i) at %08x", matchingId, currentMIPS->pc); - //if (!g_Config.bEnableWlan) - // return -1; +static int sceNetAdhocGameModeDeleteMaster() { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeDeleteMaster()"); + if (isZeroMAC(&masterGameModeArea.mac)) + return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); - SceNetAdhocMatchingContext * item = findMatchingContext(matchingId); + if (masterGameModeArea.data) { + free(masterGameModeArea.data); + } + //sceNetAdhocPdpDelete(masterGameModeArea.socket, 0); + masterGameModeArea = { 0 }; + + if (replicaGameModeAreas.size() <= 0) { + sceNetAdhocPdpDelete(gameModeSocket, 0); + gameModeSocket = (int)INVALID_SOCKET; + } + + return 0; +} + +static int sceNetAdhocGameModeUpdateReplica(int id, u32 infoAddr) { + DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocGameModeUpdateReplica(%i, %08x)", id, infoAddr); + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + + if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) + return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); + + if (!netAdhocGameModeEntered) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); + + auto it = std::find_if(replicaGameModeAreas.begin(), replicaGameModeAreas.end(), + [id](GameModeArea const& e) { + return e.id == id; + }); + + if (it == replicaGameModeAreas.end()) + return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); + + for (auto gma : replicaGameModeAreas) { + if (gma.id == id) { + if (Memory::IsValidAddress(infoAddr)) { + GameModeUpdateInfo* gmuinfo = (GameModeUpdateInfo*)Memory::GetPointer(infoAddr); + if (gma.data && gma.dataUpdated) { + memcpy(Memory::GetPointer(gma.addr), gma.data, gma.size); + gma.dataUpdated = 0; + gmuinfo->updated = 1; + } + else { + gmuinfo->updated = 0; + } + gmuinfo->timeStamp = CoreTiming::GetGlobalTimeUsScaled(); + } + break; + } + } + + return 0; +} + +static int sceNetAdhocGameModeDeleteReplica(int id) { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeDeleteReplica(%i)", id); + auto it = std::find_if(replicaGameModeAreas.begin(), replicaGameModeAreas.end(), + [id](GameModeArea const& e) { + return e.id == id; + }); + + if (it == replicaGameModeAreas.end()) + return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); + + if (it->data) { + free(it->data); + it->data = nullptr; + } + //sceNetAdhocPdpDelete(it->socket, 0); + replicaGameModeAreas.erase(it); + + if (replicaGameModeAreas.size() <= 0 && isZeroMAC(&masterGameModeArea.mac)) { + //sceNetAdhocPdpDelete(gameModeSocket, 0); + //gameModeSocket = (int)INVALID_SOCKET; + } + + return 0; +} + +int sceNetAdhocGetSocketAlert(int id, u32 flagPtr) { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocGetSocketAlert(%i, %08x) at %08x", id, flagPtr, currentMIPS->pc); + if (!Memory::IsValidAddress(flagPtr)) + return ERROR_NET_ADHOC_INVALID_ARG; + + if (id < 1 || id > MAX_SOCKET || adhocSockets[id - 1] == NULL) + return ERROR_NET_ADHOC_INVALID_SOCKET_ID; + + s32_le flg = adhocSockets[id - 1]->flags; + Memory::Write_U32(flg, flagPtr); + + return 0; +} + +int NetAdhocMatching_Stop(int matchingId) { + SceNetAdhocMatchingContext* item = findMatchingContext(matchingId); if (item != NULL) { + // This will cause using PdpRecv on this socket to return ERROR_NET_ADHOC_SOCKET_ALERTED (Based on Ys vs. Sora no Kiseki when tested with JPCSP + prx files). Is this used to abort inprogress socket activity? + NetAdhoc_SetSocketAlert(item->socket, ADHOC_F_ALERTRECV); + item->inputRunning = false; if (item->inputThread.joinable()) { item->inputThread.join(); @@ -2487,13 +3930,21 @@ int sceNetAdhocMatchingStop(int matchingId) { } // Stop fake PSP Thread - //__KernelStopThread(item->matching_thid, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching stopped"); - //item->matchingThread->Terminate(); + if (matchingThreads[item->matching_thid] > 0) { + __KernelStopThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching stopped"); + __KernelDeleteThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching deleted"); + /*item->matchingThread->Terminate(); + if (item->matchingThread && item->matchingThread->Stopped()) { + delete item->matchingThread; + item->matchingThread = nullptr; + }*/ + } + matchingThreads[item->matching_thid] = 0; // Multithreading Lock peerlock.lock(); - // Remove your own MAC, or All memebers, or don't remove at all or we should do this on MatchingDelete ? + // Remove your own MAC, or All members, or don't remove at all or we should do this on MatchingDelete ? clearPeerList(item); //deleteAllMembers(item); item->running = 0; @@ -2507,17 +3958,21 @@ int sceNetAdhocMatchingStop(int matchingId) { return 0; } -int sceNetAdhocMatchingDelete(int matchingId) { - // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right? +int sceNetAdhocMatchingStop(int matchingId) { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStop(%i) at %08x", matchingId, currentMIPS->pc); + return NetAdhocMatching_Stop(matchingId); +} + +int NetAdhocMatching_Delete(int matchingId) { // Previous Context Reference - SceNetAdhocMatchingContext * prev = NULL; + SceNetAdhocMatchingContext* prev = NULL; // Multithreading Lock peerlock.lock(); //contextlock.lock(); // Context Pointer - SceNetAdhocMatchingContext * item = contexts; + SceNetAdhocMatchingContext* item = contexts; // Iterate contexts for (; item != NULL; item = item->next) { @@ -2531,7 +3986,7 @@ int sceNetAdhocMatchingDelete(int matchingId) { // Stop it first if it's still running if (item->running) { - sceNetAdhocMatchingStop(matchingId); + NetAdhocMatching_Stop(matchingId); } // Delete the Fake PSP Thread //__KernelDeleteThread(item->matching_thid, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching deleted"); @@ -2539,7 +3994,7 @@ int sceNetAdhocMatchingDelete(int matchingId) { // Make sure nobody locking/using the socket item->socketlock->lock(); // Delete the socket - sceNetAdhocPdpDelete(item->socket, 0); // item->connected = (sceNetAdhocPdpDelete(item->socket, 0) < 0); + NetAdhocPdp_Delete(item->socket, 0); // item->connected = (sceNetAdhocPdpDelete(item->socket, 0) < 0); item->socketlock->unlock(); // Free allocated memories free(item->hello); @@ -2548,20 +4003,25 @@ int sceNetAdhocMatchingDelete(int matchingId) { // Destroy locks item->eventlock->lock(); // Make sure it's not locked when being deleted item->eventlock->unlock(); - delete item->eventlock; - item->eventlock = NULL; + delete item->eventlock; item->inputlock->lock(); // Make sure it's not locked when being deleted item->inputlock->unlock(); - delete item->inputlock; - item->inputlock = NULL; + delete item->inputlock; item->socketlock->lock(); // Make sure it's not locked when being deleted item->socketlock->unlock(); delete item->socketlock; - item->socketlock = NULL; // Free item context memory free(item); item = NULL; + // Making sure there are no leftover matching events from this session which could cause a crash on the next session + for (auto it = matchingEvents.begin(); it != matchingEvents.end(); ) { + if (it->data[0] == matchingId) + it = matchingEvents.erase(it); + else + ++it; + } + // Stop Search break; } @@ -2573,7 +4033,18 @@ int sceNetAdhocMatchingDelete(int matchingId) { // Multithreading Unlock peerlock.unlock(); //contextlock.unlock(); + return 0; +} + +int sceNetAdhocMatchingDelete(int matchingId) { + // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right? + + NetAdhocMatching_Delete(matchingId); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingDelete(%i) at %08x", matchingId, currentMIPS->pc); + + // Give a little time to make sure everything are cleaned up before the following AdhocMatchingCreate, Not too long tho, otherwise Naruto Ultimate Ninja Heroes 3 will have an issue + //hleDelayResult(0, "give time to init/cleanup", adhocExtraPollDelayMS * 1000); return 0; } @@ -2581,38 +4052,47 @@ int sceNetAdhocMatchingInit(u32 memsize) { WARN_LOG(SCENET, "sceNetAdhocMatchingInit(%d) at %08x", memsize, currentMIPS->pc); // Uninitialized Library - if (netAdhocMatchingInited) return ERROR_NET_ADHOC_MATCHING_ALREADY_INITIALIZED; + if (netAdhocMatchingInited) + return ERROR_NET_ADHOC_MATCHING_ALREADY_INITIALIZED; // Save Fake Pool Size fakePoolSize = memsize; // Initialize Library + matchingEvents.clear(); netAdhocMatchingInited = true; // Return Success return 0; } -int sceNetAdhocMatchingTerm() { - // Should we cleanup all created matching contexts first? just in case there are games that doesn't delete them before calling this +int NetAdhocMatching_Term() { if (netAdhocMatchingInited) { // Delete all Matching contexts - SceNetAdhocMatchingContext * next = NULL; - SceNetAdhocMatchingContext * context = contexts; + SceNetAdhocMatchingContext* next = NULL; + SceNetAdhocMatchingContext* context = contexts; while (context != NULL) { next = context->next; - if (context->running) sceNetAdhocMatchingStop(context->id); - sceNetAdhocMatchingDelete(context->id); + //if (context->running) NetAdhocMatching_Stop(context->id); + NetAdhocMatching_Delete(context->id); context = next; } + contexts = NULL; + matchingThreads.clear(); } - - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingTerm()"); - netAdhocMatchingInited = false; return 0; } +int sceNetAdhocMatchingTerm() { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingTerm() at %08x", currentMIPS->pc); + // Should we cleanup all created matching contexts first? just in case there are games that doesn't delete them before calling this + NetAdhocMatching_Term(); + + netAdhocMatchingInited = false; + return 0; +} + // Presumably returns a "matchingId". static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbuflen, int hello_int, int keepalive_int, int init_count, int rexmt_int, u32 callbackAddr) { @@ -2629,11 +4109,13 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle // Valid Member Limit if (maxnum > 1 && maxnum <= 16) { // Valid Receive Buffer size - if (rxbuflen >= 1024) { + if (rxbuflen >= 1) { //1024 //200 on DBZ Shin Budokai 2 // Valid Arguments if (mode >= 1 && mode <= 3) { + // Iterate Matching Contexts - SceNetAdhocMatchingContext * item = contexts; for (; item != NULL; item = item->next) { + SceNetAdhocMatchingContext * item = contexts; + for (; item != NULL; item = item->next) { // Port Match found if (item->port == port) return ERROR_NET_ADHOC_MATCHING_PORT_IN_USE; } @@ -2644,9 +4126,9 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle // Allocated Memory if (context != NULL) { // Create PDP Socket - SceNetEtherAddr localmac; getLocalMac(&localmac); - const char * mac = (const char *)&localmac.data; - int socket = sceNetAdhocPdpCreate(mac, (uint32_t)port, rxbuflen, 0); + SceNetEtherAddr localmac; + getLocalMac(&localmac); + int socket = sceNetAdhocPdpCreate((const char*)&localmac, (uint32_t)port, rxbuflen, 0); // Created PDP Socket if (socket > 0) { // Clear Memory @@ -2672,8 +4154,8 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle context->hello_int = hello_int; // client might set this to 0 if (keepalive_int < 1) context->keepalive_int = PSP_ADHOCCTL_PING_TIMEOUT; else context->keepalive_int = keepalive_int; // client might set this to 0 context->keepalivecounter = init_count; // used to multiply keepalive_int as timeout - context->timeout = (keepalive_int * init_count); - if (context->timeout < 5000000) context->timeout = 5000000; // For internet play we need higher timeout than what the game wanted + context->timeout = (((u64)(keepalive_int) + (u64)rexmt_int) * (u64)init_count); + context->timeout += (adhocDefaultTimeout * 1000ULL); // For internet play we need higher timeout than what the game wanted context->handler = handler; // Fill in Selfpeer @@ -2684,16 +4166,13 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle context->eventlock = new std::recursive_mutex; context->inputlock = new std::recursive_mutex; - // Create fake thread - //#define PSP_THREAD_ATTR_KERNEL 0x00001000 // PSP_THREAD_ATTR_KERNEL is located in sceKernelThread.cpp instead of sceKernelThread.h :( - //context->matching_thid = __KernelCreateThreadInternal("AdhocMatching", 0, idleThreadHackAddr, 0x7f, 4096, PSP_THREAD_ATTR_KERNEL); - //context->matchingThread = new HLEHelperThread("AdhocMatching", "AdhocMatchingMod", "AdhocMatchingFunc", 0x7f, 4096); //8192 - // Multithreading Lock peerlock.lock(); //contextlock.lock(); // Add Callback Handler context->handler.entryPoint = callbackAddr; + context->matching_thid = static_cast(matchingThreads.size()); + matchingThreads.push_back(0); // Link Context //context->connected = true; @@ -2703,6 +4182,9 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle // Multithreading UnLock peerlock.unlock(); //contextlock.unlock(); + // Just to make sure Adhoc is already connected + //hleDelayResult(context->id, "give time to init/cleanup", adhocEventDelayMS * 1000); + // Return Matching ID return context->id; } @@ -2737,23 +4219,18 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; } -// TODO: Should we execute the callback used to create the Matching Id if it's a valid address? -static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, int inthPri, int inthStack, int optLen, u32 optDataAddr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr, currentMIPS->pc); - if (!g_Config.bEnableWlan) - return -1; - +int NetAdhocMatching_Start(int matchingId, int evthPri, int evthPartitionId, int evthStack, int inthPri, int inthPartitionId, int inthStack, int optLen, u32 optDataAddr) { // Multithreading Lock peerlock.lock(); - SceNetAdhocMatchingContext * item = findMatchingContext(matchingId); - + SceNetAdhocMatchingContext* item = findMatchingContext(matchingId); + if (item != NULL) { //sceNetAdhocMatchingSetHelloOpt(matchingId, optLen, optDataAddr); //SetHelloOpt only works when context is running if ((optLen > 0) && Memory::IsValidAddress(optDataAddr)) { // Allocate the memory and copy the content if (item->hello != NULL) free(item->hello); - item->hello = (uint8_t *)malloc(optLen); + item->hello = (uint8_t*)malloc(optLen); if (item->hello != NULL) { Memory::Memcpy(item->hello, optDataAddr, optLen); item->hellolen = optLen; @@ -2766,7 +4243,7 @@ static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, //Add your own MAC as a member (only if it's empty?) /*SceNetAdhocMatchingMemberInternal * peer = addMember(item, &item->mac); switch (item->mode) { - case PSP_ADHOC_MATCHING_MODE_PARENT: + case PSP_ADHOC_MATCHING_MODE_PARENT: peer->state = PSP_ADHOC_MATCHING_PEER_OFFER; break; case PSP_ADHOC_MATCHING_MODE_CHILD: @@ -2776,9 +4253,15 @@ static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, peer->state = PSP_ADHOC_MATCHING_PEER_P2P; }*/ - // Start the Fake PSP Thread - //__KernelStartThread(item->matching_thid, 0, 0); - //item->matchingThread->Start(0, 0); + // Create & Start the Fake PSP Thread ("matching_ev%d" and "matching_io%d") + netAdhocValidateLoopMemory(); + std::string thrname = std::string("MatchingThr") + std::to_string(matchingId); + matchingThreads[item->matching_thid] = sceKernelCreateThread(thrname.c_str(), matchingThreadHackAddr, evthPri, evthStack, 0, 0); + //item->matchingThread = new HLEHelperThread(thrname.c_str(), "sceNetAdhocMatching", "__NetMatchingCallbacks", inthPri, inthStack); + if (matchingThreads[item->matching_thid] > 0) { + sceKernelStartThread(matchingThreads[item->matching_thid], 0, 0); //sceKernelStartThread(context->event_thid, sizeof(context), &context); + //item->matchingThread->Start(matchingId, 0); + } //Create the threads if (!item->eventRunning) { @@ -2794,15 +4277,41 @@ static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, netAdhocMatchingStarted++; } //else return ERROR_NET_ADHOC_MATCHING_INVALID_ID; //Faking success to prevent GTA:VCS from stuck unable to choose host/join menu - + // Multithreading Unlock peerlock.unlock(); + // Give a little time to make sure matching Threads are ready before the game use the next sceNet functions, should've checked for status instead of guessing the time? + //sleep_ms(adhocMatchingEventDelayMS); + hleDelayResult(0, "give some time", adhocMatchingEventDelayMS * 1000); + return 0; } +#define KERNEL_PARTITION_ID 1 +#define USER_PARTITION_ID 2 +#define VSHELL_PARTITION_ID 5 +// This should be similar with sceNetAdhocMatchingStart2 but using USER_PARTITION_ID (2) for PartitionId params +static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, int inthPri, int inthStack, int optLen, u32 optDataAddr) { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr, currentMIPS->pc); + if (!g_Config.bEnableWlan) + return -1; + + return NetAdhocMatching_Start(matchingId, evthPri, USER_PARTITION_ID, evthStack, inthPri, USER_PARTITION_ID, inthStack, optLen, optDataAddr); +} + +// With params for Partition ID for the event & input handler stack +static int sceNetAdhocMatchingStart2(int matchingId, int evthPri, int evthPartitionId, int evthStack, int inthPri, int inthPartitionId, int inthStack, int optLen, u32 optDataAddr) { + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart2(%i, %i, %i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthPartitionId, evthStack, inthPri, inthPartitionId, inthStack, optLen, optDataAddr, currentMIPS->pc); + if (!g_Config.bEnableWlan) + return -1; + + return NetAdhocMatching_Start(matchingId, evthPri, evthPartitionId, evthStack, inthPri, inthPartitionId, inthStack, optLen, optDataAddr); +} + + static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddress, int optLen, u32 optDataPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSelectTarget(%i, %s, %i, %08x) at %08x", matchingId, macAddress, optLen, optDataPtr, currentMIPS->pc); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSelectTarget(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str(), optLen, optDataPtr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -2830,7 +4339,7 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres if (peer != NULL) { // Valid Optional Data Length - if ((optLen == 0 && optDataPtr == 0) || (optLen > 0 && optDataPtr != 0)) + if ((optLen == 0) || (optLen > 0 && optDataPtr != 0)) { void * opt = NULL; if (Memory::IsValidAddress(optDataPtr)) opt = Memory::GetPointer(optDataPtr); @@ -2838,10 +4347,10 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) { // Already Connected - if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) return ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED; + if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); // Not enough space - if (countChildren(context) == (context->maxpeers - 1)) return ERROR_NET_ADHOC_MATCHING_EXCEED_MAXNUM; + if (countChildren(context) == (context->maxpeers - 1)) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_EXCEED_MAXNUM, "adhocmatching exceed maxnum"); // Requesting Peer if (peer->state == PSP_ADHOC_MATCHING_PEER_INCOMING_REQUEST) @@ -2869,10 +4378,10 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres else if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD) { // Already connected - if (findParent(context) != NULL) return ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED; + if (findParent(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); // Outgoing Request in Progress - if (findOutgoingRequest(context) != NULL) return ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS; + if (findOutgoingRequest(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS, "adhocmatching request in progress"); // Valid Offer if (peer->state == PSP_ADHOC_MATCHING_PEER_OFFER) @@ -2892,10 +4401,10 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres else { // Already connected - if (findP2P(context) != NULL) return ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED; + if (findP2P(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); // Outgoing Request in Progress - if (findOutgoingRequest(context) != NULL) return ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS; + if (findOutgoingRequest(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS, "adhocmatching request in progress"); // Join Request Mode if (peer->state == PSP_ADHOC_MATCHING_PEER_OFFER) @@ -2927,35 +4436,35 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres } // How did this happen?! It shouldn't! - return ERROR_NET_ADHOC_MATCHING_TARGET_NOT_READY; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_TARGET_NOT_READY, "adhocmatching target not ready"); } // Invalid Optional Data Length - return ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN, "adhocmatching invalid optlen"); } // Peer not found - return ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); } // Idle Context - return ERROR_NET_ADHOC_MATCHING_NOT_RUNNING; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); } // Invalid Matching ID - return ERROR_NET_ADHOC_MATCHING_INVALID_ID; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); } // Invalid Arguments - return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Uninitialized Library - return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); } int sceNetAdhocMatchingCancelTargetWithOpt(int matchingId, const char *macAddress, int optLen, u32 optDataPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingCancelTargetWithOpt(%i, %s, %i, %08x) at %08x", matchingId, macAddress, optLen, optDataPtr, currentMIPS->pc); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingCancelTargetWithOpt(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str(), optLen, optDataPtr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -2967,7 +4476,7 @@ int sceNetAdhocMatchingCancelTargetWithOpt(int matchingId, const char *macAddres if (Memory::IsValidAddress(optDataPtr)) opt = Memory::GetPointer(optDataPtr); // Valid Arguments - if (target != NULL && ((optLen == 0 && opt == NULL) || (optLen > 0 && opt != NULL))) + if (target != NULL && ((optLen == 0) || (optLen > 0 && opt != NULL))) { // Find Matching Context SceNetAdhocMatchingContext * context = findMatchingContext(matchingId); @@ -3005,6 +4514,8 @@ int sceNetAdhocMatchingCancelTargetWithOpt(int matchingId, const char *macAddres // Delete Peer from List // Can't delete here, Threads still need this data. // deletePeer(context, peer); + // Marking peer to be timedout instead of deleting immediately + peer->lastping = 0; // Return Success return 0; @@ -3012,29 +4523,29 @@ int sceNetAdhocMatchingCancelTargetWithOpt(int matchingId, const char *macAddres } // Peer not found - //return ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET; + //return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); // Faking success to prevent the game (ie. Soul Calibur) to repeatedly calling this function when the other player is disconnected return 0; } // Context not running - return ERROR_NET_ADHOC_MATCHING_NOT_RUNNING; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); } // Invalid Matching ID - return ERROR_NET_ADHOC_MATCHING_INVALID_ID; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); } // Invalid Arguments - return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Uninitialized Library - return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); } int sceNetAdhocMatchingCancelTarget(int matchingId, const char *macAddress) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingCancelTarget(%i, %s)", matchingId, macAddress); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingCancelTarget(%i, %s)", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str()); if (!g_Config.bEnableWlan) return -1; return sceNetAdhocMatchingCancelTargetWithOpt(matchingId, macAddress, 0, 0); @@ -3072,11 +4583,12 @@ int sceNetAdhocMatchingGetHelloOpt(int matchingId, u32 optLenAddr, u32 optDataAd } int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAddr) { - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSetHelloOpt(%i, %i, %08x) at %08x", matchingId, optLenAddr, optDataAddr, currentMIPS->pc); + VERBOSE_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSetHelloOpt(%i, %i, %08x) at %08x", matchingId, optLenAddr, optDataAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; - if (!netAdhocMatchingInited) return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; + if (!netAdhocMatchingInited) + return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; // Multithreading Lock peerlock.lock(); @@ -3096,7 +4608,7 @@ int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAd if (context->running) { // Valid Optional Data Length - if ((optLenAddr == 0 && optDataAddr == 0) || (optLenAddr > 0 && optDataAddr != 0)) + if ((optLenAddr == 0) || (optLenAddr > 0 && optDataAddr != 0)) { // Grab Existing Hello Data void * hello = context->hello; @@ -3160,10 +4672,12 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) if (!g_Config.bEnableWlan) return -1; - if (!netAdhocMatchingInited) return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; + if (!netAdhocMatchingInited) + return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; // Minimum Argument - if (!Memory::IsValidAddress(sizeAddr)) return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; + if (!Memory::IsValidAddress(sizeAddr)) + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); // Multithreading Lock peerlock.lock(); @@ -3187,8 +4701,9 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) buf2 = (SceNetAdhocMatchingMemberInfoEmu *)Memory::GetPointer(buf); } - // Number of Connected Peers - uint32_t peercount = countConnectedPeers(context); + // Number of Connected Peers, should we exclude timeout members? + bool excludeTimedout = false; // false; + uint32_t peercount = countConnectedPeers(context, excludeTimedout); // Calculate Connected Peer Bytesize int available = sizeof(SceNetAdhocMatchingMemberInfoEmu) * peercount; @@ -3198,6 +4713,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) { // Get Connected Peer Count *buflen = available; + DEBUG_LOG(SCENET, "MemberList [Connected: %i]", peercount); } // Normal Mode @@ -3218,11 +4734,15 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Filled Request Counter int filledpeers = 0; - // Add Self-Peer if (requestedpeers > 0) { - // Add Local MAC - buf2[filledpeers++].mac_addr = context->mac; + // Add Self-Peer first, unless if there is existing Parent/P2P peer + if (peercount == 1 || context->mode != PSP_ADHOC_MATCHING_MODE_CHILD) { + // Add Local MAC + buf2[filledpeers++].mac_addr = context->mac; + + DEBUG_LOG(SCENET, "MemberSelf [%s]", mac2str(&context->mac).c_str()); + } // Room for more than local peer if (requestedpeers > 1) @@ -3231,55 +4751,107 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) if (context->mode == PSP_ADHOC_MATCHING_MODE_P2P) { // Find P2P Brother - SceNetAdhocMatchingMemberInternal * p2p = findP2P(context); + SceNetAdhocMatchingMemberInternal * p2p = findP2P(context, excludeTimedout); // P2P Brother found if (p2p != NULL) { + // Faking lastping + auto friendpeer = findFriend(&p2p->mac); + if (p2p->lastping != 0 && friendpeer != NULL && friendpeer->last_recv != 0) + p2p->lastping = CoreTiming::GetGlobalTimeUsScaled() - 1; + else + p2p->lastping = 0; + // Add P2P Brother MAC buf2[filledpeers++].mac_addr = p2p->mac; + + DEBUG_LOG(SCENET, "MemberP2P [%s]", mac2str(&p2p->mac).c_str()); } } // Parent or Child Mode else { - // Iterate Peer List - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL && filledpeers < requestedpeers; peer = peer->next) - { - // Parent Mode - if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) - { - // Interested in Children (Michael Jackson Style) - if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) - { - // Add Child MAC - buf2[filledpeers++].mac_addr = peer->mac; - } - } - - // Children Mode + // Add Parent first + SceNetAdhocMatchingMemberInternal* parentpeer = findParent(context); + if (parentpeer != NULL) { + // Faking lastping + auto friendpeer = findFriend(&parentpeer->mac); + if (parentpeer->lastping != 0 && friendpeer != NULL && friendpeer->last_recv != 0) + parentpeer->lastping = CoreTiming::GetGlobalTimeUsScaled() - 1; else - { - // Interested in Parent & Siblings - if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD || peer->state == PSP_ADHOC_MATCHING_PEER_PARENT) - { - // Add Peer MAC - buf2[filledpeers++].mac_addr = peer->mac; - } + parentpeer->lastping = 0; + + // Add Parent MAC + buf2[filledpeers++].mac_addr = parentpeer->mac; + + DEBUG_LOG(SCENET, "MemberParent [%s]", mac2str(&parentpeer->mac).c_str()); + } + + // We may need to rearrange children where last joined player placed last + std::deque sortedPeers; + + // Iterate Peer List + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL && filledpeers < requestedpeers; peer = peer->next) + { + // Should we exclude timedout members? + if (!excludeTimedout || peer->lastping != 0) { + // Faking lastping + auto friendpeer = findFriend(&peer->mac); + if (peer->lastping != 0 && friendpeer != NULL && friendpeer->last_recv != 0) + peer->lastping = CoreTiming::GetGlobalTimeUsScaled() - 1; + else + peer->lastping = 0; + + // Add Peer MAC + sortedPeers.push_front(peer); } } - } + // Iterate rearranged peers + for (const auto& peer : sortedPeers) { + // Parent Mode + if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) { + // Interested in Children + if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) { + // Add Child MAC + buf2[filledpeers++].mac_addr = peer->mac; + + DEBUG_LOG(SCENET, "MemberChild [%s]", mac2str(&peer->mac).c_str()); + } + } + + // Child Mode + else { + // Interested in Siblings + if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) { + // Add Peer MAC + buf2[filledpeers++].mac_addr = peer->mac; + + DEBUG_LOG(SCENET, "MemberSibling [%s]", mac2str(&peer->mac).c_str()); + } + // Self Peer + else if (peer->state == 0) { + // Add Local MAC + buf2[filledpeers++].mac_addr = peer->mac; + + DEBUG_LOG(SCENET, "MemberSelf [%s]", mac2str(&peer->mac).c_str()); + } + + } + } + sortedPeers.clear(); + } } // Link Result List - int i = 0; - for (; i < filledpeers - 1; i++) + for (int i = 0; i < filledpeers - 1; i++) { // Link Next Element //buf2[i].next = &buf2[i + 1]; - buf2[i].next = buf + (sizeof(SceNetAdhocMatchingMemberInfoEmu)*i) + sizeof(SceNetAdhocMatchingMemberInfoEmu); + buf2[i].next = buf + (sizeof(SceNetAdhocMatchingMemberInfoEmu)*(i+1LL)); } // Fix Last Element if (filledpeers > 0) buf2[filledpeers - 1].next = 0; @@ -3287,6 +4859,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Fix Buffer Size *buflen = sizeof(SceNetAdhocMatchingMemberInfoEmu) * filledpeers; + DEBUG_LOG(SCENET, "MemberList [Requested: %i][Discovered: %i]", requestedpeers, filledpeers); } // Return Success @@ -3294,19 +4867,20 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) } // Invalid Arguments - return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Context not running - return ERROR_NET_ADHOC_MATCHING_NOT_RUNNING; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); } // Invalid Matching ID - return ERROR_NET_ADHOC_MATCHING_INVALID_ID; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); } +// Gran Turismo may replace the 1st bit of the 1st byte of MAC address's OUI with 0 (unicast bit), or replace the whole 6-bytes of MAC address with all 00 (invalid mac) for unknown reason int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u32 dataAddr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSendData(%i, %s, %i, %08x)", matchingId, mac, dataLen, dataAddr); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSendData(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)mac).c_str(), dataLen, dataAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -3325,23 +4899,59 @@ int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u3 // Running Context if (context->running) { - // Find Target Peer - SceNetAdhocMatchingMemberInternal * peer = findPeer(context, (SceNetEtherAddr *)mac); + // Invalid Data Length + if (dataLen <=0 || dataAddr == 0) + // Invalid Data Length + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_DATALEN, "invalid datalen"); - // Found Peer - if (peer != NULL) - { - void * data = NULL; - if (Memory::IsValidAddress(dataAddr)) data = Memory::GetPointer(dataAddr); + void* data = NULL; + if (Memory::IsValidAddress(dataAddr)) data = Memory::GetPointer(dataAddr); - // Valid Data Length - if (dataLen > 0 && data != NULL) + // FIXME: If the target MAC is 00:00:00:00:00:00 (invalid mac) Should we default to P2P/Parent's MAC or return an Error? + if (isZeroMAC((const SceNetEtherAddr*)mac)) { + int sent = 0; + peerlock.lock(); + // Iterate Peer List for Matching Target + SceNetAdhocMatchingMemberInternal* peer = context->peerlist; + for (; peer != NULL; peer = peer->next) + { + // Valid Peer Connection State + if (peer->state == PSP_ADHOC_MATCHING_PEER_PARENT || peer->state == PSP_ADHOC_MATCHING_PEER_P2P) + { + // Skip Busy peers + if (peer->sending) + continue; + + // Mark Peer as Sending + peer->sending = 1; + + // Send Data to Peer + sendBulkData(context, peer, dataLen, data); + sent++; + break; + } + } + peerlock.unlock(); + + if (sent == 0) + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "invalid target"); + + // Return Success + return 0; + } + else { + // Find Target Peer + SceNetAdhocMatchingMemberInternal* peer = findPeer(context, (SceNetEtherAddr*)mac); + + // Found Peer + if (peer != NULL) { // Valid Peer Connection State if (peer->state == PSP_ADHOC_MATCHING_PEER_PARENT || peer->state == PSP_ADHOC_MATCHING_PEER_CHILD || peer->state == PSP_ADHOC_MATCHING_PEER_P2P) { // Send in Progress - if (peer->sending) return ERROR_NET_ADHOC_MATCHING_DATA_BUSY; + if (peer->sending) + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_DATA_BUSY, "data busy"); // Mark Peer as Sending peer->sending = 1; @@ -3354,35 +4964,32 @@ int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u3 } // Not connected / accepted - return ERROR_NET_ADHOC_MATCHING_NOT_ESTABLISHED; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_ESTABLISHED, "not established"); } - - // Invalid Data Length - return ERROR_NET_ADHOC_MATCHING_INVALID_DATALEN; } // Peer not found - return ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "unknown target"); } // Context not running - return ERROR_NET_ADHOC_MATCHING_NOT_RUNNING; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "not running"); } // Invalid Matching ID - return ERROR_NET_ADHOC_MATCHING_INVALID_ID; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "invalid id"); } // Invalid Arguments - return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "invalid arg"); } // Uninitialized Library - return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "not initialized"); } int sceNetAdhocMatchingAbortSendData(int matchingId, const char *mac) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingAbortSendData(%i, %s)", matchingId, mac); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingAbortSendData(%i, %s)", matchingId, mac2str((SceNetEtherAddr*)mac).c_str()); if (!g_Config.bEnableWlan) return -1; @@ -3422,36 +5029,37 @@ int sceNetAdhocMatchingAbortSendData(int matchingId, const char *mac) { } // Peer not found - return ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); } // Context not running - return ERROR_NET_ADHOC_MATCHING_NOT_RUNNING; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); } // Invalid Matching ID - return ERROR_NET_ADHOC_MATCHING_INVALID_ID; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); } // Invalid Arguments - return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Uninitialized Library - return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; + return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); } +// Get the maximum memory usage by the matching library static int sceNetAdhocMatchingGetPoolMaxAlloc() { ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolMaxAlloc()"); if (!g_Config.bEnableWlan) return -1; // Lazy way out - hardcoded return value - return (50 * 1024); + return fakePoolSize/2; // (50 * 1024); } int sceNetAdhocMatchingGetPoolStat(u32 poolstatPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingGetPoolStat(%08x)", poolstatPtr); + DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocMatchingGetPoolStat(%08x)", poolstatPtr); if (!g_Config.bEnableWlan) return -1; @@ -3466,8 +5074,8 @@ int sceNetAdhocMatchingGetPoolStat(u32 poolstatPtr) { { // Fill Poolstat with Fake Data poolstat->pool = fakePoolSize; - poolstat->maximum = fakePoolSize / 8 * 6; - poolstat->free = fakePoolSize / 8 * 7; + poolstat->maximum = fakePoolSize / 2; // Max usage faked to halt the pool + poolstat->free = fakePoolSize - poolstat->maximum; // Return Success return 0; @@ -3483,42 +5091,103 @@ int sceNetAdhocMatchingGetPoolStat(u32 poolstatPtr) { void __NetTriggerCallbacks() { + std::lock_guard adhocGuard(adhocEvtMtx); + int delayus = 10000; + + auto params = adhocctlEvents.begin(); + if (params != adhocctlEvents.end()) { - std::lock_guard adhocGuard(adhocEvtMtx); + u32 flags = params->first; + u32 error = params->second; + u32_le args[3] = { 0, 0, 0 }; + args[0] = flags; + args[1] = error; - for (auto ¶ms : adhocctlEvents) + // FIXME: When Joining a group, Do we need to wait for group creator's peer data before triggering the callback to make sure the game not to thinks we're the group creator? + u64 now = (u64)(time_now_d() * 1000.0); + if ((flags != ADHOCCTL_EVENT_CONNECT && flags != ADHOCCTL_EVENT_GAME) || adhocConnectionType != ADHOC_JOIN || getActivePeerCount() > 0 || now - adhocctlStartTime > adhocDefaultTimeout) { - int flags = params.first; - int error = params.second; - u32_le args[3] = { 0, 0, 0 }; - args[0] = flags; - args[1] = error; + // Since 0 is a valid index to types_ we use -1 to detects if it was loaded from an old save state + if (actionAfterAdhocMipsCall < 0) { + actionAfterAdhocMipsCall = __KernelRegisterActionType(AfterAdhocMipsCall::Create); + } + + delayus = (adhocEventPollDelayMS + 2 * adhocExtraPollDelayMS) * 1000; // Added an extra delay to prevent I/O Timing method from causing disconnection + switch (flags) { + case ADHOCCTL_EVENT_CONNECT: + adhocctlState = ADHOCCTL_STATE_CONNECTED; + delayus = (adhocEventDelayMS + 2 * adhocExtraPollDelayMS) * 1000; // May affects Dissidia 012 and GTA VCS + break; + case ADHOCCTL_EVENT_SCAN: // notified only when scan completed? + adhocctlState = ADHOCCTL_STATE_DISCONNECTED; + break; + case ADHOCCTL_EVENT_DISCONNECT: + adhocctlState = ADHOCCTL_STATE_DISCONNECTED; + break; + case ADHOCCTL_EVENT_GAME: + adhocctlState = ADHOCCTL_STATE_GAMEMODE; + delayus = (adhocEventDelayMS + 2 * adhocExtraPollDelayMS) * 1000; + break; + case ADHOCCTL_EVENT_DISCOVER: + adhocctlState = ADHOCCTL_STATE_DISCOVER; + break; + case ADHOCCTL_EVENT_WOL_INTERRUPT: + adhocctlState = ADHOCCTL_STATE_WOL; + break; + case ADHOCCTL_EVENT_ERROR: + adhocctlState = ADHOCCTL_STATE_DISCONNECTED; + break; + } for (std::map::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) { + DEBUG_LOG(SCENET, "AdhocctlCallback: [ID=%i][EVENT=%i][Error=%08x]", it->first, flags, error); args[2] = it->second.argument; - __KernelDirectMipsCall(it->second.entryPoint, NULL, args, 3, true); + AfterAdhocMipsCall* after = (AfterAdhocMipsCall*)__KernelCreateAction(actionAfterAdhocMipsCall); + after->SetData(it->first, flags, args[2]); + hleEnqueueCall(it->second.entryPoint, 3, args, after); } + adhocctlEvents.pop_front(); } - adhocctlEvents.clear(); - - for (auto ¶m : matchingEvents) - { - u32_le *args = (u32_le *) param; - AfterMatchingMipsCall *after = (AfterMatchingMipsCall *) __KernelCreateAction(actionAfterMatchingMipsCall); - after->SetContextID(args[0], args[1]); - __KernelDirectMipsCall(args[5], after, args, 5, true); - } - matchingEvents.clear(); } - //magically make this work - hleDelayResult(0, "Prevent Adhoc thread from blocking", 1000); + + // Must be delayed long enough whenever there is a pending callback. Should it be 100-500ms for Adhocctl Events? or Not Less than the delays on sceNetAdhocctl HLE? + sceKernelDelayThread(delayus); + hleSkipDeadbeef(); +} + +void __NetMatchingCallbacks() //(int matchingId) +{ + std::lock_guard adhocGuard(adhocEvtMtx); + int delayus = 10000; + + auto params = matchingEvents.begin(); + if (params != matchingEvents.end()) + { + u32_le* args = (u32_le*)&(*params); + //auto context = findMatchingContext(args[0]); + + if (actionAfterMatchingMipsCall < 0) { + actionAfterMatchingMipsCall = __KernelRegisterActionType(AfterMatchingMipsCall::Create); + } + + DEBUG_LOG(SCENET, "AdhocMatchingCallback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr*)Memory::GetPointer(args[2])).c_str()); + AfterMatchingMipsCall* after = (AfterMatchingMipsCall*)__KernelCreateAction(actionAfterMatchingMipsCall); + after->SetData(args[0], args[1], args[2]); + hleEnqueueCall(args[5], 5, args, after); + matchingEvents.pop_front(); + delayus = (adhocMatchingEventDelayMS + 2 * adhocExtraPollDelayMS) * 1000; // Added an extra delay to prevent I/O Timing method from causing disconnection + } + + // Must be delayed long enough whenever there is a pending callback. Should it be 10-100ms for Matching Events? or Not Less than the delays on sceNetAdhocMatching HLE? + sceKernelDelayThread(delayus); + hleSkipDeadbeef(); } const HLEFunction sceNetAdhoc[] = { {0XE1D621D7, &WrapU_V, "sceNetAdhocInit", 'x', "" }, {0XA62C6F57, &WrapI_V, "sceNetAdhocTerm", 'i', "" }, - {0X0AD043ED, &WrapI_U, "sceNetAdhocctlConnect", 'i', "x" }, - {0X6F92741B, &WrapI_CUIU, "sceNetAdhocPdpCreate", 'i', "sxix" }, + {0X0AD043ED, &WrapI_C, "sceNetAdhocctlConnect", 'i', "s" }, + {0X6F92741B, &WrapI_CIIU, "sceNetAdhocPdpCreate", 'i', "siix" }, {0XABED3790, &WrapI_ICUVIII, "sceNetAdhocPdpSend", 'i', "isxpiii" }, {0XDFE53E03, &WrapI_IVVVVUI, "sceNetAdhocPdpRecv", 'i', "ippppxi" }, {0X7F27BB5E, &WrapI_II, "sceNetAdhocPdpDelete", 'i', "ii" }, @@ -3550,6 +5219,7 @@ const HLEFunction sceNetAdhocMatching[] = { {0X7945ECDA, &WrapI_V, "sceNetAdhocMatchingTerm", 'i', "" }, {0XCA5EDA6F, &WrapI_IIIIIIIIU, "sceNetAdhocMatchingCreate", 'i', "iiiiiiiix"}, {0X93EF3843, &WrapI_IIIIIIU, "sceNetAdhocMatchingStart", 'i', "iiiiiix" }, + {0xE8454C65, &WrapI_IIIIIIIIU, "sceNetAdhocMatchingStart2", 'i', "iiiiiiiix"}, {0X32B156B3, &WrapI_I, "sceNetAdhocMatchingStop", 'i', "i" }, {0XF16EAF4F, &WrapI_I, "sceNetAdhocMatchingDelete", 'i', "i" }, {0X5E3D4B79, &WrapI_ICIU, "sceNetAdhocMatchingSelectTarget", 'i', "isix" }, @@ -3562,16 +5232,47 @@ const HLEFunction sceNetAdhocMatching[] = { {0XEC19337D, &WrapI_IC, "sceNetAdhocMatchingAbortSendData", 'i', "is" }, {0X40F8F435, &WrapI_V, "sceNetAdhocMatchingGetPoolMaxAlloc", 'i', "" }, {0X9C5CFB7D, &WrapI_U, "sceNetAdhocMatchingGetPoolStat", 'i', "x" }, + // Fake function for PPSSPP's use. + {0X756E6F00, &WrapV_V<__NetMatchingCallbacks>, "__NetMatchingCallbacks", 'v', "" }, }; +int NetAdhocctl_ExitGameMode() { + if (gameModeSocket > 0) + sceNetAdhocPdpDelete(gameModeSocket, 0); + + deleteAllGMB(); + + adhocctlCurrentMode = ADHOCCTL_MODE_NONE; + netAdhocGameModeEntered = false; + return NetAdhocctl_Disconnect(); +} + static int sceNetAdhocctlExitGameMode() { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlExitGameMode()"); - return 0; + WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlExitGameMode()"); + + return NetAdhocctl_ExitGameMode(); } static int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetGameModeInfo(%08x)", infoAddr); - return -1; + WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlGetGameModeInfo(%08x)", infoAddr); + if (!netAdhocctlInited) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + + if (!Memory::IsValidAddress(infoAddr)) + return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + + SceNetAdhocctlGameModeInfo* gmInfo = (SceNetAdhocctlGameModeInfo*)Memory::GetPointer(infoAddr); + // Writes number of participants and each participating MAC address into infoAddr/gmInfo + gmInfo->num = static_cast(gameModeMacs.size()); + int i = 0; + for (auto& mac : gameModeMacs) { + INFO_LOG(SCENET, "GameMode macAddress#%d=%s", i, mac2str(&mac).c_str()); + gmInfo->members[i++] = mac; + if (i >= ADHOCCTL_GAMEMODE_MAX_MEMBERS) + break; + } + + return 0; } static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { @@ -3580,7 +5281,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { SceNetAdhocctlPeerInfoEmu *buf = NULL; if (Memory::IsValidAddress(bufAddr)) buf = (SceNetAdhocctlPeerInfoEmu *)Memory::GetPointer(bufAddr); - DEBUG_LOG(SCENET, "sceNetAdhocctlGetPeerList([%08x]=%i, %08x) at %08x", sizeAddr, buflen ? *buflen : -1, bufAddr, currentMIPS->pc); + DEBUG_LOG(SCENET, "sceNetAdhocctlGetPeerList([%08x]=%i, %08x) at %08x", sizeAddr, /*buflen ? *buflen : -1*/Memory::Read_U32(sizeAddr), bufAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -3592,9 +5293,13 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { // Multithreading Lock peerlock.lock(); + bool excludeTimedout = true; // Length Calculation Mode - if (buf == NULL) *buflen = getActivePeerCount() * sizeof(SceNetAdhocctlPeerInfoEmu); - + if (buf == NULL) { + int activePeers = getActivePeerCount(excludeTimedout); + *buflen = activePeers * sizeof(SceNetAdhocctlPeerInfoEmu); + DEBUG_LOG(SCENET, "PeerList [Active: %i]", activePeers); + } // Normal Mode else { // Discovery Counter @@ -3613,20 +5318,26 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { // Iterate Peers for (; peer != NULL && discovered < requestcount; peer = peer->next) { - // Fake Receive Time - if (peer->last_recv != 0) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); + // Exclude Soon to be timedout peers? + if (!excludeTimedout || peer->last_recv != 0) { + // Faking Last Receive Time + if (peer->last_recv != 0) + peer->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; - // Copy Peer Info - buf[discovered].nickname = peer->nickname; - buf[discovered].mac_addr = peer->mac_addr; - buf[discovered].ip_addr = peer->ip_addr; - buf[discovered].last_recv = peer->last_recv; - discovered++; + // Copy Peer Info + buf[discovered].nickname = peer->nickname; + buf[discovered].mac_addr = peer->mac_addr; + buf[discovered].flags = 0x0400; + buf[discovered].last_recv = peer->last_recv; + discovered++; + u32_le ipaddr = peer->ip_addr; + DEBUG_LOG(SCENET, "Peer [%s][%s][%s][%llu]", mac2str(&peer->mac_addr).c_str(), inet_ntoa(*(in_addr*)&ipaddr), (const char*)&peer->nickname.data, peer->last_recv); + } } // Link List - int i = 0; for (; i < discovered - 1; i++) { + for (int i = 0; i < discovered - 1; i++) { // Link Network buf[i].next = bufAddr+(sizeof(SceNetAdhocctlPeerInfoEmu)*i) + sizeof(SceNetAdhocctlPeerInfoEmu); } @@ -3636,6 +5347,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { // Fix Size *buflen = discovered * sizeof(SceNetAdhocctlPeerInfoEmu); + DEBUG_LOG(SCENET, "PeerList [Requested: %i][Discovered: %i]", requestcount, discovered); } // Multithreading Unlock @@ -3656,8 +5368,12 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 bufAddr) { s32_le *buflen = NULL; //int32_t if (Memory::IsValidAddress(sizeAddr)) buflen = (s32_le *)Memory::GetPointer(sizeAddr); + + char nckName[ADHOCCTL_NICKNAME_LEN]; + memcpy(nckName, nickName, ADHOCCTL_NICKNAME_LEN); // Copied to null-terminated var to prevent unexpected behaviour on Logs + nckName[ADHOCCTL_NICKNAME_LEN - 1] = 0; - WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlGetPeerList(%s, [%08x]=%i, %08x)", nickName, sizeAddr, buflen ? *buflen : -1, bufAddr); + WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlGetAddrByName(%s, [%08x]=%d/%zu, %08x)", nckName, sizeAddr, buflen ? *buflen : -1, sizeof(SceNetAdhocctlPeerInfoEmu), bufAddr); // Library initialized if (netAdhocctlInited) @@ -3690,19 +5406,17 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b if (requestcount > 0) { // Local Nickname Matches - if (strcmp((char *)parameter.nickname.data, nickName) == 0) + if (strncmp((char *)¶meter.nickname.data, nickName, ADHOCCTL_NICKNAME_LEN) == 0) { // Get Local IP Address sockaddr_in addr; getLocalIp(&addr); - //buf->next = 0; buf[discovered].nickname = parameter.nickname; buf[discovered].nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; // last char need to be null-terminated char getLocalMac(&buf[discovered].mac_addr); - buf[discovered].ip_addr = addr.sin_addr.s_addr; // 0x11111111; - //buf->padding = 0x1111; //0; - buf[discovered++].last_recv = CoreTiming::GetGlobalTimeUsScaled(); + buf[discovered].flags = 0x0400; + buf[discovered++].last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; } // Peer Reference @@ -3712,22 +5426,23 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b for (; peer != NULL && discovered < requestcount; peer = peer->next) { // Match found - if (strcmp((char *)peer->nickname.data, nickName) == 0) + if (strncmp((char *)&peer->nickname.data, nickName, ADHOCCTL_NICKNAME_LEN) == 0) { // Fake Receive Time - if (peer->last_recv != 0) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); //sceKernelGetSystemTimeWide(); + if (peer->last_recv != 0) + peer->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; // Copy Peer Info buf[discovered].nickname = peer->nickname; buf[discovered].nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; // last char need to be null-terminated char buf[discovered].mac_addr = peer->mac_addr; - buf[discovered].ip_addr = peer->ip_addr; + buf[discovered].flags = 0x0400; buf[discovered++].last_recv = peer->last_recv; } } // Link List - int i = 0; for (; i < discovered - 1; i++) + for (int i = 0; i < discovered - 1; i++) { // Link Network buf[i].next = bufAddr + (sizeof(SceNetAdhocctlPeerInfoEmu)*i) + sizeof(SceNetAdhocctlPeerInfoEmu); @@ -3762,7 +5477,7 @@ const HLEFunction sceNetAdhocctl[] = { {0X20B317A0, &WrapU_UU, "sceNetAdhocctlAddHandler", 'x', "xx" }, {0X6402490B, &WrapU_U, "sceNetAdhocctlDelHandler", 'x', "x" }, {0X34401D65, &WrapU_V, "sceNetAdhocctlDisconnect", 'x', "" }, - {0X0AD043ED, &WrapI_U, "sceNetAdhocctlConnect", 'i', "x" }, + {0X0AD043ED, &WrapI_C, "sceNetAdhocctlConnect", 'i', "s" }, {0X08FFF7A0, &WrapI_V, "sceNetAdhocctlScan", 'i', "" }, {0X75ECD386, &WrapI_U, "sceNetAdhocctlGetState", 'i', "x" }, {0X8916C003, &WrapI_CU, "sceNetAdhocctlGetNameByAddr", 'i', "sx" }, @@ -3806,7 +5521,7 @@ int sceNetAdhocDiscoverGetStatus() { return 0; } -int sceNetAdhocDiscoverRequestSuspend(void) +int sceNetAdhocDiscoverRequestSuspend() { ERROR_LOG(SCENET, "UNIMPL sceNetAdhocDiscoverRequestSuspend()"); return 0; @@ -3854,8 +5569,11 @@ void broadcastHelloMessage(SceNetAdhocMatchingContext * context) // Allocate Hello Message Buffer, reuse when necessary if ((int32_t)context->hellolen > len) { - hello = (uint8_t *)realloc(hello, 5 + context->hellolen); - len = context->hellolen; + uint8_t* tmp = (uint8_t *)realloc(hello, 5LL + context->hellolen); + if (tmp != NULL) { + hello = tmp; + len = context->hellolen; + } } // Allocated Hello Message Buffer @@ -3867,9 +5585,17 @@ void broadcastHelloMessage(SceNetAdhocMatchingContext * context) // Hello Data Length (have to memcpy this to avoid cpu alignment crash) memcpy(hello + 1, &context->hellolen, sizeof(context->hellolen)); + // FIXME: When using JPCSP + prx files the data being sent have a header of 12 bytes instead of 5 bytes: + // [01(always 1? size of the next data? or combined with next byte as U16_BE opcode?) 01(matching opcode, or combined with previous byte as U16_BE opcode?) 01 E0(size of next data + hello data in big-endian/U16_BE) 00 0F 42 40(U32_BE? time?) 00 0F 42 40(U32_BE? time?)], + // followed by hello data (0x1D8 bytes of opt data, based on Ys vs. Sora no Kiseki), and followed by 16 bytes of (optional?) footer [01 00 00 .. 00 00](footer doesn't exist if the size after opcode is 00 00) + // Copy Hello Data if (context->hellolen > 0) memcpy(hello + 5, context->hello, context->hellolen); + std::string hellohex; + DataToHexString(" ", 0, context->hello, context->hellolen, &hellohex); + DEBUG_LOG(SCENET, "HELLO Dump:\n%s", hellohex.c_str()); + // Send Broadcast context->socketlock->lock(); sceNetAdhocPdpSend(context->socket, (const char*)(SceNetEtherAddr *)broadcastMAC, context->port, hello, 5 + context->hellolen, 0, ADHOC_F_NONBLOCK); @@ -3905,7 +5631,7 @@ void sendAcceptPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * ma int siblingcount = siblingbuflen / sizeof(SceNetEtherAddr); // Allocate Accept Message Buffer - uint8_t * accept = (uint8_t *)malloc(9 + optlen + siblingbuflen); + uint8_t * accept = (uint8_t *)malloc(9LL + optlen + siblingbuflen); // Allocated Accept Message Buffer if (accept != NULL) @@ -3932,7 +5658,8 @@ void sendAcceptPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * ma int i = 0; // Iterate Peer List - SceNetAdhocMatchingMemberInternal * item = context->peerlist; for (; item != NULL; item = item->next) + SceNetAdhocMatchingMemberInternal * item = context->peerlist; + for (; item != NULL; item = item->next) { // Ignore Target if (item == peer) continue; @@ -3976,7 +5703,7 @@ void sendJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac, if (peer != NULL && peer->state == PSP_ADHOC_MATCHING_PEER_OUTGOING_REQUEST) { // Allocate Join Message Buffer - uint8_t * join = (uint8_t *)malloc(5 + optlen); + uint8_t * join = (uint8_t *)malloc(5LL + optlen); // Allocated Join Message Buffer if (join != NULL) @@ -4011,7 +5738,7 @@ void sendJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac, void sendCancelPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac, int optlen, void * opt) { // Allocate Cancel Message Buffer - uint8_t * cancel = (uint8_t *)malloc(5 + optlen); + uint8_t * cancel = (uint8_t *)malloc(5LL + optlen); // Allocated Cancel Message Buffer if (cancel != NULL) @@ -4073,7 +5800,7 @@ void sendBulkDataPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * //if (peer->sending == 0) return; // Allocate Send Message Buffer - uint8_t * send = (uint8_t *)malloc(5 + datalen); + uint8_t * send = (uint8_t *)malloc(5LL + datalen); // Allocated Send Message Buffer if (send != NULL) @@ -4127,7 +5854,8 @@ void sendBirthPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac memcpy(packet + 1, mac, sizeof(SceNetEtherAddr)); // Iterate Peers - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL; peer = peer->next) { // Skip Newborn Child if (peer == newborn) continue; @@ -4142,9 +5870,9 @@ void sendBirthPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac // Log Send Success if (sent >= 0) - INFO_LOG(SCENET, "InputLoop: Sending BIRTH to %02X:%02X:%02X:%02X:%02X:%02X", peer->mac.data[0], peer->mac.data[1], peer->mac.data[2], peer->mac.data[3], peer->mac.data[4], peer->mac.data[5]); + INFO_LOG(SCENET, "InputLoop: Sending BIRTH [%s] to %s", mac2str(mac).c_str(), mac2str(&peer->mac).c_str()); else - WARN_LOG(SCENET, "InputLoop: Failed to Send BIRTH to %02X:%02X:%02X:%02X:%02X:%02X", peer->mac.data[0], peer->mac.data[1], peer->mac.data[2], peer->mac.data[3], peer->mac.data[4], peer->mac.data[5]); + WARN_LOG(SCENET, "InputLoop: Failed to Send BIRTH [%s] to %s", mac2str(mac).c_str(), mac2str(&peer->mac).c_str()); } } } @@ -4166,27 +5894,39 @@ void sendDeathPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac // Packet Buffer uint8_t packet[7]; - // Set Opcode - packet[0] = PSP_ADHOC_MATCHING_PACKET_DEATH; - // Set abandoned Child MAC memcpy(packet + 1, mac, sizeof(SceNetEtherAddr)); // Iterate Peers - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL; peer = peer->next) { - // Skip dead Child - if (peer == deadkid) continue; + // Skip dead Child? Or May be we should also tells the disconnected Child, that they have been disconnected from the Host (in the case they were disconnected because they went to PPSSPP settings for too long) + if (peer == deadkid) { + // Set Opcode + packet[0] = PSP_ADHOC_MATCHING_PACKET_BYE; - // Send only to children + // Send Bye Packet + context->socketlock->lock(); + sceNetAdhocPdpSend(context->socket, (const char*)&peer->mac, context->port, packet, sizeof(packet[0]), 0, ADHOC_F_NONBLOCK); + context->socketlock->unlock(); + } + else + // Send to other children if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) { - // Send Packet + // Set Opcode + packet[0] = PSP_ADHOC_MATCHING_PACKET_DEATH; + + // Send Death Packet context->socketlock->lock(); sceNetAdhocPdpSend(context->socket, (const char*)&peer->mac, context->port, packet, sizeof(packet), 0, ADHOC_F_NONBLOCK); context->socketlock->unlock(); } } + + // Delete Peer + deletePeer(context, deadkid); } } @@ -4197,7 +5937,8 @@ void sendDeathPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac void sendByePacket(SceNetAdhocMatchingContext * context) { // Iterate Peers - SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for (; peer != NULL; peer = peer->next) + SceNetAdhocMatchingMemberInternal * peer = context->peerlist; + for (; peer != NULL; peer = peer->next) { // Peer of Interest if (peer->state == PSP_ADHOC_MATCHING_PEER_PARENT || peer->state == PSP_ADHOC_MATCHING_PEER_CHILD || peer->state == PSP_ADHOC_MATCHING_PEER_P2P) @@ -4227,7 +5968,7 @@ void actOnPingPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sen if (peer != NULL) { // Update Receive Timer - peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; + peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0; } } @@ -4279,18 +6020,24 @@ void actOnHelloPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * se peer->state = PSP_ADHOC_MATCHING_PEER_OFFER; // Initialize Ping Timer - peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; + peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0; + peerlock.lock(); // Link Peer into List peer->next = context->peerlist; context->peerlist = peer; + peerlock.unlock(); } } // Peer available now - if (peer != NULL) + if (peer != NULL && peer->state != PSP_ADHOC_MATCHING_PEER_OUTGOING_REQUEST && peer->state != PSP_ADHOC_MATCHING_PEER_INCOMING_REQUEST) { - // Spawn Hello Event + std::string hellohex; + DataToHexString(" ", 0, (u8*)opt, optlen, &hellohex); + DEBUG_LOG(SCENET, "HELLO Dump:\n%s", hellohex.c_str()); + + // Spawn Hello Event. FIXME: HELLO event should not be triggered in the middle of joining? This will cause Bleach 7 to Cancel the join request spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_HELLO, sendermac, optlen, opt); } } @@ -4333,7 +6080,10 @@ void actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sen // If we got the peer in the table already and are a parent, there is nothing left to be done. // This is because the only way a parent can know of a child is via a join request... // If we thus know of a possible child, then we already had a previous join request thus no need for double tapping. - if (peer != NULL && context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) return; + if (peer != NULL && peer->lastping != 0 && context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) { + WARN_LOG(SCENET, "Join Event(2) Ignored"); + return; + } // New Peer if (peer == NULL) @@ -4354,11 +6104,13 @@ void actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sen peer->state = PSP_ADHOC_MATCHING_PEER_INCOMING_REQUEST; // Initialize Ping Timer - peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; + peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0; + peerlock.lock(); // Link Peer into List peer->next = context->peerlist; context->peerlist = peer; + peerlock.unlock(); // Spawn Request Event spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_REQUEST, sendermac, optlen, opt); @@ -4374,6 +6126,9 @@ void actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sen // Set Peer State peer->state = PSP_ADHOC_MATCHING_PEER_INCOMING_REQUEST; + // Initialize Ping Timer + peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); + // Spawn Request Event spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_REQUEST, sendermac, optlen, opt); @@ -4383,7 +6138,7 @@ void actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sen } } } - INFO_LOG(SCENET, "Join Event(2) Rejected"); + WARN_LOG(SCENET, "Join Event(2) Rejected"); // Auto-Reject Player sendCancelPacket(context, sendermac, 0, NULL); } @@ -4413,7 +6168,7 @@ void actOnAcceptPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * s int siblingcount = 0; memcpy(&siblingcount, context->rxbuf + 5, sizeof(siblingcount)); // Complete Valid Packet available - if (optlen >= 0 && length >= (9 + optlen + sizeof(SceNetEtherAddr) * siblingcount)) + if (optlen >= 0 && length >= (9LL + optlen + static_cast(sizeof(SceNetEtherAddr)) * siblingcount)) { // Set Default Null Data void * opt = NULL; @@ -4446,7 +6201,13 @@ void actOnAcceptPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * s postAcceptCleanPeerList(context); // Add Sibling Peers - if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD) postAcceptAddSiblings(context, siblingcount, siblings); + if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD) { + // Add existing siblings + postAcceptAddSiblings(context, siblingcount, siblings); + + // Add Self Peer to the following position (using peer->state = 0 to identify as Self) + addMember(context, &context->mac); + } // IMPORTANT! The Event Order here is ok! // Internally the Event Stack appends to the front, so the order will be switched around. @@ -4475,15 +6236,6 @@ void actOnCancelPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * s // Find Peer SceNetAdhocMatchingMemberInternal * peer = findPeer(context, sendermac); - // Get Parent - SceNetAdhocMatchingMemberInternal * parent = findParent(context); - - // Get Outgoing Join Request - SceNetAdhocMatchingMemberInternal * request = findOutgoingRequest(context); - - // Get P2P Partner - SceNetAdhocMatchingMemberInternal * p2p = findP2P(context); - // Interest Condition fulfilled if (peer != NULL) { @@ -4502,9 +6254,15 @@ void actOnCancelPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * s // Extract Optional Data Pointer if (optlen > 0) opt = context->rxbuf + 5; + // Get Outgoing Join Request + SceNetAdhocMatchingMemberInternal* request = findOutgoingRequest(context); + // Child Mode if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD) { + // Get Parent + SceNetAdhocMatchingMemberInternal* parent = findParent(context); + // Join Request denied if (request == peer) { @@ -4519,7 +6277,8 @@ void actOnCancelPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * s else if (parent == peer) { // Iterate Peers - SceNetAdhocMatchingMemberInternal * item = context->peerlist; for (; item != NULL; item = item->next) + SceNetAdhocMatchingMemberInternal * item = context->peerlist; + for (; item != NULL; item = item->next) { // Established Peer if (item->state == PSP_ADHOC_MATCHING_PEER_CHILD || item->state == PSP_ADHOC_MATCHING_PEER_PARENT) @@ -4561,6 +6320,9 @@ void actOnCancelPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * s // P2P Mode else { + // Get P2P Partner + SceNetAdhocMatchingMemberInternal* p2p = findP2P(context); + // Join Request denied if (request == peer) { @@ -4653,7 +6415,7 @@ void actOnBirthPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * se SceNetEtherAddr mac; memcpy(&mac, context->rxbuf + 1, sizeof(SceNetEtherAddr)); - // Allocate Memory (If this fails... we are fucked.) + // Allocate Memory SceNetAdhocMatchingMemberInternal * sibling = (SceNetAdhocMatchingMemberInternal *)malloc(sizeof(SceNetAdhocMatchingMemberInternal)); // Allocated Memory @@ -4669,20 +6431,18 @@ void actOnBirthPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * se sibling->state = PSP_ADHOC_MATCHING_PEER_CHILD; // Initialize Ping Timer - sibling->lastping = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; + sibling->lastping = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0; peerlock.lock(); - peer->lastping = sibling->lastping; - // Link Peer sibling->next = context->peerlist; context->peerlist = sibling; peerlock.unlock(); - // Spawn Established Event - spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL); + // Spawn Established Event. FIXME: ESTABLISHED event should only be triggered for Parent/P2P peer? + //spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL); } } } @@ -4743,26 +6503,22 @@ void actOnByePacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * send (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD && peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) || (context->mode == PSP_ADHOC_MATCHING_MODE_P2P && peer->state == PSP_ADHOC_MATCHING_PEER_P2P)) { - // Spawn Leave / Kick Event - spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_BYE, sendermac, 0, NULL); + if (context->mode != PSP_ADHOC_MATCHING_MODE_CHILD) { + // Spawn Leave / Kick Event. FIXME: DISCONNECT event should only be triggered on Parent/P2P mode and for Parent/P2P peer? + spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_BYE, sendermac, 0, NULL); + } // Delete Peer deletePeer(context, peer); + // Instead of removing peer immediately, We should give a little time before removing the peer and let it timed out? just in case the game is in the middle of communicating with the peer on another thread so it won't recognize it as Unknown peer + //peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); } // Parent Bye else if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD && peer->state == PSP_ADHOC_MATCHING_PEER_PARENT) { - // Iterate Peers - SceNetAdhocMatchingMemberInternal * item = context->peerlist; for (; item != NULL; item = item->next) - { - // Established Peer - if (item->state == PSP_ADHOC_MATCHING_PEER_CHILD || item->state == PSP_ADHOC_MATCHING_PEER_PARENT) - { - // Spawn Leave / Kick Event - spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_BYE, &item->mac, 0, NULL); - } - } + // Spawn Leave / Kick Event. FIXME: DISCONNECT event should only be triggered on Parent/P2P mode and for Parent/P2P peer? + spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_BYE, sendermac, 0, NULL); // Delete Peer from List clearPeerList(context); @@ -4779,9 +6535,7 @@ void actOnByePacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * send */ int matchingEventThread(int matchingId) { - u32 bufLen = 0; - u32 bufAddr = 0; - + setCurrentThreadName("MatchingEvent"); // Multithreading Lock peerlock.lock(); // Cast Context @@ -4794,59 +6548,78 @@ int matchingEventThread(int matchingId) // Run while needed... if (context != NULL) { - //static u32_le args[5] = { 0, 0, 0, 0, 0 }; // Need to be global/static so it can be accessed from a different thread - u32_le * args = context->handlerArgs; + u32 bufLen = context->rxbuflen; //0; + u32 bufAddr = 0; //= userMemory.Alloc(bufLen); //context->rxbuf; + u32_le * args = context->handlerArgs; //MatchingArgs - while (context->eventRunning) // (context->eventThread.get_id() != NULL) + while (contexts != NULL && context->eventRunning) { + // Multithreading Lock + peerlock.lock(); + // Cast Context + context = findMatchingContext(matchingId); + // Multithreading Unlock + peerlock.unlock(); + // Messages on Stack ready for processing - if (context->event_stack != NULL) + if (context != NULL && context->event_stack != NULL) { // Claim Stack context->eventlock->lock(); // Iterate Message List - ThreadMessage * msg = context->event_stack; for (; msg != NULL; msg = msg->next) + ThreadMessage * msg = context->event_stack; + if (msg != NULL) { // Default Optional Data - void * opt = NULL; + void* opt = NULL; // Grab Optional Data - if (msg->optlen > 0) opt = ((u8 *)msg) + sizeof(ThreadMessage); //&msg[1] + if (msg->optlen > 0) opt = ((u8*)msg) + sizeof(ThreadMessage); //&msg[1] // Log Matching Events - INFO_LOG(SCENET, "EventLoop[%d]: Matching Event [%d=%s] OptSize=%d", matchingId, msg->opcode, getMatchingEventStr(msg->opcode), msg->optlen); + INFO_LOG(SCENET, "EventLoop[%d]: Matching Event [%d=%s][%s] OptSize=%d", matchingId, msg->opcode, getMatchingEventStr(msg->opcode), mac2str(&msg->mac).c_str(), msg->optlen); - context->eventlock->unlock(); // Unlock to prevent race-condition with other threads due to recursive lock + // Unlock to prevent race-condition with other threads due to recursive lock + //context->eventlock->unlock(); // Call Event Handler //context->handler(context->id, msg->opcode, &msg->mac, msg->optlen, opt); // Notify Event Handlers - notifyMatchingHandler(context, msg, opt, bufAddr, bufLen, args); - context->eventlock->lock(); // Lock again + notifyMatchingHandler(context, msg, opt, bufAddr, bufLen, args); // If we're using shared Buffer & Args for All Events We should wait for the Mipscall to be fully executed before processing the next event. GTA VCS need this delay/sleep. + + // Give some time before executing the next mipscall to prevent event ACCEPT(6)->ESTABLISH(7) getting reversed After Action ESTABLISH(7)->ACCEPT(6) + // Must Not be delayed too long to prevent desync/disconnect. Not longer than the delays on callback's HLE? + //sleep_ms(10); //sceKernelDelayThread(10000); + + // Lock again + //context->eventlock->lock(); + + // Pop event stack from front (this should be queue instead of stack?) + context->event_stack = msg->next; + free(msg); + msg = NULL; } - // Clear Event Message Stack - clearStack(context, PSP_ADHOC_MATCHING_EVENT_STACK); - - // Free Stack + // Unlock Stack context->eventlock->unlock(); } // Share CPU Time - sleep_ms(1); //10 //sceKernelDelayThread(10000); + sleep_ms(10); //1 //sceKernelDelayThread(10000); // Don't do anything if it's paused, otherwise the log will be flooded - while (Core_IsStepping() && context->eventRunning) sleep_ms(1); + while (Core_IsStepping() && coreState != CORE_POWERDOWN && contexts != NULL && context->eventRunning) sleep_ms(10); } // Process Last Messages - if (context->event_stack != NULL) + if (contexts != NULL && context->event_stack != NULL) { // Claim Stack context->eventlock->lock(); // Iterate Message List - ThreadMessage * msg = context->event_stack; for (; msg != NULL; msg = msg->next) + ThreadMessage * msg = context->event_stack; + for (; msg != NULL; msg = msg->next) { // Default Optional Data void * opt = NULL; @@ -4856,12 +6629,12 @@ int matchingEventThread(int matchingId) INFO_LOG(SCENET, "EventLoop[%d]: Matching Event [EVENT=%d]\n", matchingId, msg->opcode); - context->eventlock->unlock(); + //context->eventlock->unlock(); // Original Call Event Handler //context->handler(context->id, msg->opcode, &msg->mac, msg->optlen, opt); // Notify Event Handlers notifyMatchingHandler(context, msg, opt, bufAddr, bufLen, args); - context->eventlock->lock(); + //context->eventlock->lock(); } // Clear Event Message Stack @@ -4871,6 +6644,9 @@ int matchingEventThread(int matchingId) context->eventlock->unlock(); } + // Free memory + //if (Memory::IsValidAddress(bufAddr)) userMemory.Free(bufAddr); + // Delete Pointer Reference (and notify caller about finished cleanup) //context->eventThread = NULL; } @@ -4878,10 +6654,7 @@ int matchingEventThread(int matchingId) // Log Shutdown INFO_LOG(SCENET, "EventLoop: End of EventLoop[%i] Thread", matchingId); - // Free memory - if (Memory::IsValidAddress(bufAddr)) userMemory.Free(bufAddr); - - // Return Zero to shut up Compiler (never reached anyway) + // Return Zero to shut up Compiler return 0; } @@ -4891,12 +6664,13 @@ int matchingEventThread(int matchingId) * @param argp SceNetAdhocMatchingContext * * @return Exit Point is never reached... */ -int matchingInputThread(int matchingId) +int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is using sceNetAdhocPdpRecv & sceNetAdhocPdpSend functions so it might be better to run this on PSP thread instead of real thread { + setCurrentThreadName("MatchingInput"); // Multithreading Lock peerlock.lock(); // Cast Context - SceNetAdhocMatchingContext * context = findMatchingContext(matchingId); + SceNetAdhocMatchingContext* context = findMatchingContext(matchingId); // Multithreading Unlock peerlock.unlock(); @@ -4908,162 +6682,190 @@ int matchingInputThread(int matchingId) u64_le now; + static SceNetEtherAddr sendermac; + static uint16_t senderport; + static int rxbuflen; + // Log Startup INFO_LOG(SCENET, "InputLoop: Begin of InputLoop[%i] Thread", matchingId); // Run while needed... if (context != NULL) { - while (context->inputRunning) + while (contexts != NULL && context->inputRunning) { - now = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0; + // Multithreading Lock + peerlock.lock(); + // Cast Context + context = findMatchingContext(matchingId); + // Multithreading Unlock + peerlock.unlock(); - // Hello Message Sending Context with unoccupied Slots - if ((context->mode == PSP_ADHOC_MATCHING_MODE_PARENT && (countChildren(context) < (context->maxpeers - 1))) || (context->mode == PSP_ADHOC_MATCHING_MODE_P2P && findP2P(context) == NULL)) - { - // Hello Message Broadcast necessary because of Hello Interval - if (context->hello_int > 0) - if ((now - lasthello) >= context->hello_int) + if (context != NULL) { + now = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0; + + // Hello Message Sending Context with unoccupied Slots + if ((context->mode == PSP_ADHOC_MATCHING_MODE_PARENT && (countChildren(context) < (context->maxpeers - 1))) || (context->mode == PSP_ADHOC_MATCHING_MODE_P2P && findP2P(context) == NULL)) { - // Broadcast Hello Message - broadcastHelloMessage(context); + // Hello Message Broadcast necessary because of Hello Interval + if (context->hello_int > 0) + if ((now - lasthello) >= context->hello_int) + { + // Broadcast Hello Message + broadcastHelloMessage(context); - // Update Hello Timer - lasthello = now; + // Update Hello Timer + lasthello = now; + } } - } - // Ping Required - if (context->keepalive_int > 0) - if ((now - lastping) >= context->keepalive_int) - { - // Broadcast Ping Message - broadcastPingMessage(context); + // Ping Required + if (context->keepalive_int > 0) + if ((now - lastping) >= context->keepalive_int) + { + // Broadcast Ping Message + broadcastPingMessage(context); - // Update Ping Timer - lastping = now; - } + // Update Ping Timer + lastping = now; + } - // Messages on Stack ready for processing - if (context->input_stack != NULL) - { - // Claim Stack - context->inputlock->lock(); - - // Iterate Message List - ThreadMessage * msg = context->input_stack; - for (; msg != NULL; msg = msg->next) + // Messages on Stack ready for processing + if (context->input_stack != NULL) { - // Default Optional Data - void * opt = NULL; + // Claim Stack + context->inputlock->lock(); - // Grab Optional Data - if (msg->optlen > 0) opt = ((u8 *)msg) + sizeof(ThreadMessage); + // Iterate Message List + ThreadMessage* msg = context->input_stack; + while (msg != NULL) + { + // Default Optional Data + void* opt = NULL; - context->inputlock->unlock(); // Unlock to prevent race condition when locking peerlock + // Grab Optional Data + if (msg->optlen > 0) opt = ((u8*)msg) + sizeof(ThreadMessage); - // Send Accept Packet - if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_ACCEPT) sendAcceptPacket(context, &msg->mac, msg->optlen, opt); + //context->inputlock->unlock(); // Unlock to prevent race condition when locking peerlock - // Send Join Packet - else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_JOIN) sendJoinPacket(context, &msg->mac, msg->optlen, opt); + // Send Accept Packet + if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_ACCEPT) sendAcceptPacket(context, &msg->mac, msg->optlen, opt); - // Send Cancel Packet - else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_CANCEL) sendCancelPacket(context, &msg->mac, msg->optlen, opt); + // Send Join Packet + else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_JOIN) sendJoinPacket(context, &msg->mac, msg->optlen, opt); - // Send Bulk Data Packet - else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_BULK) sendBulkDataPacket(context, &msg->mac, msg->optlen, opt); + // Send Cancel Packet + else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_CANCEL) sendCancelPacket(context, &msg->mac, msg->optlen, opt); - // Send Birth Packet - else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_BIRTH) sendBirthPacket(context, &msg->mac); + // Send Bulk Data Packet + else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_BULK) sendBulkDataPacket(context, &msg->mac, msg->optlen, opt); - // Cancel Bulk Data Transfer (does nothing as of now as we fire and forget anyway) // Do we need to check DeathPacket and BytePacket here? - // else if(msg->opcode == PSP_ADHOC_MATCHING_PACKET_BULK_ABORT) blabla; + // Send Birth Packet + else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_BIRTH) sendBirthPacket(context, &msg->mac); - context->inputlock->lock(); // Lock again + // Send Death Packet + else if (msg->opcode == PSP_ADHOC_MATCHING_PACKET_DEATH) sendDeathPacket(context, &msg->mac); + + // Cancel Bulk Data Transfer (does nothing as of now as we fire and forget anyway) // Do we need to check DeathPacket and ByePacket here? + //else if(msg->opcode == PSP_ADHOC_MATCHING_PACKET_BULK_ABORT) sendAbortBulkDataPacket(context, &msg->mac, msg->optlen, opt); + + //context->inputlock->lock(); // Lock again + + // Pop input stack from front (this should be queue instead of stack?) + context->input_stack = msg->next; + free(msg); + msg = context->input_stack; + } + + // Free Stack + context->inputlock->unlock(); } - // Clear IO Message Stack - clearStack(context, PSP_ADHOC_MATCHING_INPUT_STACK); + // Receive PDP Datagram + // FIXME: When using JPCSP + prx files, the "SceNetAdhocMatchingInput" thread is using blocking PdpRecv with infinite(0) timeout, which can be stopped/aborted using SetSocketAlert, while "SceNetAdhocMatchingEvent" thread is using non-blocking for sending + rxbuflen = context->rxbuflen; + senderport = 0; + context->socketlock->lock(); + int recvresult = sceNetAdhocPdpRecv(context->socket, &sendermac, &senderport, context->rxbuf, &rxbuflen, 0, ADHOC_F_NONBLOCK); + context->socketlock->unlock(); - // Free Stack - context->inputlock->unlock(); + // Received Data from a Sender that interests us + if (recvresult == 0 && rxbuflen > 0 && context->port == senderport) + { + // Log Receive Success + if (context->rxbuf[0] > 1) { + INFO_LOG(SCENET, "InputLoop[%d]: Received %d Bytes (Opcode[%d]=%s)", matchingId, rxbuflen, context->rxbuf[0], getMatchingOpcodeStr(context->rxbuf[0])); + } + + // Update Peer Timestamp + peerlock.lock(); + SceNetAdhocctlPeerInfo* peer = findFriend(&sendermac); + if (peer != NULL) { + now = CoreTiming::GetGlobalTimeUsScaled(); + u64_le delta = now - peer->last_recv; + DEBUG_LOG(SCENET, "Timestamp Delta: %llu (%llu - %llu) from %s", delta, now, peer->last_recv, mac2str(&sendermac).c_str()); + if (/*context->rxbuf[0] > 0 &&*/ peer->last_recv != 0) peer->last_recv = now - 1; // - context->keepalive_int; // May need to deduce by ping interval to prevent Dissidia 012 unable to see other players (ie. disappearing issue) + } + else { + WARN_LOG(SCENET, "InputLoop[%d]: Unknown Peer[%s:%u] (Recved=%i, Length=%i)", matchingId, mac2str(&sendermac).c_str(), senderport, recvresult, rxbuflen); + } + peerlock.unlock(); + + // Ping Packet + if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_PING) actOnPingPacket(context, &sendermac); + + // Hello Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_HELLO) actOnHelloPacket(context, &sendermac, rxbuflen); + + // Join Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_JOIN) actOnJoinPacket(context, &sendermac, rxbuflen); + + // Accept Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_ACCEPT) actOnAcceptPacket(context, &sendermac, rxbuflen); + + // Cancel Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_CANCEL) actOnCancelPacket(context, &sendermac, rxbuflen); + + // Bulk Data Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_BULK) actOnBulkDataPacket(context, &sendermac, rxbuflen); + + // Abort Bulk Data Packet + //else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_BULK_ABORT) actOnAbortBulkDataPacket(context, &sendermac, rxbuflen); + + // Birth Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_BIRTH) actOnBirthPacket(context, &sendermac, rxbuflen); + + // Death Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_DEATH) actOnDeathPacket(context, &sendermac, rxbuflen); + + // Bye Packet + else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_BYE) actOnByePacket(context, &sendermac); + + // Ignore Incoming Trash Data + } + + // Handle Peer Timeouts + handleTimeout(context); } - - // Receive PDP Datagram - SceNetEtherAddr sendermac; - uint16_t senderport; - int rxbuflen = context->rxbuflen; - context->socketlock->lock(); - int recvresult = sceNetAdhocPdpRecv(context->socket, &sendermac, &senderport, context->rxbuf, &rxbuflen, 0, ADHOC_F_NONBLOCK); - context->socketlock->unlock(); - - // Received Data from a Sender that interests us - if (recvresult == 0 && rxbuflen > 0 && context->port == senderport) - { - // Log Receive Success - if (context->rxbuf[0] > 1) { - INFO_LOG(SCENET, "InputLoop[%d]: Received %d Bytes (Opcode[%d]=%s)", matchingId, rxbuflen, context->rxbuf[0], getMatchingOpcodeStr(context->rxbuf[0])); - } - - // Update Peer Timestamp - peerlock.lock(); - SceNetAdhocctlPeerInfo * peer = findFriend(&sendermac); - if (peer != NULL) { - now = CoreTiming::GetGlobalTimeUsScaled(); - u64_le delta = now - peer->last_recv; - DEBUG_LOG(SCENET, "Timestamp Delta: %llu (%llu - %llu)", delta, now, peer->last_recv); - if (/*context->rxbuf[0] > 0 &&*/ peer->last_recv != 0) peer->last_recv = now; // - context->keepalive_int; // May need to deduce by ping interval to prevent Dissidia 012 unable to see other players (ie. disappearing issue) - } - peerlock.unlock(); - - // Ping Packet - if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_PING) actOnPingPacket(context, &sendermac); - - // Hello Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_HELLO) actOnHelloPacket(context, &sendermac, rxbuflen); - - // Join Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_JOIN) actOnJoinPacket(context, &sendermac, rxbuflen); - - // Accept Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_ACCEPT) actOnAcceptPacket(context, &sendermac, rxbuflen); - - // Cancel Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_CANCEL) actOnCancelPacket(context, &sendermac, rxbuflen); - - // Bulk Data Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_BULK) actOnBulkDataPacket(context, &sendermac, rxbuflen); - - // Birth Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_BIRTH) actOnBirthPacket(context, &sendermac, rxbuflen); - - // Death Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_DEATH) actOnDeathPacket(context, &sendermac, rxbuflen); - - // Bye Packet - else if (context->rxbuf[0] == PSP_ADHOC_MATCHING_PACKET_BYE) actOnByePacket(context, &sendermac); - - // Ignore Incoming Trash Data - } - - // Handle Peer Timeouts - handleTimeout(context); - // Share CPU Time - sleep_ms(1); //10 //sceKernelDelayThread(10000); + sleep_ms(10); //1 //sceKernelDelayThread(10000); // Don't do anything if it's paused, otherwise the log will be flooded - while (Core_IsStepping() && context->inputRunning) sleep_ms(1); + while (Core_IsStepping() && coreState != CORE_POWERDOWN && contexts != NULL && context->inputRunning) sleep_ms(10); } - // Send Bye Messages - sendByePacket(context); + if (contexts != NULL) { + // Clear IO Message Stack + clearStack(context, PSP_ADHOC_MATCHING_INPUT_STACK); - // Free Peer List Buffer - clearPeerList(context); //deleteAllMembers(context); + // Send Bye Messages + sendByePacket(context); - // Delete Pointer Reference (and notify caller about finished cleanup) - //context->inputThread = NULL; + // Free Peer List Buffer + clearPeerList(context); //deleteAllMembers(context); + + // Delete Pointer Reference (and notify caller about finished cleanup) + //context->inputThread = NULL; + } } // Log Shutdown @@ -5072,6 +6874,6 @@ int matchingInputThread(int matchingId) // Terminate Thread //sceKernelExitDeleteThread(0); - // Return Zero to shut up Compiler (never reached anyway) + // Return Zero to shut up Compiler return 0; } diff --git a/Core/HLE/sceNetAdhoc.h b/Core/HLE/sceNetAdhoc.h index 829c973ebd..0ec9218bb5 100644 --- a/Core/HLE/sceNetAdhoc.h +++ b/Core/HLE/sceNetAdhoc.h @@ -17,21 +17,97 @@ #pragma once +#include +#include "Core/HLE/proAdhoc.h" + +#ifdef _MSC_VER +#pragma pack(push,1) +#endif +typedef struct MatchingArgs { + u32_le data[6]; //ContextID, Opcode, bufAddr[ to MAC], OptLen, OptAddr[, EntryPoint] +} PACK MatchingArgs; +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +struct AdhocctlRequest { + u8 opcode; + SceNetAdhocctlGroupName group; +}; + +struct AdhocSendTarget { + u32 ip; + u16 port; // original port +}; + +struct AdhocSendTargets { + int length; + std::deque peers; + bool isBroadcast; +}; + +struct AdhocSocketRequest { + int type; + int id; // PDP/PTP socket id + void* buffer; + s32_le* length; + u32 timeout; + u64 startTime; + SceNetEtherAddr* remoteMAC; + u16_le* remotePort; +}; + +enum AdhocSocketRequestType : int +{ + PTP_CONNECT = 0, + PTP_ACCEPT = 1, + PTP_SEND = 2, + PTP_RECV = 3, + PTP_FLUSH = 4, + PDP_SEND = 5, + PDP_RECV = 6, + ADHOC_POLL_SOCKET = 7, +}; + class PointerWrap; void Register_sceNetAdhoc(); +u32_le __CreateHLELoop(u32_le* loopAddr, const char* sceFuncName, const char* hleFuncName, const char* tagName = NULL); void __NetAdhocInit(); void __NetAdhocShutdown(); void __NetAdhocDoState(PointerWrap &p); void __UpdateAdhocctlHandlers(u32 flags, u32 error); -void __UpdateMatchingHandler(u64 params); +void __UpdateMatchingHandler(MatchingArgs params); // I have to call this from netdialog +int sceNetAdhocctlGetState(u32 ptrToStatus); int sceNetAdhocctlCreate(const char * groupName); +int sceNetAdhocctlConnect(const char* groupName); +int sceNetAdhocctlJoin(u32 scanInfoAddr); +int sceNetAdhocctlScan(); +int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr); + +int NetAdhocMatching_Term(); +int NetAdhocctl_Term(); +int NetAdhocctl_GetState(); +int NetAdhocctl_Create(const char* groupName); +int NetAdhoc_Term(); // May need to use these from sceNet.cpp extern bool netAdhocInited; extern bool netAdhocctlInited; -int sceNetAdhocctlTerm(); -int sceNetAdhocTerm(); +extern bool networkInited; +extern int adhocDefaultTimeout; +extern int adhocExtraPollDelayMS; +extern int adhocEventPollDelayMS; +extern int adhocMatchingEventDelayMS; +extern int adhocEventDelayMS; // This will affect the duration of "Connecting..." dialog/message box in .Hack//Link and Naruto Ultimate Ninja Heroes 3 +extern std::recursive_mutex adhocEvtMtx; +extern int IsAdhocctlInCB; + +extern u32 dummyThreadHackAddr; +extern u32_le dummyThreadCode[3]; +extern u32 matchingThreadHackAddr; +extern u32_le matchingThreadCode[3]; + diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index a8a926c72d..cd0fc9a26b 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -18,28 +18,129 @@ // This is pretty much a stub implementation. Doesn't actually do anything, just tries to return values // to keep games happy anyway. +#include +#include +#include +#include +#include "Core/MemMapHelpers.h" +#include #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceNp.h" +#include -static int sceNp_857B47D3() + +bool npAuthInited = false; +SceNpAuthMemoryStat npAuthMemStat = {}; +std::string serviceId = ""; + +int parentalControl = PARENTAL_CONTROL_ENABLED; +int userAge = 24; // faking user Age to 24 yo +int chatRestriction = 0; // default/initial value on Patapon 3 is 1 (restricted boolean?) +std::string onlineId = "DummyOnlineId"; +std::string avatarUrl = "http://DummyAvatarUrl"; + +std::recursive_mutex npAuthEvtMtx; +std::deque npAuthEvents; +std::map npAuthHandlers; + + +// Tickets data are in big-endian based on captured packets +int writeTicketParam(u8* buffer, const u16_be type, const char* data = nullptr, const u16_be size = 0) { + if (buffer == nullptr) return 0; + + u16_be sz = (data == nullptr)? static_cast(0): size; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + if (sz>0) memcpy(buffer + 4, data, sz); + + return sz + 4; +} + +int writeTicketStringParam(u8* buffer, const u16_be type, const char* data = nullptr, const u16_be size = 0) { + if (buffer == nullptr) return 0; + + u16_be sz = (data == nullptr) ? static_cast(0) : size; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + if (sz > 0) { + memset(buffer + 4, 0, sz); + truncate_cpy((char*)buffer + 4, sz, data); + } + return sz + 4; +} + +int writeTicketU32Param(u8* buffer, const u16_be type, const u32_be data) { + if (buffer == nullptr) return 0; + + u16_be sz = 4; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + memcpy(buffer + 4, &data, 4); + + return sz + 4; +} + +int writeTicketU64Param(u8* buffer, const u16_be type, const u64_be data) { + if (buffer == nullptr) return 0; + + u16_be sz = 8; + memcpy(buffer, &type, 2); + memcpy(buffer + 2, &sz, 2); + memcpy(buffer + 4, &data, sz); + + return sz + 4; +} + +void notifyNpAuthHandlers(u32 id, u32 result, u32 argAddr) { + std::lock_guard npAuthGuard(npAuthEvtMtx); + npAuthEvents.push_back({ id, result, argAddr }); +} + +static int sceNpInit() { - // No parameters - ERROR_LOG(HLE, "UNIMPL sceNp_857B47D3()"); + ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); return 0; } -static int sceNp_37E1E274() +static int sceNpTerm() { // No parameters - ERROR_LOG(HLE, "UNIMPL sceNp_37E1E274()"); + ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + return 0; +} + +static int sceNpGetContentRatingFlag(u32 parentalControlAddr, u32 userAgeAddr) +{ + WARN_LOG(HLE, "UNTESTED %s(%08x, %08x)", __FUNCTION__, parentalControlAddr, userAgeAddr); + + if (!Memory::IsValidAddress(parentalControlAddr) || !Memory::IsValidAddress(userAgeAddr)) + return hleLogError(HLE, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + Memory::Write_U32(parentalControl, parentalControlAddr); + Memory::Write_U32(userAge, userAgeAddr); + + return 0; +} + +static int sceNpGetChatRestrictionFlag(u32 flagAddr) +{ + WARN_LOG(HLE, "UNTESTED %s(%08x)", __FUNCTION__, flagAddr); + + if (!Memory::IsValidAddress(flagAddr)) + return hleLogError(HLE, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + Memory::Write_U32(chatRestriction, flagAddr); + return 0; } const HLEFunction sceNp[] = { - {0X857B47D3, &WrapI_V, "sceNp_857B47D3", 'i', "" }, - {0X37E1E274, &WrapI_V, "sceNp_37E1E274", 'i', "" }, + {0X857B47D3, &WrapI_V, "sceNpInit", 'i', "" }, + {0X37E1E274, &WrapI_V, "sceNpTerm", 'i', "" }, + {0XBB069A87, &WrapI_UU, "sceNpGetContentRatingFlag", 'i', "xx" }, + {0X1D60AE4B, &WrapI_U, "sceNpGetChatRestrictionFlag", 'i', "x" }, }; void Register_sceNp() @@ -47,22 +148,210 @@ void Register_sceNp() RegisterModule("sceNp", ARRAY_SIZE(sceNp), sceNp); } -static int sceNpAuth_4EC1F667() +static int sceNpAuthTerm() { // No parameters - ERROR_LOG(HLE, "UNIMPL sceNpAuth_4EC1F667()"); + ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + npAuthInited = false; return 0; } -static int sceNpAuth_A1DE86F8(u32 poolSize, u32 stackSize, u32 threadPrio) +static int sceNpAuthInit(u32 poolSize, u32 stackSize, u32 threadPrio) { - ERROR_LOG(HLE, "UNIMPL sceNpAuth_A1DE86F8(%08x, %08x, %08x)",poolSize, stackSize, threadPrio); + ERROR_LOG(HLE, "UNIMPL %s(%d, %d, %d)", __FUNCTION__, poolSize, stackSize, threadPrio); + npAuthMemStat.npMemSize = poolSize; + npAuthMemStat.npMaxMemSize = poolSize / 2; // Dummy + npAuthMemStat.npFreeMemSize = poolSize - 16; // Dummy. + npAuthEvents.clear(); + + npAuthInited = true; return 0; } +static int sceNpAuthGetMemoryStat(u32 memStatAddr) +{ + ERROR_LOG(HLE, "UNIMPL %s(%08x)", __FUNCTION__, memStatAddr); + + if (!Memory::IsValidAddress(memStatAddr)) + return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + + Memory::WriteStruct(memStatAddr, &npAuthMemStat); + + return 0; +} + +/* +"Authenticating matching server usage license" on Patapon 3. Could be waiting for a state change for eternity? probably need to trigger a callback handler? +TODO: Login to "https://auth.np.ac.playstation.net/nav/auth" based on https://www.psdevwiki.com/ps3/Online_Connections +param seems to be a struct where offset: + +00: 32-bit is the size of the struct (ie. 36 bytes), + +04: 32-bit is also a small number (ie. 3) a mode/event/flag/version may be?, + +08: 32-bit is a pointer to a productId? (ie. "EP9000-UCES01421_00"), + +0C: 4x 32-bit reserved? all zero + +1C: 32-bit callback handler? optional handler? seems to be a valid pointer and pointing to a starting point of a function (have a label on the disassembly) + +20: 32-bit a pointer to a random data (4 to 8-bytes data max? both 2x 32-bit seems to be a valid pointer). optional handler args? +return value >= 0 and <0 seems to be stored at a different location by the game (valid result vs error code?) +*/ +static int sceNpAuthCreateStartRequest(u32 paramAddr) +{ + WARN_LOG(HLE, "UNTESTED %s(%08x) at %08x", __FUNCTION__, paramAddr, currentMIPS->pc); + + if (!Memory::IsValidAddress(paramAddr)) + return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + + SceNpAuthRequestParameter params = {}; + int size = Memory::Read_U32(paramAddr); + Memory::Memcpy(¶ms, paramAddr, size); + serviceId = Memory::GetCharPointer(params.serviceIdAddr); + + INFO_LOG(HLE, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor); + INFO_LOG(HLE, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr)); + INFO_LOG(HLE, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr)); + INFO_LOG(HLE, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr)); + + u32 retval = 0; + if (params.size >= 32 && params.ticketCbAddr != 0) { + bool foundHandler = false; + + struct NpAuthHandler handler; + memset(&handler, 0, sizeof(handler)); + + while (npAuthHandlers.find(retval) != npAuthHandlers.end()) + ++retval; + + handler.entryPoint = params.ticketCbAddr; + handler.argument = params.cbArgAddr; + + for (std::map::iterator it = npAuthHandlers.begin(); it != npAuthHandlers.end(); it++) { + if (it->second.entryPoint == handler.entryPoint) { + foundHandler = true; + retval = it->first; + break; + } + } + + if (!foundHandler && Memory::IsValidAddress(handler.entryPoint)) { + npAuthHandlers[retval] = handler; + WARN_LOG(SCENET, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, retval); + } + else { + ERROR_LOG(SCENET, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); + } + // Patapon 3 will only Abort & Destroy AuthRequest if the ID is larger than 0. Is 0 a valid request id? + retval++; + + // 1st Arg usually either an ID returned from Create/AddHandler function or an Event ID if the game is expecting a sequence of events. + // 2nd Arg seems to be used if not a negative number and exits the handler if it's negative (error code?) + // 3rd Arg seems to be a data (ie. 92 bytes of data?) pointer and tested for null within callback handler (optional callback args?) + u32 ticketLength = 248; // default ticket length? should be updated using the ticket length returned from login + notifyNpAuthHandlers(retval, ticketLength, (params.size >= 36) ? params.cbArgAddr : 0); + } + + //hleDelayResult(0, "give time", 500000); + return retval; +} + +// Used within callback of sceNpAuthCreateStartRequest (arg1 = callback's args[0], arg2 = output structPtr?, arg3 = callback's args[1]) +// Is this using request id for Arg1 or cbId? +// JPCSP is using length = 248 for dummy ticket +static int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) +{ + ERROR_LOG(HLE, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, requestId, bufferAddr, length, currentMIPS->pc); + + if (!Memory::IsValidAddress(bufferAddr)) + return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + + int result = length; + Memory::Memset(bufferAddr, 0, length); + SceNpTicket ticket = {}; + // Dummy Login ticket returned as Login response. Dummy ticket contents were taken from https://www.psdevwiki.com/ps3/X-I-5-Ticket + ticket.header.version = TICKET_VER_2_1; + ticket.header.size = 0xF0; // size excluding the header + u8* buf = Memory::GetPointer(bufferAddr + sizeof(ticket)); + int ofs = 0; + ofs += writeTicketParam(buf, PARAM_TYPE_STRING_ASCII, "\x4c\x47\x56\x3b\x81\x39\x4a\x22\xd8\x6b\xc1\x57\x71\x6e\xfd\xb8\xab\x63\xcc\x51", 20); // 20 random letters, token key? + ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, 0x0100); // a flags? + PSPTimeval tv; + __RtcTimeOfDay(&tv); + u64 now = 1000ULL*tv.tv_sec + tv.tv_usec/1000ULL; // in milliseconds, since 1900? + ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_DATE, now); + ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_DATE, now + 10 * 60 * 1000); // now + 10 minutes, expired time? + ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_LONG, 0x592e71c546e86859); // seems to be consistent, 8-bytes password hash may be? or related to entitlement? or console id? + ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, onlineId.c_str(), 32); // username + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "fr\0\2", 4); // SceNpCountryCode ? ie. "fr" + 00 02 + ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, "c9", 4); // 2-char code? related to country/lang code? ie. "c9" + 00 00 + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, serviceId.c_str(), 24); + int status = 0; + if (parentalControl == PARENTAL_CONTROL_ENABLED) { + status |= STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED; + } + status |= (userAge & 0x7F) << 24; + ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, status); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL); + ticket.section.type = SECTION_TYPE_BODY; + ticket.section.size = ofs; + Memory::WriteStruct(bufferAddr, &ticket); + SceNpTicketSection footer = { SECTION_TYPE_FOOTER, 32 }; // footer section? ie. 32-bytes on ver 2.1 containing 4-chars ASCII + 20-chars ASCII + Memory::WriteStruct(bufferAddr + sizeof(ticket) + ofs, &footer); + ofs += sizeof(footer); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x34\xcd\x3c\xa9", 4); + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x3a\x4b\x42\x66\x92\xda\x6b\x7c\xb7\x4c\xe8\xd9\x4f\x2b\x77\x15\x91\xb8\xa4\xa9", 20); + u8 unknownBytes[36] = {}; + Memory::WriteStruct(bufferAddr + sizeof(ticket) + ofs, unknownBytes); + + result = ticket.header.size + sizeof(ticket.header); // dummy ticket is 248 bytes + + return result; +} + +// Used within callback of sceNpAuthCreateStartRequest (arg1 = structPtr?, arg2 = callback's args[1], arg3 = DLCcode? ie. "EP9000-UCES01421_00-DLL001", arg4 = Patapon 3 always set to 0?) +// Patapon 3 will loop (for each DLC?) through an array of 4+4 bytes, ID addr (pchar) + result (int). Each loop calls this function using the same ticket addr but use different ID addr (arg3) and store the return value in result field (default/initial = -1) +static int sceNpAuthGetEntitlementById(u32 ticketBufferAddr, u32 ticketLength, u32 entitlementIdAddr, u32 arg4) +{ + ERROR_LOG(HLE, "UNIMPL %s(%08x, %d, %08x, %d)", __FUNCTION__, ticketBufferAddr, ticketLength, entitlementIdAddr, arg4); + INFO_LOG(HLE, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(entitlementIdAddr)); + // Do we return the entitlement through function result? or update the ticket content? or replace the arg3 data with SceNpEntitlement struct? + return 1; // dummy value assuming it's a boolean/flag, since we don't know how to return the entitlement result yet +} + +static int sceNpAuthAbortRequest(int requestId) +{ + WARN_LOG(HLE, "UNTESTED %s(%i)", __FUNCTION__, requestId); + // TODO: Disconnect HTTPS connection & cancel the callback event + std::lock_guard npAuthGuard(npAuthEvtMtx); + for (auto it = npAuthEvents.begin(); it != npAuthEvents.end(); ) { + (it->data[0] == requestId) ? it = npAuthEvents.erase(it) : ++it; + } + return 0; +} + +static int sceNpAuthDestroyRequest(int requestId) +{ + WARN_LOG(HLE, "UNTESTED %s(%i)", __FUNCTION__, requestId); + // Remove callback handler + int handlerID = requestId - 1; + if (npAuthHandlers.find(handlerID) != npAuthHandlers.end()) { + npAuthHandlers.erase(handlerID); + WARN_LOG(SCENET, "%s: Deleted handler %d", __FUNCTION__, handlerID); + } + else { + ERROR_LOG(SCENET, "%s: Invalid request ID %d", __FUNCTION__, requestId); + } + // Patapon 3 is checking for error code 0x80550402 + return 0; +} + + const HLEFunction sceNpAuth[] = { - {0X4EC1F667, &WrapI_V, "sceNpAuth_4EC1F667", 'i', "" }, - {0XA1DE86F8, &WrapI_UUU, "sceNpAuth_A1DE86F8", 'i', "xxx"}, + {0X4EC1F667, &WrapI_V, "sceNpAuthTerm", 'i', "" }, + {0XA1DE86F8, &WrapI_UUU, "sceNpAuthInit", 'i', "xxx" }, + {0XF4531ADC, &WrapI_U, "sceNpAuthGetMemoryStat", 'i', "x" }, + {0XCD86A656, &WrapI_U, "sceNpAuthCreateStartRequest", 'i', "x" }, + {0X3F1C1F70, &WrapI_UUU, "sceNpAuthGetTicket", 'i', "xxx" }, + {0X6900F084, &WrapI_UUUU, "sceNpAuthGetEntitlementById", 'i', "xxxx" }, + {0XD99455DD, &WrapI_I, "sceNpAuthAbortRequest", 'i', "i" }, + {0X72BB0467, &WrapI_I, "sceNpAuthDestroyRequest", 'i', "i" }, }; void Register_sceNpAuth() @@ -70,22 +359,49 @@ void Register_sceNpAuth() RegisterModule("sceNpAuth", ARRAY_SIZE(sceNpAuth), sceNpAuth); } -static int sceNpService_00ACFAC3() +static int sceNpServiceTerm() { // No parameters - ERROR_LOG(HLE, "UNIMPL sceNpService_00ACFAC3()"); + ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); return 0; } -static int sceNpService_0F8F5821(u32 poolSize, u32 stackSize, u32 threadPrio) +static int sceNpServiceInit(u32 poolSize, u32 stackSize, u32 threadPrio) { - ERROR_LOG(HLE, "UNIMPL sceNpService_0F8F5821(%08x, %08x, %08x)",poolSize, stackSize, threadPrio); + ERROR_LOG(HLE, "UNIMPL %s(%08x, %08x, %08x)", __FUNCTION__, poolSize, stackSize, threadPrio); + return 0; +} + +static int sceNpLookupCreateTransactionCtx(u32 lookupTitleCtxIdAddr) +{ + ERROR_LOG(HLE, "UNIMPL %s(%08x)", __FUNCTION__, lookupTitleCtxIdAddr); + INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, Memory::GetCharPointer(lookupTitleCtxIdAddr)); + // Patapon 3 will only Destroy if returned Id > 0. Is 0 a valid id? + return 1; // returning dummy transaction id +} + +// transId: id returned from sceNpLookupCreateTransactionCtx +static int sceNpLookupDestroyTransactionCtx(u32 transId) +{ + ERROR_LOG(HLE, "UNIMPL %s(%d)", __FUNCTION__, transId); + return 0; +} + +// transId: id returned from sceNpLookupCreateTransactionCtx +// Patapon 3 always set Arg5 to 0 +// Addr args have something to do with GameUpdate? +static int sceNpLookupTitleSmallStorage(u32 transId, u32 arg2Addr, u32 arg3, u32 arg4Addr, u32 arg5) +{ + ERROR_LOG(HLE, "UNIMPL %s(%d, %08x, %08x, %08x, %08x)", __FUNCTION__, transId, arg2Addr, arg3, arg4Addr, arg5); return 0; } const HLEFunction sceNpService[] = { - {0X00ACFAC3, &WrapI_V, "sceNpService_00ACFAC3", 'i', "" }, - {0X0F8F5821, &WrapI_UUU, "sceNpService_0F8F5821", 'i', "xxx"}, + {0X00ACFAC3, &WrapI_V, "sceNpServiceTerm", 'i', "" }, + {0X0F8F5821, &WrapI_UUU, "sceNpServiceInit", 'i', "xxx" }, + {0X5494274B, &WrapI_U, "sceNpLookupCreateTransactionCtx", 'i', "x" }, + {0XA670D3A3, &WrapI_U, "sceNpLookupDestroyTransactionCtx", 'i', "x" }, + {0XC76F55ED, &WrapI_UUUUU, "sceNpLookupTitleSmallStorage", 'i', "xxxxx" }, }; void Register_sceNpService() @@ -94,25 +410,25 @@ void Register_sceNpService() } const HLEFunction sceNpCommerce2[] = { - {0X005B5F20, nullptr, "sceNpCommerce2_005B5F20", '?', "" }, - {0X0E9956E3, nullptr, "sceNpCommerce2_0e9956e3", '?', "" }, - {0X1888A9FE, nullptr, "sceNpCommerce2_1888a9fe", '?', "" }, - {0X1C952DCB, nullptr, "sceNpCommerce2_1c952dcb", '?', "" }, - {0X2B25F6E9, nullptr, "sceNpCommerce2_2b25f6e9", '?', "" }, - {0X3371D5F1, nullptr, "sceNpCommerce2_3371d5f1", '?', "" }, - {0X4ECD4503, nullptr, "sceNpCommerce2_4ecd4503", '?', "" }, - {0X590A3229, nullptr, "sceNpCommerce2_590a3229", '?', "" }, - {0X6F1FE37F, nullptr, "sceNpCommerce2_6f1fe37f", '?', "" }, - {0XA5A34EA4, nullptr, "sceNpCommerce2_a5a34ea4", '?', "" }, - {0XAA4A1E3D, nullptr, "sceNpCommerce2_aa4a1e3d", '?', "" }, - {0XBC61FFC8, nullptr, "sceNpCommerce2_bc61ffc8", '?', "" }, - {0XC7F32242, nullptr, "sceNpCommerce2_c7f32242", '?', "" }, - {0XF2278B90, nullptr, "sceNpCommerce2_f2278b90", '?', "" }, - {0XF297AB9C, nullptr, "sceNpCommerce2_f297ab9c", '?', "" }, - {0XFC30C19E, nullptr, "sceNpCommerce2_fc30c19e", '?', "" }, + {0X005B5F20, nullptr, "sceNpCommerce2GetProductInfoStart", '?', "" }, + {0X0E9956E3, nullptr, "sceNpCommerce2Init", '?', "" }, + {0X1888A9FE, nullptr, "sceNpCommerce2DestroyReq", '?', "" }, + {0X1C952DCB, nullptr, "sceNpCommerce2GetGameProductInfo", '?', "" }, + {0X2B25F6E9, nullptr, "sceNpCommerce2CreateSessionStart", '?', "" }, + {0X3371D5F1, nullptr, "sceNpCommerce2GetProductInfoCreateReq", '?', "" }, + {0X4ECD4503, nullptr, "sceNpCommerce2CreateSessionCreateReq", '?', "" }, + {0X590A3229, nullptr, "sceNpCommerce2GetSessionInfo", '?', "" }, + {0X6F1FE37F, nullptr, "sceNpCommerce2CreateCtx", '?', "" }, + {0XA5A34EA4, nullptr, "sceNpCommerce2Term", '?', "" }, + {0XAA4A1E3D, nullptr, "sceNpCommerce2GetProductInfoGetResult", '?', "" }, + {0XBC61FFC8, nullptr, "sceNpCommerce2CreateSessionGetResult", '?', "" }, + {0XC7F32242, nullptr, "sceNpCommerce2AbortReq", '?', "" }, + {0XF2278B90, nullptr, "sceNpCommerce2GetGameSkuInfoFromGameProductInfo", '?', "" }, + {0XF297AB9C, nullptr, "sceNpCommerce2DestroyCtx", '?', "" }, + {0XFC30C19E, nullptr, "sceNpCommerce2InitGetProductInfoResult", '?', "" }, }; void Register_sceNpCommerce2() { RegisterModule("sceNpCommerce2", ARRAY_SIZE(sceNpCommerce2), sceNpCommerce2); -} \ No newline at end of file +} diff --git a/Core/HLE/sceNp.h b/Core/HLE/sceNp.h index 7985a4d739..3c117b33c7 100644 --- a/Core/HLE/sceNp.h +++ b/Core/HLE/sceNp.h @@ -17,7 +17,266 @@ #pragma once +#ifdef _MSC_VER +#pragma pack(push,1) +#endif + +// Based on https://playstationdev.wiki/psvitadevwiki/index.php?title=Error_Codes +#define SCE_NP_ERROR_ALREADY_INITIALIZED 0x80550001 +#define SCE_NP_ERROR_NOT_INITIALIZED 0x80550002 +#define SCE_NP_ERROR_INVALID_ARGUMENT 0x80550003 + +#define SCE_NP_AUTH_ERROR_ALREADY_INITIALIZED 0x80550301 +#define SCE_NP_AUTH_ERROR_NOT_INITIALIZED 0x80550302 +#define SCE_NP_AUTH_ERROR_EINVAL 0x80550303 +#define SCE_NP_AUTH_ERROR_ENOMEM 0x80550304 +#define SCE_NP_AUTH_ERROR_ESRCH 0x80550305 +#define SCE_NP_AUTH_ERROR_EBUSY 0x80550306 +#define SCE_NP_AUTH_ERROR_ABORTED 0x80550307 +#define SCE_NP_AUTH_ERROR_INVALID_SERVICE_ID 0x80550308 +#define SCE_NP_AUTH_ERROR_INVALID_CREDENTIAL 0x80550309 +#define SCE_NP_AUTH_ERROR_INVALID_ENTITLEMENT_ID 0x8055030a +#define SCE_NP_AUTH_ERROR_INVALID_DATA_LENGTH 0x8055030b +#define SCE_NP_AUTH_ERROR_UNSUPPORTED_TICKET_VERSION 0x8055030c +#define SCE_NP_AUTH_ERROR_STACKSIZE_TOO_SHORT 0x8055030d +#define SCE_NP_AUTH_ERROR_TICKET_STATUS_CODE_INVALID 0x8055030e +#define SCE_NP_AUTH_ERROR_TICKET_PARAM_NOT_FOUND 0x8055030f +#define SCE_NP_AUTH_ERROR_INVALID_TICKET_VERSION 0x80550310 +#define SCE_NP_AUTH_ERROR_INVALID_ARGUMENT 0x80550311 + +#define SCE_NP_AUTH_ERROR_SERVICE_END 0x80550400 +#define SCE_NP_AUTH_ERROR_SERVICE_DOWN 0x80550401 +#define SCE_NP_AUTH_ERROR_SERVICE_BUSY 0x80550402 + +// Based on https://github.com/RPCS3/rpcs3/blob/psp2/rpcs3/Emu/PSP2/Modules/sceNpCommon.h +enum SceNpServiceState : s32 +{ + SCE_NP_SERVICE_STATE_UNKNOWN = 0, + SCE_NP_SERVICE_STATE_SIGNED_OUT, + SCE_NP_SERVICE_STATE_SIGNED_IN, + SCE_NP_SERVICE_STATE_ONLINE +}; + +struct SceNpCommunicationId +{ + char data[9]; + char term; + u8 num; + char dummy; +}; + +struct SceNpCommunicationPassphrase +{ + u8 data[128]; +}; + +struct SceNpCommunicationSignature +{ + u8 data[160]; +}; + +struct SceNpCommunicationConfig +{ + PSPPointer commId; + PSPPointer commPassphrase; + PSPPointer commSignature; +}; + +struct SceNpCountryCode +{ + char data[2]; + char term; + char padding[1]; +}; + +// Username? +struct SceNpOnlineId +{ + char data[16]; + char term; + char dummy[3]; +}; + +struct SceNpId +{ + SceNpOnlineId handle; + u8 opt[8]; + u8 reserved[8]; +}; + +struct SceNpAvatarUrl +{ + char data[127]; + char term; +}; + +struct SceNpUserInformation +{ + SceNpId userId; + SceNpAvatarUrl icon; + u8 reserved[52]; +}; + +struct SceNpMyLanguages +{ + s32_le language1; + s32_le language2; + s32_le language3; + u8 padding[4]; +}; + +struct SceNpAvatarImage +{ + u8 data[200 * 1024]; + u32_le size; + u8 reserved[12]; +}; + +enum SceNpAvatarSizeType : s32 +{ + SCE_NP_AVATAR_SIZE_LARGE, + SCE_NP_AVATAR_SIZE_MIDDLE, + SCE_NP_AVATAR_SIZE_SMALL +}; + +struct SceNpAboutMe +{ + char data[64]; +}; + +struct SceNpDate +{ + u16_le year; + u8 month; + u8 day; +}; + +union SceNpTicketParam +{ + s32_le _s32; + s64_le _s64; + u32_le _u32; + u64_le _u64; + SceNpDate date; + u8 data[256]; +}; + +struct SceNpTicketVersion +{ + u16_le major; + u16_le minor; +}; + +struct NpAuthHandler { + u32 entryPoint; + u32 argument; +}; + +struct NpAuthArgs { + u32_le data[3]; // id, result, ArgAddr +}; + +using SceNpAuthCallback = s32(s32 id, s32 result, PSPPointer arg); + +struct SceNpAuthRequestParameter +{ + u32_le size; // Size of this struct + SceNpTicketVersion version; // Highest ticket version supported by this game/device? so PSN server can return supported ticket + u32_le serviceIdAddr; //PSPPointer serviceId; // null-terminated string + u32_le cookieAddr; //PSPPointer cookie; // null-terminated string? + u32_le cookieSize; + u32_le entitlementIdAddr; //PSPPointer entitlementId; // null-terminated string + u32_le consumedCount; // related to entitlement? + u32 ticketCbAddr; //PSPPointer ticketCb + u32_le cbArgAddr; //PSPPointer cbArg +}; + +struct SceNpEntitlementId +{ + u8 data[32]; +}; + +struct SceNpEntitlement +{ + SceNpEntitlementId id; + u64_le createdDate; + u64_le expireDate; + u32_le type; + s32_le remainingCount; + u32_le consumedCount; + u8 padding[4]; +}; + +#define TICKET_VER_2_0 0x21000000; +#define TICKET_VER_2_1 0x21010000; +#define TICKET_VER_3_0 0x31000000; +#define TICKET_VER_4_0 0x41000000; + +#define NUMBER_PARAMETERS 12 + +#define PARAM_TYPE_NULL 0 +#define PARAM_TYPE_INT 1 +#define PARAM_TYPE_LONG 2 +#define PARAM_TYPE_STRING 4 // PSP returns maximum 255 bytes +#define PARAM_TYPE_DATE 7 +#define PARAM_TYPE_STRING_ASCII 8 // PSP returns maximum 255 bytes, can contains control code + +#define SECTION_TYPE_BODY 0x3000 +#define SECTION_TYPE_FOOTER 0x3002 + +// Tickets data are in big-endian based on captured packets +struct SceNpTicketParamData +{ + u16_be type; + u16_be length; + //u8 value[]; // optional data +}; + +struct SceNpTicketHeader +{ + u32_be version; // Version contents byte are: V1 0M 00 00, where V = major version, M = minor version according to https://www.psdevwiki.com/ps3/X-I-5-Ticket + s32_be size; // total ticket size (excluding this 8-bytes header struct) +}; + +// Section contents byte are: 30 XX 00 YY, where XX = section type, YY = section size according to https://www.psdevwiki.com/ps3/X-I-5-Ticket +// A section can contain other sections or param data, thus sharing their enum/def? +struct SceNpTicketSection +{ + u16_be type; // section type? ie. 30 XX where known XX are 00, 02, 10, 11 + u16_be size; // total section size (excluding this 4-bytes section delimiter struct) +}; + +struct SceNpTicket +{ + SceNpTicketHeader header; + SceNpTicketSection section; // Body or Parameter sections? + //SceNpTicketParamData parameters[]; // a list of TicketParamData + //u8 unknownBytes[]; // optional data? +}; + +#define PARENTAL_CONTROL_DISABLED 0 +#define PARENTAL_CONTROL_ENABLED 1 + +#define STATUS_ACCOUNT_SUSPENDED 0x80 +#define STATUS_ACCOUNT_CHAT_RESTRICTED 0x100 +#define STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED 0x200 + +struct SceNpAuthMemoryStat { + int npMemSize; // Memory allocated by the NP utility. + int npMaxMemSize; // Maximum memory used by the NP utility. + int npFreeMemSize; // Free memory available to use by the NP utility. +}; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + + +extern std::recursive_mutex npAuthEvtMtx; +extern std::deque npAuthEvents; +extern std::map npAuthHandlers; + void Register_sceNp(); void Register_sceNpCommerce2(); void Register_sceNpService(); -void Register_sceNpAuth(); \ No newline at end of file +void Register_sceNpAuth(); diff --git a/Core/HLE/sceOpenPSID.cpp b/Core/HLE/sceOpenPSID.cpp index 19577dae22..d20e349307 100644 --- a/Core/HLE/sceOpenPSID.cpp +++ b/Core/HLE/sceOpenPSID.cpp @@ -19,11 +19,14 @@ #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceOpenPSID.h" #include "Core/MemMap.h" +#include + +u8 dummyOpenPSID[16] = { 0x10, 0x02, 0xA3, 0x44, 0x13, 0xF5, 0x93, 0xB0, 0xCC, 0x6E, 0xD1, 0x32, 0x27, 0x85, 0x0F, 0x9D }; static int sceOpenPSIDGetOpenPSID(u32 OpenPSIDPtr) { - ERROR_LOG(HLE, "UNTESTED sceOpenPSIDGetOpenPSID(%d)", OpenPSIDPtr); - u8 dummyOpenPSID[16] = {0x10, 0x02, 0xA3, 0x44, 0x13, 0xF5, 0x93, 0xB0, 0xCC, 0x6E, 0xD1, 0x32, 0x27, 0x85, 0x0F, 0x9D}; + WARN_LOG(HLE, "UNTESTED sceOpenPSIDGetOpenPSID(%d)", OpenPSIDPtr); + getLocalMac((SceNetEtherAddr*)&dummyOpenPSID); if (Memory::IsValidAddress(OpenPSIDPtr)) { @@ -35,6 +38,21 @@ static int sceOpenPSIDGetOpenPSID(u32 OpenPSIDPtr) return 0; } +static int sceOpenPSID_driver_0x19D579F0(u32 OpenPSIDPtr,u32 unknown) +{ + WARN_LOG(HLE, "UNTESTED sceOpenPSID_driver_0x19D579F0(%d,%d)", OpenPSIDPtr,unknown); + getLocalMac((SceNetEtherAddr*)&dummyOpenPSID); + + if (Memory::IsValidAddress(OpenPSIDPtr)) + { + for (int i = 0; i < 16; i++) + { + Memory::Write_U8(dummyOpenPSID[i], OpenPSIDPtr + i); + } + } + return 0; +} + const HLEFunction sceOpenPSID[] = { {0XC69BEBCE, &WrapI_U, "sceOpenPSIDGetOpenPSID", 'i', "x"}, @@ -44,3 +62,13 @@ void Register_sceOpenPSID() { RegisterModule("sceOpenPSID", ARRAY_SIZE(sceOpenPSID), sceOpenPSID); } + +const HLEFunction sceOpenPSID_driver[] = +{ + {0x19D579F0, &WrapI_UU, "sceOpenPSID_driver_0x19D579F0", 'i', "xx" }, +}; + +void Register_sceOpenPSID_driver() +{ + RegisterModule("sceOpenPSID_driver", ARRAY_SIZE(sceOpenPSID_driver), sceOpenPSID_driver); +} diff --git a/Core/HLE/sceOpenPSID.h b/Core/HLE/sceOpenPSID.h index 07c5171e59..24855ef4a4 100644 --- a/Core/HLE/sceOpenPSID.h +++ b/Core/HLE/sceOpenPSID.h @@ -20,3 +20,4 @@ void __sceOpenPSIDInit(); void Register_sceOpenPSID(); +void Register_sceOpenPSID_driver(); \ No newline at end of file diff --git a/Core/HLE/scePauth.cpp b/Core/HLE/scePauth.cpp index 84d92ec126..ceba0710fb 100644 --- a/Core/HLE/scePauth.cpp +++ b/Core/HLE/scePauth.cpp @@ -25,7 +25,7 @@ #include "Core/HLE/scePauth.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" static int scePauth_F7AA47F6(u32 srcPtr, int srcLength, u32 destLengthPtr, u32 workArea) { diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index b4fe3b0925..caa8e1d8fe 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -16,7 +16,8 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/CoreTiming.h" @@ -132,8 +133,8 @@ void __PowerDoState(PointerWrap &p) { return; if (s >= 2) { - p.Do(RealpllFreq); - p.Do(RealbusFreq); + Do(p, RealpllFreq); + Do(p, RealbusFreq); if (RealpllFreq < 1000000) RealpllFreq = PowerPllMhzToHz(RealpllFreq); @@ -151,9 +152,9 @@ void __PowerDoState(PointerWrap &p) { pllFreq = RealpllFreq; busFreq = RealbusFreq; } - p.DoArray(powerCbSlots, ARRAY_SIZE(powerCbSlots)); - p.Do(volatileMemLocked); - p.Do(volatileWaitingThreads); + DoArray(p, powerCbSlots, ARRAY_SIZE(powerCbSlots)); + Do(p, volatileMemLocked); + Do(p, volatileWaitingThreads); } static int scePowerGetBatteryLifePercent() { diff --git a/Core/HLE/scePsmf.cpp b/Core/HLE/scePsmf.cpp index 7d3eee9680..0a601db8d4 100644 --- a/Core/HLE/scePsmf.cpp +++ b/Core/HLE/scePsmf.cpp @@ -15,7 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" #include "Core/System.h" @@ -334,13 +336,13 @@ public: if (!s) return; - p.Do(type_); - p.Do(channel_); + Do(p, type_); + Do(p, channel_); if (s >= 2) { - p.Do(videoWidth_); - p.Do(videoHeight_); - p.Do(audioChannels_); - p.Do(audioFrequency_); + Do(p, videoWidth_); + Do(p, videoHeight_); + Do(p, audioChannels_); + Do(p, audioFrequency_); } } @@ -440,38 +442,38 @@ void Psmf::DoState(PointerWrap &p) { if (!s) return; - p.Do(magic); - p.Do(version); - p.Do(streamOffset); - p.Do(streamSize); - p.Do(headerOffset); - p.Do(streamDataTotalSize); - p.Do(presentationStartTime); - p.Do(presentationEndTime); - p.Do(streamDataNextBlockSize); - p.Do(streamDataNextInnerBlockSize); - p.Do(numStreams); + Do(p, magic); + Do(p, version); + Do(p, streamOffset); + Do(p, streamSize); + Do(p, headerOffset); + Do(p, streamDataTotalSize); + Do(p, presentationStartTime); + Do(p, presentationEndTime); + Do(p, streamDataNextBlockSize); + Do(p, streamDataNextInnerBlockSize); + Do(p, numStreams); - p.Do(currentStreamNum); + Do(p, currentStreamNum); int legacyStreamNums = 0; - p.Do(legacyStreamNums); - p.Do(legacyStreamNums); + Do(p, legacyStreamNums); + Do(p, legacyStreamNums); - p.Do(EPMapOffset); - p.Do(EPMapEntriesNum); - p.Do(videoWidth); - p.Do(videoHeight); - p.Do(audioChannels); - p.Do(audioFrequency); + Do(p, EPMapOffset); + Do(p, EPMapEntriesNum); + Do(p, videoWidth); + Do(p, videoHeight); + Do(p, audioChannels); + Do(p, audioFrequency); if (s >= 2) { - p.Do(EPMap); + Do(p, EPMap); } - p.Do(streamMap); + Do(p, streamMap); if (s >= 3) { - p.Do(currentStreamType); - p.Do(currentStreamChannel); + Do(p, currentStreamType); + Do(p, currentStreamChannel); } else { currentStreamType = -1; currentStreamChannel = -1; @@ -488,65 +490,65 @@ void PsmfPlayer::DoState(PointerWrap &p) { if (!s) return; - p.Do(videoCodec); - p.Do(videoStreamNum); - p.Do(audioCodec); - p.Do(audioStreamNum); - p.Do(playMode); - p.Do(playSpeed); + Do(p, videoCodec); + Do(p, videoStreamNum); + Do(p, audioCodec); + Do(p, audioStreamNum); + Do(p, playMode); + Do(p, playSpeed); - p.Do(displayBuffer); - p.Do(displayBufferSize); - p.Do(playbackThreadPriority); + Do(p, displayBuffer); + Do(p, displayBufferSize); + Do(p, playbackThreadPriority); int oldMaxAheadTimestamp = 0; - p.Do(oldMaxAheadTimestamp); + Do(p, oldMaxAheadTimestamp); if (s >= 4) { - p.Do(totalDurationTimestamp); + Do(p, totalDurationTimestamp); } else { long oldTimestamp; - p.Do(oldTimestamp); + Do(p, oldTimestamp); totalDurationTimestamp = oldTimestamp; } if (s >= 2) { - p.Do(totalVideoStreams); - p.Do(totalAudioStreams); - p.Do(playerVersion); + Do(p, totalVideoStreams); + Do(p, totalAudioStreams); + Do(p, playerVersion); } else { totalVideoStreams = 1; totalAudioStreams = 1; playerVersion = PSMF_PLAYER_VERSION_FULL; } if (s >= 3) { - p.Do(videoStep); + Do(p, videoStep); } else { videoStep = 0; } if (s >= 4) { - p.Do(warmUp); + Do(p, warmUp); } else { warmUp = 10000; } if (s >= 5) { - p.Do(seekDestTimeStamp); + Do(p, seekDestTimeStamp); } else { seekDestTimeStamp = 0; } - p.DoClass(mediaengine); - p.Do(filehandle); - p.Do(fileoffset); - p.Do(readSize); - p.Do(streamSize); + DoClass(p, mediaengine); + Do(p, filehandle); + Do(p, fileoffset); + Do(p, readSize); + Do(p, streamSize); - p.Do(status); + Do(p, status); if (s >= 4) { - p.Do(psmfPlayerAtracAu); + Do(p, psmfPlayerAtracAu); } - p.Do(psmfPlayerAvcAu); + Do(p, psmfPlayerAvcAu); if (s >= 7) { bool hasFinishThread = finishThread != nullptr; - p.Do(hasFinishThread); + Do(p, hasFinishThread); if (hasFinishThread) { - p.Do(finishThread); + Do(p, finishThread); } else { if (finishThread) finishThread->Forget(); @@ -554,7 +556,7 @@ void PsmfPlayer::DoState(PointerWrap &p) { finishThread = nullptr; } } else if (s >= 6) { - p.Do(finishThread); + Do(p, finishThread); } else { if (finishThread) finishThread->Forget(); @@ -563,8 +565,8 @@ void PsmfPlayer::DoState(PointerWrap &p) { } if (s >= 8) { - p.Do(videoWidth); - p.Do(videoHeight); + Do(p, videoWidth); + Do(p, videoHeight); } } @@ -679,7 +681,7 @@ void __PsmfDoState(PointerWrap &p) { if (!s) return; - p.Do(psmfMap); + Do(p, psmfMap); } void __PsmfPlayerDoState(PointerWrap &p) { @@ -687,11 +689,11 @@ void __PsmfPlayerDoState(PointerWrap &p) { if (!s) return; - p.Do(psmfPlayerMap); - p.Do(videoPixelMode); - p.Do(videoLoopStatus); + Do(p, psmfPlayerMap); + Do(p, videoPixelMode); + Do(p, videoLoopStatus); if (s >= 2) { - p.Do(psmfPlayerLibVersion); + Do(p, psmfPlayerLibVersion); } else { // Assume the latest, which is what we were emulating before. psmfPlayerLibVersion = 0x06060010; @@ -1734,7 +1736,7 @@ static u32 scePsmfPlayerGetCurrentPts(u32 psmfPlayer, u32 currentPtsAddr) return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->psmfPlayerAvcAu.pts < 0) { - WARN_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): no frame yet", psmfPlayer, currentPtsAddr); + VERBOSE_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): no frame yet", psmfPlayer, currentPtsAddr); return ERROR_PSMFPLAYER_NO_MORE_DATA; } diff --git a/Core/HLE/sceRtc.cpp b/Core/HLE/sceRtc.cpp index 75e9e3ef3b..5fc8d372ce 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -24,9 +24,10 @@ #endif #include -#include "base/timeutil.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/TimeUtil.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MIPS/MIPS.h" @@ -167,7 +168,7 @@ void __RtcDoState(PointerWrap &p) if (!s) return; - p.Do(rtcBaseTime); + Do(p, rtcBaseTime); // Update the precalc, pointless to savestate this as it's just based on the other value. RtcUpdateBaseTicks(); } diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 778708e65d..25cb02f392 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -32,9 +32,9 @@ #include #include -#include "base/basictypes.h" -#include "profiler/profiler.h" -#include "thread/threadutil.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Common/Log.h" #include "Core/Config.h" #include "Core/CoreTiming.h" @@ -204,10 +204,10 @@ void __SasDoState(PointerWrap &p) { __SasDrain(); } - p.DoClass(sas); + DoClass(p, sas); if (s >= 2) { - p.Do(sasMixEvent); + Do(p, sasMixEvent); } else { sasMixEvent = -1; __SasDisableThread(); diff --git a/Core/HLE/sceSsl.cpp b/Core/HLE/sceSsl.cpp index 2fa138cb78..7361962d1d 100644 --- a/Core/HLE/sceSsl.cpp +++ b/Core/HLE/sceSsl.cpp @@ -15,11 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MemMap.h" -#include "Common/ChunkFile.h" - #include "Core/HLE/sceSsl.h" #define ERROR_SSL_NOT_INIT 0x80435001; @@ -44,9 +44,9 @@ void __SslDoState(PointerWrap &p) if (!s) return; - p.Do(isSslInit); - p.Do(maxMemSize); - p.Do(currentMemSize); + Do(p, isSslInit); + Do(p, maxMemSize); + Do(p, currentMemSize); } static int sceSslInit(int heapSize) @@ -127,4 +127,4 @@ const HLEFunction sceSsl[] = void Register_sceSsl() { RegisterModule("sceSsl", ARRAY_SIZE(sceSsl), sceSsl); -} \ No newline at end of file +} diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index ab2d62a490..5cb209c6c4 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -17,9 +17,9 @@ #include -#include "file/file_util.h" - -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" #include "Core/Loaders.h" #include "Core/MemMap.h" #include "Core/System.h" @@ -87,26 +87,26 @@ void __UmdDoState(PointerWrap &p) if (!s) return; - p.Do(umdActivated); - p.Do(umdStatus); - p.Do(umdErrorStat); - p.Do(driveCBId); - p.Do(umdStatTimeoutEvent); + Do(p, umdActivated); + Do(p, umdStatus); + Do(p, umdErrorStat); + Do(p, driveCBId); + Do(p, umdStatTimeoutEvent); CoreTiming::RestoreRegisterEvent(umdStatTimeoutEvent, "UmdTimeout", __UmdStatTimeout); - p.Do(umdStatChangeEvent); + Do(p, umdStatChangeEvent); CoreTiming::RestoreRegisterEvent(umdStatChangeEvent, "UmdChange", __UmdStatChange); - p.Do(umdWaitingThreads); - p.Do(umdPausedWaits); + Do(p, umdWaitingThreads); + Do(p, umdPausedWaits); if (s > 1) { - p.Do(UMDReplacePermit); + Do(p, UMDReplacePermit); if (UMDReplacePermit) host->UpdateUI(); } if (s > 2) { - p.Do(umdInsertChangeEvent); + Do(p, umdInsertChangeEvent); CoreTiming::RestoreRegisterEvent(umdInsertChangeEvent, "UmdInsertChange", __UmdInsertChange); - p.Do(UMDInserted); + Do(p, UMDInserted); } else UMDInserted = true; @@ -189,7 +189,7 @@ void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId) if (umdPausedWaits.find(pauseKey) != umdPausedWaits.end()) return; - _dbg_assert_msg_(SCEIO, umdStatTimeoutEvent != -1, "Must have a umd timer"); + _dbg_assert_msg_(umdStatTimeoutEvent != -1, "Must have a umd timer"); s64 cyclesLeft = CoreTiming::UnscheduleEvent(umdStatTimeoutEvent, threadID); if (cyclesLeft != 0) umdPausedWaits[pauseKey] = CoreTiming::GetTicks() + cyclesLeft; @@ -234,7 +234,7 @@ void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId) __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); else { - _dbg_assert_msg_(SCEIO, umdStatTimeoutEvent != -1, "Must have a umd timer"); + _dbg_assert_msg_(umdStatTimeoutEvent != -1, "Must have a umd timer"); CoreTiming::ScheduleEvent(cyclesLeft, umdStatTimeoutEvent, __KernelGetCurThread()); umdWaitingThreads.push_back(threadID); diff --git a/Core/HLE/sceUsb.cpp b/Core/HLE/sceUsb.cpp index cd2e5e5e16..520b057826 100644 --- a/Core/HLE/sceUsb.cpp +++ b/Core/HLE/sceUsb.cpp @@ -15,12 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/NativeApp.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MIPS/MIPS.h" #include "Core/CoreTiming.h" -#include "Common/ChunkFile.h" #include "Core/HLE/sceUsb.h" // TODO: Map by driver name @@ -53,13 +53,13 @@ void __UsbDoState(PointerWrap &p) return; if (s >= 2) { - p.Do(usbStarted); - p.Do(usbConnected); + Do(p, usbStarted); + Do(p, usbConnected); } else { usbStarted = false; usbConnected = true; } - p.Do(usbActivated); + Do(p, usbActivated); } static int sceUsbStart(const char* driverName, u32 argsSize, u32 argsPtr) { @@ -83,7 +83,7 @@ static int sceUsbGetState() { | (usbConnected ? USB_STATUS_CONNECTED : USB_STATUS_DISCONNECTED) | (usbActivated ? USB_STATUS_ACTIVATED : USB_STATUS_DEACTIVATED); } - INFO_LOG(HLE, "sceUsbGetState: 0x%x", state); + DEBUG_LOG(HLE, "sceUsbGetState: 0x%x", state); return state; } diff --git a/Core/HLE/sceUsbCam.cpp b/Core/HLE/sceUsbCam.cpp index c2ab2979fa..7793e372a0 100644 --- a/Core/HLE/sceUsbCam.cpp +++ b/Core/HLE/sceUsbCam.cpp @@ -18,15 +18,22 @@ #include #include -#include "base/NativeApp.h" #include "ppsspp_config.h" -#include "Common/ChunkFile.h" + +#include "Common/System/System.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/sceUsbCam.h" +#include "Core/HLE/sceUsbMic.h" #include "Core/HW/Camera.h" #include "Core/MemMapHelpers.h" -#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) +#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) && !defined(__LIBRETRO__) +#define HAVE_WIN32_CAMERA +#endif + +#ifdef HAVE_WIN32_CAMERA #ifndef NOMINMAX #define NOMINMAX #endif @@ -45,7 +52,7 @@ enum { }; void __UsbCamInit() { - config = new Camera::Config; + config = new Camera::Config(); config->mode = Camera::Mode::Unused; config->type = Camera::ConfigType::CfNone; videoBuffer = new uint8_t[VIDEO_BUFFER_SIZE]; @@ -57,7 +64,7 @@ void __UsbCamDoState(PointerWrap &p) { return; } - p.Do(*config); + Do(p, *config); if (config->mode == Camera::Mode::Video) { // stillImage? TBD Camera::stopCapture(); Camera::startCapture(); @@ -70,7 +77,7 @@ void __UsbCamShutdown() { } delete[] videoBuffer; videoBuffer = nullptr; - delete[] config; + delete config; config = nullptr; } @@ -108,7 +115,7 @@ static int getCameraResolution(Camera::ConfigType type, int *width, int *height) static int sceUsbCamSetupMic(u32 paramAddr, u32 workareaAddr, int wasize) { - INFO_LOG(HLE, "UNIMPL sceUsbCamSetupMic"); + INFO_LOG(HLE, "sceUsbCamSetupMic"); if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupMicParam))) { Memory::ReadStruct(paramAddr, &config->micParam); } @@ -127,13 +134,7 @@ static int sceUsbCamStopMic() { static int sceUsbCamReadMicBlocking(u32 bufAddr, u32 size) { INFO_LOG(HLE, "UNIMPL sceUsbCamReadMicBlocking: size: %d", size); - for (unsigned int i = 0; i < size; i++) { - if (Memory::IsValidAddress(bufAddr + i)) { - Memory::Write_U8(i & 0xFF, bufAddr + i); - } - } - hleEatMicro(1000000 / config->micParam.frequency * (size / 2)); - return size; + return __MicInputBlocking(size >> 1, config->micParam.frequency, bufAddr); } static int sceUsbCamSetupVideo(u32 paramAddr, u32 workareaAddr, int wasize) { @@ -300,7 +301,7 @@ void Register_sceUsbCam() } std::vector Camera::getDeviceList() { - #if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) + #ifdef HAVE_WIN32_CAMERA if (winCamera) { return winCamera->getDeviceList(); } @@ -320,7 +321,7 @@ int Camera::startCapture() { INFO_LOG(HLE, "%s resolution: %dx%d", __FUNCTION__, width, height); config->mode = Camera::Mode::Video; - #if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) + #ifdef HAVE_WIN32_CAMERA if (winCamera) { if (winCamera->isShutDown()) { delete winCamera; @@ -344,7 +345,7 @@ int Camera::startCapture() { int Camera::stopCapture() { INFO_LOG(HLE, "%s", __FUNCTION__); - #if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) + #ifdef HAVE_WIN32_CAMERA if (winCamera) { winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::STOP, nullptr }); } diff --git a/Core/HLE/sceUsbGps.cpp b/Core/HLE/sceUsbGps.cpp index 05b16e5b3d..723e83d445 100644 --- a/Core/HLE/sceUsbGps.cpp +++ b/Core/HLE/sceUsbGps.cpp @@ -15,8 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/NativeApp.h" -#include "Common/ChunkFile.h" +#include + +#include "Common/System/System.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceUsbGps.h" @@ -40,7 +43,7 @@ void __UsbGpsDoState(PointerWrap &p) { if (!s) return; - p.Do(gpsStatus); + Do(p, gpsStatus); } void __UsbGpsShutdown() { diff --git a/Core/HLE/sceUsbMic.cpp b/Core/HLE/sceUsbMic.cpp index 306f527da1..91855a0804 100644 --- a/Core/HLE/sceUsbMic.cpp +++ b/Core/HLE/sceUsbMic.cpp @@ -17,33 +17,412 @@ #include -#include "base/NativeApp.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceUsbMic.h" +#include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" -static int sceUsbMicInputBlocking(u32 size, u32 samplerate, u32 bufAddr) { - INFO_LOG(HLE, "UNIMPL sceUsbMicInputBlocking: size: %d, samplerate: %d", size, samplerate); - for (unsigned int i = 0; i < size; i++) { - if (Memory::IsValidAddress(bufAddr + i)) { - Memory::Write_U8(i & 0xFF, bufAddr + i); +#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) && !defined(__LIBRETRO__) +#define HAVE_WIN32_MICROPHONE +#endif + +#ifdef HAVE_WIN32_MICROPHONE +#include "Windows/CaptureDevice.h" +#endif + +enum { + SCE_USBMIC_ERROR_INVALID_MAX_SAMPLES = 0x80243806, + SCE_USBMIC_ERROR_INVALID_SAMPLERATE = 0x8024380A, +}; + +int eventUsbMicAudioUpdate = -1; + +QueueBuf *audioBuf = nullptr; +u32 numNeedSamples; +static std::vector waitingThreads; +std::mutex wtMutex; +bool isNeedInput; +u32 curSampleRate; +u32 curChannels; +int micState; // 0 means stopped, 1 means started, for save state. + +static void __UsbMicAudioUpdate(u64 userdata, int cyclesLate) { + SceUID threadID = (SceUID)userdata; + u32 error; + int count = 0; + std::unique_lock lock(wtMutex); + for (auto waitingThread : waitingThreads) { + if (waitingThread.threadID == threadID) { + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MICINPUT, error); + if (waitID == 0) + continue; + if (Microphone::isHaveDevice()) { + if (Microphone::availableAudioBufSize() >= waitingThread.needSize) { + u8 *tempbuf8 = new u8[waitingThread.needSize]; + Microphone::getAudioData(tempbuf8, waitingThread.needSize); + Memory::Memcpy(waitingThread.addr, tempbuf8, waitingThread.needSize); + delete[] tempbuf8; + u32 ret = __KernelGetWaitValue(threadID, error); + DEBUG_LOG(HLE, "sceUsbMic: Waking up thread(%d)", (int)waitingThread.threadID); + __KernelResumeThreadFromWait(threadID, ret); + waitingThreads.erase(waitingThreads.begin() + count); + if (waitingThreads.size() == 0) + isNeedInput = false; + } else { + u64 waitTimeus = (waitingThread.needSize - Microphone::availableAudioBufSize()) * 1000000 / 2 / waitingThread.sampleRate; + CoreTiming::ScheduleEvent(usToCycles(waitTimeus), eventUsbMicAudioUpdate, userdata); + } + } else { + for (u32 i = 0; i < waitingThread.needSize; i++) { + if (Memory::IsValidAddress(waitingThread.addr + i)) { + Memory::Write_U8(i & 0xFF, waitingThread.addr + i); + } + } + u32 ret = __KernelGetWaitValue(threadID, error); + DEBUG_LOG(HLE, "sceUsbMic: Waking up thread(%d)", (int)waitingThread.threadID); + __KernelResumeThreadFromWait(threadID, ret); + waitingThreads.erase(waitingThreads.begin() + count); + if (waitingThreads.size() == 0) + isNeedInput = false; + } + } + ++count; + } + lock.unlock(); +} + +void __UsbMicInit() { + if (audioBuf) { + delete audioBuf; + audioBuf = nullptr; + } + numNeedSamples = 0; + waitingThreads.clear(); + isNeedInput = false; + curSampleRate = 44100; + curChannels = 1; + micState = 0; + eventUsbMicAudioUpdate = CoreTiming::RegisterEvent("UsbMicAudioUpdate", &__UsbMicAudioUpdate); +} + +void __UsbMicShutdown() { + if (audioBuf) { + delete audioBuf; + audioBuf = nullptr; + } + Microphone::stopMic(); +} + +void __UsbMicDoState(PointerWrap &p) { + auto s = p.Section("sceUsbMic", 0, 1); + if (!s) { + return; + } + Do(p, numNeedSamples); + Do(p, waitingThreads); + Do(p, isNeedInput); + Do(p, curSampleRate); + Do(p, curChannels); + Do(p, micState); + // Maybe also need to save the state of audioBuf. + if (waitingThreads.size() != 0 && p.mode == PointerWrap::MODE_READ) { + u64 waitTimeus = (waitingThreads[0].needSize - Microphone::availableAudioBufSize()) * 1000000 / 2 / waitingThreads[0].sampleRate; + CoreTiming::ScheduleEvent(usToCycles(waitTimeus), eventUsbMicAudioUpdate, waitingThreads[0].threadID); + } + if (micState == 0) { + if (Microphone::isMicStarted()) + Microphone::stopMic(); + } else if (micState == 1) { + if (Microphone::isMicStarted()) { + Microphone::stopMic(); + Microphone::startMic(new std::vector({ curSampleRate, curChannels })); + } else { + Microphone::startMic(new std::vector({ curSampleRate, curChannels })); } } - hleEatMicro(1000000 / samplerate * (size / 2)); +} + +QueueBuf::QueueBuf(u32 size) : start(0), end(0), capacity(size) { + buf_ = new u8[size]; +} + +QueueBuf::~QueueBuf() { + delete[] buf_; +} + +QueueBuf::QueueBuf(const QueueBuf &buf) { + buf_ = new u8[buf.capacity]; + memcpy(buf_, buf.buf_, buf.capacity); + start = buf.start; + end = buf.end; + capacity = buf.capacity; +} + +QueueBuf& QueueBuf::operator=(const QueueBuf &buf) { + if (capacity < buf.capacity) { + resize(buf.capacity); + } + std::unique_lock lock(mutex); + memcpy(buf_, buf.buf_, buf.capacity); + start = buf.start; + end = buf.end; + lock.unlock(); + return *this; +} + +void QueueBuf::push(u8 *buf, u32 size) { + if (getRemainingSize() < size) { + resize((capacity + size - getRemainingSize()) * 3 / 2); + } + std::unique_lock lock(mutex); + if (end + size <= capacity) { + memcpy(buf_ + end, buf, size); + end += size; + } else { + memcpy(buf_ + end, buf, capacity - end); + size -= capacity - end; + memcpy(buf_, buf + capacity - end, size); + end = size; + } + lock.unlock(); +} + +u32 QueueBuf::pop(u8 *buf, u32 size) { + u32 ret = 0; + if (getAvailableSize() < size) + size = getAvailableSize(); + ret = size; + + std::unique_lock lock(mutex); + if (start + size <= capacity) { + memcpy(buf, buf_ + start, size); + start += size; + } else { + memcpy(buf, buf_ + start, capacity - start); + size -= capacity - start; + memcpy(buf + capacity - start, buf_, size); + start = size; + } + lock.unlock(); + return ret; +} + +void QueueBuf::resize(u32 newSize) { + if (capacity >= newSize) { + return; + } + u32 availableSize = getAvailableSize(); + u8 *oldbuf = buf_; + + std::unique_lock lock(mutex); + buf_ = new u8[newSize]; + if (end >= start) { + memcpy(buf_, oldbuf + start, availableSize); + } else { + memcpy(buf_, oldbuf + start, capacity - start); + memcpy(buf_ + capacity - start, oldbuf, availableSize - (capacity - start)); + } + start = 0; + end = availableSize; + capacity = newSize; + delete[] oldbuf; + lock.unlock(); +} + +void QueueBuf::flush() { + std::unique_lock lock(mutex); + start = 0; + end = 0; + lock.unlock(); +} + +u32 QueueBuf::getAvailableSize() { + u32 availableSize = 0; + if (end >= start) { + availableSize = end - start; + } else { + availableSize = end + capacity - start; + } + return availableSize; +} + +u32 QueueBuf::getRemainingSize() { + return capacity - getAvailableSize(); +} + +static int sceUsbMicPollInputEnd() { + ERROR_LOG(HLE, "UNIMPL sceUsbMicPollInputEnd"); + return 0; +} + +static int sceUsbMicInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) { + INFO_LOG(HLE, "sceUsbMicInputBlocking: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); + if (maxSamples <= 0 || (maxSamples & 0x3F) != 0) { + return SCE_USBMIC_ERROR_INVALID_MAX_SAMPLES; + } + + if (sampleRate != 44100 && sampleRate != 22050 && sampleRate != 11025) { + return SCE_USBMIC_ERROR_INVALID_SAMPLERATE; + } + curSampleRate = sampleRate; + curChannels = 1; + return __MicInputBlocking(maxSamples, sampleRate, bufAddr); +} + +static int sceUsbMicInputInitEx(u32 paramAddr) { + ERROR_LOG(HLE, "UNIMPL sceUsbMicInputInitEx: %08x", paramAddr); + return 0; +} + +static int sceUsbMicInput() { + ERROR_LOG(HLE, "UNIMPL sceUsbMicInput"); + return 0; +} +static int sceUsbMicGetInputLength() { + int ret = Microphone::availableAudioBufSize() / 2; + ERROR_LOG(HLE, "UNTEST sceUsbMicGetInputLength(ret: %d)", ret); + return ret; +} + +static int sceUsbMicInputInit(int unknown1, int inputVolume, int unknown2) { + ERROR_LOG(HLE, "UNIMPL sceUsbMicInputInit(unknown1: %d, inputVolume: %d, unknown2: %d)", unknown1, inputVolume, unknown2); + return 0; +} + +static int sceUsbMicWaitInputEnd() { + ERROR_LOG(HLE, "UNIMPL sceUsbMicWaitInputEnd"); + return 0; +} + +int Microphone::startMic(void *param) { +#ifdef HAVE_WIN32_MICROPHONE + if (winMic) + winMic->sendMessage({ CAPTUREDEVIDE_COMMAND::START, param }); +#endif + micState = 1; + return 0; +} + +int Microphone::stopMic() { +#ifdef HAVE_WIN32_MICROPHONE + if (winMic) + winMic->sendMessage({ CAPTUREDEVIDE_COMMAND::STOP, nullptr }); +#endif + micState = 0; + return 0; +} + +bool Microphone::isHaveDevice() { +#ifdef HAVE_WIN32_MICROPHONE + return winMic->getDeviceCounts() >= 1; +#endif + return false; +} + +bool Microphone::isMicStarted() { +#ifdef HAVE_WIN32_MICROPHONE + if(winMic) + return winMic->isStarted(); +#endif + return false; +} + +bool Microphone::isNeedInput() { + return ::isNeedInput; +} + +u32 Microphone::numNeedSamples() { + return ::numNeedSamples; +} + +u32 Microphone::availableAudioBufSize() { + return audioBuf->getAvailableSize(); +} + +int Microphone::addAudioData(u8 *buf, u32 size) { + if (audioBuf) + audioBuf->push(buf, size); + else + return 0; + return size; } +u32 Microphone::getAudioData(u8 *buf, u32 size) { + if(audioBuf) + return audioBuf->pop(buf, size); + + return 0; +} + +void Microphone::flushAudioData() { + audioBuf->flush(); +} + +std::vector Microphone::getDeviceList() { +#ifdef HAVE_WIN32_MICROPHONE + if (winMic) { + return winMic->getDeviceList(); + } +#endif + return std::vector(); +} + +void Microphone::onMicDeviceChange() { + if (Microphone::isMicStarted()) { + Microphone::stopMic(); + // Just use the last param. + Microphone::startMic(nullptr); + } +} + +u32 __MicInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) { + u32 size = maxSamples << 1; + if (size > numNeedSamples << 1) { + if (!audioBuf) { + audioBuf = new QueueBuf(size); + } else { + audioBuf->resize(size); + } + } + if (!audioBuf) + return 0; + + numNeedSamples = maxSamples; + Microphone::flushAudioData(); + if (!Microphone::isMicStarted()) { + std::vector *param = new std::vector({ sampleRate, 1 }); + Microphone::startMic(param); + } + u64 waitTimeus = 0; + if (Microphone::availableAudioBufSize() < size) { + waitTimeus = (size - Microphone::availableAudioBufSize()) * 1000000 / 2 / sampleRate; + isNeedInput = true; + } + CoreTiming::ScheduleEvent(usToCycles(waitTimeus), eventUsbMicAudioUpdate, __KernelGetCurThread()); + MicWaitInfo waitInfo = { __KernelGetCurThread(), bufAddr, size, sampleRate }; + std::unique_lock lock(wtMutex); + waitingThreads.push_back(waitInfo); + lock.unlock(); + DEBUG_LOG(HLE, "MicInputBlocking: blocking thread(%d)", (int)__KernelGetCurThread()); + __KernelWaitCurThread(WAITTYPE_MICINPUT, 1, size, 0, false, "blocking microphone"); + + return maxSamples; +} + const HLEFunction sceUsbMic[] = { - {0x06128E42, nullptr, "sceUsbMicPollInputEnd", '?', "" }, + {0x06128E42, &WrapI_V, "sceUsbMicPollInputEnd", 'i', "" }, {0x2E6DCDCD, &WrapI_UUU, "sceUsbMicInputBlocking", 'i', "xxx" }, - {0x45310F07, nullptr, "sceUsbMicInputInitEx", '?', "" }, - {0x5F7F368D, nullptr, "sceUsbMicInput", '?', "" }, - {0x63400E20, nullptr, "sceUsbMicGetInputLength", '?', "" }, - {0xB8E536EB, nullptr, "sceUsbMicInputInit", '?', "" }, - {0xF899001C, nullptr, "sceUsbMicWaitInputEnd", '?', "" }, + {0x45310F07, &WrapI_U, "sceUsbMicInputInitEx", 'i', "x" }, + {0x5F7F368D, &WrapI_V , "sceUsbMicInput", 'i', "" }, + {0x63400E20, &WrapI_V, "sceUsbMicGetInputLength", 'i', "" }, + {0xB8E536EB, &WrapI_III, "sceUsbMicInputInit", 'i', "iii" }, + {0xF899001C, &WrapI_V, "sceUsbMicWaitInputEnd", 'i', "" }, }; void Register_sceUsbMic() diff --git a/Core/HLE/sceUsbMic.h b/Core/HLE/sceUsbMic.h index 35e1132861..c073d4cf56 100644 --- a/Core/HLE/sceUsbMic.h +++ b/Core/HLE/sceUsbMic.h @@ -16,4 +16,61 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #pragma once + +#include "sceKernel.h" +#include + void Register_sceUsbMic(); + +void __UsbMicInit(); +void __UsbMicShutdown(); +void __UsbMicDoState(PointerWrap &p); + +struct MicWaitInfo { + SceUID threadID; + u32 addr; + u32 needSize; + u32 sampleRate; +}; + +class QueueBuf { +public: + QueueBuf(u32 size); + ~QueueBuf(); + + QueueBuf(const QueueBuf &buf); + QueueBuf& operator=(const QueueBuf &buf); + + void push(u8 *buf, u32 size); + u32 pop(u8 *buf, u32 size); + void resize(u32 newSize); + void flush(); + u32 getAvailableSize(); + u32 getRemainingSize(); + +private: + u32 start; + u32 end; + u32 capacity; + u8 *buf_; + std::mutex mutex; +}; + +namespace Microphone { + int startMic(void *param); + int stopMic(); + bool isHaveDevice(); + bool isMicStarted(); + bool isNeedInput(); + u32 numNeedSamples(); + u32 availableAudioBufSize(); + + int addAudioData(u8 *buf, u32 size); + u32 getAudioData(u8 *buf, u32 size); + void flushAudioData(); + + std::vector getDeviceList(); + void onMicDeviceChange(); +} + +u32 __MicInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr); diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 42ba77e2f6..966ed2d6c1 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -18,9 +18,12 @@ #include #include -#include "file/ini_file.h" +#include "Common/Data/Format/IniFile.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" +#include "Common/Serialize/SerializeSet.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/MIPS/MIPS.h" @@ -153,8 +156,8 @@ void __UtilityDoState(PointerWrap &p) { return; } - p.Do(currentDialogType); - p.Do(currentDialogActive); + Do(p, currentDialogType); + Do(p, currentDialogActive); saveDialog.DoState(p); msgDialog.DoState(p); oskDialog.DoState(p); @@ -163,10 +166,10 @@ void __UtilityDoState(PointerWrap &p) { gamedataInstallDialog.DoState(p); if (s >= 2) { - p.Do(currentlyLoadedModules); + Do(p, currentlyLoadedModules); } else { std::set oldModules; - p.Do(oldModules); + Do(p, oldModules); for (auto it = oldModules.begin(), end = oldModules.end(); it != end; ++it) { currentlyLoadedModules[*it] = 0; } @@ -714,6 +717,15 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) switch (id) { case PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL: param = g_Config.iWlanAdhocChannel; + if (param == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) { + // FIXME: Actually.. it's always returning 0x800ADF4 regardless using Auto channel or Not, and regardless the connection state either, + // Not sure whether this error code only returned after Adhocctl Initialized (ie. netAdhocctlInited) or also before initialized. + // FIXME: Outputted channel (might be unchanged?) either 0 when not connected to a group yet (ie. adhocctlState == ADHOCCTL_STATE_DISCONNECTED), + // or -1 (0xFFFFFFFF) when a scan is in progress (ie. adhocctlState == ADHOCCTL_STATE_SCANNING), + // or 0x60 early when in connected state (ie. adhocctlState == ADHOCCTL_STATE_CONNECTED) right after Creating a group, regardless the channel settings. + Memory::Write_U32(param, destaddr); + return 0x800ADF4; + } break; case PSP_SYSTEMPARAM_ID_INT_WLAN_POWERSAVE: param = g_Config.bWlanPowerSave?PSP_SYSTEMPARAM_WLAN_POWERSAVE_ON:PSP_SYSTEMPARAM_WLAN_POWERSAVE_OFF; @@ -722,7 +734,10 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) param = g_Config.iDateFormat; break; case PSP_SYSTEMPARAM_ID_INT_TIME_FORMAT: - param = g_Config.iTimeFormat?PSP_SYSTEMPARAM_TIME_FORMAT_12HR:PSP_SYSTEMPARAM_TIME_FORMAT_24HR; + if (g_Config.iTimeFormat == PSP_SYSTEMPARAM_TIME_FORMAT_12HR) + param = PSP_SYSTEMPARAM_TIME_FORMAT_12HR; + else + param = PSP_SYSTEMPARAM_TIME_FORMAT_24HR; break; case PSP_SYSTEMPARAM_ID_INT_TIMEZONE: param = g_Config.iTimeZone; diff --git a/Core/HLE/sceVaudio.cpp b/Core/HLE/sceVaudio.cpp index e3749d0680..7d5819114f 100644 --- a/Core/HLE/sceVaudio.cpp +++ b/Core/HLE/sceVaudio.cpp @@ -15,7 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Reporting.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" @@ -36,7 +37,7 @@ void __VaudioDoState(PointerWrap &p) { if (!s) return; - p.Do(vaudioReserved); + Do(p, vaudioReserved); } static u32 sceVaudioChReserve(int sampleCount, int freq, int format) { diff --git a/Core/HW/AsyncIOManager.cpp b/Core/HW/AsyncIOManager.cpp index b2a99805e4..1d4ce89b0a 100644 --- a/Core/HW/AsyncIOManager.cpp +++ b/Core/HW/AsyncIOManager.cpp @@ -18,7 +18,10 @@ #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" +#include "Common/Serialize/SerializeSet.h" #include "Core/MIPS/MIPS.h" #include "Core/Reporting.h" #include "Core/System.h" @@ -153,12 +156,12 @@ void AsyncIOManager::DoState(PointerWrap &p) { SyncThread(); std::lock_guard guard(resultsLock_); - p.Do(resultsPending_); + Do(p, resultsPending_); if (s >= 2) { - p.Do(results_); + Do(p, results_); } else { std::map oldResults; - p.Do(oldResults); + Do(p, oldResults); for (auto it = oldResults.begin(), end = oldResults.end(); it != end; ++it) { results_[it->first] = AsyncIOResult(it->second); } diff --git a/Core/HW/AsyncIOManager.h b/Core/HW/AsyncIOManager.h index 41b997b089..4b1e0b5276 100644 --- a/Core/HW/AsyncIOManager.h +++ b/Core/HW/AsyncIOManager.h @@ -61,10 +61,10 @@ struct AsyncIOResult { if (!s) return; - p.Do(result); - p.Do(finishTicks); + Do(p, result); + Do(p, finishTicks); if (s >= 2) { - p.Do(invalidateAddr); + Do(p, invalidateAddr); } else { invalidateAddr = 0; } @@ -91,7 +91,7 @@ public: protected: void ProcessEvent(AsyncIOEvent ref) override; bool ShouldExitEventLoop() override { - return coreState == CORE_ERROR || coreState == CORE_POWERDOWN; + return coreState == CORE_BOOT_ERROR || coreState == CORE_RUNTIME_ERROR || coreState == CORE_POWERDOWN; } private: @@ -106,4 +106,4 @@ private: std::condition_variable resultsWait_; std::set resultsPending_; std::map results_; -}; \ No newline at end of file +}; diff --git a/Core/HW/BufferQueue.cpp b/Core/HW/BufferQueue.cpp new file mode 100644 index 0000000000..9fbffe0c65 --- /dev/null +++ b/Core/HW/BufferQueue.cpp @@ -0,0 +1,35 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" +#include "Core/HW/BufferQueue.h" + +void BufferQueue::DoState(PointerWrap &p) { + auto s = p.Section("BufferQueue", 0, 1); + + Do(p, bufQueueSize); + Do(p, start); + Do(p, end); + if (bufQueue) { + DoArray(p, bufQueue, bufQueueSize); + } + + if (s >= 1) { + Do(p, ptsMarks); + } +} diff --git a/Core/HW/BufferQueue.h b/Core/HW/BufferQueue.h index 79e7072f19..b587b29498 100644 --- a/Core/HW/BufferQueue.h +++ b/Core/HW/BufferQueue.h @@ -19,7 +19,7 @@ #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" struct BufferQueue { BufferQueue(int size = 0x20000) { @@ -124,20 +124,7 @@ struct BufferQueue { return bytesgot; } - void DoState(PointerWrap &p) { - auto s = p.Section("BufferQueue", 0, 1); - - p.Do(bufQueueSize); - p.Do(start); - p.Do(end); - if (bufQueue) { - p.DoArray(bufQueue, bufQueueSize); - } - - if (s >= 1) { - p.Do(ptsMarks); - } - } + void DoState(PointerWrap &p); private: void savePts(u64 pts) { diff --git a/Core/HW/Camera.cpp b/Core/HW/Camera.cpp index 75c1a74eb8..415ac0a190 100644 --- a/Core/HW/Camera.cpp +++ b/Core/HW/Camera.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Camera.h" +#include "Core/Config.h" void convert_frame(int inw, int inh, unsigned char *inData, AVPixelFormat inFormat, int outw, int outh, unsigned char **outData, int *outLen) { @@ -242,15 +243,16 @@ void *v4l_loop(void *data) { int jpegLen = 0; if (v4l_format == V4L2_PIX_FMT_YUYV) { - convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)v4l_buffer, AV_PIX_FMT_YUYV422, + convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)v4l_buffers[buf.index].start, AV_PIX_FMT_YUYV422, v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen); - } else if (v4l_format == V4L2_PIX_FMT_MJPEG) { + } else if (v4l_format == V4L2_PIX_FMT_JPEG + || v4l_format == V4L2_PIX_FMT_MJPEG) { // decompress jpeg int width, height, req_comps; unsigned char *rgbData = jpgd::decompress_jpeg_image_from_memory( - (unsigned char*)v4l_buffer, buf.bytesused, &width, &height, &req_comps, 3); + (unsigned char*)v4l_buffers[buf.index].start, buf.bytesused, &width, &height, &req_comps, 3); - convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)v4l_buffer, AV_PIX_FMT_RGB24, + convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)rgbData, AV_PIX_FMT_RGB24, v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen); free(rgbData); } @@ -318,7 +320,8 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { if (fmt.fmt.pix.pixelformat != 0) { continue; } else if (desc.pixelformat == V4L2_PIX_FMT_YUYV - || desc.pixelformat == V4L2_PIX_FMT_MJPEG) { + || desc.pixelformat == V4L2_PIX_FMT_JPEG + || desc.pixelformat == V4L2_PIX_FMT_MJPEG) { INFO_LOG(HLE, "V4L2: %s selected", desc.description); fmt.fmt.pix.pixelformat = desc.pixelformat; v4l_format = desc.pixelformat; @@ -373,38 +376,43 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { ERROR_LOG(HLE, "VIDIOC_REQBUFS"); return -1; } + v4l_buffer_count = req.count; + INFO_LOG(HLE, "V4L2: buffer count: %d", v4l_buffer_count); + v4l_buffers = (v4l_buf_t*) calloc(v4l_buffer_count, sizeof(v4l_buf_t)); - struct v4l2_buffer buf; - memset(&buf, 0, sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = 0; - if (ioctl(v4l_fd, VIDIOC_QUERYBUF, &buf) == -1) { - ERROR_LOG(HLE, "VIDIOC_QUERYBUF"); - return -1; + for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) { + struct v4l2_buffer buf; + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = buf_id; + if (ioctl(v4l_fd, VIDIOC_QUERYBUF, &buf) == -1) { + ERROR_LOG(HLE, "VIDIOC_QUERYBUF"); + return -1; + } + + v4l_buffers[buf_id].length = buf.length; + v4l_buffers[buf_id].start = mmap(NULL, + buf.length, + PROT_READ | PROT_WRITE, + MAP_SHARED, + v4l_fd, buf.m.offset); + if (v4l_buffers[buf_id].start == MAP_FAILED) { + ERROR_LOG(HLE, "MAP_FAILED"); + return -1; + } + + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = buf_id; + if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) { + ERROR_LOG(HLE, "VIDIOC_QBUF"); + return -1; + } } - v4l_length = buf.length; - v4l_buffer = mmap(NULL, - v4l_length, - PROT_READ | PROT_WRITE, - MAP_SHARED, - v4l_fd, buf.m.offset); - if (v4l_buffer == MAP_FAILED) { - ERROR_LOG(HLE, "MAP_FAILED"); - return -1; - } - - memset(&buf, 0, sizeof(buf)); enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.type = type; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = 0; - if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) { - ERROR_LOG(HLE, "VIDIOC_QBUF"); - return -1; - } - if (ioctl(v4l_fd, VIDIOC_STREAMON, &type) == -1) { ERROR_LOG(HLE, "VIDIOC_STREAMON"); return -1; @@ -427,9 +435,11 @@ int __v4l_stopCapture() { goto exit; } - if (munmap(v4l_buffer, v4l_length) == -1) { - ERROR_LOG(HLE, "munmap"); - goto exit; + for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) { + if (munmap(v4l_buffers[buf_id].start, v4l_buffers[buf_id].length) == -1) { + ERROR_LOG(HLE, "munmap"); + goto exit; + } } if (close(v4l_fd) == -1) { diff --git a/Core/HW/Camera.h b/Core/HW/Camera.h index 9308e1e732..c23290915f 100644 --- a/Core/HW/Camera.h +++ b/Core/HW/Camera.h @@ -18,7 +18,6 @@ #pragma once #include "ppsspp_config.h" -#include "Core/Config.h" #include "Core/HLE/sceUsbCam.h" #include "Log.h" @@ -58,7 +57,12 @@ void __cameraDummyImage(int width, int height, unsigned char** outData, int* out #include #include -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" + + typedef struct { + void *start; + int length; + } v4l_buf_t; static int v4l_fd = -1; static uint32_t v4l_format; @@ -69,8 +73,8 @@ void __cameraDummyImage(int width, int height, unsigned char** outData, int* out static int v4l_ideal_height; static pthread_t v4l_thread; - static void *v4l_buffer; - static int v4l_length; + static int v4l_buffer_count; + static v4l_buf_t *v4l_buffers; std::vector __v4l_getDeviceList(); int __v4l_startCapture(int width, int height); diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 8df4f1b398..2d97916349 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Config.h" #include "Core/Debugger/Breakpoints.h" #include "Core/HW/MediaEngine.h" @@ -185,25 +186,25 @@ void MediaEngine::DoState(PointerWrap &p) { if (!s) return; - p.Do(m_videoStream); - p.Do(m_audioStream); + Do(p, m_videoStream); + Do(p, m_audioStream); - p.DoArray(m_mpegheader, sizeof(m_mpegheader)); + DoArray(p, m_mpegheader, sizeof(m_mpegheader)); if (s >= 4) { - p.Do(m_mpegheaderSize); + Do(p, m_mpegheaderSize); } else { m_mpegheaderSize = sizeof(m_mpegheader); } if (s >= 5) { - p.Do(m_mpegheaderReadPos); + Do(p, m_mpegheaderReadPos); } else { m_mpegheaderReadPos = m_mpegheaderSize; } - p.Do(m_ringbuffersize); + Do(p, m_ringbuffersize); u32 hasloadStream = m_pdata != NULL; - p.Do(hasloadStream); + Do(p, hasloadStream); if (hasloadStream && p.mode == p.MODE_READ) reloadStream(); #ifdef USE_FFMPEG @@ -211,29 +212,29 @@ void MediaEngine::DoState(PointerWrap &p) { #else u32 hasopencontext = false; #endif - p.Do(hasopencontext); + Do(p, hasopencontext); if (m_pdata) m_pdata->DoState(p); if (m_demux) m_demux->DoState(p); - p.Do(m_videopts); - p.Do(m_audiopts); + Do(p, m_videopts); + Do(p, m_audiopts); if (s >= 2) { - p.Do(m_firstTimeStamp); - p.Do(m_lastTimeStamp); + Do(p, m_firstTimeStamp); + Do(p, m_lastTimeStamp); } if (hasopencontext && p.mode == p.MODE_READ) { openContext(true); } - p.Do(m_isVideoEnd); + Do(p, m_isVideoEnd); bool noAudioDataRemoved; - p.Do(noAudioDataRemoved); + Do(p, noAudioDataRemoved); if (s >= 3) { - p.Do(m_audioType); + Do(p, m_audioType); } else { m_audioType = PSP_CODEC_AT3PLUS; } diff --git a/Core/HW/MemoryStick.cpp b/Core/HW/MemoryStick.cpp index 42bc625bdb..f0d9a38708 100644 --- a/Core/HW/MemoryStick.cpp +++ b/Core/HW/MemoryStick.cpp @@ -1,5 +1,24 @@ -#include "Common/ChunkFile.h" +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/CoreTiming.h" +#include "Core/Compatibility.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/HW/MemoryStick.h" #include "Core/System.h" @@ -7,26 +26,31 @@ // MS and FatMS states. static MemStickState memStickState; static MemStickFatState memStickFatState; -static u64 memStickSize; static bool memStickNeedsAssign = false; static u64 memStickInsertedAt = 0; +const u64 normalMemstickSize = 9ULL * 1024 * 1024 * 1024; +const u64 smallMemstickSize = 1ULL * 1024 * 1024 * 1024; + void MemoryStick_DoState(PointerWrap &p) { - auto s = p.Section("MemoryStick", 1, 3); + auto s = p.Section("MemoryStick", 1, 4); if (!s) return; - p.Do(memStickState); - p.Do(memStickFatState); - if (s >= 2) - p.Do(memStickSize); - else - memStickSize = 1ULL * 1024 * 1024 * 1024; - if (s >= 3) { - p.Do(memStickNeedsAssign); - p.Do(memStickInsertedAt); + Do(p, memStickState); + Do(p, memStickFatState); + if (s >= 4) { + // Do nothing. + } else if (s >= 2) { + // Really no point in storing the memstick size. + u64 memStickSize = normalMemstickSize; + Do(p, memStickSize); } + if (s >= 3) { + Do(p, memStickNeedsAssign); + Do(p, memStickInsertedAt); + } } MemStickState MemoryStick_State() { @@ -48,6 +72,11 @@ u64 MemoryStick_SectorSize() { u64 MemoryStick_FreeSpace() { u64 freeSpace = pspFileSystem.FreeSpace("ms0:/"); + + // Cap the memory stick size to avoid math errors when old games get sizes that were + // hard to imagine back then. + // We have a compat setting to make it even smaller for Harry Potter : Goblet of Fire, see #13266. + const u64 memStickSize = PSP_CoreParameter().compat.flags().ReportSmallMemstick ? smallMemstickSize : normalMemstickSize; if (freeSpace < memStickSize) return freeSpace; return memStickSize; @@ -83,9 +112,5 @@ void MemoryStick_Init() { memStickFatState = PSP_FAT_MEMORYSTICK_STATE_UNASSIGNED; } - // Harry Potter and the Goblet of Fire has a bug where it can't handle certain amounts - // of free space due to incorrect 32-bit math. - // We use 9GB here, which does not trigger the bug, as a cap for the max free space. - memStickSize = 9ULL * 1024 * 1024 * 1024; // 9GB memStickNeedsAssign = false; } diff --git a/Core/HW/MemoryStick.h b/Core/HW/MemoryStick.h index 01b526fa98..f8bd295aba 100644 --- a/Core/HW/MemoryStick.h +++ b/Core/HW/MemoryStick.h @@ -1,3 +1,20 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + #pragma once #include "Common/CommonTypes.h" diff --git a/Core/HW/MpegDemux.cpp b/Core/HW/MpegDemux.cpp index 7b51c6b68a..da121f72e0 100644 --- a/Core/HW/MpegDemux.cpp +++ b/Core/HW/MpegDemux.cpp @@ -1,4 +1,5 @@ -#include "MpegDemux.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Core/HW/MpegDemux.h" #include "Core/Reporting.h" const int PACKET_START_CODE_MASK = 0xffffff00; @@ -37,13 +38,13 @@ void MpegDemux::DoState(PointerWrap &p) { if (!s) return; - p.Do(m_index); - p.Do(m_len); - p.Do(m_audioChannel); - p.Do(m_readSize); + Do(p, m_index); + Do(p, m_len); + Do(p, m_audioChannel); + Do(p, m_readSize); if (m_buf) - p.DoArray(m_buf, m_len); - p.DoClass(m_audioStream); + DoArray(p, m_buf, m_len); + DoClass(p, m_audioStream); } bool MpegDemux::addStreamData(const u8 *buf, int addSize) { diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index a0afc9e9b4..f588539414 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -17,9 +17,9 @@ #include -#include "base/basictypes.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/MemMapHelpers.h" #include "Core/HLE/sceAtrac.h" #include "Core/Config.h" @@ -159,28 +159,28 @@ void VagDecoder::DoState(PointerWrap &p) { return; if (s >= 2) { - p.DoArray(samples, ARRAY_SIZE(samples)); + DoArray(p, samples, ARRAY_SIZE(samples)); } else { int samplesOld[ARRAY_SIZE(samples)]; - p.DoArray(samplesOld, ARRAY_SIZE(samples)); + DoArray(p, samplesOld, ARRAY_SIZE(samples)); for (size_t i = 0; i < ARRAY_SIZE(samples); ++i) { samples[i] = samplesOld[i]; } } - p.Do(curSample); + Do(p, curSample); - p.Do(data_); - p.Do(read_); - p.Do(curBlock_); - p.Do(loopStartBlock_); - p.Do(numBlocks_); + Do(p, data_); + Do(p, read_); + Do(p, curBlock_); + Do(p, loopStartBlock_); + Do(p, numBlocks_); - p.Do(s_1); - p.Do(s_2); + Do(p, s_1); + Do(p, s_2); - p.Do(loopEnabled_); - p.Do(loopAtNextBlock_); - p.Do(end_); + Do(p, loopEnabled_); + Do(p, loopAtNextBlock_); + Do(p, end_); } int SasAtrac3::setContext(u32 context) { @@ -226,13 +226,13 @@ void SasAtrac3::DoState(PointerWrap &p) { if (!s) return; - p.Do(contextAddr_); - p.Do(atracID_); + Do(p, contextAddr_); + Do(p, atracID_); if (p.mode == p.MODE_READ && atracID_ >= 0 && !sampleQueue_) { sampleQueue_ = new BufferQueue(); } if (s >= 2) { - p.Do(end_); + Do(p, end_); } } @@ -693,7 +693,7 @@ void SasInstance::DoState(PointerWrap &p) { if (!s) return; - p.Do(grainSize); + Do(p, grainSize); if (p.mode == p.MODE_READ) { if (grainSize > 0) { SetGrainSize(grainSize); @@ -702,32 +702,32 @@ void SasInstance::DoState(PointerWrap &p) { } } - p.Do(maxVoices); - p.Do(sampleRate); - p.Do(outputMode); + Do(p, maxVoices); + Do(p, sampleRate); + Do(p, outputMode); // SetGrainSize() / ClearGrainSize() should've made our buffers match. if (mixBuffer != NULL && grainSize > 0) { - p.DoArray(mixBuffer, grainSize * 2); + DoArray(p, mixBuffer, grainSize * 2); } if (sendBuffer != NULL && grainSize > 0) { - p.DoArray(sendBuffer, grainSize * 2); + DoArray(p, sendBuffer, grainSize * 2); } if (sendBuffer != NULL && grainSize > 0) { // Backwards compat int16_t *resampleBuf = new int16_t[grainSize * 4 + 3](); - p.DoArray(resampleBuf, grainSize * 4 + 3); + DoArray(p, resampleBuf, grainSize * 4 + 3); delete[] resampleBuf; } int n = PSP_SAS_VOICES_MAX; - p.Do(n); + Do(p, n); if (n != PSP_SAS_VOICES_MAX) { ERROR_LOG(SAVESTATE, "Wrong number of SAS voices"); return; } - p.DoArray(voices, ARRAY_SIZE(voices)); - p.Do(waveformEffect); + DoArray(p, voices, ARRAY_SIZE(voices)); + Do(p, waveformEffect); if (p.mode == p.MODE_READ) { reverb_.SetPreset(waveformEffect.type); } @@ -777,45 +777,45 @@ void SasVoice::DoState(PointerWrap &p) { if (!s) return; - p.Do(playing); - p.Do(paused); - p.Do(on); + Do(p, playing); + Do(p, paused); + Do(p, on); - p.Do(type); + Do(p, type); - p.Do(vagAddr); - p.Do(vagSize); - p.Do(pcmAddr); - p.Do(pcmSize); - p.Do(pcmIndex); + Do(p, vagAddr); + Do(p, vagSize); + Do(p, pcmAddr); + Do(p, pcmSize); + Do(p, pcmIndex); if (s >= 2) { - p.Do(pcmLoopPos); + Do(p, pcmLoopPos); } else { pcmLoopPos = 0; } - p.Do(sampleRate); + Do(p, sampleRate); - p.Do(sampleFrac); - p.Do(pitch); - p.Do(loop); + Do(p, sampleFrac); + Do(p, pitch); + Do(p, loop); if (s < 2 && type == VOICETYPE_PCM) { // We set loop incorrectly before, and always looped. // Let's keep always looping, since it's usually right. loop = true; } - p.Do(noiseFreq); + Do(p, noiseFreq); - p.Do(volumeLeft); - p.Do(volumeRight); + Do(p, volumeLeft); + Do(p, volumeRight); if (s < 3) { // There were extra variables here that were for the same purpose. - p.Do(effectLeft); - p.Do(effectRight); + Do(p, effectLeft); + Do(p, effectRight); } - p.Do(effectLeft); - p.Do(effectRight); - p.DoArray(resampleHist, ARRAY_SIZE(resampleHist)); + Do(p, effectLeft); + Do(p, effectRight); + DoArray(p, resampleHist, ARRAY_SIZE(resampleHist)); envelope.DoState(p); vag.DoState(p); @@ -949,24 +949,24 @@ void ADSREnvelope::DoState(PointerWrap &p) { return; } - p.Do(attackRate); - p.Do(decayRate); - p.Do(sustainRate); - p.Do(releaseRate); - p.Do(attackType); - p.Do(decayType); - p.Do(sustainType); - p.Do(sustainLevel); - p.Do(releaseType); + Do(p, attackRate); + Do(p, decayRate); + Do(p, sustainRate); + Do(p, releaseRate); + Do(p, attackType); + Do(p, decayType); + Do(p, sustainType); + Do(p, sustainLevel); + Do(p, releaseType); if (s < 2) { - p.Do(state_); + Do(p, state_); if (state_ == 4) { state_ = STATE_OFF; } int stepsLegacy; - p.Do(stepsLegacy); + Do(p, stepsLegacy); } else { - p.Do(state_); + Do(p, state_); } - p.Do(height_); + Do(p, height_); } diff --git a/Core/HW/SasReverb.cpp b/Core/HW/SasReverb.cpp index 7dfb429f8b..14dbc06248 100644 --- a/Core/HW/SasReverb.cpp +++ b/Core/HW/SasReverb.cpp @@ -18,7 +18,6 @@ #include #include -#include "base/basictypes.h" #include "Core/HW/SasReverb.h" #include "Core/Util/AudioFormat.h" diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 4e4b2e642f..84e18df67e 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -17,6 +17,7 @@ #include +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Config.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HW/SimpleAudioDec.h" @@ -502,25 +503,25 @@ void AuCtx::DoState(PointerWrap &p) { if (!s) return; - p.Do(startPos); - p.Do(endPos); - p.Do(AuBuf); - p.Do(AuBufSize); - p.Do(PCMBuf); - p.Do(PCMBufSize); - p.Do(freq); - p.Do(SumDecodedSamples); - p.Do(LoopNum); - p.Do(Channels); - p.Do(MaxOutputSample); - p.Do(readPos); - p.Do(audioType); - p.Do(BitRate); - p.Do(SamplingRate); - p.Do(askedReadSize); + Do(p, startPos); + Do(p, endPos); + Do(p, AuBuf); + Do(p, AuBufSize); + Do(p, PCMBuf); + Do(p, PCMBufSize); + Do(p, freq); + Do(p, SumDecodedSamples); + Do(p, LoopNum); + Do(p, Channels); + Do(p, MaxOutputSample); + Do(p, readPos); + Do(p, audioType); + Do(p, BitRate); + Do(p, SamplingRate); + Do(p, askedReadSize); int dummy = 0; - p.Do(dummy); - p.Do(FrameNum); + Do(p, dummy); + Do(p, FrameNum); if (p.mode == p.MODE_READ) { decoder = new SimpleAudio(audioType); diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index 5a21bfe330..d7bcfc7b03 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -19,7 +19,6 @@ #include -#include "base/basictypes.h" #include "Core/HW/MediaEngine.h" #include "Core/HLE/sceAudio.h" diff --git a/Core/HW/StereoResampler.cpp b/Core/HW/StereoResampler.cpp index a6e06fafcf..8e7f22833d 100644 --- a/Core/HW/StereoResampler.cpp +++ b/Core/HW/StereoResampler.cpp @@ -35,11 +35,11 @@ #include #include -#include "base/logging.h" -#include "base/timeutil.h" -#include "base/NativeApp.h" -#include "Common/ChunkFile.h" -#include "Common/MathUtil.h" +#include "Common/System/System.h" +#include "Common/Math/math_util.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Log.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/HW/StereoResampler.h" @@ -71,7 +71,7 @@ StereoResampler::StereoResampler() // If framerate is "close"... if (refresh != 60.0f && refresh > 50.0f && refresh < 70.0f) { int input_sample_rate = (int)(44100 * (refresh / 60.0f)); - ILOG("StereoResampler: Adjusting target sample rate to %dHz", input_sample_rate); + INFO_LOG(AUDIO, "StereoResampler: Adjusting target sample rate to %dHz", input_sample_rate); m_input_sample_rate = input_sample_rate; } @@ -179,7 +179,9 @@ unsigned int StereoResampler::Mix(short* samples, unsigned int numSamples, bool u32 indexW = m_indexW.load(); const int INDEX_MASK = (m_maxBufsize * 2 - 1); - lastBufSize_ = (indexR - m_indexW) & INDEX_MASK; + + // This is only for debug visualization, not used for anything. + lastBufSize_ = ((indexW - indexR) & INDEX_MASK) / 2; // Drift prevention mechanism. float numLeft = (float)(((indexW - indexR) & INDEX_MASK) / 2); @@ -289,7 +291,7 @@ void StereoResampler::PushSamples(const s32 *samples, unsigned int numSamples) { } void StereoResampler::GetAudioDebugStats(char *buf, size_t bufSize) { - double elapsed = real_time_now() - startTime_; + double elapsed = time_now_d() - startTime_; double effective_input_sample_rate = (double)inputSampleCount_ / elapsed; double effective_output_sample_rate = (double)outputSampleCount_ / elapsed; @@ -333,7 +335,7 @@ void StereoResampler::ResetStatCounters() { overrunCountTotal_ = 0; inputSampleCount_ = 0; outputSampleCount_ = 0; - startTime_ = real_time_now(); + startTime_ = time_now_d(); } void StereoResampler::DoState(PointerWrap &p) { diff --git a/Core/HW/StereoResampler.h b/Core/HW/StereoResampler.h index 451b598d66..4b10d032c0 100644 --- a/Core/HW/StereoResampler.h +++ b/Core/HW/StereoResampler.h @@ -22,7 +22,7 @@ #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" #include "Common/CommonTypes.h" struct AudioDebugStats; diff --git a/Core/Host.h b/Core/Host.h index 2fd79e9510..35838c8083 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -48,6 +48,7 @@ public: virtual bool IsDebuggingEnabled() {return true;} virtual bool AttemptLoadSymbolMap(); virtual void SaveSymbolMap() {} + virtual void NotifySymbolMapUpdated() {} virtual void SetWindowTitle(const char *message) {} virtual bool CanCreateShortcut() {return false;} diff --git a/Core/Instance.cpp b/Core/Instance.cpp new file mode 100644 index 0000000000..8084c2ff25 --- /dev/null +++ b/Core/Instance.cpp @@ -0,0 +1,189 @@ +// Copyright (c) 2020 PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Instance.h" + +#if __linux__ || __APPLE__ +#include +#include +#include +#include +#endif + +#include "Common/Log.h" + +#if PPSSPP_PLATFORM(WINDOWS) + +#include "Common/CommonWindows.h" + +#endif + +#include + +uint8_t PPSSPP_ID = 0; + +#if PPSSPP_PLATFORM(WINDOWS) +static HANDLE hIDMapFile = nullptr; +static HANDLE mapLock = nullptr; +#else +static int hIDMapFile = -1; +static long BUF_SIZE = 4096; +#endif + +struct InstanceInfo { + uint8_t pad[2]; + uint8_t next; + uint8_t total; +}; + +#define ID_SHM_NAME "/PPSSPP_ID" + +static bool UpdateInstanceCounter(void (*callback)(volatile InstanceInfo *)) { +#if PPSSPP_PLATFORM(WINDOWS) + if (!hIDMapFile) { + return false; + } + InstanceInfo *buf = (InstanceInfo *)MapViewOfFile(hIDMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(InstanceInfo)); + + if (!buf) { + ERROR_LOG(SCENET, "Could not map view of file %s (%d).", ID_SHM_NAME, GetLastError()); + return false; + } + + bool result = false; + if (!mapLock || WaitForSingleObject(mapLock, INFINITE) == 0) { + callback(buf); + if (mapLock) { + ReleaseMutex(mapLock); + } + result = true; + } + UnmapViewOfFile(buf); + + return result; +#elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) + // TODO: replace shm_open & shm_unlink with ashmem or android-shmem + return false; +#else + if (hIDMapFile < 0) { + return false; + } + + InstanceInfo *buf = (InstanceInfo *)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0); + if (buf == MAP_FAILED) { + ERROR_LOG(SCENET, "mmap(%s) failure.", ID_SHM_NAME); + return false; + } + + bool result = false; + if (mlock(buf, BUF_SIZE) == 0) { + callback(buf); + munlock(buf, BUF_SIZE); + result = true; + } + + munmap(buf, BUF_SIZE); + return result; +#endif +} + +int GetInstancePeerCount() { + static int c = 0; + UpdateInstanceCounter([](volatile InstanceInfo *buf) { + c = buf->total; + }); + return c; +} + +// Get current number of instance of PPSSPP running. +// Must be called only once during init. +void InitInstanceCounter() { +#if PPSSPP_PLATFORM(WINDOWS) + uint32_t BUF_SIZE = 4096; + SYSTEM_INFO sysInfo; + + GetSystemInfo(&sysInfo); + int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; + BUF_SIZE = (BUF_SIZE + gran - 1) & ~(gran - 1); + + mapLock = CreateMutex(nullptr, FALSE, L"PPSSPP_ID_mutex"); + + hIDMapFile = CreateFileMapping( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + BUF_SIZE, // maximum object size (low-order DWORD) + TEXT(ID_SHM_NAME)); // name of mapping object + + DWORD lasterr = GetLastError(); + if (!hIDMapFile) { + ERROR_LOG(SCENET, "Could not create %s file mapping object (%d).", ID_SHM_NAME, lasterr); + PPSSPP_ID = 1; + return; + } +#elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) + // TODO : replace shm_open & shm_unlink with ashmem or android-shmem +#else + // Create shared memory object + hIDMapFile = shm_open(ID_SHM_NAME, O_CREAT | O_RDWR, 0); + BUF_SIZE = (BUF_SIZE < sysconf(_SC_PAGE_SIZE)) ? sysconf(_SC_PAGE_SIZE) : BUF_SIZE; + + if (hIDMapFile < 0 || (ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size + ERROR_LOG(SCENET, "ftruncate(%s) failure.", ID_SHM_NAME); + PPSSPP_ID = 1; + return; + } +#endif + + bool success = UpdateInstanceCounter([](volatile InstanceInfo *buf) { + PPSSPP_ID = ++buf->next; + buf->total++; + }); + if (!success) { + PPSSPP_ID = 1; + } +} + +void ShutdownInstanceCounter() { + UpdateInstanceCounter([](volatile InstanceInfo *buf) { + buf->total--; + }); + +#if PPSSPP_PLATFORM(WINDOWS) + if (hIDMapFile) { + CloseHandle(hIDMapFile); // If program exited(or crashed?) or the last handle reference closed the shared memory object will be deleted. + hIDMapFile = nullptr; + } + if (mapLock) { + CloseHandle(mapLock); + mapLock = nullptr; + } +#elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) + // Do nothing +#else + if (hIDMapFile >= 0) { + close(hIDMapFile); + shm_unlink(ID_SHM_NAME); // If program exited or crashed before unlinked the shared memory object and it's contents will persist. + hIDMapFile = -1; + } +#endif +} diff --git a/Core/Instance.h b/Core/Instance.h new file mode 100644 index 0000000000..12f6518f10 --- /dev/null +++ b/Core/Instance.h @@ -0,0 +1,32 @@ +// Copyright (c) 2020 PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "ppsspp_config.h" + +#include + +extern uint8_t PPSSPP_ID; + +void InitInstanceCounter(); +void ShutdownInstanceCounter(); +int GetInstancePeerCount(); + +inline bool IsFirstInstance() { + return PPSSPP_ID == 1; +} diff --git a/Common/KeyMap.cpp b/Core/KeyMap.cpp similarity index 98% rename from Common/KeyMap.cpp rename to Core/KeyMap.cpp index e4f5f47f9a..ab232a939a 100644 --- a/Common/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -24,15 +24,17 @@ #include "CommonWindows.h" #endif -#include "base/logging.h" -#include "base/NativeApp.h" -#include "file/ini_file.h" -#include "input/input_state.h" #include "ppsspp_config.h" -#include "KeyMap.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Data/Format/IniFile.h" +#include "Common/Input/InputState.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" #include "Core/HLE/sceUtility.h" #include "Core/Config.h" +#include "Core/KeyMap.h" namespace KeyMap { @@ -901,10 +903,10 @@ void RestoreDefault() { } else if (IsXperiaPlay(name)) { SetDefaultKeyMap(DEFAULT_MAPPING_XPERIA_PLAY, true); } else if (IsMOQII7S(name)) { - ILOG("MOQI pad map"); + INFO_LOG(SYSTEM, "MOQI pad map"); SetDefaultKeyMap(DEFAULT_MAPPING_MOQI_I7S, true); } else { - ILOG("Default pad map"); + INFO_LOG(SYSTEM, "Default pad map"); SetDefaultKeyMap(DEFAULT_MAPPING_PAD, true); } #else @@ -920,7 +922,7 @@ void LoadFromIni(IniFile &file) { return; } - IniFile::Section *controls = file.GetOrCreateSection("ControlMapping"); + Section *controls = file.GetOrCreateSection("ControlMapping"); for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) { std::string value; controls->Get(psp_button_names[i].name, &value, ""); @@ -947,7 +949,7 @@ void LoadFromIni(IniFile &file) { } void SaveToIni(IniFile &file) { - IniFile::Section *controls = file.GetOrCreateSection("ControlMapping"); + Section *controls = file.GetOrCreateSection("ControlMapping"); for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) { std::vector keys; @@ -995,7 +997,7 @@ void NotifyPadConnected(const std::string &name) { } void AutoConfForPad(const std::string &name) { - ILOG("Autoconfiguring pad for '%s'", name.c_str()); + INFO_LOG(SYSTEM, "Autoconfiguring pad for '%s'", name.c_str()); if (name == "Xbox 360 Pad") { SetDefaultKeyMap(DEFAULT_MAPPING_X360, true); } else { diff --git a/Common/KeyMap.h b/Core/KeyMap.h similarity index 97% rename from Common/KeyMap.h rename to Core/KeyMap.h index ce2f499f47..a94f603417 100644 --- a/Common/KeyMap.h +++ b/Core/KeyMap.h @@ -21,8 +21,8 @@ #include #include #include -#include "input/input_state.h" // KeyDef -#include "input/keycodes.h" // keyboard keys +#include "Common/Input/InputState.h" // KeyDef +#include "Common/Input/KeyCodes.h" // keyboard keys #include "../Core/HLE/sceCtrl.h" // psp keys #define KEYMAP_ERROR_KEY_ALREADY_USED -1 diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index a4d102e122..77c2fafae0 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -18,10 +18,8 @@ #include #include -#include "base/stringutil.h" -#include "file/file_util.h" -#include "Common/FileUtil.h" - +#include "Common/File/FileUtil.h" +#include "Common/StringUtils.h" #include "Core/FileLoaders/CachingFileLoader.h" #include "Core/FileLoaders/DiskCachingFileLoader.h" #include "Core/FileLoaders/HTTPFileLoader.h" @@ -127,17 +125,13 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { u32 psar_offset = 0, psar_id = 0; u32 _id = id; - switch (_id) { - case 'PBP\x00': + if (!memcmp(&_id, "PK\x03\x04", 4) || !memcmp(&_id, "PK\x05\x06", 4) || !memcmp(&_id, "PK\x07\x08", 4)) { + return IdentifiedFileType::ARCHIVE_ZIP; + } else if (!memcmp(&_id, "\x00PBP", 4)) { fileLoader->ReadAt(0x24, 4, 1, &psar_offset); fileLoader->ReadAt(psar_offset, 4, 1, &psar_id); - break; - case '!raR': + } else if (!memcmp(&_id, "Rar!", 4)) { return IdentifiedFileType::ARCHIVE_RAR; - case '\x04\x03KP': - case '\x06\x05KP': - case '\x08\x07KP': - return IdentifiedFileType::ARCHIVE_ZIP; } if (id == 'FLE\x7F') { @@ -258,7 +252,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { } else if (ebootType == IdentifiedFileType::PSP_PS1_PBP) { *error_string = "PS1 EBOOTs are not supported by PPSSPP."; - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; return false; } std::string path = fileLoader->Path(); @@ -270,7 +264,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { return Load_PSP_ELF_PBP(fileLoader, error_string); } else { *error_string = "No EBOOT.PBP, misidentified game"; - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; return false; } } @@ -352,7 +346,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { break; } - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; return false; } diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index 3a5bcba1a5..44176dc293 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -237,6 +237,7 @@ void ArmJit::GenerateFixedCode() { CMP(R0, 0); B_CC(CC_EQ, outerLoop); + const uint8_t *quitLoop = GetCodePtr(); SetJumpTarget(badCoreState); SaveDowncount(); @@ -251,6 +252,12 @@ void ArmJit::GenerateFixedCode() { POP(9, R4, R5, R6, R7, R8, R9, R10, R11, R_PC); // Returns + crashHandler = GetCodePtr(); + MOVP2R(R0, &coreState); + MOVI2R(R1, CORE_RUNTIME_ERROR); + STR(R1, R0, 0); + B(quitLoop); + // Uncomment if you want to see the output... if (disasm) { INFO_LOG(JIT, "THE DISASM ========================"); diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 66d12ed8a9..471b3e0dc2 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -19,11 +19,13 @@ #if PPSSPP_ARCH(ARM) #include + #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/ARM/ArmJit.h" #include "Core/MIPS/ARM/ArmRegCache.h" #include "Common/CPUDetect.h" +#include "Common/BitSet.h" using namespace MIPSAnalyst; diff --git a/Core/MIPS/ARM/ArmCompBranch.cpp b/Core/MIPS/ARM/ArmCompBranch.cpp index e96643643d..f05bd96f30 100644 --- a/Core/MIPS/ARM/ArmCompBranch.cpp +++ b/Core/MIPS/ARM/ArmCompBranch.cpp @@ -18,10 +18,11 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(ARM) -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" -#include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/Core.h" +#include "Core/Reporting.h" #include "Core/MemMap.h" #include "Core/HLE/HLE.h" #include "Core/HLE/HLETables.h" @@ -85,7 +86,7 @@ void ArmJit::BranchRSRTComp(MIPSOpcode op, CCFlags cc, bool likely) { case CC_EQ: immBranchNotTaken = rsImm == rtImm; break; case CC_NEQ: immBranchNotTaken = rsImm != rtImm; break; - default: immBranchNotTaken = false; _dbg_assert_msg_(JIT, false, "Bad cc flag in BranchRSRTComp()."); + default: immBranchNotTaken = false; _dbg_assert_msg_(false, "Bad cc flag in BranchRSRTComp()."); } immBranch = true; immBranchTaken = !immBranchNotTaken; @@ -198,7 +199,7 @@ void ArmJit::BranchRSZeroComp(MIPSOpcode op, CCFlags cc, bool andLink, bool like case CC_GE: immBranchNotTaken = imm >= 0; break; case CC_LT: immBranchNotTaken = imm < 0; break; case CC_LE: immBranchNotTaken = imm <= 0; break; - default: immBranchNotTaken = false; _dbg_assert_msg_(JIT, false, "Bad cc flag in BranchRSZeroComp()."); + default: immBranchNotTaken = false; _dbg_assert_msg_(false, "Bad cc flag in BranchRSZeroComp()."); } immBranch = true; immBranchTaken = !immBranchNotTaken; @@ -297,7 +298,7 @@ void ArmJit::Comp_RelBranch(MIPSOpcode op) case 23: BranchRSZeroComp(op, CC_LE, false, true); break;//bgtzl default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -315,7 +316,7 @@ void ArmJit::Comp_RelBranchRI(MIPSOpcode op) case 18: BranchRSZeroComp(op, CC_GE, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else SkipLikely(); break;//bltzall case 19: BranchRSZeroComp(op, CC_LT, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else SkipLikely(); break;//bgezall default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -373,7 +374,7 @@ void ArmJit::Comp_FPUBranch(MIPSOpcode op) case 2: BranchFPFlag(op, CC_NEQ, true); break; // bc1fl case 3: BranchFPFlag(op, CC_EQ, true); break; // bc1tl default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } } @@ -446,6 +447,10 @@ void ArmJit::Comp_VBranch(MIPSOpcode op) } } +static void HitInvalidJump(uint32_t dest) { + Core_ExecException(dest, currentMIPS->pc - 8, ExecExceptionType::JUMP); +} + void ArmJit::Comp_Jump(MIPSOpcode op) { if (js.inDelaySlot) { ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); @@ -462,6 +467,13 @@ void ArmJit::Comp_Jump(MIPSOpcode op) { js.compiling = false; } // TODO: Mark this block dirty or something? May be indication it will be changed by imports. + CompileDelaySlot(DELAYSLOT_NICE); + FlushAll(); + gpr.SetRegImm(SCRATCHREG1, GetCompilerPC() + 8); + MovToPC(SCRATCHREG1); + MOVI2R(R0, targetAddr); + QuickCallFunction(SCRATCHREG2, &HitInvalidJump); + WriteSyscallExit(); return; } @@ -499,7 +511,7 @@ void ArmJit::Comp_Jump(MIPSOpcode op) { break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } js.compiling = false; @@ -575,7 +587,7 @@ void ArmJit::Comp_JumpReg(MIPSOpcode op) case 9: //jalr break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } diff --git a/Core/MIPS/ARM/ArmCompLoadStore.cpp b/Core/MIPS/ARM/ArmCompLoadStore.cpp index 3dfcae2e61..3d49b2dc61 100644 --- a/Core/MIPS/ARM/ArmCompLoadStore.cpp +++ b/Core/MIPS/ARM/ArmCompLoadStore.cpp @@ -182,7 +182,7 @@ namespace MIPSComp // This gets hit in a few games, as a result of never-taken delay slots (some branch types // conditionally execute the delay slot instructions). Ignore in those cases. if (!js.inDelaySlot) { - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); + _dbg_assert_msg_(!gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); } if (load) { @@ -339,7 +339,7 @@ namespace MIPSComp addrReg = R0; } } else { - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address? CPU bug?"); + _dbg_assert_msg_(!gpr.IsImm(rs), "Invalid immediate address? CPU bug?"); load ? gpr.MapDirtyIn(rt, rs) : gpr.MapInIn(rt, rs); if (!g_Config.bFastMemory && rs != MIPS_REG_SP) { diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 94cd0d811c..4291f694f2 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -19,7 +19,7 @@ #if PPSSPP_ARCH(ARM) #include -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Core/Compatibility.h" #include "Core/Config.h" @@ -543,7 +543,7 @@ namespace MIPSComp VMOV(fpr.V(dregs[3]), (vd&3)==3 ? S1 : S0); break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } @@ -1320,7 +1320,7 @@ namespace MIPSComp } } else { //ERROR - _dbg_assert_msg_(CPU,0,"mtv - invalid register"); + _dbg_assert_msg_(false,"mtv - invalid register"); } break; diff --git a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp index db1af06b6f..5fd30516de 100644 --- a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp +++ b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp @@ -30,8 +30,7 @@ #include -#include "base/logging.h" -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Common/CPUDetect.h" #include "Core/MemMap.h" @@ -56,8 +55,7 @@ // #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } #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; } - +#define DISABLE_UNKNOWN_PREFIX { WARN_LOG(JIT, "DISABLE: Unknown Prefix in %s", __FUNCTION__); fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } #define _RS MIPS_GET_RS(op) #define _RT MIPS_GET_RT(op) @@ -731,7 +729,7 @@ void ArmJit::CompNEON_Mftv(MIPSOpcode op) { } } else { //ERROR - _dbg_assert_msg_(CPU,0,"mtv - invalid register"); + _dbg_assert_msg_(false,"mtv - invalid register"); } break; @@ -809,7 +807,7 @@ void ArmJit::CompNEON_VMatrixInit(MIPSOpcode op) { // NEONTranspose4x4(cols); break; default: - _assert_msg_(JIT, 0, "Bad matrix size"); + _assert_msg_(false, "Bad matrix size"); break; } break; @@ -865,7 +863,7 @@ void ArmJit::CompNEON_Vmmul(MIPSOpcode op) { bool overlap = GetMatrixOverlap(_VD, _VS, msz) || GetMatrixOverlap(_VD, _VT, msz); if (overlap) { // Later. Fortunately, the VFPU also seems to prohibit overlap for matrix mul. - ILOG("Matrix overlap, ignoring."); + INFO_LOG(JIT, "Matrix overlap, ignoring."); DISABLE; } @@ -1160,7 +1158,7 @@ void ArmJit::CompNEON_VIdt(MIPSOpcode op) { } break; default: - _dbg_assert_msg_(CPU,0,"Bad vidt instruction"); + _dbg_assert_msg_(false,"Bad vidt instruction"); break; } diff --git a/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp b/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp index 546c791a46..5a6f727456 100644 --- a/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp +++ b/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp @@ -30,8 +30,7 @@ #include -#include "base/logging.h" -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Common/CPUDetect.h" #include "Core/MemMap.h" @@ -271,7 +270,7 @@ ArmJit::DestARMReg ArmJit::NEONMapPrefixD(int vreg, VectorSize sz, int mapFlags) dest.backingRd = dest.rd; } else { // Allocate a temporary register. - ELOG("PREFIXD: Write mask allocated! %i/%i", writeMask, full_mask); + ERROR_LOG(JIT, "PREFIXD: Write mask allocated! %i/%i", writeMask, full_mask); dest.rd = fpr.QAllocTemp(sz); dest.backingRd = fpr.QMapReg(vreg, sz, mapFlags & ~MAP_NOINIT); // Force initialization of the backing reg. } @@ -295,12 +294,12 @@ void ArmJit::NEONApplyPrefixD(DestARMReg dest) { if (sat1_mask && sat3_mask) { // Why would anyone do this? - ELOG("PREFIXD: Can't have both sat[0-1] and sat[-1-1] at the same time yet"); + ERROR_LOG(JIT, "PREFIXD: Can't have both sat[0-1] and sat[-1-1] at the same time yet"); } if (sat1_mask) { if (sat1_mask != full_mask) { - ELOG("PREFIXD: Can't have partial sat1 mask yet (%i vs %i)", sat1_mask, full_mask); + ERROR_LOG(JIT, "PREFIXD: Can't have partial sat1 mask yet (%i vs %i)", sat1_mask, full_mask); } if (IsD(dest.rd)) { VMOV_immf(D0, 0.0); @@ -317,7 +316,7 @@ void ArmJit::NEONApplyPrefixD(DestARMReg dest) { if (sat3_mask && sat1_mask != full_mask) { if (sat3_mask != full_mask) { - ELOG("PREFIXD: Can't have partial sat3 mask yet (%i vs %i)", sat3_mask, full_mask); + ERROR_LOG(JIT, "PREFIXD: Can't have partial sat3 mask yet (%i vs %i)", sat3_mask, full_mask); } if (IsD(dest.rd)) { VMOV_immf(D0, 0.0); @@ -341,11 +340,11 @@ void ArmJit::NEONApplyPrefixD(DestARMReg dest) { int writeMask = (~(js.prefixD >> 8)) & 0xF; if (writeMask == 3) { - ILOG("Doing writemask = 3"); + INFO_LOG(JIT, "Doing writemask = 3"); VMOV(D_0(dest.rd), D_0(dest.backingRd)); } else { // TODO - ELOG("PREFIXD: Arbitrary write masks not supported (%i / %i)", writeMask, full_mask); + ERROR_LOG(JIT, "PREFIXD: Arbitrary write masks not supported (%i / %i)", writeMask, full_mask); VMOV(dest.backingRd, dest.rd); } } diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index f20e5e2600..653e1afe4c 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -18,9 +18,11 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(ARM) -#include "base/logging.h" -#include "profiler/profiler.h" -#include "Common/ChunkFile.h" +#include "Common/Profiler/Profiler.h" + +#include "Common/Log.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Reporting.h" #include "Core/Config.h" @@ -60,13 +62,13 @@ void DisassembleArm(const u8 *data, int size) { int reg1 = (next & 0x0000F000) >> 12; if (reg0 == reg1) { sprintf(temp, "%08x MOV32 %s, %04x%04x", (u32)inst, ArmRegName(reg0), hi, low); - ILOG("A: %s", temp); + INFO_LOG(JIT, "A: %s", temp); i += 4; continue; } } ArmDis((u32)codePtr, inst, temp, sizeof(temp), true); - ILOG("A: %s", temp); + INFO_LOG(JIT, "A: %s", temp); } } @@ -129,9 +131,9 @@ void ArmJit::DoState(PointerWrap &p) if (!s) return; - p.Do(js.startDefaultPrefix); + Do(p, js.startDefaultPrefix); if (s >= 2) { - p.Do(js.hasSetRounding); + Do(p, js.hasSetRounding); js.lastSetRounding = 0; } else { js.hasSetRounding = 1; @@ -703,6 +705,7 @@ void ArmJit::UpdateRoundingMode(u32 fcr31) { // I don't think this gives us that much benefit. void ArmJit::WriteExit(u32 destination, int exit_num) { + // TODO: Check destination is valid and trigger exception. WriteDownCount(); //If nobody has taken care of this yet (this can be removed when all branches are done) JitBlock *b = js.curBlock; @@ -723,6 +726,7 @@ void ArmJit::WriteExit(u32 destination, int exit_num) void ArmJit::WriteExitDestInR(ARMReg Reg) { + // TODO: If not fast memory, check for invalid address in reg and trigger exception. MovToPC(Reg); WriteDownCount(); // TODO: shouldn't need an indirect branch here... diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 80a3bc6ae9..50322a65bc 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -51,6 +51,8 @@ public: void Compile(u32 em_address) override; // Compiles a block at current MIPS PC + const u8 *GetCrashHandler() const override { return crashHandler; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } bool DescribeCodePtr(const u8 *ptr, std::string &name) override; MIPSOpcode GetOriginalOp(MIPSOpcode op) override; @@ -313,6 +315,8 @@ public: const u8 *restoreRoundingMode; const u8 *applyRoundingMode; + + const u8 *crashHandler; }; } // namespace MIPSComp diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.cpp b/Core/MIPS/ARM/ArmRegCacheFPU.cpp index cac7f374b9..21001b2b58 100644 --- a/Core/MIPS/ARM/ArmRegCacheFPU.cpp +++ b/Core/MIPS/ARM/ArmRegCacheFPU.cpp @@ -17,8 +17,8 @@ #include -#include "base/logging.h" #include "Common/CPUDetect.h" +#include "Common/Log.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/ARM/ArmRegCacheFPU.h" #include "Core/MIPS/ARM/ArmJit.h" @@ -463,13 +463,13 @@ void ArmRegCacheFPU::FlushAll() { if (ar[a].isDirty) { if (m == -1) { - ILOG("ARM reg %i is dirty but has no mipsreg", a); + INFO_LOG(JIT, "ARM reg %i is dirty but has no mipsreg", a); continue; } int c = FlushGetSequential(a, GetNumARMFPURegs()); if (c == 1) { - // ILOG("Got single register: %i (%i)", a, m); + // INFO_LOG(JIT, "Got single register: %i (%i)", a, m); emit_->VSTR((ARMReg)(a + S0), CTXREG, GetMipsRegOffset(m)); } else if (c == 2) { // Probably not worth using VSTMIA for two. @@ -477,9 +477,9 @@ void ArmRegCacheFPU::FlushAll() { emit_->VSTR((ARMReg)(a + S0), CTXREG, offset); emit_->VSTR((ARMReg)(a + 1 + S0), CTXREG, offset + 4); } else { - // ILOG("Got sequence: %i at %i (%i)", c, a, m); + // INFO_LOG(JIT, "Got sequence: %i at %i (%i)", c, a, m); emit_->ADDI2R(SCRATCHREG1, CTXREG, GetMipsRegOffset(m), SCRATCHREG2); - // ILOG("VSTMIA R0, %i, %i", a, c); + // INFO_LOG(JIT, "VSTMIA R0, %i, %i", a, c); emit_->VSTMIA(SCRATCHREG1, false, (ARMReg)(S0 + a), c); } @@ -561,7 +561,7 @@ int ArmRegCacheFPU::GetTempR() { } ERROR_LOG(CPU, "Out of temp regs! Might need to DiscardR() some"); - _assert_msg_(JIT, 0, "Regcache ran out of temp regs, might need to DiscardR() some."); + _assert_msg_(false, "Regcache ran out of temp regs, might need to DiscardR() some."); return -1; } @@ -908,7 +908,7 @@ ARMReg ArmRegCacheFPU::QMapReg(int vreg, VectorSize sz, int flags) { // We didn't find the extra register, but we got a list of regs to flush. Flush 'em. // Here we can check for opportunities to do a "transpose-flush" of row vectors, etc. if (!quadsToFlush.empty()) { - ILOG("New mapping %s collided with %i quads, flushing them.", GetVectorNotation(vreg, sz), (int)quadsToFlush.size()); + INFO_LOG(JIT, "New mapping %s collided with %d quads, flushing them.", GetVectorNotation(vreg, sz), (int)quadsToFlush.size()); } for (size_t i = 0; i < quadsToFlush.size(); i++) { QFlush(quadsToFlush[i]); diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index 755e35f57c..99f4dadf65 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -18,15 +18,14 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(ARM64) -#include "base/logging.h" - +#include "Common/Log.h" +#include "Common/MemoryUtil.h" +#include "Common/CPUDetect.h" +#include "Common/Arm64Emitter.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" #include "Core/System.h" #include "Core/CoreTiming.h" -#include "Common/MemoryUtil.h" -#include "Common/CPUDetect.h" -#include "Common/Arm64Emitter.h" #include "Core/MIPS/ARM64/Arm64Jit.h" #include "Core/MIPS/JitCommon/JitCommon.h" @@ -77,9 +76,9 @@ extern volatile CoreState coreState; void ShowPC(u32 downcount, void *membase, void *jitbase) { static int count = 0; if (currentMIPS) { - ELOG("ShowPC : %08x Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); + ERROR_LOG(JIT, "ShowPC : %08x Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); } else { - ELOG("Universe corrupt?"); + ERROR_LOG(JIT, "Universe corrupt?"); } //if (count > 2000) // exit(0); @@ -277,6 +276,7 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { CMP(SCRATCH1, 0); B(CC_EQ, outerLoop); + const uint8_t *quitLoop = GetCodePtr(); SetJumpTarget(badCoreState); SaveStaticRegisters(); @@ -286,6 +286,12 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { RET(); + crashHandler = GetCodePtr(); + MOVP2R(SCRATCH1_64, &coreState); + MOVI2R(SCRATCH2, CORE_RUNTIME_ERROR); + STR(INDEX_UNSIGNED, SCRATCH2, SCRATCH1_64, 0); + B(quitLoop); + // Generate some integer conversion funcs. // MIPS order! static const RoundingMode roundModes[8] = { ROUND_N, ROUND_Z, ROUND_P, ROUND_M, ROUND_N, ROUND_Z, ROUND_P, ROUND_M }; diff --git a/Core/MIPS/ARM64/Arm64CompALU.cpp b/Core/MIPS/ARM64/Arm64CompALU.cpp index f97ba0dee7..a4e5ea25e9 100644 --- a/Core/MIPS/ARM64/Arm64CompALU.cpp +++ b/Core/MIPS/ARM64/Arm64CompALU.cpp @@ -20,11 +20,12 @@ #include +#include "Common/BitSet.h" +#include "Common/CPUDetect.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/ARM64/Arm64Jit.h" #include "Core/MIPS/ARM64/Arm64RegCache.h" -#include "Common/CPUDetect.h" using namespace MIPSAnalyst; diff --git a/Core/MIPS/ARM64/Arm64CompBranch.cpp b/Core/MIPS/ARM64/Arm64CompBranch.cpp index a3446858b4..889ac212c7 100644 --- a/Core/MIPS/ARM64/Arm64CompBranch.cpp +++ b/Core/MIPS/ARM64/Arm64CompBranch.cpp @@ -18,10 +18,11 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(ARM64) -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" -#include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/Core.h" +#include "Core/Reporting.h" #include "Core/MemMap.h" #include "Core/HLE/HLE.h" #include "Core/HLE/HLETables.h" @@ -85,7 +86,7 @@ void Arm64Jit::BranchRSRTComp(MIPSOpcode op, CCFlags cc, bool likely) { case CC_EQ: immBranchNotTaken = rsImm == rtImm; break; case CC_NEQ: immBranchNotTaken = rsImm != rtImm; break; - default: immBranchNotTaken = false; _dbg_assert_msg_(JIT, false, "Bad cc flag in BranchRSRTComp()."); + default: immBranchNotTaken = false; _dbg_assert_msg_(false, "Bad cc flag in BranchRSRTComp()."); } immBranch = true; immBranchTaken = !immBranchNotTaken; @@ -216,7 +217,7 @@ void Arm64Jit::BranchRSZeroComp(MIPSOpcode op, CCFlags cc, bool andLink, bool li case CC_GE: immBranchNotTaken = imm >= 0; break; case CC_LT: immBranchNotTaken = imm < 0; break; case CC_LE: immBranchNotTaken = imm <= 0; break; - default: immBranchNotTaken = false; _dbg_assert_msg_(JIT, false, "Bad cc flag in BranchRSZeroComp()."); + default: immBranchNotTaken = false; _dbg_assert_msg_(false, "Bad cc flag in BranchRSZeroComp()."); } immBranch = true; immBranchTaken = !immBranchNotTaken; @@ -315,7 +316,7 @@ void Arm64Jit::Comp_RelBranch(MIPSOpcode op) case 23: BranchRSZeroComp(op, CC_LE, false, true); break;//bgtzl default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -333,7 +334,7 @@ void Arm64Jit::Comp_RelBranchRI(MIPSOpcode op) case 18: BranchRSZeroComp(op, CC_GE, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else SkipLikely(); break;//bltzall case 19: BranchRSZeroComp(op, CC_LT, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else SkipLikely(); break;//bgezall default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -390,7 +391,7 @@ void Arm64Jit::Comp_FPUBranch(MIPSOpcode op) { case 2: BranchFPFlag(op, CC_NEQ, true); break; // bc1fl case 3: BranchFPFlag(op, CC_EQ, true); break; // bc1tl default: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Trying to interpret instruction that can't be interpreted"); break; } } @@ -461,6 +462,10 @@ void Arm64Jit::Comp_VBranch(MIPSOpcode op) } } +static void HitInvalidJump(uint32_t dest) { + Core_ExecException(dest, currentMIPS->pc - 8, ExecExceptionType::JUMP); +} + void Arm64Jit::Comp_Jump(MIPSOpcode op) { if (js.inDelaySlot) { ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); @@ -477,6 +482,13 @@ void Arm64Jit::Comp_Jump(MIPSOpcode op) { js.compiling = false; } // TODO: Mark this block dirty or something? May be indication it will be changed by imports. + CompileDelaySlot(DELAYSLOT_NICE); + FlushAll(); + gpr.SetRegImm(SCRATCH1, GetCompilerPC() + 8); + MovToPC(SCRATCH1); + MOVI2R(W0, targetAddr); + QuickCallFunction(SCRATCH1, (const void *)&HitInvalidJump); + WriteSyscallExit(); return; } @@ -514,7 +526,7 @@ void Arm64Jit::Comp_Jump(MIPSOpcode op) { break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } js.compiling = false; @@ -592,7 +604,7 @@ void Arm64Jit::Comp_JumpReg(MIPSOpcode op) case 9: //jalr break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } diff --git a/Core/MIPS/ARM64/Arm64CompLoadStore.cpp b/Core/MIPS/ARM64/Arm64CompLoadStore.cpp index a4d647d98b..ad706c5221 100644 --- a/Core/MIPS/ARM64/Arm64CompLoadStore.cpp +++ b/Core/MIPS/ARM64/Arm64CompLoadStore.cpp @@ -180,7 +180,7 @@ namespace MIPSComp { return; } - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); + _dbg_assert_msg_(!gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); if (load) { gpr.MapDirtyIn(rt, rs, false); } else { @@ -380,7 +380,7 @@ namespace MIPSComp { // This gets hit in a few games, as a result of never-taken delay slots (some branch types // conditionally execute the delay slot instructions). Ignore in those cases. if (!js.inDelaySlot) { - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); + _dbg_assert_msg_(!gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); } // If we already have a targetReg, we optimized an imm, and rs is already mapped. diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp index 69d6a302c6..6b6e26eca7 100644 --- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp @@ -19,7 +19,7 @@ #if PPSSPP_ARCH(ARM64) #include -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Core/Compatibility.h" #include "Core/Config.h" @@ -171,7 +171,7 @@ namespace MIPSComp { } void Arm64Jit::ApplyPrefixD(const u8 *vregs, VectorSize sz) { - _assert_msg_(JIT, js.prefixDFlag & JitState::PREFIX_KNOWN, "Unexpected unknown prefix!"); + _assert_msg_(js.prefixDFlag & JitState::PREFIX_KNOWN, "Unexpected unknown prefix!"); if (!js.prefixD) return; @@ -435,7 +435,7 @@ namespace MIPSComp { fp.FMOV(fpr.V(dregs[3]), (vd & 3) == 3 ? S1 : S0); break; default: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Trying to interpret instruction that can't be interpreted"); break; } @@ -1069,7 +1069,7 @@ namespace MIPSComp { } } else { //ERROR - _dbg_assert_msg_(CPU, 0, "mtv - invalid register"); + _dbg_assert_msg_( 0, "mtv - invalid register"); } break; diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 330c6b4761..cfdb3d0385 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -18,9 +18,10 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(ARM64) -#include "base/logging.h" -#include "profiler/profiler.h" -#include "Common/ChunkFile.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Log.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Common/CPUDetect.h" #include "Common/StringUtils.h" @@ -48,17 +49,17 @@ using namespace Arm64JitConstants; static void DisassembleArm64Print(const u8 *data, int size) { std::vector lines = DisassembleArm64(data, size); for (auto s : lines) { - ILOG("%s", s.c_str()); + INFO_LOG(JIT, "%s", s.c_str()); } /* - ILOG("+++"); + INFO_LOG(JIT, "+++"); // A format friendly to Online Disassembler which gets endianness wrong for (size_t i = 0; i < lines.size(); i++) { uint32_t opcode = ((const uint32_t *)data)[i]; - ILOG("%d/%d: %08x", (int)(i+1), (int)lines.size(), swap32(opcode)); + INFO_LOG(JIT, "%d/%d: %08x", (int)(i+1), (int)lines.size(), swap32(opcode)); } - ILOG("==="); - ILOG("===");*/ + INFO_LOG(JIT, "==="); + INFO_LOG(JIT, "===");*/ } static u32 JitBreakpoint() { @@ -122,9 +123,9 @@ void Arm64Jit::DoState(PointerWrap &p) { if (!s) return; - p.Do(js.startDefaultPrefix); + Do(p, js.startDefaultPrefix); if (s >= 2) { - p.Do(js.hasSetRounding); + Do(p, js.hasSetRounding); js.lastSetRounding = 0; } else { js.hasSetRounding = 1; @@ -168,7 +169,7 @@ void Arm64Jit::FlushPrefixV() { } void Arm64Jit::ClearCache() { - ILOG("ARM64Jit: Clearing the cache!"); + INFO_LOG(JIT, "ARM64Jit: Clearing the cache!"); blocks.Clear(); ClearCodeSpace(jitStartOffset); FlushIcacheSection(region + jitStartOffset, region + region_size - jitStartOffset); @@ -360,16 +361,16 @@ const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) { char temp[256]; if (logBlocks > 0 && dontLogBlocks == 0) { - ILOG("=============== mips %d ===============", blocks.GetNumBlocks()); + INFO_LOG(JIT, "=============== mips %d ===============", blocks.GetNumBlocks()); for (u32 cpc = em_address; cpc != GetCompilerPC() + 4; cpc += 4) { MIPSDisAsm(Memory::Read_Opcode_JIT(cpc), cpc, temp, true); - ILOG("M: %08x %s", cpc, temp); + INFO_LOG(JIT, "M: %08x %s", cpc, temp); } } b->codeSize = GetCodePtr() - b->normalEntry; if (logBlocks > 0 && dontLogBlocks == 0) { - ILOG("=============== ARM (%d instructions -> %d bytes) ===============", js.numInstructions, b->codeSize); + INFO_LOG(JIT, "=============== ARM (%d instructions -> %d bytes) ===============", js.numInstructions, b->codeSize); DisassembleArm64Print(b->normalEntry, GetCodePtr() - b->normalEntry); } if (logBlocks > 0) @@ -471,7 +472,7 @@ void Arm64Jit::UnlinkBlock(u8 *checkedEntry, u32 originalAddress) { } bool Arm64Jit::ReplaceJalTo(u32 dest) { -#ifdef ARM64 +#if PPSSPP_ARCH(ARM64) const ReplacementTableEntry *entry = nullptr; u32 funcSize = 0; if (!CanReplaceJalTo(dest, &entry, &funcSize)) { @@ -677,6 +678,7 @@ void Arm64Jit::UpdateRoundingMode(u32 fcr31) { // though, as we need to have the SUBS flag set in the end. So with block linking in the mix, // I don't think this gives us that much benefit. void Arm64Jit::WriteExit(u32 destination, int exit_num) { + // TODO: Check destination is valid and trigger exception. WriteDownCount(); //If nobody has taken care of this yet (this can be removed when all branches are done) JitBlock *b = js.curBlock; @@ -696,6 +698,7 @@ void Arm64Jit::WriteExit(u32 destination, int exit_num) { } void Arm64Jit::WriteExitDestInR(ARM64Reg Reg) { + // TODO: If not fast memory, check for invalid address in reg and trigger exception. MovToPC(Reg); WriteDownCount(); // TODO: shouldn't need an indirect branch here... diff --git a/Core/MIPS/ARM64/Arm64Jit.h b/Core/MIPS/ARM64/Arm64Jit.h index 6ad5921d53..17734ade59 100644 --- a/Core/MIPS/ARM64/Arm64Jit.h +++ b/Core/MIPS/ARM64/Arm64Jit.h @@ -52,6 +52,8 @@ public: void Compile(u32 em_address) override; // Compiles a block at current MIPS PC const u8 *DoJit(u32 em_address, JitBlock *b); + const u8 *GetCrashHandler() const override { return crashHandler; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } bool DescribeCodePtr(const u8 *ptr, std::string &name) override; MIPSOpcode GetOriginalOp(MIPSOpcode op) override; @@ -281,6 +283,8 @@ public: const u8 *applyRoundingMode; const u8 *updateRoundingMode; + const u8 *crashHandler; + int jitStartOffset; // Indexed by FPCR FZ:RN bits for convenience. Uses SCRATCH2. diff --git a/Core/MIPS/ARM64/Arm64RegCache.cpp b/Core/MIPS/ARM64/Arm64RegCache.cpp index b089efa309..b084adf109 100644 --- a/Core/MIPS/ARM64/Arm64RegCache.cpp +++ b/Core/MIPS/ARM64/Arm64RegCache.cpp @@ -18,7 +18,7 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(ARM64) -#include "base/logging.h" +#include "Common/Log.h" #include "Core/MemMap.h" #include "Core/MIPS/ARM64/Arm64RegCache.h" #include "Core/MIPS/ARM64/Arm64Jit.h" @@ -150,7 +150,7 @@ bool Arm64RegCache::IsMappedAsPointer(MIPSGPReg mipsReg) { return ar[mr[mipsReg].reg].pointerified; } else if (mr[mipsReg].loc == ML_ARMREG_IMM) { if (ar[mr[mipsReg].reg].pointerified) { - ELOG("Really shouldn't be pointerified here"); + ERROR_LOG(JIT, "Really shouldn't be pointerified here"); } } else if (mr[mipsReg].loc == ML_ARMREG_AS_PTR) { return true; @@ -164,7 +164,7 @@ void Arm64RegCache::MarkDirty(ARM64Reg reg) { void Arm64RegCache::SetRegImm(ARM64Reg reg, u64 imm) { if (reg == INVALID_REG) { - ELOG("SetRegImm to invalid register: at %08x", js_->compilerPC); + ERROR_LOG(JIT, "SetRegImm to invalid register: at %08x", js_->compilerPC); return; } // On ARM64, at least Cortex A57, good old MOVT/MOVW (MOVK in 64-bit) is really fast. @@ -174,7 +174,7 @@ void Arm64RegCache::SetRegImm(ARM64Reg reg, u64 imm) { void Arm64RegCache::MapRegTo(ARM64Reg reg, MIPSGPReg mipsReg, int mapFlags) { if (mr[mipsReg].isStatic) { - ELOG("Cannot MapRegTo static register %d", mipsReg); + ERROR_LOG(JIT, "Cannot MapRegTo static register %d", mipsReg); return; } ar[reg].isDirty = (mapFlags & MAP_DIRTY) ? true : false; @@ -215,7 +215,7 @@ void Arm64RegCache::MapRegTo(ARM64Reg reg, MIPSGPReg mipsReg, int mapFlags) { mr[mipsReg].loc = ML_ARMREG_IMM; break; default: - _assert_msg_(JIT, mr[mipsReg].loc != ML_ARMREG_AS_PTR, "MapRegTo with a pointer?"); + _assert_msg_(mr[mipsReg].loc != ML_ARMREG_AS_PTR, "MapRegTo with a pointer?"); mr[mipsReg].loc = ML_ARMREG; break; } @@ -450,7 +450,7 @@ Arm64Gen::ARM64Reg Arm64RegCache::MapRegAsPointer(MIPSGPReg reg) { ar[a].pointerified = true; } } else { - ELOG("MapRegAsPointer : MapReg failed to allocate a register?"); + ERROR_LOG(JIT, "MapRegAsPointer : MapReg failed to allocate a register?"); } return retval; } @@ -506,7 +506,7 @@ void Arm64RegCache::MapDirtyDirtyInIn(MIPSGPReg rd1, MIPSGPReg rd2, MIPSGPReg rs void Arm64RegCache::FlushArmReg(ARM64Reg r) { if (r == INVALID_REG) { - ELOG("FlushArmReg called on invalid register %d", r); + ERROR_LOG(JIT, "FlushArmReg called on invalid register %d", r); return; } if (ar[r].mipsReg == MIPS_REG_INVALID) { @@ -517,7 +517,7 @@ void Arm64RegCache::FlushArmReg(ARM64Reg r) { return; } if (mr[ar[r].mipsReg].isStatic) { - ELOG("Cannot FlushArmReg a statically mapped register"); + ERROR_LOG(JIT, "Cannot FlushArmReg a statically mapped register"); return; } auto &mreg = mr[ar[r].mipsReg]; @@ -629,7 +629,7 @@ ARM64Reg Arm64RegCache::ARM64RegForFlush(MIPSGPReg r) { void Arm64RegCache::FlushR(MIPSGPReg r) { if (mr[r].isStatic) { - ELOG("Cannot flush static reg %d", r); + ERROR_LOG(JIT, "Cannot flush static reg %d", r); return; } @@ -753,7 +753,7 @@ void Arm64RegCache::FlushAll() { } else if (mr[i].loc == ML_ARMREG_IMM) { // The register already contains the immediate. if (ar[armReg].pointerified) { - ELOG("ML_ARMREG_IMM but pointerified. Wrong."); + ERROR_LOG(JIT, "ML_ARMREG_IMM but pointerified. Wrong."); ar[armReg].pointerified = false; } mr[i].loc = ML_ARMREG; @@ -762,7 +762,7 @@ void Arm64RegCache::FlushAll() { mr[i].loc = ML_ARMREG; } if (i != MIPS_REG_ZERO && mr[i].reg == INVALID_REG) { - ELOG("ARM reg of static %i is invalid", i); + ERROR_LOG(JIT, "ARM reg of static %i is invalid", i); continue; } } else { diff --git a/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp b/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp index ba2bb0105b..fffb38fcc7 100644 --- a/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp +++ b/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp @@ -20,8 +20,8 @@ #include -#include "base/logging.h" #include "Common/CPUDetect.h" +#include "Common/Log.h" #include "Core/Reporting.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/ARM64/Arm64RegCacheFPU.h" @@ -400,7 +400,7 @@ void Arm64RegCacheFPU::FlushAll() { if (ar[a].isDirty) { if (m == -1) { - ILOG("ARM reg %i is dirty but has no mipsreg", a); + INFO_LOG(JIT, "ARM reg %d is dirty but has no mipsreg", a); continue; } @@ -423,7 +423,7 @@ void Arm64RegCacheFPU::FlushAll() { // Sanity check for (int i = 0; i < numARMFpuReg_; i++) { if (ar[i].mipsReg != -1) { - ERROR_LOG(JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); + ERROR_LOG(JIT, "Flush fail: ar[%d].mipsReg=%d", i, ar[i].mipsReg); } } pendingFlush = false; @@ -479,7 +479,7 @@ int Arm64RegCacheFPU::GetTempR() { } ERROR_LOG(CPU, "Out of temp regs! Might need to DiscardR() some"); - _assert_msg_(JIT, 0, "Regcache ran out of temp regs, might need to DiscardR() some."); + _assert_msg_(false, "Regcache ran out of temp regs, might need to DiscardR() some."); return -1; } diff --git a/Core/MIPS/IR/IRAsm.cpp b/Core/MIPS/IR/IRAsm.cpp index f5d9c7ad31..38d40469d8 100644 --- a/Core/MIPS/IR/IRAsm.cpp +++ b/Core/MIPS/IR/IRAsm.cpp @@ -15,13 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" - +#include "Common/Log.h" +#include "Common/MemoryUtil.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" #include "Core/System.h" #include "Core/CoreTiming.h" -#include "Common/MemoryUtil.h" #include "Core/MIPS/IR/IRJit.h" #include "Core/MIPS/JitCommon/JitCommon.h" diff --git a/Core/MIPS/IR/IRCompBranch.cpp b/Core/MIPS/IR/IRCompBranch.cpp index 20d352b5c1..2592d6227c 100644 --- a/Core/MIPS/IR/IRCompBranch.cpp +++ b/Core/MIPS/IR/IRCompBranch.cpp @@ -15,7 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Core/Reporting.h" #include "Core/Config.h" @@ -165,7 +165,7 @@ void IRFrontend::Comp_RelBranch(MIPSOpcode op) { case 23: BranchRSZeroComp(op, IRComparison::LessEqual, false, true); break;//bgtzl default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -181,7 +181,7 @@ void IRFrontend::Comp_RelBranchRI(MIPSOpcode op) { case 18: BranchRSZeroComp(op, IRComparison::GreaterEqual, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else SkipLikely(); break;//bltzall case 19: BranchRSZeroComp(op, IRComparison::Less, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else SkipLikely(); break;//bgezall default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -224,7 +224,7 @@ void IRFrontend::Comp_FPUBranch(MIPSOpcode op) { case 2: BranchFPFlag(op, IRComparison::NotEqual, true); break; // bc1fl case 3: BranchFPFlag(op, IRComparison::Equal, true); break; // bc1tl default: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Trying to interpret instruction that can't be interpreted"); break; } } @@ -300,9 +300,8 @@ void IRFrontend::Comp_Jump(MIPSOpcode op) { js.cancel = true; else ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x", targetAddr); - js.compiling = false; // TODO: Mark this block dirty or something? May be indication it will be changed by imports. - return; + // Continue so the block gets completed and crashes properly. } switch (op >> 26) { @@ -316,7 +315,7 @@ void IRFrontend::Comp_Jump(MIPSOpcode op) { break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } @@ -380,7 +379,7 @@ void IRFrontend::Comp_JumpReg(MIPSOpcode op) { case 9: //jalr break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 13fa39b2c2..054594f4c5 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -17,7 +17,7 @@ #include -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Common/CPUDetect.h" #include "Core/Compatibility.h" diff --git a/Core/MIPS/IR/IRFrontend.cpp b/Core/MIPS/IR/IRFrontend.cpp index b86ff2890e..c3a2df444a 100644 --- a/Core/MIPS/IR/IRFrontend.cpp +++ b/Core/MIPS/IR/IRFrontend.cpp @@ -15,9 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" - -#include "Common/ChunkFile.h" +#include "Common/Log.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Debugger/Breakpoints.h" #include "Core/Debugger/SymbolMap.h" #include "Core/Reporting.h" @@ -46,9 +46,9 @@ void IRFrontend::DoState(PointerWrap &p) { if (!s) return; - p.Do(js.startDefaultPrefix); + Do(p, js.startDefaultPrefix); if (s >= 2) { - p.Do(js.hasSetRounding); + Do(p, js.hasSetRounding); js.lastSetRounding = 0; } else { js.hasSetRounding = 1; diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index 9a4e491228..aa962dbb5e 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -2,7 +2,7 @@ #include #include "ppsspp_config.h" -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Common/Common.h" #include "Common/BitScan.h" @@ -947,10 +947,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { } case IROp::Break: - if (!g_Config.bIgnoreBadMemAccess) { - Core_EnableStepping(true); - host->SetDebugMode(true); - } + Core_Break(); return mips->pc + 4; case IROp::SetCtrlVFPU: diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index ec9a2fdabb..77d988d139 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -15,10 +15,13 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" +#include + #include "ext/xxhash.h" -#include "profiler/profiler.h" -#include "Common/ChunkFile.h" +#include "Common/Profiler/Profiler.h" + +#include "Common/Log.h" +#include "Common/Serialize/Serializer.h" #include "Common/StringUtils.h" #include "Core/Core.h" @@ -60,7 +63,7 @@ void IRJit::UpdateFCR31() { } void IRJit::ClearCache() { - ILOG("IRJit: Clearing the cache!"); + INFO_LOG(JIT, "IRJit: Clearing the cache!"); blocks_.Clear(); } @@ -104,7 +107,7 @@ void IRJit::Compile(u32 em_address) { bool IRJit::CompileBlock(u32 em_address, std::vector &instructions, u32 &mipsBytes, bool preload) { frontend_.DoJit(em_address, instructions, mipsBytes, preload); if (instructions.empty()) { - _dbg_assert_(JIT, preload); + _dbg_assert_(preload); // We return true when preloading so it doesn't abort. return preload; } @@ -224,6 +227,10 @@ void IRJit::RunLoopUntil(u64 globalticks) { u32 data = inst & 0xFFFFFF; IRBlock *block = blocks_.GetBlock(data); mips_->pc = IRInterpret(mips_, block->GetInstructions(), block->GetNumInstructions()); + if (!Memory::IsValidAddress(mips_->pc)) { + Core_ExecException(mips_->pc, mips_->pc, ExecExceptionType::JUMP); + break; + } } else { // RestoreRoundingMode(true); Compile(mips_->pc); @@ -474,7 +481,7 @@ u64 IRBlock::CalculateHash() const { buffer[pos++] = instr.encoding; } - return XXH64(&buffer[0], origSize_, 0x9A5C33B8); + return XXH3_64bits(&buffer[0], origSize_); } return 0; diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index d378dcfc87..9beabe585a 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -160,7 +160,12 @@ public: void InvalidateCacheAt(u32 em_address, int length = 4) override; void UpdateFCR31() override; + bool CodeInRange(const u8 *ptr) const override { + return false; + } + const u8 *GetDispatcher() const override { return nullptr; } + const u8 *GetCrashHandler() const override { return nullptr; } void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override; void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override; diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index fa7481aeff..d7f8195c98 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -2,6 +2,7 @@ #include #include +#include "Common/BitSet.h" #include "Common/Log.h" #include "Core/MIPS/IR/IRInterpreter.h" #include "Core/MIPS/IR/IRPassSimplify.h" diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index fa9ca1edd8..9807ce9551 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -420,7 +420,7 @@ void JitBlockCache::LinkBlock(int i) { if (ppp.first == ppp.second) return; for (auto iter = ppp.first; iter != ppp.second; ++iter) { - // PanicAlert("Linking block %i to block %i", iter->second, i); + // INFO_LOG(JIT, "Linking block %i to block %i", iter->second, i); LinkBlockExits(iter->second); } } @@ -601,12 +601,12 @@ void JitBlockCache::InvalidateChangedBlocks() { } int JitBlockCache::GetBlockExitSize() { -#if defined(ARM) +#if PPSSPP_ARCH(ARM) // Will depend on the sequence found to encode the destination address. return 0; -#elif defined(_M_IX86) || defined(_M_X64) +#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) return 15; -#elif defined(ARM64) +#elif PPSSPP_ARCH(ARM64) // Will depend on the sequence found to encode the destination address. return 0; #else @@ -654,11 +654,11 @@ JitBlockDebugInfo JitBlockCache::GetBlockDebugInfo(int blockNum) const { debugInfo.origDisasm.push_back(mipsDis); } -#if defined(ARM) +#if PPSSPP_ARCH(ARM) debugInfo.targetDisasm = DisassembleArm2(block->normalEntry, block->codeSize); -#elif defined(ARM64) +#elif PPSSPP_ARCH(ARM64) debugInfo.targetDisasm = DisassembleArm64(block->normalEntry, block->codeSize); -#elif defined(_M_IX86) || defined(_M_X64) +#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) debugInfo.targetDisasm = DisassembleX86(block->normalEntry, block->codeSize); #endif diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index 3c51a67f66..0b26138fb2 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -22,12 +22,13 @@ #include #include +#include "ppsspp_config.h" #include "Common/CommonTypes.h" #include "Common/CodeBlock.h" #include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPS.h" -#if defined(ARM) || defined(ARM64) +#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) const int MAX_JIT_BLOCK_EXITS = 2; #else const int MAX_JIT_BLOCK_EXITS = 8; diff --git a/Core/MIPS/JitCommon/JitCommon.cpp b/Core/MIPS/JitCommon/JitCommon.cpp index baf26f6bcc..397cc85ad9 100644 --- a/Core/MIPS/JitCommon/JitCommon.cpp +++ b/Core/MIPS/JitCommon/JitCommon.cpp @@ -21,7 +21,8 @@ #include "ext/udis86/udis86.h" #include "Common/StringUtils.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Util/DisArm64.h" #include "Core/Config.h" @@ -55,10 +56,10 @@ namespace MIPSComp { return; bool dummy = false; - p.Do(dummy); + Do(p, dummy); if (s >= 2) { dummy = true; - p.Do(dummy); + Do(p, dummy); } } @@ -77,7 +78,7 @@ namespace MIPSComp { } } -#if PPSSPP_PLATFORM(WINDOWS) +#if PPSSPP_PLATFORM(WINDOWS) && !defined(__LIBRETRO__) #define DISASM_ALL 1 #endif @@ -246,7 +247,12 @@ std::vector DisassembleX86(const u8 *data, int size) { int int3_count = 0; while (ud_disassemble(&ud_obj) != 0) { - std::string str = ud_insn_asm(&ud_obj); + const char *buf = ud_insn_asm(&ud_obj); + if (!buf) { + lines.push_back("[bad]"); + continue; + } + std::string str = buf; if (str == "int3") { int3_count++; } else { diff --git a/Core/MIPS/JitCommon/JitCommon.h b/Core/MIPS/JitCommon/JitCommon.h index bf3023e21d..08063f866e 100644 --- a/Core/MIPS/JitCommon/JitCommon.h +++ b/Core/MIPS/JitCommon/JitCommon.h @@ -121,8 +121,10 @@ namespace MIPSComp { public: virtual ~JitInterface() {} + virtual bool CodeInRange(const u8 *ptr) const = 0; virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) = 0; virtual const u8 *GetDispatcher() const = 0; + virtual const u8 *GetCrashHandler() const = 0; virtual JitBlockCache *GetBlockCache() = 0; virtual JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() = 0; virtual void InvalidateCacheAt(u32 em_address, int length = 4) = 0; diff --git a/Core/MIPS/JitCommon/JitState.h b/Core/MIPS/JitCommon/JitState.h index a8bb4e6691..d3c998f817 100644 --- a/Core/MIPS/JitCommon/JitState.h +++ b/Core/MIPS/JitCommon/JitState.h @@ -19,6 +19,7 @@ #pragma once #include "Common/Common.h" +#include "Common/Log.h" #include "Core/MIPS/MIPS.h" struct JitBlock; diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index a04e8f2387..37210c8c5d 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -18,10 +18,11 @@ #include #include -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Common.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/ConfigValues.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSInt.h" @@ -265,35 +266,35 @@ void MIPSState::DoState(PointerWrap &p) { else MIPSComp::DoDummyJitState(p); - p.DoArray(r, sizeof(r) / sizeof(r[0])); - p.DoArray(f, sizeof(f) / sizeof(f[0])); + DoArray(p, r, sizeof(r) / sizeof(r[0])); + DoArray(p, f, sizeof(f) / sizeof(f[0])); if (s <= 2) { float vtemp[128]; - p.DoArray(vtemp, sizeof(v) / sizeof(v[0])); + DoArray(p, vtemp, sizeof(v) / sizeof(v[0])); for (int i = 0; i < 128; i++) { v[voffset[i]] = vtemp[i]; } } else { - p.DoArray(v, sizeof(v) / sizeof(v[0])); + DoArray(p, v, sizeof(v) / sizeof(v[0])); } - p.DoArray(vfpuCtrl, sizeof(vfpuCtrl) / sizeof(vfpuCtrl[0])); - p.Do(pc); - p.Do(nextPC); - p.Do(downcount); + DoArray(p, vfpuCtrl, sizeof(vfpuCtrl) / sizeof(vfpuCtrl[0])); + Do(p, pc); + Do(p, nextPC); + Do(p, downcount); // Reversed, but we can just leave it that way. - p.Do(hi); - p.Do(lo); - p.Do(fpcond); + Do(p, hi); + Do(p, lo); + Do(p, fpcond); if (s <= 1) { u32 fcr0_unused = 0; - p.Do(fcr0_unused); + Do(p, fcr0_unused); } - p.Do(fcr31); - p.Do(rng.m_w); - p.Do(rng.m_z); - p.Do(inDelaySlot); - p.Do(llBit); - p.Do(debugCount); + Do(p, fcr31); + Do(p, rng.m_w); + Do(p, rng.m_z); + Do(p, inDelaySlot); + Do(p, llBit); + Do(p, debugCount); if (p.mode == p.MODE_READ && MIPSComp::jit) { // Now that we've loaded fcr31, update any jit state associated. diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index 7d2c40e879..31df9d8baf 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -17,9 +17,11 @@ #pragma once +#include "ppsspp_config.h" + #include -#include "util/random/rng.h" +#include "Common/Data/Random/Rng.h" #include "Common/Common.h" #include "Common/CommonTypes.h" // #include "Core/CoreParameter.h" @@ -148,7 +150,7 @@ extern u8 fromvoffset[128]; enum class CPUCore; -#if defined(PPSSPP_ARCH_X86) || defined(PPSSPP_ARCH_AMD64) +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) // Note that CTXREG is offset to point at the first floating point register, intentionally. This is so that a byte offset // can reach both GPR and FPR regs. @@ -246,7 +248,7 @@ public: static const u32 FCR0_VALUE = 0x00003351; -#if defined(PPSSPP_ARCH_X86) || defined(PPSSPP_ARCH_AMD64) +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) // FPU TEMP0, etc. are swapped in here if necessary (e.g. on x86.) float tempValues[NUM_X86_FPU_TEMPS]; #endif diff --git a/Core/MIPS/MIPS/MipsJit.cpp b/Core/MIPS/MIPS/MipsJit.cpp index bf3b88ee20..5201437784 100644 --- a/Core/MIPS/MIPS/MipsJit.cpp +++ b/Core/MIPS/MIPS/MipsJit.cpp @@ -18,9 +18,8 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(MIPS) -#include "base/logging.h" -#include "profiler/profiler.h" -#include "Common/ChunkFile.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Serialize/Serializer.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "Core/Core.h" @@ -57,9 +56,9 @@ void MipsJit::DoState(PointerWrap &p) if (!s) return; - p.Do(js.startDefaultPrefix); + Do(p, js.startDefaultPrefix); if (s >= 2) { - p.Do(js.hasSetRounding); + Do(p, js.hasSetRounding); js.lastSetRounding = 0; } else { js.hasSetRounding = 1; diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index d52c2ffebd..1a39988abc 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -21,9 +21,12 @@ #include #include -#include "base/timeutil.h" #include "ext/cityhash/city.h" -#include "Common/FileUtil.h" +#include "ext/xxhash.h" + +#include "Common/File/FileUtil.h" +#include "Common/Log.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/MemMap.h" #include "Core/System.h" @@ -35,7 +38,6 @@ #include "Core/Debugger/SymbolMap.h" #include "Core/Debugger/DebugInterface.h" #include "Core/HLE/ReplaceTables.h" -#include "ext/xxhash.h" using namespace MIPSCodeUtils; @@ -924,13 +926,13 @@ skip: // TODO: Load from cache file if available instead. - double st = real_time_now(); + double st = time_now_d(); for (auto iter = functions.begin(), end = functions.end(); iter != end; iter++) { const AnalyzedFunction &f = *iter; PrecompileFunction(f.start, f.end - f.start + 4); } - double et = real_time_now(); + double et = time_now_d(); NOTICE_LOG(JIT, "Precompiled %d MIPS functions in %0.2f milliseconds", (int)functions.size(), (et - st) * 1000.0); } diff --git a/Core/MIPS/MIPSAsm.cpp b/Core/MIPS/MIPSAsm.cpp index 08965b4fc2..0e59e62da1 100644 --- a/Core/MIPS/MIPSAsm.cpp +++ b/Core/MIPS/MIPSAsm.cpp @@ -1,17 +1,12 @@ -#ifdef _WIN32 -#include "stdafx.h" -#endif #include #include #include #include #include "Common/CommonTypes.h" - -// This has to be before basictypes to avoid a define conflict. #include "ext/armips/Core/Assembler.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MemMapHelpers.h" #include "Core/MIPS/JitCommon/JitCommon.h" diff --git a/Core/MIPS/MIPSDebugInterface.cpp b/Core/MIPS/MIPSDebugInterface.cpp index e99e86073c..f81b55ca98 100644 --- a/Core/MIPS/MIPSDebugInterface.cpp +++ b/Core/MIPS/MIPSDebugInterface.cpp @@ -215,7 +215,7 @@ unsigned int MIPSDebugInterface::readMemory(unsigned int address) bool MIPSDebugInterface::isAlive() { - return PSP_IsInited() && coreState != CORE_ERROR && coreState != CORE_POWERDOWN; + return PSP_IsInited() && coreState != CORE_BOOT_ERROR && coreState != CORE_RUNTIME_ERROR && coreState != CORE_POWERDOWN; } bool MIPSDebugInterface::isBreakpoint(unsigned int address) diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index 93372391c8..b49dab057f 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -17,10 +17,11 @@ #include -#include "math/math_util.h" +#include "Common/Math/math_util.h" -#include "Common/Common.h" +#include "Common/BitSet.h" #include "Common/BitScan.h" +#include "Common/Common.h" #include "Core/Config.h" #include "Core/Core.h" #include "Core/Host.h" @@ -54,6 +55,10 @@ static inline void DelayBranchTo(u32 where) { + if (!Memory::IsValidAddress(where)) { + // TODO: What about misaligned? + Core_ExecException(where, PC, ExecExceptionType::JUMP); + } PC += 4; mipsr4k.nextPC = where; mipsr4k.inDelaySlot = true; @@ -152,11 +157,7 @@ namespace MIPSInt void Int_Break(MIPSOpcode op) { Reporting::ReportMessage("BREAK instruction hit"); - ERROR_LOG(CPU, "BREAK!"); - if (!g_Config.bIgnoreBadMemAccess) { - Core_EnableStepping(true); - host->SetDebugMode(true); - } + Core_Break(); PC += 4; } @@ -180,7 +181,7 @@ namespace MIPSInt case 23: if ((s32)R(rs) > 0) DelayBranchTo(addr); else SkipLikely(); break; //bgtzl default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } } @@ -202,7 +203,7 @@ namespace MIPSInt case 18: R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else SkipLikely(); break;//bltzall case 19: R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else SkipLikely(); break;//bgezall default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } } @@ -237,7 +238,7 @@ namespace MIPSInt case 2: if (!currentMIPS->fpcond) DelayBranchTo(addr); else SkipLikely(); break;//bc1fl case 3: if ( currentMIPS->fpcond) DelayBranchTo(addr); else SkipLikely(); break;//bc1tl default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } } @@ -245,7 +246,7 @@ namespace MIPSInt void Int_JumpType(MIPSOpcode op) { if (mipsr4k.inDelaySlot) - _dbg_assert_msg_(CPU,0,"Jump in delay slot :("); + _dbg_assert_msg_(false,"Jump in delay slot :("); u32 off = ((op & 0x03FFFFFF) << 2); u32 addr = (currentMIPS->pc & 0xF0000000) | off; @@ -258,7 +259,7 @@ namespace MIPSInt DelayBranchTo(addr); break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } } @@ -271,7 +272,7 @@ namespace MIPSInt if (op == 0x03e00008) return; ERROR_LOG(CPU, "Jump in delay slot :("); - _dbg_assert_msg_(CPU,0,"Jump in delay slot :("); + _dbg_assert_msg_(false,"Jump in delay slot :("); } int rs = _RS; @@ -316,7 +317,7 @@ namespace MIPSInt case 14: R(rt) = R(rs) ^ uimm; break; //xori case 15: R(rt) = uimm << 16; break; //lui default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -348,7 +349,7 @@ namespace MIPSInt } break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -386,7 +387,7 @@ namespace MIPSInt case 44: R(rd) = ((s32)R(rs) > (s32)R(rt)) ? R(rs) : R(rt); break; //max case 45: R(rd) = ((s32)R(rs) < (s32)R(rt)) ? R(rs) : R(rt); break;//min default: - _dbg_assert_msg_(CPU, 0, "Unknown MIPS instruction %08x", op.encoding); + _dbg_assert_msg_( 0, "Unknown MIPS instruction %08x", op.encoding); break; } PC += 4; @@ -457,7 +458,7 @@ namespace MIPSInt break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret Mem instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret Mem instruction that can't be interpreted"); break; } PC += 4; @@ -475,7 +476,7 @@ namespace MIPSInt case 49: FI(ft) = Memory::Read_U32(addr); break; //lwc1 case 57: Memory::Write_U32(FI(ft), addr); break; //swc1 default: - _dbg_assert_msg_(CPU,0,"Trying to interpret FPULS instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret FPULS instruction that can't be interpreted"); break; } PC += 4; @@ -528,7 +529,7 @@ namespace MIPSInt } default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -555,7 +556,7 @@ namespace MIPSInt R(rd) = clz32(~R(rs)); break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -659,7 +660,7 @@ namespace MIPSInt break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -714,7 +715,7 @@ namespace MIPSInt case 7: R(rd) = (u32)(((s32)R(rt)) >> (R(rs)&0x1F)); break; //srav default: wrong: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -757,7 +758,7 @@ namespace MIPSInt break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret ALLEGREX instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret ALLEGREX instruction that can't be interpreted"); break; } PC += 4; @@ -784,7 +785,7 @@ namespace MIPSInt R(rd) = swap32(R(rt)); break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret ALLEGREX instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret ALLEGREX instruction that can't be interpreted"); break; } PC += 4; @@ -902,7 +903,7 @@ namespace MIPSInt } break; //cvt.w.s default: - _dbg_assert_msg_(CPU,0,"Trying to interpret FPU2Op instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret FPU2Op instruction that can't be interpreted"); break; } PC += 4; @@ -956,7 +957,7 @@ namespace MIPSInt break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret FPUComp instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret FPUComp instruction that can't be interpreted"); cond = false; break; } @@ -984,7 +985,7 @@ namespace MIPSInt break; case 3: F(fd) = F(fs) / F(ft); break; // div.s default: - _dbg_assert_msg_(CPU,0,"Trying to interpret FPU3Op instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret FPU3Op instruction that can't be interpreted"); break; } PC += 4; @@ -1009,7 +1010,7 @@ namespace MIPSInt void Int_Emuhack(MIPSOpcode op) { if (((op >> 24) & 3) != EMUOP_CALL_REPLACEMENT) { - _dbg_assert_msg_(CPU,0,"Trying to interpret emuhack instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret emuhack instruction that can't be interpreted"); } // It's a replacement func! int index = op.encoding & 0xFFFFFF; diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 8e3ad0ba01..a9c3b66832 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -21,7 +21,7 @@ #include #include -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Core/Compatibility.h" #include "Core/Core.h" @@ -213,7 +213,7 @@ namespace MIPSInt { if (addr & 0x3) { - _dbg_assert_msg_(CPU, 0, "Misaligned lvX.q"); + _dbg_assert_msg_( 0, "Misaligned lvX.q at %08x (pc = %08x)", addr, PC); } float d[4]; ReadVector(d, V_Quad, vt); @@ -241,7 +241,7 @@ namespace MIPSInt case 54: //lv.q if (addr & 0xF) { - _dbg_assert_msg_(CPU, 0, "Misaligned lv.q"); + _dbg_assert_msg_( 0, "Misaligned lv.q at %08x (pc = %08x)", addr, PC); } #ifndef COMMON_BIG_ENDIAN WriteVector((const float*)Memory::GetPointer(addr), V_Quad, vt); @@ -261,7 +261,7 @@ namespace MIPSInt { if (addr & 0x3) { - _dbg_assert_msg_(CPU, 0, "Misaligned svX.q"); + _dbg_assert_msg_( 0, "Misaligned svX.q at %08x (pc = %08x)", addr, PC); } float d[4]; ReadVector(d, V_Quad, vt); @@ -288,7 +288,7 @@ namespace MIPSInt case 62: //sv.q if (addr & 0xF) { - _dbg_assert_msg_(CPU, 0, "Misaligned sv.q"); + _dbg_assert_msg_( 0, "Misaligned sv.q at %08x (pc = %08x)", addr, PC); } #ifndef COMMON_BIG_ENDIAN ReadVector(reinterpret_cast(Memory::GetPointer(addr)), V_Quad, vt); @@ -304,7 +304,7 @@ namespace MIPSInt break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret VQ instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret VQ instruction that can't be interpreted"); break; } PC += 4; @@ -338,7 +338,7 @@ namespace MIPSInt case 6: m=zero; break; // vmzero case 7: m=one; break; // vmone default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); PC += 4; EatPrefixes(); return; @@ -369,7 +369,7 @@ namespace MIPSInt sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE); break; default: - _dbg_assert_msg_(CPU, 0, "Unknown matrix init op"); + _dbg_assert_msg_( 0, "Unknown matrix init op"); break; } ApplyPrefixST(&prefixed[off * 4], VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Quad); @@ -393,7 +393,7 @@ namespace MIPSInt case 6: constant = VFPUConst::ZERO; break; //vzero case 7: constant = VFPUConst::ONE; break; //vone default: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Trying to interpret instruction that can't be interpreted"); PC += 4; EatPrefixes(); return; @@ -422,7 +422,7 @@ namespace MIPSInt } else if (type == 7) { f[0] = Float16ToFloat32((u16)uimm16); // vfim } else { - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Invalid Viim opcode type %d", type); f[0] = 0; } @@ -634,7 +634,7 @@ namespace MIPSInt case 26: { d[i] = -vfpu_sin(s[i]); } break; // vnsin case 28: d[i] = 1.0f / powf(2.0, s[i]); break; // vrexp2 default: - _dbg_assert_msg_(CPU,0,"Trying to interpret VV2Op instruction that can't be interpreted"); + _dbg_assert_msg_( false, "Invalid VV2Op op type %d", optype); break; } } @@ -993,7 +993,7 @@ namespace MIPSInt break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( false, "Trying to interpret instruction that can't be interpreted"); break; } @@ -1051,7 +1051,7 @@ namespace MIPSInt case V_Pair: oz = V_Single; break; case V_Single: oz = V_Single; break; default: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( false, "Trying to interpret instruction that can't be interpreted"); oz = V_Single; break; } @@ -1070,13 +1070,13 @@ namespace MIPSInt case V_Pair: oz = V_Single; break; case V_Single: oz = V_Single; break; default: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Trying to interpret instruction that can't be interpreted"); oz = V_Single; break; } break; default: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Trying to interpret instruction that can't be interpreted"); oz = V_Single; break; } @@ -1550,7 +1550,7 @@ namespace MIPSInt case 1: d.u[i] = currentMIPS->rng.R32(); break; // vrndi case 2: d.f[i] = 1.0f + ((float)currentMIPS->rng.R32() / 0xFFFFFFFF); break; // vrndf1 TODO: make more accurate case 3: d.f[i] = 2.0f + 2 * ((float)currentMIPS->rng.R32() / 0xFFFFFFFF); break; // vrndf2 TODO: make more accurate - default: _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + default: _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); } } // D prefix is broken and applies to the last element only (mask and sat.) @@ -1724,7 +1724,7 @@ namespace MIPSInt Memory::Write_U32(VI(vt), addr); break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -1746,7 +1746,7 @@ namespace MIPSInt R(rt) = currentMIPS->vfpuCtrl[imm - 128]; } else { //ERROR - maybe need to make this value too an "interlock" value? - _dbg_assert_msg_(CPU,0,"mfv - invalid register"); + _dbg_assert_msg_(false,"mfv - invalid register"); } } break; @@ -1761,12 +1761,12 @@ namespace MIPSInt } } else { //ERROR - _dbg_assert_msg_(CPU,0,"mtv - invalid register"); + _dbg_assert_msg_(false,"mtv - invalid register"); } break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } PC += 4; @@ -1853,7 +1853,7 @@ namespace MIPSInt case VC_NS: c = !(my_isnanorinf(s[i])); break; // How about t[i] ? default: - _dbg_assert_msg_(CPU,0,"Unsupported vcmp condition code %d", cond); + _dbg_assert_msg_(false,"Unsupported vcmp condition code %d", cond); PC += 4; EatPrefixes(); return; @@ -1920,7 +1920,7 @@ namespace MIPSInt } break; default: - _dbg_assert_msg_(CPU,0,"unknown min/max op %d", cond); + _dbg_assert_msg_(false,"unknown min/max op %d", cond); PC += 4; EatPrefixes(); return; @@ -2075,7 +2075,7 @@ namespace MIPSInt break; default: bad: - _dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_( 0, "Trying to interpret instruction that can't be interpreted"); break; } diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 69e5d28afa..2270fc3630 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -28,7 +28,6 @@ #include "Core/CoreTiming.h" #include "Core/Reporting.h" #include "Core/Debugger/Breakpoints.h" -#include "base/logging.h" #include "JitCommon/JitCommon.h" @@ -948,7 +947,7 @@ void MIPSInterpret(MIPSOpcode op) { // Try to disassemble it char disasm[256]; MIPSDisAsm(op, currentMIPS->pc, disasm); - _dbg_assert_msg_(CPU, 0, "%s", disasm); + _dbg_assert_msg_( 0, "%s", disasm); currentMIPS->pc += 4; } } @@ -1019,13 +1018,14 @@ int MIPSInterpret_RunUntil(u64 globalTicks) if (curMips->inDelaySlot) { + curMips->downcount -= 1; // The reason we have to check this is the delay slot hack in Int_Syscall. if (wasInDelaySlot) { curMips->pc = curMips->nextPC; curMips->inDelaySlot = false; + continue; } - curMips->downcount -= 1; goto again; } } diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index 280dec90e4..923faf804d 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -41,7 +41,7 @@ void GetVectorRegs(u8 regs[4], VectorSize N, int vectorReg) { case V_Pair: row=(vectorReg>>5)&2; length = 2; break; case V_Triple: row=(vectorReg>>6)&1; length = 3; break; case V_Quad: row=(vectorReg>>5)&2; length = 4; break; - default: _assert_msg_(JIT, 0, "%s: Bad vector size", __FUNCTION__); + default: _assert_msg_(false, "%s: Bad vector size", __FUNCTION__); } for (int i = 0; i < length; i++) { @@ -67,7 +67,7 @@ void GetMatrixRegs(u8 regs[16], MatrixSize N, int matrixReg) { case M_2x2: row = (matrixReg >> 5) & 2; side = 2; break; case M_3x3: row = (matrixReg >> 6) & 1; side = 3; break; case M_4x4: row = (matrixReg >> 5) & 2; side = 4; break; - default: _assert_msg_(JIT, 0, "%s: Bad matrix size", __FUNCTION__); + default: _assert_msg_(false, "%s: Bad matrix size", __FUNCTION__); } for (int i = 0; i < side; i++) { @@ -112,7 +112,7 @@ int GetMatrixName(int matrix, MatrixSize msize, int column, int row, bool transp name |= (row << 5) | column; break; - default: _assert_msg_(JIT, 0, "%s: Bad matrix size", __FUNCTION__); + default: _assert_msg_(false, "%s: Bad matrix size", __FUNCTION__); } return name; @@ -161,7 +161,7 @@ void ReadVector(float *rd, VectorSize size, int reg) { case V_Pair: row=(reg>>5)&2; length = 2; break; case V_Triple: row=(reg>>6)&1; length = 3; break; case V_Quad: row=(reg>>5)&2; length = 4; break; - default: _assert_msg_(JIT, 0, "%s: Bad vector size", __FUNCTION__); + default: _assert_msg_(false, "%s: Bad vector size", __FUNCTION__); } int transpose = (reg>>5) & 1; const int mtx = (reg >> 2) & 7; @@ -194,11 +194,11 @@ void WriteVector(const float *rd, VectorSize size, int reg) { int length = 0; switch (size) { - case V_Single: _dbg_assert_(JIT, 0); return; // transpose = 0; row=(reg>>5)&3; length = 1; break; + case V_Single: _dbg_assert_(false); return; // transpose = 0; row=(reg>>5)&3; length = 1; break; case V_Pair: row=(reg>>5)&2; length = 2; break; case V_Triple: row=(reg>>6)&1; length = 3; break; case V_Quad: row=(reg>>5)&2; length = 4; break; - default: _assert_msg_(JIT, 0, "%s: Bad vector size", __FUNCTION__); + default: _assert_msg_(false, "%s: Bad vector size", __FUNCTION__); } if (currentMIPS->VfpuWriteMask() == 0) { @@ -243,7 +243,7 @@ void ReadMatrix(float *rd, MatrixSize size, int reg) { case M_2x2: row = (reg >> 5) & 2; side = 2; break; case M_3x3: row = (reg >> 6) & 1; side = 3; break; case M_4x4: row = (reg >> 5) & 2; side = 4; break; - default: _assert_msg_(JIT, 0, "%s: Bad matrix size", __FUNCTION__); + default: _assert_msg_(false, "%s: Bad matrix size", __FUNCTION__); } // The voffset ordering is now integrated in these formulas, @@ -293,7 +293,7 @@ void WriteMatrix(const float *rd, MatrixSize size, int reg) { case M_2x2: row = (reg >> 5) & 2; side = 2; break; case M_3x3: row = (reg >> 6) & 1; side = 3; break; case M_4x4: row = (reg >> 5) & 2; side = 4; break; - default: _assert_msg_(JIT, 0, "%s: Bad matrix size", __FUNCTION__); + default: _assert_msg_(false, "%s: Bad matrix size", __FUNCTION__); } if (currentMIPS->VfpuWriteMask() != 0) { @@ -374,7 +374,7 @@ VectorSize GetHalfVectorSizeSafe(VectorSize sz) { VectorSize GetHalfVectorSize(VectorSize sz) { VectorSize res = GetHalfVectorSizeSafe(sz); - _assert_msg_(JIT, res != V_Invalid, "%s: Bad vector size", __FUNCTION__); + _assert_msg_(res != V_Invalid, "%s: Bad vector size", __FUNCTION__); return res; } @@ -388,7 +388,7 @@ VectorSize GetDoubleVectorSizeSafe(VectorSize sz) { VectorSize GetDoubleVectorSize(VectorSize sz) { VectorSize res = GetDoubleVectorSizeSafe(sz); - _assert_msg_(JIT, res != V_Invalid, "%s: Bad vector size", __FUNCTION__); + _assert_msg_(res != V_Invalid, "%s: Bad vector size", __FUNCTION__); return res; } @@ -407,7 +407,7 @@ VectorSize GetVecSizeSafe(MIPSOpcode op) { VectorSize GetVecSize(MIPSOpcode op) { VectorSize res = GetVecSizeSafe(op); - _assert_msg_(JIT, res != V_Invalid, "%s: Bad vector size", __FUNCTION__); + _assert_msg_(res != V_Invalid, "%s: Bad vector size", __FUNCTION__); return res; } @@ -423,7 +423,7 @@ VectorSize GetVectorSizeSafe(MatrixSize sz) { VectorSize GetVectorSize(MatrixSize sz) { VectorSize res = GetVectorSizeSafe(sz); - _assert_msg_(JIT, res != V_Invalid, "%s: Bad vector size", __FUNCTION__); + _assert_msg_(res != V_Invalid, "%s: Bad vector size", __FUNCTION__); return res; } @@ -439,7 +439,7 @@ MatrixSize GetMatrixSizeSafe(VectorSize sz) { MatrixSize GetMatrixSize(VectorSize sz) { MatrixSize res = GetMatrixSizeSafe(sz); - _assert_msg_(JIT, res != M_Invalid, "%s: Bad vector size", __FUNCTION__); + _assert_msg_(res != M_Invalid, "%s: Bad vector size", __FUNCTION__); return res; } @@ -458,7 +458,7 @@ MatrixSize GetMtxSizeSafe(MIPSOpcode op) { MatrixSize GetMtxSize(MIPSOpcode op) { MatrixSize res = GetMtxSizeSafe(op); - _assert_msg_(JIT, res != M_Invalid, "%s: Bad matrix size", __FUNCTION__); + _assert_msg_(res != M_Invalid, "%s: Bad matrix size", __FUNCTION__); return res; } @@ -474,7 +474,7 @@ VectorSize MatrixVectorSizeSafe(MatrixSize sz) { VectorSize MatrixVectorSize(MatrixSize sz) { VectorSize res = MatrixVectorSizeSafe(sz); - _assert_msg_(JIT, res != V_Invalid, "%s: Bad matrix size", __FUNCTION__); + _assert_msg_(res != V_Invalid, "%s: Bad matrix size", __FUNCTION__); return res; } @@ -490,7 +490,7 @@ int GetMatrixSideSafe(MatrixSize sz) { int GetMatrixSide(MatrixSize sz) { int res = GetMatrixSideSafe(sz); - _assert_msg_(JIT, res != 0, "%s: Bad matrix size", __FUNCTION__); + _assert_msg_(res != 0, "%s: Bad matrix size", __FUNCTION__); return res; } @@ -776,7 +776,7 @@ float vfpu_dot(float a[4], float b[4]) { mant_sum <<= shift; max_exp -= shift; } - _dbg_assert_msg_(JIT, (mant_sum & 0x00800000) != 0, "Mantissa wrong: %08x", mant_sum); + _dbg_assert_msg_((mant_sum & 0x00800000) != 0, "Mantissa wrong: %08x", mant_sum); if (max_exp >= 255) { max_exp = 255; diff --git a/Core/MIPS/fake/FakeJit.cpp b/Core/MIPS/fake/FakeJit.cpp index 1a521ee68b..257005a429 100644 --- a/Core/MIPS/fake/FakeJit.cpp +++ b/Core/MIPS/fake/FakeJit.cpp @@ -15,8 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "Core/Core.h" diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index fd1815132d..a099e1044b 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -18,7 +18,7 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "ABI.h" #include "x64Emitter.h" @@ -163,13 +163,13 @@ void Jit::GenerateFixedCode(JitOptions &jo) { #endif #ifdef _M_IX86 - _assert_msg_(CPU, Memory::base != 0, "Memory base bogus"); + _assert_msg_( Memory::base != 0, "Memory base bogus"); MOV(32, R(EAX), MDisp(EAX, (u32)Memory::base)); #elif _M_X64 MOV(32, R(EAX), MComplex(MEMBASEREG, RAX, SCALE_1, 0)); #endif MOV(32, R(EDX), R(EAX)); - _assert_msg_(JIT, MIPS_JITBLOCK_MASK == 0xFF000000, "Hardcoded assumption of emuhack mask"); + _assert_msg_(MIPS_JITBLOCK_MASK == 0xFF000000, "Hardcoded assumption of emuhack mask"); SHR(32, R(EDX), Imm8(24)); CMP(32, R(EDX), Imm8(MIPS_EMUHACK_OPCODE >> 24)); FixupBranch notfound = J_CC(CC_NE); @@ -206,11 +206,21 @@ void Jit::GenerateFixedCode(JitOptions &jo) { } J_CC(CC_Z, outerLoop, true); + const uint8_t *quitLoop = GetCodePtr(); SetJumpTarget(badCoreState); RestoreRoundingMode(true); ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); + crashHandler = GetCodePtr(); + if (RipAccessible((const void *)&coreState)) { + MOV(32, M(&coreState), Imm32(CORE_RUNTIME_ERROR)); + } else { + MOV(PTRBITS, R(RAX), ImmPtr((const void *)&coreState)); + MOV(32, MatR(RAX), Imm32(CORE_RUNTIME_ERROR)); + } + JMP(quitLoop, true); + // Let's spare the pre-generated code from unprotect-reprotect. endOfPregeneratedCode = AlignCodePage(); EndWrite(); diff --git a/Core/MIPS/x86/CompALU.cpp b/Core/MIPS/x86/CompALU.cpp index 456695b575..4c262cf1a4 100644 --- a/Core/MIPS/x86/CompALU.cpp +++ b/Core/MIPS/x86/CompALU.cpp @@ -18,10 +18,13 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) +#include + +#include "Common/BitSet.h" +#include "Common/Common.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/x86/Jit.h" #include "Core/MIPS/x86/RegCache.h" -#include using namespace MIPSAnalyst; diff --git a/Core/MIPS/x86/CompBranch.cpp b/Core/MIPS/x86/CompBranch.cpp index 2cfce8486b..875ff24399 100644 --- a/Core/MIPS/x86/CompBranch.cpp +++ b/Core/MIPS/x86/CompBranch.cpp @@ -18,10 +18,11 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" -#include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/Core.h" +#include "Core/Reporting.h" #include "Core/HLE/HLE.h" #include "Core/HLE/HLETables.h" #include "Core/Host.h" @@ -335,7 +336,7 @@ void Jit::BranchRSRTComp(MIPSOpcode op, Gen::CCFlags cc, bool likely) { case CC_E: immBranchNotTaken = rsImm == rtImm; break; case CC_NE: immBranchNotTaken = rsImm != rtImm; break; - default: immBranchNotTaken = false; _dbg_assert_msg_(JIT, false, "Bad cc flag in BranchRSRTComp()."); + default: immBranchNotTaken = false; _dbg_assert_msg_(false, "Bad cc flag in BranchRSRTComp()."); } immBranch = true; immBranchTaken = !immBranchNotTaken; @@ -411,7 +412,7 @@ void Jit::BranchRSZeroComp(MIPSOpcode op, Gen::CCFlags cc, bool andLink, bool li case CC_GE: immBranchNotTaken = imm >= 0; break; case CC_L: immBranchNotTaken = imm < 0; break; case CC_LE: immBranchNotTaken = imm <= 0; break; - default: immBranchNotTaken = false; _dbg_assert_msg_(JIT, false, "Bad cc flag in BranchRSZeroComp()."); + default: immBranchNotTaken = false; _dbg_assert_msg_(false, "Bad cc flag in BranchRSZeroComp()."); } immBranch = true; immBranchTaken = !immBranchNotTaken; @@ -478,7 +479,7 @@ void Jit::Comp_RelBranch(MIPSOpcode op) case 23: BranchRSZeroComp(op, CC_LE, false, true); break;//bgtzl default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -496,7 +497,7 @@ void Jit::Comp_RelBranchRI(MIPSOpcode op) case 18: BranchRSZeroComp(op, CC_GE, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else SkipLikely(); break;//bltzall case 19: BranchRSZeroComp(op, CC_L, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else SkipLikely(); break;//bgezall default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } } @@ -535,7 +536,7 @@ void Jit::Comp_FPUBranch(MIPSOpcode op) case 2: BranchFPFlag(op, CC_NZ, true); break; //bc1fl case 3: BranchFPFlag(op, CC_Z, true); break; //bc1tl default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } } @@ -586,11 +587,15 @@ void Jit::Comp_VBranch(MIPSOpcode op) case 2: BranchVFPUFlag(op, CC_NZ, true); break; //bvfl case 3: BranchVFPUFlag(op, CC_Z, true); break; //bvtl default: - _dbg_assert_msg_(CPU,0,"Comp_VBranch: Invalid instruction"); + _dbg_assert_msg_(false,"Comp_VBranch: Invalid instruction"); break; } } +static void HitInvalidJump(uint32_t dest) { + Core_ExecException(dest, currentMIPS->pc - 8, ExecExceptionType::JUMP); +} + void Jit::Comp_Jump(MIPSOpcode op) { CONDITIONAL_LOG; if (js.inDelaySlot) { @@ -608,6 +613,12 @@ void Jit::Comp_Jump(MIPSOpcode op) { js.compiling = false; } // TODO: Mark this block dirty or something? May be indication it will be changed by imports. + + CompileDelaySlot(DELAYSLOT_NICE); + FlushAll(); + MOV(32, MIPSSTATE_VAR(pc), Imm32(GetCompilerPC() + 8)); + ABI_CallFunctionC(&HitInvalidJump, targetAddr); + WriteSyscallExit(); return; } @@ -654,7 +665,7 @@ void Jit::Comp_Jump(MIPSOpcode op) { break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } js.compiling = false; @@ -688,7 +699,7 @@ void Jit::Comp_JumpReg(MIPSOpcode op) CompileDelaySlot(DELAYSLOT_FLUSH); // Syscalls write the exit code for us. - _dbg_assert_msg_(JIT, !js.compiling, "Expected syscall to write an exit code."); + _dbg_assert_msg_(!js.compiling, "Expected syscall to write an exit code."); return; } else if (delaySlotIsNice) @@ -742,7 +753,7 @@ void Jit::Comp_JumpReg(MIPSOpcode op) case 9: //jalr break; default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); + _dbg_assert_msg_(false,"Trying to compile instruction that can't be compiled"); break; } diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index 806d631047..cb1d7be5ed 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -116,7 +116,7 @@ void Jit::Comp_FPU3op(MIPSOpcode op) { break; case 3: CompFPTriArith(op, &XEmitter::DIVSS, true); break; //F(fd) = F(fs) / F(ft); //div default: - _dbg_assert_msg_(CPU,0,"Trying to compile FPU3Op instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to compile FPU3Op instruction that can't be interpreted"); break; } } @@ -169,7 +169,7 @@ void Jit::Comp_FPULS(MIPSOpcode op) { break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret FPULS instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret FPULS instruction that can't be interpreted"); break; } } diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index 5182c7fdc2..e3d87bcf94 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -228,7 +228,7 @@ namespace MIPSComp { break; default: - _dbg_assert_msg_(JIT, 0, "Unsupported left/right load/store instruction."); + _dbg_assert_msg_(false, "Unsupported left/right load/store instruction."); } // Flip ECX around from 3 bytes / 24 bits. @@ -279,7 +279,7 @@ namespace MIPSComp { break; default: - _dbg_assert_msg_(JIT, 0, "Unsupported left/right load/store instruction."); + _dbg_assert_msg_(false, "Unsupported left/right load/store instruction."); } } diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 89bcf93fbc..95d0704da3 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -25,10 +25,10 @@ #include #include -#include "base/logging.h" -#include "math/math_util.h" +#include "Common/Math/math_util.h" #include "Common/CPUDetect.h" +#include "Common/Log.h" #include "Core/Compatibility.h" #include "Core/Config.h" #include "Core/MemMap.h" @@ -603,7 +603,7 @@ void Jit::Comp_VIdt(MIPSOpcode op) { MOVSS(fpr.VX(dregs[3]), R((vd&3)==3 ? XMM1 : XMM0)); break; default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } ApplyPrefixD(dregs, sz); @@ -2479,7 +2479,7 @@ void Jit::Comp_Mftv(MIPSOpcode op) { } } else { //ERROR - maybe need to make this value too an "interlock" value? - _dbg_assert_msg_(CPU,0,"mfv - invalid register"); + _dbg_assert_msg_(false,"mfv - invalid register"); } } break; @@ -2520,7 +2520,7 @@ void Jit::Comp_Mftv(MIPSOpcode op) { } } else { //ERROR - _dbg_assert_msg_(CPU,0,"mtv - invalid register"); + _dbg_assert_msg_(false,"mtv - invalid register"); } break; diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index a8050ac0ac..97682d5f7d 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -21,10 +21,11 @@ #include #include -#include "math/math_util.h" -#include "profiler/profiler.h" +#include "Common/Math/math_util.h" +#include "Common/Profiler/Profiler.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Core.h" #include "Core/MemMap.h" #include "Core/System.h" @@ -129,9 +130,9 @@ void Jit::DoState(PointerWrap &p) { if (!s) return; - p.Do(js.startDefaultPrefix); + Do(p, js.startDefaultPrefix); if (s >= 2) { - p.Do(js.hasSetRounding); + Do(p, js.hasSetRounding); js.lastSetRounding = 0; } else { js.hasSetRounding = 1; @@ -442,6 +443,8 @@ bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name) { name = "enterDispatcher"; else if (ptr == restoreRoundingMode) name = "restoreRoundingMode"; + else if (ptr == crashHandler) + name = "crashHandler"; else { u32 jitAddr = blocks.GetAddressFromBlockPtr(ptr); @@ -631,7 +634,7 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) { void Jit::Comp_Generic(MIPSOpcode op) { FlushAll(); MIPSInterpretFunc func = MIPSGetInterpretFunc(op); - _dbg_assert_msg_(JIT, (MIPSGetInfo(op) & DELAYSLOT) == 0, "Cannot use interpreter for branch ops."); + _dbg_assert_msg_((MIPSGetInfo(op) & DELAYSLOT) == 0, "Cannot use interpreter for branch ops."); if (func) { @@ -656,11 +659,18 @@ void Jit::Comp_Generic(MIPSOpcode op) { } } +static void HitInvalidBranch(uint32_t dest) { + Core_ExecException(dest, currentMIPS->pc, ExecExceptionType::JUMP); +} + void Jit::WriteExit(u32 destination, int exit_num) { - _dbg_assert_msg_(JIT, exit_num < MAX_JIT_BLOCK_EXITS, "Expected a valid exit_num"); + _dbg_assert_msg_(exit_num < MAX_JIT_BLOCK_EXITS, "Expected a valid exit_num"); if (!Memory::IsValidAddress(destination)) { ERROR_LOG_REPORT(JIT, "Trying to write block exit to illegal destination %08x: pc = %08x", destination, currentMIPS->pc); + MOV(32, MIPSSTATE_VAR(pc), Imm32(GetCompilerPC())); + ABI_CallFunctionC(&HitInvalidBranch, destination); + js.afterOp |= JitState::AFTER_CORE_STATE; } // If we need to verify coreState and rewind, we may not jump yet. if (js.afterOp & (JitState::AFTER_CORE_STATE | JitState::AFTER_REWIND_PC_BAD_STATE)) { @@ -705,6 +715,11 @@ void Jit::WriteExit(u32 destination, int exit_num) { } } +static void HitInvalidJumpReg(uint32_t source) { + Core_ExecException(currentMIPS->pc, source, ExecExceptionType::JUMP); + currentMIPS->pc = source + 8; +} + void Jit::WriteExitDestInReg(X64Reg reg) { // If we need to verify coreState and rewind, we may not jump yet. if (js.afterOp & (JitState::AFTER_CORE_STATE | JitState::AFTER_REWIND_PC_BAD_STATE)) { @@ -741,15 +756,13 @@ void Jit::WriteExitDestInReg(X64Reg reg) { SetJumpTarget(tooLow); SetJumpTarget(tooHigh); - ABI_CallFunctionA((const void *)&Memory::GetPointer, R(reg)); + ABI_CallFunctionA((const void *)&Memory::IsValidAddress, R(reg)); // If we're ignoring, coreState didn't trip - so trip it now. - if (g_Config.bIgnoreBadMemAccess) { - CMP(32, R(EAX), Imm32(0)); - FixupBranch skip = J_CC(CC_NE); - ABI_CallFunctionA((const void *)&Core_UpdateState, Imm32(CORE_ERROR)); - SetJumpTarget(skip); - } + CMP(32, R(EAX), Imm32(0)); + FixupBranch skip = J_CC(CC_NE); + ABI_CallFunctionC(&HitInvalidJumpReg, GetCompilerPC()); + SetJumpTarget(skip); SUB(32, MIPSSTATE_VAR(downcount), Imm8(0)); JMP(dispatcherCheckCoreState, true); diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 0eefe89c40..b065d90522 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -63,6 +63,8 @@ public: void Compile(u32 em_address) override; // Compiles a block at current MIPS PC const u8 *DoJit(u32 em_address, JitBlock *b); + const u8 *GetCrashHandler() const override { return crashHandler; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } bool DescribeCodePtr(const u8 *ptr, std::string &name) override; void Comp_RunBlock(MIPSOpcode op) override; @@ -325,6 +327,8 @@ private: const u8 *endOfPregeneratedCode; + const u8 *crashHandler; + friend class JitSafeMem; friend class JitSafeMemFuncs; }; diff --git a/Core/MIPS/x86/JitSafeMem.cpp b/Core/MIPS/x86/JitSafeMem.cpp index 676f8b1ced..d35e3022ce 100644 --- a/Core/MIPS/x86/JitSafeMem.cpp +++ b/Core/MIPS/x86/JitSafeMem.cpp @@ -142,7 +142,7 @@ OpArg JitSafeMem::NextFastAddress(int suboffset) #endif } - _dbg_assert_msg_(JIT, (suboffset & alignMask_) == suboffset, "suboffset must be aligned"); + _dbg_assert_msg_((suboffset & alignMask_) == suboffset, "suboffset must be aligned"); #if PPSSPP_ARCH(32BIT) return MDisp(xaddr_, (u32) Memory::base + offset_ + suboffset); @@ -303,7 +303,7 @@ bool JitSafeMem::PrepareSlowRead(const void *safeFunc) void JitSafeMem::NextSlowRead(const void *safeFunc, int suboffset) { - _dbg_assert_msg_(JIT, !fast_, "NextSlowRead() called in fast memory mode?"); + _dbg_assert_msg_(!fast_, "NextSlowRead() called in fast memory mode?"); // For simplicity, do nothing for 0. We already read in PrepareSlowRead(). if (suboffset == 0) @@ -311,7 +311,7 @@ void JitSafeMem::NextSlowRead(const void *safeFunc, int suboffset) if (jit_->gpr.IsImm(raddr_)) { - _dbg_assert_msg_(JIT, !Memory::IsValidAddress(iaddr_ + suboffset), "NextSlowRead() for an invalid immediate address?"); + _dbg_assert_msg_(!Memory::IsValidAddress(iaddr_ + suboffset), "NextSlowRead() for an invalid immediate address?"); jit_->MOV(32, R(EAX), Imm32((iaddr_ + suboffset) & alignMask_)); } diff --git a/Core/MIPS/x86/RegCache.cpp b/Core/MIPS/x86/RegCache.cpp index 11868c0e82..fa8479323d 100644 --- a/Core/MIPS/x86/RegCache.cpp +++ b/Core/MIPS/x86/RegCache.cpp @@ -115,9 +115,7 @@ void GPRRegCache::Lock(MIPSGPReg p1, MIPSGPReg p2, MIPSGPReg p3, MIPSGPReg p4) { // these are x64 reg indices void GPRRegCache::LockX(int x1, int x2, int x3, int x4) { - if (xregs[x1].allocLocked) { - PanicAlert("RegCache: x %i already locked!", x1); - } + _assert_msg_(!xregs[x1].allocLocked, "RegCache: x %d already locked!", x1); xregs[x1].allocLocked = true; if (x2 != 0xFF) xregs[x2].allocLocked = true; if (x3 != 0xFF) xregs[x3].allocLocked = true; @@ -197,24 +195,23 @@ X64Reg GPRRegCache::GetFreeXReg() return bestToSpill; } - //Still no dice? Die! - _assert_msg_(JIT, 0, "Regcache ran out of regs"); - return (X64Reg) -1; + // Still no dice? Give up. + _assert_msg_(false, "Regcache ran out of regs"); + return (X64Reg)-1; } void GPRRegCache::FlushR(X64Reg reg) { - if (reg >= NUM_X_REGS) - PanicAlert("Flushing non existent reg"); - else if (!xregs[reg].free) + if (reg >= NUM_X_REGS) { + _assert_msg_(false, "Flushing non existent reg"); + } else if (!xregs[reg].free) { StoreFromRegister(xregs[reg].mipsReg); + } } void GPRRegCache::FlushRemap(MIPSGPReg oldreg, MIPSGPReg newreg) { OpArg oldLocation = regs[oldreg].location; - if (!oldLocation.IsSimpleReg()) { - PanicAlert("FlushRemap: Must already be in an x86 register"); - } + _assert_msg_(oldLocation.IsSimpleReg(), "FlushRemap: Must already be in an x86 register"); X64Reg xr = oldLocation.GetSimpleReg(); @@ -302,7 +299,7 @@ bool GPRRegCache::IsImm(MIPSGPReg preg) const { } u32 GPRRegCache::GetImm(MIPSGPReg preg) const { - _dbg_assert_msg_(JIT, IsImm(preg), "Reg %d must be an immediate.", preg); + _dbg_assert_msg_(IsImm(preg), "Reg %d must be an immediate.", preg); // Always 0 for ZERO. if (preg == MIPS_REG_ZERO) return 0; @@ -335,7 +332,7 @@ OpArg GPRRegCache::GetDefaultLocation(MIPSGPReg reg) const { case MIPS_REG_VFPUCC: return MIPSSTATE_VAR(vfpuCtrl[VFPU_CTRL_CC]); default: - ERROR_LOG_REPORT(JIT, "bad mips register %i", reg); + ERROR_LOG_REPORT(JIT, "Bad mips register %d", reg); return MIPSSTATE_VAR(r[0]); } } @@ -351,13 +348,13 @@ void GPRRegCache::KillImmediate(MIPSGPReg preg, bool doLoad, bool makeDirty) { } void GPRRegCache::MapReg(MIPSGPReg i, bool doLoad, bool makeDirty) { - if (!regs[i].away && regs[i].location.IsImm()) - PanicAlert("Bad immediate"); - + if (!regs[i].away && regs[i].location.IsImm()) { + _assert_msg_(false, "Bad immediate"); + } if (!regs[i].away || (regs[i].away && regs[i].location.IsImm())) { X64Reg xr = GetFreeXReg(); - if (xregs[xr].dirty) PanicAlert("Xreg already dirty"); - if (xregs[xr].allocLocked) PanicAlert("GetFreeXReg returned locked register"); + _assert_msg_(!xregs[xr].dirty, "Xreg already dirty"); + _assert_msg_(!xregs[xr].allocLocked, "GetFreeXReg returned locked register"); xregs[xr].free = false; xregs[xr].mipsReg = i; xregs[xr].dirty = makeDirty || regs[i].location.IsImm(); @@ -371,8 +368,7 @@ void GPRRegCache::MapReg(MIPSGPReg i, bool doLoad, bool makeDirty) { } for (int j = 0; j < 32; j++) { if (i != MIPSGPReg(j) && regs[j].location.IsSimpleReg(xr)) { - ERROR_LOG(JIT, "BindToRegister: Strange condition"); - Crash(); + _assert_msg_(false, "BindToRegister: Strange condition"); } } regs[i].away = true; @@ -382,9 +378,8 @@ void GPRRegCache::MapReg(MIPSGPReg i, bool doLoad, bool makeDirty) { // and immediates are taken care of above. xregs[RX(i)].dirty |= makeDirty; } - if (xregs[RX(i)].allocLocked) { - PanicAlert("Seriously WTF, this reg should have been flushed"); - } + + _assert_msg_(!xregs[RX(i)].allocLocked, "This reg should have been flushed (r%d)", i); } void GPRRegCache::StoreFromRegister(MIPSGPReg i) { @@ -411,15 +406,12 @@ void GPRRegCache::StoreFromRegister(MIPSGPReg i) { void GPRRegCache::Flush() { for (int i = 0; i < NUM_X_REGS; i++) { - if (xregs[i].allocLocked) - PanicAlert("Someone forgot to unlock X64 reg %i.", i); + _assert_msg_(!xregs[i].allocLocked, "Someone forgot to unlock X64 reg %d.", i); } SetImm(MIPS_REG_ZERO, 0); for (int i = 1; i < NUM_MIPS_GPRS; i++) { const MIPSGPReg r = MIPSGPReg(i); - if (regs[i].locked) { - PanicAlert("Somebody forgot to unlock MIPS reg %i.", i); - } + _assert_msg_(!regs[i].locked, "Somebody forgot to unlock MIPS reg %d.", i); if (regs[i].away) { if (regs[i].location.IsSimpleReg()) { X64Reg xr = RX(r); @@ -429,7 +421,7 @@ void GPRRegCache::Flush() { else if (regs[i].location.IsImm()) { StoreFromRegister(r); } else { - _assert_msg_(JIT,0,"Jit64 - Flush unhandled case, reg %i PC: %08x", i, mips->pc); + _assert_msg_(false, "Jit64 - Flush unhandled case, reg %d PC: %08x", i, mips->pc); } } } diff --git a/Core/MIPS/x86/RegCache.h b/Core/MIPS/x86/RegCache.h index fe7cc43a21..cdda09eb3f 100644 --- a/Core/MIPS/x86/RegCache.h +++ b/Core/MIPS/x86/RegCache.h @@ -101,7 +101,7 @@ public: { if (regs[preg].away && regs[preg].location.IsSimpleReg()) return regs[preg].location.GetSimpleReg(); - PanicAlert("Not so simple - %i", preg); + _assert_msg_(false, "Not so simple - %d", preg); return (Gen::X64Reg)-1; } Gen::OpArg GetDefaultLocation(MIPSGPReg reg) const; diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp index b4542a3f5c..e217bfc9e7 100644 --- a/Core/MIPS/x86/RegCacheFPU.cpp +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -111,15 +111,10 @@ void FPURegCache::ReduceSpillLockV(const u8 *vec, VectorSize sz) { void FPURegCache::FlushRemap(int oldreg, int newreg) { OpArg oldLocation = regs[oldreg].location; - if (!oldLocation.IsSimpleReg()) { - PanicAlert("FlushRemap: Must already be in an x86 SSE register"); - } - if (regs[oldreg].lane != 0) { - PanicAlert("FlushRemap only supports FPR registers"); - } + _assert_msg_(oldLocation.IsSimpleReg(), "FlushRemap: Must already be in an x86 SSE register"); + _assert_msg_(regs[oldreg].lane == 0, "FlushRemap only supports FPR registers"); X64Reg xr = oldLocation.GetSimpleReg(); - if (oldreg == newreg) { xregs[xr].dirty = true; return; @@ -199,7 +194,7 @@ bool FPURegCache::IsMappedVS(const u8 *v, VectorSize vsz) { void FPURegCache::MapRegsVS(const u8 *r, VectorSize vsz, int flags) { const int n = GetNumVectorElements(vsz); - _dbg_assert_msg_(JIT, jo_->enableVFPUSIMD, "Should not map simd regs when option is off."); + _dbg_assert_msg_(jo_->enableVFPUSIMD, "Should not map simd regs when option is off."); if (!TryMapRegsVS(r, vsz, flags)) { // TODO: Could be more optimal. @@ -207,7 +202,7 @@ void FPURegCache::MapRegsVS(const u8 *r, VectorSize vsz, int flags) { StoreFromRegisterV(r[i]); } if (!TryMapRegsVS(r, vsz, flags)) { - _dbg_assert_msg_(JIT, false, "MapRegsVS() failed on second try."); + _dbg_assert_msg_(false, "MapRegsVS() failed on second try."); } } } @@ -223,8 +218,8 @@ bool FPURegCache::CanMapVS(const u8 *v, VectorSize vsz) { return true; } else if (vregs[v[0]].lane != 0) { const MIPSCachedFPReg &v0 = vregs[v[0]]; - _dbg_assert_msg_(JIT, v0.away, "Must be away when lane != 0"); - _dbg_assert_msg_(JIT, v0.location.IsSimpleReg(), "Must be is register when lane != 0"); + _dbg_assert_msg_(v0.away, "Must be away when lane != 0"); + _dbg_assert_msg_(v0.location.IsSimpleReg(), "Must be is register when lane != 0"); // Already in a different simd set. return false; @@ -245,7 +240,7 @@ bool FPURegCache::CanMapVS(const u8 *v, VectorSize vsz) { if (vregs[v[i]].locked) { return false; } - _assert_msg_(JIT, !vregs[v[i]].location.IsImm(), "Cannot handle imms in fp cache."); + _assert_msg_(!vregs[v[i]].location.IsImm(), "Cannot handle imms in fp cache."); } return true; @@ -331,7 +326,7 @@ X64Reg FPURegCache::LoadRegsVS(const u8 *v, int n) { X64Reg xrs[4] = {INVALID_REG, INVALID_REG, INVALID_REG, INVALID_REG}; bool xrsLoaded[4] = {false, false, false, false}; - _dbg_assert_msg_(JIT, n >= 2 && n <= 4, "LoadRegsVS is only implemented for simd loads."); + _dbg_assert_msg_(n >= 2 && n <= 4, "LoadRegsVS is only implemented for simd loads."); for (int i = 0; i < n; ++i) { const MIPSCachedFPReg &mr = vregs[v[i]]; @@ -345,7 +340,7 @@ X64Reg FPURegCache::LoadRegsVS(const u8 *v, int n) { ++regsLoaded; ++regsAvail; } else if (mr.lane != 0) { - _dbg_assert_msg_(JIT, false, "LoadRegsVS is not able to handle simd remapping yet, store first."); + _dbg_assert_msg_(false, "LoadRegsVS is not able to handle simd remapping yet, store first."); } } } @@ -386,8 +381,8 @@ X64Reg FPURegCache::LoadRegsVS(const u8 *v, int n) { // TODO: Not handling the case of some regs avail and some loaded right now. if (regsAvail < n && (sequential != n || regsLoaded == n || regsAvail == 0)) { regsAvail = GetFreeXRegs(xrs, 2, true); - _dbg_assert_msg_(JIT, regsAvail >= 2, "Ran out of fp regs for loading simd regs with."); - _dbg_assert_msg_(JIT, xrs[0] != xrs[1], "Regs for simd load are the same, bad things await."); + _dbg_assert_msg_(regsAvail >= 2, "Ran out of fp regs for loading simd regs with."); + _dbg_assert_msg_(xrs[0] != xrs[1], "Regs for simd load are the same, bad things await."); // We spilled, so we assume that all our regs are screwed up now anyway. for (int i = 0; i < 4; ++i) { xrsLoaded[i] = false; @@ -448,7 +443,7 @@ X64Reg FPURegCache::LoadRegsVS(const u8 *v, int n) { } res = xrs[0]; } else { - _dbg_assert_msg_(JIT, n > 2, "2 should not be possible here."); + _dbg_assert_msg_(n > 2, "2 should not be possible here."); // Available regs are less than n, and some may be loaded. // Let's grab the most optimal unloaded ones. @@ -513,8 +508,8 @@ bool FPURegCache::TryMapDirtyInVS(const u8 *vd, VectorSize vdsz, const u8 *vs, V ReleaseSpillLockV(vs, vssz); ReleaseSpillLockV(vd, vdsz); - _dbg_assert_msg_(JIT, !success || IsMappedVS(vd, vdsz), "vd should be mapped now"); - _dbg_assert_msg_(JIT, !success || IsMappedVS(vs, vssz), "vs should be mapped now"); + _dbg_assert_msg_(!success || IsMappedVS(vd, vdsz), "vd should be mapped now"); + _dbg_assert_msg_(!success || IsMappedVS(vs, vssz), "vs should be mapped now"); return success; } @@ -538,9 +533,9 @@ bool FPURegCache::TryMapDirtyInInVS(const u8 *vd, VectorSize vdsz, const u8 *vs, ReleaseSpillLockV(vs, vssz); ReleaseSpillLockV(vt, vtsz); - _dbg_assert_msg_(JIT, !success || IsMappedVS(vd, vdsz), "vd should be mapped now"); - _dbg_assert_msg_(JIT, !success || IsMappedVS(vs, vssz), "vs should be mapped now"); - _dbg_assert_msg_(JIT, !success || IsMappedVS(vt, vtsz), "vt should be mapped now"); + _dbg_assert_msg_(!success || IsMappedVS(vd, vdsz), "vd should be mapped now"); + _dbg_assert_msg_(!success || IsMappedVS(vs, vssz), "vs should be mapped now"); + _dbg_assert_msg_(!success || IsMappedVS(vt, vtsz), "vt should be mapped now"); return success; } @@ -585,7 +580,7 @@ void FPURegCache::SimpleRegV(const u8 v, int flags) { if (flags & MAP_DIRTY) { xregs[VX(v)].dirty = true; } - _assert_msg_(JIT, vr.location.IsSimpleReg(), "not loaded and not simple."); + _assert_msg_(vr.location.IsSimpleReg(), "not loaded and not simple."); } Invariant(); } @@ -603,13 +598,13 @@ void FPURegCache::ReleaseSpillLocks() { void FPURegCache::MapReg(const int i, bool doLoad, bool makeDirty) { pendingFlush = true; - _assert_msg_(JIT, !regs[i].location.IsImm(), "WTF - FPURegCache::MapReg - imm"); - _assert_msg_(JIT, i >= 0 && i < NUM_MIPS_FPRS, "WTF - FPURegCache::MapReg - invalid mips reg %d", i); + _assert_msg_(!regs[i].location.IsImm(), "WTF - FPURegCache::MapReg - imm"); + _assert_msg_(i >= 0 && i < NUM_MIPS_FPRS, "WTF - FPURegCache::MapReg - invalid mips reg %d", i); if (!regs[i].away) { // Reg is at home in the memory register file. Let's pull it out. X64Reg xr = GetFreeXReg(); - _assert_msg_(JIT, xr < NUM_X_FPREGS, "WTF - FPURegCache::MapReg - invalid reg %d", (int)xr); + _assert_msg_(xr < NUM_X_FPREGS, "WTF - FPURegCache::MapReg - invalid reg %d", (int)xr); xregs[xr].mipsReg = i; xregs[xr].dirty = makeDirty; OpArg newloc = ::Gen::R(xr); @@ -627,7 +622,7 @@ void FPURegCache::MapReg(const int i, bool doLoad, bool makeDirty) { } else { // There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary. xregs[RX(i)].dirty |= makeDirty; - _assert_msg_(JIT, regs[i].location.IsSimpleReg(), "not loaded and not simple."); + _assert_msg_(regs[i].location.IsSimpleReg(), "not loaded and not simple."); } Invariant(); } @@ -642,18 +637,18 @@ static int MMShuffleSwapTo0(int lane) { } else if (lane == 3) { return _MM_SHUFFLE(0, 2, 1, 3); } else { - PanicAlert("MMShuffleSwapTo0: Invalid lane %d", lane); + _assert_msg_(false, "MMShuffleSwapTo0: Invalid lane %d", lane); return 0; } } void FPURegCache::StoreFromRegister(int i) { - _assert_msg_(JIT, !regs[i].location.IsImm(), "WTF - FPURegCache::StoreFromRegister - it's an imm"); - _assert_msg_(JIT, i >= 0 && i < NUM_MIPS_FPRS, "WTF - FPURegCache::StoreFromRegister - invalid mipsreg %i PC=%08x", i, js_->compilerPC); + _assert_msg_(!regs[i].location.IsImm(), "WTF - FPURegCache::StoreFromRegister - it's an imm"); + _assert_msg_(i >= 0 && i < NUM_MIPS_FPRS, "WTF - FPURegCache::StoreFromRegister - invalid mipsreg %i PC=%08x", i, js_->compilerPC); if (regs[i].away) { X64Reg xr = regs[i].location.GetSimpleReg(); - _assert_msg_(JIT, xr < NUM_X_FPREGS, "WTF - FPURegCache::StoreFromRegister - invalid reg: x %i (mr: %i). PC=%08x", (int)xr, i, js_->compilerPC); + _assert_msg_(xr < NUM_X_FPREGS, "WTF - FPURegCache::StoreFromRegister - invalid reg: x %i (mr: %i). PC=%08x", (int)xr, i, js_->compilerPC); if (regs[i].lane != 0) { const int *mri = xregs[xr].mipsRegs; int seq = 1; @@ -727,16 +722,16 @@ void FPURegCache::StoreFromRegister(int i) { xregs[xr].dirty = false; regs[i].away = false; } else { - // _assert_msg_(DYNA_REC,0,"already stored"); + // _assert_msg_(false,"already stored"); } Invariant(); } void FPURegCache::DiscardR(int i) { - _assert_msg_(JIT, !regs[i].location.IsImm(), "FPU can't handle imm yet."); + _assert_msg_(!regs[i].location.IsImm(), "FPU can't handle imm yet."); if (regs[i].away) { X64Reg xr = regs[i].location.GetSimpleReg(); - _assert_msg_(JIT, xr < NUM_X_FPREGS, "DiscardR: MipsReg had bad X64Reg"); + _assert_msg_(xr < NUM_X_FPREGS, "DiscardR: MipsReg had bad X64Reg"); // Note that we DO NOT write it back here. That's the whole point of Discard. if (regs[i].lane != 0) { // But we can't just discard all of them in SIMD, just the one lane. @@ -769,19 +764,19 @@ void FPURegCache::DiscardR(int i) { regs[i].away = false; regs[i].tempLocked = false; } else { - // _assert_msg_(DYNA_REC,0,"already stored"); + // _assert_msg_(false,"already stored"); regs[i].tempLocked = false; } Invariant(); } void FPURegCache::DiscardVS(int vreg) { - _assert_msg_(JIT, !vregs[vreg].location.IsImm(), "FPU can't handle imm yet."); + _assert_msg_(!vregs[vreg].location.IsImm(), "FPU can't handle imm yet."); if (vregs[vreg].away) { - _assert_msg_(JIT, vregs[vreg].lane != 0, "VS expects a SIMD reg."); + _assert_msg_(vregs[vreg].lane != 0, "VS expects a SIMD reg."); X64Reg xr = vregs[vreg].location.GetSimpleReg(); - _assert_msg_(JIT, xr < NUM_X_FPREGS, "DiscardR: MipsReg had bad X64Reg"); + _assert_msg_(xr < NUM_X_FPREGS, "DiscardR: MipsReg had bad X64Reg"); // Note that we DO NOT write it back here. That's the whole point of Discard. for (int i = 0; i < 4; ++i) { int mr = xregs[xr].mipsRegs[i]; @@ -813,7 +808,7 @@ int FPURegCache::GetTempR() { } } - _assert_msg_(JIT, 0, "Regcache ran out of temp regs, might need to DiscardR() some."); + _assert_msg_(false, "Regcache ran out of temp regs, might need to DiscardR() some."); return -1; } @@ -852,7 +847,7 @@ int FPURegCache::GetTempVS(u8 *v, VectorSize vsz) { } if (found != n) { - _assert_msg_(JIT, 0, "Regcache ran out of temp regs, might need to DiscardR() some."); + _assert_msg_(false, "Regcache ran out of temp regs, might need to DiscardR() some."); return -1; } @@ -868,9 +863,7 @@ void FPURegCache::Flush() { return; } for (int i = 0; i < NUM_MIPS_FPRS; i++) { - if (regs[i].locked) { - PanicAlert("Somebody forgot to unlock MIPS reg %i.", i); - } + _assert_msg_(!regs[i].locked, "Somebody forgot to unlock MIPS reg %d.", i); if (regs[i].away) { if (regs[i].location.IsSimpleReg()) { X64Reg xr = RX(i); @@ -879,7 +872,7 @@ void FPURegCache::Flush() { } else if (regs[i].location.IsImm()) { StoreFromRegister(i); } else { - _assert_msg_(JIT,0,"Jit64 - Flush unhandled case, reg %i PC: %08x", i, mips->pc); + _assert_msg_(false, "Jit64 - Flush unhandled case, reg %i PC: %08x", i, mips->pc); } } } @@ -908,8 +901,8 @@ OpArg FPURegCache::GetDefaultLocation(int reg) const { } void FPURegCache::Invariant() const { -#ifdef _DEBUG - _dbg_assert_msg_(JIT, SanityCheck() == 0, "Sanity check failed: %d", SanityCheck()); +#if 0 + _assert_msg_(SanityCheck() == 0, "Sanity check failed: %d", SanityCheck()); #endif } @@ -1043,7 +1036,7 @@ X64Reg FPURegCache::GetFreeXReg() { X64Reg res; int obtained = GetFreeXRegs(&res, 1); - _assert_msg_(JIT, obtained == 1, "Regcache ran out of regs"); + _assert_msg_(obtained == 1, "Regcache ran out of regs"); return res; } @@ -1052,7 +1045,7 @@ int FPURegCache::GetFreeXRegs(X64Reg *res, int n, bool spill) { int aCount; const int *aOrder = GetAllocationOrder(aCount); - _dbg_assert_msg_(JIT, n <= NUM_X_FPREGS - 2, "Cannot obtain that many regs."); + _dbg_assert_msg_(n <= NUM_X_FPREGS - 2, "Cannot obtain that many regs."); int r = 0; @@ -1072,7 +1065,7 @@ int FPURegCache::GetFreeXRegs(X64Reg *res, int n, bool spill) { for (int i = 0; i < aCount; i++) { X64Reg xr = (X64Reg)aOrder[i]; int preg = xregs[xr].mipsReg; - _assert_msg_(JIT, preg >= -1 && preg < NUM_MIPS_FPRS, "WTF - FPURegCache::GetFreeXRegs - invalid mips reg %d in xr %d", preg, (int)xr); + _assert_msg_(preg >= -1 && preg < NUM_MIPS_FPRS, "WTF - FPURegCache::GetFreeXRegs - invalid mips reg %d in xr %d", preg, (int)xr); // We're only spilling here, so don't overlap. if (preg != -1 && !regs[preg].locked) { @@ -1093,7 +1086,7 @@ int FPURegCache::GetFreeXRegs(X64Reg *res, int n, bool spill) { void FPURegCache::FlushX(X64Reg reg) { if (reg >= NUM_X_FPREGS) { - PanicAlert("Flushing non existent reg"); + _assert_msg_(false, "Flushing non existent reg"); } else if (xregs[reg].mipsReg != -1) { StoreFromRegister(xregs[reg].mipsReg); } diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index dd0916ebc9..3cf33d53b4 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -126,34 +126,34 @@ public: const Gen::OpArg &R(int freg) const {return regs[freg].location;} const Gen::OpArg &V(int vreg) const { - _dbg_assert_msg_(JIT, vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VS instead). pc=%08x", vreg, mips->pc); + _dbg_assert_msg_(vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VS instead). pc=%08x", vreg, mips->pc); return vregs[vreg].location; } const Gen::OpArg &VS(const u8 *vs) const { - _dbg_assert_msg_(JIT, vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use V instead). pc=%08x", vs[0], mips->pc); + _dbg_assert_msg_(vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use V instead). pc=%08x", vs[0], mips->pc); return vregs[vs[0]].location; } Gen::X64Reg RX(int freg) const { if (regs[freg].away && regs[freg].location.IsSimpleReg()) return regs[freg].location.GetSimpleReg(); - PanicAlert("Not so simple - f%i", freg); + _assert_msg_(false, "Not so simple - f%i", freg); return (Gen::X64Reg)-1; } Gen::X64Reg VX(int vreg) const { - _dbg_assert_msg_(JIT, vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VSX instead). pc=%08x", vreg, mips->pc); + _dbg_assert_msg_(vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VSX instead). pc=%08x", vreg, mips->pc); if (vregs[vreg].away && vregs[vreg].location.IsSimpleReg()) return vregs[vreg].location.GetSimpleReg(); - PanicAlert("Not so simple - v%i", vreg); + _assert_msg_(false, "Not so simple - v%i", vreg); return (Gen::X64Reg)-1; } Gen::X64Reg VSX(const u8 *vs) const { - _dbg_assert_msg_(JIT, vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use VX instead). pc=%08x", vs[0], mips->pc); + _dbg_assert_msg_(vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use VX instead). pc=%08x", vs[0], mips->pc); if (vregs[vs[0]].away && vregs[vs[0]].location.IsSimpleReg()) return vregs[vs[0]].location.GetSimpleReg(); - PanicAlert("Not so simple - v%i", vs[0]); + _assert_msg_(false, "Not so simple - v%i", vs[0]); return (Gen::X64Reg)-1; } diff --git a/Core/MemFault.cpp b/Core/MemFault.cpp new file mode 100644 index 0000000000..a550375161 --- /dev/null +++ b/Core/MemFault.cpp @@ -0,0 +1,182 @@ +// Copyright (C) 2020 PPSSPP Project + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "ppsspp_config.h" + +#include "Common/MachineContext.h" + +#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) +#include "Common/x64Analyzer.h" + +#elif PPSSPP_ARCH(ARM64) +#include "Core/Util/DisArm64.h" +#elif PPSSPP_ARCH(ARM) +#include "ext/disarm.h" +#endif + +#include "Common/Log.h" +#include "Core/Core.h" +#include "Core/MemFault.h" +#include "Core/MemMap.h" +#include "Core/MIPS/JitCommon/JitCommon.h" + +namespace Memory { + +static int64_t g_numReportedBadAccesses = 0; + +void MemFault_Init() { + g_numReportedBadAccesses = 0; +} + +#ifdef MACHINE_CONTEXT_SUPPORTED + +static bool DisassembleNativeAt(const uint8_t *codePtr, int instructionSize, std::string *dest) { +#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) + auto lines = DisassembleX86(codePtr, instructionSize); + if (!lines.empty()) { + *dest = lines[0]; + return true; + } +#elif PPSSPP_ARCH(ARM64) + auto lines = DisassembleArm64(codePtr, instructionSize); + if (!lines.empty()) { + *dest = lines[0]; + return true; + } +#elif PPSSPP_ARCH(ARM) + auto lines = DisassembleArm2(codePtr, instructionSize); + if (!lines.empty()) { + *dest = lines[0]; + return true; + } +#endif + return false; +} + +bool HandleFault(uintptr_t hostAddress, void *ctx) { + SContext *context = (SContext *)ctx; + const uint8_t *codePtr = (uint8_t *)(context->CTX_PC); + + // TODO: Check that codePtr is within the current JIT space. + bool inJitSpace = MIPSComp::jit && MIPSComp::jit->CodeInRange(codePtr); + if (!inJitSpace) { + // This is a crash in non-jitted code. Not something we want to handle here, ignore. + return false; + } + + uintptr_t baseAddress = (uintptr_t)base; +#ifdef MASKED_PSP_MEMORY + const uintptr_t addressSpaceSize = 0x40000000ULL; +#else + const uintptr_t addressSpaceSize = 0x100000000ULL; +#endif + + // Check whether hostAddress is within the PSP memory space, which (likely) means it was a guest executable that did the bad access. + if (hostAddress < baseAddress || hostAddress >= baseAddress + addressSpaceSize) { + // Host address outside - this was a different kind of crash. + return false; + } + + // OK, a guest executable did a bad access. Take care of it. + + uint32_t guestAddress = hostAddress - baseAddress; + + // TODO: Share the struct between the various analyzers, that will allow us to share most of + // the implementations here. + bool success = false; + + MemoryExceptionType type = MemoryExceptionType::NONE; + + std::string infoString = ""; + + if (MIPSComp::jit) { + std::string desc; + if (MIPSComp::jit->DescribeCodePtr(codePtr, desc)) { + infoString += desc + "\n"; + } + } + + int instructionSize = 4; +#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) + // X86, X86-64. Variable instruction size so need to analyze the mov instruction in detail. + + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + LSInstructionInfo info{}; + success = X86AnalyzeMOV(codePtr, info); + instructionSize = info.instructionSize; +#elif PPSSPP_ARCH(ARM64) + uint32_t word; + memcpy(&word, codePtr, 4); + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + Arm64LSInstructionInfo info{}; + success = Arm64AnalyzeLoadStore((uint64_t)codePtr, word, &info); +#elif PPSSPP_ARCH(ARM) + uint32_t word; + memcpy(&word, codePtr, 4); + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + ArmLSInstructionInfo info{}; + success = ArmAnalyzeLoadStore((uint32_t)codePtr, word, &info); +#endif + + std::string disassembly; + if (success && DisassembleNativeAt(codePtr, instructionSize, &disassembly)) { + infoString += disassembly + "\n"; + } + + if (success) { + if (info.isMemoryWrite) { + type = MemoryExceptionType::WRITE_WORD; + } else { + type = MemoryExceptionType::READ_WORD; + } + } else { + type = MemoryExceptionType::UNKNOWN; + } + + if (success && g_Config.bIgnoreBadMemAccess) { + if (!info.isMemoryWrite) { + // It was a read. Fill the destination register with 0. + // TODO + } + // Move on to the next instruction. Note that handling bad accesses like this is pretty slow. + context->CTX_PC += info.instructionSize; + g_numReportedBadAccesses++; + if (g_numReportedBadAccesses < 100) { + ERROR_LOG(MEMMAP, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress); + } + } else { + // Either bIgnoreBadMemAccess is off, or we failed recovery analysis. + uint32_t approximatePC = currentMIPS->pc; + Core_MemoryExceptionInfo(guestAddress, approximatePC, type, infoString); + + // Redirect execution to a crash handler that will exit the game immediately. + context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler(); + ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation. Info:\n%s", guestAddress, (void *)hostAddress, infoString.c_str()); + } + return true; +} + +#else + +bool HandleFault(uintptr_t hostAddress, void *ctx) { + ERROR_LOG(MEMMAP, "Exception handling not supported"); + return false; +} + +#endif + +} // namespace Memory diff --git a/Core/MemFault.h b/Core/MemFault.h new file mode 100644 index 0000000000..40472a50da --- /dev/null +++ b/Core/MemFault.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace Memory { + +void MemFault_Init(); + +// Called by exception handlers. We simply filter out accesses to PSP RAM and otherwise +// just leave it as-is. +bool HandleFault(uintptr_t hostAddress, void *context); + +} diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 9c7a2cce19..69c23c85e5 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -27,9 +27,11 @@ #include "Common/Common.h" #include "Common/MemoryUtil.h" #include "Common/MemArena.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/MemMap.h" +#include "Core/MemFault.h" #include "Core/HDRemaster.h" #include "Core/MIPS/MIPS.h" #include "Core/HLE/HLE.h" @@ -41,11 +43,13 @@ #include "Core/ConfigValues.h" #include "Core/HLE/ReplaceTables.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" +#include "Core/MIPS/JitCommon/JitCommon.h" +#include "UI/OnScreenDisplay.h" namespace Memory { // The base pointer to the auto-mirrored arena. -u8* base = NULL; +u8* base = nullptr; // The MemArena class MemArena g_arena; @@ -221,16 +225,22 @@ bool MemoryMap_Setup(u32 flags) { #if !PPSSPP_PLATFORM(ANDROID) if (g_arena.NeedsProbing()) { int base_attempts = 0; -#if defined(_WIN32) && PPSSPP_ARCH(32BIT) +#if PPSSPP_PLATFORM(WINDOWS) && PPSSPP_ARCH(32BIT) // Try a whole range of possible bases. Return once we got a valid one. uintptr_t max_base_addr = 0x7FFF0000 - 0x10000000; uintptr_t min_base_addr = 0x01000000; uintptr_t stride = 0x400000; -#else +#elif PPSSPP_ARCH(ARM64) && PPSSPP_PLATFORM(IOS) // iOS uintptr_t max_base_addr = 0x1FFFF0000ULL - 0x80000000ULL; uintptr_t min_base_addr = 0x100000000ULL; uintptr_t stride = 0x800000; +#else + uintptr_t max_base_addr = 0; + uintptr_t min_base_addr = 0; + uintptr_t stride = 0; + ERROR_LOG(MEMMAP, "MemoryMap_Setup: Hit a wrong path, should not be needed on this platform."); + return false; #endif for (uintptr_t base_addr = min_base_addr; base_addr < max_base_addr; base_addr += stride) { base_attempts++; @@ -241,7 +251,6 @@ bool MemoryMap_Setup(u32 flags) { } } ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); return false; } else @@ -272,11 +281,10 @@ void MemoryMap_Shutdown(u32 flags) { #endif } -void Init() { - // On some 32 bit platforms, you can only map < 32 megs at a time. - // TODO: Wait, wtf? What platforms are those? This seems bad. +bool Init() { + // On some 32 bit platforms (like Android, iOS, etc.), you can only map < 32 megs at a time. const static int MAX_MMAP_SIZE = 31 * 1024 * 1024; - _dbg_assert_msg_(MEMMAP, g_MemorySize < MAX_MMAP_SIZE * 3, "ACK - too much memory for three mmap views."); + _dbg_assert_msg_(g_MemorySize <= MAX_MMAP_SIZE * 3, "ACK - too much memory for three mmap views."); for (size_t i = 0; i < ARRAY_SIZE(views); i++) { if (views[i].flags & MV_IS_PRIMARY_RAM) views[i].size = std::min((int)g_MemorySize, MAX_MMAP_SIZE); @@ -285,15 +293,21 @@ void Init() { if (views[i].flags & MV_IS_EXTRA2_RAM) views[i].size = std::min(std::max((int)g_MemorySize - MAX_MMAP_SIZE * 2, 0), MAX_MMAP_SIZE); } + int flags = 0; - MemoryMap_Setup(flags); + if (!MemoryMap_Setup(flags)) { + return false; + } INFO_LOG(MEMMAP, "Memory system initialized. Base at %p (RAM at @ %p, uncached @ %p)", base, m_pPhysicalRAM, m_pUncachedRAM); + + MemFault_Init(); + return true; } void Reinit() { - _assert_msg_(SYSTEM, PSP_IsInited(), "Cannot reinit during startup/shutdown"); + _assert_msg_(PSP_IsInited(), "Cannot reinit during startup/shutdown"); Core_NotifyLifecycle(CoreLifecycle::MEMORY_REINITING); Shutdown(); Init(); @@ -312,7 +326,7 @@ void DoState(PointerWrap &p) { } else if (s == 2) { // In version 2, we determine memory size based on PSP model. u32 oldMemorySize = g_MemorySize; - p.Do(g_PSPModel); + Do(p, g_PSPModel); p.DoMarker("PSPModel"); if (!g_RemasterMode) { g_MemorySize = g_PSPModel == PSP_MODEL_FAT ? RAM_NORMAL_SIZE : RAM_DOUBLE_SIZE; @@ -324,20 +338,20 @@ void DoState(PointerWrap &p) { // In version 3, we started just saving the memory size directly. // It's no longer based strictly on the PSP model. u32 oldMemorySize = g_MemorySize; - p.Do(g_PSPModel); + Do(p, g_PSPModel); p.DoMarker("PSPModel"); - p.Do(g_MemorySize); + Do(p, g_MemorySize); if (oldMemorySize != g_MemorySize) { Reinit(); } } - p.DoArray(GetPointer(PSP_GetKernelMemoryBase()), g_MemorySize); + DoArray(p, GetPointer(PSP_GetKernelMemoryBase()), g_MemorySize); p.DoMarker("RAM"); - p.DoArray(m_pPhysicalVRAM1, VRAM_SIZE); + DoArray(p, m_pPhysicalVRAM1, VRAM_SIZE); p.DoMarker("VRAM"); - p.DoArray(m_pPhysicalScratchPad, SCRATCHPAD_SIZE); + DoArray(p, m_pPhysicalScratchPad, SCRATCHPAD_SIZE); p.DoMarker("ScratchPad"); } diff --git a/Core/MemMap.h b/Core/MemMap.h index 28c635c181..7383b719ea 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -20,6 +20,7 @@ #include "ppsspp_config.h" #include +#include #ifndef offsetof #include #endif @@ -52,8 +53,7 @@ typedef void (*readFn16)(u16&, const u32); typedef void (*readFn32)(u32&, const u32); typedef void (*readFn64)(u64&, const u32); -namespace Memory -{ +namespace Memory { // Base is a pointer to the base of the memory map. Yes, some MMU tricks // are used to set up a full GC or Wii memory map in process memory. on // 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that @@ -126,7 +126,7 @@ bool MemoryMap_Setup(u32 flags); void MemoryMap_Shutdown(u32 flags); // Init and Shutdown -void Init(); +bool Init(); void Shutdown(); void DoState(PointerWrap &p); void Clear(); @@ -165,16 +165,6 @@ inline u8* GetPointerUnchecked(const u32 address) { #endif } -#ifdef SAFE_MEMORY -u32 ReadUnchecked_U32(const u32 _Address); -// ONLY for use by GUI and fast interpreter -u8 ReadUnchecked_U8(const u32 _Address); -u16 ReadUnchecked_U16(const u32 _Address); -void WriteUnchecked_U8(const u8 _Data, const u32 _Address); -void WriteUnchecked_U16(const u16 _Data, const u32 _Address); -void WriteUnchecked_U32(const u32 _Data, const u32 _Address); -#else - inline u32 ReadUnchecked_U32(const u32 address) { #ifdef MASKED_PSP_MEMORY return *(u32_le *)(base + (address & MEMVIEW32_MASK)); @@ -239,8 +229,6 @@ inline void WriteUnchecked_U8(u8 data, u32 address) { #endif } -#endif - inline float Read_Float(u32 address) { u32 ifloat = Read_U32(address); @@ -267,25 +255,37 @@ inline void Write_Float(float f, u32 address) u8* GetPointer(const u32 address); bool IsRAMAddress(const u32 address); -bool IsVRAMAddress(const u32 address); -bool IsScratchpadAddress(const u32 address); - -inline const char* GetCharPointer(const u32 address) { - return (const char *)GetPointer(address); +inline bool IsVRAMAddress(const u32 address) { + return ((address & 0x3F800000) == 0x04000000); +} +inline bool IsDepthTexVRAMAddress(const u32 address) { + return ((address & 0x3FE00000) == 0x04200000) || ((address & 0x3FE00000) == 0x04600000); +} +inline bool IsKernelAddress(const u32 address) { + return ((address & 0x3F800000) == 0x08000000); } -inline void MemcpyUnchecked(void *to_data, const u32 from_address, const u32 len) -{ +bool IsScratchpadAddress(const u32 address); + +// Used for auto-converted char * parameters, which can sometimes legitimately be null - +// so we don't want to get caught in GetPointer's crash reporting. +inline const char* GetCharPointer(const u32 address) { + if (address) { + return (const char *)GetPointer(address); + } else { + return nullptr; + } +} + +inline void MemcpyUnchecked(void *to_data, const u32 from_address, const u32 len) { memcpy(to_data, GetPointerUnchecked(from_address), len); } -inline void MemcpyUnchecked(const u32 to_address, const void *from_data, const u32 len) -{ +inline void MemcpyUnchecked(const u32 to_address, const void *from_data, const u32 len) { memcpy(GetPointerUnchecked(to_address), from_data, len); } -inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const u32 len) -{ +inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const u32 len) { MemcpyUnchecked(GetPointer(to_address), from_address, len); } @@ -327,7 +327,7 @@ inline bool IsValidRange(const u32 address, const u32 size) { return IsValidAddress(address) && ValidSize(address, size) == size; } -}; +} // namespace Memory template struct PSPPointer @@ -462,44 +462,36 @@ inline u32 PSP_GetKernelMemoryEnd() { return 0x08400000;} // game through sceKernelVolatileMemTryLock. inline u32 PSP_GetUserMemoryBase() { return 0x08800000;} - inline u32 PSP_GetDefaultLoadAddress() { return 0;} -//inline u32 PSP_GetDefaultLoadAddress() { return 0x0898dab0;} inline u32 PSP_GetVidMemBase() { return 0x04000000;} inline u32 PSP_GetVidMemEnd() { return 0x04800000;} template -inline bool operator==(const PSPPointer &lhs, const PSPPointer &rhs) -{ +inline bool operator==(const PSPPointer &lhs, const PSPPointer &rhs) { return lhs.ptr == rhs.ptr; } template -inline bool operator!=(const PSPPointer &lhs, const PSPPointer &rhs) -{ +inline bool operator!=(const PSPPointer &lhs, const PSPPointer &rhs) { return lhs.ptr != rhs.ptr; } template -inline bool operator<(const PSPPointer &lhs, const PSPPointer &rhs) -{ +inline bool operator<(const PSPPointer &lhs, const PSPPointer &rhs) { return lhs.ptr < rhs.ptr; } template -inline bool operator>(const PSPPointer &lhs, const PSPPointer &rhs) -{ +inline bool operator>(const PSPPointer &lhs, const PSPPointer &rhs) { return lhs.ptr > rhs.ptr; } template -inline bool operator<=(const PSPPointer &lhs, const PSPPointer &rhs) -{ +inline bool operator<=(const PSPPointer &lhs, const PSPPointer &rhs) { return lhs.ptr <= rhs.ptr; } template -inline bool operator>=(const PSPPointer &lhs, const PSPPointer &rhs) -{ +inline bool operator>=(const PSPPointer &lhs, const PSPPointer &rhs) { return lhs.ptr >= rhs.ptr; } diff --git a/Core/MemMapFunctions.cpp b/Core/MemMapFunctions.cpp index ac543e36bd..36903cdabb 100644 --- a/Core/MemMapFunctions.cpp +++ b/Core/MemMapFunctions.cpp @@ -26,17 +26,7 @@ #include "Core/MIPS/MIPS.h" -namespace Memory -{ - -// ================================= -// From Memmap.cpp -// ---------------- - -// Read and write shortcuts - -// GetPointer must always return an address in the bottom 32 bits of address space, so that 64-bit -// programs don't have problems directly addressing any part of memory. +namespace Memory { u8 *GetPointer(const u32 address) { if ((address & 0x3E000000) == 0x08000000) { @@ -52,16 +42,12 @@ u8 *GetPointer(const u32 address) { // More RAM (remasters, etc.) return GetPointerUnchecked(address); } else { - ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); static bool reported = false; if (!reported) { Reporting::ReportMessage("Unknown GetPointer %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); reported = true; } - if (!g_Config.bIgnoreBadMemAccess) { - Core_EnableStepping(true); - host->SetDebugMode(true); - } + Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::WRITE_BLOCK); return nullptr; } } @@ -69,10 +55,6 @@ u8 *GetPointer(const u32 address) { template inline void ReadFromHardware(T &var, const u32 address) { // TODO: Figure out the fastest order of tests for both read and write (they are probably different). - // TODO: Make sure this represents the mirrors in a correct way. - - // Could just do a base-relative read, too.... TODO - if ((address & 0x3E000000) == 0x08000000) { // RAM var = *((const T*)GetPointerUnchecked(address)); @@ -86,29 +68,18 @@ inline void ReadFromHardware(T &var, const u32 address) { // More RAM (remasters, etc.) var = *((const T*)GetPointerUnchecked(address)); } else { - // In jit, we only flush PC when bIgnoreBadMemAccess is off. - if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) { - WARN_LOG(MEMMAP, "ReadFromHardware: Invalid address %08x", address); - } else { - WARN_LOG(MEMMAP, "ReadFromHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); - } static bool reported = false; if (!reported) { Reporting::ReportMessage("ReadFromHardware: Invalid address %08x near PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); reported = true; } - if (!g_Config.bIgnoreBadMemAccess) { - Core_EnableStepping(true); - host->SetDebugMode(true); - } + Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::READ_WORD); var = 0; } } template inline void WriteToHardware(u32 address, const T data) { - // Could just do a base-relative write, too.... TODO - if ((address & 0x3E000000) == 0x08000000) { // RAM *(T*)GetPointerUnchecked(address) = data; @@ -122,140 +93,75 @@ inline void WriteToHardware(u32 address, const T data) { // More RAM (remasters, etc.) *(T*)GetPointerUnchecked(address) = data; } else { - // In jit, we only flush PC when bIgnoreBadMemAccess is off. - if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) { - WARN_LOG(MEMMAP, "WriteToHardware: Invalid address %08x", address); - } else { - WARN_LOG(MEMMAP, "WriteToHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); - } static bool reported = false; if (!reported) { Reporting::ReportMessage("WriteToHardware: Invalid address %08x near PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); reported = true; } - if (!g_Config.bIgnoreBadMemAccess) { - Core_EnableStepping(true); - host->SetDebugMode(true); - } + Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::WRITE_WORD); } } -// ===================== - bool IsRAMAddress(const u32 address) { if ((address & 0x3E000000) == 0x08000000) { return true; - } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { + } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { return true; - } else { + } else { return false; } } -bool IsVRAMAddress(const u32 address) { - return ((address & 0x3F800000) == 0x04000000); -} - bool IsScratchpadAddress(const u32 address) { return (address & 0xBFFF0000) == 0x00010000 && (address & 0x0000FFFF) < SCRATCHPAD_SIZE; } -u8 Read_U8(const u32 _Address) -{ - u8 _var = 0; - ReadFromHardware(_var, _Address); - return (u8)_var; +u8 Read_U8(const u32 address) { + u8 value = 0; + ReadFromHardware(value, address); + return (u8)value; } -u16 Read_U16(const u32 _Address) -{ - u16_le _var = 0; - ReadFromHardware(_var, _Address); - return (u16)_var; +u16 Read_U16(const u32 address) { + u16_le value = 0; + ReadFromHardware(value, address); + return (u16)value; } -u32 Read_U32(const u32 _Address) -{ - u32_le _var = 0; - ReadFromHardware(_var, _Address); - return _var; +u32 Read_U32(const u32 address) { + u32_le value = 0; + ReadFromHardware(value, address); + return value; } -u64 Read_U64(const u32 _Address) -{ - u64_le _var = 0; - ReadFromHardware(_var, _Address); - return _var; +u64 Read_U64(const u32 address) { + u64_le value = 0; + ReadFromHardware(value, address); + return value; } -u32 Read_U8_ZX(const u32 _Address) -{ - return (u32)Read_U8(_Address); +u32 Read_U8_ZX(const u32 address) { + return (u32)Read_U8(address); } -u32 Read_U16_ZX(const u32 _Address) -{ - return (u32)Read_U16(_Address); +u32 Read_U16_ZX(const u32 address) { + return (u32)Read_U16(address); } -void Write_U8(const u8 _Data, const u32 _Address) -{ - WriteToHardware(_Address, _Data); +void Write_U8(const u8 _Data, const u32 address) { + WriteToHardware(address, _Data); } -void Write_U16(const u16 _Data, const u32 _Address) -{ - WriteToHardware(_Address, _Data); +void Write_U16(const u16 _Data, const u32 address) { + WriteToHardware(address, _Data); } -void Write_U32(const u32 _Data, const u32 _Address) -{ - WriteToHardware(_Address, _Data); +void Write_U32(const u32 _Data, const u32 address) { + WriteToHardware(address, _Data); } -void Write_U64(const u64 _Data, const u32 _Address) -{ - WriteToHardware(_Address, _Data); +void Write_U64(const u64 _Data, const u32 address) { + WriteToHardware(address, _Data); } -#ifdef SAFE_MEMORY - -u8 ReadUnchecked_U8(const u32 _Address) -{ - u8 _var = 0; - ReadFromHardware(_var, _Address); - return _var; -} - -u16 ReadUnchecked_U16(const u32 _Address) -{ - u16_le _var = 0; - ReadFromHardware(_var, _Address); - return _var; -} - -u32 ReadUnchecked_U32(const u32 _Address) -{ - u32_le _var = 0; - ReadFromHardware(_var, _Address); - return _var; -} - -void WriteUnchecked_U8(const u8 _iValue, const u32 _Address) -{ - WriteToHardware(_Address, _iValue); -} - -void WriteUnchecked_U16(const u16 _iValue, const u32 _Address) -{ - WriteToHardware(_Address, _iValue); -} - -void WriteUnchecked_U32(const u32 _iValue, const u32 _Address) -{ - WriteToHardware(_Address, _iValue); -} - -#endif - } // namespace Memory diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index d72c648601..51a8758843 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -17,11 +17,10 @@ #include -#include "file/file_util.h" -#include "util/text/utf8.h" -#include "thread/threadutil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Thread/ThreadUtil.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" #include "Common/StringUtils.h" #ifdef _WIN32 #include "Common/CommonWindows.h" @@ -203,7 +202,7 @@ static const char *altBootNames[] = { "disc0:/PSP_GAME/SYSDIR/EBOOT.LLD", //"disc0:/PSP_GAME/SYSDIR/OLD_EBOOT.BIN", //Utawareru Mono Chinese version "disc0:/PSP_GAME/SYSDIR/EBOOT.123", - "disc0:/PSP_GAME/SYSDIR/EBOOT_LRC_CH.BIN", + //"disc0:/PSP_GAME/SYSDIR/EBOOT_LRC_CH.BIN", // Hatsune Miku Project Diva Extend chinese version "disc0:/PSP_GAME/SYSDIR/BOOT0.OLD", "disc0:/PSP_GAME/SYSDIR/BOOT1.OLD", "disc0:/PSP_GAME/SYSDIR/BINOT.BIN", @@ -212,7 +211,7 @@ static const char *altBootNames[] = { "disc0:/PSP_GAME/SYSDIR/EBOOT.LEI", "disc0:/PSP_GAME/SYSDIR/EBOOT.DNR", "disc0:/PSP_GAME/SYSDIR/DBZ2.BIN", - "disc0:/PSP_GAME/SYSDIR/ss.RAW", + //"disc0:/PSP_GAME/SYSDIR/ss.RAW",//Code Geass: Lost Colors chinese version }; bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) { @@ -278,7 +277,7 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) { } else { *error_string = "A PSP game couldn't be found on the disc."; } - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; return false; } @@ -303,7 +302,7 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) { if (success && coreState == CORE_POWERUP) { coreState = PSP_CoreParameter().startBreak ? CORE_STEPPING : CORE_RUNNING; } else { - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; // TODO: This is a crummy way to communicate the error... PSP_CoreParameter().fileToStart = ""; } @@ -340,10 +339,11 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { auto bd = constructBlockDevice(PSP_CoreParameter().mountIsoLoader); if (bd != NULL) { ISOFileSystem *umd2 = new ISOFileSystem(&pspFileSystem, bd); + ISOBlockSystem *blockSystem = new ISOBlockSystem(umd2); - pspFileSystem.Mount("umd1:", umd2); + pspFileSystem.Mount("umd1:", blockSystem); pspFileSystem.Mount("disc0:", umd2); - pspFileSystem.Mount("umd:", umd2); + pspFileSystem.Mount("umd:", blockSystem); } } @@ -374,7 +374,7 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { // If root is not a subpath of path, we can't boot the game. if (!startsWith(pathNorm, rootNorm)) { *error_string = "Cannot boot ELF located outside mountRoot."; - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; return false; } @@ -386,7 +386,7 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { pspFileSystem.SetStartingDirectory(ms_path); } - DirectoryFileSystem *fs = new DirectoryFileSystem(&pspFileSystem, path); + DirectoryFileSystem *fs = new DirectoryFileSystem(&pspFileSystem, path, FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD); pspFileSystem.Mount("umd0:", fs); std::string finalName = ms_path + file + extension; @@ -433,7 +433,7 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { if (success && coreState == CORE_POWERUP) { coreState = PSP_CoreParameter().startBreak ? CORE_STEPPING : CORE_RUNNING; } else { - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; // TODO: This is a crummy way to communicate the error... PSP_CoreParameter().fileToStart = ""; } @@ -457,7 +457,7 @@ bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) { if (success && coreState == CORE_POWERUP) { coreState = PSP_CoreParameter().startBreak ? CORE_STEPPING : CORE_RUNNING; } else { - coreState = CORE_ERROR; + coreState = CORE_BOOT_ERROR; // TODO: This is a crummy way to communicate the error... PSP_CoreParameter().fileToStart = ""; } diff --git a/Core/Replay.cpp b/Core/Replay.cpp index 0e76c2c481..fb03eeea4a 100644 --- a/Core/Replay.cpp +++ b/Core/Replay.cpp @@ -18,8 +18,10 @@ #include #include #include + #include "Common/Common.h" -#include "Common/FileUtil.h" +#include "Common/Log.h" +#include "Common/File/FileUtil.h" #include "Common/StringUtils.h" #include "Core/Replay.h" #include "Core/FileSystems/FileSystem.h" diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 388086ad76..be0248dff7 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -19,10 +19,16 @@ #include #include #include +#include +#include +#include #include "Core/Reporting.h" - +#include "Common/File/VFS/VFS.h" #include "Common/CPUDetect.h" +#include "Common/File/FileUtil.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/StringUtils.h" #include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/Config.h" @@ -32,23 +38,16 @@ #include "Core/System.h" #include "Core/FileSystems/BlockDevices.h" #include "Core/FileSystems/MetaFileSystem.h" +#include "Core/HLE/Plugins.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceKernelMemory.h" #include "Core/ELF/ParamSFO.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" -#include "net/http_client.h" -#include "net/resolve.h" -#include "net/url.h" - -#include "base/stringutil.h" -#include "base/buffer.h" -#include "thread/threadutil.h" -#include "file/zip_read.h" - -#include -#include -#include +#include "Common/Net/HTTPClient.h" +#include "Common/Net/Resolve.h" +#include "Common/Net/URL.h" +#include "Common/Thread/ThreadUtil.h" namespace Reporting { @@ -61,7 +60,7 @@ namespace Reporting // Temporarily stores a reference to the hostname. static std::string lastHostname; // Keeps track of report-only-once identifiers. Since they're always constants, a pointer is okay. - static std::set logOnceUsed; + static std::map logOnceUsed; // Keeps track of whether a harmful setting was ever used. static bool everUnsupported = false; // Support is cached here to avoid checking it on every single request. @@ -335,7 +334,7 @@ namespace Reporting return; } - p.Do(everUnsupported); + Do(p, everUnsupported); } void UpdateConfig() @@ -345,10 +344,21 @@ namespace Reporting everUnsupported = true; } - bool ShouldLogOnce(const char *identifier) + bool ShouldLogNTimes(const char *identifier, int count) { // True if it wasn't there already -> so yes, log. - return logOnceUsed.insert(identifier).second; + auto iter = logOnceUsed.find(identifier); + if (iter == logOnceUsed.end()) { + logOnceUsed.insert(std::pair(identifier, 1)); + return true; + } else { + if (iter->second >= count) { + return false; + } else { + iter->second++; + return true; + } + } } std::string CurrentGameID() @@ -484,7 +494,7 @@ namespace Reporting bool IsSupported() { // Disabled when using certain hacks, because they make for poor reports. - if (CheatsInEffect()) + if (CheatsInEffect() || HLEPlugins::HasEnabled()) return false; if (g_Config.iLockedCPUSpeed != 0) return false; diff --git a/Core/Reporting.h b/Core/Reporting.h index c34f815119..1d168cb88c 100644 --- a/Core/Reporting.h +++ b/Core/Reporting.h @@ -17,27 +17,33 @@ #pragma once -#include "Common/CommonTypes.h" -#include "Common/Log.h" #include #include +#include "Common/CommonTypes.h" +#include "Common/Log.h" + #define DEBUG_LOG_REPORT(t,...) do { DEBUG_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false) #define ERROR_LOG_REPORT(t,...) do { ERROR_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false) #define WARN_LOG_REPORT(t,...) do { WARN_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false) #define NOTICE_LOG_REPORT(t,...) do { NOTICE_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false) #define INFO_LOG_REPORT(t,...) do { INFO_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false) -#define DEBUG_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { DEBUG_LOG_REPORT(t, __VA_ARGS__); } } while (false) -#define ERROR_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { ERROR_LOG_REPORT(t, __VA_ARGS__); } } while (false) -#define WARN_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { WARN_LOG_REPORT(t, __VA_ARGS__); } } while (false) -#define NOTICE_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { NOTICE_LOG_REPORT(t, __VA_ARGS__); } } while (false) -#define INFO_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { INFO_LOG_REPORT(t, __VA_ARGS__); } } while (false) +#define DEBUG_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { DEBUG_LOG_REPORT(t, __VA_ARGS__); } } while (false) +#define ERROR_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { ERROR_LOG_REPORT(t, __VA_ARGS__); } } while (false) +#define WARN_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { WARN_LOG_REPORT(t, __VA_ARGS__); } } while (false) +#define NOTICE_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { NOTICE_LOG_REPORT(t, __VA_ARGS__); } } while (false) +#define INFO_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { INFO_LOG_REPORT(t, __VA_ARGS__); } } while (false) -#define ERROR_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { ERROR_LOG(t, __VA_ARGS__); } } while (false) -#define WARN_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { WARN_LOG(t, __VA_ARGS__); } } while (false) -#define NOTICE_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { NOTICE_LOG(t, __VA_ARGS__); } } while (false) -#define INFO_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogOnce(#n)) { INFO_LOG(t, __VA_ARGS__); } } while (false) +#define ERROR_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { ERROR_LOG(t, __VA_ARGS__); } } while (false) +#define WARN_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { WARN_LOG(t, __VA_ARGS__); } } while (false) +#define NOTICE_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { NOTICE_LOG(t, __VA_ARGS__); } } while (false) +#define INFO_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { INFO_LOG(t, __VA_ARGS__); } } while (false) + +#define ERROR_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { ERROR_LOG(t, __VA_ARGS__); } } while (false) +#define WARN_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { WARN_LOG(t, __VA_ARGS__); } } while (false) +#define NOTICE_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { NOTICE_LOG(t, __VA_ARGS__); } } while (false) +#define INFO_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { INFO_LOG(t, __VA_ARGS__); } } while (false) class PointerWrap; @@ -79,7 +85,7 @@ namespace Reporting std::vector CompatibilitySuggestions(); // Returns true if that identifier has not been logged yet. - bool ShouldLogOnce(const char *identifier); + bool ShouldLogNTimes(const char *identifier, int n); enum class ReportStatus { WORKING, diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 92fad1e07a..6be7191e37 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -20,13 +20,15 @@ #include #include -#include "base/timeutil.h" -#include "i18n/i18n.h" -#include "thread/threadutil.h" -#include "util/text/parsers.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Text/Parsers.h" -#include "Common/FileUtil.h" -#include "Common/ChunkFile.h" +#include "Common/File/FileUtil.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/StringUtils.h" +#include "Common/TimeUtil.h" #include "Core/SaveState.h" #include "Core/Config.h" @@ -41,6 +43,7 @@ #include "Core/HLE/sceDisplay.h" #include "Core/HLE/ReplaceTables.h" #include "Core/HLE/sceKernel.h" +#include "Core/HLE/sceUtility.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" @@ -92,9 +95,9 @@ namespace SaveState return CChunkFileReader::SavePtr(&data[0], state); } - CChunkFileReader::Error LoadFromRam(std::vector &data) { + CChunkFileReader::Error LoadFromRam(std::vector &data, std::string *errorString) { SaveStart state; - return CChunkFileReader::LoadPtr(&data[0], state); + return CChunkFileReader::LoadPtr(&data[0], state, errorString); } struct StateRingbuffer @@ -136,7 +139,7 @@ namespace SaveState return err; } - CChunkFileReader::Error Restore() + CChunkFileReader::Error Restore(std::string *errorString) { std::lock_guard guard(lock_); @@ -150,7 +153,7 @@ namespace SaveState static std::vector buffer; LockedDecompress(buffer, states_[n], bases_[baseMapping_[n]]); - return LoadFromRam(buffer); + return LoadFromRam(buffer, errorString); } void ScheduleCompress(std::vector *result, const std::vector *state, const std::vector *base) @@ -262,7 +265,7 @@ namespace SaveState static StateRingbuffer rewindStates(REWIND_NUM_STATES); // TODO: Any reason for this to be configurable? const static float rewindMaxWallFrequency = 1.0f; - static float rewindLastTime = 0.0f; + static double rewindLastTime = 0.0f; const int StateRingbuffer::BLOCK_SIZE = 8192; const int StateRingbuffer::BASE_USAGE_INTERVAL = 15; @@ -275,11 +278,11 @@ namespace SaveState if (s >= 2) { // This only increments on save, of course. ++saveStateGeneration; - p.Do(saveStateGeneration); + Do(p, saveStateGeneration); // This saves the first git version to create this save state (or generation of save states.) if (saveStateInitialGitVersion.empty()) saveStateInitialGitVersion = PPSSPP_GIT_VERSION; - p.Do(saveStateInitialGitVersion); + Do(p, saveStateInitialGitVersion); } else { saveStateGeneration = 1; } @@ -617,7 +620,19 @@ namespace SaveState if (File::GetModifTime(fn, time)) { char buf[256]; // TODO: Use local time format? Americans and some others might not like ISO standard :) - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time); + switch (g_Config.iDateFormat) { + case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD: + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time); + break; + case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY: + strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &time); + break; + case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY: + strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", &time); + break; + default: // Should never happen + return ""; + } return std::string(buf); } } @@ -633,13 +648,14 @@ namespace SaveState return copy; } - bool HandleFailure() + bool HandleLoadFailure() { // Okay, first, let's give the rewind state a shot - maybe we can at least not reset entirely. // Even if this was a rewind, maybe we can still load a previous one. CChunkFileReader::Error result; do { - result = rewindStates.Restore(); + std::string errorString; + result = rewindStates.Restore(&errorString); } while (result == CChunkFileReader::ERROR_BROKEN_STATE); if (result == CChunkFileReader::ERROR_NONE) { @@ -668,12 +684,12 @@ namespace SaveState return; // For fast-forwarding, otherwise they may be useless and too close. - time_update(); - float diff = time_now() - rewindLastTime; + double now = time_now_d(); + float diff = now - rewindLastTime; if (diff < rewindMaxWallFrequency) return; - rewindLastTime = time_now(); + rewindLastTime = now; DEBUG_LOG(BOOT, "saving rewind state"); rewindStates.Save(); } @@ -729,7 +745,6 @@ namespace SaveState Status callbackResult; bool tempResult; std::string callbackMessage; - std::string reason; std::string title; auto sc = GetI18NCategory("Screen"); @@ -741,13 +756,14 @@ namespace SaveState i18nSaveFailure = sc->T("Failed to save state"); std::string slot_prefix = op.slot >= 0 ? StringFromFormat("(%d) ", op.slot + 1) : ""; + std::string errorString; switch (op.type) { case SAVESTATE_LOAD: - INFO_LOG(SAVESTATE, "Loading state from %s", op.filename.c_str()); + INFO_LOG(SAVESTATE, "Loading state from '%s'", op.filename.c_str()); // Use the state's latest version as a guess for saveStateInitialGitVersion. - result = CChunkFileReader::Load(op.filename, &saveStateInitialGitVersion, state, &reason); + result = CChunkFileReader::Load(op.filename, &saveStateInitialGitVersion, state, &errorString); if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = slot_prefix + sc->T("Loaded State"); callbackResult = Status::SUCCESS; @@ -778,12 +794,12 @@ namespace SaveState } #endif } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { - HandleFailure(); - callbackMessage = i18nLoadFailure; - ERROR_LOG(SAVESTATE, "Load state failure: %s", reason.c_str()); + HandleLoadFailure(); + callbackMessage = std::string(i18nLoadFailure) + ": " + errorString; + ERROR_LOG(SAVESTATE, "Load state failure: %s", errorString.c_str()); callbackResult = Status::FAILURE; } else { - callbackMessage = sc->T(reason.c_str(), i18nLoadFailure); + callbackMessage = sc->T(errorString.c_str(), i18nLoadFailure); callbackResult = Status::FAILURE; } break; @@ -813,9 +829,9 @@ namespace SaveState } #endif } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { - HandleFailure(); + // TODO: What else might we want to do here? This should be very unusual. callbackMessage = i18nSaveFailure; - ERROR_LOG(SAVESTATE, "Save state failure: %s", reason.c_str()); + ERROR_LOG(SAVESTATE, "Save state failure"); callbackResult = Status::FAILURE; } else { callbackMessage = i18nSaveFailure; @@ -835,24 +851,24 @@ namespace SaveState case SAVESTATE_REWIND: INFO_LOG(SAVESTATE, "Rewinding to recent savestate snapshot"); - result = rewindStates.Restore(); + result = rewindStates.Restore(&errorString); if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = sc->T("Loaded State"); callbackResult = Status::SUCCESS; hasLoadedState = true; } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { // Cripes. Good news is, we might have more. Let's try those too, better than a reset. - if (HandleFailure()) { + if (HandleLoadFailure()) { // Well, we did rewind, even if too much... callbackMessage = sc->T("Loaded State"); callbackResult = Status::SUCCESS; hasLoadedState = true; } else { - callbackMessage = i18nLoadFailure; + callbackMessage = std::string(i18nLoadFailure) + ": " + errorString; callbackResult = Status::FAILURE; } } else { - callbackMessage = i18nLoadFailure; + callbackMessage = std::string(i18nLoadFailure) + ": " + errorString; callbackResult = Status::FAILURE; } break; diff --git a/Core/SaveState.h b/Core/SaveState.h index 8a205ee579..f2c1a3a426 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -19,7 +19,7 @@ #include #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" namespace SaveState { @@ -69,7 +69,7 @@ namespace SaveState void Save(const std::string &filename, int slot, Callback callback = Callback(), void *cbUserData = 0); CChunkFileReader::Error SaveToRam(std::vector &state); - CChunkFileReader::Error LoadFromRam(std::vector &state); + CChunkFileReader::Error LoadFromRam(std::vector &state, std::string *errorString); // For testing / automated tests. Runs a save state verification pass (async.) // Warning: callback will be called on a different thread. diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp index a90f3c542b..0e4066bdbf 100644 --- a/Core/Screenshot.cpp +++ b/Core/Screenshot.cpp @@ -26,7 +26,8 @@ #endif #include "Common/ColorConv.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/Log.h" #include "Core/Config.h" #include "Core/Screenshot.h" #include "Core/Core.h" @@ -71,13 +72,12 @@ private: static bool WriteScreenshotToJPEG(const char *filename, int width, int height, int num_channels, const uint8_t *image_data, const jpge::params &comp_params) { JPEGFileStream dst_stream(filename); if (!dst_stream.Valid()) { - ERROR_LOG(SYSTEM, "Unable to open screenshot file for writing."); + ERROR_LOG(IO, "Unable to open screenshot file for writing."); return false; } jpge::jpeg_encoder dst_image; if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params)) { - ERROR_LOG(SYSTEM, "Screenshot JPEG encode init failed."); return false; } @@ -85,12 +85,10 @@ static bool WriteScreenshotToJPEG(const char *filename, int width, int height, i for (int i = 0; i < height; i++) { const uint8_t *buf = image_data + i * width * num_channels; if (!dst_image.process_scanline(buf)) { - ERROR_LOG(SYSTEM, "Screenshot JPEG encode scanline failed."); return false; } } if (!dst_image.process_scanline(NULL)) { - ERROR_LOG(SYSTEM, "Screenshot JPEG encode scanline flush failed."); return false; } } @@ -106,18 +104,15 @@ static bool WriteScreenshotToJPEG(const char *filename, int width, int height, i static bool WriteScreenshotToPNG(png_imagep image, const char *filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { FILE *fp = File::OpenCFile(filename, "wb"); if (!fp) { - ERROR_LOG(SYSTEM, "Unable to open screenshot file for writing."); + ERROR_LOG(IO, "Unable to open screenshot file for writing."); return false; } if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, row_stride, colormap)) { - if (fclose(fp) != 0) { - ERROR_LOG(SYSTEM, "Screenshot file write failed."); - return false; - } + fclose(fp); return true; } else { - ERROR_LOG(SYSTEM, "Screenshot PNG encode failed."); + ERROR_LOG(IO, "Screenshot PNG encode failed."); fclose(fp); remove(filename); return false; @@ -229,7 +224,7 @@ static bool ConvertPixelTo8888RGBA(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b a = (src >> 8) & 0xFF; break; default: - _assert_msg_(SYSTEM, false, "Unsupported framebuffer format for screenshot: %d", fmt); + _assert_msg_(false, "Unsupported framebuffer format for screenshot: %d", fmt); return false; } @@ -347,7 +342,7 @@ bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotTy delete [] flipbuffer; if (!success) { - ERROR_LOG(SYSTEM, "Failed to write screenshot."); + ERROR_LOG(IO, "Failed to write screenshot."); } return success; } @@ -368,7 +363,7 @@ bool Save888RGBScreenshot(const char *filename, ScreenshotFormat fmt, const u8 * png_image_free(&png); if (png.warning_or_error >= 2) { - ERROR_LOG(SYSTEM, "Saving screenshot to PNG produced errors."); + ERROR_LOG(IO, "Saving screenshot to PNG produced errors."); success = false; } return success; @@ -397,7 +392,7 @@ bool Save8888RGBAScreenshot(const char *filename, const u8 *buffer, int w, int h png_image_free(&png); if (png.warning_or_error >= 2) { - ERROR_LOG(SYSTEM, "Saving screenshot to PNG produced errors."); + ERROR_LOG(IO, "Saving screenshot to PNG produced errors."); success = false; } return success; diff --git a/Core/System.cpp b/Core/System.cpp index eff04fbead..736499a7f4 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -32,14 +32,15 @@ #include #include -#include "base/timeutil.h" -#include "base/NativeApp.h" -#include "math/math_util.h" -#include "thread/threadutil.h" -#include "util/text/utf8.h" +#include "Common/System/System.h" +#include "Common/Math/math_util.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/File/FileUtil.h" +#include "Common/TimeUtil.h" #include "Common/GraphicsContext.h" -#include "Core/MemMap.h" +#include "Core/MemFault.h" #include "Core/HDRemaster.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSAnalyst.h" @@ -47,6 +48,7 @@ #include "Core/Host.h" #include "Core/System.h" #include "Core/HLE/HLE.h" +#include "Core/HLE/Plugins.h" #include "Core/HLE/ReplaceTables.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelMemory.h" @@ -62,10 +64,12 @@ #include "Core/ELF/ParamSFO.h" #include "Core/SaveState.h" #include "Common/LogManager.h" +#include "Common/ExceptionHandlerSetup.h" #include "Core/HLE/sceAudiocodec.h" #include "GPU/GPUState.h" #include "GPU/GPUInterface.h" +#include "GPU/Debugger/RecordFormat.h" enum CPUThreadState { CPU_THREAD_NOT_RUNNING, @@ -97,13 +101,19 @@ bool coreCollectDebugStatsForced = false; // This can be read and written from ANYWHERE. volatile CoreState coreState = CORE_STEPPING; -// Note: intentionally not used for CORE_NEXTFRAME. +// If true, core state has been changed, but JIT has probably not noticed yet. volatile bool coreStatePending = false; + static volatile CPUThreadState cpuThreadState = CPU_THREAD_NOT_RUNNING; static GPUBackend gpuBackend; static std::string gpuBackendDevice; +// Ugly! +static volatile bool pspIsInited = false; +static volatile bool pspIsIniting = false; +static volatile bool pspIsQuitting = false; + void ResetUIState() { globalUIState = UISTATE_MENU; } @@ -177,7 +187,34 @@ bool CPU_HasPendingAction() { void CPU_Shutdown(); -void CPU_Init() { +bool DiscIDFromGEDumpPath(const std::string &path, FileLoader *fileLoader, std::string *id) { + using namespace GPURecord; + + // For newer files, it's stored in the dump. + Header header; + if (fileLoader->ReadAt(0, sizeof(header), &header) == sizeof(header)) { + const bool magicMatch = memcmp(header.magic, HEADER_MAGIC, sizeof(header.magic)) == 0; + if (magicMatch && header.version <= VERSION && header.version >= 4) { + size_t gameIDLength = strnlen(header.gameID, sizeof(header.gameID)); + if (gameIDLength != 0) { + *id = std::string(header.gameID, gameIDLength); + return true; + } + } + } + + // Fall back to using the filename. + std::string filename = File::GetFilename(path); + // Could be more discerning, but hey.. + if (filename.size() > 10 && filename[0] == 'U' && filename[9] == '_') { + *id = filename.substr(0, 9); + return true; + } else { + return false; + } +} + +bool CPU_Init() { coreState = CORE_POWERUP; currentMIPS = &mipsr4k; @@ -208,35 +245,53 @@ void CPU_Init() { MIPSAnalyst::Reset(); Replacement_Init(); + std::string discID; + switch (type) { case IdentifiedFileType::PSP_ISO: case IdentifiedFileType::PSP_ISO_NP: case IdentifiedFileType::PSP_DISC_DIRECTORY: InitMemoryForGameISO(loadedFile); + discID = g_paramSFO.GetDiscID(); break; case IdentifiedFileType::PSP_PBP: case IdentifiedFileType::PSP_PBP_DIRECTORY: // This is normal for homebrew. // ERROR_LOG(LOADER, "PBP directory resolution failed."); InitMemoryForGamePBP(loadedFile); + discID = g_paramSFO.GetDiscID(); break; case IdentifiedFileType::PSP_ELF: if (Memory::g_PSPModel != PSP_MODEL_FAT) { INFO_LOG(LOADER, "ELF, using full PSP-2000 memory access"); Memory::g_MemorySize = Memory::RAM_DOUBLE_SIZE; } + discID = g_paramSFO.GetDiscID(); + break; + case IdentifiedFileType::PPSSPP_GE_DUMP: + // Try to grab the disc ID from the filename, since unfortunately, we don't store + // it in the GE dump. This should probably be fixed, but as long as you don't rename the dumps, + // this will do the trick. + if (!DiscIDFromGEDumpPath(filename, loadedFile, &discID)) { + // Failed? Let the param SFO autogen a fake disc ID. + discID = g_paramSFO.GetDiscID(); + } break; default: + discID = g_paramSFO.GetDiscID(); break; } // Here we have read the PARAM.SFO, let's see if we need any compatibility overrides. // Homebrew usually has an empty discID, and even if they do have a disc id, it's not // likely to collide with any commercial ones. - std::string discID = g_paramSFO.GetDiscID(); coreParameter.compat.Load(discID); - Memory::Init(); + HLEPlugins::Init(); + if (!Memory::Init()) { + // We're screwed. + return false; + } mipsr4k.Reset(); host->AttemptLoadSymbolMap(); @@ -257,13 +312,15 @@ void CPU_Init() { if (!LoadFile(&loadedFile, &coreParameter.errorString)) { CPU_Shutdown(); coreParameter.fileToStart = ""; - return; + return false; } - if (coreParameter.updateRecent) { g_Config.AddRecent(filename); } + + InstallExceptionHandler(&Memory::HandleFault); + return true; } PSP_LoadingLock::PSP_LoadingLock() { @@ -275,6 +332,8 @@ PSP_LoadingLock::~PSP_LoadingLock() { } void CPU_Shutdown() { + UninstallExceptionHandler(); + // Since we load on a background thread, wait for startup to complete. PSP_LoadingLock lock; PSPLoaders_Shutdown(); @@ -294,6 +353,7 @@ void CPU_Shutdown() { pspFileSystem.Shutdown(); mipsr4k.Shutdown(); Memory::Shutdown(); + HLEPlugins::Shutdown(); delete loadedFile; loadedFile = nullptr; @@ -328,11 +388,6 @@ void Core_UpdateDebugStats(bool collectStats) { gpuStats.ResetFrame(); } -// Ugly! -static bool pspIsInited = false; -static bool pspIsIniting = false; -static bool pspIsQuitting = false; - bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { if (pspIsIniting || pspIsQuitting) { return false; @@ -356,7 +411,10 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { pspIsIniting = true; PSP_SetLoading("Loading game..."); - CPU_Init(); + if (!CPU_Init()) { + *error_string = "Failed initializing CPU/Memory"; + return false; + } // Compat flags get loaded in CPU_Init (which is a bit of a misnomer) so we check for SW renderer here. if (g_Config.bSoftwareRendering || PSP_CoreParameter().compat.flags().ForceSoftwareRenderer) { @@ -433,7 +491,7 @@ void PSP_Shutdown() { // Make sure things know right away that PSP memory, etc. is going away. pspIsQuitting = true; if (coreState == CORE_RUNNING) - Core_UpdateState(CORE_ERROR); + Core_UpdateState(CORE_POWERDOWN); #ifndef MOBILE_DEVICE if (g_Config.bFuncHashMap) { @@ -486,7 +544,7 @@ void PSP_RunLoopWhileState() { void PSP_RunLoopUntil(u64 globalticks) { SaveState::Process(); - if (coreState == CORE_POWERDOWN || coreState == CORE_ERROR) { + if (coreState == CORE_POWERDOWN || coreState == CORE_BOOT_ERROR || coreState == CORE_RUNTIME_ERROR) { return; } else if (coreState == CORE_STEPPING) { Core_ProcessStepping(); @@ -537,6 +595,8 @@ std::string GetSysDirectory(PSPDirectories directoryType) { return g_Config.memStickDirectory + "PSP/SYSTEM/CACHE/"; case DIRECTORY_TEXTURES: return g_Config.memStickDirectory + "PSP/TEXTURES/"; + case DIRECTORY_PLUGINS: + return g_Config.memStickDirectory + "PSP/PLUGINS/"; case DIRECTORY_APP_CACHE: if (!g_Config.appCacheDirectory.empty()) { return g_Config.appCacheDirectory; diff --git a/Core/System.h b/Core/System.h index 43be1e55eb..fac6b16767 100644 --- a/Core/System.h +++ b/Core/System.h @@ -46,6 +46,7 @@ enum PSPDirectories { DIRECTORY_SAVESTATE, DIRECTORY_CACHE, DIRECTORY_TEXTURES, + DIRECTORY_PLUGINS, DIRECTORY_APP_CACHE, // Use the OS app cache if available DIRECTORY_VIDEO, DIRECTORY_AUDIO @@ -101,12 +102,20 @@ void InitSysDirectories(); // RUNNING must be at 0, NEXTFRAME must be at 1. enum CoreState { + // Emulation is running normally. CORE_RUNNING = 0, + // Emulation was running normally, just reached the end of a frame. CORE_NEXTFRAME = 1, - CORE_STEPPING, + // Emulation is paused, CPU thread is sleeping. + CORE_STEPPING, // Can be used for recoverable runtime errors (ignored memory exceptions) + // Core is being powered up. CORE_POWERUP, + // Core is being powered down. CORE_POWERDOWN, - CORE_ERROR, + // An error happened at boot. + CORE_BOOT_ERROR, + // Unrecoverable runtime error. Recoverable errors should use CORE_STEPPING. + CORE_RUNTIME_ERROR, }; extern bool coreCollectDebugStats; diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index 4b10586b07..3b9aeb99e4 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -15,18 +15,18 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#ifdef USING_QT_UI -#include -#else #include -#endif #include -#include "i18n/i18n.h" + #include "ext/xxhash.h" -#include "file/ini_file.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Format/IniFile.h" +#include "Common/Data/Text/Parsers.h" #include "Common/ColorConv.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Host.h" #include "Core/System.h" @@ -222,7 +222,7 @@ void TextureReplacer::ParseHashRange(const std::string &key, const std::string & } u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV) { - _dbg_assert_msg_(G3D, enabled_, "Replacement not enabled"); + _dbg_assert_msg_(enabled_, "Replacement not enabled"); if (!LookupHashRange(addr, w, h)) { // There wasn't any hash range, let's fall back to maxSeenV logic. @@ -244,9 +244,9 @@ u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureForm case ReplacedTextureHash::QUICK: return StableQuickTexHash(checkp, sizeInRAM); case ReplacedTextureHash::XXH32: - return DoReliableHash32(checkp, sizeInRAM, 0xBACD7814); + return XXH32(checkp, sizeInRAM, 0xBACD7814); case ReplacedTextureHash::XXH64: - return DoReliableHash64(checkp, sizeInRAM, 0xBACD7814); + return XXH64(checkp, sizeInRAM, 0xBACD7814); default: return 0; } @@ -267,7 +267,7 @@ u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureForm case ReplacedTextureHash::XXH32: for (int y = 0; y < h; ++y) { - u32 rowHash = DoReliableHash32(checkp, bytesPerLine, 0xBACD7814); + u32 rowHash = XXH32(checkp, bytesPerLine, 0xBACD7814); result = (result * 11) ^ rowHash; checkp += stride; } @@ -275,7 +275,7 @@ u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureForm case ReplacedTextureHash::XXH64: for (int y = 0; y < h; ++y) { - u32 rowHash = DoReliableHash64(checkp, bytesPerLine, 0xBACD7814); + u32 rowHash = XXH64(checkp, bytesPerLine, 0xBACD7814); result = (result * 11) ^ rowHash; checkp += stride; } @@ -330,16 +330,6 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, level.fmt = ReplacedTextureFormat::F_8888; level.file = filename; -#ifdef USING_QT_UI - QImage image(filename.c_str(), "PNG"); - if (image.isNull()) { - ERROR_LOG(G3D, "Could not load texture replacement info: %s", filename.c_str()); - } else { - level.w = (image.width() * w) / newW; - level.h = (image.height() * h) / newH; - good = true; - } -#else png_image png = {}; png.version = PNG_IMAGE_VERSION; FILE *fp = File::OpenCFile(filename, "rb"); @@ -354,7 +344,6 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, fclose(fp); png_image_free(&png); -#endif if (good && i != 0) { // Check that the mipmap size is correct. Can't load mips of the wrong size. @@ -374,19 +363,15 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, result->alphaStatus_ = ReplacedTextureAlpha::UNKNOWN; } -#ifndef USING_QT_UI static bool WriteTextureToPNG(png_imagep image, const std::string &filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { FILE *fp = File::OpenCFile(filename, "wb"); if (!fp) { - ERROR_LOG(SYSTEM, "Unable to open texture file for writing."); + ERROR_LOG(IO, "Unable to open texture file for writing."); return false; } if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, row_stride, colormap)) { - if (fclose(fp) != 0) { - ERROR_LOG(SYSTEM, "Texture file write failed."); - return false; - } + fclose(fp); return true; } else { ERROR_LOG(SYSTEM, "Texture PNG encode failed."); @@ -395,10 +380,9 @@ static bool WriteTextureToPNG(png_imagep image, const std::string &filename, int return false; } } -#endif void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int w, int h) { - _assert_msg_(G3D, enabled_, "Replacement not enabled"); + _assert_msg_(enabled_, "Replacement not enabled"); if (!g_Config.bSaveNewTextures) { // Ignore. return; @@ -459,9 +443,6 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl h = lookupH * replacedInfo.scaleFactor; } -#ifdef USING_QT_UI - ERROR_LOG(G3D, "Replacement texture saving not implemented for Qt"); -#else if (replacedInfo.fmt != ReplacedTextureFormat::F_8888) { saveBuf.resize((pitch * h) / sizeof(u16)); switch (replacedInfo.fmt) { @@ -512,7 +493,6 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl } else if (success) { NOTICE_LOG(G3D, "Saving texture for replacement: %08x / %dx%d", replacedInfo.hash, w, h); } -#endif // Remember that we've saved this for next time. ReplacedTextureLevel saved; @@ -595,39 +575,11 @@ bool TextureReplacer::LookupHashRange(u32 addr, int &w, int &h) { } void ReplacedTexture::Load(int level, void *out, int rowPitch) { - _assert_msg_(G3D, (size_t)level < levels_.size(), "Invalid miplevel"); - _assert_msg_(G3D, out != nullptr && rowPitch > 0, "Invalid out/pitch"); + _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel"); + _assert_msg_(out != nullptr && rowPitch > 0, "Invalid out/pitch"); const ReplacedTextureLevel &info = levels_[level]; -#ifdef USING_QT_UI - QImage image(info.file.c_str(), "PNG"); - if (image.isNull()) { - ERROR_LOG(G3D, "Could not load texture replacement info: %s", info.file.c_str()); - return; - } - - image = image.convertToFormat(QImage::Format_ARGB32); - bool alphaFull = true; - for (int y = 0; y < image.height(); ++y) { - const QRgb *src = (const QRgb *)image.constScanLine(y); - uint8_t *outLine = (uint8_t *)out + y * rowPitch; - for (int x = 0; x < image.width(); ++x) { - outLine[x * 4 + 0] = qRed(src[x]); - outLine[x * 4 + 1] = qGreen(src[x]); - outLine[x * 4 + 2] = qBlue(src[x]); - outLine[x * 4 + 3] = qAlpha(src[x]); - // We're already scanning each pixel... - if (qAlpha(src[x]) != 255) { - alphaFull = false; - } - } - } - - if (level == 0 || !alphaFull) { - alphaStatus_ = alphaFull ? ReplacedTextureAlpha::FULL : ReplacedTextureAlpha::UNKNOWN; - } -#else png_image png = {}; png.version = PNG_IMAGE_VERSION; @@ -662,7 +614,6 @@ void ReplacedTexture::Load(int level, void *out, int rowPitch) { fclose(fp); png_image_free(&png); -#endif } bool TextureReplacer::GenerateIni(const std::string &gameID, std::string *generatedFilename) { diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index a79d7b6c31..d90f373c4e 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -48,7 +48,6 @@ enum class ReplacedTextureAlpha { // For forward comatibility, we specify the hash. enum class ReplacedTextureHash { - // TODO: Maybe only support crc32c for now? QUICK, XXH32, XXH64, diff --git a/Core/ThreadEventQueue.h b/Core/ThreadEventQueue.h index 66f442cdfd..d365454776 100644 --- a/Core/ThreadEventQueue.h +++ b/Core/ThreadEventQueue.h @@ -139,7 +139,7 @@ struct ThreadEventQueue : public B { // Don't run if it's not running, but wait for startup. if (!eventsRunning_) { - if (eventsHaveRun_ || coreState == CORE_ERROR || coreState == CORE_POWERDOWN) { + if (eventsHaveRun_ || coreState == CORE_BOOT_ERROR || coreState == CORE_RUNTIME_ERROR || coreState == CORE_POWERDOWN) { return false; } } diff --git a/Common/ThreadPools.cpp b/Core/ThreadPools.cpp similarity index 100% rename from Common/ThreadPools.cpp rename to Core/ThreadPools.cpp diff --git a/Common/ThreadPools.h b/Core/ThreadPools.h similarity index 90% rename from Common/ThreadPools.h rename to Core/ThreadPools.h index e04303a9d2..350d56da1e 100644 --- a/Common/ThreadPools.h +++ b/Core/ThreadPools.h @@ -1,6 +1,6 @@ #pragma once -#include "thread/threadpool.h" +#include "Common/Thread/ThreadPool.h" class GlobalThreadPool { public: diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index 02496432b1..7dfa4637ba 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -18,7 +18,8 @@ #include #include "Common/Log.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Common/StringUtils.h" #include "Core/Util/BlockAllocator.h" #include "Core/Reporting.h" @@ -163,13 +164,13 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) alignedPosition &= ~(grain_ - 1); // Since the position was decreased, size must increase. - alignedSize += alignedPosition - position; + alignedSize += position - alignedPosition; } // Upalign size to grain. alignedSize = (alignedSize + grain_ - 1) & ~(grain_ - 1); // Tell the caller the allocated size from their requested starting position. - size = alignedSize - (alignedPosition - position); + size = alignedSize - (position - alignedPosition); Block *bp = GetBlockFromAddress(alignedPosition); if (bp != NULL) @@ -389,13 +390,13 @@ u32 BlockAllocator::GetBlockSizeFromAddress(u32 addr) const void BlockAllocator::ListBlocks() const { - INFO_LOG(SCEKERNEL,"-----------"); + DEBUG_LOG(SCEKERNEL,"-----------"); for (const Block *bp = bottom_; bp != NULL; bp = bp->next) { const Block &b = *bp; - INFO_LOG(SCEKERNEL, "Block: %08x - %08x size %08x taken=%i tag=%s", b.start, b.start+b.size, b.size, b.taken ? 1:0, b.tag); + DEBUG_LOG(SCEKERNEL, "Block: %08x - %08x size %08x taken=%i tag=%s", b.start, b.start+b.size, b.size, b.taken ? 1:0, b.tag); } - INFO_LOG(SCEKERNEL,"-----------"); + DEBUG_LOG(SCEKERNEL,"-----------"); } u32 BlockAllocator::GetLargestFreeBlockSize() const @@ -442,7 +443,7 @@ void BlockAllocator::DoState(PointerWrap &p) if (p.mode == p.MODE_READ) { Shutdown(); - p.Do(count); + Do(p, count); bottom_ = new Block(0, 0, false, NULL, NULL); bottom_->DoState(p); @@ -460,7 +461,7 @@ void BlockAllocator::DoState(PointerWrap &p) { for (const Block *bp = bottom_; bp != NULL; bp = bp->next) ++count; - p.Do(count); + Do(p, count); bottom_->DoState(p); --count; @@ -473,9 +474,9 @@ void BlockAllocator::DoState(PointerWrap &p) } } - p.Do(rangeStart_); - p.Do(rangeSize_); - p.Do(grain_); + Do(p, rangeStart_); + Do(p, rangeSize_); + Do(p, grain_); } BlockAllocator::Block::Block(u32 _start, u32 _size, bool _taken, Block *_prev, Block *_next) @@ -498,13 +499,13 @@ void BlockAllocator::Block::DoState(PointerWrap &p) if (!s) return; - p.Do(start); - p.Do(size); - p.Do(taken); + Do(p, start); + Do(p, size); + Do(p, taken); // Since we use truncate_cpy, the empty space is not zeroed. Zero it now. // This avoids saving uninitialized memory. size_t tagLen = strlen(tag); if (tagLen != sizeof(tag)) memset(tag + tagLen, 0, sizeof(tag) - tagLen); - p.DoArray(tag, sizeof(tag)); + DoArray(p, tag, sizeof(tag)); } diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index fd17c54412..651ffe35c9 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -21,7 +21,8 @@ // Does enough to understand what's going on without having to resort to an // external disassembler all the time... -#include +#include +#include #include "Common/Arm64Emitter.h" #include "Common/StringUtils.h" @@ -265,6 +266,40 @@ static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *ins } } +bool Arm64AnalyzeLoadStore(uint64_t addr, uint32_t w, Arm64LSInstructionInfo *info) { + *info = {}; + info->instructionSize = 4; + int id = (w >> 25) & 0xF; + switch (id) { + case 4: case 6: case 0xC: case 0xE: + break; + default: + return false; // not the expected instruction + } + + info->size = w >> 30; + info->Rt = (w & 0x1F); + info->Rn = ((w >> 5) & 0x1F); + info->Rm = ((w >> 16) & 0x1F); + int opc = (w >> 22) & 0x3; + if (opc == 0 || opc == 2) { + info->isMemoryWrite = true; + } + + if (((w >> 27) & 7) == 7) { + int V = (w >> 26) & 1; + if (V == 0) { + info->isIntegerLoadStore = true; + } else { + info->isFPLoadStore = true; + } + } else { + info->isPairLoadStore = true; + // TODO + } + return true; +} + static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) { int size = w >> 30; int imm9 = SignExtend9((w >> 12) & 0x1FF); diff --git a/Core/Util/DisArm64.h b/Core/Util/DisArm64.h index fc55c6c34b..ced77f2cc2 100644 --- a/Core/Util/DisArm64.h +++ b/Core/Util/DisArm64.h @@ -18,9 +18,28 @@ // Basic ARM64 disassembler. // No promises of accuracy, mostly just made to debug JIT code. -#include +#include typedef bool (*SymbolCallback)(char *buffer, int bufsize, uint8_t *address); void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord, SymbolCallback symbolCallback = nullptr); +// Information about a load/store instruction. +struct Arm64LSInstructionInfo { + int instructionSize; + + bool isIntegerLoadStore; + bool isFPLoadStore; + bool isPairLoadStore; + + int size; // 0 = 8-bit, 1 = 16-bit, 2 = 32-bit, 3 = 64-bit + bool isMemoryWrite; + + int Rt; + int Rn; + int Rm; + + // TODO: more. +}; + +bool Arm64AnalyzeLoadStore(uint64_t addr, uint32_t op, Arm64LSInstructionInfo *info); diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index da0617dd43..17b2e75751 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -17,21 +17,21 @@ #include #include +#include #include #include -#include +#include #include -#include "file/file_util.h" #ifdef SHARED_LIBZIP #include #else #include "ext/libzip/zip.h" #endif -#include "util/text/utf8.h" - +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Format/IniFile.h" #include "Common/Log.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" #include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Loaders.h" @@ -40,7 +40,7 @@ #include "Core/System.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/Util/GameManager.h" -#include "i18n/i18n.h" +#include "Common/Data/Text/I18n.h" GameManager g_GameManager; @@ -599,7 +599,7 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, std::string std::string outputISOFilename = g_Config.currentDirectory + "/" + fn.substr(nameOffset); size_t bytesCopied = 0; if (ExtractFile(z, isoFileIndex, outputISOFilename, &bytesCopied, allBytes)) { - ILOG("Successfully extracted ISO file to '%s'", outputISOFilename.c_str()); + INFO_LOG(IO, "Successfully extracted ISO file to '%s'", outputISOFilename.c_str()); } zip_close(z); if (deleteAfter) { diff --git a/Core/Util/GameManager.h b/Core/Util/GameManager.h index 81d1368273..63460f66d7 100644 --- a/Core/Util/GameManager.h +++ b/Core/Util/GameManager.h @@ -23,7 +23,7 @@ #pragma once #include -#include "net/http_client.h" +#include "Common/Net/HTTPClient.h" enum class GameManagerState { IDLE, diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index 8b0fe61a37..4f4a9d9c28 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -17,15 +17,17 @@ #include -#include "base/stringutil.h" -#include "file/vfs.h" -#include "gfx/texture_atlas.h" -#include "gfx_es2/draw_text.h" -#include "image/zim_load.h" -#include "image/png_load.h" -#include "util/text/utf8.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/Text/draw_text.h" -#include "Common/ChunkFile.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/File/VFS/VFS.h" +#include "Common/Data/Format/ZIMLoad.h" +#include "Common/Data/Format/PNGLoad.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/StringUtils.h" #include "Core/HDRemaster.h" #include "Core/Host.h" #include "GPU/ge_constants.h" @@ -125,7 +127,7 @@ struct PPGeTextDrawerImage { std::map textDrawerImages; // Overwrite the current text lines buffer so it can be drawn later. -void PPGePrepareText(const char *text, float x, float y, int align, float scale, float lineHeightScale, +void PPGePrepareText(const char *text, float x, float y, PPGeAlign align, float scale, float lineHeightScale, int WrapType = PPGE_LINE_NONE, int wrapWidth = 0); // These functions must be called between PPGeBegin and PPGeEnd. @@ -140,6 +142,7 @@ void PPGeSetTexture(u32 dataAddr, int width, int height); static void WriteCmd(u8 cmd, u32 data) { Memory::Write_U32((cmd << 24) | (data & 0xFFFFFF), dlWritePtr); dlWritePtr += 4; + _dbg_assert_(dlWritePtr <= dlPtr + dlSize); } static void WriteCmdAddrWithBase(u8 cmd, u32 addr) { @@ -178,6 +181,7 @@ static void Vertex(float x, float y, float u, float v, int tw, int th, u32 color Memory::WriteStruct(dataWritePtr, &vtx); dataWritePtr += sizeof(vtx); } + _dbg_assert_(dataWritePtr <= dataPtr + dataSize); vertexCount++; } @@ -219,15 +223,13 @@ void __PPGeInit() { bool loadedZIM = !skipZIM && LoadZIM("ppge_atlas_luna.zim", width, height, &flags, imageData); if (!skipZIM && !loadedZIM) { - PanicAlert("Failed to load ppge_atlas_luna.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory."); - ERROR_LOG(SCEGE, "PPGe init failed - no atlas texture. PPGe stuff will not be drawn."); + ERROR_LOG(SCEGE, "Failed to load ppge_atlas_luna.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.\n\nPPGe stuff will not be drawn."); } if (loadedZIM) { size_t atlas_data_size; - uint8_t *atlas_data; if (!g_ppge_atlas.IsMetadataLoaded()) { - atlas_data = VFSReadFile("ppge_atlas_luna.meta", &atlas_data_size); + uint8_t *atlas_data = VFSReadFile("ppge_atlas_luna.meta", &atlas_data_size); if (atlas_data) g_ppge_atlas.Load(atlas_data, atlas_data_size); delete[] atlas_data; @@ -262,7 +264,7 @@ void __PPGeInit() { u8 cval = (a2 << 4) | a1; ramPtr[i] = cval; } - + free(imageData[0]); // We can't create it here, because Android needs it on the right thread. @@ -271,7 +273,7 @@ void __PPGeInit() { textDrawer = nullptr; textDrawerImages.clear(); - DEBUG_LOG(SCEGE, "PPGe drawing library initialized. DL: %08x Data: %08x Atlas: %08x (%i) Args: %08x", + INFO_LOG(SCEGE, "PPGe drawing library initialized. DL: %08x Data: %08x Atlas: %08x (%i) Args: %08x", dlPtr, dataPtr, atlasPtr, atlasSize, listArgs.ptr); } @@ -281,23 +283,23 @@ void __PPGeDoState(PointerWrap &p) if (!s) return; - p.Do(atlasPtr); - p.Do(atlasWidth); - p.Do(atlasHeight); - p.Do(palette); + Do(p, atlasPtr); + Do(p, atlasWidth); + Do(p, atlasHeight); + Do(p, palette); - p.Do(savedContextPtr); - p.Do(savedContextSize); + Do(p, savedContextPtr); + Do(p, savedContextSize); if (s == 1) { listArgs = 0; } else { - p.Do(listArgs); + Do(p, listArgs); } if (s >= 3) { uint32_t sz = (uint32_t)textDrawerImages.size(); - p.Do(sz); + Do(p, sz); switch (p.mode) { case PointerWrap::MODE_READ: @@ -306,12 +308,12 @@ void __PPGeDoState(PointerWrap &p) // We only care about the pointers, so we can free them. We'll decimate right away. PPGeTextDrawerCacheKey key{ StringFromFormat("__savestate__%d", i), -1, -1 }; textDrawerImages[key] = PPGeTextDrawerImage{}; - p.Do(textDrawerImages[key].ptr); + Do(p, textDrawerImages[key].ptr); } break; default: for (const auto &im : textDrawerImages) { - p.Do(im.second.ptr); + Do(p, im.second.ptr); } break; } @@ -319,19 +321,19 @@ void __PPGeDoState(PointerWrap &p) textDrawerImages.clear(); } - p.Do(dlPtr); - p.Do(dlWritePtr); - p.Do(dlSize); + Do(p, dlPtr); + Do(p, dlWritePtr); + Do(p, dlSize); - p.Do(dataPtr); - p.Do(dataWritePtr); - p.Do(dataSize); + Do(p, dataPtr); + Do(p, dataWritePtr); + Do(p, dataSize); - p.Do(vertexStart); - p.Do(vertexCount); + Do(p, vertexStart); + Do(p, vertexCount); - p.Do(char_lines); - p.Do(char_lines_metrics); + Do(p, char_lines); + Do(p, char_lines_metrics); } void __PPGeShutdown() @@ -385,8 +387,7 @@ void PPGeBegin() PPGeSetDefaultTexture(); - WriteCmd(GE_CMD_SCISSOR1, (0 << 10) | 0); - WriteCmd(GE_CMD_SCISSOR2, (271 << 10) | 479); + PPGeScissor(0, 0, 480, 272); WriteCmd(GE_CMD_MINZ, 0); WriteCmd(GE_CMD_MAXZ, 0xFFFF); @@ -418,6 +419,17 @@ void PPGeEnd() } } +void PPGeScissor(int x1, int y1, int x2, int y2) { + _dbg_assert_(x1 >= 0 && x1 <= 480 && x2 >= 0 && x2 <= 480); + _dbg_assert_(y1 >= 0 && y1 <= 272 && y2 >= 0 && y2 <= 272); + WriteCmd(GE_CMD_SCISSOR1, (y1 << 10) | x1); + WriteCmd(GE_CMD_SCISSOR2, ((y2 - 1) << 10) | (x2 - 1)); +} + +void PPGeScissorReset() { + PPGeScissor(0, 0, 480, 272); +} + static const AtlasChar *PPGeGetChar(const AtlasFont &atlasfont, unsigned int cval) { const AtlasChar *c = atlasfont.getChar(cval); @@ -455,7 +467,7 @@ static const AtlasChar *PPGeGetChar(const AtlasFont &atlasfont, unsigned int cva // Break a single text string into mutiple lines. static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont, float x, float y, - int align, float scale, float lineHeightScale, int wrapType, float wrapWidth, bool dryRun) + PPGeAlign align, float scale, float lineHeightScale, int wrapType, float wrapWidth, bool dryRun) { y += atlasfont.ascend * scale; float sx = x, sy = y; @@ -665,26 +677,22 @@ static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont, const float w = maxw; const float h = (float)numLines * lineHeight; - if (align) - { - if (!dryRun) - { - for (auto i = char_lines.begin(); i != char_lines.end(); ++i) - { - for (auto j = i->begin(); j != i->end(); ++j) - { - if (align & PPGE_ALIGN_HCENTER) j->x -= w / 2.0f; - else if (align & PPGE_ALIGN_RIGHT) j->x -= w; + if (align & PPGeAlign::ANY) { + if (!dryRun) { + for (auto i = char_lines.begin(); i != char_lines.end(); ++i) { + for (auto j = i->begin(); j != i->end(); ++j) { + if (align & PPGeAlign::BOX_HCENTER) j->x -= w / 2.0f; + else if (align & PPGeAlign::BOX_RIGHT) j->x -= w; - if (align & PPGE_ALIGN_VCENTER) j->y -= h / 2.0f; - else if (align & PPGE_ALIGN_BOTTOM) j->y -= h; + if (align & PPGeAlign::BOX_VCENTER) j->y -= h / 2.0f; + else if (align & PPGeAlign::BOX_BOTTOM) j->y -= h; } } } - if (align & PPGE_ALIGN_HCENTER) sx -= w / 2.0f; - else if (align & PPGE_ALIGN_RIGHT) sx -= w; - if (align & PPGE_ALIGN_VCENTER) sy -= h / 2.0f; - else if (align & PPGE_ALIGN_BOTTOM) sy -= h; + if (align & PPGeAlign::BOX_HCENTER) sx -= w / 2.0f; + else if (align & PPGeAlign::BOX_RIGHT) sx -= w; + if (align & PPGeAlign::BOX_VCENTER) sy -= h / 2.0f; + else if (align & PPGeAlign::BOX_BOTTOM) sy -= h; } AtlasTextMetrics metrics = { sx, sy, w, lineHeight, scale, numLines }; @@ -734,12 +742,12 @@ void PPGeMeasureText(float *w, float *h, const char *text, float scale, int Wrap } const AtlasFont &atlasfont = g_ppge_atlas.fonts[0]; - AtlasTextMetrics metrics = BreakLines(text, atlasfont, 0, 0, 0, scale, scale, WrapType, wrapWidth, true); + AtlasTextMetrics metrics = BreakLines(text, atlasfont, 0, 0, PPGeAlign::BOX_TOP, scale, scale, WrapType, wrapWidth, true); if (w) *w = metrics.maxWidth; if (h) *h = metrics.lineHeight * metrics.numLines; } -void PPGePrepareText(const char *text, float x, float y, int align, float scale, float lineHeightScale, int WrapType, int wrapWidth) +void PPGePrepareText(const char *text, float x, float y, PPGeAlign align, float scale, float lineHeightScale, int WrapType, int wrapWidth) { const AtlasFont &atlasfont = g_ppge_atlas.fonts[0]; if (!g_ppge_atlas.IsMetadataLoaded() || g_ppge_atlas.num_fonts < 1) { @@ -794,15 +802,15 @@ int GetPow2(int x) { return ret; } -static PPGeTextDrawerImage PPGeGetTextImage(const char *text, int align, float scale, float maxWidth, bool wrap) { - int tdalign = (align & PPGE_ALIGN_HCENTER) ? ALIGN_HCENTER : 0; +static PPGeTextDrawerImage PPGeGetTextImage(const char *text, const PPGeStyle &style, float maxWidth, bool wrap) { + int tdalign = 0; tdalign |= FLAG_ELLIPSIZE_TEXT; if (wrap) { tdalign |= FLAG_WRAP_TEXT; } - PPGeTextDrawerCacheKey key{ text, tdalign, maxWidth / scale }; - PPGeTextDrawerImage im; + PPGeTextDrawerCacheKey key{ text, tdalign, maxWidth / style.scale }; + PPGeTextDrawerImage im{}; auto cacheItem = textDrawerImages.find(key); if (cacheItem != textDrawerImages.end()) { @@ -810,7 +818,7 @@ static PPGeTextDrawerImage PPGeGetTextImage(const char *text, int align, float s cacheItem->second.entry.lastUsedFrame = gpuStats.numFlips; } else { std::vector bitmapData; - textDrawer->SetFontScale(scale, scale); + textDrawer->SetFontScale(style.scale, style.scale); Bounds b(0, 0, maxWidth, 272.0f); std::string cleaned = ReplaceAll(text, "\r", ""); textDrawer->DrawStringBitmapRect(bitmapData, im.entry, Draw::DataFormat::R8_UNORM, cleaned.c_str(), b, tdalign); @@ -847,7 +855,11 @@ static PPGeTextDrawerImage PPGeGetTextImage(const char *text, int align, float s return im; } -static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, int align, float scale, u32 color) { +static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, const PPGeStyle &style) { + if (!im.ptr) { + return; + } + int bufw = ((im.entry.bmWidth + 31) / 32) * 32; int wp2 = GetPow2(im.entry.bmWidth); int hp2 = GetPow2(im.entry.bmHeight); @@ -856,37 +868,58 @@ static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, int alig WriteCmd(GE_CMD_TEXSIZE0, wp2 | (hp2 << 8)); WriteCmd(GE_CMD_TEXFLUSH, 0); - float w = im.entry.width * scale; - float h = im.entry.height * scale; + float w = im.entry.width * style.scale; + float h = im.entry.height * style.scale; - if (align & PPGE_ALIGN_HCENTER) + if (style.align & PPGeAlign::BOX_HCENTER) x -= w / 2.0f; - else if (align & PPGE_ALIGN_RIGHT) + else if (style.align & PPGeAlign::BOX_RIGHT) x -= w; - if (align & PPGE_ALIGN_VCENTER) + if (style.align & PPGeAlign::BOX_VCENTER) y -= h / 2.0f; - else if (align & PPGE_ALIGN_BOTTOM) + else if (style.align & PPGeAlign::BOX_BOTTOM) y -= h; BeginVertexData(); float u1 = (float)im.entry.width / (1 << wp2); float v1 = (float)im.entry.height / (1 << hp2); - Vertex(x, y, 0, 0, 1 << wp2, 1 << hp2, color); - Vertex(x + w, y + h, u1, v1, 1 << wp2, 1 << hp2, color); + if (style.hasShadow) { + // Draw more shadows for a blurrier shadow. + for (float dy = 0.0f; dy <= 2.0f; dy += 1.0f) { + for (float dx = 0.0f; dx <= 1.0f; dx += 0.5f) { + if (dx == 0.0f && dy == 0.0f) + continue; + Vertex(x + dx, y + dy, 0, 0, 1 << wp2, 1 << hp2, alphaMul(style.shadowColor, 0.35f)); + Vertex(x + dx + w, y + dy + h, u1, v1, 1 << wp2, 1 << hp2, alphaMul(style.shadowColor, 0.35f)); + } + } + } + Vertex(x, y, 0, 0, 1 << wp2, 1 << hp2, style.color); + Vertex(x + w, y + h, u1, v1, 1 << wp2, 1 << hp2, style.color); EndVertexDataAndDraw(GE_PRIM_RECTANGLES); PPGeSetDefaultTexture(); } -void PPGeDrawText(const char *text, float x, float y, int align, float scale, u32 color) { - if (HasTextDrawer()) { - PPGeTextDrawerImage im = PPGeGetTextImage(text, align, scale, 480.0f - x, false); - PPGeDrawTextImage(im, x, y, align, scale, color); +void PPGeDrawText(const char *text, float x, float y, const PPGeStyle &style) { + if (!text || !strlen(text)) { return; } - PPGePrepareText(text, x, y, align, scale, scale, PPGE_LINE_USE_ELLIPSIS); - PPGeDrawCurrentText(color); + if (HasTextDrawer()) { + PPGeTextDrawerImage im = PPGeGetTextImage(text, style, 480.0f - x, false); + PPGeDrawTextImage(im, x, y, style); + return; + } + + if (style.hasShadow) { + // This doesn't have the nicer shadow because it's so many verts. + PPGePrepareText(text, x + 1, y + 2, style.align, style.scale, style.scale, PPGE_LINE_USE_ELLIPSIS); + PPGeDrawCurrentText(style.shadowColor); + } + + PPGePrepareText(text, x, y, style.align, style.scale, style.scale, PPGE_LINE_USE_ELLIPSIS); + PPGeDrawCurrentText(style.color); } static std::string StripTrailingWhite(const std::string &s) { @@ -912,7 +945,7 @@ static std::string CropLinesToCount(const std::string &s, int numLines) { return s.substr(0, len); } -void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, float wrapHeight, int align, float scale, u32 color) { +void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, float wrapHeight, const PPGeStyle &style) { std::string s = text; if (wrapHeight != 0.0f) { s = StripTrailingWhite(s); @@ -924,9 +957,12 @@ void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, fl if (HasTextDrawer()) { float actualWidth, actualHeight; Bounds b(0, 0, wrapWidth <= 0 ? 480.0f - x : wrapWidth, wrapHeight); - int tdalign = (align & PPGE_ALIGN_HCENTER) ? ALIGN_HCENTER : 0; - textDrawer->SetFontScale(scale, scale); + int tdalign = 0; + textDrawer->SetFontScale(style.scale, style.scale); textDrawer->MeasureStringRect(s.c_str(), s.size(), b, &actualWidth, &actualHeight, tdalign | FLAG_WRAP_TEXT); + + // Check if we need to scale the text down to fit better. + PPGeStyle adjustedStyle = style; if (wrapHeight != 0.0f && actualHeight > wrapHeight) { // Cheap way to get the line height. float oneLine, twoLines; @@ -942,16 +978,20 @@ void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, fl s = StripTrailingWhite(CropLinesToCount(s, (int)maxLines)) + "\n..."; } - scale *= wrapHeight / actualHeight; + adjustedStyle.scale *= wrapHeight / actualHeight; } - PPGeTextDrawerImage im = PPGeGetTextImage(s.c_str(), align, scale, wrapWidth <= 0 ? 480.0f - x : wrapWidth, true); - PPGeDrawTextImage(im, x, y, align, scale, color); + PPGeTextDrawerImage im = PPGeGetTextImage(s.c_str(), adjustedStyle, wrapWidth <= 0 ? 480.0f - x : wrapWidth, true); + PPGeDrawTextImage(im, x, y, adjustedStyle); return; } - PPGePrepareText(s.c_str(), x, y, align, scale, scale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth); + int sx = style.hasShadow ? 1 : 0; + int sy = style.hasShadow ? 2 : 0; + PPGePrepareText(s.c_str(), x + sx, y + sy, style.align, style.scale, style.scale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth); + float scale = style.scale; + float lineHeightScale = style.scale; float actualHeight = char_lines_metrics.lineHeight * char_lines_metrics.numLines; if (wrapHeight != 0.0f && actualHeight > wrapHeight) { if (actualHeight > wrapHeight * maxScaleDown) { @@ -964,11 +1004,18 @@ void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, fl // Measure the text again after scaling down. PPGeResetCurrentText(); - float reduced = scale * wrapHeight / actualHeight; + float reduced = style.scale * wrapHeight / actualHeight; // Try to keep the font as large as possible, so reduce the line height some. - PPGePrepareText(s.c_str(), x, y, align, reduced * 1.15, reduced, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth); + scale = reduced * 1.15f; + lineHeightScale = reduced; + PPGePrepareText(s.c_str(), x + sx, y + sy, style.align, scale, lineHeightScale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth); } - PPGeDrawCurrentText(color); + if (style.hasShadow) { + // This doesn't have the nicer shadow because it's so many verts. + PPGeDrawCurrentText(style.shadowColor); + PPGePrepareText(s.c_str(), x, y, style.align, scale, lineHeightScale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth); + } + PPGeDrawCurrentText(style.color); } // Draws a "4-patch" for button-like things that can be resized @@ -1028,8 +1075,7 @@ void PPGeDrawRect(float x1, float y1, float x2, float y2, u32 color) { } // Just blits an image to the screen, multiplied with the color. -void PPGeDrawImage(ImageID atlasImage, float x, float y, int align, u32 color) -{ +void PPGeDrawImage(ImageID atlasImage, float x, float y, const PPGeStyle &style) { if (!dlPtr) return; @@ -1040,13 +1086,22 @@ void PPGeDrawImage(ImageID atlasImage, float x, float y, int align, u32 color) float w = img->w; float h = img->h; BeginVertexData(); - Vertex(x, y, img->u1, img->v1, atlasWidth, atlasHeight, color); - Vertex(x + w, y + h, img->u2, img->v2, atlasWidth, atlasHeight, color); + if (style.hasShadow) { + for (float dy = 0.0f; dy <= 2.0f; dy += 1.0f) { + for (float dx = 0.0f; dx <= 1.0f; dx += 0.5f) { + if (dx == 0.0f && dy == 0.0f) + continue; + Vertex(x + dx, y + dy, img->u1, img->v1, atlasWidth, atlasHeight, alphaMul(style.shadowColor, 0.35f)); + Vertex(x + dx + w, y + dy + h, img->u2, img->v2, atlasWidth, atlasHeight, alphaMul(style.shadowColor, 0.35f)); + } + } + } + Vertex(x, y, img->u1, img->v1, atlasWidth, atlasHeight, style.color); + Vertex(x + w, y + h, img->u2, img->v2, atlasWidth, atlasHeight, style.color); EndVertexDataAndDraw(GE_PRIM_RECTANGLES); } -void PPGeDrawImage(ImageID atlasImage, float x, float y, float w, float h, int align, u32 color) -{ +void PPGeDrawImage(ImageID atlasImage, float x, float y, float w, float h, const PPGeStyle &style) { if (!dlPtr) return; @@ -1055,8 +1110,18 @@ void PPGeDrawImage(ImageID atlasImage, float x, float y, float w, float h, int a return; } BeginVertexData(); - Vertex(x, y, img->u1, img->v1, atlasWidth, atlasHeight, color); - Vertex(x + w, y + h, img->u2, img->v2, atlasWidth, atlasHeight, color); + if (style.hasShadow) { + for (float dy = 0.0f; dy <= 2.0f; dy += 1.0f) { + for (float dx = 0.0f; dx <= 1.0f; dx += 0.5f) { + if (dx == 0.0f && dy == 0.0f) + continue; + Vertex(x + dx, y + dy, img->u1, img->v1, atlasWidth, atlasHeight, alphaMul(style.shadowColor, 0.35f)); + Vertex(x + dx + w, y + dy + h, img->u2, img->v2, atlasWidth, atlasHeight, alphaMul(style.shadowColor, 0.35f)); + } + } + } + Vertex(x, y, img->u1, img->v1, atlasWidth, atlasHeight, style.color); + Vertex(x + w, y + h, img->u2, img->v2, atlasWidth, atlasHeight, style.color); EndVertexDataAndDraw(GE_PRIM_RECTANGLES); } @@ -1137,7 +1202,7 @@ bool PPGeImage::Load() { unsigned char *textureData; int success; if (filename_.empty()) { - success = pngLoadPtr(Memory::GetPointer(png_), size_, &width_, &height_, &textureData, false); + success = pngLoadPtr(Memory::GetPointer(png_), size_, &width_, &height_, &textureData); } else { std::vector pngData; if (pspFileSystem.ReadEntireFile(filename_, pngData) < 0) { @@ -1145,7 +1210,7 @@ bool PPGeImage::Load() { return false; } - success = pngLoadPtr((const unsigned char *)&pngData[0], pngData.size(), &width_, &height_, &textureData, false); + success = pngLoadPtr((const unsigned char *)&pngData[0], pngData.size(), &width_, &height_, &textureData); } if (!success) { WARN_LOG(SCEGE, "Bad PPGeImage - not a valid png"); @@ -1181,13 +1246,13 @@ void PPGeImage::DoState(PointerWrap &p) { if (!s) return; - p.Do(filename_); - p.Do(png_); - p.Do(size_); - p.Do(texture_); - p.Do(width_); - p.Do(height_); - p.Do(lastFrame_); + Do(p, filename_); + Do(p, png_); + Do(p, size_); + Do(p, texture_); + Do(p, width_); + Do(p, height_); + Do(p, lastFrame_); } void PPGeImage::CompatLoad(u32 texture, int width, int height) { diff --git a/Core/Util/PPGeDraw.h b/Core/Util/PPGeDraw.h index f97b482769..dbff6bb831 100644 --- a/Core/Util/PPGeDraw.h +++ b/Core/Util/PPGeDraw.h @@ -20,7 +20,7 @@ #include #include -#include "gfx/texture_atlas.h" +#include "Common/Render/TextureAtlas.h" #include "Common/CommonTypes.h" @@ -45,21 +45,22 @@ void __PPGeShutdown(); void PPGeBegin(); void PPGeEnd(); -enum { - PPGE_ALIGN_LEFT = 0, - PPGE_ALIGN_RIGHT = 16, - PPGE_ALIGN_TOP = 0, - PPGE_ALIGN_BOTTOM = 1, - PPGE_ALIGN_HCENTER = 4, - PPGE_ALIGN_VCENTER = 8, - PPGE_ALIGN_VBASELINE = 32, // text only, possibly not yet working +enum class PPGeAlign { + BOX_LEFT = 0x00, + BOX_RIGHT = 0x01, + BOX_HCENTER = 0x02, - PPGE_ALIGN_CENTER = PPGE_ALIGN_HCENTER | PPGE_ALIGN_VCENTER, - PPGE_ALIGN_TOPLEFT = PPGE_ALIGN_TOP | PPGE_ALIGN_LEFT, - PPGE_ALIGN_TOPRIGHT = PPGE_ALIGN_TOP | PPGE_ALIGN_RIGHT, - PPGE_ALIGN_BOTTOMLEFT = PPGE_ALIGN_BOTTOM | PPGE_ALIGN_LEFT, - PPGE_ALIGN_BOTTOMRIGHT = PPGE_ALIGN_BOTTOM | PPGE_ALIGN_RIGHT, + BOX_TOP = 0x00, + BOX_BOTTOM = 0x10, + BOX_VCENTER = 0x20, + + BOX_CENTER = 0x22, + + ANY = 0xFF, }; +inline bool operator &(const PPGeAlign &lhs, const PPGeAlign &rhs) { + return ((int)lhs & (int)rhs) != 0; +} enum { PPGE_LINE_NONE = 0, @@ -68,22 +69,34 @@ enum { PPGE_LINE_WRAP_CHAR = 4, }; +struct PPGeStyle { + PPGeAlign align = PPGeAlign::BOX_LEFT; + float scale = 1.0f; + uint32_t color = 0xFFFFFFFF; + bool hasShadow = false; + uint32_t shadowColor = 0x80000000; +}; + // Get the metrics of the bounding box of the text without changing the buffer or state. void PPGeMeasureText(float *w, float *h, const char *text, float scale, int WrapType = PPGE_LINE_NONE, int wrapWidth = 0); // Draws some text using the one font we have. // Clears the text buffer when done. -void PPGeDrawText(const char *text, float x, float y, int align, float scale = 1.0f, u32 color = 0xFFFFFFFF); -void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, float wrapHeight, int align, float scale = 1.0f, u32 color = 0xFFFFFFFF); +void PPGeDrawText(const char *text, float x, float y, const PPGeStyle &style); +void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, float wrapHeight, const PPGeStyle &style); // Draws a "4-patch" for button-like things that can be resized. void PPGeDraw4Patch(ImageID atlasImage, float x, float y, float w, float h, u32 color = 0xFFFFFFFF); // Just blits an image to the screen, multiplied with the color. -void PPGeDrawImage(ImageID atlasImage, float x, float y, int align, u32 color = 0xFFFFFFFF); -void PPGeDrawImage(ImageID atlasImage, float x, float y, float w, float h, int align, u32 color = 0xFFFFFFFF); +void PPGeDrawImage(ImageID atlasImage, float x, float y, const PPGeStyle &style); +void PPGeDrawImage(ImageID atlasImage, float x, float y, float w, float h, const PPGeStyle &style); void PPGeDrawImage(float x, float y, float w, float h, float u1, float v1, float u2, float v2, int tw, int th, u32 color); +// Note: x2/y2 are exclusive. +void PPGeScissor(int x1, int y1, int x2, int y2); +void PPGeScissorReset(); + void PPGeNotifyFrame(); class PPGeImage { diff --git a/Core/Util/PortManager.cpp b/Core/Util/PortManager.cpp new file mode 100644 index 0000000000..3c4b808502 --- /dev/null +++ b/Core/Util/PortManager.cpp @@ -0,0 +1,497 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +// Most of the code are based on https://github.com/RJ/libportfwd and updated to the latest miniupnp library +// All credit goes to him and the official miniupnp project! http://miniupnp.free.fr/ + + +#include +#include +#include +#include +#include "Common/TimeUtil.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Net/Resolve.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Log.h" +#include "Core/System.h" +#include "Core/Host.h" +#include "Core/ELF/ParamSFO.h" +#include "Core/Util/PortManager.h" + + +PortManager g_PortManager; +bool upnpServiceRunning = false; +std::thread upnpServiceThread; +std::recursive_mutex upnpLock; +std::deque upnpReqs; + +PortManager::PortManager(): + urls(0), + datas(0), + m_InitState(UPNP_INITSTATE_NONE), + m_LocalPort(UPNP_LOCAL_PORT_ANY), + m_leaseDuration("43200") { + // Since WSAStartup can be used multiple times it should be safe to do this right? + net::Init(); +} + +PortManager::~PortManager() { + // FIXME: On Windows it seems using any UPnP functions in this destructor that gets triggered when exiting PPSSPP will resulting to UPNPCOMMAND_HTTP_ERROR due to early WSACleanup (miniupnpc was getting WSANOTINITIALISED internally) + Clear(); + Restore(); + Terminate(); + net::Shutdown(); +} + +void PortManager::Terminate() { + VERBOSE_LOG(SCENET, "PortManager::Terminate()"); + if (urls) { + FreeUPNPUrls(urls); + free(urls); + urls = NULL; + } + if (datas) { + free(datas); + datas = NULL; + } + m_otherPortList.clear(); m_otherPortList.shrink_to_fit(); + m_portList.clear(); m_portList.shrink_to_fit(); + m_lanip.clear(); + m_defaultDesc.clear(); + m_leaseDuration.clear(); + m_LocalPort = UPNP_LOCAL_PORT_ANY; + m_InitState = UPNP_INITSTATE_NONE; +} + +bool PortManager::Initialize(const unsigned int timeout) { + // Windows: Assuming WSAStartup already called beforehand + struct UPNPDev* devlist; + struct UPNPDev* dev; + char* descXML; + int descXMLsize = 0; + int descXMLstatus = 0; + int localport = m_LocalPort; // UPNP_LOCAL_PORT_ANY (0), or UPNP_LOCAL_PORT_SAME (1) as an alias for 1900 (for backwards compatability?) + int ipv6 = 0; // 0 = IPv4, 1 = IPv6 + unsigned char ttl = 2; // defaulting to 2 + int error = 0; + + VERBOSE_LOG(SCENET, "PortManager::Initialize(%d)", timeout); + if (!g_Config.bEnableUPnP) { + ERROR_LOG(SCENET, "PortManager::Initialize - UPnP is Disabled on Networking Settings"); + return false; + } + + if (m_InitState != UPNP_INITSTATE_NONE) { + switch (m_InitState) + { + case UPNP_INITSTATE_BUSY: { + WARN_LOG(SCENET, "PortManager - Initialization already in progress"); + return false; + } + // Should we redetect UPnP? just in case the player switched to a different network in the middle + case UPNP_INITSTATE_DONE: { + WARN_LOG(SCENET, "PortManager - Already Initialized"); + return true; + } + default: + break; + } + } + + m_leaseDuration = "43200"; // 12 hours + m_InitState = UPNP_INITSTATE_BUSY; + urls = (UPNPUrls*)malloc(sizeof(struct UPNPUrls)); + datas = (IGDdatas*)malloc(sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + memset(datas, 0, sizeof(struct IGDdatas)); + + devlist = upnpDiscover(timeout, NULL, NULL, localport, ipv6, ttl, &error); + if (devlist) + { + dev = devlist; + while (dev) + { + if (strstr(dev->st, "InternetGatewayDevice")) + break; + dev = dev->pNext; + } + if (!dev) + dev = devlist; // defaulting to first device + + INFO_LOG(SCENET, "PortManager - UPnP device: [desc: %s] [st: %s]", dev->descURL, dev->st); + + descXML = (char*)miniwget(dev->descURL, &descXMLsize, dev->scope_id, &descXMLstatus); + if (descXML) + { + parserootdesc(descXML, descXMLsize, datas); + free(descXML); descXML = 0; + GetUPNPUrls(urls, datas, dev->descURL, dev->scope_id); + } + + // Get LAN IP address that connects to the router + char lanaddr[64] = "unset"; + int status = UPNP_GetValidIGD(devlist, urls, datas, lanaddr, sizeof(lanaddr)); //possible "status" values, 0 = NO IGD found, 1 = A valid connected IGD has been found, 2 = A valid IGD has been found but it reported as not connected, 3 = an UPnP device has been found but was not recognized as an IGD + m_lanip = std::string(lanaddr); + INFO_LOG(SCENET, "PortManager - Detected LAN IP: %s", m_lanip.c_str()); + + // Additional Info + char connectionType[64] = ""; + if (UPNP_GetConnectionTypeInfo(urls->controlURL, datas->first.servicetype, connectionType) != UPNPCOMMAND_SUCCESS) { + WARN_LOG(SCENET, "PortManager - GetConnectionTypeInfo failed"); + } + else { + INFO_LOG(SCENET, "PortManager - Connection Type: %s", connectionType); + } + + // Using Game ID & Player Name as default description for mapping + std::string gameID = g_paramSFO.GetDiscID(); + m_defaultDesc = "PPSSPP:" + gameID + ":" + g_Config.sNickName; // Some routers may automatically prefixed it with "UPnP:" + + freeUPNPDevlist(devlist); + + //m_LocalPort = localport; // We shouldn't keep the right port for the next game reset if we wanted to redetect UPnP + m_InitState = UPNP_INITSTATE_DONE; + RefreshPortList(); + return true; + } + + ERROR_LOG(SCENET, "PortManager - upnpDiscover failed (error: %i) or No UPnP device detected", error); + auto n = GetI18NCategory("Networking"); + host->NotifyUserMessage(n->T("Unable to find UPnP device"), 2.0f, 0x0000ff); + m_InitState = UPNP_INITSTATE_NONE; + return false; +} + +int PortManager::GetInitState() { + return m_InitState; +} + +bool PortManager::Add(const char* protocol, unsigned short port, unsigned short intport) { + char port_str[16]; + char intport_str[16]; + int r; + + if (intport == 0) + intport = port; + INFO_LOG(SCENET, "PortManager::Add(%s, %d, %d)", protocol, port, intport); + if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') + { + if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::Add - the init was not done !"); + return false; + } + sprintf(port_str, "%d", port); + sprintf(intport_str, "%d", intport); + // Only add new port map if it's not previously created by PPSSPP for current IP + auto el_it = std::find_if(m_portList.begin(), m_portList.end(), + [port_str, protocol](const std::pair &el) { return el.first == port_str && el.second == protocol; }); + if (el_it == m_portList.end()) { + auto el_it = std::find_if(m_otherPortList.begin(), m_otherPortList.end(), + [port_str, protocol](const PortMap& el) { return el.extPort_str == port_str && el.protocol == protocol; }); + if (el_it != m_otherPortList.end()) { + // Try to delete the port mapping before we create it, just in case we have dangling port mapping from the daemon not being shut down correctly or the port was taken by other + r = UPNP_DeletePortMapping(urls->controlURL, datas->first.servicetype, port_str, protocol, NULL); + } + r = UPNP_AddPortMapping(urls->controlURL, datas->first.servicetype, + port_str, intport_str, m_lanip.c_str(), m_defaultDesc.c_str(), protocol, NULL, m_leaseDuration.c_str()); + if (r == 725 && m_leaseDuration != "0") { + m_leaseDuration = "0"; + r = UPNP_AddPortMapping(urls->controlURL, datas->first.servicetype, + port_str, intport_str, m_lanip.c_str(), m_defaultDesc.c_str(), protocol, NULL, m_leaseDuration.c_str()); + } + if (r != 0) + { + ERROR_LOG(SCENET, "PortManager - AddPortMapping failed (error: %i)", r); + if (r == UPNPCOMMAND_HTTP_ERROR) { + auto n = GetI18NCategory("Networking"); + host->NotifyUserMessage(n->T("UPnP need to be reinitialized"), 2.0f, 0x0000ff); + Terminate(); // Most of the time errors occurred because the router is no longer reachable (ie. changed networks) so we should invalidate the state to prevent further lags due to timeouts + return false; + } + } + m_portList.push_front({ port_str, protocol }); + // Keep tracks of it to be restored later if it belongs to others + if (el_it != m_otherPortList.end()) el_it->taken = true; + } + return true; +} + +bool PortManager::Remove(const char* protocol, unsigned short port) { + char port_str[16]; + + INFO_LOG(SCENET, "PortManager::Remove(%s, %d)", protocol, port); + if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') + { + if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::Remove - the init was not done !"); + return false; + } + sprintf(port_str, "%d", port); + int r = UPNP_DeletePortMapping(urls->controlURL, datas->first.servicetype, port_str, protocol, NULL); + if (r != 0) + { + ERROR_LOG(SCENET, "PortManager - DeletePortMapping failed (error: %i)", r); + if (r == UPNPCOMMAND_HTTP_ERROR) { + auto n = GetI18NCategory("Networking"); + host->NotifyUserMessage(n->T("UPnP need to be reinitialized"), 2.0f, 0x0000ff); + Terminate(); // Most of the time errors occurred because the router is no longer reachable (ie. changed networks) so we should invalidate the state to prevent further lags due to timeouts + return false; + } + } + for (auto it = m_portList.begin(); it != m_portList.end(); ) { + (it->first == port_str && it->second == protocol) ? it = m_portList.erase(it) : ++it; + } + return true; +} + +bool PortManager::Restore() { + int r; + VERBOSE_LOG(SCENET, "PortManager::Restore()"); + if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') + { + if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::Remove - the init was not done !"); + return false; + } + for (auto it = m_otherPortList.begin(); it != m_otherPortList.end(); ++it) { + if (it->taken) { + auto port_str = it->extPort_str; + auto protocol = it->protocol; + // Remove it first if it's still being taken by PPSSPP + auto el_it = std::find_if(m_portList.begin(), m_portList.end(), + [port_str, protocol](const std::pair& el) { return el.first == port_str && el.second == protocol; }); + if (el_it != m_portList.end()) { + r = UPNP_DeletePortMapping(urls->controlURL, datas->first.servicetype, port_str.c_str(), protocol.c_str(), NULL); + if (r == 0) { + m_portList.erase(el_it); + } + else { + ERROR_LOG(SCENET, "PortManager::Restore - DeletePortMapping failed (error: %i)", r); + if (r == UPNPCOMMAND_HTTP_ERROR) + return false; // Might be better not to exit here, but exiting a loop will avoid long timeouts in the case the router is no longer reachable + } + } + // Add the original owner back + r = UPNP_AddPortMapping(urls->controlURL, datas->first.servicetype, + it->extPort_str.c_str(), it->intPort_str.c_str(), it->lanip.c_str(), it->desc.c_str(), it->protocol.c_str(), it->remoteHost.c_str(), it->duration.c_str()); + if (r == 0) { + it->taken = false; + } + else { + ERROR_LOG(SCENET, "PortManager::Restore - AddPortMapping failed (error: %i)", r); + if (r == UPNPCOMMAND_HTTP_ERROR) + return false; // Might be better not to exit here, but exiting a loop will avoid long timeouts in the case the router is no longer reachable + } + } + } + return true; +} + +bool PortManager::Clear() { + int r; + int i = 0; + char index[6]; + char intAddr[40]; + char intPort[6]; + char extPort[6]; + char protocol[4]; + char desc[80]; + char enabled[6]; + char rHost[64]; + char duration[16]; + + VERBOSE_LOG(SCENET, "PortManager::Clear()"); + if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') + { + if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::Clear - the init was not done !"); + return false; + } + //unsigned int num = 0; + //UPNP_GetPortMappingNumberOfEntries(urls->controlURL, datas->first.servicetype, &num); // Not supported by many routers + do { + snprintf(index, 6, "%d", i); + rHost[0] = '\0'; enabled[0] = '\0'; + duration[0] = '\0'; desc[0] = '\0'; protocol[0] = '\0'; + extPort[0] = '\0'; intPort[0] = '\0'; intAddr[0] = '\0'; + // May gets UPNPCOMMAND_HTTP_ERROR when called while exiting PPSSPP (ie. used in destructor) + r = UPNP_GetGenericPortMappingEntry(urls->controlURL, + datas->first.servicetype, + index, + extPort, intAddr, intPort, + protocol, desc, enabled, + rHost, duration); + // Only removes port mappings created by PPSSPP for current LAN IP + if (r == 0 && intAddr == m_lanip && std::string(desc).find("PPSSPP:") != std::string::npos) { + int r2 = UPNP_DeletePortMapping(urls->controlURL, datas->first.servicetype, extPort, protocol, rHost); + if (r2 != 0) + { + ERROR_LOG(SCENET, "PortManager::Clear - DeletePortMapping(%s, %s) failed (error: %i)", extPort, protocol, r2); + if (r2 == UPNPCOMMAND_HTTP_ERROR) + return false; + } + else { + i--; + for (auto it = m_portList.begin(); it != m_portList.end(); ) { + (it->first == extPort && it->second == protocol) ? it = m_portList.erase(it) : ++it; + } + } + } + i++; + } while (r == 0); + return true; +} + +bool PortManager::RefreshPortList() { + int r; + int i = 0; + char index[6]; + char intAddr[40]; + char intPort[6]; + char extPort[6]; + char protocol[4]; + char desc[80]; + char enabled[6]; + char rHost[64]; + char duration[16]; + + INFO_LOG(SCENET, "PortManager::RefreshPortList()"); + if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') + { + if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::RefreshPortList - the init was not done !"); + return false; + } + m_portList.clear(); + m_otherPortList.clear(); + //unsigned int num = 0; + //UPNP_GetPortMappingNumberOfEntries(urls->controlURL, datas->first.servicetype, &num); // Not supported by many routers + do { + snprintf(index, 6, "%d", i); + rHost[0] = '\0'; enabled[0] = '\0'; + duration[0] = '\0'; desc[0] = '\0'; protocol[0] = '\0'; + extPort[0] = '\0'; intPort[0] = '\0'; intAddr[0] = '\0'; + r = UPNP_GetGenericPortMappingEntry(urls->controlURL, + datas->first.servicetype, + index, + extPort, intAddr, intPort, + protocol, desc, enabled, + rHost, duration); + if (r == 0) { + std::string desc_str = std::string(desc); + // Some router might prefix the description with "UPnP:" so we may need to truncate it to prevent it from getting multiple prefix when restored later + if (desc_str.find("UPnP:") == 0) + desc_str = desc_str.substr(5); + // Only include port mappings created by PPSSPP for current LAN IP + if (intAddr == m_lanip && desc_str.find("PPSSPP:") != std::string::npos) { + m_portList.push_back({ extPort, protocol }); + } + // Port mappings belong to others that might be taken by PPSSPP later + else { + m_otherPortList.push_back({ false, protocol, extPort, intPort, intAddr, rHost, desc_str, duration, enabled }); + } + } + i++; + } while (r == 0); + return true; +} + +int upnpService(const unsigned int timeout) +{ + setCurrentThreadName("UPnPService"); + INFO_LOG(SCENET, "UPnPService: Begin of UPnPService Thread"); + + // Service Loop + while (upnpServiceRunning && coreState != CORE_POWERDOWN) { + // Attempts to reconnect if not connected yet or got disconnected + if (g_Config.bEnableUPnP && g_PortManager.GetInitState() == UPNP_INITSTATE_NONE) { + g_PortManager.Initialize(timeout); + } + + if (g_Config.bEnableUPnP && g_PortManager.GetInitState() == UPNP_INITSTATE_DONE && !upnpReqs.empty()) { + upnpLock.lock(); + UPnPArgs arg = upnpReqs.front(); + upnpLock.unlock(); + + bool ok = true; + switch (arg.cmd) { + case UPNP_CMD_ADD: + ok = g_PortManager.Add(arg.protocol.c_str(), arg.port, arg.intport); + break; + case UPNP_CMD_REMOVE: + ok = g_PortManager.Remove(arg.protocol.c_str(), arg.port); + break; + default: + break; + } + + // It's only considered failed when disconnected (should be retried when reconnected) + if (ok) { + upnpLock.lock(); + upnpReqs.pop_front(); + upnpLock.unlock(); + } + } + + // Sleep for 1ms for faster response + sleep_ms(1); + } + + // Cleaning up regardless of g_Config.bEnableUPnP to prevent lingering open ports on the router + if (g_PortManager.GetInitState() == UPNP_INITSTATE_DONE) { + g_PortManager.Clear(); + g_PortManager.Restore(); + g_PortManager.Terminate(); + } + + // Should we ingore any leftover UPnP requests? instead of processing it on the next game start + upnpLock.lock(); + upnpReqs.clear(); + upnpLock.unlock(); + + INFO_LOG(SCENET, "UPnPService: End of UPnPService Thread"); + return 0; +} + +void __UPnPInit(const unsigned int timeout) { + if (!upnpServiceRunning) { + upnpServiceRunning = true; + upnpServiceThread = std::thread(upnpService, timeout); + } +} + +void __UPnPShutdown() { + if (upnpServiceRunning) { + upnpServiceRunning = false; + if (upnpServiceThread.joinable()) { + upnpServiceThread.join(); + } + } +} + +void UPnP_Add(const char* protocol, unsigned short port, unsigned short intport) { + std::lock_guard upnpGuard(upnpLock); + upnpReqs.push_back({ UPNP_CMD_ADD, protocol, port, intport }); +} + +void UPnP_Remove(const char* protocol, unsigned short port) { + std::lock_guard upnpGuard(upnpLock); + upnpReqs.push_back({ UPNP_CMD_REMOVE, protocol, port, port }); +} + diff --git a/Core/Util/PortManager.h b/Core/Util/PortManager.h new file mode 100644 index 0000000000..a4c7df6c27 --- /dev/null +++ b/Core/Util/PortManager.h @@ -0,0 +1,125 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +// Most of the code are based on https://github.com/RJ/libportfwd and updated to the latest miniupnp library +// All credit goes to him and the official miniupnp project! http://miniupnp.free.fr/ + + +#pragma once + + +#ifndef MINIUPNP_STATICLIB +#define MINIUPNP_STATICLIB +#endif + +#include "ext/miniupnp/miniupnpc/miniwget.h" +#include "ext/miniupnp/miniupnpc/miniupnpc.h" +#include "ext/miniupnp/miniupnpc/upnpcommands.h" + +#include +#include + +#ifdef _MSC_VER +#pragma pack(push,1) +#endif +typedef struct UPnPArgs { + int cmd; + std::string protocol; + unsigned short port; + unsigned short intport; +} PACK; +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +#define IP_PROTOCOL_TCP "TCP" +#define IP_PROTOCOL_UDP "UDP" +#define UPNP_INITSTATE_NONE 0 +#define UPNP_INITSTATE_BUSY 1 +#define UPNP_INITSTATE_DONE 2 + +#define UPNP_CMD_ADD 0 +#define UPNP_CMD_REMOVE 1 + +struct UPNPUrls; +struct IGDdatas; + +struct PortMap { + bool taken; + std::string protocol; + std::string extPort_str; + std::string intPort_str; + std::string lanip; + std::string remoteHost; + std::string desc; + std::string duration; + std::string enabled; +}; + +class PortManager { +public: + PortManager(); + ~PortManager(); + + // Initialize UPnP + // timeout: milliseconds to wait for a router to respond (default = 2000 ms) + bool Initialize(const unsigned int timeout = 2000); + + // Uninitialize/Reset the state + void Terminate(); + + // Get UPnP Initialization status + int GetInitState(); + + // Add a port & protocol (TCP, UDP or vendor-defined) to map for forwarding (intport = 0 : same as [external] port) + bool Add(const char* protocol, unsigned short port, unsigned short intport = 0); + + // Remove a port mapping (external port) + bool Remove(const char* protocol, unsigned short port); + + // Removes any lingering mapped ports created by PPSSPP (including from previous crashes) + bool Clear(); + + // Restore ports mapped by others that were taken by PPSSPP, better used after Clear() + bool Restore(); + + // Retrieves port lists mapped by PPSSPP for current LAN IP & other's applications + bool RefreshPortList(); + +protected: + struct UPNPUrls* urls = NULL; + struct IGDdatas* datas = NULL; + + int m_InitState = UPNP_INITSTATE_NONE; + int m_LocalPort = UPNP_LOCAL_PORT_ANY; + std::string m_lanip; + std::string m_defaultDesc; + std::string m_leaseDuration = "43200"; // range(0-604800) in seconds (0 = Indefinite/permanent). Some routers doesn't support non-zero value + std::deque> m_portList; + std::deque m_otherPortList; +}; + +extern PortManager g_PortManager; + +void __UPnPInit(const unsigned int timeout = 2000); +void __UPnPShutdown(); + +// Add a port & protocol (TCP, UDP or vendor-defined) to map for forwarding (intport = 0 : same as [external] port) +void UPnP_Add(const char* protocol, unsigned short port, unsigned short intport = 0); + +// Remove a port mapping (external port) +void UPnP_Remove(const char* protocol, unsigned short port); diff --git a/Core/WaveFile.cpp b/Core/WaveFile.cpp index 76df969f61..1f4f4bdef4 100644 --- a/Core/WaveFile.cpp +++ b/Core/WaveFile.cpp @@ -1,19 +1,16 @@ // Copyright 2008 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. -#ifndef MOBILE_DEVICE + #include #include "Core/WaveFile.h" -#include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" +#include "Common/Log.h" #include "Core/Config.h" constexpr size_t WaveFileWriter::BUFFER_SIZE; -WaveFileWriter::WaveFileWriter() -{ -} +WaveFileWriter::WaveFileWriter() {} WaveFileWriter::~WaveFileWriter() { @@ -23,19 +20,14 @@ WaveFileWriter::~WaveFileWriter() bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRate) { // Check if the file is already open - if (file) - { - PanicAlert("The file %s was already open, the file header will not be written.", - filename.c_str()); + if (file) { + ERROR_LOG(SYSTEM, "The file %s was already open, the file header will not be written.", filename.c_str()); return false; } file.Open(filename, "wb"); - if (!file) - { - PanicAlert("The file %s could not be opened for writing. Please check if it's already opened " - "by another program.", - filename.c_str()); + if (!file) { + ERROR_LOG(IO, "The file %s could not be opened for writing. Please check if it's already opened by another program.", filename.c_str()); return false; } @@ -52,7 +44,7 @@ bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRa Write(16); // size of fmt block Write(0x00020001); // two channels, uncompressed - const u32 sample_rate = HLESampleRate; + const uint32_t sample_rate = HLESampleRate; Write(sample_rate); Write(sample_rate * 2 * 2); // two channels, 16bit @@ -61,9 +53,8 @@ bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRa Write(100 * 1000 * 1000 - 32); // We are now at offset 44 - if (file.Tell() != 44) - PanicAlert("Wrong offset: %lld", (long long)file.Tell()); - + uint64_t offset = file.Tell(); + _assert_msg_(offset == 44, "Wrong offset: %lld", (long long)offset); return true; } @@ -79,7 +70,7 @@ void WaveFileWriter::Stop() file.Close(); } -void WaveFileWriter::Write(u32 value) +void WaveFileWriter::Write(uint32_t value) { file.WriteArray(&value, 1); } @@ -89,19 +80,16 @@ void WaveFileWriter::Write4(const char* ptr) file.WriteBytes(ptr, 4); } -void WaveFileWriter::AddStereoSamples(const short* sample_data, u32 count) +void WaveFileWriter::AddStereoSamples(const short* sample_data, uint32_t count) { - if (!file) - PanicAlert("WaveFileWriter - file not open."); - - if (count > BUFFER_SIZE * 2) - PanicAlert("WaveFileWriter - buffer too small (count = %u).", count); + _assert_msg_(file, "WaveFileWriter - file not open."); + _assert_msg_(count <= BUFFER_SIZE * 2, "WaveFileWriter - buffer too small (count = %u).", count); if (skip_silence) { bool all_zero = true; - for (u32 i = 0; i < count * 2; i++) + for (uint32_t i = 0; i < count * 2; i++) { if (sample_data[i]) all_zero = false; @@ -114,4 +102,3 @@ void WaveFileWriter::AddStereoSamples(const short* sample_data, u32 count) file.WriteBytes(sample_data, count * 4); audio_size += count * 4; } -#endif diff --git a/Core/WaveFile.h b/Core/WaveFile.h index 39bcf483a4..3ef3f09b4c 100644 --- a/Core/WaveFile.h +++ b/Core/WaveFile.h @@ -11,12 +11,12 @@ // --------------------------------------------------------------------------------- #pragma once -#ifndef MOBILE_DEVICE #include #include -#include "Common/CommonTypes.h" -#include "Common/FileUtil.h" +#include + +#include "Common/File/FileUtil.h" class WaveFileWriter { @@ -28,18 +28,15 @@ public: void Stop(); void SetSkipSilence(bool skip) { skip_silence = skip; } - void AddStereoSamples(const short* sample_data, u32 count); - u32 GetAudioSize() const { return audio_size; } + void AddStereoSamples(const short* sample_data, uint32_t count); + uint32_t GetAudioSize() const { return audio_size; } private: static constexpr size_t BUFFER_SIZE = 32 * 1024; File::IOFile file; bool skip_silence = false; - u32 audio_size = 0; + uint32_t audio_size = 0; std::array conv_buffer{}; - void Write(u32 value); + void Write(uint32_t value); void Write4(const char* ptr); }; - -#endif - diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp index eab106add0..9e96baf9f8 100644 --- a/Core/WebServer.cpp +++ b/Core/WebServer.cpp @@ -18,16 +18,16 @@ #include #include #include -#include -#include "base/stringutil.h" -#include "base/timeutil.h" -#include "file/fd_util.h" -#include "net/http_client.h" -#include "net/http_server.h" -#include "net/sinks.h" -#include "thread/threadutil.h" -#include "Common/FileUtil.h" + +#include "Common/Net/HTTPClient.h" +#include "Common/Net/HTTPServer.h" +#include "Common/Net/Sinks.h" +#include "Common/Thread/ThreadUtil.h" #include "Common/Log.h" +#include "Common/File/FileUtil.h" +#include "Common/File/FileDescriptor.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Debugger/WebSocket.h" #include "Core/WebServer.h" @@ -257,11 +257,11 @@ static void ExecuteWebServer() { g_Config.iRemoteISOPort = http->Port(); RegisterServer(http->Port()); - double lastRegister = real_time_now(); + double lastRegister = time_now_d(); while (RetrieveStatus() == ServerStatus::RUNNING) { http->RunSlice(1.0); - double now = real_time_now(); + double now = time_now_d(); if (now > lastRegister + 540.0) { RegisterServer(http->Port()); lastRegister = now; diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index a5e9bc0e5e..23b662c672 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -17,10 +17,11 @@ #include -#include "gfx_es2/gpu_features.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderCommon.h" +#include "Common/StringUtils.h" #include "Common/Log.h" #include "Core/Reporting.h" #include "GPU/GPUState.h" @@ -45,6 +46,14 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang WRITE(p, "layout(set = 0, binding = 1) uniform sampler2D pal;\n"); WRITE(p, "layout(location = 0) in vec2 v_texcoord0;\n"); WRITE(p, "layout(location = 0) out vec4 fragColor0;\n"); + + // Support for depth. + if (pixelFormat == GE_FORMAT_DEPTH16) { + WRITE(p, "layout (push_constant) uniform params {\n"); + WRITE(p, " float z_scale; float z_offset;\n"); + WRITE(p, "};\n"); + } + } else { if (gl_extensions.IsGLES) { WRITE(p, "#version 300 es\n"); @@ -63,7 +72,6 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang WRITE(p, "float4 main(in float2 v_texcoord0 : TEXCOORD0) : SV_Target {\n"); WRITE(p, " float4 color = tex.Sample(texSamp, v_texcoord0);\n"); } else { - // TODO: Add support for integer textures. Though it hardly matters. WRITE(p, "void main() {\n"); WRITE(p, " vec4 color = texture(tex, v_texcoord0);\n"); } @@ -72,10 +80,20 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang int shift = gstate.getClutIndexShift(); int offset = gstate.getClutIndexStartPos(); GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); - // Unfortunately sampling turned our texture into floating point. To avoid this, might be able + + // Sampling turns our texture into floating point. To avoid this, might be able // to declare them as isampler2D objects, but these require integer textures, which needs more work. - // Anyhow, we simply work around this by converting back to integer. Hopefully there will be no loss of precision. + // Anyhow, we simply work around this by converting back to integer, which is fine. // Use the mask to skip reading some components. + + // TODO: Since we actually have higher precision color data here, we might want to apply a dithering pattern here + // in the 5551, 565 and 4444 modes. This would benefit Test Drive which renders at 16-bit on the real hardware + // and dithers immediately, while we render at higher color depth and thus don't dither resulting in banding + // when we sample it at low color depth like this. + + // An alternative would be to have a special mode where we keep some extra precision here and sample the CLUT linearly - works for ramps such + // as those that Test Drive uses for its color remapping. But would need game specific flagging. + int shiftedMask = mask << shift; switch (pixelFormat) { case GE_FORMAT_8888: @@ -105,6 +123,11 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang if (shiftedMask & 0x8000) WRITE(p, " int a = int(color.a);\n"); else WRITE(p, " int a = 0;\n"); WRITE(p, " int index = (a << 15) | (b << 10) | (g << 5) | (r);\n"); break; + case GE_FORMAT_DEPTH16: + // Remap depth buffer. + WRITE(p, " float depth = (color.x - z_offset) * z_scale;\n"); + WRITE(p, " int index = int(clamp(depth, 0.0, 65535.0));\n"); + break; default: break; } @@ -225,6 +248,17 @@ void GenerateDepalShaderFloat(char *buffer, GEBufferFormat pixelFormat, ShaderLa formatOK = false; } break; + case GE_FORMAT_DEPTH16: + { + // TODO: I think we can handle most scenarios here, but texturing from depth buffers requires an extension on ES 2.0 anyway. + if ((mask & (mask + 1)) == 0 && shift < 16) { + index_multiplier = 1.0f / (float)(1 << shift); + truncate_cpy(lookupMethod, "index.r"); + } else { + formatOK = false; + } + break; + } default: break; } @@ -292,7 +326,7 @@ void GenerateDepalShader(char *buffer, GEBufferFormat pixelFormat, ShaderLanguag break; case HLSL_D3D11_LEVEL9: default: - _assert_msg_(G3D, false, "Depal shader language not supported: %d", (int)language); + _assert_msg_(false, "Depal shader language not supported: %d", (int)language); } } diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index bcd8a41e29..bb554d1c38 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -17,13 +17,12 @@ #include -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Common/ColorConv.h" #include "Core/Config.h" #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/SplineCommon.h" #include "GPU/Common/VertexDecoderCommon.h" -#include "GPU/Common/TextureDecoder.h" // for ReliableHash #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -103,7 +102,7 @@ void DrawEngineCommon::DecodeVerts(u8 *dest) { if (indexGen.Prim() < 0) { ERROR_LOG_REPORT(G3D, "DecodeVerts: Failed to deduce prim: %i", indexGen.Prim()); // Force to points (0) - indexGen.AddPrim(GE_PRIM_POINTS, 0); + indexGen.AddPrim(GE_PRIM_POINTS, 0, true); } } @@ -607,7 +606,7 @@ inline u32 ComputeMiniHashRange(const void *ptr, size_t sz) { size_t step = sz / 4; u32 hash = 0; for (size_t i = 0; i < sz; i += step) { - hash += DoReliableHash32(p + i, 100, 0x3A44B9C4); + hash += XXH3_64bits(p + i, 100); } return hash; } else { @@ -642,8 +641,8 @@ u32 DrawEngineCommon::ComputeMiniHash() { return fullhash; } -ReliableHashType DrawEngineCommon::ComputeHash() { - ReliableHashType fullhash = 0; +uint64_t DrawEngineCommon::ComputeHash() { + uint64_t fullhash = 0; const int vertexSize = dec_->GetDecVtxFmt().stride; const int indexSize = IndexSize(dec_->VertexType()); @@ -652,7 +651,7 @@ ReliableHashType DrawEngineCommon::ComputeHash() { for (int i = 0; i < numDrawCalls; i++) { const DeferredDrawCall &dc = drawCalls[i]; if (!dc.inds) { - fullhash += DoReliableHash((const char *)dc.verts, vertexSize * dc.vertexCount, 0x1DE8CAC4); + fullhash += XXH3_64bits((const char *)dc.verts, vertexSize * dc.vertexCount); } else { int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound; int j = i + 1; @@ -667,15 +666,15 @@ ReliableHashType DrawEngineCommon::ComputeHash() { } // This could get seriously expensive with sparse indices. Need to combine hashing ranges the same way // we do when drawing. - fullhash += DoReliableHash((const char *)dc.verts + vertexSize * indexLowerBound, - vertexSize * (indexUpperBound - indexLowerBound), 0x029F3EE1); + fullhash += XXH3_64bits((const char *)dc.verts + vertexSize * indexLowerBound, + vertexSize * (indexUpperBound - indexLowerBound)); // Hm, we will miss some indices when combining above, but meh, it should be fine. - fullhash += DoReliableHash((const char *)dc.inds, indexSize * dc.vertexCount, 0x955FD1CA); + fullhash += XXH3_64bits((const char *)dc.inds, indexSize * dc.vertexCount); i = lastMatch; } } - fullhash += DoReliableHash(&drawCalls[0].uvScale, sizeof(drawCalls[0].uvScale) * numDrawCalls, 0x0123e658); + fullhash += XXH3_64bits(&drawCalls[0].uvScale, sizeof(drawCalls[0].uvScale) * numDrawCalls); return fullhash; } @@ -699,6 +698,8 @@ void DrawEngineCommon::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, } *bytesRead = vertexCount * dec_->VertexSize(); + + // Check that we have enough vertices to form the requested primitive. if ((vertexCount < 2 && prim > 0) || (vertexCount < 3 && prim > 2 && prim != GE_PRIM_RECTANGLES)) return; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 6bc34f10ac..f53b96f487 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -18,10 +18,9 @@ #pragma once #include -#include #include "Common/CommonTypes.h" -#include "Common/Hashmaps.h" +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/GPUState.h" #include "GPU/Common/GPUDebugInterface.h" @@ -36,13 +35,6 @@ enum { DECODED_INDEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * 16, }; -// Avoiding the full include of TextureDecoder.h. -#if (defined(_M_SSE) && defined(_M_X64)) || defined(ARM64) -typedef u64 ReliableHashType; -#else -typedef u32 ReliableHashType; -#endif - inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it // into the top of the verttype where there are unused bits. @@ -115,7 +107,7 @@ protected: // Utility for vertex caching u32 ComputeMiniHash(); - ReliableHashType ComputeHash(); + uint64_t ComputeHash(); // Vertex decoding void DecodeVertsStep(u8 *dest, int &i, int &decodedVerts); diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp similarity index 87% rename from GPU/Common/FramebufferCommon.cpp rename to GPU/Common/FramebufferManagerCommon.cpp index 70a8ff0e52..892297c7b8 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -17,23 +17,21 @@ #include #include -#include #include -#include "ext/native/thin3d/thin3d.h" -#include "gfx_es2/gpu_features.h" - -#include "i18n/i18n.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Data/Text/I18n.h" #include "Common/ColorConv.h" #include "Common/Common.h" #include "Core/Config.h" #include "Core/ConfigValues.h" +#include "Core/Core.h" #include "Core/CoreParameter.h" #include "Core/Host.h" #include "Core/Reporting.h" -#include "Core/System.h" #include "GPU/Common/DrawEngineCommon.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PostShader.h" #include "GPU/Common/PresentationCommon.h" #include "GPU/Common/TextureCacheCommon.h" @@ -152,16 +150,17 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma drawing_width = scissor_width; drawing_height = std::max(drawing_height, scissor_height); } - if (scissor_width == 481 && region_width == 480 && scissor_height == 273 && region_height == 272) { - drawing_width = 480; - drawing_height = 272; - } } else { // If viewport wasn't valid, let's just take the greatest anything regardless of stride. drawing_width = std::min(std::max(region_width, scissor_width), fb_stride); drawing_height = std::max(region_height, scissor_height); } + if (scissor_width == 481 && region_width == 480 && scissor_height == 273 && region_height == 272) { + drawing_width = 480; + drawing_height = 272; + } + // Assume no buffer is > 512 tall, it couldn't be textured or displayed fully if so. if (drawing_height >= MAX_FRAMEBUF_HEIGHT) { if (region_height < MAX_FRAMEBUF_HEIGHT) { @@ -207,6 +206,13 @@ void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPU params->z_address = (gstate.getDepthBufRawAddress() & 0x3FFFFFFF) | 0x04000000; params->z_stride = gstate.DepthBufStride(); + if (params->z_address == params->fb_address) { + // Probably indicates that the game doesn't care about Z for this VFB. + // Let's avoid matching it for Z copies and other shenanigans. + params->z_address = 0; + params->z_stride = 0; + } + params->fmt = gstate.FrameBufFormat(); params->isClearingDepth = gstate.isModeClear() && gstate.isClearModeDepthMask(); @@ -267,7 +273,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->format = params.fmt; } - if (vfb->z_address == 0 && vfb->z_stride == 0) { + if (vfb->z_address == 0 && vfb->z_stride == 0 && params.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); @@ -371,7 +377,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame ResizeFramebufFBO(vfb, drawing_width, drawing_height, true); NotifyRenderFramebufferCreated(vfb); - INFO_LOG(FRAMEBUF, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format); + INFO_LOG(FRAMEBUF, "Creating FBO for %08x (z: %08x) : %i x %i x %i", vfb->fb_address, vfb->z_address, vfb->width, vfb->height, vfb->format); vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed_ = gpuStats.numFlips; @@ -380,7 +386,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) { gpu->PerformMemoryUpload(params.fb_address, byteSize); - NotifyStencilUpload(params.fb_address, byteSize, true); + NotifyStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO); // TODO: Is it worth trying to upload the depth buffer? } @@ -404,7 +410,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // This happens a lot, but virtually always it's cleared. // It's possible the other might not clear, but when every game is reported it's not useful. if (params.isWritingDepth) { - WARN_LOG(SCEGE, "FBO reusing depthbuffer, %08x/%08x and %08x/%08x", params.fb_address, params.z_address, vfbs_[i]->fb_address, vfbs_[i]->z_address); + WARN_LOG(SCEGE, "FBO reusing depthbuffer, c=%08x/d=%08x and c=%08x/d=%08x", params.fb_address, params.z_address, vfbs_[i]->fb_address, vfbs_[i]->z_address); sharingReported = true; } } @@ -413,7 +419,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // We already have it! } else if (vfb != currentRenderVfb_) { // Use it as a render target. - DEBUG_LOG(FRAMEBUF, "Switching render target to FBO for %08x: %i x %i x %i ", vfb->fb_address, vfb->width, vfb->height, vfb->format); + DEBUG_LOG(FRAMEBUF, "Switching render target to FBO for %08x: %d x %d x %d ", vfb->fb_address, vfb->width, vfb->height, vfb->format); vfb->usageFlags |= FB_USAGE_RENDERTARGET; vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed_ = gpuStats.numFlips; @@ -442,7 +448,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame } void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) { - textureCache_->NotifyFramebuffer(v->fb_address, v, NOTIFY_FB_DESTROYED); + // Notify the texture cache of both the color and depth buffers. + textureCache_->NotifyFramebuffer(v, NOTIFY_FB_DESTROYED); if (v->fbo) { v->fbo->Release(); v->fbo = nullptr; @@ -450,17 +457,32 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) { // Wipe some pointers if (currentRenderVfb_ == v) - currentRenderVfb_ = 0; + currentRenderVfb_ = nullptr; if (displayFramebuf_ == v) - displayFramebuf_ = 0; + displayFramebuf_ = nullptr; if (prevDisplayFramebuf_ == v) - prevDisplayFramebuf_ = 0; + prevDisplayFramebuf_ = nullptr; if (prevPrevDisplayFramebuf_ == v) - prevPrevDisplayFramebuf_ = 0; + prevPrevDisplayFramebuf_ = nullptr; delete v; } +void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { + int w = std::min(src->renderWidth, dst->renderWidth); + int h = std::min(src->renderHeight, dst->renderHeight); + + // Note: We prefer Blit ahead of Copy here, since at least on GL, Copy will always also copy stencil which we don't want. See #9740. + if (gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT)) { + draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth"); + RebindFramebuffer("BlitFramebufferDepth"); + } else if (gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) { + draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, w, h, 1, Draw::FB_DEPTH_BIT, "BlitFramebufferDepth"); + RebindFramebuffer("BlitFramebufferDepth"); + } + dst->last_frame_depth_updated = gpuStats.numFlips; +} + void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) { if (!useBufferedRendering_) { // Let's ignore rendering to targets that have not (yet) been displayed. @@ -469,9 +491,9 @@ void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer DownloadFramebufferOnSwitch(currentRenderVfb_); } - textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); + textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED); - // ugly... + // Ugly... if (gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) { gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE); } @@ -483,7 +505,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged) { if (vfbFormatChanged) { - textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_UPDATED); + textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_UPDATED); if (vfb->drawnFormat != vfb->format) { ReformatFramebufferFrom(vfb, vfb->drawnFormat); } @@ -501,7 +523,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) { if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) { - ReadFramebufferToMemory(vfb, true, 0, 0, vfb->width, vfb->height); + ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->firstFrameSaved = true; } else { @@ -510,14 +532,20 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe textureCache_->ForgetLastTexture(); shaderManager_->DirtyLastShader(); - // Copy depth pixel value from the read framebuffer to the draw framebuffer if (prevVfb) { + // Copy depth value from the previously bound framebuffer to the current one. + // We check that the address is the same within BlitFramebufferDepth before actually blitting. + 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. // This is an optimization: it probably doesn't need to be copied in this case. } else { - BlitFramebufferDepth(prevVfb, vfb); + bool matchingDepthBuffer = prevVfb->z_address == vfb->z_address && prevVfb->z_stride != 0 && vfb->z_stride != 0; + bool matchingSize = prevVfb->width == vfb->width && prevVfb->height == vfb->height; + if (matchingDepthBuffer && matchingSize) { + BlitFramebufferDepth(prevVfb, vfb); + } } } if (vfb->drawnFormat != vfb->format) { @@ -528,20 +556,19 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe if (useBufferedRendering_) { if (vfb->fbo) { shaderManager_->DirtyLastShader(); - if (gl_extensions.IsGLES) { - // Some tiled mobile GPUs benefit IMMENSELY from clearing an FBO before rendering - // to it. This broke stuff before, so now it only clears on the first use of an - // FBO in a frame. This means that some games won't be able to avoid the on-some-GPUs - // performance-crushing framebuffer reloads from RAM, but we'll have to live with that. + if (g_Config.bClearFramebuffersOnFirstUseHack) { + // HACK: Some tiled mobile GPUs benefit IMMENSELY from clearing an FBO before rendering + // to it (or in Vulkan, clear during framebuffer load). This is a hack to force this + // the first time a framebuffer is bound for rendering in a frame. + // + // Quite unsafe as it might kill some feedback effects. if (vfb->last_frame_render != gpuStats.numFlips) { - 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); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "FramebufferSwitch"); } else { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "FramebufferSwitch"); } } else { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "FramebufferSwitch"); } } else { // This should only happen very briefly when toggling useBufferedRendering_. @@ -550,7 +577,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe } else { if (vfb->fbo) { // This should only happen very briefly when toggling useBufferedRendering_. - textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_DESTROYED); + textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_DESTROYED); vfb->fbo->Release(); vfb->fbo = nullptr; } @@ -562,9 +589,9 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe gstate_c.skipDrawReason |= SKIPDRAW_NON_DISPLAYED_FB; } } - textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_UPDATED); + textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_UPDATED); - // ugly... + // ugly... is all this needed? if (gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) { gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE); } @@ -635,7 +662,7 @@ void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size, bool safe) { } } - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - UpdateFromMemory"); } // TODO: Necessary? gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); @@ -650,18 +677,21 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int DrawTextureFlags flags; if (useBufferedRendering_ && vfb && vfb->fbo) { flags = DRAWTEX_LINEAR; - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "DrawPixels"); + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); SetViewport2D(0, 0, vfb->renderWidth, vfb->renderHeight); draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight); } else { - // We are drawing to the back buffer so need to flip. + // We are drawing directly to the back buffer so need to flip. + // Should more of this be handled by the presentation engine? if (needBackBufferYSwap_) std::swap(v0, v1); flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST; flags = flags | DRAWTEX_TO_BACKBUFFER; - float x, y, w, h; - CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL); - SetViewport2D(x, y, w, h); + FRect frame = GetScreenFrame(pixelWidth_, pixelHeight_); + FRect rc; + CenterDisplayOutputRect(&rc, 480.0f, 272.0f, frame, ROTATION_LOCKED_HORIZONTAL); + SetViewport2D(rc.x, rc.y, rc.w, rc.h); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); } @@ -672,8 +702,9 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); gpuStats.numUploads++; pixelsTex->Release(); + draw_->InvalidateCachedState(); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); } } @@ -744,7 +775,8 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G break; case GE_FORMAT_INVALID: - _dbg_assert_msg_(G3D, false, "Invalid pixelFormat passed to DrawPixels()."); + case GE_FORMAT_DEPTH16: + _dbg_assert_msg_(false, "Invalid pixelFormat passed to DrawPixels()."); break; } } @@ -807,7 +839,7 @@ void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *v // To support this, we save the first frame to memory when we have a safe w/h. // Saving each frame would be slow. if (!g_Config.bDisableSlowFramebufEffects) { - ReadFramebufferToMemory(vfb, true, 0, 0, vfb->safeWidth, vfb->safeHeight); + ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->firstFrameSaved = true; vfb->safeWidth = 0; @@ -828,15 +860,15 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { currentRenderVfb_ = 0; if (displayFramebufPtr_ == 0) { - if (coreState == CORE_STEPPING) + if (Core_IsStepping()) VERBOSE_LOG(FRAMEBUF, "Display disabled, displaying only black"); else DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); // No framebuffer to display! Clear to black. if (useBufferedRendering_) { - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput"); } - gstate_c.Dirty(DIRTY_BLEND_STATE); + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); return; } @@ -876,7 +908,8 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { if (vfb) { // Okay, we found one above. - INFO_LOG_REPORT_ONCE(displayoffset, HLE, "Rendering from framebuf with offset %08x -> %08x+%dx%d", addr, vfb->fb_address, offsetX, offsetY); + // Log should be "Displaying from framebuf" but not worth changing the report. + INFO_LOG_REPORT_ONCE(displayoffset, FRAMEBUF, "Rendering from framebuf with offset %08x -> %08x+%dx%d", addr, vfb->fb_address, offsetX, offsetY); } } @@ -893,15 +926,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { if (Memory::IsValidAddress(fbaddr)) { // The game is displaying something directly from RAM. In GTA, it's decoded video. if (!vfb) { - if (useBufferedRendering_) { - // Bind and clear the backbuffer. This should be the first time during the frame that it's bound. - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); - } - // Just a pointer to plain memory to draw. We should create a framebuffer, then draw to it. - SetViewport2D(0, 0, pixelWidth_, pixelHeight_); - draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); DrawFramebufferToOutput(Memory::GetPointer(fbaddr), displayFormat_, displayStride_); - gstate_c.Dirty(DIRTY_BLEND_STATE); return; } } else { @@ -909,9 +934,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { // No framebuffer to display! Clear to black. if (useBufferedRendering_) { // Bind and clear the backbuffer. This should be the first time during the frame that it's bound. - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO"); } - gstate_c.Dirty(DIRTY_BLEND_STATE); + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); return; } } @@ -930,7 +955,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { displayFramebuf_ = vfb; if (vfb->fbo) { - if (coreState == CORE_STEPPING) + if (Core_IsStepping()) VERBOSE_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); else DEBUG_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); @@ -981,8 +1006,7 @@ void FramebufferManagerCommon::DecimateFBOs() { int age = frameLastFramebufUsed_ - std::max(vfb->last_frame_render, vfb->last_frame_used); if (ShouldDownloadFramebuffer(vfb) && age == 0 && !vfb->memoryUpdated) { - bool sync = gl_extensions.IsGLES; - ReadFramebufferToMemory(vfb, sync, 0, 0, vfb->width, vfb->height); + ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->firstFrameSaved = true; } @@ -1022,8 +1046,8 @@ void FramebufferManagerCommon::DecimateFBOs() { } void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, int h, bool force, bool skipCopy) { - assert(w > 0); - assert(h > 0); + _dbg_assert_(w > 0); + _dbg_assert_(h > 0); VirtualFramebuffer old = *vfb; int oldWidth = vfb->bufferWidth; @@ -1064,29 +1088,27 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } shaderManager_->DirtyLastShader(); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth }); + char tag[256]; + snprintf(tag, sizeof(tag), "%08x_%08x_%dx%d", vfb->fb_address, vfb->z_address, w, h); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth, tag }); if (old.fbo) { - INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %d x %d x %d", vfb->fb_address, w, h, vfb->format); + INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->format)); if (vfb->fbo) { - 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); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); 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); } } fbosToDelete_.push_back(old.fbo); if (needGLESRebinds_) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO"); } } else { - 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); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); } if (!vfb->fbo) { - ERROR_LOG(FRAMEBUF, "Error creating FBO! %i x %i", vfb->renderWidth, vfb->renderHeight); + ERROR_LOG(FRAMEBUF, "Error creating FBO during resize! %dx%d", vfb->renderWidth, vfb->renderHeight); vfb->last_frame_failed = gpuStats.numFlips; } } @@ -1170,34 +1192,34 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, if (dstBuffer && srcBuffer && !isMemset) { if (srcBuffer == dstBuffer) { - WARN_LOG_REPORT_ONCE(dstsrccpy, G3D, "Intra-buffer memcpy (not supported) %08x -> %08x", src, dst); + WARN_LOG_ONCE(dstsrccpy, G3D, "Intra-buffer memcpy (not supported) %08x -> %08x (size: %x)", src, dst, size); } else { - WARN_LOG_REPORT_ONCE(dstnotsrccpy, G3D, "Inter-buffer memcpy %08x -> %08x", src, dst); + WARN_LOG_ONCE(dstnotsrccpy, G3D, "Inter-buffer memcpy %08x -> %08x (size: %x)", src, dst, size); // Just do the blit! BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0); SetColorUpdated(dstBuffer, skipDrawReason); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - Inter-buffer memcpy"); } return false; } else if (dstBuffer) { if (isMemset) { gpuStats.numClears++; } - WARN_LOG_ONCE(btucpy, G3D, "Memcpy fbo upload %08x -> %08x", src, dst); + WARN_LOG_ONCE(btucpy, G3D, "Memcpy fbo upload %08x -> %08x (size: %x)", src, dst, size); FlushBeforeCopy(); const u8 *srcBase = Memory::GetPointerUnchecked(src); DrawPixels(dstBuffer, 0, dstY, srcBase, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstH); SetColorUpdated(dstBuffer, skipDrawReason); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - Memcpy fbo upload"); // 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); FlushBeforeCopy(); if (srcH == 0 || srcY + srcH > srcBuffer->bufferHeight) { - WARN_LOG_REPORT_ONCE(btdcpyheight, G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight); + WARN_LOG_ONCE(btdcpyheight, G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight); } else if (g_Config.bBlockTransferGPU && !srcBuffer->memoryUpdated && !PSP_CoreParameter().compat.flags().DisableReadbacks) { - ReadFramebufferToMemory(srcBuffer, true, 0, srcY, srcBuffer->width, srcH); + ReadFramebufferToMemory(srcBuffer, 0, srcY, srcBuffer->width, srcH); srcBuffer->usageFlags = (srcBuffer->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; } return false; @@ -1288,10 +1310,20 @@ 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.. + if (srcBuffer && !dstBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) { + GEBufferFormat ramFormat; + // Try to guess the appropriate format. We only know the bpp from the block transfer command (16 or 32 bit). + if (bpp == 4) { + // Only one possibility unless it's doing split pixel tricks (which we could detect through stride maybe). + ramFormat = GE_FORMAT_8888; + } else if (srcBuffer->format != GE_FORMAT_8888) { + // We guess that the game will interpret the data the same as it was in the source of the copy. + // Seems like a likely good guess, and works in Test Drive Unlimited. + ramFormat = srcBuffer->format; + } else { + // No info left - just fall back to something. But this is definitely split pixel tricks. + ramFormat = GE_FORMAT_5551; + } dstBuffer = CreateRAMFramebuffer(dstBasePtr, dstWidth, dstHeight, dstStride, ramFormat); } @@ -1312,7 +1344,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd float renderWidthFactor = renderWidth_ / 480.0f; float renderHeightFactor = renderHeight_ / 272.0f; - DEBUG_LOG(G3D, "Creating RAM framebuffer at %08x (%dx%d, stride %d, format %d)", fbAddress, width, height, stride, format); + INFO_LOG(G3D, "Creating RAM framebuffer at %08x (%dx%d, stride %d, format %d)", fbAddress, width, height, stride, format); // 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 @@ -1336,8 +1368,10 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd 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 }); + char name[64]; + snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address); + textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth, name }); vfbs_.push_back(vfb); u32 byteSize = ColorBufferByteSize(vfb); @@ -1425,9 +1459,11 @@ bool FramebufferManagerCommon::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb } } - nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, false, (Draw::FBColorDepth)nvfb->colorDepth }); + char name[64]; + snprintf(name, sizeof(name), "download_temp"); + nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, false, (Draw::FBColorDepth)nvfb->colorDepth, name }); if (!nvfb->fbo) { - ERROR_LOG(FRAMEBUF, "Error creating GL FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); + ERROR_LOG(FRAMEBUF, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight); return false; } return true; @@ -1451,7 +1487,7 @@ void FramebufferManagerCommon::ApplyClearToMemory(int x1, int y1, int x2, int y2 case GE_FORMAT_565: ConvertRGBA8888ToRGB565(&clear16, &clearColor, 1); break; case GE_FORMAT_5551: ConvertRGBA8888ToRGBA5551(&clear16, &clearColor, 1); break; case GE_FORMAT_4444: ConvertRGBA8888ToRGBA4444(&clear16, &clearColor, 1); break; - default: _dbg_assert_(G3D, 0); break; + default: _dbg_assert_(0); break; } clearBits = clear16 | (clear16 << 16); } @@ -1562,10 +1598,13 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst if (dstBuffer && srcBuffer) { if (srcBuffer == dstBuffer) { if (srcX != dstX || srcY != dstY) { - WARN_LOG_ONCE(dstsrc, G3D, "Intra-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr); + WARN_LOG_N_TIMES(dstsrc, 100, G3D, "Intra-buffer block transfer %08x (x:%d y:%d stride:%d) -> %08x (x:%d y:%d stride:%d) (%dx%d %dbpp)", + srcBasePtr, srcX, srcY, srcStride, + dstBasePtr, dstX, dstY, dstStride, + width, height, bpp); FlushBeforeCopy(); BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp); - RebindFramebuffer(); + RebindFramebuffer("rebind after intra block transfer"); SetColorUpdated(dstBuffer, skipDrawReason); return true; } else { @@ -1573,11 +1612,14 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst return true; } } else { - WARN_LOG_ONCE(dstnotsrc, G3D, "Inter-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr); + WARN_LOG_N_TIMES(dstnotsrc, 100, G3D, "Inter-buffer block transfer %08x (x:%d y:%d stride:%d) -> %08x (x:%d y:%d stride:%d) (%dx%d %dbpp)", + srcBasePtr, srcX, srcY, srcStride, + dstBasePtr, dstX, dstY, dstStride, + width, height, bpp); // Just do the blit! FlushBeforeCopy(); BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - Inter-buffer block transfer"); SetColorUpdated(dstBuffer, skipDrawReason); return true; // No need to actually do the memory copy behind, probably. } @@ -1586,7 +1628,10 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst // Here we should just draw the pixels into the buffer. Copy first. return false; } else if (srcBuffer) { - WARN_LOG_ONCE(btd, G3D, "Block transfer download %08x -> %08x", srcBasePtr, dstBasePtr); + WARN_LOG_N_TIMES(btd, 100, G3D, "Block transfer readback %08x (x:%d y:%d stride:%d) -> %08x (x:%d y:%d stride:%d) (%dx%d %dbpp)", + srcBasePtr, srcX, srcY, srcStride, + dstBasePtr, dstX, dstY, dstStride, + width, height, bpp); FlushBeforeCopy(); if (g_Config.bBlockTransferGPU && !srcBuffer->memoryUpdated) { const int srcBpp = srcBuffer->format == GE_FORMAT_8888 ? 4 : 2; @@ -1595,9 +1640,10 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst if (srcHeight <= 0 || (tooTall && srcY != 0)) { WARN_LOG_ONCE(btdheight, G3D, "Block transfer download %08x -> %08x skipped, %d+%d is taller than %d", srcBasePtr, dstBasePtr, srcY, srcHeight, srcBuffer->bufferHeight); } else { - if (tooTall) + if (tooTall) { WARN_LOG_ONCE(btdheight, G3D, "Block transfer download %08x -> %08x dangerous, %d+%d is taller than %d", srcBasePtr, dstBasePtr, srcY, srcHeight, srcBuffer->bufferHeight); - ReadFramebufferToMemory(srcBuffer, true, static_cast(srcX * srcXFactor), srcY, static_cast(srcWidth * srcXFactor), srcHeight); + } + ReadFramebufferToMemory(srcBuffer, static_cast(srcX * srcXFactor), srcY, static_cast(srcWidth * srcXFactor), srcHeight); srcBuffer->usageFlags = (srcBuffer->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; } } @@ -1654,7 +1700,7 @@ void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstS } DrawPixels(dstBuffer, static_cast(dstX * dstXFactor), dstY, srcBase, dstBuffer->format, static_cast(srcStride * dstXFactor), static_cast(dstWidth * dstXFactor), dstHeight); SetColorUpdated(dstBuffer, skipDrawReason); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - NotifyBlockTransferAfter"); } } } @@ -1691,8 +1737,8 @@ void FramebufferManagerCommon::SetRenderSize(VirtualFramebuffer *vfb) { void FramebufferManagerCommon::SetSafeSize(u16 w, u16 h) { VirtualFramebuffer *vfb = currentRenderVfb_; if (vfb) { - vfb->safeWidth = std::max(vfb->safeWidth, w); - vfb->safeHeight = std::max(vfb->safeHeight, h); + vfb->safeWidth = std::min(vfb->bufferWidth, std::max(vfb->safeWidth, w)); + vfb->safeHeight = std::min(vfb->bufferHeight, std::max(vfb->safeHeight, h)); } } @@ -1742,19 +1788,21 @@ void FramebufferManagerCommon::DestroyAllFBOs() { tempFBOs_.clear(); } -Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h, Draw::FBColorDepth depth) { - u64 key = ((u64)reason << 48) | ((u64)depth << 32) | ((u32)w << 16) | h; +Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h, Draw::FBColorDepth color_depth) { + u64 key = ((u64)reason << 48) | ((u64)color_depth << 32) | ((u32)w << 16) | h; auto it = tempFBOs_.find(key); if (it != tempFBOs_.end()) { it->second.last_frame_used = gpuStats.numFlips; return it->second.fbo; } - textureCache_->ForgetLastTexture(); bool z_stencil = reason == TempFBO::STENCIL; - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, depth }); - if (!fbo) - return fbo; + char name[128]; + snprintf(name, sizeof(name), "temp_fbo_%dx%d%s", w, h, z_stencil ? "_depth" : ""); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, color_depth, name }); + if (!fbo) { + return nullptr; + } const TempFBOInfo info = { fbo, gpuStats.numFlips }; tempFBOs_[key] = info; @@ -1849,12 +1897,12 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB // TODO: Maybe should handle flipY inside CopyFramebufferToMemorySync somehow? bool flipY = (GetGPUBackend() == GPUBackend::OPENGL && !useBufferedRendering_) ? true : false; buffer.Allocate(w, h, GE_FORMAT_8888, flipY); - bool retval = draw_->CopyFramebufferToMemorySync(bound, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w); + bool retval = draw_->CopyFramebufferToMemorySync(bound, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w, "GetFramebuffer"); gpuStats.numReadbacks++; // After a readback we'll have flushed and started over, need to dirty a bunch of things to be safe. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); // We may have blitted to a temp FBO. - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - GetFramebuffer"); return retval; } @@ -1885,11 +1933,11 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT, flipY); } // No need to free on failure, that's the caller's job (it likely will reuse a buffer.) - bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w); + bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w, "GetDepthBuffer"); // After a readback we'll have flushed and started over, need to dirty a bunch of things to be safe. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); // That may have unbound the framebuffer, rebind to avoid crashes when debugging. - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - GetDepthbuffer"); return retval; } @@ -1917,9 +1965,9 @@ bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, G bool flipY = (GetGPUBackend() == GPUBackend::OPENGL && !useBufferedRendering_) ? true : false; // No need to free on failure, the caller/destructor will do that. Usually this is a reused buffer, anyway. buffer.Allocate(w, h, GPU_DBG_FORMAT_8BIT, flipY); - bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_STENCIL_BIT, 0, 0, w,h, Draw::DataFormat::S8, buffer.GetData(), w); + bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_STENCIL_BIT, 0, 0, w,h, Draw::DataFormat::S8, buffer.GetData(), w, "GetStencilbuffer"); // That may have unbound the framebuffer, rebind to avoid crashes when debugging. - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - GetStencilbuffer"); return retval; } @@ -1931,9 +1979,9 @@ bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { if (fmt != Draw::DataFormat::B8G8R8A8_UNORM) fmt = Draw::DataFormat::R8G8B8A8_UNORM; buffer.Allocate(w, h, fmt == Draw::DataFormat::R8G8B8A8_UNORM ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA, false); - bool retval = draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, fmt, buffer.GetData(), w); + bool retval = draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, fmt, buffer.GetData(), w, "GetOutputFramebuffer"); // That may have unbound the framebuffer, rebind to avoid crashes when debugging. - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - GetOutputFramebuffer"); return retval; } @@ -1973,18 +2021,15 @@ void FramebufferManagerCommon::PackFramebufferSync_(VirtualFramebuffer *vfb, int DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr); if (destPtr) { - draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride); + draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride, "PackFramebufferSync_"); } else { ERROR_LOG(G3D, "PackFramebufferSync_: Tried to readback to bad address %08x (stride = %d)", fb_address + dstByteOffset, vfb->fb_stride); } - // A new command buffer will begin after CopyFrameBufferToMemorySync, so we need to trigger - // updates of any dynamic command buffer state by dirtying some stuff. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); gpuStats.numReadbacks++; } -void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) { +void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h) { // Clamp to bufferWidth. Sometimes block transfers can cause this to hit. if (x + w >= vfb->bufferWidth) { w = vfb->bufferWidth - x; @@ -2004,7 +2049,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, } textureCache_->ForgetLastTexture(); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - ReadFramebufferToMemory"); } } @@ -2050,20 +2095,19 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo } textureCache_->ForgetLastTexture(); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - DownloadFramebufferForClut"); } } } -void FramebufferManagerCommon::RebindFramebuffer() { +void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { shaderManager_->DirtyLastShader(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); } else { // Should this even happen? It could while debugging, but maybe we can just skip binding at all. - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad"); } - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); } std::vector FramebufferManagerCommon::GetFramebufferList() { diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferManagerCommon.h similarity index 93% rename from GPU/Common/FramebufferCommon.h rename to GPU/Common/FramebufferManagerCommon.h index bf92ae189d..44cd2f6b5f 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -22,11 +22,12 @@ #include #include "Common/CommonTypes.h" +#include "Common/Log.h" #include "Core/MemMap.h" #include "GPU/GPU.h" #include "GPU/ge_constants.h" #include "GPU/GPUInterface.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" enum { FB_USAGE_DISPLAYED_FRAMEBUFFER = 1, @@ -49,32 +50,22 @@ namespace Draw { class VulkanFBO; struct VirtualFramebuffer { - int last_frame_used; - int last_frame_attached; - int last_frame_render; - int last_frame_displayed; - int last_frame_clut; - int last_frame_failed; - int last_frame_depth_updated; - int last_frame_depth_render; - u32 clutUpdatedBytes; - bool memoryUpdated; - bool firstFrameSaved; - u32 fb_address; u32 z_address; // If 0, it's a "RAM" framebuffer. int fb_stride; int z_stride; - // There's also a top left of the drawing region, but meh... + GEBufferFormat format; // virtual, right now they are all RGBA8888 - // width/height: The detected size of the current framebuffer. + // width/height: The detected size of the current framebuffer, in original PSP pixels. u16 width; u16 height; + // renderWidth/renderHeight: The scaled size we render at. May be scaled to render at higher resolutions. // The physical buffer may be larger than renderWidth/renderHeight. u16 renderWidth; u16 renderHeight; + // bufferWidth/bufferHeight: The pre-scaling size of the buffer itself. May only be bigger than width/height. // Actual physical buffer is this size times the render resolution multiplier. // The buffer may be used to render a width or height from 0 to these values without being recreated. @@ -87,8 +78,6 @@ struct VirtualFramebuffer { u16 newHeight; int lastFrameNewSize; - GEBufferFormat format; // virtual, right now they are all RGBA8888 - // TODO: Handle fbo and colorDepth better. u8 colorDepth; Draw::Framebuffer *fbo; @@ -101,6 +90,18 @@ struct VirtualFramebuffer { bool dirtyAfterDisplay; bool reallyDirtyAfterDisplay; // takes frame skipping into account + + int last_frame_used; + int last_frame_attached; + int last_frame_render; + int last_frame_displayed; + int last_frame_clut; + int last_frame_failed; + int last_frame_depth_updated; + int last_frame_depth_render; + u32 clutUpdatedBytes; + bool memoryUpdated; + bool firstFrameSaved; }; struct FramebufferHeuristicParams { @@ -146,6 +147,11 @@ inline DrawTextureFlags operator | (const DrawTextureFlags &lhs, const DrawTextu return DrawTextureFlags((u32)lhs | (u32)rhs); } +enum class StencilUpload { + NEEDS_CLEAR, + STENCIL_IS_ZERO, +}; + enum class TempFBO { DEPAL, BLIT, @@ -182,7 +188,7 @@ class TextureCacheCommon; class FramebufferManagerCommon { public: - FramebufferManagerCommon(Draw::DrawContext *draw); + explicit FramebufferManagerCommon(Draw::DrawContext *draw); virtual ~FramebufferManagerCommon(); virtual void Init(); @@ -205,12 +211,12 @@ public: FramebufferHeuristicParams inputs; GetFramebufferHeuristicInputs(&inputs, gstate); VirtualFramebuffer *vfb = DoSetRenderFrameBuffer(inputs, skipDrawReason); - _dbg_assert_msg_(G3D, vfb, "DoSetRenderFramebuffer must return a valid framebuffer."); - _dbg_assert_msg_(G3D, currentRenderVfb_, "DoSetRenderFramebuffer must set a valid framebuffer."); + _dbg_assert_msg_(vfb, "DoSetRenderFramebuffer must return a valid framebuffer."); + _dbg_assert_msg_(currentRenderVfb_, "DoSetRenderFramebuffer must set a valid framebuffer."); return vfb; } } - void RebindFramebuffer(); + void RebindFramebuffer(const char *tag); std::vector GetFramebufferList(); void CopyDisplayToOutput(bool reallyDirty); @@ -219,14 +225,14 @@ public: void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt); void UpdateFromMemory(u32 addr, int size, bool safe); void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor); - virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) = 0; + virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) = 0; // Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it. // In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless // read framebuffers is on, in which case this should always return false). bool NotifyBlockTransferBefore(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason); void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason); - void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h); + void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h); void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes); void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride); @@ -306,6 +312,10 @@ public: virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer); virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer); + const std::vector &Framebuffers() { + return vfbs_; + } + protected: virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h); void SetViewport2D(int x, int y, int w, int h); @@ -330,7 +340,7 @@ protected: void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth); virtual void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) = 0; - virtual void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) = 0; + void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst); void ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, int h, bool force = false, bool skipCopy = false); void ShowScreenResolution(); @@ -347,7 +357,7 @@ protected: void UpdateFramebufUsage(VirtualFramebuffer *vfb); - void SetColorUpdated(VirtualFramebuffer *dstBuffer, int skipDrawReason) { + static void SetColorUpdated(VirtualFramebuffer *dstBuffer, int skipDrawReason) { dstBuffer->memoryUpdated = false; dstBuffer->clutUpdatedBytes = 0; dstBuffer->dirtyAfterDisplay = true; diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 3ffc8d8038..8ccf5b2764 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -18,7 +18,7 @@ #include #include -#include "base/display.h" +#include "Common/System/Display.h" #include "Common/StringUtils.h" #include "Core/Config.h" @@ -28,7 +28,7 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "GPU/Math3D.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" #include "GPU/Common/ShaderId.h" #include "GPU/Common/VertexDecoderCommon.h" @@ -226,6 +226,7 @@ StencilValueType ReplaceAlphaWithStencilType() { case GE_FORMAT_4444: case GE_FORMAT_8888: case GE_FORMAT_INVALID: + case GE_FORMAT_DEPTH16: switch (gstate.getStencilOpZPass()) { case GE_STENCILOP_REPLACE: // TODO: Could detect zero here and force ZERO - less uniform updates? @@ -531,14 +532,20 @@ float ToScaledDepthFromIntegerScale(float z) { } } -float FromScaledDepth(float z) { +// See struct DepthScaleFactors for how to apply. +DepthScaleFactors GetDepthScaleFactors() { + DepthScaleFactors factors; if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { - return z * 65535.0f; + factors.offset = 0; + factors.scale = 65535.0f; + return factors; } const float depthSliceFactor = DepthSliceFactor(); const float offset = 0.5f * (depthSliceFactor - 1.0f) * (1.0f / depthSliceFactor); - return (z - offset) * depthSliceFactor * 65535.0f; + factors.scale = depthSliceFactor * 65535.0f; + factors.offset = offset; + return factors; } void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out) { @@ -557,12 +564,18 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo } else { float pixelW = PSP_CoreParameter().pixelWidth; float pixelH = PSP_CoreParameter().pixelHeight; - CenterDisplayOutputRect(&displayOffsetX, &displayOffsetY, &renderWidth, &renderHeight, 480, 272, pixelW, pixelH, ROTATION_LOCKED_HORIZONTAL); + FRect frame = GetScreenFrame(pixelW, pixelH); + FRect rc; + CenterDisplayOutputRect(&rc, 480, 272, frame, ROTATION_LOCKED_HORIZONTAL); + displayOffsetX = rc.x; + displayOffsetY = rc.y; + renderWidth = rc.w; + renderHeight = rc.h; renderWidthFactor = renderWidth / 480.0f; renderHeightFactor = renderHeight / 272.0f; } - renderX += gstate_c.curRTOffsetX * renderWidthFactor; + renderX = gstate_c.curRTOffsetX; // Scissor int scissorX1 = gstate.getScissorX1(); @@ -570,8 +583,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; - // This is a bit of a hack as the render buffer isn't always that size - // We always scissor on non-buffered so that clears don't spill outside the frame. out.scissorEnable = true; if (scissorX2 < scissorX1 || scissorY2 < scissorY1) { out.scissorX = 0; @@ -579,8 +590,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo out.scissorW = 0; out.scissorH = 0; } else { - out.scissorX = renderX + displayOffsetX + scissorX1 * renderWidthFactor; - out.scissorY = renderY + displayOffsetY + scissorY1 * renderHeightFactor; + out.scissorX = (renderX * renderWidthFactor) + displayOffsetX + scissorX1 * renderWidthFactor; + out.scissorY = (renderY * renderHeightFactor) + displayOffsetY + scissorY1 * renderHeightFactor; out.scissorW = (scissorX2 - scissorX1) * renderWidthFactor; out.scissorH = (scissorY2 - scissorY1) * renderHeightFactor; } @@ -592,8 +603,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float offsetY = gstate.getOffsetY(); if (throughmode) { - out.viewportX = renderX + displayOffsetX; - out.viewportY = renderY + displayOffsetY; + out.viewportX = renderX * renderWidthFactor + displayOffsetX; + out.viewportY = renderY * renderHeightFactor + displayOffsetY; out.viewportW = curRTWidth * renderWidthFactor; out.viewportH = curRTHeight * renderHeightFactor; out.depthRangeMin = ToScaledDepthFromIntegerScale(0); @@ -623,15 +634,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float vpWidth = fabsf(gstate_c.vpWidth); float vpHeight = fabsf(gstate_c.vpHeight); - // This multiplication should probably be done after viewport clipping. Would let us very slightly simplify the clipping logic? - vpX0 *= renderWidthFactor; - vpY0 *= renderHeightFactor; - vpWidth *= renderWidthFactor; - vpHeight *= renderHeightFactor; - - // We used to apply the viewport here via glstate, but there are limits which vary by driver. - // This may mean some games won't work, or at least won't work at higher render resolutions. - // So we apply it in the shader instead. float left = renderX + vpX0; float top = renderY + vpY0; float right = left + vpWidth; @@ -642,27 +644,46 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float hScale = 1.0f; float yOffset = 0.0f; - if (!gstate_c.Supports(GPU_SUPPORTS_LARGE_VIEWPORTS)) { - // If we're within the bounds, we want clipping the viewport way. So leave it be. - if (left < 0.0f || right > renderWidth) { - float overageLeft = std::max(-left, 0.0f); - float overageRight = std::max(right - renderWidth, 0.0f); - // Our center drifted by the difference in overages. - float drift = overageRight - overageLeft; + // If we're within the bounds, we want clipping the viewport way. So leave it be. + { + float overageLeft = std::max(-left, 0.0f); + float overageRight = std::max(right - bufferWidth, 0.0f); + // Expand viewport to cover scissor region. The viewport doesn't clip on the PSP. + if (right < scissorX2) { + overageRight -= scissorX2 - right; + } + if (left > scissorX1) { + overageLeft += scissorX1 - left; + } + + // Our center drifted by the difference in overages. + float drift = overageRight - overageLeft; + + if (overageLeft != 0.0f || overageRight != 0.0f) { left += overageLeft; right -= overageRight; wScale = vpWidth / (right - left); xOffset = drift / (right - left); } + } - if (top < 0.0f || bottom > renderHeight) { - float overageTop = std::max(-top, 0.0f); - float overageBottom = std::max(bottom - renderHeight, 0.0f); - // Our center drifted by the difference in overages. - float drift = overageBottom - overageTop; + { + float overageTop = std::max(-top, 0.0f); + float overageBottom = std::max(bottom - bufferHeight, 0.0f); + // Expand viewport to cover scissor region. The viewport doesn't clip on the PSP. + if (bottom < scissorY2) { + overageBottom -= scissorY2 - bottom; + } + if (top > scissorY1) { + overageTop += scissorY1 - top; + } + // Our center drifted by the difference in overages. + float drift = overageBottom - overageTop; + + if (overageTop != 0.0f || overageBottom != 0.0f) { top += overageTop; bottom -= overageBottom; @@ -671,10 +692,10 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo } } - out.viewportX = left + displayOffsetX; - out.viewportY = top + displayOffsetY; - out.viewportW = right - left; - out.viewportH = bottom - top; + out.viewportX = left * renderWidthFactor + displayOffsetX; + out.viewportY = top * renderHeightFactor + displayOffsetY; + out.viewportW = (right - left) * renderWidthFactor; + out.viewportH = (bottom - top) * renderHeightFactor; // The depth viewport parameters are the same, but we handle it a bit differently. // When clipping is enabled, depth is clamped to [0, 65535]. And minz/maxz discard. diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index c4a26058f7..d58d38f6d4 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -72,7 +72,18 @@ struct ViewportAndScissor { }; void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out); float ToScaledDepthFromIntegerScale(float z); -float FromScaledDepth(float z); + +// Use like this: (z - offset) * scale +struct DepthScaleFactors { + float offset; + float scale; + + float Apply(float z) const { + return (z - offset) * scale; + } +}; +DepthScaleFactors GetDepthScaleFactors(); + float DepthSliceFactor(); // These are common to all modern APIs and can be easily converted with a lookup table. diff --git a/GPU/Common/IndexGenerator.cpp b/GPU/Common/IndexGenerator.cpp index d339fb4790..446d7a680e 100644 --- a/GPU/Common/IndexGenerator.cpp +++ b/GPU/Common/IndexGenerator.cpp @@ -16,9 +16,23 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "IndexGenerator.h" -#include "Common/Common.h" +#include "ppsspp_config.h" +#include "CPUDetect.h" +#include "Common.h" + +#ifdef _M_SSE +#include +#endif +#if PPSSPP_ARCH(ARM_NEON) + +#if defined(_MSC_VER) && PPSSPP_ARCH(ARM64) +#include +#else +#include +#endif +#endif +#include "IndexGenerator.h" // Points don't need indexing... const u8 IndexGenerator::indexedPrimitiveType[7] = { @@ -83,19 +97,98 @@ void IndexGenerator::AddList(int numVerts, bool clockwise) { } } +alignas(16) static const u16 offsets_clockwise[24] = { + 0, (u16)(0 + 1), (u16)(0 + 2), + 1, (u16)(1 + 2), (u16)(1 + 1), + 2, (u16)(2 + 1), (u16)(2 + 2), + 3, (u16)(3 + 2), (u16)(3 + 1), + 4, (u16)(4 + 1), (u16)(4 + 2), + 5, (u16)(5 + 2), (u16)(5 + 1), + 6, (u16)(6 + 1), (u16)(6 + 2), + 7, (u16)(7 + 2), (u16)(7 + 1), +}; + +alignas(16) static const uint16_t offsets_counter_clockwise[24] = { + 0, (u16)(0 + 2), (u16)(0 + 1), + 1, (u16)(1 + 1), (u16)(1 + 2), + 2, (u16)(2 + 2), (u16)(2 + 1), + 3, (u16)(3 + 1), (u16)(3 + 2), + 4, (u16)(4 + 2), (u16)(4 + 1), + 5, (u16)(5 + 1), (u16)(5 + 2), + 6, (u16)(6 + 2), (u16)(6 + 1), + 7, (u16)(7 + 1), (u16)(7 + 2), +}; + void IndexGenerator::AddStrip(int numVerts, bool clockwise) { + int numTris = numVerts - 2; + +#ifdef _M_SSE + // In an SSE2 register we can fit 8 16-bit integers. + // However, we need to output a multiple of 3 indices. + // The first such multiple is 24, which means we'll generate 24 indices per cycle, + // which corresponds to 8 triangles. That's pretty cool. + + // We allow ourselves to write some extra indices to avoid the fallback loop. + // That's alright as we're appending to a buffer - they will get overwritten anyway. + int numChunks = (numTris + 7) / 8; + __m128i ibase8 = _mm_set1_epi16(index_); + __m128i increment = _mm_set1_epi16(8); + const __m128i *offsets = (const __m128i *)(clockwise ? offsets_clockwise : offsets_counter_clockwise); + __m128i offsets0 = _mm_load_si128(offsets); + __m128i offsets1 = _mm_load_si128(offsets + 1); + __m128i offsets2 = _mm_load_si128(offsets + 2); + __m128i *dst = (__m128i *)inds_; + for (int i = 0; i < numChunks; i++) { + _mm_storeu_si128(dst, _mm_add_epi16(ibase8, offsets0)); + _mm_storeu_si128(dst + 1, _mm_add_epi16(ibase8, offsets1)); + _mm_storeu_si128(dst + 2, _mm_add_epi16(ibase8, offsets2)); + ibase8 = _mm_add_epi16(ibase8, increment); + dst += 3; + } + inds_ += numTris * 3; + // wind doesn't need to be updated, an even number of triangles have been drawn. +#elif PPSSPP_ARCH(ARM_NEON) + int numChunks = (numTris + 7) / 8; + uint16x8_t ibase8 = vdupq_n_u16(index_); + uint16x8_t increment = vdupq_n_u16(8); + const u16 *offsets = clockwise ? offsets_clockwise : offsets_counter_clockwise; + uint16x8_t offsets0 = vld1q_u16(offsets); + uint16x8_t offsets1 = vld1q_u16(offsets + 8); + uint16x8_t offsets2 = vld1q_u16(offsets + 16); + u16 *dst = inds_; + for (int i = 0; i < numChunks; i++) { + vst1q_u16(dst, vaddq_u16(ibase8, offsets0)); + vst1q_u16(dst + 8, vaddq_u16(ibase8, offsets1)); + vst1q_u16(dst + 16, vaddq_u16(ibase8, offsets2)); + ibase8 = vaddq_u16(ibase8, increment); + dst += 3 * 8; + } + inds_ += numTris * 3; +#else + // Slow fallback loop. int wind = clockwise ? 1 : 2; - const int numTris = numVerts - 2; - u16 *outInds = inds_; int ibase = index_; - for (int i = 0; i < numTris; i++) { + size_t numPairs = numTris / 2; + u16 *outInds = inds_; + while (numPairs > 0) { + *outInds++ = ibase; + *outInds++ = ibase + wind; + *outInds++ = ibase + (wind ^ 3); + *outInds++ = ibase + 1; + *outInds++ = ibase + 1 + (wind ^ 3); + *outInds++ = ibase + 1 + wind; + ibase += 2; + numPairs--; + } + if (numTris & 1) { *outInds++ = ibase; *outInds++ = ibase + wind; wind ^= 3; // toggle between 1 and 2 *outInds++ = ibase + wind; - ibase++; } inds_ = outInds; +#endif + index_ += numVerts; if (numTris > 0) count_ += numTris * 3; diff --git a/GPU/Common/IndexGenerator.h b/GPU/Common/IndexGenerator.h index 6fb24930ee..05ac01d0f2 100644 --- a/GPU/Common/IndexGenerator.h +++ b/GPU/Common/IndexGenerator.h @@ -18,7 +18,6 @@ #pragma once -#include #include "Common/CommonTypes.h" #include "Common/Swap.h" #include "GPU/ge_constants.h" @@ -49,7 +48,7 @@ public: GEPrimitiveType Prim() const { return prim_; } - void AddPrim(int prim, int vertexCount, bool clockwise = true); + void AddPrim(int prim, int vertexCount, bool clockwise); void TranslatePrim(int prim, int numInds, const u8 *inds, int indexOffset, bool clockwise); void TranslatePrim(int prim, int numInds, const u16_le *inds, int indexOffset, bool clockwise); void TranslatePrim(int prim, int numInds, const u32_le *inds, int indexOffset, bool clockwise); diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index c8aacbf843..9971650ba5 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -22,20 +22,23 @@ #include #include -#include "file/ini_file.h" -#include "file/file_util.h" -#include "file/vfs.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Data/Format/IniFile.h" +#include "Common/File/FileUtil.h" +#include "Common/File/DirListing.h" +#include "Common/File/VFS/VFS.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "GPU/Common/PostShader.h" static std::vector shaderInfo; +// Okay, not really "post" shaders, but related. +static std::vector textureShaderInfo; // Scans the directories for shader ini files and collects info about all the shaders found. -// Additionally, scan the VFS assets. (TODO) -void LoadPostShaderInfo(std::vector directories) { +void LoadPostShaderInfo(const std::vector &directories) { std::vector notVisible; shaderInfo.clear(); @@ -52,6 +55,12 @@ void LoadPostShaderInfo(std::vector directories) { } shaderInfo.push_back(off); + textureShaderInfo.clear(); + TextureShaderInfo textureOff{}; + textureOff.name = "Off"; + textureOff.section = "Off"; + textureShaderInfo.push_back(textureOff); + auto appendShader = [&](const ShaderInfo &info) { auto beginErase = std::remove(shaderInfo.begin(), shaderInfo.end(), info.name); if (beginErase != shaderInfo.end()) { @@ -60,12 +69,19 @@ void LoadPostShaderInfo(std::vector directories) { shaderInfo.push_back(info); }; + auto appendTextureShader = [&](const TextureShaderInfo &info) { + auto beginErase = std::remove(textureShaderInfo.begin(), textureShaderInfo.end(), info.name); + if (beginErase != textureShaderInfo.end()) { + textureShaderInfo.erase(beginErase, textureShaderInfo.end()); + } + textureShaderInfo.push_back(info); + }; + for (size_t d = 0; d < directories.size(); d++) { std::vector fileInfo; getFilesInDir(directories[d].c_str(), &fileInfo, "ini:"); if (fileInfo.size() == 0) { - // TODO: Really gotta fix the filter, now it's gonna open shaders as ini files.. VFSGetFileListing(directories[d].c_str(), &fileInfo, "ini:"); } @@ -89,8 +105,11 @@ void LoadPostShaderInfo(std::vector directories) { // Alright, let's loop through the sections and see if any is a shader. for (size_t i = 0; i < ini.Sections().size(); i++) { - IniFile::Section §ion = ini.Sections()[i]; - if (section.Exists("Fragment") && section.Exists("Vertex")) { + Section §ion = ini.Sections()[i]; + std::string shaderType; + section.Get("Type", &shaderType, "render"); + + if (section.Exists("Fragment") && section.Exists("Vertex") && strncasecmp(shaderType.c_str(), "render", shaderType.size()) == 0) { // Valid shader! ShaderInfo info; std::string temp; @@ -135,6 +154,16 @@ void LoadPostShaderInfo(std::vector directories) { } else { notVisible.push_back(info); } + } else if (section.Exists("Compute") && strncasecmp(shaderType.c_str(), "texture", shaderType.size()) == 0) { + // This is a texture shader. + TextureShaderInfo info; + std::string temp; + info.section = section.name(); + section.Get("Name", &info.name, section.name().c_str()); + section.Get("Compute", &temp, ""); + info.computeShaderFile = path + "/" + temp; + + appendTextureShader(info); } } } @@ -186,6 +215,37 @@ std::vector GetPostShaderChain(const std::string &name) { return backwards; } +std::vector GetFullPostShadersChain(const std::vector &names) { + std::vector fullChain; + for (auto shaderName : names) { + if (shaderName == "Off") + break; + auto shaderChain = GetPostShaderChain(shaderName); + fullChain.insert(fullChain.end(), shaderChain.begin(), shaderChain.end()); + } + return fullChain; +} + +bool PostShaderChainRequires60FPS(const std::vector &chain) { + for (auto shaderInfo : chain) { + if (shaderInfo->requires60fps) + return true; + } + return false; +} + const std::vector &GetAllPostShaderInfo() { return shaderInfo; } + +const TextureShaderInfo *GetTextureShaderInfo(const std::string &name) { + for (auto &info : textureShaderInfo) { + if (info.section == name) { + return &info; + } + } + return nullptr; +} +const std::vector &GetAllTextureShaderInfo() { + return textureShaderInfo; +} diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index 86fd7b77da..42aa30d4bc 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -22,7 +22,7 @@ #include #include -#include "file/ini_file.h" +#include "Common/Data/Format/IniFile.h" struct ShaderInfo { std::string iniFile; // which ini file was this definition in? So we can write settings back later @@ -54,7 +54,7 @@ struct ShaderInfo { Setting settings[4]; // TODO: Add support for all kinds of fun options like mapping the depth buffer, - // SRGB texture reads, etc. + // SRGB texture reads, etc. prev shader? bool operator == (const std::string &other) { return name == other; @@ -64,8 +64,28 @@ struct ShaderInfo { } }; +struct TextureShaderInfo { + std::string iniFile; + std::string section; + std::string name; + + std::string computeShaderFile; + + bool operator == (const std::string &other) { + return name == other; + } + bool operator == (const TextureShaderInfo &other) { + return name == other.name; + } +}; + void ReloadAllPostShaderInfo(); const ShaderInfo *GetPostShaderInfo(const std::string &name); std::vector GetPostShaderChain(const std::string &name); +std::vector GetFullPostShadersChain(const std::vector &names); +bool PostShaderChainRequires60FPS(const std::vector &chain); const std::vector &GetAllPostShaderInfo(); + +const TextureShaderInfo *GetTextureShaderInfo(const std::string &name); +const std::vector &GetAllTextureShaderInfo(); diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 4df4b43716..5d62f1a7fe 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -15,15 +15,17 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include #include #include #include -#include "base/display.h" -#include "base/timeutil.h" -#include "file/vfs.h" -#include "file/zip_read.h" -#include "thin3d/thin3d.h" + +#include "Common/GPU/thin3d.h" + +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/File/VFS/VFS.h" +#include "Common/Log.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Host.h" @@ -39,19 +41,45 @@ struct Vertex { uint32_t rgba; }; -void CenterDisplayOutputRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH, int rotation) { +FRect GetScreenFrame(float pixelWidth, float pixelHeight) { + FRect rc = FRect{ + 0.0f, + 0.0f, + pixelWidth, + pixelHeight, + }; + + bool applyInset = !g_Config.bIgnoreScreenInsets; + + if (applyInset) { + // Remove the DPI scale to get back to pixels. + float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) / g_dpi_scale_x; + float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) / g_dpi_scale_x; + float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) / g_dpi_scale_y; + float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) / g_dpi_scale_y; + + // Adjust left edge to compensate for cutouts (notches) if any. + rc.x += left; + rc.w -= (left + right); + rc.y += top; + rc.h -= (top + bottom); + } + return rc; +} + +void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &frame, int rotation) { float outW; float outH; bool rotated = rotation == ROTATION_LOCKED_VERTICAL || rotation == ROTATION_LOCKED_VERTICAL180; if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::STRETCH) { - outW = frameW; - outH = frameH; + outW = frame.w; + outH = frame.h; } else { if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::MANUAL) { - float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frameW; - float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frameH; + float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frame.w + frame.x; + float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frame.h + frame.y; // Have to invert Y for GL if (GetGPUBackend() == GPUBackend::OPENGL) { offsetY = offsetY * -1.0f; @@ -60,54 +88,54 @@ void CenterDisplayOutputRect(float *x, float *y, float *w, float *h, float origW float smallDisplayW = origW * customZoom; float smallDisplayH = origH * customZoom; if (!rotated) { - *x = floorf(((frameW - smallDisplayW) / 2.0f) + offsetX); - *y = floorf(((frameH - smallDisplayH) / 2.0f) + offsetY); - *w = floorf(smallDisplayW); - *h = floorf(smallDisplayH); + rc->x = floorf(((frame.w - smallDisplayW) / 2.0f) + offsetX); + rc->y = floorf(((frame.h - smallDisplayH) / 2.0f) + offsetY); + rc->w = floorf(smallDisplayW); + rc->h = floorf(smallDisplayH); return; } else { - *x = floorf(((frameW - smallDisplayH) / 2.0f) + offsetX); - *y = floorf(((frameH - smallDisplayW) / 2.0f) + offsetY); - *w = floorf(smallDisplayH); - *h = floorf(smallDisplayW); + rc->x = floorf(((frame.w - smallDisplayH) / 2.0f) + offsetX); + rc->y = floorf(((frame.h - smallDisplayW) / 2.0f) + offsetY); + rc->w = floorf(smallDisplayH); + rc->h = floorf(smallDisplayW); return; } } else if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { // Stretch to 1080 for 272*4. But don't distort if not widescreen (i.e. ultrawide of halfwide.) - float pixelCrop = frameH / 270.0f; + float pixelCrop = frame.h / 270.0f; float resCommonWidescreen = pixelCrop - floor(pixelCrop); - if (!rotated && resCommonWidescreen == 0.0f && frameW >= pixelCrop * 480.0f) { - *x = floorf((frameW - pixelCrop * 480.0f) * 0.5f); - *y = floorf(-pixelCrop); - *w = floorf(pixelCrop * 480.0f); - *h = floorf(pixelCrop * 272.0f); + if (!rotated && resCommonWidescreen == 0.0f && frame.w >= pixelCrop * 480.0f) { + rc->x = floorf((frame.w - pixelCrop * 480.0f) * 0.5f + frame.x); + rc->y = floorf(-pixelCrop + frame.y); + rc->w = floorf(pixelCrop * 480.0f); + rc->h = floorf(pixelCrop * 272.0f); return; } } float origRatio = !rotated ? origW / origH : origH / origW; - float frameRatio = frameW / frameH; + float frameRatio = frame.w / frame.h; if (origRatio > frameRatio) { // Image is wider than frame. Center vertically. - outW = frameW; - outH = frameW / origRatio; + outW = frame.w; + outH = frame.w / origRatio; // Stretch a little bit if (!rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) - outH = (frameH + outH) / 2.0f; // (408 + 720) / 2 = 564 + outH = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 } else { // Image is taller than frame. Center horizontally. - outW = frameH * origRatio; - outH = frameH; + outW = frame.h * origRatio; + outH = frame.h; if (rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) - outW = (frameH + outH) / 2.0f; // (408 + 720) / 2 = 564 + outW = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 } } - *x = floorf((frameW - outW) / 2.0f); - *y = floorf((frameH - outH) / 2.0f); - *w = floorf(outW); - *h = floorf(outH); + rc->x = floorf((frame.w - outW) / 2.0f + frame.x); + rc->y = floorf((frame.h - outH) / 2.0f + frame.y); + rc->w = floorf(outW); + rc->h = floorf(outH); } PresentationCommon::PresentationCommon(Draw::DrawContext *draw) : draw_(draw) { @@ -119,6 +147,10 @@ PresentationCommon::~PresentationCommon() { } void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettings) { + if (!g_Config.bEnableCardboardVR) { + cardboardSettings->enabled = false; + return; + } // Calculate Cardboard Settings float cardboardScreenScale = g_Config.iCardboardScreenSize / 100.0f; float cardboardScreenWidth = pixelWidth_ / 2.0f * cardboardScreenScale; @@ -131,7 +163,7 @@ void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettin float cardboardUserYShift = g_Config.iCardboardYShift / 100.0f * cardboardMaxYShift; float cardboardScreenY = cardboardMaxYShift + cardboardUserYShift; - cardboardSettings->enabled = g_Config.bEnableCardboardVR; + cardboardSettings->enabled = true; cardboardSettings->leftEyeXPosition = cardboardLeftEyeX; cardboardSettings->rightEyeXPosition = cardboardRightEyeX; cardboardSettings->screenYPosition = cardboardScreenY; @@ -146,7 +178,7 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer float v_pixel_delta = 1.0f / targetHeight; int flipCount = __DisplayGetFlipCount(); int vCount = __DisplayGetVCount(); - float time[4] = { time_now(), (vCount % 60) * 1.0f / 60.0f, (float)vCount, (float)(flipCount % 60) }; + float time[4] = { (float)time_now_d(), (vCount % 60) * 1.0f / 60.0f, (float)vCount, (float)(flipCount % 60) }; uniforms->texelDelta[0] = u_delta; uniforms->texelDelta[1] = v_delta; @@ -179,9 +211,9 @@ static std::string ReadShaderSrc(const std::string &filename) { // Note: called on resize and settings changes. bool PresentationCommon::UpdatePostShader() { std::vector shaderInfo; - if (g_Config.sPostShaderName != "Off") { + if (!g_Config.vPostShaderNames.empty() && g_Config.vPostShaderNames[0] != "Off") { ReloadAllPostShaderInfo(); - shaderInfo = GetPostShaderChain(g_Config.sPostShaderName); + shaderInfo = GetFullPostShadersChain(g_Config.vPostShaderNames); } DestroyPostShader(); @@ -252,10 +284,11 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha nextHeight *= next->SSAAFilterLevel; } else if (shaderInfo->outputResolution) { // If the current shader uses output res (not next), we will use output res for it. - float x, y, w, h; - CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, g_Config.iInternalScreenRotation); - nextWidth = (int)w; - nextHeight = (int)h; + FRect rc; + FRect frame = GetScreenFrame((float)pixelWidth_, (float)pixelHeight_); + CenterDisplayOutputRect(&rc, 480.0f, 272.0f, frame, g_Config.iInternalScreenRotation); + nextWidth = (int)rc.w; + nextHeight = (int)rc.h; } if (!AllocateFramebuffer(nextWidth, nextHeight)) { @@ -284,7 +317,7 @@ bool PresentationCommon::AllocateFramebuffer(int w, int h) { } // No depth/stencil for post processing - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, Draw::FBO_8888 }); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, Draw::FBO_8888, "presentation" }); if (!fbo) { return false; } @@ -374,6 +407,7 @@ Draw::Pipeline *PresentationCommon::CreatePipeline(std::vectorCreateBuffer(sizeof(Vertex) * 8, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); @@ -497,7 +531,7 @@ void PresentationCommon::BindSource(int binding) { } else if (srcFramebuffer_) { draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); } else { - assert(false); + _assert_(false); } } @@ -506,8 +540,7 @@ void PresentationCommon::UpdateUniforms(bool hasVideo) { } void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) { - // Make sure Direct3D 11 clears state, since we set shaders outside Draw. - draw_->BindPipeline(nullptr); + draw_->InvalidateCachedState(); // TODO: If shader objects have been created by now, we might have received errors. // GLES can have the shader fail later, shader->failed / shader->error. @@ -521,13 +554,14 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u int lastHeight = srcHeight_; // These are the output coordinates. - float x, y, w, h; - CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation); + FRect frame = GetScreenFrame((float)pixelWidth_, (float)pixelHeight_); + FRect rc; + CenterDisplayOutputRect(&rc, 480.0f, 272.0f, frame, uvRotation); if (GetGPUBackend() == GPUBackend::DIRECT3D9) { - x -= 0.5f; + rc.x -= 0.5f; // This is plus because the top is larger y. - y += 0.5f; + rc.y += 0.5f; } if ((flags & OutputFlags::BACKBUFFER_FLIPPED) || (flags & OutputFlags::POSITION_FLIPPED)) { @@ -537,10 +571,10 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u // To make buffer updates easier, we use one array of verts. int postVertsOffset = (int)sizeof(Vertex) * 4; Vertex verts[8] = { - { x, y, 0, u0, v0, 0xFFFFFFFF }, // TL - { x, y + h, 0, u0, v1, 0xFFFFFFFF }, // BL - { x + w, y + h, 0, u1, v1, 0xFFFFFFFF }, // BR - { x + w, y, 0, u1, v0, 0xFFFFFFFF }, // TR + { rc.x, rc.y, 0, u0, v0, 0xFFFFFFFF }, // TL + { rc.x, rc.y + rc.h, 0, u0, v1, 0xFFFFFFFF }, // BL + { rc.x + rc.w, rc.y + rc.h, 0, u1, v1, 0xFFFFFFFF }, // BR + { rc.x + rc.w, rc.y, 0, u1, v0, 0xFFFFFFFF }, // TR }; float invDestW = 1.0f / (pixelWidth_ * 0.5f); @@ -592,6 +626,13 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u } } + if (flags & OutputFlags::PILLARBOX) { + for (int i = 0; i < 4; i++) { + // Looks about right. + verts[i].x *= 0.75f; + } + } + if (usePostShader) { bool flipped = flags & OutputFlags::POSITION_FLIPPED; float post_v0 = !flipped ? 1.0f : 0.0f; @@ -607,7 +648,8 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u const ShaderInfo *shaderInfo = &postShaderInfo_[i]; Draw::Framebuffer *postShaderFramebuffer = postShaderFramebuffers_[i]; - draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader"); + if (usePostShaderOutput) { draw_->BindFramebufferAsTexture(postShaderFramebuffers_[i - 1], 0, Draw::FB_COLOR_BIT, 0); } else { @@ -652,7 +694,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u pipeline = postShaderPipelines_.back(); } - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit"); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); draw_->BindPipeline(pipeline); @@ -666,7 +708,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u if (isFinalAtOutputResolution) { PostShaderUniforms uniforms; - CalculatePostShaderUniforms(lastWidth, lastHeight, (int)w, (int)h, &postShaderInfo_.back(), &uniforms); + CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, &postShaderInfo_.back(), &uniforms); draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms)); } else { Draw::VsTexColUB ub{}; @@ -706,15 +748,16 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u DoRelease(srcFramebuffer_); DoRelease(srcTexture_); + // Unbinds all textures and samplers too, needed since sometimes a MakePixelTexture is deleted etc. draw_->BindPipeline(nullptr); } void PresentationCommon::CalculateRenderResolution(int *width, int *height, bool *upscaling, bool *ssaa) { // Check if postprocessing shader is doing upscaling as it requires native resolution std::vector shaderInfo; - if (g_Config.sPostShaderName != "Off") { + if (!g_Config.vPostShaderNames.empty() && g_Config.vPostShaderNames[0] != "Off") { ReloadAllPostShaderInfo(); - shaderInfo = GetPostShaderChain(g_Config.sPostShaderName); + shaderInfo = GetFullPostShadersChain(g_Config.vPostShaderNames); } bool firstIsUpscalingFilter = shaderInfo.empty() ? false : shaderInfo.front()->isUpscalingFilter; diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index ee0822ea0a..7acce4083a 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -37,7 +37,16 @@ struct PostShaderUniforms { float gl_HalfPixel[4]; }; -void CenterDisplayOutputRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH, int rotation); +// Could use UI::Bounds but don't want to depend on that here. +struct FRect { + float x; + float y; + float w; + float h; +}; + +FRect GetScreenFrame(float pixelWidth, float pixelHeight); +void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &frame, int rotation); namespace Draw { class Buffer; @@ -58,18 +67,9 @@ enum class OutputFlags { RB_SWIZZLE = 0x0002, BACKBUFFER_FLIPPED = 0x0004, POSITION_FLIPPED = 0x0008, + PILLARBOX = 0x0010, }; - -inline OutputFlags operator | (const OutputFlags &lhs, const OutputFlags &rhs) { - return OutputFlags((int)lhs | (int)rhs); -} -inline OutputFlags operator |= (OutputFlags &lhs, const OutputFlags &rhs) { - lhs = lhs | rhs; - return lhs; -} -inline bool operator & (const OutputFlags &lhs, const OutputFlags &rhs) { - return ((int)lhs & (int)rhs) != 0; -} +ENUM_CLASS_BITOPS(OutputFlags); class PresentationCommon { public: diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index b8827dd03d..3280c765b6 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -104,7 +104,7 @@ enum : uint64_t { // Other dirty elements that aren't uniforms! DIRTY_FRAMEBUF = 1ULL << 40, - DIRTY_TEXTURE_IMAGE = 1ULL << 41, + DIRTY_TEXTURE_IMAGE = 1ULL << 41, // Means that the definition of the texture image has changed (address, stride etc), and we need to look up again. DIRTY_TEXTURE_PARAMS = 1ULL << 42, // Render State diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 7d75996f3f..3f5864161a 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -1,7 +1,7 @@ #include #include -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" #include "Common/StringUtils.h" #include "Core/Config.h" @@ -147,7 +147,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, id.SetBit(VS_BIT_FLATSHADE, doFlatShading); // These two bits cannot be combined, otherwise havoc occurs. We get reports that indicate this happened somehow... "ERROR: 0:14: 'u_proj' : undeclared identifier" - _dbg_assert_msg_(G3D, !id.Bit(VS_BIT_USE_HW_TRANSFORM) || !id.Bit(VS_BIT_IS_THROUGH), "Can't have both THROUGH and USE_HW_TRANSFORM together!"); + _dbg_assert_msg_(!id.Bit(VS_BIT_USE_HW_TRANSFORM) || !id.Bit(VS_BIT_IS_THROUGH), "Can't have both THROUGH and USE_HW_TRANSFORM together!"); *id_out = id; } diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index f117341e7d..3adc7f4c2b 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -3,7 +3,8 @@ #include #include #include -#include "base/basictypes.h" + +#include "Common/Common.h" // TODO: There will be additional bits, indicating that groups of these will be // sent to the shader and processed there. This will cut down the number of shaders ("ubershader approach") diff --git a/GPU/Common/ShaderTranslation.cpp b/GPU/Common/ShaderTranslation.cpp index 2361ba9e11..25edef6297 100644 --- a/GPU/Common/ShaderTranslation.cpp +++ b/GPU/Common/ShaderTranslation.cpp @@ -29,13 +29,18 @@ #undef realloc #endif -#include "base/logging.h" -#include "base/basictypes.h" -#include "base/stringutil.h" -#include "ShaderTranslation.h" +// Weird issue +#if PPSSPP_PLATFORM(WINDOWS) && PPSSPP_ARCH(ARM) +#undef free +#endif + +#include "Common/Log.h" +#include "Common/StringUtils.h" + +#include "GPU/Common/ShaderTranslation.h" #include "ext/glslang/SPIRV/GlslangToSpv.h" -#include "thin3d/thin3d.h" -#include "gfx_es2/gpu_features.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "ext/SPIRV-Cross/spirv.hpp" #include "ext/SPIRV-Cross/spirv_common.hpp" @@ -206,7 +211,7 @@ bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetada } // DUMPLOG(src.c_str()); - // ILOG("---->"); + // INFO_LOG(SYSTEM, "---->"); // DUMPLOG(LineNumberString(out.str()).c_str()); *dest = out.str(); @@ -247,8 +252,8 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade shaderStrings[0] = src.c_str(); shader.setStrings(shaderStrings, 1); if (!shader.parse(&Resources, 100, EProfile::ECompatibilityProfile, false, false, messages)) { - ELOG("%s", shader.getInfoLog()); - ELOG("%s", shader.getInfoDebugLog()); + ERROR_LOG(G3D, "%s", shader.getInfoLog()); + ERROR_LOG(G3D, "%s", shader.getInfoDebugLog()); if (errorMessage) { *errorMessage = shader.getInfoLog(); (*errorMessage) += shader.getInfoDebugLog(); @@ -260,8 +265,8 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade program.addShader(&shader); if (!program.link(messages)) { - ELOG("%s", shader.getInfoLog()); - ELOG("%s", shader.getInfoDebugLog()); + ERROR_LOG(G3D, "%s", shader.getInfoLog()); + ERROR_LOG(G3D, "%s", shader.getInfoDebugLog()); if (errorMessage) { *errorMessage = shader.getInfoLog(); (*errorMessage) += shader.getInfoDebugLog(); diff --git a/GPU/Common/ShaderTranslation.h b/GPU/Common/ShaderTranslation.h index 5985623661..9d4e41e3f1 100644 --- a/GPU/Common/ShaderTranslation.h +++ b/GPU/Common/ShaderTranslation.h @@ -19,7 +19,7 @@ #include #include "GPU/Common/ShaderCommon.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" struct TranslatedShaderMetadata { diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index be3391cc90..46f6a93855 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -2,26 +2,26 @@ #include #include "ShaderUniforms.h" -#include "base/display.h" -#include "math/dataconv.h" -#include "math/lin/matrix4x4.h" -#include "math/math_util.h" -#include "math/lin/vec3.h" +#include "Common/System/Display.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Math/math_util.h" +#include "Common/Math/lin/vec3.h" #include "GPU/GPUState.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Math3D.h" using namespace Lin; static void ConvertProjMatrixToVulkan(Matrix4x4 &in) { - const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); + const Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); in.translateAndScale(trans, scale); } static void ConvertProjMatrixToD3D11(Matrix4x4 &in) { - const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); + const Vec3 trans(gstate_c.vpXOffset, -gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); const Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); in.translateAndScale(trans, scale); } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index e87d5a940a..0a369204b9 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -17,13 +17,13 @@ #include #include -#include "math/math_util.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Math/math_util.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "Core/Config.h" #include "GPU/GPUState.h" #include "GPU/Math3D.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Common/SoftwareTransformCommon.h" #include "GPU/Common/TransformCommon.h" @@ -441,12 +441,17 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt // TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not. // TODO: Allow creating a depth clear and a color draw. bool reallyAClear = false; - if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear() && params_.allowClear) { + if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear()) { int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; reallyAClear = IsReallyAClear(transformed, maxIndex, scissorX2, scissorY2); + if (reallyAClear && gstate.getColorMask() != 0xFFFFFFFF && (gstate.isClearModeColorMask() || gstate.isClearModeAlphaMask())) { + result->setSafeSize = true; + result->safeWidth = scissorX2; + result->safeHeight = scissorY2; + } } - if (reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_IMGTEC) { + if (params_.allowClear && reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_IMGTEC) { // If alpha is not allowed to be separate, it must match for both depth/stencil and color. Vulkan requires this. bool alphaMatchesColor = gstate.isClearModeColorMask() == gstate.isClearModeAlphaMask(); bool depthMatchesStencil = gstate.isClearModeAlphaMask() == gstate.isClearModeDepthMask(); @@ -461,6 +466,22 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt return; } } + + // Detect full screen "clears" that might not be so obvious, to set the safe size if possible. + if (!result->setSafeSize && prim == GE_PRIM_RECTANGLES && maxIndex == 2) { + bool clearingColor = gstate.isModeClear() && (gstate.isClearModeColorMask() || gstate.isClearModeAlphaMask()); + bool writingColor = gstate.getColorMask() != 0xFFFFFFFF; + bool startsZeroX = transformed[0].x <= 0.0f && transformed[1].x > transformed[0].x; + bool startsZeroY = transformed[0].y <= 0.0f && transformed[1].y > transformed[0].y; + + if (startsZeroX && startsZeroY && (clearingColor || writingColor)) { + int scissorX2 = gstate.getScissorX2() + 1; + int scissorY2 = gstate.getScissorY2() + 1; + result->setSafeSize = true; + result->safeWidth = std::min(scissorX2, (int)transformed[1].x); + result->safeHeight = std::min(scissorY2, (int)transformed[1].y); + } + } } // Also, this assumes SetTexture() has already figured out the actual texture height. diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index c93e12b58d..98250afbea 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -38,6 +38,10 @@ struct SoftwareTransformResult { bool setStencil; u8 stencilValue; + bool setSafeSize; + u32 safeWidth; + u32 safeHeight; + TransformedVertex *drawBuffer; int drawNumTrans; bool drawIndexed; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 2460af74dc..c4aa0d2c49 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -18,7 +18,7 @@ #include #include -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Common/CPUDetect.h" diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 77e60a38fa..3c0929ac41 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -16,15 +16,16 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include + #include "ppsspp_config.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Common/ColorConv.h" #include "Common/MemoryUtil.h" #include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Reporting.h" #include "Core/System.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Common/TextureDecoder.h" #include "GPU/Common/ShaderId.h" @@ -87,16 +88,22 @@ // GL_UNSIGNED_BYTE/RGBA: AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR (match) // These are Data::Format:: B4G4R4A4_PACK16, B5G6R6_PACK16, B5G5R5A1_PACK16, R8G8B8A8 +// Allow the extra bits from the remasters for the purposes of this. +inline int dimWidth(u16 dim) { + return 1 << (dim & 0xFF); +} + +inline int dimHeight(u16 dim) { + return 1 << ((dim >> 8) & 0xFF); +} + // Vulkan color formats: // TODO TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw) : draw_(draw), - clearCacheNextFrame_(false), - lowMemoryMode_(false), texelsScaledThisFrame_(0), cacheSizeEstimate_(0), secondCacheSizeEstimate_(0), - nextTexture_(nullptr), clutLastFormat_(0xFFFFFFFF), clutTotalBytes_(0), clutMaxBytes_(0), @@ -116,7 +123,6 @@ TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw) // These buffers will grow if necessary, but most won't need more than this. tmpTexBuf32_.resize(512 * 512); // 1MB - tmpTexBuf16_.resize(512 * 512); // 0.5MB tmpTexBufRearrange_.resize(512 * 512); // 1MB replacer_.Init(); @@ -127,18 +133,6 @@ TextureCacheCommon::~TextureCacheCommon() { FreeAlignedMemory(clutBufRaw_); } -int TextureCacheCommon::AttachedDrawingHeight() { - if (nextTexture_) { - if (nextTexture_->framebuffer) { - return nextTexture_->framebuffer->height; - } - u16 dim = nextTexture_->dim; - const u8 dimY = dim >> 8; - return 1 << dimY; - } - return 0; -} - // Produces a signed 1.23.8 value. static int TexLog2(float delta) { union FloatBits { @@ -154,85 +148,49 @@ static int TexLog2(float delta) { return useful - 127 * 256; } -void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, int maxLevel, u32 addr, GETexLevelMode &mode) { - minFilt = gstate.texfilter & 0x7; - magFilt = gstate.isMagnifyFilteringEnabled(); - sClamp = gstate.isTexCoordClampedS(); - tClamp = gstate.isTexCoordClampedT(); +SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, u32 texAddr) { + SamplerCacheKey key; + + int minFilt = gstate.texfilter & 0x7; + key.minFilt = minFilt & 1; + key.mipEnable = (minFilt >> 2) & 1; + key.mipFilt = (minFilt >> 1) & 1; + key.magFilt = gstate.isMagnifyFilteringEnabled(); + key.sClamp = gstate.isTexCoordClampedS(); + key.tClamp = gstate.isTexCoordClampedT(); + key.aniso = false; GETexLevelMode mipMode = gstate.getTexLevelMode(); - mode = mipMode; bool autoMip = mipMode == GE_TEXLEVEL_MODE_AUTO; - lodBias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f); + + // TODO: Slope mipmap bias is still not well understood. + float lodBias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f); if (mipMode == GE_TEXLEVEL_MODE_SLOPE) { lodBias += 1.0f + TexLog2(gstate.getTextureLodSlope()) * (1.0f / 256.0f); } // If mip level is forced to zero, disable mipmapping. bool noMip = maxLevel == 0 || (!autoMip && lodBias <= 0.0f); - if (IsFakeMipmapChange()) + if (IsFakeMipmapChange()) { noMip = noMip || !autoMip; + } if (noMip) { // Enforce no mip filtering, for safety. - minFilt &= 1; // no mipmaps yet + key.mipEnable = false; + key.mipFilt = 0; lodBias = 0.0f; } - if (g_Config.iTexFiltering == TEX_FILTER_LINEAR_VIDEO) { - bool isVideo = videos_.find(addr & 0x3FFFFFFF) != videos_.end(); - if (isVideo) { - magFilt |= 1; - minFilt |= 1; - } - } - if (g_Config.iTexFiltering == TEX_FILTER_LINEAR && (!gstate.isColorTestEnabled() || IsColorTestTriviallyTrue())) { - if (!gstate.isAlphaTestEnabled() || IsAlphaTestTriviallyTrue()) { - magFilt |= 1; - minFilt |= 1; - } - } - bool forceNearest = g_Config.iTexFiltering == TEX_FILTER_NEAREST; - // Force Nearest when color test enabled and rendering resolution greater than 480x272 - if ((gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue()) && g_Config.iInternalResolution != 1 && gstate.isModeThrough()) { - // Some games use 0 as the color test color, which won't be too bad if it bleeds. - // Fuchsia and green, etc. are the problem colors. - if (gstate.getColorTestRef() != 0) { - forceNearest = true; - } - } - if (forceNearest) { - magFilt &= ~1; - minFilt &= ~1; - } -} - -void TextureCacheCommon::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key) { - // TODO: Make GetSamplingParams write SamplerCacheKey directly - int minFilt; - int magFilt; - bool sClamp; - bool tClamp; - float lodBias; - int maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; - GETexLevelMode mode; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, mode); - key.minFilt = minFilt & 1; - key.mipEnable = (minFilt >> 2) & 1; - key.mipFilt = (minFilt >> 1) & 1; - key.magFilt = magFilt & 1; - key.sClamp = sClamp; - key.tClamp = tClamp; - key.aniso = false; - if (!key.mipEnable) { key.maxLevel = 0; key.minLevel = 0; key.lodBias = 0; + key.mipFilt = 0; } else { - switch (mode) { + switch (mipMode) { case GE_TEXLEVEL_MODE_AUTO: - key.maxLevel = entry.maxLevel * 256; + key.maxLevel = maxLevel * 256; key.minLevel = 0; key.lodBias = (int)(lodBias * 256.0f); if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { @@ -249,16 +207,72 @@ void TextureCacheCommon::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache // It's incorrect to use the slope as a bias. Instead it should be passed // into the shader directly as an explicit lod level, with the bias on top. For now, we just kill the // lodBias in this mode, working around #9772. - key.maxLevel = entry.maxLevel * 256; + key.maxLevel = maxLevel * 256; key.minLevel = 0; key.lodBias = 0; break; } } - if (entry.framebuffer) { - WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?"); + // Video bilinear override + if (!key.magFilt && texAddr != 0) { + if (videos_.find(texAddr & 0x3FFFFFFF) != videos_.end()) { + // Enforce bilinear filtering on magnification. + key.magFilt = 1; + } } + + // Filtering overrides + switch (g_Config.iTexFiltering) { + case TEX_FILTER_AUTO: + // Follow what the game wants. We just do a single heuristic change to avoid bleeding of wacky color test colors + // in higher resolution (used by some games for sprites, and they accidentally have linear filter on). + if (gstate.isModeThrough() && g_Config.iInternalResolution != 1) { + bool uglyColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue() && gstate.getColorTestRef() != 0; + if (uglyColorTest) { + // Force to nearest. + key.magFilt = 0; + key.minFilt = 0; + } + } + break; + case TEX_FILTER_FORCE_LINEAR: + // Override to linear filtering if there's no alpha or color testing going on. + if ((!gstate.isColorTestEnabled() || IsColorTestTriviallyTrue()) && + (!gstate.isAlphaTestEnabled() || IsAlphaTestTriviallyTrue())) { + key.magFilt = 1; + key.minFilt = 1; + key.mipFilt = 1; + } + break; + case TEX_FILTER_FORCE_NEAREST: + default: + // Just force to nearest without checks. Safe (but ugly). + key.magFilt = 0; + key.minFilt = 0; + break; + } + + return key; +} + +SamplerCacheKey TextureCacheCommon::GetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight) { + SamplerCacheKey key = GetSamplingParams(0, 0); + + // Kill any mipmapping settings. + key.mipEnable = false; + key.mipFilt = false; + key.aniso = 0.0; + key.maxLevel = 0.0f; + + // Often the framebuffer will not match the texture size. We'll wrap/clamp in the shader in that case. + int w = gstate.getTextureWidth(0); + int h = gstate.getTextureHeight(0); + if (w != bufferWidth || h != bufferHeight) { + key.sClamp = true; + key.tClamp = true; + } + return key; } void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode) { @@ -307,20 +321,7 @@ void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode) } } - -void TextureCacheCommon::SetTexture(bool force) { -#ifdef DEBUG_TEXTURES - if (SetDebugTexture()) { - // A different texture was bound, let's rebind next time. - InvalidateLastTexture(); - return; - } -#endif - - if (force) { - InvalidateLastTexture(); - } - +TexCacheEntry *TextureCacheCommon::SetTexture() { u8 level = 0; if (IsFakeMipmapChange()) level = std::max(0, gstate.getTexLevelOffset16() / 16); @@ -328,7 +329,7 @@ void TextureCacheCommon::SetTexture(bool force) { if (!Memory::IsValidAddress(texaddr)) { // Bind a null texture and return. Unbind(); - return; + return nullptr; } const u16 dim = gstate.getTextureDimension(level); @@ -337,13 +338,11 @@ void TextureCacheCommon::SetTexture(bool force) { GETextureFormat format = gstate.getTextureFormat(); if (format >= 11) { - ERROR_LOG_REPORT(G3D, "Unknown texture format %i", format); - // TODO: Better assumption? + // TODO: Better assumption? Doesn't really matter, these are invalid. format = GE_TFMT_5650; } - bool hasClut = gstate.isTextureFormatIndexed(); - // Ignore uncached/kernel when caching. + bool hasClut = gstate.isTextureFormatIndexed(); u32 cluthash; if (hasClut) { if (clutLastFormat_ != gstate.clutformat) { @@ -361,7 +360,7 @@ void TextureCacheCommon::SetTexture(bool force) { u32 texhash = MiniHash((const u32 *)Memory::GetPointerUnchecked(texaddr)); - TexCache::iterator iter = cache_.find(cachekey); + TexCache::iterator entryIter = cache_.find(cachekey); TexCacheEntry *entry = nullptr; // Note: It's necessary to reset needshadertexclamp, for otherwise DIRTY_TEXCLAMP won't get set later. @@ -373,27 +372,17 @@ void TextureCacheCommon::SetTexture(bool force) { } gstate_c.bgraTexture = isBgraBackend_; - if (iter != cache_.end()) { - entry = iter->second.get(); + if (entryIter != cache_.end()) { + entry = entryIter->second.get(); // Validate the texture still matches the cache entry. bool match = entry->Matches(dim, format, maxLevel); const char *reason = "different params"; - // Check for FBO - slow! - if (entry->framebuffer) { - if (match) { - if (hasClut && clutRenderAddress_ != 0xFFFFFFFF) { - WARN_LOG_REPORT_ONCE(clutAndTexRender, G3D, "Using rendered texture with rendered CLUT: texfmt=%d, clutfmt=%d", gstate.getTextureFormat(), gstate.getClutPaletteFormat()); - } - - SetTextureFramebuffer(entry, entry->framebuffer); - return; - } else { - // Make sure we re-evaluate framebuffers. - DetachFramebuffer(entry, texaddr, entry->framebuffer); - reason = "detached framebuf"; - match = false; - } + // Check for FBO changes. + if (entry->status & TexCacheEntry::STATUS_FRAMEBUFFER_OVERLAP) { + // Fall through to the end where we'll delete the entry if there's a framebuffer. + entry->status &= ~TexCacheEntry::STATUS_FRAMEBUFFER_OVERLAP; + match = false; } bool rehash = entry->GetHashStatus() == TexCacheEntry::STATUS_UNRELIABLE; @@ -408,6 +397,12 @@ void TextureCacheCommon::SetTexture(bool force) { rehash = false; } + // Do we need to recreate? + if (entry->status & TexCacheEntry::STATUS_FORCE_REBUILD) { + match = false; + entry->status &= ~TexCacheEntry::STATUS_FORCE_REBUILD; + } + if (match) { if (entry->lastFrame != gpuStats.numFlips) { u32 diff = gpuStats.numFlips - entry->lastFrame; @@ -449,8 +444,7 @@ void TextureCacheCommon::SetTexture(bool force) { } if (match) { - // TODO: Mark the entry reliable if it's been safe for long enough? - //got one! + // got one! gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; if (rehash) { @@ -465,15 +459,45 @@ void TextureCacheCommon::SetTexture(bool force) { nextNeedsChange_ = false; // Might need a rebuild if the hash fails, but that will be set later. nextNeedsRebuild_ = false; - VERBOSE_LOG(G3D, "Texture at %08x Found in Cache, applying", texaddr); - return; //Done! + VERBOSE_LOG(G3D, "Texture at %08x found in cache, applying", texaddr); + return entry; //Done! } else { // Wasn't a match, we will rebuild. nextChangeReason_ = reason; nextNeedsChange_ = true; + // Fall through to the rebuild case. } - } else { - VERBOSE_LOG(G3D, "No texture in cache, decoding..."); + } + + // No texture found, or changed (depending on entry). + // Check for framebuffers. + + TextureDefinition def{}; + def.addr = texaddr; + def.dim = dim; + def.format = format; + def.bufw = bufw; + + std::vector candidates = GetFramebufferCandidates(def, 0); + if (candidates.size() > 0) { + int index = GetBestCandidateIndex(candidates); + if (index != -1) { + // If we had a texture entry here, let's get rid of it. + if (entryIter != cache_.end()) { + DeleteTexture(entryIter); + } + + nextTexture_ = nullptr; + nextNeedsRebuild_ = false; + SetTextureFramebuffer(candidates[index]); + return nullptr; + } + } + + // Didn't match a framebuffer, keep going. + + if (!entry) { + VERBOSE_LOG(G3D, "No texture in cache for %08x, decoding...", texaddr); TexCacheEntry *entryNew = new TexCacheEntry{}; cache_[cachekey].reset(entryNew); @@ -482,7 +506,10 @@ void TextureCacheCommon::SetTexture(bool force) { } entry = entryNew; - if (g_Config.bTextureBackoffCache) { + if (Memory::IsKernelAddress(texaddr)) { + // It's the builtin font texture. + entry->status = TexCacheEntry::STATUS_RELIABLE; + } else if (g_Config.bTextureBackoffCache) { entry->status = TexCacheEntry::STATUS_HASHING; } else { entry->status = TexCacheEntry::STATUS_UNRELIABLE; @@ -526,23 +553,91 @@ void TextureCacheCommon::SetTexture(bool force) { gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; - // Before we go reading the texture from memory, let's check for render-to-texture. - // We must do this early so we have the right w/h. - entry->framebuffer = nullptr; - for (size_t i = 0, n = fbCache_.size(); i < n; ++i) { - auto framebuffer = fbCache_[i]; - AttachFramebuffer(entry, framebuffer->fb_address, framebuffer); - } - - // If we ended up with a framebuffer, attach it - no texture decoding needed. - if (entry->framebuffer) { - SetTextureFramebuffer(entry, entry->framebuffer); - } - nextTexture_ = entry; - nextNeedsRehash_ = entry->framebuffer == nullptr; + if (nextFramebufferTexture_) { + nextFramebufferTexture_ = nullptr; // in case it was accidentally set somehow? + } + nextNeedsRehash_ = true; // We still need to rebuild, to allocate a texture. But we'll bail early. nextNeedsRebuild_ = true; + return entry; +} + +std::vector TextureCacheCommon::GetFramebufferCandidates(const TextureDefinition &entry, u32 texAddrOffset) { + gpuStats.numFramebufferEvaluations++; + bool success = false; + + std::vector candidates; + + FramebufferNotificationChannel channel = Memory::IsDepthTexVRAMAddress(entry.addr) ? FramebufferNotificationChannel::NOTIFY_FB_DEPTH : FramebufferNotificationChannel::NOTIFY_FB_COLOR; + + const std::vector &framebuffers = framebufferManager_->Framebuffers(); + + for (VirtualFramebuffer *framebuffer : framebuffers) { + FramebufferMatchInfo match = MatchFramebuffer(entry, framebuffer, texAddrOffset, channel); + switch (match.match) { + case FramebufferMatch::VALID: + candidates.push_back(AttachCandidate{ match, entry, framebuffer, channel }); + break; + default: + break; + } + } + + if (candidates.size() > 1) { + bool depth = channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH; + WARN_LOG_REPORT_ONCE(multifbcandidate, G3D, "GetFramebufferCandidates(%s): Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s)", + depth ? "DEPTH" : "COLOR", (int)candidates.size(), entry.addr, texAddrOffset, dimWidth(entry.dim), dimHeight(entry.dim), entry.bufw, GeTextureFormatToString(entry.format)); + } + + return candidates; +} + +int TextureCacheCommon::GetBestCandidateIndex(const std::vector &candidates) { + _dbg_assert_(!candidates.empty()); + + if (candidates.size() == 1) { + return 0; + } + + // OK, multiple possible candidates. Will need to figure out which one is the most relevant. + int bestRelevancy = -1; + int bestIndex = -1; + + // TODO: Instead of scores, we probably want to use std::min_element to pick the top element, using + // a comparison function. + for (int i = 0; i < (int)candidates.size(); i++) { + const AttachCandidate &candidate = candidates[i]; + int relevancy = 0; + switch (candidate.match.match) { + case FramebufferMatch::VALID: + relevancy += 1000; + break; + } + + // Bonus point for matching stride. + if (candidate.channel == NOTIFY_FB_COLOR && candidate.fb->fb_stride == candidate.entry.bufw) { + relevancy += 100; + } + + // Bonus points for no offset. + if (candidate.match.xOffset == 0 && candidate.match.yOffset == 0) { + relevancy += 10; + } + + if (candidate.channel == NOTIFY_FB_COLOR && candidate.fb->last_frame_render == gpuStats.numFlips) { + relevancy += 5; + } else if (candidate.channel == NOTIFY_FB_DEPTH && candidate.fb->last_frame_depth_render == gpuStats.numFlips) { + relevancy += 5; + } + + if (relevancy > bestRelevancy) { + bestRelevancy = relevancy; + bestIndex = i; + } + } + + return bestIndex; } // Removes old textures. @@ -614,7 +709,8 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c ReleaseTexture(entry, true); entry->status &= ~TexCacheEntry::STATUS_IS_SCALED; } - // Clear the reliable bit if set. + + // Mark as hashing, if marked as reliable. if (entry->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { entry->SetHashStatus(TexCacheEntry::STATUS_HASHING); } @@ -630,7 +726,6 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c } } - entry->status |= TexCacheEntry::STATUS_UNRELIABLE; if (!g_Config.bUnlockCachedScaling && entry->numFrames < TEXCACHE_FRAME_CHANGE_FREQUENT) { if (entry->status & TexCacheEntry::STATUS_FREE_CHANGE) { entry->status &= ~TexCacheEntry::STATUS_FREE_CHANGE; @@ -641,239 +736,220 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c entry->numFrames = 0; } -void TextureCacheCommon::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg) { - // Mask to ignore the Z memory mirrors if the address is in VRAM. - // These checks are mainly to reduce scanning all textures. +void TextureCacheCommon::NotifyFramebuffer(VirtualFramebuffer *framebuffer, FramebufferNotification msg) { 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. - // Also, if it's a subsample of the buffer, it'll also be within the FBO. - const u64 cacheKeyEnd = cacheKey + ((u64)(framebuffer->fb_stride * framebuffer->height * bpp) << 32); + const u32 fb_addr = framebuffer->fb_address; - // The first mirror starts at 0x04200000 and there are 3. We search all for framebuffers. - const u64 mirrorCacheKey = (u64)0x04200000 << 32; - const u64 mirrorCacheKeyEnd = (u64)0x04800000 << 32; + const u32 z_addr = framebuffer->z_address & ~mirrorMask; // Probably unnecessary. + + const u32 fb_bpp = framebuffer->format == GE_FORMAT_8888 ? 4 : 2; + const u32 z_bpp = 2; // No other format exists. + const u32 fb_stride = framebuffer->fb_stride; + const u32 z_stride = framebuffer->z_stride; + + // NOTE: Some games like Burnout massively misdetects the height of some framebuffers, leading to a lot of unnecessary invalidations. + // Let's only actually get rid of textures that cover the very start of the framebuffer. + const u32 fb_endAddr = fb_addr + fb_stride * std::min((int)framebuffer->height, 16) * fb_bpp; + const u32 z_endAddr = z_addr + z_stride * std::min((int)framebuffer->height, 16) * z_bpp; switch (msg) { case NOTIFY_FB_CREATED: case NOTIFY_FB_UPDATED: - // Ensure it's in the framebuffer cache. - if (std::find(fbCache_.begin(), fbCache_.end(), framebuffer) == fbCache_.end()) { - fbCache_.push_back(framebuffer); - } + { + // Try to match the new framebuffer to existing textures. + // Backwards from the "usual" texturing case so can't share a utility function. + + std::vector candidates; + + u64 cacheKey = (u64)fb_addr << 32; + // If it has a clut, those are the low 32 bits, so it'll be inside this range. + // Also, if it's a subsample of the buffer, it'll also be within the FBO. + u64 cacheKeyEnd = (u64)fb_endAddr << 32; + + // Color - no need to look in the mirrors. for (auto it = cache_.lower_bound(cacheKey), end = cache_.upper_bound(cacheKeyEnd); it != end; ++it) { - AttachFramebuffer(it->second.get(), addr, framebuffer); + it->second->status |= TexCacheEntry::STATUS_FRAMEBUFFER_OVERLAP; + gpuStats.numTextureInvalidationsByFramebuffer++; } - // Let's assume anything in mirrors is fair game to check. - for (auto it = cache_.lower_bound(mirrorCacheKey), end = cache_.upper_bound(mirrorCacheKeyEnd); it != end; ++it) { - const u64 mirrorlessKey = it->first & ~0x0060000000000000ULL; - // Let's still make sure it's in the cache range. - if (mirrorlessKey >= cacheKey && mirrorlessKey <= cacheKeyEnd) { - AttachFramebuffer(it->second.get(), addr, framebuffer); + + if (z_stride != 0) { + // Depth. Just look at the range, but in each mirror (0x04200000 and 0x04600000). + // Games don't use 0x04400000 as far as I know - it has no swizzle effect so kinda useless. + cacheKey = (u64)z_addr << 32; + cacheKeyEnd = (u64)z_endAddr << 32; + for (auto it = cache_.lower_bound(cacheKey | 0x200000), end = cache_.upper_bound(cacheKeyEnd | 0x200000); it != end; ++it) { + it->second->status |= TexCacheEntry::STATUS_FRAMEBUFFER_OVERLAP; + gpuStats.numTextureInvalidationsByFramebuffer++; + } + for (auto it = cache_.lower_bound(cacheKey | 0x600000), end = cache_.upper_bound(cacheKeyEnd | 0x600000); it != end; ++it) { + it->second->status |= TexCacheEntry::STATUS_FRAMEBUFFER_OVERLAP; + gpuStats.numTextureInvalidationsByFramebuffer++; } } break; - - case NOTIFY_FB_DESTROYED: - fbCache_.erase(std::remove(fbCache_.begin(), fbCache_.end(), framebuffer), fbCache_.end()); - - // We may have an offset texture attached. So we use fbTexInfo as a guide. - // We're not likely to have many attached framebuffers. - for (auto it = fbTexInfo_.begin(); it != fbTexInfo_.end(); ) { - u64 cachekey = it->first; - // We might erase, so move to the next one already (which won't become invalid.) - ++it; - - DetachFramebuffer(cache_[cachekey].get(), addr, framebuffer); - } - break; } -} -void TextureCacheCommon::AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo) { - const u64 cachekey = entry->CacheKey(); - const bool hasInvalidFramebuffer = entry->framebuffer == nullptr || entry->invalidHint == -1; - const bool hasOlderFramebuffer = entry->framebuffer != nullptr && entry->framebuffer->last_frame_render < framebuffer->last_frame_render; - bool hasFartherFramebuffer = false; - - if (!hasInvalidFramebuffer && !hasOlderFramebuffer) { - // If it's valid, but the offset is greater, then we still win. - if (fbTexInfo_[cachekey].yOffset == fbInfo.yOffset) - hasFartherFramebuffer = fbTexInfo_[cachekey].xOffset > fbInfo.xOffset; - else - hasFartherFramebuffer = fbTexInfo_[cachekey].yOffset > fbInfo.yOffset; - } - - if (hasInvalidFramebuffer || hasOlderFramebuffer || hasFartherFramebuffer) { - if (entry->framebuffer == nullptr) { - cacheSizeEstimate_ -= EstimateTexMemoryUsage(entry); - } - ReleaseTexture(entry, true); - entry->framebuffer = framebuffer; - entry->invalidHint = 0; - entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; - entry->maxLevel = 0; - fbTexInfo_[cachekey] = fbInfo; - framebuffer->last_frame_attached = gpuStats.numFlips; - GPUDebug::NotifyTextureAttachment(entry->addr); - } else if (entry->framebuffer == framebuffer) { - framebuffer->last_frame_attached = gpuStats.numFlips; } } -void TextureCacheCommon::AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo) { - const u64 cachekey = entry->CacheKey(); - - if (entry->framebuffer == nullptr || entry->framebuffer == framebuffer) { - if (entry->framebuffer == nullptr) { - cacheSizeEstimate_ -= EstimateTexMemoryUsage(entry); - } - ReleaseTexture(entry, true); - entry->framebuffer = framebuffer; - entry->invalidHint = -1; - entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; - entry->maxLevel = 0; - fbTexInfo_[cachekey] = fbInfo; - GPUDebug::NotifyTextureAttachment(entry->addr); - } -} - -void TextureCacheCommon::DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer) { - if (entry->framebuffer == framebuffer) { - const u64 cachekey = entry->CacheKey(); - cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); - entry->framebuffer = nullptr; - // Force the hash to change in case we had one before. - // Otherwise we never recreate the texture. - entry->hash ^= 1; - fbTexInfo_.erase(cachekey); - GPUDebug::NotifyTextureAttachment(entry->addr); - } -} - -bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset) { +FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer( + const TextureDefinition &entry, + VirtualFramebuffer *framebuffer, u32 texaddrOffset, FramebufferNotificationChannel channel) const { static const u32 MAX_SUBAREA_Y_OFFSET_SAFE = 32; - AttachedFramebufferInfo fbInfo = { 0 }; + uint32_t fb_address = channel == NOTIFY_FB_DEPTH ? framebuffer->z_address : framebuffer->fb_address; + + u32 addr = fb_address & 0x3FFFFFFF; + u32 texaddr = entry.addr + texaddrOffset; + + bool texInVRAM = Memory::IsVRAMAddress(texaddr); + bool fbInVRAM = Memory::IsVRAMAddress(fb_address); + + if (texInVRAM != fbInVRAM) { + // Shortcut. Cannot possibly be a match. + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; + } + + if (texInVRAM) { + const u32 mirrorMask = 0x00600000; + + // This bit controls swizzle. The swizzles at 0x00200000 and 0x00600000 are designed + // to perfectly match reading depth as color (which one to use I think might be related + // to the bpp of the color format used when rendering to it). + // It's fairly unlikely that games would screw this up since the result will be garbage so + // we use it to filter out unlikely matches. + switch (entry.addr & mirrorMask) { + case 0x00000000: + case 0x00400000: + // Don't match the depth channel with these addresses when texturing. + if (channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH) { + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; + } + break; + case 0x00200000: + case 0x00600000: + // Don't match the color channel with these addresses when texturing. + if (channel == FramebufferNotificationChannel::NOTIFY_FB_COLOR) { + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; + } + break; + } - 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); - const u32 h = 1 << ((entry->dim >> 8) & 0xf); + const bool exactMatch = noOffset && entry.format < 4 && channel == NOTIFY_FB_COLOR; + const u32 w = 1 << ((entry.dim >> 0) & 0xf); + const u32 h = 1 << ((entry.dim >> 8) & 0xf); // 512 on a 272 framebuffer is sane, so let's be lenient. const u32 minSubareaHeight = h / 4; - // If they match exactly, it's non-CLUT and from the top left. + // If they match "exactly", it's non-CLUT and from the top left. if (exactMatch) { - DEBUG_LOG(G3D, "Render to texture detected at %08x!", address); - if (framebuffer->fb_stride != entry->bufw) { - WARN_LOG_REPORT_ONCE(diffStrides1, G3D, "Render to texture with different strides %d != %d", entry->bufw, framebuffer->fb_stride); + if (framebuffer->fb_stride != entry.bufw) { + WARN_LOG_ONCE(diffStrides1, G3D, "Texturing from framebuffer with different strides %d != %d", entry.bufw, framebuffer->fb_stride); } - if (entry->format != (GETextureFormat)framebuffer->format) { - WARN_LOG_REPORT_ONCE(diffFormat1, G3D, "Render to texture with different formats %d != %d", entry->format, framebuffer->format); - // Let's avoid using it when we know the format is wrong. May be a video/etc. updating memory. - // However, some games use a different format to clear the buffer. - if (framebuffer->last_frame_attached + 1 < gpuStats.numFlips) { - DetachFramebuffer(entry, address, framebuffer); - } + // NOTE: This check is okay because the first texture formats are the same as the buffer formats. + if (entry.format != (GETextureFormat)framebuffer->format) { + WARN_LOG_ONCE(diffFormat1, G3D, "Texturing from framebuffer with different formats %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format)); + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } else { - AttachFramebufferValid(entry, framebuffer, fbInfo); - return true; + return FramebufferMatchInfo{ FramebufferMatch::VALID }; } } else { // Apply to buffered mode only. - if (!framebufferManager_->UseBufferedRendering()) - return false; + if (!framebufferManager_->UseBufferedRendering()) { + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; + } - const bool clutFormat = - (framebuffer->format == GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT32) || - (framebuffer->format != GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT16); + // Check works for D16 too (???) + const bool matchingClutFormat = + (channel != NOTIFY_FB_COLOR && entry.format == GE_TFMT_CLUT16) || + (channel == NOTIFY_FB_COLOR && framebuffer->format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT32) || + (channel == NOTIFY_FB_COLOR && framebuffer->format != GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT16); + + const bool clutFormat = IsClutFormat((GETextureFormat)(entry.format)); + + // To avoid ruining git blame, kept the same name as the old struct. + FramebufferMatchInfo fbInfo{ FramebufferMatch::VALID }; const u32 bitOffset = (texaddr - addr) * 8; - const u32 pixelOffset = bitOffset / std::max(1U, (u32)textureBitsPerPixel[entry->format]); - fbInfo.yOffset = entry->bufw == 0 ? 0 : pixelOffset / entry->bufw; - fbInfo.xOffset = entry->bufw == 0 ? 0 : pixelOffset % entry->bufw; + if (bitOffset != 0) { + const u32 pixelOffset = bitOffset / std::max(1U, (u32)textureBitsPerPixel[entry.format]); - if (framebuffer->fb_stride != entry->bufw) { + fbInfo.yOffset = entry.bufw == 0 ? 0 : pixelOffset / entry.bufw; + fbInfo.xOffset = entry.bufw == 0 ? 0 : pixelOffset % entry.bufw; + } + + if (fbInfo.yOffset + minSubareaHeight >= framebuffer->height) { + // Can't be inside the framebuffer. + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; + } + + if (framebuffer->fb_stride != entry.bufw) { if (noOffset) { - WARN_LOG_REPORT_ONCE(diffStrides2, G3D, "Render to texture using CLUT with different strides %d != %d", entry->bufw, framebuffer->fb_stride); + WARN_LOG_ONCE(diffStrides2, G3D, "Texturing from framebuffer (matching_clut=%s) different strides %d != %d", matchingClutFormat ? "yes" : "no", entry.bufw, framebuffer->fb_stride); + // Continue on with other checks. + // Not actually sure why we even try here. There's no way it'll go well if the strides are different. } else { // Assume any render-to-tex with different bufw + offset is a render from ram. - DetachFramebuffer(entry, address, framebuffer); - return false; + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } } // Check if it's in bufferWidth (which might be higher than width and may indicate the framebuffer includes the data.) if (fbInfo.xOffset >= framebuffer->bufferWidth && fbInfo.xOffset + w <= (u32)framebuffer->fb_stride) { // This happens in Brave Story, see #10045 - the texture is in the space between strides, with matching stride. - DetachFramebuffer(entry, address, framebuffer); - return false; + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } - if (fbInfo.yOffset + minSubareaHeight >= framebuffer->height) { - // Can't be inside the framebuffer then, ram. Detach to be safe. - DetachFramebuffer(entry, address, framebuffer); - return false; - } // Trying to play it safe. Below 0x04110000 is almost always framebuffers. // TODO: Maybe we can reduce this check and find a better way above 0x04110000? if (fbInfo.yOffset > MAX_SUBAREA_Y_OFFSET_SAFE && addr > 0x04110000) { - WARN_LOG_REPORT_ONCE(subareaIgnored, G3D, "Ignoring possible render to texture at %08x +%dx%d / %dx%d", address, fbInfo.xOffset, fbInfo.yOffset, framebuffer->width, framebuffer->height); - DetachFramebuffer(entry, address, framebuffer); - return false; + WARN_LOG_REPORT_ONCE(subareaIgnored, G3D, "Ignoring possible texturing from framebuffer at %08x +%dx%d / %dx%d", fb_address, fbInfo.xOffset, fbInfo.yOffset, framebuffer->width, framebuffer->height); + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } // Check for CLUT. The framebuffer is always RGB, but it can be interpreted as a CLUT texture. // 3rd Birthday (and a bunch of other games) render to a 16 bit clut texture. - if (clutFormat) { + if (matchingClutFormat) { if (!noOffset) { - WARN_LOG_REPORT_ONCE(subareaClut, G3D, "Render to texture using CLUT with offset at %08x +%dx%d", address, fbInfo.xOffset, fbInfo.yOffset); + WARN_LOG_ONCE(subareaClut, G3D, "Texturing from framebuffer using CLUT with offset at %08x +%dx%d", fb_address, fbInfo.xOffset, fbInfo.yOffset); } - AttachFramebufferValid(entry, framebuffer, fbInfo); - entry->status |= TexCacheEntry::STATUS_DEPALETTIZE; - // We'll validate it compiles later. - return true; - } else if (entry->format == GE_TFMT_CLUT8 || entry->format == GE_TFMT_CLUT4) { - ERROR_LOG_REPORT_ONCE(fourEightBit, G3D, "4 and 8-bit CLUT format not supported for framebuffers"); + fbInfo.match = FramebufferMatch::VALID; // We check the format again later, no need to return a special value here. + return fbInfo; + } else if (IsClutFormat((GETextureFormat)(entry.format)) || IsDXTFormat((GETextureFormat)(entry.format))) { + WARN_LOG_ONCE(fourEightBit, G3D, "%s format not supported when texturing from framebuffer of format %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format)); + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } // This is either normal or we failed to generate a shader to depalettize - if (framebuffer->format == entry->format || clutFormat) { - if (framebuffer->format != entry->format) { - WARN_LOG_REPORT_ONCE(diffFormat2, G3D, "Render to texture with different formats %d != %d at %08x", entry->format, framebuffer->format, address); - AttachFramebufferValid(entry, framebuffer, fbInfo); - return true; + if (framebuffer->format == entry.format || matchingClutFormat) { + if (framebuffer->format != entry.format) { + WARN_LOG_ONCE(diffFormat2, G3D, "Texturing from framebuffer with different formats %s != %s at %08x", + GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format), fb_address); + return fbInfo; } else { - WARN_LOG_REPORT_ONCE(subarea, G3D, "Render to area containing texture at %08x +%dx%d", address, fbInfo.xOffset, fbInfo.yOffset); - // If "AttachFramebufferValid" , God of War Ghost of Sparta/Chains of Olympus will be missing special effect. - AttachFramebufferInvalid(entry, framebuffer, fbInfo); - return true; + WARN_LOG_ONCE(subarea, G3D, "Texturing from framebuffer at %08x +%dx%d", fb_address, fbInfo.xOffset, fbInfo.yOffset); + return fbInfo; } } else { - WARN_LOG_REPORT_ONCE(diffFormat2, G3D, "Render to texture with incompatible formats %d != %d at %08x", entry->format, framebuffer->format, address); + WARN_LOG_ONCE(diffFormat2, G3D, "Texturing from framebuffer with incompatible format %s != %s at %08x", + GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format), fb_address); + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } } - - return false; } -void TextureCacheCommon::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { - _dbg_assert_msg_(G3D, framebuffer != nullptr, "Framebuffer must not be null."); +void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) { + VirtualFramebuffer *framebuffer = candidate.fb; + FramebufferMatchInfo fbInfo = candidate.match; + + _dbg_assert_msg_(framebuffer != nullptr, "Framebuffer must not be null."); framebuffer->usageFlags |= FB_USAGE_TEXTURE; if (framebufferManager_->UseBufferedRendering()) { - const u64 cachekey = entry->CacheKey(); - const auto &fbInfo = fbTexInfo_[cachekey]; - // Keep the framebuffer alive. framebuffer->last_frame_used = gpuStats.numFlips; @@ -895,7 +971,8 @@ void TextureCacheCommon::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFram gstate_c.SetNeedShaderTexclamp(true); } - nextTexture_ = entry; + nextFramebufferTexture_ = framebuffer; + nextTexture_ = nullptr; } else { if (framebuffer->fbo) { framebuffer->fbo->Release(); @@ -903,6 +980,8 @@ void TextureCacheCommon::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFram } Unbind(); gstate_c.SetNeedShaderTexclamp(false); + nextFramebufferTexture_ = nullptr; + nextTexture_ = nullptr; } nextNeedsRehash_ = false; @@ -910,6 +989,7 @@ void TextureCacheCommon::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFram nextNeedsRebuild_ = false; } +// Only looks for framebuffers. bool TextureCacheCommon::SetOffsetTexture(u32 yOffset) { if (!framebufferManager_->UseBufferedRendering()) { return false; @@ -924,28 +1004,20 @@ bool TextureCacheCommon::SetOffsetTexture(u32 yOffset) { return false; } - const u16 dim = gstate.getTextureDimension(0); - u64 cachekey = TexCacheEntry::CacheKey(texaddr, fmt, dim, 0); - TexCache::iterator iter = cache_.find(cachekey); - if (iter == cache_.end()) { - return false; - } - TexCacheEntry *entry = iter->second.get(); + TextureDefinition def; + def.addr = texaddr; + def.format = fmt; + def.bufw = GetTextureBufw(0, texaddr, fmt); + def.dim = gstate.getTextureDimension(0); - bool success = false; - for (size_t i = 0, n = fbCache_.size(); i < n; ++i) { - auto framebuffer = fbCache_[i]; - if (AttachFramebuffer(entry, framebuffer->fb_address, framebuffer, texaddrOffset)) { - success = true; + std::vector candidates = GetFramebufferCandidates(def, texaddrOffset); + if (candidates.size() > 0) { + int index = GetBestCandidateIndex(candidates); + if (index != -1) { + SetTextureFramebuffer(candidates[index]); + return true; } } - - if (success && entry->framebuffer) { - // This will not apply the texture immediately. - SetTextureFramebuffer(entry, entry->framebuffer); - return true; - } - return false; } @@ -1007,8 +1079,8 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { static const u32 MAX_CLUT_OFFSET = 4096; clutRenderOffset_ = MAX_CLUT_OFFSET; - for (size_t i = 0, n = fbCache_.size(); i < n; ++i) { - auto framebuffer = fbCache_[i]; + const std::vector &framebuffers = framebufferManager_->Framebuffers(); + for (VirtualFramebuffer *framebuffer : framebuffers) { const u32 fb_address = framebuffer->fb_address & 0x3FFFFFFF; const u32 bpp = framebuffer->drawnFormat == GE_FORMAT_8888 ? 4 : 2; u32 offset = clutFramebufAddr - fb_address; @@ -1186,7 +1258,7 @@ static inline void ConvertFormatToRGBA8888(GETextureFormat format, u32 *dst, con ConvertRGB565ToRGBA8888(dst, src, numPixels); break; default: - _dbg_assert_msg_(G3D, false, "Incorrect texture format."); + _dbg_assert_msg_(false, "Incorrect texture format."); break; } } @@ -1517,9 +1589,18 @@ void TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const void TextureCacheCommon::ApplyTexture() { TexCacheEntry *entry = nextTexture_; - if (entry == nullptr) { + if (!entry) { + // Maybe we bound a framebuffer? + InvalidateLastTexture(); + if (nextFramebufferTexture_) { + bool depth = Memory::IsDepthTexVRAMAddress(gstate.getTextureAddress(0)); + // ApplyTextureFrameBuffer is responsible for setting SetTextureFullAlpha. + ApplyTextureFramebuffer(nextFramebufferTexture_, gstate.getTextureFormat(), depth ? NOTIFY_FB_DEPTH : NOTIFY_FB_COLOR); + nextFramebufferTexture_ = nullptr; + } return; } + nextTexture_ = nullptr; UpdateMaxSeenV(entry, gstate.isModeThrough()); @@ -1566,15 +1647,12 @@ void TextureCacheCommon::ApplyTexture() { if (nextNeedsRebuild_) { _assert_(!entry->texturePtr); BuildTexture(entry); + InvalidateLastTexture(); } entry->lastFrame = gpuStats.numFlips; - if (entry->framebuffer) { - ApplyTextureFramebuffer(entry, entry->framebuffer); - } else { - BindTexture(entry); - gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL); - } + BindTexture(entry); + gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL); } void TextureCacheCommon::Clear(bool delete_them) { @@ -1593,16 +1671,11 @@ void TextureCacheCommon::Clear(bool delete_them) { cacheSizeEstimate_ = 0; secondCacheSizeEstimate_ = 0; } - fbTexInfo_.clear(); videos_.clear(); } void TextureCacheCommon::DeleteTexture(TexCache::iterator it) { ReleaseTexture(it->second.get(), true); - auto fbInfo = fbTexInfo_.find(it->first); - if (fbInfo != fbTexInfo_.end()) { - fbTexInfo_.erase(fbInfo); - } cacheSizeEstimate_ -= EstimateTexMemoryUsage(it->second.get()); cache_.erase(it); } @@ -1655,7 +1728,7 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) { return true; } } else { - // It wasn't found, so we're about to throw away entry and rebuild a texture. + // It wasn't found, so we're about to throw away the entry and rebuild a texture. // Let's save this in the secondary cache in case it gets used again. secondKey = entry->fullhash | ((u64)entry->cluthash << 32); secondCacheSizeEstimate_ += EstimateTexMemoryUsage(entry); @@ -1684,6 +1757,9 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) { void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type) { // They could invalidate inside the texture, let's just give a bit of leeway. + // TODO: Keep track of the largest texture size in bytes, and use that instead of this + // humongous unrealistic value. + const int LARGEST_TEXTURE_SIZE = 512 * 512 * 4; addr &= 0x3FFFFFFF; @@ -1693,8 +1769,9 @@ void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type // This is an active signal from the game that something in the texture cache may have changed. gstate_c.Dirty(DIRTY_TEXTURE_IMAGE); } else { - // Do a quick check to see if the current texture is in range. + // Do a quick check to see if the current texture could potentially be in range. const u32 currentAddr = gstate.getTextureAddress(0); + // TODO: This can be made tighter. if (addr_end >= currentAddr && addr < currentAddr + LARGEST_TEXTURE_SIZE) { gstate_c.Dirty(DIRTY_TEXTURE_IMAGE); } @@ -1715,7 +1792,8 @@ void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type u32 texAddr = iter->second->addr; u32 texEnd = iter->second->addr + iter->second->sizeInRAM; - if (texAddr < addr_end && addr < texEnd) { + // Quick check for overlap. Yes the check is right. + if (addr < texEnd && addr_end > texAddr) { if (iter->second->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { iter->second->SetHashStatus(TexCacheEntry::STATUS_HASHING); } @@ -1731,7 +1809,7 @@ void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type } } iter->second->framesUntilNextFullHash = 0; - } else if (!iter->second->framebuffer) { + } else { iter->second->invalidHint++; } } @@ -1753,9 +1831,7 @@ void TextureCacheCommon::InvalidateAll(GPUInvalidationType /*unused*/) { if (iter->second->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { iter->second->SetHashStatus(TexCacheEntry::STATUS_HASHING); } - if (!iter->second->framebuffer) { - iter->second->invalidHint++; - } + iter->second->invalidHint++; } } diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 095fd12240..6db18d08d3 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -30,9 +30,8 @@ enum TextureFiltering { TEX_FILTER_AUTO = 1, - TEX_FILTER_NEAREST = 2, - TEX_FILTER_LINEAR = 3, - TEX_FILTER_LINEAR_VIDEO = 4, + TEX_FILTER_FORCE_NEAREST = 2, + TEX_FILTER_FORCE_LINEAR = 3, }; enum FramebufferNotification { @@ -41,6 +40,11 @@ enum FramebufferNotification { NOTIFY_FB_DESTROYED, }; +enum FramebufferNotificationChannel { + NOTIFY_FB_COLOR = 0, + NOTIFY_FB_DEPTH = 1, +}; + // Changes more frequent than this will be considered "frequent" and prevent texture scaling. #define TEXCACHE_FRAME_CHANGE_FREQUENT 6 // Note: only used when hash backoff is disabled. @@ -88,7 +92,19 @@ struct SamplerCacheKey { class GLRTexture; class VulkanTexture; +// Enough information about a texture to match it to framebuffers. +struct TextureDefinition { + u32 addr; + GETextureFormat format; + u32 dim; + u32 bufw; +}; + + // TODO: Shrink this struct. There is some fluff. + +// NOTE: These only handle textures loaded directly from PSP memory contents. +// Framebuffer textures do not have entries, we bind the framebuffers directly. struct TexCacheEntry { ~TexCacheEntry() { if (texturePtr || textureName || vkTex) @@ -110,7 +126,6 @@ struct TexCacheEntry { STATUS_CLUT_VARIANTS = 0x08, // Has multiple CLUT variants. STATUS_CHANGE_FREQUENT = 0x10, // Changes often (less than 6 frames in between.) STATUS_CLUT_RECHECK = 0x20, // Another texture with same addr had a hashfail. - STATUS_DEPALETTIZE = 0x40, // Needs to go through a depalettize pass. STATUS_TO_SCALE = 0x80, // Pending texture scaling in a later frame. STATUS_IS_SCALED = 0x100, // Has been scaled (can't be replaceImages'd.) // When hashing large textures, we optimize 512x512 down to 512x272 by default, since this @@ -119,15 +134,19 @@ struct TexCacheEntry { STATUS_FREE_CHANGE = 0x200, // Allow one change before marking "frequent". STATUS_BAD_MIPS = 0x400, // Has bad or unusable mipmap levels. + + STATUS_FRAMEBUFFER_OVERLAP = 0x800, + + STATUS_FORCE_REBUILD = 0x1000, }; // Status, but int so we can zero initialize. int status; + u32 addr; u32 hash; - VirtualFramebuffer *framebuffer; // if null, not sourced from an FBO. TODO: Collapse into texturePtr u32 sizeInRAM; // Could be computed - u8 format; + u8 format; // GeTextureFormat u8 maxLevel; u16 dim; u16 bufw; @@ -172,11 +191,38 @@ struct TexCacheEntry { static u64 CacheKey(u32 addr, u8 format, u16 dim, u32 cluthash); }; -class FramebufferManagerCommon; -// Can't be unordered_map, we use lower_bound ... although for some reason that compiles on MSVC. +// Can't be unordered_map, we use lower_bound ... although for some reason that (used to?) compiles on MSVC. // Would really like to replace this with DenseHashMap but can't as long as we need lower_bound. typedef std::map> TexCache; +// Urgh. +#ifdef IGNORE +#undef IGNORE +#endif + +// TODO: Try to get rid of IGNORE, it doesn't match what we want to do +enum class FramebufferMatch { + // Valid, exact match. + VALID = 0, + // Not a match, remove if currently attached. + NO_MATCH, +}; + +struct FramebufferMatchInfo { + FramebufferMatch match; + u32 xOffset; + u32 yOffset; +}; + +struct AttachCandidate { + FramebufferMatchInfo match; + TextureDefinition entry; + VirtualFramebuffer *fb; + FramebufferNotificationChannel channel; +}; + +class FramebufferManagerCommon; + class TextureCacheCommon { public: TextureCacheCommon(Draw::DrawContext *draw); @@ -185,7 +231,10 @@ public: void LoadClut(u32 clutAddr, u32 loadBytes); bool GetCurrentClutBuffer(GPUDebugBuffer &buffer); - void SetTexture(bool force = false); + // This updates nextTexture_ / nextFramebufferTexture_, which is then used by ApplyTexture. + // TODO: Return stuff directly instead of keeping state. + TexCacheEntry *SetTexture(); + void ApplyTexture(); bool SetOffsetTexture(u32 yOffset); void Invalidate(u32 addr, int size, GPUInvalidationType type); @@ -193,17 +242,16 @@ public: void ClearNextFrame(); virtual void ForgetLastTexture() = 0; - virtual void InvalidateLastTexture(TexCacheEntry *entry = nullptr) = 0; + virtual void InvalidateLastTexture() = 0; virtual void Clear(bool delete_them); + virtual void NotifyConfigChanged(); - // FramebufferManager keeps TextureCache updated about what regions of memory are being rendered to. - void NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg); - void NotifyConfigChanged(); + // FramebufferManager keeps TextureCache updated about what regions of memory are being rendered to, + // so that it can invalidate TexCacheEntries pointed at those addresses. + void NotifyFramebuffer(VirtualFramebuffer *framebuffer, FramebufferNotification msg); void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt); std::string GetTextureReplacementInfo(u32 texAddr); - int AttachedDrawingHeight(); - size_t NumLoadedTextures() const { return cache_.size(); } @@ -223,18 +271,13 @@ protected: void DeleteTexture(TexCache::iterator it); void Decimate(bool forcePressure = false); - virtual void ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) = 0; + virtual void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) = 0; + void HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete); virtual void BuildTexture(TexCacheEntry *const entry) = 0; virtual void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) = 0; bool CheckFullHash(TexCacheEntry *entry, bool &doDelete); - // Separate to keep main texture cache size down. - struct AttachedFramebufferInfo { - u32 xOffset; - u32 yOffset; - }; - void DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, bool reverseColors, bool useBGRA, bool expandTo32Bit); void UnswizzleFromMem(u32 *dest, u32 destPitch, const u8 *texptr, u32 bufw, u32 height, u32 bytesPerPixel); void ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw, bool expandTo32Bit); @@ -245,16 +288,17 @@ protected: } u32 EstimateTexMemoryUsage(const TexCacheEntry *entry); - void GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, int maxLevel, u32 addr, GETexLevelMode &mode); - void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); // Used by D3D11 and Vulkan. + + SamplerCacheKey GetSamplingParams(int maxLevel, u32 texAddr); + SamplerCacheKey GetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight); void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode); - bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0); - void AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); - void AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); - void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer); + FramebufferMatchInfo MatchFramebuffer(const TextureDefinition &entry, VirtualFramebuffer *framebuffer, u32 texaddrOffset, FramebufferNotificationChannel channel) const; - void SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer); + std::vector GetFramebufferCandidates(const TextureDefinition &entry, u32 texAddrOffset); + int GetBestCandidateIndex(const std::vector &candidates); + + void SetTextureFramebuffer(const AttachCandidate &candidate); void DecimateVideos(); @@ -270,6 +314,8 @@ protected: const u32 sizeInRAM = (textureBitsPerPixel[format] * bufw * h) / 8; const u32 *checkp = (const u32 *)Memory::GetPointer(addr); + gpuStats.numTextureDataBytesHashed += sizeInRAM; + if (Memory::IsValidAddress(addr + sizeInRAM)) { return DoQuickTexHash(checkp, sizeInRAM); } else { @@ -285,8 +331,8 @@ protected: TextureReplacer replacer_; FramebufferManagerCommon *framebufferManager_; - bool clearCacheNextFrame_; - bool lowMemoryMode_; + bool clearCacheNextFrame_ = false; + bool lowMemoryMode_ = false; int decimationCounter_; int texelsScaledThisFrame_; @@ -298,16 +344,13 @@ protected: TexCache secondCache_; u32 secondCacheSizeEstimate_; - std::vector fbCache_; - std::map fbTexInfo_; - std::map videos_; SimpleBuf tmpTexBuf32_; - SimpleBuf tmpTexBuf16_; SimpleBuf tmpTexBufRearrange_; - TexCacheEntry *nextTexture_; + TexCacheEntry *nextTexture_ = nullptr; + VirtualFramebuffer *nextFramebufferTexture_ = nullptr; u32 clutHash_ = 0; diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index 68056ce4cd..f02094bfcd 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -311,8 +311,6 @@ void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 QuickTexHashFunc DoQuickTexHash = &QuickTexHashBasic; QuickTexHashFunc StableQuickTexHash = &QuickTexHashNonSSE; UnswizzleTex16Func DoUnswizzleTex16 = &DoUnswizzleTex16Basic; -ReliableHash32Func DoReliableHash32 = &XXH32; -ReliableHash64Func DoReliableHash64 = &XXH64; #endif // This has to be done after CPUDetect has done its magic. @@ -322,10 +320,6 @@ void SetupTextureDecoder() { DoQuickTexHash = &QuickTexHashNEON; StableQuickTexHash = &QuickTexHashNEON; DoUnswizzleTex16 = &DoUnswizzleTex16NEON; -#if !PPSSPP_PLATFORM(IOS) - // Not sure if this is safe on iOS, it's had issues with xxhash. - DoReliableHash32 = &ReliableHash32NEON; -#endif } #endif } @@ -614,7 +608,7 @@ CheckAlphaResult CheckAlphaRGBA8888Basic(const u32 *pixelData, int stride, int w if ((w & 3) == 0 && (stride & 3) == 0) { #ifdef _M_SSE return CheckAlphaRGBA8888SSE2(pixelData, stride, w, h); -#elif PPSSPP_ARCH(ARMV7) || PPSSPP_ARCH(ARM64) +#elif PPSSPP_ARCH(ARM_NEON) if (cpu_info.bNEON) { return CheckAlphaRGBA8888NEON(pixelData, stride, w, h); } @@ -644,7 +638,7 @@ CheckAlphaResult CheckAlphaABGR4444Basic(const u32 *pixelData, int stride, int w if ((w & 7) == 0 && (stride & 7) == 0) { #ifdef _M_SSE return CheckAlphaABGR4444SSE2(pixelData, stride, w, h); -#elif PPSSPP_ARCH(ARMV7) || PPSSPP_ARCH(ARM64) +#elif PPSSPP_ARCH(ARM_NEON) if (cpu_info.bNEON) { return CheckAlphaABGR4444NEON(pixelData, stride, w, h); } @@ -677,7 +671,7 @@ CheckAlphaResult CheckAlphaABGR1555Basic(const u32 *pixelData, int stride, int w if ((w & 7) == 0 && (stride & 7) == 0) { #ifdef _M_SSE return CheckAlphaABGR1555SSE2(pixelData, stride, w, h); -#elif PPSSPP_ARCH(ARMV7) || PPSSPP_ARCH(ARM64) +#elif PPSSPP_ARCH(ARM_NEON) if (cpu_info.bNEON) { return CheckAlphaABGR1555NEON(pixelData, stride, w, h); } @@ -709,7 +703,7 @@ CheckAlphaResult CheckAlphaRGBA4444Basic(const u32 *pixelData, int stride, int w if ((w & 7) == 0 && (stride & 7) == 0) { #ifdef _M_SSE return CheckAlphaRGBA4444SSE2(pixelData, stride, w, h); -#elif PPSSPP_ARCH(ARMV7) || PPSSPP_ARCH(ARM64) +#elif PPSSPP_ARCH(ARM_NEON) if (cpu_info.bNEON) { return CheckAlphaRGBA4444NEON(pixelData, stride, w, h); } @@ -742,7 +736,7 @@ CheckAlphaResult CheckAlphaRGBA5551Basic(const u32 *pixelData, int stride, int w if ((w & 7) == 0 && (stride & 7) == 0) { #ifdef _M_SSE return CheckAlphaRGBA5551SSE2(pixelData, stride, w, h); -#elif PPSSPP_ARCH(ARMV7) || PPSSPP_ARCH(ARM64) +#elif PPSSPP_ARCH(ARM_NEON) if (cpu_info.bNEON) { return CheckAlphaRGBA5551NEON(pixelData, stride, w, h); } diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index 35ffa8400f..02e7939cdc 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -23,6 +23,7 @@ enum CheckAlphaResult { CHECKALPHA_ANY = 4, }; +#include "ppsspp_config.h" #include "Common/Common.h" #include "Common/Swap.h" #include "Core/MemMap.h" @@ -45,31 +46,11 @@ u32 QuickTexHashSSE2(const void *checkp, u32 size); void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 pitch); #define DoUnswizzleTex16 DoUnswizzleTex16Basic -#include "ext/xxhash.h" -#define DoReliableHash32 XXH32 -#define DoReliableHash64 XXH64 - -#if defined(_M_X64) || defined(ARM64) -#define DoReliableHash XXH64 -typedef u64 ReliableHashType; -#else -#define DoReliableHash XXH32 -typedef u32 ReliableHashType; -#endif - // For ARM64, NEON is mandatory, so we also statically link. -#elif PPSSPP_ARCH(ARM64) || defined(ARM64) +#elif PPSSPP_ARCH(ARM64) #define DoQuickTexHash QuickTexHashNEON #define StableQuickTexHash QuickTexHashNEON #define DoUnswizzleTex16 DoUnswizzleTex16NEON -#define DoReliableHash32 ReliableHash32NEON - -#include "ext/xxhash.h" -#define DoReliableHash64 XXH64 - -#define DoReliableHash XXH64 -typedef u64 ReliableHashType; - #else typedef u32 (*QuickTexHashFunc)(const void *checkp, u32 size); extern QuickTexHashFunc DoQuickTexHash; @@ -77,15 +58,6 @@ extern QuickTexHashFunc StableQuickTexHash; typedef void (*UnswizzleTex16Func)(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 pitch); extern UnswizzleTex16Func DoUnswizzleTex16; - -typedef u32 (*ReliableHash32Func)(const void *input, size_t len, u32 seed); -extern ReliableHash32Func DoReliableHash32; - -typedef u64 (*ReliableHash64Func)(const void *input, size_t len, u64 seed); -extern ReliableHash64Func DoReliableHash64; - -#define DoReliableHash DoReliableHash32 -typedef u32 ReliableHashType; #endif CheckAlphaResult CheckAlphaRGBA8888Basic(const u32 *pixelData, int stride, int w, int h); diff --git a/GPU/Common/TextureDecoderNEON.cpp b/GPU/Common/TextureDecoderNEON.cpp index af56567a45..8e96223877 100644 --- a/GPU/Common/TextureDecoderNEON.cpp +++ b/GPU/Common/TextureDecoderNEON.cpp @@ -41,13 +41,14 @@ u32 QuickTexHashNEON(const void *checkp, u32 size) { __builtin_prefetch(checkp, 0, 0); if (((intptr_t)checkp & 0xf) == 0 && (size & 0x3f) == 0) { -#if defined(IOS) || PPSSPP_ARCH(ARM64) || defined(_MSC_VER) +#if defined(IOS) || PPSSPP_ARCH(ARM64) || defined(_MSC_VER) || !PPSSPP_ARCH(ARMV7) uint32x4_t cursor = vdupq_n_u32(0); uint16x8_t cursor2 = vld1q_u16(QuickTexHashInitial); uint16x8_t update = vdupq_n_u16(0x2455U); const u32 *p = (const u32 *)checkp; - for (u32 i = 0; i < size / 16; i += 4) { + const u32 *pend = p + size / 4; + while (p < pend) { cursor = vreinterpretq_u32_u16(vmlaq_u16(vreinterpretq_u16_u32(cursor), vreinterpretq_u16_u32(vld1q_u32(&p[4 * 0])), cursor2)); cursor = veorq_u32(cursor, vld1q_u32(&p[4 * 1])); cursor = vaddq_u32(cursor, vld1q_u32(&p[4 * 2])); @@ -58,10 +59,12 @@ u32 QuickTexHashNEON(const void *checkp, u32 size) { } cursor = vaddq_u32(cursor, vreinterpretq_u32_u16(cursor2)); - check = vgetq_lane_u32(cursor, 0) + vgetq_lane_u32(cursor, 1) + vgetq_lane_u32(cursor, 2) + vgetq_lane_u32(cursor, 3); + uint32x2_t mixed = vadd_u32(vget_high_u32(cursor), vget_low_u32(cursor)); + check = vget_lane_u32(mixed, 0) + vget_lane_u32(mixed, 1); #else // TODO: Why does this crash on iOS, but only certain devices? // It's faster than the above, but I guess it sucks to be using an iPhone. + // As of 2020 clang, it's still faster by ~1.4%. // d0/d1 (q0) - cursor // d2/d3 (q1) - cursor2 @@ -162,107 +165,6 @@ void DoUnswizzleTex16NEON(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 p } } -// NOTE: This is just a NEON version of xxhash. -// GCC sucks at making things NEON and can't seem to handle it. - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99 -# include - typedef uint8_t BYTE; - typedef uint16_t U16; - typedef uint32_t U32; - typedef int32_t S32; - typedef uint64_t U64; -#else - typedef unsigned char BYTE; - typedef unsigned short U16; - typedef unsigned int U32; - typedef signed int S32; - typedef unsigned long long U64; -#endif - -#define PRIME32_1 2654435761U -#define PRIME32_2 2246822519U -#define PRIME32_3 3266489917U -#define PRIME32_4 668265263U -#define PRIME32_5 374761393U - -#if defined(_MSC_VER) -# define XXH_rotl32(x,r) _rotl(x,r) -#else -# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) -#endif - -u32 ReliableHash32NEON(const void *input, size_t len, u32 seed) { - if (((uintptr_t)input & 3) != 0) { - // Cannot handle misaligned data. Fall back to XXH32. - return XXH32(input, len, seed); - } - - const u8 *p = (const u8 *)input; - const u8 *const bEnd = p + len; - U32 h32; - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (p==NULL) { len=0; p=(const BYTE*)(size_t)16; } -#endif - - if (len>=16) - { - const BYTE* const limit = bEnd - 16; - U32 v1 = seed + PRIME32_1 + PRIME32_2; - U32 v2 = seed + PRIME32_2; - U32 v3 = seed + 0; - U32 v4 = seed - PRIME32_1; - - uint32x4_t prime32_1q = vdupq_n_u32(PRIME32_1); - uint32x4_t prime32_2q = vdupq_n_u32(PRIME32_2); - uint32x4_t vq = vcombine_u32(vcreate_u32(v1 | ((U64)v2 << 32)), vcreate_u32(v3 | ((U64)v4 << 32))); - - do { - __builtin_prefetch(p + 0xc0, 0, 0); - vq = vmlaq_u32(vq, vld1q_u32((const U32*)p), prime32_2q); - vq = vorrq_u32(vshlq_n_u32(vq, 13), vshrq_n_u32(vq, 32 - 13)); - p += 16; - vq = vmulq_u32(vq, prime32_1q); - } while (p<=limit); - - v1 = vgetq_lane_u32(vq, 0); - v2 = vgetq_lane_u32(vq, 1); - v3 = vgetq_lane_u32(vq, 2); - v4 = vgetq_lane_u32(vq, 3); - - h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); - } - else - { - h32 = seed + PRIME32_5; - } - - h32 += (U32) len; - - while (p<=bEnd-4) - { - h32 += *(const U32*)p * PRIME32_3; - h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; - p+=4; - } - - while (p> 15; - h32 *= PRIME32_2; - h32 ^= h32 >> 13; - h32 *= PRIME32_3; - h32 ^= h32 >> 16; - - return h32; -} - static inline bool VectorIsNonZeroNEON(const uint32x4_t &v) { u64 low = vgetq_lane_u64(vreinterpretq_u64_u32(v), 0); u64 high = vgetq_lane_u64(vreinterpretq_u64_u32(v), 1); diff --git a/GPU/Common/TextureDecoderNEON.h b/GPU/Common/TextureDecoderNEON.h index 02c3a8ec70..6d3b5cf45a 100644 --- a/GPU/Common/TextureDecoderNEON.h +++ b/GPU/Common/TextureDecoderNEON.h @@ -19,7 +19,6 @@ u32 QuickTexHashNEON(const void *checkp, u32 size); void DoUnswizzleTex16NEON(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 pitch); -u32 ReliableHash32NEON(const void *input, size_t len, u32 seed); CheckAlphaResult CheckAlphaRGBA8888NEON(const u32 *pixelData, int stride, int w, int h); CheckAlphaResult CheckAlphaABGR4444NEON(const u32 *pixelData, int stride, int w, int h); diff --git a/GPU/Common/TextureScalerCommon.cpp b/GPU/Common/TextureScalerCommon.cpp index cfdf98af16..0bd5d2e958 100644 --- a/GPU/Common/TextureScalerCommon.cpp +++ b/GPU/Common/TextureScalerCommon.cpp @@ -15,13 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#if _MSC_VER == 1700 -// Has to be included before TextureScaler.h, else we get those std::bind errors in VS2012.. -#include "../native/base/basictypes.h" -#endif - #include -#include #include #include #include @@ -31,9 +25,8 @@ #include "Core/Config.h" #include "Common/Common.h" #include "Common/Log.h" -#include "Common/MsgHandler.h" #include "Common/CommonFuncs.h" -#include "Common/ThreadPools.h" +#include "Core/ThreadPools.h" #include "Common/CPUDetect.h" #include "ext/xbrz/xbrz.h" @@ -47,7 +40,7 @@ //#define DEBUG_SCALER_OUTPUT #ifdef SCALING_MEASURE_TIME -#include "base/timeutil.h" +#include "Common/TimeUtil.h" #endif /////////////////////////////////////// Helper Functions (mostly math for parallelization) @@ -551,7 +544,7 @@ void TextureScalerCommon::ScaleAlways(u32 *out, u32 *src, u32 &dstFmt, int &widt bool TextureScalerCommon::ScaleInto(u32 *outputBuf, u32 *src, u32 &dstFmt, int &width, int &height, int factor) { #ifdef SCALING_MEASURE_TIME - double t_start = real_time_now(); + double t_start = time_now_d(); #endif bufInput.resize(width*height); // used to store the input image image if it needs to be reformatted @@ -592,7 +585,7 @@ bool TextureScalerCommon::ScaleInto(u32 *outputBuf, u32 *src, u32 &dstFmt, int & #ifdef SCALING_MEASURE_TIME if (width*height > 64 * 64 * factor*factor) { - double t = real_time_now() - t_start; + double t = time_now_d() - t_start; NOTICE_LOG(G3D, "TextureScaler: processed %9d pixels in %6.5lf seconds. (%9.2lf Mpixels/second)", width*height, t, (width*height) / (t * 1000 * 1000)); } diff --git a/GPU/Common/TransformCommon.h b/GPU/Common/TransformCommon.h index 0c528133c5..0a97975d26 100644 --- a/GPU/Common/TransformCommon.h +++ b/GPU/Common/TransformCommon.h @@ -18,8 +18,7 @@ #pragma once #include -#include "base/basictypes.h" -#include "Common/Log.h" + #include "Common/CommonTypes.h" #include "Core/Reporting.h" #include "GPU/ge_constants.h" diff --git a/GPU/Common/VertexDecoderArm.cpp b/GPU/Common/VertexDecoderArm.cpp index f4fde1e097..0feb2df100 100644 --- a/GPU/Common/VertexDecoderArm.cpp +++ b/GPU/Common/VertexDecoderArm.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "ppsspp_config.h" + #if PPSSPP_ARCH(ARM) // This allows highlighting to work. Yay. @@ -25,7 +26,6 @@ #include -#include "base/logging.h" #include "Common/CPUDetect.h" #include "Core/Config.h" #include "Core/Reporting.h" @@ -543,7 +543,7 @@ void VertexDecoderJitCache::Jit_WeightsU16Skin() { void VertexDecoderJitCache::Jit_WeightsFloatSkin() { for (int i = 1; i < dec_->nweights; ++i) { - _dbg_assert_msg_(JIT, weightRegs[i - 1] + 1 == weightRegs[i], "VertexDecoder weightRegs must be in order."); + _dbg_assert_msg_(weightRegs[i - 1] + 1 == weightRegs[i], "VertexDecoder weightRegs must be in order."); } // Weights are always first, so we can use srcReg directly. @@ -1210,8 +1210,8 @@ void VertexDecoderJitCache::Jit_NormalFloat() { // Through expands into floats, always. Might want to look at changing this. void VertexDecoderJitCache::Jit_PosS8Through() { DEBUG_LOG_REPORT_ONCE(vertexS8Through, G3D, "Using S8 positions in throughmode"); - _dbg_assert_msg_(JIT, fpScratchReg + 1 == fpScratchReg2, "VertexDecoder fpScratchRegs must be in order."); - _dbg_assert_msg_(JIT, fpScratchReg2 + 1 == fpScratchReg3, "VertexDecoder fpScratchRegs must be in order."); + _dbg_assert_msg_(fpScratchReg + 1 == fpScratchReg2, "VertexDecoder fpScratchRegs must be in order."); + _dbg_assert_msg_(fpScratchReg2 + 1 == fpScratchReg3, "VertexDecoder fpScratchRegs must be in order."); // TODO: SIMD LDRSB(tempReg1, srcReg, dec_->posoff); @@ -1236,8 +1236,8 @@ void VertexDecoderJitCache::Jit_PosS8Through() { // Through expands into floats, always. Might want to look at changing this. void VertexDecoderJitCache::Jit_PosS16Through() { - _dbg_assert_msg_(JIT, fpScratchReg + 1 == fpScratchReg2, "VertexDecoder fpScratchRegs must be in order."); - _dbg_assert_msg_(JIT, fpScratchReg2 + 1 == fpScratchReg3, "VertexDecoder fpScratchRegs must be in order."); + _dbg_assert_msg_(fpScratchReg + 1 == fpScratchReg2, "VertexDecoder fpScratchRegs must be in order."); + _dbg_assert_msg_(fpScratchReg2 + 1 == fpScratchReg3, "VertexDecoder fpScratchRegs must be in order."); LDRSH(tempReg1, srcReg, dec_->posoff); LDRSH(tempReg2, srcReg, dec_->posoff + 2); @@ -1301,7 +1301,7 @@ void VertexDecoderJitCache::Jit_NormalS16Skin() { void VertexDecoderJitCache::Jit_NormalFloatSkin() { for (int i = 1; i < 3; ++i) { - _dbg_assert_msg_(JIT, src[i - 1] + 1 == src[i], "VertexDecoder src regs must be in order."); + _dbg_assert_msg_(src[i - 1] + 1 == src[i], "VertexDecoder src regs must be in order."); } ADD(tempReg1, srcReg, dec_->nrmoff); @@ -1325,8 +1325,8 @@ void VertexDecoderJitCache::Jit_WriteMatrixMul(int outOff, bool pos) { } VST1(F_32, accNEON, scratchReg, 2); } else { - _dbg_assert_msg_(JIT, fpScratchReg + 1 == fpScratchReg2, "VertexDecoder fpScratchRegs must be in order."); - _dbg_assert_msg_(JIT, fpScratchReg2 + 1 == fpScratchReg3, "VertexDecoder fpScratchRegs must be in order."); + _dbg_assert_msg_(fpScratchReg + 1 == fpScratchReg2, "VertexDecoder fpScratchRegs must be in order."); + _dbg_assert_msg_(fpScratchReg2 + 1 == fpScratchReg3, "VertexDecoder fpScratchRegs must be in order."); MOVP2R(tempReg1, skinMatrix); VLDMIA(tempReg1, true, fpScratchReg, 3); @@ -1364,7 +1364,7 @@ void VertexDecoderJitCache::Jit_PosS16Skin() { void VertexDecoderJitCache::Jit_PosFloatSkin() { for (int i = 1; i < 3; ++i) { - _dbg_assert_msg_(JIT, src[i - 1] + 1 == src[i], "VertexDecoder src regs must be in order."); + _dbg_assert_msg_(src[i - 1] + 1 == src[i], "VertexDecoder src regs must be in order."); } ADD(tempReg1, srcReg, dec_->posoff); diff --git a/GPU/Common/VertexDecoderArm64.cpp b/GPU/Common/VertexDecoderArm64.cpp index a4714ee070..c1ec8770bc 100644 --- a/GPU/Common/VertexDecoderArm64.cpp +++ b/GPU/Common/VertexDecoderArm64.cpp @@ -18,13 +18,8 @@ #include "ppsspp_config.h" #if PPSSPP_ARCH(ARM64) -// This allows highlighting to work. Yay. -#ifdef __INTELLISENSE__ -#define ARM64 -#endif - -#include "base/logging.h" #include "Common/CPUDetect.h" +#include "Common/Log.h" #include "Core/Config.h" #include "Core/Reporting.h" #include "Common/Arm64Emitter.h" @@ -287,12 +282,12 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int if (log) { char temp[1024] = { 0 }; dec.ToString(temp); - ILOG("=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start)); + INFO_LOG(JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start)); std::vector lines = DisassembleArm64(start, (int)(GetCodePtr() - start)); for (auto line : lines) { - ILOG("%s", line.c_str()); + INFO_LOG(JIT, "%s", line.c_str()); } - ILOG("=========="); + INFO_LOG(JIT, "=========="); } *jittedSize = (int)(GetCodePtr() - start); diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 0b8ee6736c..d0cdbb5b29 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -18,11 +18,12 @@ #include #include -#include "base/basictypes.h" -#include "base/logging.h" +#include "ppsspp_config.h" +#include "Common/Log.h" #include "Common/CPUDetect.h" #include "Common/ColorConv.h" +#include "Common/Common.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/MemMap.h" @@ -1345,11 +1346,11 @@ std::string VertexDecoder::GetString(DebugShaderStringType stringType) { if (!jitted_) return "Not compiled"; std::vector lines; -#if defined(ARM64) +#if PPSSPP_ARCH(ARM64) lines = DisassembleArm64((const u8 *)jitted_, jittedSize_); -#elif defined(ARM) +#elif PPSSPP_ARCH(ARM) lines = DisassembleArm2((const u8 *)jitted_, jittedSize_); -#elif defined(MIPS) +#elif PPSSPP_ARCH(MIPS) || PPSSPP_ARCH(MIPS64) // No MIPS disassembler defined #else lines = DisassembleX86((const u8 *)jitted_, jittedSize_); diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 209186fd96..6013b1a356 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -18,11 +18,12 @@ #pragma once #include + #include "ppsspp_config.h" -#include "base/basictypes.h" -#include "Common/Hashmaps.h" + +#include "Common/Common.h" +#include "Common/Data/Collections/Hashmaps.h" #include "Common/Log.h" -#include "Common/CommonTypes.h" #include "Core/Reporting.h" #include "GPU/ge_constants.h" #include "GPU/Common/ShaderCommon.h" diff --git a/GPU/Common/VertexDecoderFake.cpp b/GPU/Common/VertexDecoderFake.cpp index 1619b2ba0f..af27e69561 100644 --- a/GPU/Common/VertexDecoderFake.cpp +++ b/GPU/Common/VertexDecoderFake.cpp @@ -18,7 +18,6 @@ //TODO: Doesn't build, FIXME! #if 0 -#include "base/logging.h" #include "Common/CPUDetect.h" #include "Core/Config.h" #include "Core/Reporting.h" diff --git a/GPU/Common/VertexDecoderX86.cpp b/GPU/Common/VertexDecoderX86.cpp index e67b50fea0..6fb69c99df 100644 --- a/GPU/Common/VertexDecoderX86.cpp +++ b/GPU/Common/VertexDecoderX86.cpp @@ -167,7 +167,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int BeginWrite(); const u8 *start = this->AlignCode16(); -#ifdef _M_IX86 +#if PPSSPP_ARCH(X86) // Store register values PUSH(ESI); PUSH(EDI); @@ -179,12 +179,20 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int MOV(32, R(srcReg), MDisp(ESP, 16 + offset + 0)); MOV(32, R(dstReg), MDisp(ESP, 16 + offset + 4)); MOV(32, R(counterReg), MDisp(ESP, 16 + offset + 8)); + + const uint8_t STACK_FIXED_ALLOC = 64; +#else + // Parameters automatically fall into place. + + // This will align the stack properly to 16 bytes (the call of this function pushed RIP, which is 8 bytes). + const uint8_t STACK_FIXED_ALLOC = 64 + 8; #endif + // Allocate temporary storage on the stack. + SUB(PTRBITS, R(ESP), Imm8(STACK_FIXED_ALLOC)); // Save XMM4/XMM5 which apparently can be problematic? // Actually, if they are, it must be a compiler bug because they SHOULD be ok. // So I won't bother. - SUB(PTRBITS, R(ESP), Imm8(64)); MOVUPS(MDisp(ESP, 0), XMM4); MOVUPS(MDisp(ESP, 16), XMM5); MOVUPS(MDisp(ESP, 32), XMM6); @@ -265,7 +273,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int MOVUPS(XMM5, MDisp(ESP, 16)); MOVUPS(XMM6, MDisp(ESP, 32)); MOVUPS(XMM7, MDisp(ESP, 48)); - ADD(PTRBITS, R(ESP), Imm8(64)); + ADD(PTRBITS, R(ESP), Imm8(STACK_FIXED_ALLOC)); #ifdef _M_IX86 // Restore register values @@ -1452,8 +1460,8 @@ void VertexDecoderJitCache::Jit_AnyS16ToFloat(int srcoff) { } void VertexDecoderJitCache::Jit_AnyU8ToFloat(int srcoff, u32 bits) { - _dbg_assert_msg_(JIT, (bits & ~(32 | 16 | 8)) == 0, "Bits must be a multiple of 8."); - _dbg_assert_msg_(JIT, bits >= 8 && bits <= 32, "Bits must be a between 8 and 32."); + _dbg_assert_msg_((bits & ~(32 | 16 | 8)) == 0, "Bits must be a multiple of 8."); + _dbg_assert_msg_(bits >= 8 && bits <= 32, "Bits must be a between 8 and 32."); if (!cpu_info.bSSE4_1) { PXOR(XMM3, R(XMM3)); @@ -1484,8 +1492,8 @@ void VertexDecoderJitCache::Jit_AnyU8ToFloat(int srcoff, u32 bits) { } void VertexDecoderJitCache::Jit_AnyU16ToFloat(int srcoff, u32 bits) { - _dbg_assert_msg_(JIT, (bits & ~(64 | 32 | 16)) == 0, "Bits must be a multiple of 16."); - _dbg_assert_msg_(JIT, bits >= 16 && bits <= 64, "Bits must be a between 16 and 64."); + _dbg_assert_msg_((bits & ~(64 | 32 | 16)) == 0, "Bits must be a multiple of 16."); + _dbg_assert_msg_(bits >= 16 && bits <= 64, "Bits must be a between 16 and 64."); if (!cpu_info.bSSE4_1) { PXOR(XMM3, R(XMM3)); diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index a3b2e963af..ee6ad435d3 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -3,18 +3,19 @@ #include #include #include +#include #include #include - #if PPSSPP_PLATFORM(UWP) #define ptr_D3DCompile D3DCompile #else -#include "thin3d/d3d11_loader.h" +#include "Common/GPU/D3D11/D3D11Loader.h" #endif -#include "base/logging.h" -#include "base/stringutil.h" +#include "Common/CommonFuncs.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" #include "D3D11Util.h" @@ -25,7 +26,7 @@ static std::vector CompileShaderToBytecode(const char *code, size_t cod std::string errors; if (errorMsgs) { errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); - ELOG("%s: %s", SUCCEEDED(result) ? "warnings" : "errors", errors.c_str()); + ERROR_LOG(G3D, "%s: %s", SUCCEEDED(result) ? "warnings" : "errors", errors.c_str()); OutputDebugStringA(LineNumberString(code).c_str()); errorMsgs->Release(); } @@ -126,7 +127,7 @@ void StockObjectsD3D11::Create(ID3D11Device *device) { sampler_desc.MinLOD = -FLT_MAX; sampler_desc.MaxLOD = FLT_MAX; sampler_desc.MipLODBias = 0.0f; - sampler_desc.MaxAnisotropy = 1.0f; + sampler_desc.MaxAnisotropy = 1; ASSERT_SUCCESS(device->CreateSamplerState(&sampler_desc, &samplerPoint2DWrap)); sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; ASSERT_SUCCESS(device->CreateSamplerState(&sampler_desc, &samplerLinear2DWrap)); diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index 854c38b34b..faf6c22de2 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -18,8 +18,7 @@ #include #include -#include "base/basictypes.h" -#include "base/logging.h" +#include "Common/Common.h" #include "Common/Log.h" #include "Common/ColorConv.h" #include "Common/StringUtils.h" diff --git a/GPU/D3D11/DepalettizeShaderD3D11.h b/GPU/D3D11/DepalettizeShaderD3D11.h index df9c4f5133..0941330fa6 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.h +++ b/GPU/D3D11/DepalettizeShaderD3D11.h @@ -22,7 +22,7 @@ #include "Common/CommonTypes.h" #include "GPU/ge_constants.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" #include "GPU/Common/DepalettizeShaderCommon.h" class DepalShaderD3D11 { diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index fde2dd0102..fbfd4f820f 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -17,10 +17,9 @@ #include -#include "base/logging.h" -#include "base/timeutil.h" - +#include "Common/Log.h" #include "Common/MemoryUtil.h" +#include "Common/TimeUtil.h" #include "Core/MemMap.h" #include "Core/System.h" #include "Core/Reporting.h" @@ -307,6 +306,8 @@ void DrawEngineD3D11::BeginFrame() { NOTICE_LOG(G3D, buffer); } #endif + + lastRenderStepId_ = -1; } VertexArrayInfoD3D11::~VertexArrayInfoD3D11() { @@ -325,6 +326,14 @@ void DrawEngineD3D11::DoFlush() { gpuStats.numFlushes++; gpuStats.numTrackedVertexArrays = (int)vai_.size(); + // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. + int curRenderStepId = draw_->GetCurrentStepId(); + if (lastRenderStepId_ != curRenderStepId) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + lastRenderStepId_ = curRenderStepId; + } + // This is not done on every drawcall, we collect vertex data // until critical state changes. That's when we draw (flush). @@ -362,7 +371,7 @@ void DrawEngineD3D11::DoFlush() { case VertexArrayInfoD3D11::VAI_NEW: { // Haven't seen this one before. - ReliableHashType dataHash = ComputeHash(); + uint64_t dataHash = ComputeHash(); vai->hash = dataHash; vai->minihash = ComputeMiniHash(); vai->status = VertexArrayInfoD3D11::VAI_HASHING; @@ -386,7 +395,7 @@ void DrawEngineD3D11::DoFlush() { if (vai->drawsUntilNextFullHash == 0) { // Let's try to skip a full hash if mini would fail. const u32 newMiniHash = ComputeMiniHash(); - ReliableHashType newHash = vai->hash; + uint64_t newHash = vai->hash; if (newMiniHash == vai->minihash) { newHash = ComputeHash(); } @@ -427,7 +436,7 @@ void DrawEngineD3D11::DoFlush() { vai->numVerts = indexGen.PureCount(); } - _dbg_assert_msg_(G3D, gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); + _dbg_assert_msg_(gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); // TODO: Combine these two into one buffer? u32 size = dec_->GetDecVtxFmt().stride * indexGen.MaxIndex(); @@ -590,6 +599,9 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); } + if (result.setSafeSize) + framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + if (result.action == SW_DRAW_PRIMITIVES) { const int vertexSize = sizeof(transformed[0]); @@ -653,12 +665,11 @@ rotateVBO: uint8_t clearStencil = clearColor >> 24; draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil); - int scissorX2 = gstate.getScissorX2() + 1; - int scissorY2 = gstate.getScissorY2() + 1; - framebufferManager_->SetSafeSize(scissorX2, scissorY2); 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(); + int scissorX2 = gstate.getScissorX2() + 1; + int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 11ed3e41e9..fbc94f2d7a 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -21,7 +21,7 @@ #include #include -#include "Common/Hashmaps.h" +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/GPUState.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/IndexGenerator.h" @@ -79,7 +79,7 @@ public: VAI_UNRELIABLE, // never cache }; - ReliableHashType hash; + uint64_t hash; u32 minihash; ID3D11Buffer *vbo; @@ -216,4 +216,6 @@ private: // Hardware tessellation TessellationDataTransferD3D11 *tessDataTransferD3D11; + + int lastRenderStepId_ = -1; }; diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 70e2b19bfc..437fe4922c 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -19,13 +19,13 @@ #include #include -#include "base/display.h" -#include "math/lin/matrix4x4.h" -#include "ext/native/thin3d/thin3d.h" -#include "base/basictypes.h" - +#include "Common/Common.h" +#include "Common/System/Display.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Math/math_util.h" +#include "Common/GPU/thin3d.h" #include "Common/ColorConv.h" -#include "Common/MathUtil.h" + #include "Core/MemMap.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -34,8 +34,7 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "GPU/Debugger/Stepping.h" - -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" #include "GPU/Common/ShaderTranslation.h" #include "GPU/Common/TextureDecoder.h" @@ -267,7 +266,7 @@ void FramebufferManagerD3D11::ReformatFramebufferFrom(VirtualFramebuffer *vfb, G // and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex // to exactly reproduce in 4444 and 8888 formats. if (old == GE_FORMAT_565) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "ReformatFramebuffer"); context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0xFF); context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[D3D11_COLOR_WRITE_ENABLE_ALPHA], nullptr, 0xFFFFFFFF); @@ -315,18 +314,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { } } -void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - 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; - if (matchingDepthBuffer && matchingSize && matchingRenderSize) { - // TODO: Currently, this copies depth AND stencil, which is a problem. See #9740. - draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, src->renderWidth, src->renderHeight, 1, Draw::FB_DEPTH_BIT); - RebindFramebuffer(); - dst->last_frame_depth_updated = gpuStats.numFlips; - } -} - void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { if (!framebuffer->fbo || !useBufferedRendering_) { ID3D11ShaderResourceView *view = nullptr; @@ -349,7 +336,7 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr VirtualFramebuffer copyInfo = *framebuffer; copyInfo.fbo = renderCopy; CopyFramebufferForColorTexture(©Info, framebuffer, flags); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - BindFramebufferAsColorTexture"); draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0); } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); @@ -380,7 +367,7 @@ void FramebufferManagerD3D11::SimpleBlit( if (srcW == destW && srcH == destH && destX2 - destX1 == srcX2 - srcX1 && destY2 - destY1 == srcY2 - srcY1) { // Optimize to a copy - draw_->CopyFramebufferImage(src, 0, (int)srcX1, (int)srcY1, 0, dest, 0, (int)destX1, (int)destY1, 0, (int)(srcX2 - srcX1), (int)(srcY2 - srcY1), 1, Draw::FB_COLOR_BIT); + draw_->CopyFramebufferImage(src, 0, (int)srcX1, (int)srcY1, 0, dest, 0, (int)destX1, (int)destY1, 0, (int)(srcX2 - srcX1), (int)(srcY2 - srcY1), 1, Draw::FB_COLOR_BIT, "SimpleBlit"); return; } @@ -405,7 +392,7 @@ void FramebufferManagerD3D11::SimpleBlit( // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). draw_->BindTexture(0, nullptr); - draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "SimpleBlit"); draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0); Bind2DShader(); @@ -428,7 +415,7 @@ void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, if (!dst->fbo || !src->fbo || !useBufferedRendering_) { // This can happen if they recently switched from non-buffered. if (useBufferedRendering_) { - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer_Fail"); } return; } diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 73b917f326..a8a4089198 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -24,8 +24,8 @@ // pixel data. #include "GPU/GPUCommon.h" -#include "GPU/Common/FramebufferCommon.h" -#include "ext/native/thin3d/thin3d.h" +#include "GPU/Common/FramebufferManagerCommon.h" +#include "Common/GPU/thin3d.h" class TextureCacheD3D11; class DrawEngineD3D11; @@ -45,11 +45,9 @@ public: void DeviceLost(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; - void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); - virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; + virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; // TODO: Remove ID3D11Buffer *GetDynamicQuadBuffer() { diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 6e497064c7..a8f7b95fa6 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -36,12 +36,12 @@ #include -#include "Common/ChunkFile.h" +#include "Common/Log.h" +#include "Common/Serialize/Serializer.h" #include "Common/GraphicsContext.h" -#include "base/NativeApp.h" -#include "base/logging.h" -#include "profiler/profiler.h" -#include "i18n/i18n.h" +#include "Common/System/System.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Data/Text/I18n.h" #include "Core/Debugger/Breakpoints.h" #include "Core/MemMapHelpers.h" #include "Core/MIPS/MIPS.h" @@ -53,7 +53,7 @@ #include "GPU/ge_constants.h" #include "GPU/GeDisasm.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Debugger/Debugger.h" #include "GPU/D3D11/ShaderManagerD3D11.h" #include "GPU/D3D11/GPU_D3D11.h" @@ -119,7 +119,6 @@ GPU_D3D11::~GPU_D3D11() { shaderManagerD3D11_->ClearShaders(); delete shaderManagerD3D11_; delete textureCacheD3D11_; - draw_->BindPipeline(nullptr); stockD3D11.Destroy(); } @@ -143,16 +142,14 @@ void GPU_D3D11::CheckGPUFeatures() { #endif features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; - features |= GPU_SUPPORTS_LARGE_VIEWPORTS; if (draw_->GetDeviceCaps().dualSourceBlend) features |= GPU_SUPPORTS_DUALSOURCE_BLEND; if (draw_->GetDeviceCaps().depthClampSupported) features |= GPU_SUPPORTS_DEPTH_CLAMP; - features |= GPU_SUPPORTS_ANY_COPY_IMAGE; + features |= GPU_SUPPORTS_COPY_IMAGE; features |= GPU_SUPPORTS_TEXTURE_FLOAT; features |= GPU_SUPPORTS_INSTANCE_RENDERING; features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - features |= GPU_SUPPORTS_FBO; uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16); uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16); @@ -196,6 +193,7 @@ void GPU_D3D11::BuildReportingInfo() { } void GPU_D3D11::DeviceLost() { + draw_->InvalidateCachedState(); // Simply drop all caches and textures. // FBOs appear to survive? Or no? shaderManagerD3D11_->ClearShaders(); @@ -234,8 +232,8 @@ void GPU_D3D11::ReapplyGfxState() { } void GPU_D3D11::EndHostFrame() { - // Tell the DrawContext that it's time to reset everything. - draw_->BindPipeline(nullptr); + // Probably not really necessary. + draw_->InvalidateCachedState(); } void GPU_D3D11::BeginFrame() { @@ -307,38 +305,13 @@ void GPU_D3D11::ExecuteOp(u32 op, u32 diff) { } void GPU_D3D11::GetStats(char *buffer, size_t bufsize) { - float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; - snprintf(buffer, bufsize - 1, - "DL processing time: %0.2f ms\n" - "Draw calls: %i, flushes %i, clears %i\n" - "Cached Draw calls: %i\n" - "Num Tracked Vertex Arrays: %i\n" - "GPU cycles executed: %d (%f per vertex)\n" - "Commands per call level: %i %i %i %i\n" - "Vertices submitted: %i\n" - "Cached, Uncached Vertices Drawn: %i, %i\n" - "FBOs active: %i\n" - "Textures active: %i, decoded: %i invalidated: %i\n" - "Readbacks: %d, uploads: %d\n" - "Vertex, Fragment shaders loaded: %i, %i\n", - gpuStats.msProcessingDisplayLists * 1000.0f, - gpuStats.numDrawCalls, - gpuStats.numFlushes, - gpuStats.numClears, - gpuStats.numCachedDrawCalls, - gpuStats.numTrackedVertexArrays, - gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles, - vertexAverageCycles, - gpuStats.gpuCommandsAtCallLevel[0], gpuStats.gpuCommandsAtCallLevel[1], gpuStats.gpuCommandsAtCallLevel[2], gpuStats.gpuCommandsAtCallLevel[3], - gpuStats.numVertsSubmitted, - gpuStats.numCachedVertsDrawn, - gpuStats.numUncachedVertsDrawn, - (int)framebufferManagerD3D11_->NumVFBs(), - (int)textureCacheD3D11_->NumLoadedTextures(), - gpuStats.numTexturesDecoded, - gpuStats.numTextureInvalidations, - gpuStats.numReadbacks, - gpuStats.numUploads, + size_t offset = FormatGPUStatsCommon(buffer, bufsize); + buffer += offset; + bufsize -= offset; + if ((int)bufsize < 0) + return; + snprintf(buffer, bufsize, + "Vertex, Fragment shaders loaded: %d, %d\n", shaderManagerD3D11_->GetNumVertexShaders(), shaderManagerD3D11_->GetNumFragmentShaders() ); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index 0c1f1d3524..bf41243b88 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -17,19 +17,19 @@ #pragma once -#include -#include +#include +#include #include #include "GPU/GPUCommon.h" #include "GPU/D3D11/DrawEngineD3D11.h" -#include "GPU/D3D11/TextureCacheD3D11.h" #include "GPU/D3D11/DepalettizeShaderD3D11.h" #include "GPU/Common/VertexDecoderCommon.h" class FramebufferManagerD3D11; class ShaderManagerD3D11; class LinkedShaderD3D11; +class TextureCacheD3D11; class GPU_D3D11 : public GPUCommon { public: diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 5e4a39c062..4678f4ae65 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -22,12 +22,12 @@ #include -#include "base/logging.h" -#include "math/lin/matrix4x4.h" -#include "math/math_util.h" -#include "math/dataconv.h" -#include "thin3d/thin3d.h" -#include "util/text/utf8.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Math/math_util.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Log.h" #include "Common/Common.h" #include "Core/Config.h" #include "Core/Reporting.h" diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h index fd90d57d6b..abb867a613 100644 --- a/GPU/D3D11/ShaderManagerD3D11.h +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -21,7 +21,7 @@ #include -#include "base/basictypes.h" +#include "Common/Common.h" #include "GPU/Common/ShaderCommon.h" #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderUniforms.h" diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 51674571c8..8ef3d2c574 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -18,7 +18,9 @@ #include #include -#include "math/dataconv.h" +#include + +#include "Common/Data/Convert/SmallDataConvert.h" #include "GPU/Math3D.h" #include "GPU/GPUState.h" @@ -28,7 +30,7 @@ #include "Core/Config.h" #include "Core/Reporting.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/D3D11/DrawEngineD3D11.h" #include "GPU/D3D11/StateMappingD3D11.h" #include "GPU/D3D11/FramebufferManagerD3D11.h" @@ -276,14 +278,13 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) { keys_.raster.value = 0; + bool wantCull = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); + keys_.raster.cullMode = wantCull ? (gstate.getCullMode() ? D3D11_CULL_FRONT : D3D11_CULL_BACK) : D3D11_CULL_NONE; + if (gstate.isModeClear() || gstate.isModeThrough()) { - keys_.raster.cullMode = D3D11_CULL_NONE; // TODO: Might happen in clear mode if not through... keys_.raster.depthClipEnable = 1; } else { - // Set cull - bool wantCull = prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); - keys_.raster.cullMode = wantCull ? (gstate.getCullMode() ? D3D11_CULL_FRONT : D3D11_CULL_BACK) : D3D11_CULL_NONE; if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... diff --git a/GPU/D3D11/StateMappingD3D11.h b/GPU/D3D11/StateMappingD3D11.h index df6f4a2adf..b6e356d4de 100644 --- a/GPU/D3D11/StateMappingD3D11.h +++ b/GPU/D3D11/StateMappingD3D11.h @@ -3,7 +3,7 @@ #include #include -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" // TODO: Do this more progressively. No need to compute the entire state if the entire state hasn't changed. diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp index ad9faa7f0a..4da469ae61 100644 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -17,9 +17,9 @@ #include -#include "base/logging.h" +#include "Common/GPU/thin3d.h" -#include "ext/native/thin3d/thin3d.h" +#include "Common/Log.h" #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" #include "GPU/D3D11/FramebufferManagerD3D11.h" @@ -70,7 +70,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) { +bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; @@ -117,7 +117,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ } if (usedBits == 0) { - if (skipZero) { + if (flags == StencilUpload::STENCIL_IS_ZERO) { // Common when creating buffers, it's already 0. We're done. return false; } @@ -164,7 +164,9 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ if (!tex) return false; if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + // Typically, STENCIL_IS_ZERO means it's already bound. + Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR; + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "Stencil"); } else { // something is wrong... } @@ -197,7 +199,6 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_); context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DClamp); context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE); for (int i = 1; i < values; i += i) { if (!(usedBits & i)) { @@ -241,6 +242,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ } tex->Release(); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer stencil"); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); return true; } diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 15f9e745d0..b136e06020 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -15,9 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include #include -#include #include #include @@ -32,13 +30,13 @@ #include "GPU/D3D11/ShaderManagerD3D11.h" #include "GPU/D3D11/DepalettizeShaderD3D11.h" #include "GPU/D3D11/D3D11Util.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/TextureDecoder.h" #include "Core/Config.h" #include "Core/Host.h" #include "ext/xxhash.h" -#include "math/math_util.h" +#include "Common/Math/math_util.h" #define INVALID_TEX (ID3D11ShaderResourceView *)(-1LL) @@ -146,40 +144,13 @@ void TextureCacheD3D11::ReleaseTexture(TexCacheEntry *entry, bool delete_them) { void TextureCacheD3D11::ForgetLastTexture() { InvalidateLastTexture(); - gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); - ID3D11ShaderResourceView *nullTex = nullptr; - context_->PSSetShaderResources(0, 1, &nullTex); + + ID3D11ShaderResourceView *nullTex[2]{}; + context_->PSSetShaderResources(0, 2, nullTex); } -void TextureCacheD3D11::InvalidateLastTexture(TexCacheEntry *entry) { - if (!entry || entry->texturePtr == lastBoundTexture) { - lastBoundTexture = INVALID_TEX; - } -} - -void TextureCacheD3D11::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key) { - int minFilt; - int magFilt; - bool sClamp; - bool tClamp; - float lodBias; - GETexLevelMode mode; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, mode); - - key.minFilt = minFilt & 1; - key.mipFilt = 0; - key.magFilt = magFilt & 1; - key.sClamp = sClamp; - key.tClamp = tClamp; - - // Often the framebuffer will not match the texture size. We'll wrap/clamp in the shader in that case. - // This happens whether we have OES_texture_npot or not. - int w = gstate.getTextureWidth(0); - int h = gstate.getTextureHeight(0); - if (w != bufferWidth || h != bufferHeight) { - key.sClamp = true; - key.tClamp = true; - } +void TextureCacheD3D11::InvalidateLastTexture() { + lastBoundTexture = INVALID_TEX; } void TextureCacheD3D11::StartFrame() { @@ -209,7 +180,10 @@ void TextureCacheD3D11::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBa // Adding clutBaseBytes may just be mitigating this for some usage patterns. const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); - clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + if (replacer_.Enabled()) + clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + else + clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF; clutBuf_ = clutBufRaw_; // Special optimization: fonts typically draw clut4 with just alpha values in a single color. @@ -237,9 +211,9 @@ void TextureCacheD3D11::BindTexture(TexCacheEntry *entry) { context_->PSSetShaderResources(0, 1, &textureView); lastBoundTexture = textureView; } - SamplerCacheKey key{}; - UpdateSamplingParams(*entry, key); - ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, key); + int maxLevel = (entry->status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry->maxLevel; + SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry->addr); + ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, samplerKey); context_->PSSetSamplers(0, 1, &state); } @@ -376,10 +350,11 @@ protected: int renderH_; }; -void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { +void TextureCacheD3D11::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) { ID3D11PixelShader *pshader = nullptr; uint32_t clutMode = gstate.clutformat & 0xFFFFFF; - if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { + bool need_depalettize = IsClutFormat(texFormat); + if (need_depalettize && !g_Config.bDisableSlowFramebufEffects) { pshader = depalShaderCache_->GetDepalettizePixelShader(clutMode, framebuffer->drawnFormat); } @@ -390,7 +365,9 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra Draw::Framebuffer *depalFBO = framebufferManagerD3D11_->GetTempFBO(TempFBO::DEPAL, framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888); shaderManager_->DirtyLastShader(); - draw_->BindPipeline(nullptr); + + // Not sure why or if we need this here - we're not about to actually draw using draw_, just use its framebuffer binds. + draw_->InvalidateCachedState(); float xoff = -0.5f / framebuffer->renderWidth; float yoff = 0.5f / framebuffer->renderHeight; @@ -401,14 +378,15 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra ID3D11ShaderResourceView *nullTexture = nullptr; context_->PSSetShaderResources(0, 1, &nullTexture); // In case the target was used in the last draw call. Happens in Sega Rally. - draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "ApplyTextureFramebuffer_DepalShader"); context_->PSSetShaderResources(3, 1, &clutTexture); context_->PSSetSamplers(3, 1, &stockD3D11.samplerPoint2DWrap); framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DWrap); shaderApply.Shade(); - framebufferManagerD3D11_->RebindFramebuffer(); + context_->PSSetShaderResources(0, 1, &nullTexture); // Make D3D11 validation happy. Really of no consequence since we rebind anyway. + framebufferManagerD3D11_->RebindFramebuffer("RebindFramebuffer - ApplyTextureFramebuffer"); draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); @@ -417,37 +395,25 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra TexCacheEntry::TexStatus alphaStatus = CheckAlpha(clutBuf_, GetClutDestFormatD3D11(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); } else { - entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; - framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650); - framebufferManagerD3D11_->RebindFramebuffer(); // Probably not necessary. + framebufferManagerD3D11_->RebindFramebuffer("RebindFramebuffer - ApplyTextureFramebuffer"); // Probably not necessary. } - SamplerCacheKey samplerKey{}; - SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight, samplerKey); + + SamplerCacheKey samplerKey = GetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, samplerKey); context_->PSSetSamplers(0, 1, &state); - InvalidateLastTexture(); gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE); } - void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK; // For the estimate, we assume cluts always point to 8888 for simplicity. cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); - // TODO: If a framebuffer is attached here, might end up with a bad entry.texture. - // Should just always create one here or something (like GLES.) - - if (entry->framebuffer) { - // Nothing else to do here. - return; - } - if ((entry->bufw == 0 || (gstate.texbufwidth[0] & 0xf800) != 0) && entry->addr >= PSP_GetKernelMemoryEnd()) { ERROR_LOG_REPORT(G3D, "Texture with unexpected bufw (full=%d)", gstate.texbufwidth[0] & 0xffff); // Proceeding here can cause a crash. @@ -736,7 +702,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & pixelData = (u32 *)mapData; // We always end up at 8888. Other parts assume this. - assert(scaleFmt == DXGI_FORMAT_B8G8R8A8_UNORM); + _assert_(scaleFmt == DXGI_FORMAT_B8G8R8A8_UNORM); bpp = sizeof(u32); decPitch = w * bpp; @@ -773,27 +739,27 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & } bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) { - SetTexture(false); - if (!nextTexture_) - return false; + SetTexture(); + if (!nextTexture_) { + if (nextFramebufferTexture_) { + VirtualFramebuffer *vfb = nextFramebufferTexture_; + buffer.Allocate(vfb->bufferWidth, vfb->bufferHeight, GPU_DBG_FORMAT_8888, false); + bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->bufferWidth, vfb->bufferHeight, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), vfb->bufferWidth, "GetCurrentTextureDebug"); + // Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf. + // So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); + // We may have blitted to a temp FBO. + framebufferManager_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); + return retval; + } else { + return false; + } + } // Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer. TexCacheEntry *entry = nextTexture_; ApplyTexture(); - // TODO: Centralize. - if (entry->framebuffer) { - VirtualFramebuffer *vfb = entry->framebuffer; - buffer.Allocate(vfb->bufferWidth, vfb->bufferHeight, GPU_DBG_FORMAT_8888, false); - bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->bufferWidth, vfb->bufferHeight, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), vfb->bufferWidth); - // Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf. - // So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); - // We may have blitted to a temp FBO. - framebufferManager_->RebindFramebuffer(); - return retval; - } - ID3D11Texture2D *texture = (ID3D11Texture2D *)entry->texturePtr; if (!texture) return false; diff --git a/GPU/D3D11/TextureCacheD3D11.h b/GPU/D3D11/TextureCacheD3D11.h index 8cfa249269..ceaf64b150 100644 --- a/GPU/D3D11/TextureCacheD3D11.h +++ b/GPU/D3D11/TextureCacheD3D11.h @@ -58,9 +58,8 @@ public: } void ForgetLastTexture() override; - void InvalidateLastTexture(TexCacheEntry *entry = nullptr) override; + void InvalidateLastTexture() override; - void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key); bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override; protected: @@ -74,7 +73,7 @@ private: TexCacheEntry::TexStatus CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; - void ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) override; + void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) override; void BuildTexture(TexCacheEntry *const entry) override; ID3D11Device *device_; diff --git a/GPU/D3D11/TextureScalerD3D11.cpp b/GPU/D3D11/TextureScalerD3D11.cpp index 32c06c45ee..17dcfa3c25 100644 --- a/GPU/D3D11/TextureScalerD3D11.cpp +++ b/GPU/D3D11/TextureScalerD3D11.cpp @@ -19,7 +19,7 @@ #include #include "Common/ColorConv.h" -#include "Common/ThreadPools.h" +#include "Core/ThreadPools.h" #include "GPU/Common/TextureScalerCommon.h" #include "GPU/D3D11/TextureScalerD3D11.h" #include "GPU/D3D11/GPU_D3D11.h" diff --git a/GPU/Debugger/Breakpoints.cpp b/GPU/Debugger/Breakpoints.cpp index 401acbcdd7..90bd76c524 100644 --- a/GPU/Debugger/Breakpoints.cpp +++ b/GPU/Debugger/Breakpoints.cpp @@ -19,14 +19,13 @@ #include #include -#include "base/basictypes.h" #include "GPU/Debugger/Breakpoints.h" #include "GPU/GPUState.h" namespace GPUBreakpoints { static std::mutex breaksLock; -static std::vector breakCmds; +static bool breakCmds[256]; static std::set breakPCs; static std::set breakTextures; static std::set breakRenderTargets; @@ -36,7 +35,7 @@ static size_t breakTexturesCount = 0; static size_t breakRenderTargetsCount = 0; // If these are set, the above are also, but they should be temporary. -static std::vector breakCmdsTemp; +static bool breakCmdsTemp[256]; static std::set breakPCsTemp; static std::set breakTexturesTemp; static std::set breakRenderTargetsTemp; @@ -373,14 +372,14 @@ void UpdateLastTexture(u32 addr) { void ClearAllBreakpoints() { std::lock_guard guard(breaksLock); - breakCmds.clear(); - breakCmds.resize(256, false); + for (int i = 0; i < 256; ++i) { + breakCmds[i] = false; + breakCmdsTemp[i] = false; + } breakPCs.clear(); breakTextures.clear(); breakRenderTargets.clear(); - breakCmdsTemp.clear(); - breakCmdsTemp.resize(256, false); breakPCsTemp.clear(); breakTexturesTemp.clear(); breakRenderTargetsTemp.clear(); diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 2d5da1af3a..5c70f1066d 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Log.h" #include "GPU/GPU.h" #include "GPU/Debugger/Breakpoints.h" #include "GPU/Debugger/Debugger.h" diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index b11e0a7dda..4a7fb9ca00 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -21,11 +21,12 @@ #include #include #include -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Common/Common.h" #include "Common/Log.h" #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/ELF/ParamSFO.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceKernelMemory.h" @@ -664,23 +665,30 @@ static void ReplayStop() { } bool RunMountedReplay(const std::string &filename) { - _assert_msg_(SYSTEM, !GPURecord::IsActivePending(), "Cannot run replay while recording."); + _assert_msg_(!GPURecord::IsActivePending(), "Cannot run replay while recording."); std::lock_guard guard(executeLock); Core_ListenStopRequest(&ReplayStop); if (lastExecFilename != filename) { PROFILE_THIS_SCOPE("ReplayLoad"); u32 fp = pspFileSystem.OpenFile(filename, FILEACCESS_READ); - u8 header[8]{}; - int version = 0; - pspFileSystem.ReadFile(fp, header, sizeof(header)); - pspFileSystem.ReadFile(fp, (u8 *)&version, sizeof(version)); + Header header; + pspFileSystem.ReadFile(fp, (u8 *)&header, sizeof(header)); - if (memcmp(header, HEADER, sizeof(header)) != 0 || version > VERSION || version < MIN_VERSION) { + if (memcmp(header.magic, HEADER_MAGIC, sizeof(header.magic)) != 0 || header.version > VERSION || header.version < MIN_VERSION) { ERROR_LOG(SYSTEM, "Invalid GE dump or unsupported version"); pspFileSystem.CloseFile(fp); return false; } + if (header.version <= 3) { + pspFileSystem.SeekFile(fp, 12, FILEMOVE_BEGIN); + memset(header.gameID, 0, sizeof(header.gameID)); + } + + size_t gameIDLength = strnlen(header.gameID, sizeof(header.gameID)); + if (gameIDLength != 0) { + g_paramSFO.SetValue("DISC_ID", std::string(header.gameID, gameIDLength), (int)sizeof(header.gameID)); + } u32 sz = 0; pspFileSystem.ReadFile(fp, (u8 *)&sz, sizeof(sz)); diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 8d1b216677..4fdc32b29f 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -21,10 +21,12 @@ #include #include #include -#include "base/stringutil.h" + #include "Common/Common.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" #include "Common/Log.h" +#include "Common/StringUtils.h" + #include "Core/Core.h" #include "Core/ELF/ParamSFO.h" #include "Core/HLE/sceDisplay.h" @@ -115,8 +117,11 @@ static std::string WriteRecording() { NOTICE_LOG(G3D, "Recording filename: %s", filename.c_str()); FILE *fp = File::OpenCFile(filename, "wb"); - fwrite(HEADER, 8, 1, fp); - fwrite(&VERSION, sizeof(VERSION), 1, fp); + Header header{}; + strncpy(header.magic, HEADER_MAGIC, sizeof(header.magic)); + header.version = VERSION; + strncpy(header.gameID, g_paramSFO.GetDiscID().c_str(), sizeof(header.gameID)); + fwrite(&header, sizeof(header), 1, fp); u32 sz = (u32)commands.size(); fwrite(&sz, sizeof(sz), 1, fp); @@ -155,30 +160,43 @@ static void GetVertDataSizes(int vcount, const void *indices, u32 &vbytes, u32 & } } -static const u8 *mymemmem(const u8 *haystack, size_t hlen, const u8 *needle, size_t nlen) { +static const u8 *mymemmem(const u8 *haystack, size_t off, size_t hlen, const u8 *needle, size_t nlen, uintptr_t align) { if (!nlen) { return nullptr; } const u8 *last_possible = haystack + hlen - nlen; int first = *needle; - const u8 *p = haystack; + const u8 *p = haystack + off; + + const uintptr_t align_mask = align - 1; + auto poffset = [&]() { + return ((uintptr_t)(p - haystack) & align_mask); + }; + auto alignp = [&]() { + uintptr_t offset = poffset(); + if (offset != 0) + p += align - offset; + }; + + alignp(); while (p <= last_possible) { p = (const u8 *)memchr(p, first, last_possible - p + 1); if (!p) { return nullptr; } - if (!memcmp(p, needle, nlen)) { + if (poffset() == 0 && !memcmp(p, needle, nlen)) { return p; } p++; + alignp(); } return nullptr; } -static Command EmitCommandWithRAM(CommandType t, const void *p, u32 sz) { +static Command EmitCommandWithRAM(CommandType t, const void *p, u32 sz, u32 align) { FlushRegisters(); Command cmd{t, sz, 0}; @@ -189,10 +207,10 @@ static Command EmitCommandWithRAM(CommandType t, const void *p, u32 sz) { const size_t NEAR_WINDOW = std::max((int)sz * 2, 1024 * 10); // Let's try nearby first... it will often be nearby. if (pushbuf.size() > NEAR_WINDOW) { - prev = mymemmem(pushbuf.data() + pushbuf.size() - NEAR_WINDOW, NEAR_WINDOW, (const u8 *)p, sz); + prev = mymemmem(pushbuf.data(), pushbuf.size() - NEAR_WINDOW, pushbuf.size(), (const u8 *)p, sz, align); } if (!prev) { - prev = mymemmem(pushbuf.data(), pushbuf.size(), (const u8 *)p, sz); + prev = mymemmem(pushbuf.data(), 0, pushbuf.size(), (const u8 *)p, sz, align); } if (prev) { @@ -200,8 +218,8 @@ static Command EmitCommandWithRAM(CommandType t, const void *p, u32 sz) { } else { cmd.ptr = (u32)pushbuf.size(); int pad = 0; - if (cmd.ptr & 0xF) { - pad = 0x10 - (cmd.ptr & 0xF); + if (cmd.ptr & (align - 1)) { + pad = align - (cmd.ptr & (align - 1)); cmd.ptr += pad; } pushbuf.resize(pushbuf.size() + sz + pad); @@ -269,7 +287,7 @@ static void EmitTextureData(int level, u32 texaddr) { } // Not there, gotta emit anew. - Command cmd = EmitCommandWithRAM(type, p, bytes); + Command cmd = EmitCommandWithRAM(type, p, bytes, 16); lastTextures.push_back(cmd.ptr); } } @@ -302,10 +320,10 @@ static void FlushPrimState(int vcount) { GetVertDataSizes(vcount, indices, vbytes, ibytes); if (indices && ibytes > 0) { - EmitCommandWithRAM(CommandType::INDICES, indices, ibytes); + EmitCommandWithRAM(CommandType::INDICES, indices, ibytes, 4); } if (verts && vbytes > 0) { - EmitCommandWithRAM(CommandType::VERTICES, verts, vbytes); + EmitCommandWithRAM(CommandType::VERTICES, verts, vbytes, 4); } } @@ -330,7 +348,7 @@ static void EmitTransfer(u32 op) { srcBytes = Memory::ValidSize(srcBasePtr, srcBytes); if (srcBytes != 0) { - EmitCommandWithRAM(CommandType::TRANSFERSRC, Memory::GetPointerUnchecked(srcBasePtr), srcBytes); + EmitCommandWithRAM(CommandType::TRANSFERSRC, Memory::GetPointerUnchecked(srcBasePtr), srcBytes, 16); } lastRegisters.push_back(op); @@ -342,7 +360,7 @@ static void EmitClut(u32 op) { bytes = Memory::ValidSize(addr, bytes); if (bytes != 0) { - EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes); + EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes, 16); } lastRegisters.push_back(op); @@ -463,7 +481,7 @@ void NotifyMemcpy(u32 dest, u32 src, u32 sz) { sz = Memory::ValidSize(dest, sz); if (sz != 0) { - EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointer(dest), sz); + EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointer(dest), sz, 1); } } } diff --git a/GPU/Debugger/RecordFormat.h b/GPU/Debugger/RecordFormat.h index aeb7791fe2..f59e71aa7e 100644 --- a/GPU/Debugger/RecordFormat.h +++ b/GPU/Debugger/RecordFormat.h @@ -21,11 +21,19 @@ namespace GPURecord { -static const char *HEADER = "PPSSPPGE"; +struct Header { + char magic[8]; + uint32_t version; + char gameID[9]; + uint8_t pad[3]; +}; + +static const char *HEADER_MAGIC = "PPSSPPGE"; // Version 1: Uncompressed // Version 2: Uses snappy // Version 3: Adds FRAMEBUF0-FRAMEBUF9 -static const int VERSION = 3; +// Version 4: Expanded header with game ID +static const int VERSION = 4; static const int MIN_VERSION = 2; enum class CommandType : u8 { diff --git a/GPU/Debugger/Stepping.cpp b/GPU/Debugger/Stepping.cpp index bf5ddb4834..2cc06f52fe 100644 --- a/GPU/Debugger/Stepping.cpp +++ b/GPU/Debugger/Stepping.cpp @@ -18,10 +18,11 @@ #include #include +#include "Common/Log.h" +#include "Core/Core.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Debugger/Stepping.h" #include "GPU/GPUState.h" -#include "Core/Core.h" namespace GPUStepping { diff --git a/GPU/Directx9/DepalettizeShaderDX9.cpp b/GPU/Directx9/DepalettizeShaderDX9.cpp index 2365e41d58..bff0c04933 100644 --- a/GPU/Directx9/DepalettizeShaderDX9.cpp +++ b/GPU/Directx9/DepalettizeShaderDX9.cpp @@ -18,15 +18,14 @@ #include #include -#include "base/logging.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/D3D9/D3D9ShaderCompiler.h" +#include "Common/GPU/thin3d.h" #include "Common/Log.h" #include "Common/StringUtils.h" #include "Core/Reporting.h" #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/DepalettizeShaderDX9.h" #include "GPU/Common/DepalettizeShaderCommon.h" -#include "gfx/d3d9_shader.h" namespace DX9 { diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index a39d48f986..c464652318 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -15,17 +15,18 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" -#include "base/timeutil.h" +#include +#include "Common/Log.h" #include "Common/MemoryUtil.h" +#include "Common/TimeUtil.h" #include "Core/MemMap.h" #include "Core/System.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "Core/CoreTiming.h" -#include "gfx/d3d9_state.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" #include "GPU/Math3D.h" #include "GPU/GPUState.h" @@ -83,7 +84,7 @@ static const D3DVERTEXELEMENT9 TransformedVertexElements[] = { D3DDECL_END() }; -DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : vai_(256), vertexDeclMap_(64) { +DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : draw_(draw), vai_(256), vertexDeclMap_(64) { device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE); decOptions_.expandAllWeightsToFloat = true; decOptions_.expand8BitNormalsToFloat = true; @@ -299,14 +300,27 @@ static uint32_t SwapRB(uint32_t c) { return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c << 16) & 0xFF0000); } +void DrawEngineDX9::BeginFrame() { + DecimateTrackedVertexArrays(); + + lastRenderStepId_ = -1; +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineDX9::DoFlush() { gpuStats.numFlushes++; gpuStats.numTrackedVertexArrays = (int)vai_.size(); + // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. + int curRenderStepId = draw_->GetCurrentStepId(); + if (lastRenderStepId_ != curRenderStepId) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + lastRenderStepId_ = curRenderStepId; + } + // This is not done on every drawcall, we should collect vertex data // until critical state changes. That's when we draw (flush). - GEPrimitiveType prim = prevPrim_; ApplyDrawState(prim); @@ -338,7 +352,7 @@ void DrawEngineDX9::DoFlush() { case VertexArrayInfoDX9::VAI_NEW: { // Haven't seen this one before. - ReliableHashType dataHash = ComputeHash(); + uint64_t dataHash = ComputeHash(); vai->hash = dataHash; vai->minihash = ComputeMiniHash(); vai->status = VertexArrayInfoDX9::VAI_HASHING; @@ -363,7 +377,7 @@ void DrawEngineDX9::DoFlush() { if (vai->drawsUntilNextFullHash == 0) { // Let's try to skip a full hash if mini would fail. const u32 newMiniHash = ComputeMiniHash(); - ReliableHashType newHash = vai->hash; + uint64_t newHash = vai->hash; if (newMiniHash == vai->minihash) { newHash = ComputeHash(); } @@ -404,7 +418,7 @@ void DrawEngineDX9::DoFlush() { vai->numVerts = indexGen.PureCount(); } - _dbg_assert_msg_(G3D, gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); + _dbg_assert_msg_(gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); void * pVb; u32 size = dec_->GetDecVtxFmt().stride * indexGen.MaxIndex(); @@ -550,6 +564,9 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); } + if (result.setSafeSize) + framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + ApplyDrawStateLate(); vshader = shaderManager_->ApplyShader(false, false, lastVType_); @@ -588,12 +605,11 @@ rotateVBO: dxstate.colorMask.set((mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_STENCIL) != 0); device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); - int scissorX2 = gstate.getScissorX2() + 1; - int scissorY2 = gstate.getScissorY2() + 1; - framebufferManager_->SetSafeSize(scissorX2, scissorY2); 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(); + int scissorX2 = gstate.getScissorX2() + 1; + int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 41c828908a..3ddf99b79b 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -19,7 +19,7 @@ #include -#include "Common/Hashmaps.h" +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/GPUState.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/IndexGenerator.h" @@ -77,7 +77,7 @@ public: VAI_UNRELIABLE, // never cache }; - ReliableHashType hash; + uint64_t hash; u32 minihash; LPDIRECT3DVERTEXBUFFER9 vbo; @@ -123,7 +123,8 @@ public: void DestroyDeviceObjects(); void ClearTrackedVertexArrays() override; - void DecimateTrackedVertexArrays(); + + void BeginFrame(); // So that this can be inlined void Flush() { @@ -143,6 +144,7 @@ public: protected: // Not currently supported. bool UpdateUseHWTessellation(bool enable) override { return false; } + void DecimateTrackedVertexArrays(); private: void DoFlush(); @@ -156,6 +158,7 @@ private: void MarkUnreliable(VertexArrayInfoDX9 *vai); LPDIRECT3DDEVICE9 device_ = nullptr; + Draw::DrawContext *draw_; PrehashMap vai_; DenseHashMap vertexDeclMap_; @@ -170,6 +173,8 @@ private: // Hardware tessellation TessellationDataTransferDX9 *tessDataTransferDX9; + + int lastRenderStepId_ = -1; }; } // namespace diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp similarity index 96% rename from GPU/Directx9/FramebufferDX9.cpp rename to GPU/Directx9/FramebufferManagerDX9.cpp index 0300bbf45a..0c9c2d5720 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -15,8 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "math/lin/matrix4x4.h" -#include "ext/native/thin3d/thin3d.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/GPU/thin3d.h" #include "Common/ColorConv.h" #include "Core/MemMap.h" @@ -28,17 +28,17 @@ #include "GPU/GPUState.h" #include "GPU/Debugger/Stepping.h" -#include "gfx/d3d9_state.h" -#include "GPU/Common/FramebufferCommon.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" #include "GPU/Common/ShaderTranslation.h" #include "GPU/Common/TextureDecoder.h" -#include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Directx9/FramebufferManagerDX9.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/DrawEngineDX9.h" -#include "ext/native/thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" #include @@ -243,7 +243,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { // to exactly reproduce in 4444 and 8888 formats. if (old == GE_FORMAT_565) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "ReformatFramebuffer"); dxstate.scissorTest.disable(); dxstate.depthWrite.set(FALSE); @@ -305,14 +305,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { } } - void FramebufferManagerDX9::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - 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; - if (matchingDepthBuffer && matchingSize) { - // Should use StretchRect here? Note: should only copy depth and NOT copy stencil. See #9740. - } - } - LPDIRECT3DSURFACE9 FramebufferManagerDX9::GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb) { D3DSURFACE_DESC desc = {}; HRESULT hr = similarSurface->GetDesc(&desc); @@ -369,7 +361,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { copyInfo.fbo = renderCopy; CopyFramebufferForColorTexture(©Info, framebuffer, flags); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - BindFramebufferAsColorTexture"); draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0); } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); @@ -387,7 +379,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { if (!dst->fbo || !src->fbo || !useBufferedRendering_) { // This can happen if we recently switched from non-buffered. if (useBufferedRendering_) - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer_Fail"); return; } @@ -420,7 +412,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { bool result = draw_->BlitFramebuffer( src->fbo, srcX1, srcY1, srcX2, srcY2, tempFBO, dstX1, dstY1, dstX2, dstY2, - Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST); + Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebuffer"); if (result) { srcFBO = tempFBO; } @@ -428,7 +420,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { bool result = draw_->BlitFramebuffer( srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, - Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST); + Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebuffer"); if (!result) { ERROR_LOG_REPORT(G3D, "fbo_blit_color failed in blit (%08x -> %08x)", src->fb_address, dst->fb_address); } @@ -538,12 +530,13 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { const u32 *packed = (const u32 *)locked.pBits; u16 *depth = (u16 *)Memory::GetPointer(z_address); + DepthScaleFactors depthScale = GetDepthScaleFactors(); // TODO: Optimize. for (int yp = 0; yp < h; ++yp) { for (int xp = 0; xp < w; ++xp) { const int offset = (yp + y) * vfb->z_stride + x + xp; - float scaled = FromScaledDepth((packed[offset] & 0x00FFFFFF) * (1.0f / 16777215.0f)); + float scaled = depthScale.Apply((packed[offset] & 0x00FFFFFF) * (1.0f / 16777215.0f)); if (scaled <= 0.0f) { depth[offset] = 0; } else if (scaled >= 65535.0f) { @@ -614,7 +607,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { w = vfb->width * maxRes; h = vfb->height * maxRes; tempFBO = draw_->CreateFramebuffer({ w, h, 1, 1, false, Draw::FBO_8888 }); - if (draw_->BlitFramebuffer(vfb->fbo, 0, 0, vfb->renderWidth, vfb->renderHeight, tempFBO, 0, 0, w, h, Draw::FB_COLOR_BIT, g_Config.iBufFilter == SCALE_LINEAR ? Draw::FB_BLIT_LINEAR : Draw::FB_BLIT_NEAREST)) { + if (draw_->BlitFramebuffer(vfb->fbo, 0, 0, vfb->renderWidth, vfb->renderHeight, tempFBO, 0, 0, w, h, Draw::FB_COLOR_BIT, g_Config.iBufFilter == SCALE_LINEAR ? Draw::FB_BLIT_LINEAR : Draw::FB_BLIT_NEAREST, "GetFramebuffer")) { renderTarget = (LPDIRECT3DSURFACE9)draw_->GetFramebufferAPITexture(tempFBO, Draw::FB_COLOR_BIT | Draw::FB_SURFACE_BIT, 0); } } diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferManagerDX9.h similarity index 94% rename from GPU/Directx9/FramebufferDX9.h rename to GPU/Directx9/FramebufferManagerDX9.h index bab50d4dfc..3a8578599a 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -26,7 +26,7 @@ // pixel data. #include "GPU/GPUCommon.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" namespace DX9 { @@ -50,11 +50,9 @@ public: void DeviceLost(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; - void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); - virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; + virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes); bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 6290f14010..439b443cd7 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -17,12 +17,11 @@ #include -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" #include "Common/GraphicsContext.h" -#include "base/NativeApp.h" -#include "base/logging.h" -#include "profiler/profiler.h" -#include "i18n/i18n.h" +#include "Common/System/System.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Data/Text/I18n.h" #include "Core/Debugger/Breakpoints.h" #include "Core/MemMapHelpers.h" #include "Core/MIPS/MIPS.h" @@ -32,17 +31,17 @@ #include "Core/Reporting.h" #include "Core/System.h" -#include "gfx/d3d9_state.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" #include "GPU/GeDisasm.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Debugger/Debugger.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/GPU_DX9.h" -#include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Directx9/FramebufferManagerDX9.h" #include "GPU/Directx9/DrawEngineDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" @@ -282,7 +281,7 @@ void GPU_DX9::ReapplyGfxState() { void GPU_DX9::BeginFrame() { textureCacheDX9_->StartFrame(); - drawEngine_.DecimateTrackedVertexArrays(); + drawEngine_.BeginFrame(); depalShaderCache_.Decimate(); // fragmentTestCache_.Decimate(); @@ -345,38 +344,13 @@ void GPU_DX9::ExecuteOp(u32 op, u32 diff) { } void GPU_DX9::GetStats(char *buffer, size_t bufsize) { - float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; - snprintf(buffer, bufsize - 1, - "DL processing time: %0.2f ms\n" - "Draw calls: %i, flushes %i, clears %i\n" - "Cached Draw calls: %i\n" - "Num Tracked Vertex Arrays: %i\n" - "GPU cycles executed: %d (%f per vertex)\n" - "Commands per call level: %i %i %i %i\n" - "Vertices submitted: %i\n" - "Cached, Uncached Vertices Drawn: %i, %i\n" - "FBOs active: %i\n" - "Textures active: %i, decoded: %i invalidated: %i\n" - "Readbacks: %d, uploads: %d\n" + size_t offset = FormatGPUStatsCommon(buffer, bufsize); + buffer += offset; + bufsize -= offset; + if ((int)bufsize < 0) + return; + snprintf(buffer, bufsize, "Vertex, Fragment shaders loaded: %i, %i\n", - gpuStats.msProcessingDisplayLists * 1000.0f, - gpuStats.numDrawCalls, - gpuStats.numFlushes, - gpuStats.numClears, - gpuStats.numCachedDrawCalls, - gpuStats.numTrackedVertexArrays, - gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles, - vertexAverageCycles, - gpuStats.gpuCommandsAtCallLevel[0], gpuStats.gpuCommandsAtCallLevel[1], gpuStats.gpuCommandsAtCallLevel[2], gpuStats.gpuCommandsAtCallLevel[3], - gpuStats.numVertsSubmitted, - gpuStats.numCachedVertsDrawn, - gpuStats.numUncachedVertsDrawn, - (int)framebufferManagerDX9_->NumVFBs(), - (int)textureCacheDX9_->NumLoadedTextures(), - gpuStats.numTexturesDecoded, - gpuStats.numTextureInvalidations, - gpuStats.numReadbacks, - gpuStats.numUploads, shaderManagerDX9_->GetNumVertexShaders(), shaderManagerDX9_->GetNumFragmentShaders() ); diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 95980c5c35..6f33fcf90c 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -17,13 +17,12 @@ #pragma once -#include -#include +#include +#include #include "GPU/GPUCommon.h" -#include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Directx9/FramebufferManagerDX9.h" #include "GPU/Directx9/DrawEngineDX9.h" -#include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/DepalettizeShaderDX9.h" #include "GPU/Common/VertexDecoderCommon.h" @@ -31,6 +30,7 @@ namespace DX9 { class ShaderManagerDX9; class LinkedShaderDX9; +class TextureCacheDX9; class GPU_DX9 : public GPUCommon { public: diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 35bdfbd3b4..0e0a24ffba 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -21,16 +21,19 @@ #include #include -#include "gfx/d3d9_shader.h" -#include "base/logging.h" -#include "i18n/i18n.h" -#include "math/lin/matrix4x4.h" -#include "math/math_util.h" -#include "math/dataconv.h" -#include "thin3d/thin3d.h" -#include "util/text/utf8.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Math/math_util.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/GPU/D3D9/D3D9ShaderCompiler.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Encoding/Utf8.h" #include "Common/Common.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" + #include "Core/Config.h" #include "Core/Host.h" #include "Core/Reporting.h" @@ -40,7 +43,7 @@ #include "GPU/Common/ShaderUniforms.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/DrawEngineDX9.h" -#include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Directx9/FramebufferManagerDX9.h" using namespace Lin; @@ -251,9 +254,9 @@ static void ConvertProjMatrixToD3D(Matrix4x4 &in, bool invertedX, bool invertedY float yoff = -1.0f / gstate_c.curRTRenderHeight; if (invertedY) { - yoff = gstate_c.vpYOffset - yoff; - } else { yoff = -gstate_c.vpYOffset - yoff; + } else { + yoff = gstate_c.vpYOffset - yoff; } const Vec3 trans(xoff, yoff, gstate_c.vpZOffset * 0.5f + 0.5f); diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index 7fa9818129..a71b95d2e5 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -20,13 +20,12 @@ #include #include -#include "base/basictypes.h" +#include "Common/Common.h" #include "GPU/Directx9/VertexShaderGeneratorDX9.h" #include "GPU/Directx9/PixelShaderGeneratorDX9.h" #include "GPU/Common/ShaderCommon.h" #include "GPU/Common/ShaderId.h" -#include "thin3d/d3dx9_loader.h" -#include "math/lin/matrix4x4.h" +#include "Common/Math/lin/matrix4x4.h" namespace DX9 { diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 9f8a251451..a3ae081396 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -15,21 +15,22 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "profiler/profiler.h" -#include "GPU/Math3D.h" -#include "GPU/GPUState.h" -#include "GPU/ge_constants.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/D3D9/D3D9ShaderCompiler.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" + #include "Core/System.h" #include "Core/Config.h" #include "Core/Reporting.h" -#include "gfx/d3d9_shader.h" -#include "gfx/d3d9_state.h" +#include "GPU/Math3D.h" +#include "GPU/GPUState.h" +#include "GPU/ge_constants.h" #include "GPU/Directx9/GPU_DX9.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" -#include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Directx9/FramebufferManagerDX9.h" #include "GPU/Directx9/PixelShaderGeneratorDX9.h" namespace DX9 { @@ -202,15 +203,12 @@ void DrawEngineDX9::ApplyDrawState(int prim) { } else { dxstate.dither.disable(); } + bool wantCull = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); + dxstate.cullMode.set(wantCull, gstate.getCullMode()); if (gstate.isModeClear()) { - // Set Cull - dxstate.cullMode.set(false, false); // Well, probably doesn't matter... dxstate.shadeMode.set(D3DSHADE_GOURAUD); } else { - // Set cull - bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); - dxstate.cullMode.set(wantCull, gstate.getCullMode()); dxstate.shadeMode.set(gstate.getShadeMode() == GE_SHADE_GOURAUD ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); } } diff --git a/GPU/Directx9/StencilBufferDX9.cpp b/GPU/Directx9/StencilBufferDX9.cpp index 5302c9e4f6..d938e4339a 100644 --- a/GPU/Directx9/StencilBufferDX9.cpp +++ b/GPU/Directx9/StencilBufferDX9.cpp @@ -17,13 +17,11 @@ #include -#include "base/logging.h" - -#include "gfx/d3d9_state.h" -#include "ext/native/thin3d/thin3d.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" +#include "Common/GPU/thin3d.h" #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" -#include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Directx9/FramebufferManagerDX9.h" #include "GPU/Directx9/PixelShaderGeneratorDX9.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" @@ -66,7 +64,7 @@ VS_OUT main(VS_IN In) { } )"; -bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZero) { +bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; @@ -113,7 +111,7 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer } if (usedBits == 0) { - if (skipZero) { + if (flags == StencilUpload::STENCIL_IS_ZERO) { // Common when creating buffers, it's already 0. We're done. return false; } @@ -187,17 +185,17 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer dxstate.colorMask.set(false, false, false, true); dxstate.stencilTest.enable(); dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); u16 w = dstBuffer->renderWidth; u16 h = dstBuffer->renderHeight; if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + // Typically, STENCIL_IS_ZERO means it's already bound. + Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR; + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "StencilUpload"); } D3DVIEWPORT9 vp{ 0, 0, w, h, 0.0f, 1.0f }; device_->SetViewport(&vp); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); float u1 = 1.0f; float v1 = 1.0f; @@ -205,7 +203,7 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer if (!tex) return false; - device_->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0); + // TODO: Ideally, we should clear alpha to zero here (but not RGB.) dxstate.stencilFunc.set(D3DCMP_ALWAYS, 0xFF, 0xFF); @@ -254,7 +252,8 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer tex->Release(); dxstate.stencilMask.set(0xFF); dxstate.viewport.restore(); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer stencil"); + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); return true; } diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index b3adff05cd..230bfbf8aa 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -15,9 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include #include -#include #include #include "Core/MemMap.h" @@ -26,17 +24,17 @@ #include "GPU/GPUState.h" #include "GPU/Directx9/PixelShaderGeneratorDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" -#include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Directx9/FramebufferManagerDX9.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/DepalettizeShaderDX9.h" -#include "gfx/d3d9_state.h" -#include "GPU/Common/FramebufferCommon.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/TextureDecoder.h" #include "Core/Config.h" #include "Core/Host.h" #include "ext/xxhash.h" -#include "math/math_util.h" +#include "Common/Math/math_util.h" namespace DX9 { @@ -87,7 +85,6 @@ void TextureCacheDX9::SetFramebufferManager(FramebufferManagerDX9 *fbManager) { } void TextureCacheDX9::ReleaseTexture(TexCacheEntry *entry, bool delete_them) { - DEBUG_LOG(G3D, "Deleting texture %p", entry->texturePtr); LPDIRECT3DTEXTURE9 &texture = DxTex(entry); if (texture) { texture->Release(); @@ -95,15 +92,8 @@ void TextureCacheDX9::ReleaseTexture(TexCacheEntry *entry, bool delete_them) { } } -void TextureCacheDX9::ForgetLastTexture() { - InvalidateLastTexture(); - gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); -} - -void TextureCacheDX9::InvalidateLastTexture(TexCacheEntry *entry) { - if (!entry || entry->texturePtr == lastBoundTexture) { - lastBoundTexture = INVALID_TEX; - } +void TextureCacheDX9::InvalidateLastTexture() { + lastBoundTexture = INVALID_TEX; } D3DFORMAT getClutDestFormat(GEPaletteFormat format) { @@ -121,101 +111,24 @@ D3DFORMAT getClutDestFormat(GEPaletteFormat format) { return D3DFMT_A8R8G8B8; } -static const u8 MinFilt[8] = { - D3DTEXF_POINT, - D3DTEXF_LINEAR, - D3DTEXF_POINT, - D3DTEXF_LINEAR, - D3DTEXF_POINT, // GL_NEAREST_MIPMAP_NEAREST, - D3DTEXF_LINEAR, // GL_LINEAR_MIPMAP_NEAREST, - D3DTEXF_POINT, // GL_NEAREST_MIPMAP_LINEAR, - D3DTEXF_LINEAR, // GL_LINEAR_MIPMAP_LINEAR, -}; +void TextureCacheDX9::ApplySamplingParams(const SamplerCacheKey &key) { + dxstate.texMinFilter.set(key.minFilt ? D3DTEXF_LINEAR : D3DTEXF_POINT); + dxstate.texMipFilter.set(key.mipFilt ? D3DTEXF_LINEAR : D3DTEXF_POINT); + dxstate.texMagFilter.set(key.magFilt ? D3DTEXF_LINEAR : D3DTEXF_POINT); -static const u8 MipFilt[8] = { - D3DTEXF_NONE, - D3DTEXF_NONE, - D3DTEXF_NONE, - D3DTEXF_NONE, - D3DTEXF_POINT, // GL_NEAREST_MIPMAP_NEAREST, - D3DTEXF_POINT, // GL_LINEAR_MIPMAP_NEAREST, - D3DTEXF_LINEAR, // GL_NEAREST_MIPMAP_LINEAR, - D3DTEXF_LINEAR, // GL_LINEAR_MIPMAP_LINEAR, -}; + // DX9 mip levels are .. odd. The "max level" sets the LARGEST mip to use. + // We can enforce only the top mip level by setting a massive negative lod bias. -static const u8 MagFilt[2] = { - D3DTEXF_POINT, - D3DTEXF_LINEAR -}; - -void TextureCacheDX9::UpdateSamplingParams(TexCacheEntry &entry, bool force) { - int minFilt; - int magFilt; - bool sClamp; - bool tClamp; - float lodBias; - GETexLevelMode mode; - u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, mode); - - if (maxLevel != 0) { - if (mode == GE_TEXLEVEL_MODE_AUTO) { - dxstate.texMaxMipLevel.set(0); - dxstate.texMipLodBias.set(lodBias); - } else if (mode == GE_TEXLEVEL_MODE_CONST) { - // TODO: This is just an approximation - texMaxMipLevel sets the lowest numbered mip to use. - // Unfortunately, this doesn't support a const 1.5 or etc. - dxstate.texMaxMipLevel.set(std::max(0, std::min((int)maxLevel, (int)lodBias))); - dxstate.texMipLodBias.set(-1000.0f); - } else { // if (mode == GE_TEXLEVEL_MODE_SLOPE{ - dxstate.texMaxMipLevel.set(0); - dxstate.texMipLodBias.set(0.0f); - } - } else { + if (!key.mipEnable) { dxstate.texMaxMipLevel.set(0); - dxstate.texMipLodBias.set(0.0f); + dxstate.texMipLodBias.set(-100.0f); + } else { + dxstate.texMipLodBias.set((float)key.lodBias / 256.0f); + dxstate.texMaxMipLevel.set(key.minLevel / 256); } - D3DTEXTUREFILTERTYPE minf = (D3DTEXTUREFILTERTYPE)MinFilt[minFilt]; - D3DTEXTUREFILTERTYPE mipf = (D3DTEXTUREFILTERTYPE)MipFilt[minFilt]; - D3DTEXTUREFILTERTYPE magf = (D3DTEXTUREFILTERTYPE)MagFilt[magFilt]; - - if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0 && minf == D3DTEXF_LINEAR) { - minf = D3DTEXF_ANISOTROPIC; - } - - dxstate.texMinFilter.set(minf); - dxstate.texMipFilter.set(mipf); - dxstate.texMagFilter.set(magf); - dxstate.texAddressU.set(sClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP); - dxstate.texAddressV.set(tClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP); -} - -void TextureCacheDX9::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight) { - int minFilt; - int magFilt; - bool sClamp; - bool tClamp; - float lodBias; - GETexLevelMode mode; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, mode); - - dxstate.texMinFilter.set(MinFilt[minFilt]); - dxstate.texMipFilter.set(MipFilt[minFilt]); - dxstate.texMagFilter.set(MagFilt[magFilt]); - dxstate.texMipLodBias.set(0.0f); - dxstate.texMaxMipLevel.set(0.0f); - - // Often the framebuffer will not match the texture size. We'll wrap/clamp in the shader in that case. - // This happens whether we have OES_texture_npot or not. - int w = gstate.getTextureWidth(0); - int h = gstate.getTextureHeight(0); - if (w != bufferWidth || h != bufferHeight) { - return; - } - - dxstate.texAddressU.set(sClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP); - dxstate.texAddressV.set(tClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP); + dxstate.texAddressU.set(key.sClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP); + dxstate.texAddressV.set(key.tClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP); } void TextureCacheDX9::StartFrame() { @@ -223,7 +136,7 @@ void TextureCacheDX9::StartFrame() { timesInvalidatedAllThisFrame_ = 0; if (texelsScaledThisFrame_) { - // INFO_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); + VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); } texelsScaledThisFrame_ = 0; if (clearCacheNextFrame_) { @@ -238,7 +151,6 @@ void TextureCacheDX9::StartFrame() { DWORD anisotropyLevel = aniso > maxAnisotropyLevel ? maxAnisotropyLevel : aniso; device_->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, anisotropyLevel); } - } void TextureCacheDX9::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) { @@ -252,7 +164,10 @@ void TextureCacheDX9::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase // Adding clutBaseBytes may just be mitigating this for some usage patterns. const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); - clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + if (replacer_.Enabled()) + clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + else + clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF; clutBuf_ = clutBufRaw_; // Special optimization: fonts typically draw clut4 with just alpha values in a single color. @@ -280,7 +195,9 @@ void TextureCacheDX9::BindTexture(TexCacheEntry *entry) { device_->SetTexture(0, texture); lastBoundTexture = texture; } - UpdateSamplingParams(*entry, false); + int maxLevel = (entry->status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry->maxLevel; + SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry->addr); + ApplySamplingParams(samplerKey); } void TextureCacheDX9::Unbind() { @@ -415,10 +332,11 @@ protected: int renderH_; }; -void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { +void TextureCacheDX9::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) { LPDIRECT3DPIXELSHADER9 pshader = nullptr; uint32_t clutMode = gstate.clutformat & 0xFFFFFF; - if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { + bool need_depalettize = IsClutFormat(texFormat); + if (need_depalettize && !g_Config.bDisableSlowFramebufEffects) { pshader = depalShaderCache_->GetDepalettizePixelShader(clutMode, framebuffer->drawnFormat); } @@ -427,7 +345,7 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame LPDIRECT3DTEXTURE9 clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); Draw::Framebuffer *depalFBO = framebufferManagerDX9_->GetTempFBO(TempFBO::DEPAL, framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888); - draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); shaderManager_->DirtyLastShader(); float xoff = -0.5f / framebuffer->renderWidth; @@ -459,17 +377,15 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame TexCacheEntry::TexStatus alphaStatus = CheckAlpha(clutBuf_, getClutDestFormat(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); } else { - entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; - framebufferManagerDX9_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650); } - framebufferManagerDX9_->RebindFramebuffer(); - SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); + framebufferManagerDX9_->RebindFramebuffer("RebindFramebuffer - ApplyTextureFromFramebuffer"); - InvalidateLastTexture(); + SamplerCacheKey samplerKey = GetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); + ApplySamplingParams(samplerKey); } void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) { @@ -478,14 +394,6 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) { // For the estimate, we assume cluts always point to 8888 for simplicity. cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); - // TODO: If a framebuffer is attached here, might end up with a bad entry.texture. - // Should just always create one here or something (like GLES.) - - if (entry->framebuffer) { - // Nothing else to do here. - return; - } - if ((entry->bufw == 0 || (gstate.texbufwidth[0] & 0xf800) != 0) && entry->addr >= PSP_GetKernelMemoryEnd()) { ERROR_LOG_REPORT(G3D, "Texture with unexpected bufw (full=%d)", gstate.texbufwidth[0] & 0xffff); // Proceeding here can cause a crash. @@ -747,7 +655,7 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re pixelData = (u32 *)rect.pBits; // We always end up at 8888. Other parts assume this. - assert(dstFmt == D3DFMT_A8R8G8B8); + _assert_(dstFmt == D3DFMT_A8R8G8B8); bpp = sizeof(u32); decPitch = w * bpp; @@ -782,7 +690,7 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re } bool TextureCacheDX9::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) { - SetTexture(true); + SetTexture(); ApplyTexture(); int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); diff --git a/GPU/Directx9/TextureCacheDX9.h b/GPU/Directx9/TextureCacheDX9.h index 4d9b308793..aa57dcba4b 100644 --- a/GPU/Directx9/TextureCacheDX9.h +++ b/GPU/Directx9/TextureCacheDX9.h @@ -49,10 +49,10 @@ public: shaderManager_ = sm; } - void ForgetLastTexture() override; - void InvalidateLastTexture(TexCacheEntry *entry = nullptr) override; - - void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight); + void ForgetLastTexture() override { + InvalidateLastTexture(); + } + void InvalidateLastTexture() override; bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override; @@ -62,13 +62,14 @@ protected: void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override; private: - void UpdateSamplingParams(TexCacheEntry &entry, bool force); + void ApplySamplingParams(const SamplerCacheKey &key); + void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, int scaleFactor, u32 dstFmt); D3DFORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; TexCacheEntry::TexStatus CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; - void ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) override; + void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) override; void BuildTexture(TexCacheEntry *const entry) override; LPDIRECT3DTEXTURE9 &DxTex(TexCacheEntry *entry) { diff --git a/GPU/Directx9/TextureScalerDX9.cpp b/GPU/Directx9/TextureScalerDX9.cpp index a31dbd3af4..4508358d7e 100644 --- a/GPU/Directx9/TextureScalerDX9.cpp +++ b/GPU/Directx9/TextureScalerDX9.cpp @@ -15,17 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -// On Visual Studio 2012, include this before anything else so -// _VARIADIC_MAX gets set to 10, to avoid std::bind compile errors. -// See header file for reasons why. -#if defined(_WIN32) && _MSC_VER == 1700 -#include "../native/base/basictypes.h" -#endif - #include +#include "Common/Common.h" #include "Common/ColorConv.h" -#include "Common/ThreadPools.h" +#include "Core/ThreadPools.h" #include "GPU/Common/TextureScalerCommon.h" #include "GPU/Directx9/TextureScalerDX9.h" #include "GPU/Directx9/GPU_DX9.h" diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 64bccc9255..976158ed74 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -15,14 +15,14 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include +#include #include #if defined(_WIN32) && defined(_DEBUG) #include "Common/CommonWindows.h" #endif -#include "base/stringutil.h" +#include "Common/StringUtils.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "Core/Config.h" diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index 348411e082..59517c0f4d 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -17,7 +17,6 @@ #include -#include "base/logging.h" #include "Common/Log.h" #include "Common/StringUtils.h" #include "Core/Reporting.h" diff --git a/GPU/GLES/DepalettizeShaderGLES.h b/GPU/GLES/DepalettizeShaderGLES.h index 4368780ebd..fd9c5da7af 100644 --- a/GPU/GLES/DepalettizeShaderGLES.h +++ b/GPU/GLES/DepalettizeShaderGLES.h @@ -18,9 +18,9 @@ #include #include "Common/CommonTypes.h" -#include "gfx/gl_common.h" -#include "thin3d/thin3d.h" -#include "thin3d/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "GPU/ge_constants.h" #include "GPU/Common/ShaderCommon.h" #include "GPU/Common/DepalettizeShaderCommon.h" diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 534ee73d14..fa3ca00c5c 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -16,7 +16,8 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "gfx_es2/gpu_features.h" + +#include "Common/GPU/OpenGL/GLFeatures.h" #include "Core/ConfigValues.h" #include "Core/Reporting.h" #include "GPU/Common/GPUStateUtils.h" @@ -126,9 +127,8 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int shaderManagerGL_->DirtyLastShader(); auto *blitFBO = GetTempFBO(TempFBO::COPY, vfb->renderWidth, vfb->renderHeight, Draw::FBO_8888); - draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PackDepthbuffer"); render_->SetViewport({ 0, 0, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }); - textureCacheGL_->ForgetLastTexture(); // We must bind the program after starting the render pass, and set the color mask after clearing. render_->SetScissor({ 0, 0, vfb->renderWidth, vfb->renderHeight }); @@ -154,11 +154,13 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int float v1 = 1.0f; DrawActiveTexture(x, y, w, h, vfb->renderWidth, vfb->renderHeight, 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); - draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, 0, y, packWidth, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, vfb->z_stride); + draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, 0, y, packWidth, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, vfb->z_stride, "PackDepthbuffer"); + + textureCacheGL_->ForgetLastTexture(); // TODO: Use 4444 so we can copy lines directly? format16Bit = true; } else { - draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride); + draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride, "PackDepthbuffer"); format16Bit = false; } @@ -169,6 +171,7 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; if (format16Bit) { + // TODO: We have to apply GetDepthScaleFactors here too, right? for (int yp = 0; yp < h; ++yp) { int row_offset = vfb->z_stride * yp; for (int xp = 0; xp < packWidth; ++xp) { @@ -177,11 +180,13 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int } } } else { + // TODO: Apply this in the shader. + DepthScaleFactors depthScale = GetDepthScaleFactors(); for (int yp = 0; yp < h; ++yp) { int row_offset = vfb->z_stride * yp; for (int xp = 0; xp < packWidth; ++xp) { const int i = row_offset + xp; - float scaled = FromScaledDepth(packedf[i]); + float scaled = depthScale.Apply(packedf[i]); if (scaled <= 0.0f) { depth[i] = 0; } else if (scaled >= 65535.0f) { @@ -193,5 +198,5 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int } } - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index ca32d8e508..deb288bd85 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -15,18 +15,18 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" -#include "base/timeutil.h" +#include #include "Common/MemoryUtil.h" +#include "Common/TimeUtil.h" #include "Core/MemMap.h" #include "Core/System.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "Core/CoreTiming.h" -#include "gfx/gl_debug_log.h" -#include "profiler/profiler.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" +#include "Common/Profiler/Profiler.h" #include "GPU/Math3D.h" #include "GPU/GPUState.h" @@ -109,7 +109,7 @@ void DrawEngineGLES::DeviceRestore(Draw::DrawContext *draw) { } void DrawEngineGLES::InitDeviceObjects() { - _assert_msg_(G3D, render_ != nullptr, "Render manager must be set"); + _assert_msg_(render_ != nullptr, "Render manager must be set"); for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { frameData_[i].pushVertex = render_->CreatePushBuffer(i, GL_ARRAY_BUFFER, 1024 * 1024); @@ -156,9 +156,13 @@ void DrawEngineGLES::ClearInputLayoutMap() { } void DrawEngineGLES::BeginFrame() { + DecimateTrackedVertexArrays(); + FrameData &frameData = frameData_[render_->GetCurFrame()]; render_->BeginPushBuffer(frameData.pushIndex); render_->BeginPushBuffer(frameData.pushVertex); + + lastRenderStepId_ = -1; } void DrawEngineGLES::EndFrame() { @@ -228,7 +232,7 @@ GLRInputLayout *DrawEngineGLES::SetupDecFmtForDraw(LinkedShader *program, const return inputLayout; } -void DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bindOffset, GLRBuffer **buf) { +void *DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bindOffset, GLRBuffer **buf) { u8 *dest = decoded; // Figure out how much pushbuffer space we need to allocate. @@ -237,6 +241,7 @@ void DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bindO dest = (u8 *)push->Push(vertsToDecode * dec_->GetDecVtxFmt().stride, bindOffset, buf); } DecodeVerts(dest); + return dest; } void DrawEngineGLES::MarkUnreliable(VertexArrayInfo *vai) { @@ -305,6 +310,16 @@ void DrawEngineGLES::DoFlush() { gpuStats.numFlushes++; gpuStats.numTrackedVertexArrays = (int)vai_.size(); + // A new render step means we need to flush any dynamic state. Really, any state that is reset in + // GLQueueRunner::PerformRenderPass. + int curRenderStepId = render_->GetCurrentStepId(); + if (lastRenderStepId_ != curRenderStepId) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + textureCache_->ForgetLastTexture(); + lastRenderStepId_ = curRenderStepId; + } + bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); @@ -328,6 +343,8 @@ void DrawEngineGLES::DoFlush() { if (vshader->UseHWTransform()) { int vertexCount = 0; bool useElements = true; + bool populateCache = false; + VertexArrayInfo *vai = nullptr; // Cannot cache vertex data with morph enabled. bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK); @@ -340,7 +357,7 @@ void DrawEngineGLES::DoFlush() { if (useCache) { u32 id = dcid_ ^ gstate.getUVGenMode(); // This can have an effect on which UV decoder we need to use! And hence what the decoded data will look like. See #9263 - VertexArrayInfo *vai = vai_.Get(id); + vai = vai_.Get(id); if (!vai) { vai = new VertexArrayInfo(); vai_.Insert(id, vai); @@ -350,18 +367,13 @@ void DrawEngineGLES::DoFlush() { case VertexArrayInfo::VAI_NEW: { // Haven't seen this one before. - ReliableHashType dataHash = ComputeHash(); + uint64_t dataHash = ComputeHash(); vai->hash = dataHash; vai->minihash = ComputeMiniHash(); vai->status = VertexArrayInfo::VAI_HASHING; vai->drawsUntilNextFullHash = 0; - DecodeVerts(decoded); // writes to indexGen - vai->numVerts = indexGen.VertexCount(); - vai->prim = indexGen.Prim(); - vai->maxIndex = indexGen.MaxIndex(); - vai->flags = gstate_c.vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0; - - goto rotateVBO; + useCache = false; + break; } // Hashing - still gaining confidence about the buffer. @@ -375,14 +387,14 @@ void DrawEngineGLES::DoFlush() { if (vai->drawsUntilNextFullHash == 0) { // Let's try to skip a full hash if mini would fail. const u32 newMiniHash = ComputeMiniHash(); - ReliableHashType newHash = vai->hash; + uint64_t newHash = vai->hash; if (newMiniHash == vai->minihash) { newHash = ComputeHash(); } if (newMiniHash != vai->minihash || newHash != vai->hash) { MarkUnreliable(vai); - DecodeVerts(decoded); - goto rotateVBO; + useCache = false; + break; } if (vai->numVerts > 64) { // exponential backoff up to 16 draws, then every 32 @@ -400,48 +412,27 @@ void DrawEngineGLES::DoFlush() { u32 newMiniHash = ComputeMiniHash(); if (newMiniHash != vai->minihash) { MarkUnreliable(vai); - DecodeVerts(decoded); - goto rotateVBO; + break; } } - if (vai->vbo == 0) { - DecodeVerts(decoded); - vai->numVerts = indexGen.VertexCount(); - vai->prim = indexGen.Prim(); - vai->maxIndex = indexGen.MaxIndex(); - vai->flags = gstate_c.vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0; - useElements = !indexGen.SeenOnlyPurePrims(); - if (!useElements && indexGen.PureCount()) { - vai->numVerts = indexGen.PureCount(); - } + if (vai->vbo == nullptr) { + _dbg_assert_msg_(gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); - _dbg_assert_msg_(G3D, gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); - - size_t vsz = dec_->GetDecVtxFmt().stride * indexGen.MaxIndex(); - vai->vbo = render_->CreateBuffer(GL_ARRAY_BUFFER, vsz, GL_STATIC_DRAW); - render_->BufferSubdata(vai->vbo, 0, vsz, decoded); - // If there's only been one primitive type, and it's either TRIANGLES, LINES or POINTS, - // there is no need for the index buffer we built. We can then use glDrawArrays instead - // for a very minor speed boost. - if (useElements) { - size_t esz = sizeof(short) * indexGen.VertexCount(); - vai->ebo = render_->CreateBuffer(GL_ELEMENT_ARRAY_BUFFER, esz, GL_STATIC_DRAW); - render_->BufferSubdata(vai->ebo, 0, esz, (uint8_t *)decIndex, false); - } else { - vai->ebo = 0; - render_->BindIndexBuffer(vai->ebo); - } + // We'll populate the cache this time around, use it next time. + populateCache = true; + useCache = false; } else { gpuStats.numCachedDrawCalls++; useElements = vai->ebo ? true : false; gpuStats.numCachedVertsDrawn += vai->numVerts; gstate_c.vertexFullAlpha = vai->flags & VAI_FLAG_VERTEXFULLALPHA; + + vertexBuffer = vai->vbo; + indexBuffer = vai->ebo; + vertexCount = vai->numVerts; + prim = static_cast(vai->prim); } - vertexBuffer = vai->vbo; - indexBuffer = vai->ebo; - vertexCount = vai->numVerts; - prim = static_cast(vai->prim); break; } @@ -469,13 +460,17 @@ void DrawEngineGLES::DoFlush() { if (vai->lastFrame != gpuStats.numFlips) { vai->numFrames++; } - DecodeVerts(decoded); - goto rotateVBO; + useCache = false; + break; } } - vai->lastFrame = gpuStats.numFlips; - } else { + if (useCache) { + vai->lastFrame = gpuStats.numFlips; + } + } + + if (!useCache) { if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { // If software skinning, we've already predecoded into "decoded". So push that content. size_t size = decodedVerts_ * dec_->GetDecVtxFmt().stride; @@ -483,11 +478,25 @@ void DrawEngineGLES::DoFlush() { memcpy(dest, decoded, size); } else { // Decode directly into the pushbuffer - DecodeVertsToPushBuffer(frameData.pushVertex, &vertexBufferOffset, &vertexBuffer); + u8 *dest = (u8 *)DecodeVertsToPushBuffer(frameData.pushVertex, &vertexBufferOffset, &vertexBuffer); + if (populateCache) { + size_t size = decodedVerts_ * dec_->GetDecVtxFmt().stride; + vai->vbo = render_->CreateBuffer(GL_ARRAY_BUFFER, size, GL_STATIC_DRAW); + render_->BufferSubdata(vai->vbo, 0, size, dest, false); + } + } + + if (populateCache || (vai && vai->status == VertexArrayInfo::VAI_NEW)) { + vai->numVerts = indexGen.VertexCount(); + vai->prim = indexGen.Prim(); + vai->maxIndex = indexGen.MaxIndex(); + vai->flags = gstate_c.vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0; } -rotateVBO: gpuStats.numUncachedVertsDrawn += indexGen.VertexCount(); + // If there's only been one primitive type, and it's either TRIANGLES, LINES or POINTS, + // there is no need for the index buffer we built. We can then use glDrawArrays instead + // for a very minor speed boost. useElements = !indexGen.SeenOnlyPurePrims(); vertexCount = indexGen.VertexCount(); if (!useElements && indexGen.PureCount()) { @@ -516,9 +525,16 @@ rotateVBO: render_->BindVertexBuffer(inputLayout, vertexBuffer, vertexBufferOffset); if (useElements) { if (!indexBuffer) { - indexBufferOffset = (uint32_t)frameData.pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &indexBuffer); - render_->BindIndexBuffer(indexBuffer); + size_t esz = sizeof(uint16_t) * indexGen.VertexCount(); + void *dest = frameData.pushIndex->Push(esz, &indexBufferOffset, &indexBuffer); + memcpy(dest, decIndex, esz); + + if (populateCache) { + vai->ebo = render_->CreateBuffer(GL_ELEMENT_ARRAY_BUFFER, esz, GL_STATIC_DRAW); + render_->BufferSubdata(vai->ebo, 0, esz, (uint8_t *)dest, false); + } } + render_->BindIndexBuffer(indexBuffer); render_->DrawIndexed(glprim[prim], vertexCount, GL_UNSIGNED_SHORT, (GLvoid*)(intptr_t)indexBufferOffset); } else { render_->Draw(glprim[prim], 0, vertexCount); @@ -573,6 +589,8 @@ rotateVBO: if (result.action == SW_NOT_READY) swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, maxIndex, &result); + if (result.setSafeSize) + framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); ApplyDrawStateLate(result.setStencil, result.stencilValue); @@ -612,16 +630,14 @@ rotateVBO: if (alphaMask) target |= GL_STENCIL_BUFFER_BIT; if (depthMask) target |= GL_DEPTH_BUFFER_BIT; - int scissorX2 = gstate.getScissorX2() + 1; - int scissorY2 = gstate.getScissorY2() + 1; - render_->Clear(clearColor, clearDepth, clearColor >> 24, target, rgbaMask, vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH); framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - framebufferManager_->SetSafeSize(scissorX2, scissorY2); if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate.FrameBufFormat() == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); + int scissorX2 = gstate.getScissorX2() + 1; + int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied. diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 8fd17e0514..9291543478 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -17,8 +17,9 @@ #pragma once -#include -#include +#include "Common/Data/Collections/Hashmaps.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "GPU/GPUState.h" #include "GPU/Common/GPUDebugInterface.h" @@ -27,8 +28,6 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/GLES/FragmentShaderGeneratorGLES.h" -#include "gfx/gl_common.h" -#include "thin3d/GLRenderManager.h" class LinkedShader; class ShaderManagerGLES; @@ -90,7 +89,7 @@ public: VAI_UNRELIABLE, // never cache }; - ReliableHashType hash; + uint64_t hash; u32 minihash; GLRBuffer *vbo; @@ -150,7 +149,6 @@ public: void DeviceRestore(Draw::DrawContext *draw); void ClearTrackedVertexArrays() override; - void DecimateTrackedVertexArrays(); void BeginFrame(); void EndFrame(); @@ -186,6 +184,7 @@ public: protected: bool UpdateUseHWTessellation(bool enable) override; + void DecimateTrackedVertexArrays(); private: void InitDeviceObjects(); @@ -198,7 +197,7 @@ private: GLRInputLayout *SetupDecFmtForDraw(LinkedShader *program, const DecVtxFormat &decFmt); - void DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bindOffset, GLRBuffer **buf); + void *DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bindOffset, GLRBuffer **buf); void FreeVertexArray(VertexArrayInfo *vai); @@ -229,6 +228,8 @@ private: int bufferDecimationCounter_ = 0; + int lastRenderStepId_ = -1; + // Hardware tessellation TessellationDataTransferGLES *tessDataTransferGLES; }; diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index f86c608105..77174224db 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -18,9 +18,9 @@ #include #include +#include "Common/Log.h" #include "Common/StringUtils.h" -#include "base/logging.h" -#include "gfx_es2/gpu_features.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "Core/System.h" diff --git a/GPU/GLES/FragmentTestCacheGLES.cpp b/GPU/GLES/FragmentTestCacheGLES.cpp index a9459cd49a..47a23efc4d 100644 --- a/GPU/GLES/FragmentTestCacheGLES.cpp +++ b/GPU/GLES/FragmentTestCacheGLES.cpp @@ -15,8 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "thin3d/thin3d.h" -#include "gfx/gl_debug_log.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" #include "Core/Config.h" #include "GPU/GLES/FragmentTestCacheGLES.h" #include "GPU/GPUState.h" diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 972b3e9159..c551b7756f 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -15,14 +15,13 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include #include -#include "profiler/profiler.h" -#include "gfx/gl_common.h" -#include "gfx/gl_debug_log.h" -#include "gfx_es2/glsl_program.h" -#include "thin3d/thin3d.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" +#include "Common/GPU/thin3d.h" #include "Common/ColorConv.h" #include "Core/MemMap.h" #include "Core/Config.h" @@ -31,7 +30,7 @@ #include "Core/Reporting.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" #include "GPU/Common/TextureDecoder.h" #include "GPU/Debugger/Stepping.h" @@ -259,28 +258,11 @@ void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GE if (old == GE_FORMAT_565) { // Clear alpha and stencil. - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "ReformatFramebuffer"); render_->Clear(0, 0.0f, 0, GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0); } } -void FramebufferManagerGLES::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - 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; - - // Note: we don't use CopyFramebufferImage here, because it would copy depth AND stencil. See #9740. - if (matchingDepthBuffer && matchingSize) { - int w = std::min(src->renderWidth, dst->renderWidth); - int h = std::min(src->renderHeight, dst->renderHeight); - - if (gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT)) { - // Let's only do this if not clearing depth. - draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST); - dst->last_frame_depth_updated = gpuStats.numFlips; - } - } -} - void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { if (!framebuffer->fbo || !useBufferedRendering_) { render_->BindTexture(stage, nullptr); @@ -312,13 +294,13 @@ void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFra } void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) { - _assert_msg_(G3D, nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer"); + _assert_msg_(nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer"); // Discard the previous contents of this buffer where possible. if (gl_extensions.GLES3) { - draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "UpdateDownloadTempBuffer"); } else if (gl_extensions.IsGLES) { - draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); + draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "UpdateDownloadTempBuffer"); gstate_c.Dirty(DIRTY_BLEND_STATE); } } @@ -327,12 +309,11 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, if (!dst->fbo || !src->fbo || !useBufferedRendering_) { // This can happen if they recently switched from non-buffered. if (useBufferedRendering_) - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); return; } - bool useBlit = gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT); - bool useNV = useBlit && !gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT); + bool useBlit = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT); float srcXFactor = useBlit ? (float)src->renderWidth / (float)src->bufferWidth : 1.0f; float srcYFactor = useBlit ? (float)src->renderHeight / (float)src->bufferHeight : 1.0f; @@ -362,7 +343,7 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, return; } - if (gstate_c.Supports(GPU_SUPPORTS_ANY_COPY_IMAGE)) { + if (gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) { // glBlitFramebuffer can clip, but glCopyImageSubData is more restricted. // In case the src goes outside, we just skip the optimization in that case. const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; @@ -372,15 +353,15 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; if (sameSize && sameDepth && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { - draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT); + draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, "BlitFramebuffer"); return; } } if (useBlit) { - draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST); + draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebuffer"); } else { - draw_->BindFramebufferAsRenderTarget(dst->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(dst->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); draw_->BindFramebufferAsTexture(src->fbo, 0, Draw::FB_COLOR_BIT, 0); // Make sure our 2D drawing program is ready. Compiles only if not already compiled. @@ -431,6 +412,6 @@ bool FramebufferManagerGLES::GetOutputFramebuffer(GPUDebugBuffer &buffer) { int w, h; draw_->GetFramebufferDimensions(nullptr, &w, &h); buffer.Allocate(w, h, GPU_DBG_FORMAT_888_RGB, true); - draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8_UNORM, buffer.GetData(), w); + draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8_UNORM, buffer.GetData(), w, "GetOutputFramebuffer"); return true; } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 25f541fd81..51d44af73c 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -17,14 +17,14 @@ #pragma once -#include "ext/native/thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" // Keeps track of allocated FBOs. // Also provides facilities for drawing and later converting raw // pixel data. #include "GPU/GPUCommon.h" -#include "GPU/Common/FramebufferCommon.h" -#include "thin3d/GLRenderManager.h" +#include "GPU/Common/FramebufferManagerCommon.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" struct GLSLProgram; class TextureCacheGLES; @@ -49,12 +49,10 @@ public: void DeviceLost(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; - // For use when texturing from a framebuffer. May create a duplicate if target. void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); - bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; + bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 5cf1ec1b41..acbd172dfa 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -15,11 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" -#include "profiler/profiler.h" -#include "i18n/i18n.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Data/Text/I18n.h" -#include "Common/ChunkFile.h" +#include "Common/Log.h" +#include "Common/Serialize/Serializer.h" +#include "Common/File/FileUtil.h" #include "Common/GraphicsContext.h" #include "Core/Config.h" @@ -34,7 +35,7 @@ #include "GPU/GPUState.h" #include "GPU/ge_constants.h" #include "GPU/GeDisasm.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Debugger/Debugger.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/GPU_GLES.h" @@ -181,14 +182,8 @@ void GPU_GLES::CheckGPUFeatures() { } } - if (gl_extensions.ARB_framebuffer_object || gl_extensions.EXT_framebuffer_object || gl_extensions.IsGLES) { - features |= GPU_SUPPORTS_FBO; - } - if (gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3) { - features |= GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT; - } - if (gl_extensions.NV_framebuffer_blit) { - features |= GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT; + if (gl_extensions.ARB_framebuffer_object || gl_extensions.NV_framebuffer_blit || gl_extensions.GLES3) { + features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT; } if (gl_extensions.ARB_vertex_array_object && gl_extensions.IsCoreContext) { features |= GPU_SUPPORTS_VAO; @@ -219,7 +214,7 @@ void GPU_GLES::CheckGPUFeatures() { features |= GPU_SUPPORTS_BLEND_MINMAX; if (gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image) - features |= GPU_SUPPORTS_ANY_COPY_IMAGE; + features |= GPU_SUPPORTS_COPY_IMAGE; if (!gl_extensions.IsGLES) features |= GPU_SUPPORTS_LOGIC_OP; @@ -309,7 +304,7 @@ void GPU_GLES::BuildReportingInfo() { } void GPU_GLES::DeviceLost() { - ILOG("GPU_GLES: DeviceLost"); + INFO_LOG(G3D, "GPU_GLES: DeviceLost"); // Simply drop all caches and textures. // FBOs appear to survive? Or no? @@ -327,7 +322,7 @@ void GPU_GLES::DeviceLost() { void GPU_GLES::DeviceRestore() { draw_ = (Draw::DrawContext *)PSP_CoreParameter().graphicsContext->GetDrawContext(); - ILOG("GPU_GLES: DeviceRestore"); + INFO_LOG(G3D, "GPU_GLES: DeviceRestore"); UpdateCmdInfo(); UpdateVsyncInterval(true); @@ -373,7 +368,6 @@ void GPU_GLES::ReapplyGfxState() { void GPU_GLES::BeginFrame() { textureCacheGL_->StartFrame(); - drawEngine_.DecimateTrackedVertexArrays(); depalShaderCache_.Decimate(); fragmentTestCache_.Decimate(); @@ -399,7 +393,7 @@ void GPU_GLES::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat fo void GPU_GLES::CopyDisplayToOutput(bool reallyDirty) { // Flush anything left over. - framebufferManagerGL_->RebindFramebuffer(); + framebufferManagerGL_->RebindFramebuffer("RebindFramebuffer - CopyDisplayToOutput"); drawEngine_.Flush(); shaderManagerGL_->DirtyLastShader(); @@ -451,41 +445,17 @@ void GPU_GLES::ExecuteOp(u32 op, u32 diff) { } void GPU_GLES::GetStats(char *buffer, size_t bufsize) { - float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; - snprintf(buffer, bufsize - 1, - "DL processing time: %0.2f ms\n" - "Draw calls: %i, flushes %i, clears %i\n" - "Cached Draw calls: %i\n" - "Num Tracked Vertex Arrays: %i\n" - "GPU cycles executed: %d (%f per vertex)\n" - "Commands per call level: %i %i %i %i\n" - "Vertices submitted: %i\n" - "Cached, Uncached Vertices Drawn: %i, %i\n" - "FBOs active: %i\n" - "Textures active: %i, decoded: %i invalidated: %i\n" - "Readbacks: %d, uploads: %d\n" - "Vertex, Fragment, Programs loaded: %i, %i, %i\n", - gpuStats.msProcessingDisplayLists * 1000.0f, - gpuStats.numDrawCalls, - gpuStats.numFlushes, - gpuStats.numClears, - gpuStats.numCachedDrawCalls, - gpuStats.numTrackedVertexArrays, - gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles, - vertexAverageCycles, - gpuStats.gpuCommandsAtCallLevel[0], gpuStats.gpuCommandsAtCallLevel[1], gpuStats.gpuCommandsAtCallLevel[2], gpuStats.gpuCommandsAtCallLevel[3], - gpuStats.numVertsSubmitted, - gpuStats.numCachedVertsDrawn, - gpuStats.numUncachedVertsDrawn, - (int)framebufferManagerGL_->NumVFBs(), - (int)textureCacheGL_->NumLoadedTextures(), - gpuStats.numTexturesDecoded, - gpuStats.numTextureInvalidations, - gpuStats.numReadbacks, - gpuStats.numUploads, + size_t offset = FormatGPUStatsCommon(buffer, bufsize); + buffer += offset; + bufsize -= offset; + if ((int)bufsize < 0) + return; + snprintf(buffer, bufsize, + "Vertex, Fragment, Programs loaded: %d, %d, %d\n", shaderManagerGL_->GetNumVertexShaders(), shaderManagerGL_->GetNumFragmentShaders(), - shaderManagerGL_->GetNumPrograms()); + shaderManagerGL_->GetNumPrograms() + ); } void GPU_GLES::ClearCacheNextFrame() { diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index 0775ec8d8b..5bb68e2ef3 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -17,17 +17,17 @@ #pragma once -#include -#include +#include +#include #include "GPU/GPUCommon.h" #include "GPU/GLES/FramebufferManagerGLES.h" #include "GPU/GLES/DrawEngineGLES.h" -#include "GPU/GLES/TextureCacheGLES.h" #include "GPU/GLES/DepalettizeShaderGLES.h" #include "GPU/GLES/FragmentTestCacheGLES.h" class ShaderManagerGLES; +class TextureCacheGLES; class LinkedShader; class GPU_GLES : public GPUCommon { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index d13c892ac6..e4e3d4fda4 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -23,19 +23,19 @@ #include #include -#include "math/dataconv.h" -#include "base/logging.h" -#include "base/timeutil.h" -#include "gfx/gl_debug_log.h" -#include "gfx_es2/gpu_features.h" -#include "i18n/i18n.h" -#include "math/math_util.h" -#include "math/lin/matrix4x4.h" -#include "profiler/profiler.h" -#include "thin3d/thin3d.h" -#include "thin3d/GLRenderManager.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Math/math_util.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" -#include "Common/FileUtil.h" +#include "Common/Log.h" +#include "Common/File/FileUtil.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/Host.h" #include "Core/Reporting.h" @@ -736,10 +736,10 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, shaderSwitchDirtyUniforms_ = 0; if (ls == nullptr) { - _dbg_assert_(G3D, FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE)); - _dbg_assert_(G3D, FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE)); - _dbg_assert_(G3D, FSID.Bit(FS_BIT_ENABLE_FOG) == VSID.Bit(VS_BIT_ENABLE_FOG)); - _dbg_assert_(G3D, FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE)); + _dbg_assert_(FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE)); + _dbg_assert_(FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE)); + _dbg_assert_(FSID.Bit(FS_BIT_ENABLE_FOG) == VSID.Bit(VS_BIT_ENABLE_FOG)); + _dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE)); // Check if we can link these. ls = new LinkedShader(render_, VSID, vs, FSID, fs, vs->UseHWTransform()); @@ -850,7 +850,6 @@ void ShaderManagerGLES::Load(const std::string &filename) { if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.featureFlags != gstate_c.featureFlags) { return; } - time_update(); diskCachePending_.start = time_now_d(); diskCachePending_.Clear(); @@ -908,12 +907,12 @@ bool ShaderManagerGLES::ContinuePrecompile(float sliceTime) { PSP_SetLoading("Compiling shaders..."); - double start = real_time_now(); + double start = time_now_d(); // Let's try to keep it under sliceTime if possible. double end = start + sliceTime; for (size_t &i = pending.vertPos; i < pending.vert.size(); i++) { - if (real_time_now() >= end) { + if (time_now_d() >= end) { // We'll finish later. return false; } @@ -943,7 +942,7 @@ bool ShaderManagerGLES::ContinuePrecompile(float sliceTime) { } for (size_t &i = pending.fragPos; i < pending.frag.size(); i++) { - if (real_time_now() >= end) { + if (time_now_d() >= end) { // We'll finish later. return false; } @@ -957,7 +956,7 @@ bool ShaderManagerGLES::ContinuePrecompile(float sliceTime) { } for (size_t &i = pending.linkPos; i < pending.link.size(); i++) { - if (real_time_now() >= end) { + if (time_now_d() >= end) { // We'll finish later. return false; } @@ -974,7 +973,6 @@ bool ShaderManagerGLES::ContinuePrecompile(float sliceTime) { } // Okay, finally done. Time to report status. - time_update(); double finish = time_now_d(); NOTICE_LOG(G3D, "Precompile: Compiled and linked %d programs (%d vertex, %d fragment) in %0.1f milliseconds", (int)pending.link.size(), (int)pending.vert.size(), (int)pending.frag.size(), 1000 * (finish - pending.start)); diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 3ee0e8e002..613fab8eaf 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -19,9 +19,8 @@ #include -#include "base/basictypes.h" -#include "Common/Hashmaps.h" -#include "thin3d/GLRenderManager.h" +#include "Common/Data/Collections/Hashmaps.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "GPU/Common/ShaderCommon.h" #include "GPU/Common/ShaderId.h" #include "GPU/GLES/VertexShaderGeneratorGLES.h" diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 0df2077834..46883171c7 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -21,9 +21,9 @@ #include "StateMappingGLES.h" -#include "profiler/profiler.h" -#include "gfx/gl_debug_log.h" -#include "thin3d/GLRenderManager.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "GPU/Math3D.h" #include "GPU/GPUState.h" @@ -184,7 +184,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { fboTexBound_ = true; fboTexNeedBind_ = false; - framebufferManager_->RebindFramebuffer(); + framebufferManager_->RebindFramebuffer("RebindFramebuffer - ApplyDrawState"); // Must dirty blend state here so we re-copy next time. Example: Lunar's spell effects. gstate_c.Dirty(DIRTY_BLEND_STATE); } @@ -259,13 +259,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { bool cullEnable; GLenum cullMode = cullingMode[gstate.getCullMode() ^ !useBufferedRendering]; - if (gstate.isModeClear()) { - // Culling - cullEnable = false; - } else { - // Set cull - cullEnable = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); - } + cullEnable = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); renderManager->SetRaster(cullEnable, GL_CCW, cullMode, dither); } @@ -320,8 +314,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) { } } -void DrawEngineGLES::ApplyDrawStateLate(bool setStencil, int stencilValue) { - if (setStencil) { +void DrawEngineGLES::ApplyDrawStateLate(bool setStencilValue, int stencilValue) { + if (setStencilValue) { render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, stencilValue, 255); } diff --git a/GPU/GLES/StateMappingGLES.h b/GPU/GLES/StateMappingGLES.h index da4a271551..7fe7f082fa 100644 --- a/GPU/GLES/StateMappingGLES.h +++ b/GPU/GLES/StateMappingGLES.h @@ -17,4 +17,4 @@ #pragma once -#include "gfx/gl_common.h" +#include "Common/GPU/OpenGL/GLCommon.h" diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 387001db26..1c19fa09e8 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -15,7 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "gfx_es2/glsl_program.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Reporting.h" @@ -68,7 +68,7 @@ void main() { } )"; -bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZero) { +bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; @@ -109,12 +109,14 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe values = 256; break; case GE_FORMAT_INVALID: - // Impossible. + case GE_FORMAT_DEPTH16: + // Inconceivable. + _assert_(false); break; } if (usedBits == 0) { - if (skipZero) { + if (flags == StencilUpload::STENCIL_IS_ZERO) { // Common when creating buffers, it's already 0. We're done. return false; } @@ -122,7 +124,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe // Let's not bother with the shader if it's just zero. if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Clear"); } render_->Clear(0, 0, 0, GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); @@ -156,7 +158,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe shaderManagerGL_->DirtyLastShader(); - bool useBlit = gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT); + bool useBlit = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT); // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. // Then after we're done, we'll just blit it across and stretch it there. @@ -169,9 +171,9 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe Draw::Framebuffer *blitFBO = nullptr; if (useBlit) { blitFBO = GetTempFBO(TempFBO::STENCIL, w, h, Draw::FBO_8888); - draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "NotifyStencilUpload_Blit"); } else if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }, "NotifyStencilUpload_NoBlit"); } render_->SetViewport({ 0, 0, (float)w, (float)h, 0.0f, 1.0f }); @@ -212,11 +214,11 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe } if (useBlit) { - draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST); + draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST, "NotifyStencilUpload_Blit"); } tex->Release(); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - Stencil"); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); return true; } diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 9c036b85a7..03c1556376 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -19,11 +19,10 @@ #include #include "ext/xxhash.h" -#include "gfx/gl_debug_log.h" -#include "i18n/i18n.h" -#include "math/math_util.h" -#include "profiler/profiler.h" -#include "thin3d/GLRenderManager.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Math/math_util.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/ColorConv.h" #include "Core/Config.h" @@ -47,7 +46,6 @@ TextureCacheGLES::TextureCacheGLES(Draw::DrawContext *draw) : TextureCacheCommon(draw) { timesInvalidatedAllThisFrame_ = 0; - lastBoundTexture = nullptr; render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); SetupTextureDecoder(); @@ -73,7 +71,6 @@ void TextureCacheGLES::SetFramebufferManager(FramebufferManagerGLES *fbManager) } void TextureCacheGLES::ReleaseTexture(TexCacheEntry *entry, bool delete_them) { - DEBUG_LOG(G3D, "Deleting texture %08x", entry->addr); if (delete_them) { if (entry->textureName) { render_->DeleteTexture(entry->textureName); @@ -116,76 +113,19 @@ static const GLuint MagFiltGL[2] = { GL_LINEAR }; -// This should not have to be done per texture! OpenGL is silly yo -void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) { - int minFilt; - int magFilt; - bool sClamp; - bool tClamp; - float lodBias; - u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; - GETexLevelMode mode; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, mode); - +void TextureCacheGLES::ApplySamplingParams(const SamplerCacheKey &key) { if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - float minLod = 0.0f; - float maxLod = 0.0f; - if (maxLevel != 0) { - // TODO: What about a swap of autoMip mode? - if (true) { - if (mode == GE_TEXLEVEL_MODE_AUTO) { - minLod = 0.0f; - maxLod = (float)maxLevel; - } else if (mode == GE_TEXLEVEL_MODE_CONST) { - minLod = std::max(0.0f, std::min((float)maxLevel, lodBias)); - maxLod = std::max(0.0f, std::min((float)maxLevel, lodBias)); - } else { // mode == GE_TEXLEVEL_MODE_SLOPE) { - // It's incorrect to use the slope as a bias. Instead it should be passed - // into the shader directly as an explicit lod level, with the bias on top. For now, we just kill the - // lodBias in this mode, working around #9772. -#ifndef USING_GLES2 - lodBias = 0.0f; -#endif - minLod = 0.0f; - maxLod = (float)maxLevel; - } - } - } else { - minLod = 0.0f; - maxLod = 0.0f; - } + float minLod = (float)key.minLevel / 256.0f; + float maxLod = (float)key.maxLevel / 256.0f; + float lodBias = (float)key.lodBias / 256.0f; render_->SetTextureLod(0, minLod, maxLod, lodBias); } float aniso = 0.0f; - render_->SetTextureSampler(0, sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, MagFiltGL[magFilt], MinFiltGL[minFilt], aniso); -} - -void TextureCacheGLES::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, bool forcePoint) { - int minFilt; - int magFilt; - bool sClamp; - bool tClamp; - float lodBias; - GETexLevelMode mode; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, mode); - - minFilt &= 1; // framebuffers can't mipmap. - if (forcePoint) { - minFilt &= ~1; - magFilt &= ~1; - } - - // Often the framebuffer will not match the texture size. We'll wrap/clamp in the shader in that case. - // This happens whether we have OES_texture_npot or not. - int w = gstate.getTextureWidth(0); - int h = gstate.getTextureHeight(0); - if (w != bufferWidth || h != bufferHeight) { - sClamp = true; - tClamp = true; - } - float aniso = 0.0f; - render_->SetTextureSampler(TEX_SLOT_PSP_TEXTURE, sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, MagFiltGL[magFilt], MinFiltGL[minFilt], aniso); + int minKey = ((int)key.mipEnable << 2) | ((int)key.mipFilt << 1) | ((int)key.minFilt); + render_->SetTextureSampler(0, + key.sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, key.tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, + key.magFilt ? GL_LINEAR : GL_NEAREST, MinFiltGL[minKey], aniso); } static void ConvertColors(void *dstBuf, const void *srcBuf, Draw::DataFormat dstFmt, int numPixels) { @@ -228,7 +168,7 @@ void TextureCacheGLES::StartFrame() { } if (texelsScaledThisFrame_) { - // INFO_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); + VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); } texelsScaledThisFrame_ = 0; if (clearCacheNextFrame_) { @@ -250,7 +190,10 @@ void TextureCacheGLES::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBas // Adding clutBaseBytes may just be mitigating this for some usage patterns. const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); - clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + if (replacer_.Enabled()) + clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + else + clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF; // Avoid a copy when we don't need to convert colors. if (clutFormat != GE_CMODE_32BIT_ABGR8888) { @@ -280,54 +223,14 @@ void TextureCacheGLES::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBas clutLastFormat_ = gstate.clutformat; } -// #define DEBUG_TEXTURES - -#ifdef DEBUG_TEXTURES -bool SetDebugTexture() { - static const int highlightFrames = 30; - - static int numTextures = 0; - static int lastFrames = 0; - static int mostTextures = 1; - - if (lastFrames != gpuStats.numFlips) { - mostTextures = std::max(mostTextures, numTextures); - numTextures = 0; - lastFrames = gpuStats.numFlips; - } - - static GLuint solidTexture = 0; - - bool changed = false; - if (((gpuStats.numFlips / highlightFrames) % mostTextures) == numTextures) { - if (gpuStats.numFlips % highlightFrames == 0) { - NOTICE_LOG(G3D, "Highlighting texture # %d / %d", numTextures, mostTextures); - } - static const u32 solidTextureData[] = {0x99AA99FF}; - - if (solidTexture == 0) { - glGenTextures(1, &solidTexture); - glBindTexture(GL_TEXTURE_2D, solidTexture); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, solidTextureData); - } else { - glBindTexture(GL_TEXTURE_2D, solidTexture); - } - changed = true; - } - - ++numTextures; - return changed; -} -#endif - void TextureCacheGLES::BindTexture(TexCacheEntry *entry) { if (entry->textureName != lastBoundTexture) { render_->BindTexture(0, entry->textureName); lastBoundTexture = entry->textureName; } - UpdateSamplingParams(*entry, false); + int maxLevel = (entry->status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry->maxLevel; + SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry->addr); + ApplySamplingParams(samplerKey); gstate_c.SetUseShaderDepal(false); } @@ -439,21 +342,27 @@ protected: int renderH_; }; -void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { +void TextureCacheGLES::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) { DepalShader *depal = nullptr; uint32_t clutMode = gstate.clutformat & 0xFFFFFF; + bool need_depalettize = IsClutFormat(texFormat); + bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300); if (!gstate_c.Supports(GPU_SUPPORTS_32BIT_INT_FSHADER)) { useShaderDepal = false; } - if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { + if (need_depalettize && !g_Config.bDisableSlowFramebufEffects) { if (useShaderDepal) { const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); GLRTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); render_->BindTexture(TEX_SLOT_CLUT, clutTexture); render_->SetTextureSampler(TEX_SLOT_CLUT, GL_REPEAT, GL_CLAMP_TO_EDGE, GL_NEAREST, GL_NEAREST, 0.0f); framebufferManagerGL_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); - SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight, true); + SamplerCacheKey samplerKey = GetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); + samplerKey.magFilt = false; + samplerKey.minFilt = false; + samplerKey.mipEnable = false; + ApplySamplingParams(samplerKey); InvalidateLastTexture(); // Since we started/ended render passes, might need these. @@ -475,7 +384,7 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); GLRTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); Draw::Framebuffer *depalFBO = framebufferManagerGL_->GetTempFBO(TempFBO::DEPAL, framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888); - draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); render_->SetScissor(GLRect2D{ 0, 0, (int)framebuffer->renderWidth, (int)framebuffer->renderHeight }); render_->SetViewport(GLRViewport{ 0.0f, 0.0f, (float)framebuffer->renderWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f }); @@ -497,17 +406,15 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram TexCacheEntry::TexStatus alphaStatus = CheckAlpha((const uint8_t *)clutBuf_, getClutDestFormat(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); } else { - entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; - framebufferManagerGL_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650); } - framebufferManagerGL_->RebindFramebuffer(); - SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight, false); + framebufferManagerGL_->RebindFramebuffer("ApplyTextureFramebuffer"); - InvalidateLastTexture(); + SamplerCacheKey samplerKey = GetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); + ApplySamplingParams(samplerKey); // Since we started/ended render passes, might need these. gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE); @@ -538,11 +445,6 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { // For the estimate, we assume cluts always point to 8888 for simplicity. cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); - if (entry->framebuffer) { - // Nothing else to do here. - return; - } - // Always generate a texture name unless it's a framebuffer, we might need it if the texture is replaced later. if (!entry->textureName) { entry->textureName = render_->CreateTexture(GL_TEXTURE_2D); @@ -640,9 +542,6 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { texelsScaledThisFrame_ += w * h; } } - - // glBindTexture(GL_TEXTURE_2D, entry->textureName); - lastBoundTexture = entry->textureName; // GLES2 doesn't have support for a "Max lod" which is critical as PSP games often // don't specify mips all the way down. As a result, we either need to manually generate @@ -699,11 +598,6 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { } render_->FinalizeTexture(entry->textureName, texMaxLevel, genMips); - - // This will rebind it, but that's okay. - // Need to actually bind it now - it might only have gotten bound in the init phase. - render_->BindTexture(TEX_SLOT_PSP_TEXTURE, entry->textureName); - UpdateSamplingParams(*entry, true); } Draw::DataFormat TextureCacheGLES::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { @@ -832,29 +726,34 @@ bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) gstate.texbufwidth[0] = gstate.texbufwidth[level]; } - SetTexture(true); - if (!nextTexture_) - return false; + InvalidateLastTexture(); + SetTexture(); + + if (!nextTexture_) { + if (nextFramebufferTexture_) { + VirtualFramebuffer *vfb = nextFramebufferTexture_; + buffer.Allocate(vfb->bufferWidth, vfb->bufferHeight, GPU_DBG_FORMAT_8888, false); + bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->bufferWidth, vfb->bufferHeight, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), vfb->bufferWidth, "GetCurrentTextureDebug"); + // Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf. + // So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); + // We may have blitted to a temp FBO. + framebufferManager_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); + if (!retval) + ERROR_LOG(G3D, "Failed to get debug texture: copy to memory failed"); + return retval; + } else { + ERROR_LOG(G3D, "Failed to get debug texture: no texture set"); + return false; + } + } // Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer. TexCacheEntry *entry = nextTexture_; // We might need a render pass to set the sampling params, unfortunately. Otherwise BuildTexture may crash. - framebufferManagerGL_->RebindFramebuffer(); + framebufferManagerGL_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); ApplyTexture(); - // TODO: Centralize? - if (entry->framebuffer) { - VirtualFramebuffer *vfb = entry->framebuffer; - buffer.Allocate(vfb->bufferWidth, vfb->bufferHeight, GPU_DBG_FORMAT_8888, false); - bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->bufferWidth, vfb->bufferHeight, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), vfb->bufferWidth); - // Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf. - // So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); - // We may have blitted to a temp FBO. - framebufferManager_->RebindFramebuffer(); - return retval; - } - GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); // Not a framebuffer, so let's assume these are right. @@ -866,12 +765,17 @@ bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) gstate = saved; } - buffer.Allocate(w, h, GE_FORMAT_8888, false); - renderManager->CopyImageToMemorySync(entry->textureName, level, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, (uint8_t *)buffer.GetData(), w); + bool result = entry->textureName != nullptr; + if (result) { + buffer.Allocate(w, h, GE_FORMAT_8888, false); + renderManager->CopyImageToMemorySync(entry->textureName, level, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, (uint8_t *)buffer.GetData(), w, "GetCurrentTextureDebug"); + } else { + ERROR_LOG(G3D, "Failed to get debug texture: texture is null"); + } gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - framebufferManager_->RebindFramebuffer(); + framebufferManager_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); - return true; + return result; #else return false; #endif diff --git a/GPU/GLES/TextureCacheGLES.h b/GPU/GLES/TextureCacheGLES.h index abb4d2d2fb..1b3ba422e3 100644 --- a/GPU/GLES/TextureCacheGLES.h +++ b/GPU/GLES/TextureCacheGLES.h @@ -19,9 +19,9 @@ #include -#include "gfx_es2/gpu_features.h" -#include "gfx/gl_common.h" -#include "thin3d/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" #include "GPU/GLES/TextureScalerGLES.h" @@ -55,15 +55,11 @@ public: void ForgetLastTexture() override { lastBoundTexture = nullptr; - gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); } - void InvalidateLastTexture(TexCacheEntry *entry = nullptr) override { - if (!entry || entry->textureName == lastBoundTexture) { - lastBoundTexture = nullptr; - } + void InvalidateLastTexture() override { + lastBoundTexture = nullptr; } - void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, bool forcePoint); bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override; void DeviceLost(); @@ -75,13 +71,13 @@ protected: void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override; private: - void UpdateSamplingParams(TexCacheEntry &entry, bool force); + void ApplySamplingParams(const SamplerCacheKey &key); void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int scaleFactor, Draw::DataFormat dstFmt); Draw::DataFormat GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; TexCacheEntry::TexStatus CheckAlpha(const uint8_t *pixelData, Draw::DataFormat dstFmt, int stride, int w, int h); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; - void ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) override; + void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) override; void BuildTexture(TexCacheEntry *const entry) override; @@ -89,7 +85,7 @@ private: TextureScalerGLES scaler; - GLRTexture *lastBoundTexture; + GLRTexture *lastBoundTexture = nullptr; FramebufferManagerGLES *framebufferManagerGL_; DepalShaderCacheGLES *depalShaderCache_; diff --git a/GPU/GLES/TextureScalerGLES.cpp b/GPU/GLES/TextureScalerGLES.cpp index 73c1b849a7..2a22d8b178 100644 --- a/GPU/GLES/TextureScalerGLES.cpp +++ b/GPU/GLES/TextureScalerGLES.cpp @@ -15,20 +15,15 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#if _MSC_VER == 1700 -// Has to be included before TextureScaler.h, else we get those std::bind errors in VS2012.. -#include "../native/base/basictypes.h" -#endif - #include -#include "gfx/gl_common.h" +#include "Common/GPU/OpenGL/GLCommon.h" #include "GPU/Common/TextureScalerCommon.h" #include "GPU/GLES/TextureScalerGLES.h" #include "Common/ColorConv.h" #include "Common/Log.h" -#include "Common/ThreadPools.h" -#include "thin3d/DataFormat.h" +#include "Core/ThreadPools.h" +#include "Common/GPU/DataFormat.h" int TextureScalerGLES::BytesPerPixel(u32 format) { return ((Draw::DataFormat)format == Draw::DataFormat::R8G8B8A8_UNORM) ? 4 : 2; diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 078d79c283..188dd3c706 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -19,13 +19,13 @@ #include #include -#include "gfx_es2/gpu_features.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #if defined(_WIN32) && defined(_DEBUG) #include "Common/CommonWindows.h" #endif -#include "base/stringutil.h" +#include "Common/StringUtils.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "Core/Config.h" diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index 2a0bee4842..f731ee6cbb 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -17,7 +17,7 @@ #include "ppsspp_config.h" -#include "base/timeutil.h" +#include "Common/TimeUtil.h" #include "Common/GraphicsContext.h" #include "Core/Core.h" diff --git a/GPU/GPU.h b/GPU/GPU.h index 2c2fa9cc70..0a4fb4f66d 100644 --- a/GPU/GPU.h +++ b/GPU/GPU.h @@ -55,6 +55,7 @@ struct GPUStatistics { // Never add a vtable :) memset(this, 0, sizeof(*this)); } + void ResetFrame() { numDrawCalls = 0; numCachedDrawCalls = 0; @@ -63,10 +64,14 @@ struct GPUStatistics { numUncachedVertsDrawn = 0; numTrackedVertexArrays = 0; numTextureInvalidations = 0; + numTextureInvalidationsByFramebuffer = 0; + numTexturesHashed = 0; numTextureSwitches = 0; + numTextureDataBytesHashed = 0; numShaderSwitches = 0; numFlushes = 0; numTexturesDecoded = 0; + numFramebufferEvaluations = 0; numReadbacks = 0; numUploads = 0; numClears = 0; @@ -85,9 +90,13 @@ struct GPUStatistics { int numUncachedVertsDrawn; int numTrackedVertexArrays; int numTextureInvalidations; + int numTextureInvalidationsByFramebuffer; + int numTexturesHashed; + int numTextureDataBytesHashed; int numTextureSwitches; int numShaderSwitches; int numTexturesDecoded; + int numFramebufferEvaluations; int numReadbacks; int numUploads; int numClears; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 9b16ccf742..5d3468b07d 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -164,7 +164,7 @@ Level3 - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) StreamingSIMDExtensions2 Precise @@ -178,15 +178,11 @@ true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - Level3 - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang NotSet Precise false @@ -202,15 +198,11 @@ true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - Level3 - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang NotSet Precise false @@ -225,15 +217,11 @@ true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - Level3 - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang NotSet Precise false @@ -249,10 +237,6 @@ true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - @@ -260,7 +244,7 @@ MaxSpeed true true - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang false StreamingSIMDExtensions2 Precise @@ -276,10 +260,6 @@ true true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - @@ -287,7 +267,7 @@ MaxSpeed true true - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang false NotSet Precise @@ -305,10 +285,6 @@ true true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - @@ -316,7 +292,7 @@ MaxSpeed true true - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang false NotSet Precise @@ -334,10 +310,6 @@ true true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - @@ -345,7 +317,7 @@ MaxSpeed true true - ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy;../ext/glslang + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang false NotSet Precise @@ -363,16 +335,12 @@ true true - - ../Windows/git-version-gen.cmd - Updating git-version.cpp - - + @@ -417,9 +385,9 @@ + - @@ -511,7 +479,7 @@ - + @@ -525,7 +493,7 @@ - + @@ -596,9 +564,9 @@ + - @@ -607,6 +575,7 @@ + true true @@ -703,7 +672,7 @@ - + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index e5e6f1a0e7..04ac5cae2d 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -27,9 +27,6 @@ - - Common - Common @@ -84,9 +81,6 @@ DirectX9 - - DirectX9 - DirectX9 @@ -129,9 +123,6 @@ Common - - Common - Common @@ -168,7 +159,7 @@ Vulkan - + Vulkan @@ -288,6 +279,15 @@ Common + + Common + + + DirectX9 + + + Common + @@ -341,9 +341,6 @@ DirectX9 - - DirectX9 - DirectX9 @@ -383,9 +380,6 @@ Common - - Common - Common @@ -536,7 +530,7 @@ Common - + Vulkan @@ -572,5 +566,14 @@ Common + + Common + + + DirectX9 + + + Common + \ No newline at end of file diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index c63bab6e40..603ec061cc 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2,17 +2,19 @@ #include #include -#include "base/timeutil.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Common/ColorConv.h" #include "Common/GraphicsContext.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeList.h" +#include "Common/TimeUtil.h" #include "Core/Reporting.h" #include "GPU/GeDisasm.h" #include "GPU/GPU.h" #include "GPU/GPUCommon.h" #include "GPU/GPUState.h" -#include "ChunkFile.h" #include "Core/Config.h" #include "Core/CoreTiming.h" #include "Core/MemMap.h" @@ -26,7 +28,7 @@ #include "Core/Debugger/Breakpoints.h" #include "Core/MemMapHelpers.h" #include "GPU/Common/DrawEngineCommon.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/SplineCommon.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Debugger/Debugger.h" @@ -467,7 +469,7 @@ void GPUCommon::Reinitialize() { } void GPUCommon::UpdateVsyncInterval(bool force) { -#ifdef _WIN32 +#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) int desiredVSyncInterval = g_Config.bVSync ? 1 : 0; if (PSP_CoreParameter().unthrottle) { desiredVSyncInterval = 0; @@ -678,15 +680,15 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointernumStacks >= 256) { - ERROR_LOG_REPORT(G3D, "sceGeListEnqueue: invalid size %d", args->numStacks); - return SCE_KERNEL_ERROR_INVALID_SIZE; + + // If args->size is below 16, it's the old struct without stack info. + if (args.IsValid() && args->size >= 16 && args->numStacks >= 256) { + return hleLogError(G3D, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid stack depth %d", args->numStacks); } - + int id = -1; u64 currentTicks = CoreTiming::GetTicks(); - u32_le stackAddr = args.IsValid() ? args->stackAddr : 0; + u32_le stackAddr = args.IsValid() && args->size >= 16 ? args->stackAddr : 0; // Check compatibility if (sceKernelGetCompiledSdkVersion() > 0x01FFFFFF) { //numStacks = 0; @@ -929,7 +931,6 @@ u32 GPUCommon::Break(int mode) { void GPUCommon::NotifySteppingEnter() { if (coreCollectDebugStats) { - time_update(); timeSteppingStarted_ = time_now_d(); } } @@ -938,7 +939,6 @@ void GPUCommon::NotifySteppingExit() { if (timeSteppingStarted_ <= 0.0) { ERROR_LOG(G3D, "Mismatched stepping enter/exit."); } - time_update(); timeSpentStepping_ += time_now_d() - timeSteppingStarted_; timeSteppingStarted_ = 0.0; } @@ -948,7 +948,6 @@ bool GPUCommon::InterpretList(DisplayList &list) { // Initialized to avoid a race condition with bShowDebugStats changing. double start = 0.0; if (coreCollectDebugStats) { - time_update(); start = time_now_d(); } @@ -1016,7 +1015,6 @@ bool GPUCommon::InterpretList(DisplayList &list) { list.offsetAddr = gstate_c.offsetAddr; if (coreCollectDebugStats) { - time_update(); double total = time_now_d() - start - timeSpentStepping_; hleSetSteppingTime(timeSpentStepping_); timeSpentStepping_ = 0.0; @@ -1132,6 +1130,9 @@ void GPUCommon::ReapplyGfxState() { // The commands are embedded in the command memory so we can just reexecute the words. Convenient. // To be safe we pass 0xFFFFFFFF as the diff. + // TODO: Consider whether any of this should really be done. We might be able to get all the way + // by simplying dirtying the appropriate gstate_c dirty flags. + for (int i = GE_CMD_VERTEXTYPE; i < GE_CMD_BONEMATRIXNUMBER; i++) { if (i != GE_CMD_ORIGIN && i != GE_CMD_OFFSETADDR) { ExecuteOp(gstate.cmdmem[i], 0xFFFFFFFF); @@ -1146,8 +1147,17 @@ void GPUCommon::ReapplyGfxState() { // There are a few here in the middle that we shouldn't execute... + // 0x42 to 0xEA for (int i = GE_CMD_VIEWPORTXSCALE; i < GE_CMD_TRANSFERSTART; i++) { - ExecuteOp(gstate.cmdmem[i], 0xFFFFFFFF); + switch (i) { + case GE_CMD_LOADCLUT: + case GE_CMD_TEXSYNC: + case GE_CMD_TEXFLUSH: + break; + default: + ExecuteOp(gstate.cmdmem[i], 0xFFFFFFFF); + break; + } } // Let's just skip the transfer size stuff, it's just values. @@ -1223,7 +1233,7 @@ void GPUCommon::Execute_Origin(u32 op, u32 diff) { void GPUCommon::Execute_Jump(u32 op, u32 diff) { const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); if (!Memory::IsValidAddress(target)) { - ERROR_LOG_REPORT(G3D, "JUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + ERROR_LOG(G3D, "JUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); return; } @@ -1245,7 +1255,7 @@ void GPUCommon::Execute_BJump(u32 op, u32 diff) { UpdatePC(currentList->pc, target - 4); currentList->pc = target - 4; // pc will be increased after we return, counteract that } else { - ERROR_LOG_REPORT(G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + ERROR_LOG(G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); } } @@ -1256,7 +1266,7 @@ void GPUCommon::Execute_Call(u32 op, u32 diff) { const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); if (!Memory::IsValidAddress(target)) { - ERROR_LOG_REPORT(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + ERROR_LOG(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); return; } @@ -1289,7 +1299,7 @@ void GPUCommon::DoExecuteCall(u32 target) { } if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) { - ERROR_LOG_REPORT(G3D, "CALL: Stack full!"); + ERROR_LOG(G3D, "CALL: Stack full!"); } else { auto &stackEntry = currentList->stack[currentList->stackptr++]; stackEntry.pc = retval; @@ -1302,7 +1312,7 @@ void GPUCommon::DoExecuteCall(u32 target) { void GPUCommon::Execute_Ret(u32 op, u32 diff) { if (currentList->stackptr == 0) { - DEBUG_LOG_REPORT(G3D, "RET: Stack empty!"); + DEBUG_LOG(G3D, "RET: Stack empty!"); } else { auto &stackEntry = currentList->stack[--currentList->stackptr]; gstate_c.offsetAddr = stackEntry.offsetAddr; @@ -1576,7 +1586,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { } if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); return; } @@ -1586,18 +1596,12 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { u32 indexAddr = gstate_c.indexAddr; if (!Memory::IsValidAddress(indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", indexAddr); + ERROR_LOG(G3D, "Bad index address %08x!", indexAddr); return; } inds = Memory::GetPointerUnchecked(indexAddr); } -#ifndef MOBILE_DEVICE - if (prim > GE_PRIM_RECTANGLES) { - ERROR_LOG_REPORT_ONCE(reportPrim, G3D, "Unexpected prim type: %d", prim); - } -#endif - if (gstate_c.dirty & DIRTY_VERTEXSHADER_STATE) { vertexCost_ = EstimatePerVertexCost(); } @@ -1623,9 +1627,8 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { // Optimized submission of sequences of PRIM. Allows us to avoid going through all the mess // above for each one. This can be expanded to support additional games that intersperse - // PRIM commands with other commands. A special case that might be interesting is that game - // that changes culling mode between each prim, we could just change the triangle winding - // right here to still be able to join draw calls. + // PRIM commands with other commands. A special case is Earth Defence Force 2 that changes culling mode + // between each prim, we just change the triangle winding right here to still be able to join draw calls. uint32_t vtypeCheckMask = ~GE_VTYPE_WEIGHTCOUNT_MASK; if (!g_Config.bSoftwareSkinning) @@ -1672,11 +1675,11 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { break; } case GE_CMD_VADDR: - gstate.cmdmem[data >> 24] = data; + gstate.cmdmem[GE_CMD_VADDR] = data; gstate_c.vertexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF); break; case GE_CMD_IADDR: - gstate.cmdmem[data >> 24] = data; + gstate.cmdmem[GE_CMD_IADDR] = data; gstate_c.indexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF); break; case GE_CMD_OFFSETADDR: @@ -2340,10 +2343,10 @@ void GPUCommon::Execute_Unknown(u32 op, u32 diff) { } void GPUCommon::FastLoadBoneMatrix(u32 target) { - const int num = gstate.boneMatrixNumber & 0x7F; - const int mtxNum = num / 12; - uint32_t uniformsToDirty = DIRTY_BONEMATRIX0 << mtxNum; - if ((num - 12 * mtxNum) != 0) { + const u32 num = gstate.boneMatrixNumber & 0x7F; + const u32 mtxNum = num / 12; + u32 uniformsToDirty = DIRTY_BONEMATRIX0 << mtxNum; + if (num != 12 * mtxNum) { uniformsToDirty |= DIRTY_BONEMATRIX0 << ((mtxNum + 1) & 7); } @@ -2403,9 +2406,9 @@ void GPUCommon::DoState(PointerWrap &p) { if (!s) return; - p.Do(dlQueue); + Do(p, dlQueue); if (s >= 4) { - p.DoArray(dls, ARRAY_SIZE(dls)); + DoArray(p, dls, ARRAY_SIZE(dls)); } else if (s >= 3) { // This may have been saved with or without padding, depending on platform. // We need to upconvert it to our consistently-padded struct. @@ -2423,7 +2426,7 @@ void GPUCommon::DoState(PointerWrap &p) { const bool hasPadding = savedPtr32[1] == 1; if (hasPadding) { u32 padding; - p.Do(padding); + Do(p, padding); } for (size_t i = 1; i < ARRAY_SIZE(dls); ++i) { @@ -2431,13 +2434,13 @@ void GPUCommon::DoState(PointerWrap &p) { dls[i].padding = 0; if (hasPadding) { u32 padding; - p.Do(padding); + Do(p, padding); } } } else if (s >= 2) { for (size_t i = 0; i < ARRAY_SIZE(dls); ++i) { DisplayList_v2 oldDL; - p.Do(oldDL); + Do(p, oldDL); // Copy over everything except the last, new member (stackAddr.) memcpy(&dls[i], &oldDL, sizeof(DisplayList_v2)); dls[i].stackAddr = 0; @@ -2446,7 +2449,7 @@ void GPUCommon::DoState(PointerWrap &p) { // Can only be in read mode here. for (size_t i = 0; i < ARRAY_SIZE(dls); ++i) { DisplayList_v1 oldDL; - p.Do(oldDL); + Do(p, oldDL); // On 32-bit, they're the same, on 64-bit oldDL is bigger. memcpy(&dls[i], &oldDL, sizeof(DisplayList_v1)); // Fix the other fields. Let's hope context wasn't important, it was a pointer. @@ -2460,17 +2463,17 @@ void GPUCommon::DoState(PointerWrap &p) { if (currentList != nullptr) { currentID = (int)(currentList - &dls[0]); } - p.Do(currentID); + Do(p, currentID); if (currentID == 0) { currentList = nullptr; } else { currentList = &dls[currentID]; } - p.Do(interruptRunning); - p.Do(gpuState); - p.Do(isbreak); - p.Do(drawCompleteTicks); - p.Do(busyTicks); + Do(p, interruptRunning); + Do(p, gpuState); + Do(p, isbreak); + Do(p, drawCompleteTicks); + Do(p, busyTicks); } void GPUCommon::InterruptStart(int listid) { @@ -2535,7 +2538,7 @@ std::vector GPUCommon::ActiveDisplayLists() { void GPUCommon::ResetListPC(int listID, u32 pc) { if (listID < 0 || listID >= DisplayListMaxCount) { - _dbg_assert_msg_(G3D, false, "listID out of range: %d", listID); + _dbg_assert_msg_(false, "listID out of range: %d", listID); return; } @@ -2544,7 +2547,7 @@ void GPUCommon::ResetListPC(int listID, u32 pc) { void GPUCommon::ResetListStall(int listID, u32 stall) { if (listID < 0 || listID >= DisplayListMaxCount) { - _dbg_assert_msg_(G3D, false, "listID out of range: %d", listID); + _dbg_assert_msg_(false, "listID out of range: %d", listID); return; } @@ -2553,7 +2556,7 @@ void GPUCommon::ResetListStall(int listID, u32 stall) { void GPUCommon::ResetListState(int listID, DisplayListState state) { if (listID < 0 || listID >= DisplayListMaxCount) { - _dbg_assert_msg_(G3D, false, "listID out of range: %d", listID); + _dbg_assert_msg_(false, "listID out of range: %d", listID); return; } @@ -2872,3 +2875,38 @@ bool GPUCommon::FramebufferReallyDirty() { } return true; } + +size_t GPUCommon::FormatGPUStatsCommon(char *buffer, size_t size) { + float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; + return snprintf(buffer, size, + "DL processing time: %0.2f ms\n" + "Draw calls: %d, flushes %d, clears %d (cached: %d)\n" + "Num Tracked Vertex Arrays: %d\n" + "Commands per call level: %i %i %i %i\n" + "Vertices: %d cached: %d uncached: %d\n" + "FBOs active: %d (evaluations: %d)\n" + "Textures: %d, dec: %d, invalidated: %d, hashed: %d kB\n" + "Readbacks: %d, uploads: %d\n" + "GPU cycles executed: %d (%f per vertex)\n", + gpuStats.msProcessingDisplayLists * 1000.0f, + gpuStats.numDrawCalls, + gpuStats.numFlushes, + gpuStats.numClears, + gpuStats.numCachedDrawCalls, + gpuStats.numTrackedVertexArrays, + gpuStats.gpuCommandsAtCallLevel[0], gpuStats.gpuCommandsAtCallLevel[1], gpuStats.gpuCommandsAtCallLevel[2], gpuStats.gpuCommandsAtCallLevel[3], + gpuStats.numVertsSubmitted, + gpuStats.numCachedVertsDrawn, + gpuStats.numUncachedVertsDrawn, + (int)framebufferManager_->NumVFBs(), + gpuStats.numFramebufferEvaluations, + (int)textureCache_->NumLoadedTextures(), + gpuStats.numTexturesDecoded, + gpuStats.numTextureInvalidations, + gpuStats.numTextureDataBytesHashed / 1024, + gpuStats.numReadbacks, + gpuStats.numUploads, + gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles, + vertexAverageCycles + ); +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 9637cd6d04..77c354a43f 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -304,6 +304,8 @@ protected: } } + size_t FormatGPUStatsCommon(char *buf, size_t size); + FramebufferManagerCommon *framebufferManager_ = nullptr; TextureCacheCommon *textureCache_ = nullptr; DrawEngineCommon *drawEngineCommon_ = nullptr; @@ -341,7 +343,7 @@ protected: bool dumpThisFrame_; bool debugRecording_; bool interruptsEnabled_; - bool resized_; + bool resized_ = false; DrawType lastDraw_ = DRAW_UNKNOWN; GEPrimitiveType lastPrim_ = GE_PRIM_INVALID; @@ -364,10 +366,7 @@ private: // Debug stats. double timeSteppingStarted_; double timeSpentStepping_; - -#ifdef _WIN32 int lastVsync_ = -1; -#endif }; struct CommonCommandTableEntry { diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index 44c9419cb9..bc62a3661b 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -18,7 +18,8 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" -#include "Common/ChunkFile.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/CoreParameter.h" #include "Core/Config.h" #include "Core/System.h" @@ -277,7 +278,7 @@ void GPUStateCache::DoState(PointerWrap &p) { if (!s) { // Old state, this was not versioned. GPUStateCache_v0 old; - p.Do(old); + Do(p, old); vertexAddr = old.vertexAddr; indexAddr = old.indexAddr; @@ -290,67 +291,67 @@ void GPUStateCache::DoState(PointerWrap &p) { savedContextVersion = 0; } else { - p.Do(vertexAddr); - p.Do(indexAddr); - p.Do(offsetAddr); + Do(p, vertexAddr); + Do(p, indexAddr); + Do(p, offsetAddr); uint8_t textureChanged = 0; - p.Do(textureChanged); // legacy + Do(p, textureChanged); // legacy gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - p.Do(textureFullAlpha); - p.Do(vertexFullAlpha); + Do(p, textureFullAlpha); + Do(p, vertexFullAlpha); bool framebufChanged = false; // legacy - p.Do(framebufChanged); + Do(p, framebufChanged); - p.Do(skipDrawReason); + Do(p, skipDrawReason); - p.Do(uv); + Do(p, uv); bool oldFlipTexture = false; - p.Do(oldFlipTexture); // legacy + Do(p, oldFlipTexture); // legacy } // needShaderTexClamp and bgraTexture don't need to be saved. if (s >= 3) { bool oldTextureSimpleAlpha = false; - p.Do(oldTextureSimpleAlpha); + Do(p, oldTextureSimpleAlpha); } if (s < 2) { float l12[12]; float l4[4]; - p.Do(l12); // lightpos - p.Do(l12); // lightdir - p.Do(l12); // lightattr - p.Do(l12); // lightcol0 - p.Do(l12); // lightcol1 - p.Do(l12); // lightcol2 - p.Do(l4); // lightangle - p.Do(l4); // lightspot + Do(p, l12); // lightpos + Do(p, l12); // lightdir + Do(p, l12); // lightattr + Do(p, l12); // lightcol0 + Do(p, l12); // lightcol1 + Do(p, l12); // lightcol2 + Do(p, l4); // lightangle + Do(p, l4); // lightspot } - p.Do(morphWeights); + Do(p, morphWeights); - p.Do(curTextureWidth); - p.Do(curTextureHeight); - p.Do(actualTextureHeight); + Do(p, curTextureWidth); + Do(p, curTextureHeight); + Do(p, actualTextureHeight); // curTextureXOffset and curTextureYOffset don't need to be saved. Well, the above don't either... - p.Do(vpWidth); - p.Do(vpHeight); + Do(p, vpWidth); + Do(p, vpHeight); if (s == 4) { float oldDepth = 1.0f; - p.Do(oldDepth); + Do(p, oldDepth); } - p.Do(curRTWidth); - p.Do(curRTHeight); + Do(p, curRTWidth); + Do(p, curRTHeight); // curRTBufferWidth, curRTBufferHeight, and cutRTOffsetX don't need to be saved. if (s < 5) { savedContextVersion = 0; } else { - p.Do(savedContextVersion); + Do(p, savedContextVersion); } } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 2f33c3fb91..f012e023bc 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -17,8 +17,6 @@ #pragma once -#include - #include "Common/Common.h" #include "Common/Swap.h" #include "GPU/GPU.h" @@ -482,18 +480,16 @@ enum { GPU_SUPPORTS_16BIT_FORMATS = FLAG_BIT(13), GPU_SUPPORTS_DEPTH_CLAMP = FLAG_BIT(14), GPU_SUPPORTS_32BIT_INT_FSHADER = FLAG_BIT(15), - GPU_SUPPORTS_LARGE_VIEWPORTS = FLAG_BIT(16), + // Free bit: 16 GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17), GPU_SUPPORTS_VAO = FLAG_BIT(18), - GPU_SUPPORTS_ANY_COPY_IMAGE = FLAG_BIT(19), + GPU_SUPPORTS_COPY_IMAGE = FLAG_BIT(19), GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20), GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24), - GPU_SUPPORTS_FBO = FLAG_BIT(25), - GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT = FLAG_BIT(26), - GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT = FLAG_BIT(27), + GPU_SUPPORTS_FRAMEBUFFER_BLIT = FLAG_BIT(26), GPU_SUPPORTS_OES_TEXTURE_NPOT = FLAG_BIT(28), GPU_NEEDS_Z_EQUAL_W_HACK = FLAG_BIT(29), GPU_PREFER_CPU_DOWNLOAD = FLAG_BIT(30), diff --git a/GPU/GeConstants.cpp b/GPU/GeConstants.cpp new file mode 100644 index 0000000000..a8a27685cb --- /dev/null +++ b/GPU/GeConstants.cpp @@ -0,0 +1,28 @@ +#include "GPU/ge_constants.h" + +const char *GeBufferFormatToString(GEBufferFormat fmt) { + switch (fmt) { + case GE_FORMAT_4444: return "4444"; + case GE_FORMAT_5551: return "5551"; + case GE_FORMAT_565: return "565"; + case GE_FORMAT_8888: return "8888"; + default: return "N/A"; + } +} + +const char *GeTextureFormatToString(GETextureFormat fmt) { + switch (fmt) { + case GE_TFMT_5650: return "565"; + case GE_TFMT_5551: return "5551"; + case GE_TFMT_4444: return "4444"; + case GE_TFMT_8888: return "8888"; + case GE_TFMT_CLUT4: return "CLUT4"; + case GE_TFMT_CLUT8: return "CLUT8"; + case GE_TFMT_CLUT16: return "CLUT16"; + case GE_TFMT_CLUT32: return "CLUT32"; + case GE_TFMT_DXT1: return "DXT1"; + case GE_TFMT_DXT3: return "DXT3"; + case GE_TFMT_DXT5: return "DXT5"; + default: return "N/A"; + } +} diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index 4faaca6a43..ef04d7c606 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -15,9 +15,10 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Core/MemMap.h" +#include -#include "ge_constants.h" +#include "Core/MemMap.h" +#include "GPU/ge_constants.h" #include "GPU/GPU.h" #include "GPU/GPUState.h" @@ -429,7 +430,7 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { case GE_CMD_LOADCLUT: // This could be used to "dirty" textures with clut. if (data) - snprintf(buffer, bufsize, "Clut load: %06x", data); + snprintf(buffer, bufsize, "Clut load: %08x, %d bytes, %06x", gstate.getClutAddress(), (data & 0x3F) << 5, data & 0xFFFFC0); else snprintf(buffer, bufsize, "Clut load"); break; diff --git a/GPU/Math3D.h b/GPU/Math3D.h index ada1a6931e..873119613d 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -21,7 +21,7 @@ #include "Common/Common.h" #include "Core/Util/AudioFormat.h" // for clamp_u8 -#include "math/fast/fast_matrix.h" +#include "Common/Math/fast/fast_matrix.h" #if defined(_M_SSE) #include diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index 2aa3ff69eb..66db9a08e4 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -23,7 +23,7 @@ #include "GPU/Software/Rasterizer.h" #include "GPU/Software/RasterizerRectangle.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" namespace Clipper { @@ -206,7 +206,7 @@ void ProcessRect(const VertexData& v0, const VertexData& v1) VertexData* bottomleft = &buf[2]; VertexData* bottomright = &buf[3]; - // Um. Why is this stuff needed? + // DrawTriangle always culls, so sort out the drawing order. for (int i = 0; i < 4; ++i) { if (buf[i].screenpos.x < topleft->screenpos.x && buf[i].screenpos.y < topleft->screenpos.y) topleft = &buf[i]; @@ -324,10 +324,11 @@ void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2, const Verte indices[1] = SKIP_FLAG; indices[2] = SKIP_FLAG; - POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); - POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); - POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); - POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); + // The PSP doesn't clip on the sides (so, commented out) but it does appear to have a Z clipper. + // POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); + // POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); + // POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); + // POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1); POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 23a0437be2..feaeca1e89 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -18,10 +18,9 @@ #include #include -#include "base/basictypes.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" -#include "Common/ThreadPools.h" +#include "Core/ThreadPools.h" #include "Common/ColorConv.h" #include "Core/Config.h" #include "Core/MemMap.h" @@ -268,7 +267,8 @@ static inline u32 GetPixelColor(int x, int y) return fb.Get32(x, y, gstate.FrameBufStride()); case GE_FORMAT_INVALID: - _dbg_assert_msg_(G3D, false, "Software: invalid framebuf format."); + case GE_FORMAT_DEPTH16: + _dbg_assert_msg_(false, "Software: invalid framebuf format."); } return 0; } @@ -293,7 +293,8 @@ static inline void SetPixelColor(int x, int y, u32 value) break; case GE_FORMAT_INVALID: - _dbg_assert_msg_(G3D, false, "Software: invalid framebuf format."); + case GE_FORMAT_DEPTH16: + _dbg_assert_msg_(false, "Software: invalid framebuf format."); } } @@ -1034,9 +1035,9 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const levelFrac = 0; } - if (g_Config.iTexFiltering == TEX_FILTER_LINEAR) { + if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { filt = true; - } else if (g_Config.iTexFiltering == TEX_FILTER_NEAREST) { + } else if (g_Config.iTexFiltering == TEX_FILTER_FORCE_NEAREST) { filt = false; } else { filt = detail > 0 ? gstate.isMinifyFilteringEnabled() : gstate.isMagnifyFilteringEnabled(); @@ -1498,7 +1499,8 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1) break; case GE_FORMAT_INVALID: - _dbg_assert_msg_(G3D, false, "Software: invalid framebuf format."); + case GE_FORMAT_DEPTH16: + _dbg_assert_msg_(false, "Software: invalid framebuf format."); break; } diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index e396d3a16a..668a9476e3 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -1,10 +1,9 @@ -// See comment in header for the purpose of this. +// See comment in header for the purpose of the code in this file. #include #include -#include "base/basictypes.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Core/System.h" @@ -24,25 +23,24 @@ #include #endif -extern bool g_DarkStalkerStretch; +extern DSStretch g_DarkStalkerStretch; // For Darkstalkers hack. Ugh. extern bool currentDialogActive; namespace Rasterizer { // Through mode, with the specific Darkstalker settings. -inline void DrawSinglePixel5551(u16 *pixel, const Vec4 &color_in) { +inline void DrawSinglePixel5551(u16 *pixel, const u32 color_in) { u32 new_color; - if (color_in.a() == 255) { - new_color = color_in.ToRGBA() & 0xFFFFFF; + if ((color_in >> 24) == 255) { + new_color = color_in & 0xFFFFFF; } else { const u32 old_color = RGBA5551ToRGBA8888(*pixel); const Vec4 dst = Vec4::FromRGBA(old_color); - Vec3 blended = AlphaBlendingResult(color_in, dst); + Vec3 blended = AlphaBlendingResult(Vec4::FromRGBA(color_in), dst); // ToRGB() always automatically clamps. new_color = blended.ToRGB(); } - new_color |= (*pixel & 0x8000) ? 0xff000000 : 0x00000000; *pixel = RGBA8888ToRGBA5551(new_color); } @@ -148,7 +146,7 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) { for (int x = pos0.x; x < pos1.x; x++) { u32 tex_color = nearestFunc(s, t, texptr, texbufw, 0); if (tex_color & 0xFF000000) { - DrawSinglePixel5551(pixel, Vec4::FromRGBA(tex_color)); + DrawSinglePixel5551(pixel, tex_color); } s += ds; pixel++; @@ -159,7 +157,7 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) { Vec4 tex_color = Vec4::FromRGBA(nearestFunc(s, t, texptr, texbufw, 0)); prim_color = ModulateRGBA(prim_color, tex_color); if (prim_color.a() > 0) { - DrawSinglePixel5551(pixel, prim_color); + DrawSinglePixel5551(pixel, prim_color.ToRGBA()); } s += ds; pixel++; @@ -208,7 +206,7 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) { u16 *pixel = fb.Get16Ptr(pos0.x, y, gstate.FrameBufStride()); for (int x = pos0.x; x < pos1.x; x++) { Vec4 prim_color = v0.color0; - DrawSinglePixel5551(pixel, prim_color); + DrawSinglePixel5551(pixel, prim_color.ToRGBA()); pixel++; } } @@ -224,11 +222,11 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) { } } -bool needsClear = false; +bool g_needsClearAfterDialog = false; // Returns true if the normal path should be skipped. bool RectangleFastPath(const VertexData &v0, const VertexData &v1) { - g_DarkStalkerStretch = false; + g_DarkStalkerStretch = DSStretch::Off; // Check for 1:1 texture mapping. In that case we can call DrawSprite. int xdiff = v1.screenpos.x - v0.screenpos.x; int ydiff = v1.screenpos.y - v0.screenpos.y; @@ -237,8 +235,10 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1) { bool coord_check = (xdiff == udiff || xdiff == -udiff) && (ydiff == vdiff || ydiff == -vdiff); + // Currently only works for TL/BR, which is the most common but not required. + bool orient_check = xdiff >= 0 && ydiff >= 0; bool state_check = !gstate.isModeClear(); // TODO: Add support for clear modes in Rasterizer::DrawSprite. - if ((coord_check || !gstate.isTextureMapEnabled()) && state_check) { + if ((coord_check || !gstate.isTextureMapEnabled()) && orient_check && state_check) { Rasterizer::DrawSprite(v0, v1); return true; } @@ -246,24 +246,28 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1) { // Eliminate the stretch blit in DarkStalkers. // We compensate for that when blitting the framebuffer in SoftGpu.cpp. if (PSP_CoreParameter().compat.flags().DarkStalkersPresentHack && v0.texturecoords.x == 64.0f && v0.texturecoords.y == 16.0f && v1.texturecoords.x == 448.0f && v1.texturecoords.y == 240.0f) { - if (v0.screenpos.x == 0x7100 && v0.screenpos.y == 0x7780 && v1.screenpos.x == 0x8f00 && v1.screenpos.y == 0x8880) { - // Also check for save/load dialog. - if (!currentDialogActive) { - g_DarkStalkerStretch = true; - if (needsClear) { - needsClear = false; - // Afterwards, we also need to clear the actual destination. Can do a fast rectfill. - gstate.textureMapEnable &= ~1; - VertexData newV0 = v0; - newV0.color0 = Vec4(0, 0, 0, 255); - Rasterizer::DrawSprite(newV0, v1); - gstate.textureMapEnable |= 1; - } - return true; + // check for save/load dialog. + if (!currentDialogActive) { + if (v0.screenpos.x == 0x7100 && v0.screenpos.y == 0x7780 && v1.screenpos.x == 0x8f00 && v1.screenpos.y == 0x8880) { + g_DarkStalkerStretch = DSStretch::Wide; + } else if (v0.screenpos.x == 0x7400 && v0.screenpos.y == 0x7780 && v1.screenpos.x == 0x8C00 && v1.screenpos.y == 0x8880) { + g_DarkStalkerStretch = DSStretch::Normal; } else { - needsClear = true; + return false; } - } // else, handle the Capcom screen stretch, or the non-wide stretch? Or let's just not bother. + if (g_needsClearAfterDialog) { + g_needsClearAfterDialog = false; + // Afterwards, we also need to clear the actual destination. Can do a fast rectfill. + gstate.textureMapEnable &= ~1; + VertexData newV0 = v0; + newV0.color0 = Vec4(0, 0, 0, 255); + Rasterizer::DrawSprite(newV0, v1); + gstate.textureMapEnable |= 1; + } + return true; + } else { + g_needsClearAfterDialog = true; + } } return false; } diff --git a/GPU/Software/SamplerX86.cpp b/GPU/Software/SamplerX86.cpp index 5fdca729f8..2fb08e88d3 100644 --- a/GPU/Software/SamplerX86.cpp +++ b/GPU/Software/SamplerX86.cpp @@ -97,7 +97,7 @@ alignas(16) static const float by256[4] = { 1.0f / 256.0f, 1.0f / 256.0f, 1.0f / alignas(16) static const float ones[4] = { 1.0f, 1.0f, 1.0f, 1.0f, }; LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { - _assert_msg_(G3D, id.linear, "Linear should be set on sampler id"); + _assert_msg_(id.linear, "Linear should be set on sampler id"); BeginWrite(); // We'll first write the nearest sampler, which we will CALL. diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index a45b4791dc..f5c53b7bbb 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -15,8 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/display.h" -#include "gfx_es2/gpu_features.h" +#include "Common/System/Display.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" @@ -32,8 +32,8 @@ #include "Core/MIPS/MIPS.h" #include "Core/Reporting.h" #include "Core/Core.h" -#include "profiler/profiler.h" -#include "thin3d/thin3d.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/thin3d.h" #include "GPU/Software/Rasterizer.h" #include "GPU/Software/Sampler.h" @@ -132,7 +132,7 @@ void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for GPURecord::NotifyDisplay(framebuf, stride, format); } -bool g_DarkStalkerStretch; +DSStretch g_DarkStalkerStretch; void SoftGPU::ConvertTextureDescFrom16(Draw::TextureDesc &desc, int srcwidth, int srcheight, u8 *overrideData) { // TODO: This should probably be converted in a shader instead.. @@ -200,7 +200,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { OutputFlags outputFlags = g_Config.iBufFilter == SCALE_NEAREST ? OutputFlags::NEAREST : OutputFlags::LINEAR; bool hasPostShader = presentation_->HasPostShader(); - if (PSP_CoreParameter().compat.flags().DarkStalkersPresentHack && displayFormat_ == GE_FORMAT_5551 && g_DarkStalkerStretch) { + if (PSP_CoreParameter().compat.flags().DarkStalkersPresentHack && displayFormat_ == GE_FORMAT_5551 && g_DarkStalkerStretch != DSStretch::Off) { u8 *data = Memory::GetPointer(0x04088000); bool fillDesc = true; if (draw_->GetDataFormatSupport(Draw::DataFormat::A1B5G5R5_UNORM_PACK16) & Draw::FMT_TEXTURE) { @@ -223,6 +223,9 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { u1 = 447.5f / (float)desc.width; v0 = 16.0f / (float)desc.height; v1 = 240.0f / (float)desc.height; + if (g_DarkStalkerStretch == DSStretch::Normal) { + outputFlags |= OutputFlags::PILLARBOX; + } } else if (!Memory::IsValidAddress(displayFramebuf_) || srcwidth == 0 || srcheight == 0) { hasImage = false; u1 = 1.0f; @@ -257,7 +260,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { u1 = 1.0f; } if (!hasImage) { - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam"); return; } diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index e97f6c1dde..bd8e6a12fe 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -19,7 +19,7 @@ #include "GPU/GPUCommon.h" #include "GPU/Common/GPUDebugInterface.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" struct FormatBuffer { FormatBuffer() { data = nullptr; } @@ -121,3 +121,10 @@ private: extern u32 clut[4096]; extern FormatBuffer fb; extern FormatBuffer depthbuf; + +// Type for the DarkStalkers stretch replacement. +enum class DSStretch { + Off = 0, + Normal, + Wide, +}; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 0efb0903d4..501e369e52 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -16,7 +16,9 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "math/math_util.h" +#include + +#include "Common/Math/math_util.h" #include "Common/MemoryUtil.h" #include "Core/Config.h" #include "GPU/GPUState.h" @@ -54,7 +56,7 @@ void SoftwareDrawEngine::DispatchFlush() { } void SoftwareDrawEngine::DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead) { - _assert_msg_(G3D, cullMode == gstate.getCullMode(), "Mixed cull mode not supported."); + _assert_msg_(cullMode == gstate.getCullMode(), "Mixed cull mode not supported."); transformUnit.SubmitPrimitive(verts, inds, prim, vertexCount, vertTypeID, bytesRead, this); } @@ -398,7 +400,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy break; default: - _dbg_assert_msg_(G3D, false, "Unexpected prim type: %d", prim_type); + _dbg_assert_msg_(false, "Unexpected prim type: %d", prim_type); } } break; diff --git a/GPU/Vulkan/DebugVisVulkan.cpp b/GPU/Vulkan/DebugVisVulkan.cpp index 8f2cc381a4..78616e86c5 100644 --- a/GPU/Vulkan/DebugVisVulkan.cpp +++ b/GPU/Vulkan/DebugVisVulkan.cpp @@ -15,16 +15,17 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "gfx_es2/draw_buffer.h" -#include "thin3d/thin3d.h" -#include "ui/ui_context.h" -#include "ui/view.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/GPU/thin3d.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" #include "DebugVisVulkan.h" -#include "Common/Vulkan/VulkanMemory.h" -#include "Common/Vulkan/VulkanImage.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanImage.h" #include "GPU/Vulkan/GPU_Vulkan.h" #include "GPU/Vulkan/VulkanUtil.h" +#include "GPU/Vulkan/TextureCacheVulkan.h" #undef DrawText diff --git a/GPU/Vulkan/DebugVisVulkan.h b/GPU/Vulkan/DebugVisVulkan.h index e220003a56..b616d856f3 100644 --- a/GPU/Vulkan/DebugVisVulkan.h +++ b/GPU/Vulkan/DebugVisVulkan.h @@ -17,7 +17,7 @@ #pragma once -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" class GPUInterface; class UIContext; diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.cpp b/GPU/Vulkan/DepalettizeShaderVulkan.cpp index 31041b010b..4d11207eb2 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.cpp +++ b/GPU/Vulkan/DepalettizeShaderVulkan.cpp @@ -16,12 +16,15 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/ColorConv.h" -#include "Common/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanImage.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "GPU/Common/DepalettizeShaderCommon.h" #include "GPU/Vulkan/DepalettizeShaderVulkan.h" #include "GPU/Vulkan/VulkanUtil.h" -#include "Common/Vulkan/VulkanImage.h" +#include "Common/GPU/Vulkan/VulkanImage.h" static const char depal_vs[] = R"(#version 450 #extension GL_ARB_separate_shader_objects : enable @@ -84,7 +87,7 @@ void DepalShaderCacheVulkan::DeviceRestore(Draw::DrawContext *draw, VulkanContex vulkan_ = vulkan; std::string errors; vshader_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, depal_vs, &errors); - assert(vshader_ != VK_NULL_HANDLE); + _assert_(vshader_ != VK_NULL_HANDLE); } DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat) { @@ -103,6 +106,7 @@ DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMod std::string error; VkShaderModule fshader = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, buffer, &error); if (fshader == VK_NULL_HANDLE) { + INFO_LOG(G3D, "Source:\n%s\n\n", buffer); Crash(); delete[] buffer; return nullptr; @@ -111,6 +115,7 @@ DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMod VkPipeline pipeline = vulkan2D_->GetPipeline(rp, vshader_, fshader); // Can delete the shader module now that the pipeline has been created. // Maybe don't even need to queue it.. + // "true" keeps the pipeline itself alive, forgetting the fshader. vulkan2D_->PurgeFragmentShader(fshader, true); vulkan_->Delete().QueueDeleteShaderModule(fshader); diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.h b/GPU/Vulkan/DepalettizeShaderVulkan.h index ec01a17b96..e78d817feb 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.h +++ b/GPU/Vulkan/DepalettizeShaderVulkan.h @@ -20,11 +20,8 @@ #include #include "Common/CommonTypes.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanImage.h" -#include "Common/Vulkan/VulkanMemory.h" -#include "GPU/ge_constants.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/thin3d.h" #include "GPU/Common/DepalettizeShaderCommon.h" class DepalShaderVulkan { @@ -45,6 +42,7 @@ public: class VulkanTexture; class Vulkan2D; +class VulkanPushBuffer; // Caches both shaders and palette textures. // Could even avoid bothering with palette texture and just use uniform data... @@ -74,7 +72,6 @@ private: VkShaderModule vshader_ = VK_NULL_HANDLE; Vulkan2D *vulkan2D_ = nullptr; - // GLuint vertexShader_; std::map cache_; std::map texCache_; }; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 62305dd14a..04d48db348 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -15,15 +15,15 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include +#include -#include "base/logging.h" -#include "base/timeutil.h" -#include "math/dataconv.h" -#include "profiler/profiler.h" -#include "thin3d/VulkanRenderManager.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/Log.h" #include "Common/MemoryUtil.h" +#include "Common/TimeUtil.h" #include "Core/MemMap.h" #include "Core/System.h" #include "Core/Reporting.h" @@ -34,10 +34,9 @@ #include "GPU/GPUState.h" #include "GPU/ge_constants.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" -#include "GPU/Common/TextureDecoder.h" #include "GPU/Common/SplineCommon.h" #include "GPU/Common/TransformCommon.h" #include "GPU/Common/VertexDecoderCommon.h" @@ -48,7 +47,7 @@ #include "GPU/Vulkan/TextureCacheVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Vulkan/PipelineManagerVulkan.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/GPU_Vulkan.h" @@ -142,7 +141,7 @@ void DrawEngineVulkan::InitDeviceObjects() { dsl.bindingCount = ARRAY_SIZE(bindings); dsl.pBindings = bindings; VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_); - assert(VK_SUCCESS == res); + _dbg_assert_(VK_SUCCESS == res); // We are going to use one-shot descriptors in the initial implementation. Might look into caching them // if creating and updating them turns out to be expensive. @@ -164,7 +163,7 @@ void DrawEngineVulkan::InitDeviceObjects() { pl.pSetLayouts = &descriptorSetLayout_; pl.flags = 0; res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); - assert(VK_SUCCESS == res); + _dbg_assert_(VK_SUCCESS == res); VkSamplerCreateInfo samp{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; @@ -175,8 +174,9 @@ void DrawEngineVulkan::InitDeviceObjects() { samp.magFilter = VK_FILTER_NEAREST; samp.minFilter = VK_FILTER_NEAREST; res = vkCreateSampler(device, &samp, nullptr, &samplerSecondary_); + _dbg_assert_(VK_SUCCESS == res); res = vkCreateSampler(device, &samp, nullptr, &nullSampler_); - assert(VK_SUCCESS == res); + _dbg_assert_(VK_SUCCESS == res); vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); @@ -259,9 +259,10 @@ void DrawEngineVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *d } void DrawEngineVulkan::BeginFrame() { - // Too many issues right now to allow reuse. lastPipeline_ = nullptr; + lastRenderStepId_ = -1; + int curFrame = vulkan_->GetCurFrame(); FrameData *frame = &frame_[curFrame]; @@ -289,6 +290,9 @@ void DrawEngineVulkan::BeginFrame() { vertexCache_->Destroy(vulkan_); delete vertexCache_; // orphans the buffers, they'll get deleted once no longer used by an in-flight frame. vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + vai_.Iterate([&](uint32_t hash, VertexArrayInfoVulkan *vai) { + delete vai; + }); vai_.Clear(); } @@ -384,6 +388,10 @@ VkResult DrawEngineVulkan::RecreateDescriptorPool(FrameData &frame, int newSize) } VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess) { + _dbg_assert_(base != VK_NULL_HANDLE); + _dbg_assert_(light != VK_NULL_HANDLE); + _dbg_assert_(bone != VK_NULL_HANDLE); + DescriptorSetKey key; key.imageView_ = imageView; key.sampler_ = sampler; @@ -392,9 +400,6 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView key.base_ = base; key.light_ = light; key.bone_ = bone; - _dbg_assert_(G3D, base != VK_NULL_HANDLE); - _dbg_assert_(G3D, light != VK_NULL_HANDLE); - _dbg_assert_(G3D, bone != VK_NULL_HANDLE); FrameData &frame = frame_[vulkan_->GetCurFrame()]; // See if we already have this descriptor set cached. @@ -406,7 +411,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView if (!frame.descPool || frame.descPoolSize < frame.descCount + 1) { VkResult res = RecreateDescriptorPool(frame, frame.descPoolSize * 2); - assert(res == VK_SUCCESS); + _dbg_assert_(res == VK_SUCCESS); } // Didn't find one in the frame descriptor set cache, let's make a new one. @@ -424,14 +429,14 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView // so let's do that. See https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkAllocateDescriptorSets.html // Fragmentation shouldn't really happen though since we wipe the pool every frame.. VkResult res = RecreateDescriptorPool(frame, frame.descPoolSize); - _assert_msg_(G3D, res == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to recreate a descriptor pool. sz=%d res=%d", (int)frame.descSets.size(), (int)res); + _assert_msg_(res == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to recreate a descriptor pool. sz=%d res=%d", (int)frame.descSets.size(), (int)res); descAlloc.descriptorPool = frame.descPool; // Need to update this pointer since we have allocated a new one. result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); - _assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to allocate after recreating a descriptor pool. res=%d", (int)result); + _assert_msg_(result == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to allocate after recreating a descriptor pool. res=%d", (int)result); } // Even in release mode, this is bad. - _assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d res=%d", (int)frame.descSets.size(), (int)result); + _assert_msg_(result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d res=%d", (int)frame.descSets.size(), (int)result); // We just don't write to the slots we don't care about, which is fine. VkWriteDescriptorSet writes[7]{}; @@ -439,6 +444,8 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView int n = 0; VkDescriptorImageInfo tex[3]{}; if (imageView) { + _dbg_assert_(sampler != VK_NULL_HANDLE); + #ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR tex[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL; #else @@ -587,10 +594,19 @@ void DrawEngineVulkan::DoFlush() { VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - // HACK: These two lines should only execute if we started on a new render pass. Can't tell from in here though... + // TODO: Needs to be behind a check for changed render pass, at an appropriate time in this function. + // Similar issues as with the lastRenderStepId_ check. Will need a bit of a rethink. lastPipeline_ = nullptr; - // Since we have a new cmdbuf, dirty our dynamic state so it gets re-set. - // gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE); + // If have a new render pass, dirty our dynamic state so it gets re-set. + // We have to do this again after the last possible place in DoFlush that can cause a renderpass switch + // like a shader blend blit or similar. But before we actually set the state! + int curRenderStepId = renderManager->GetCurrentStepId(); + if (lastRenderStepId_ != curRenderStepId) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + textureCache_->ForgetLastTexture(); + lastRenderStepId_ = curRenderStepId; + } FrameData *frame = &frame_[vulkan_->GetCurFrame()]; @@ -646,7 +662,7 @@ void DrawEngineVulkan::DoFlush() { case VertexArrayInfoVulkan::VAI_NEW: { // Haven't seen this one before. We don't actually upload the vertex data yet. - ReliableHashType dataHash = ComputeHash(); + uint64_t dataHash = ComputeHash(); vai->hash = dataHash; vai->minihash = ComputeMiniHash(); vai->status = VertexArrayInfoVulkan::VAI_HASHING; @@ -671,7 +687,7 @@ void DrawEngineVulkan::DoFlush() { if (vai->drawsUntilNextFullHash == 0) { // Let's try to skip a full hash if mini would fail. const u32 newMiniHash = ComputeMiniHash(); - ReliableHashType newHash = vai->hash; + uint64_t newHash = vai->hash; if (newMiniHash == vai->minihash) { newHash = ComputeHash(); } @@ -704,7 +720,7 @@ void DrawEngineVulkan::DoFlush() { if (!vai->vb) { // Directly push to the vertex cache. DecodeVertsToPushBuffer(vertexCache_, &vai->vbOffset, &vai->vb); - _dbg_assert_msg_(G3D, gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); + _dbg_assert_msg_(gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); vai->numVerts = indexGen.VertexCount(); vai->prim = indexGen.Prim(); vai->maxIndex = indexGen.MaxIndex(); @@ -814,7 +830,7 @@ void DrawEngineVulkan::DoFlush() { } shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, true, useHWTessellation_); // usehwtransform - _dbg_assert_msg_(G3D, vshader->UseHWTransform(), "Bad vshader"); + _dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader"); Draw::NativeObject object = framebufferManager_->UseBufferedRendering() ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object); @@ -824,6 +840,17 @@ void DrawEngineVulkan::DoFlush() { return; } BindShaderBlendTex(); // This might cause copies so important to do before BindPipeline. + + // If have a new render pass, dirty our dynamic state so it gets re-set. + // WARNING: We have to do this AFTER the last possible place in DoFlush that can cause a renderpass switch + // like a shader blend blit or similar. But before we actually set the state! + int curRenderStepId = renderManager->GetCurrentStepId(); + if (lastRenderStepId_ != curRenderStepId) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE); + lastRenderStepId_ = curRenderStepId; + } + renderManager->BindPipeline(pipeline->pipeline); if (pipeline != lastPipeline_) { if (lastPipeline_ && !(lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant())) { @@ -910,6 +937,9 @@ void DrawEngineVulkan::DoFlush() { swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); } + if (result.setSafeSize) + framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Only here, where we know whether to clear or to draw primitives, should we actually set the current framebuffer! Because that gives use the opportunity // to use a "pre-clear" render pass, for high efficiency on tilers. if (result.action == SW_DRAW_PRIMITIVES) { @@ -923,7 +953,7 @@ void DrawEngineVulkan::DoFlush() { } if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) { shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false, false); // usehwtransform - _dbg_assert_msg_(G3D, !vshader->UseHWTransform(), "Bad vshader"); + _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } @@ -935,6 +965,17 @@ void DrawEngineVulkan::DoFlush() { return; } BindShaderBlendTex(); // This might cause copies so super important to do before BindPipeline. + + // If have a new render pass, dirty our dynamic state so it gets re-set. + // WARNING: We have to do this AFTER the last possible place in DoFlush that can cause a renderpass switch + // like a shader blend blit or similar. But before we actually set the state! + int curRenderStepId = renderManager->GetCurrentStepId(); + if (lastRenderStepId_ != curRenderStepId) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE); + lastRenderStepId_ = curRenderStepId; + } + renderManager->BindPipeline(pipeline->pipeline); if (pipeline != lastPipeline_) { if (lastPipeline_ && !lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant()) { @@ -983,13 +1024,11 @@ void DrawEngineVulkan::DoFlush() { // If non-buffered though, it'll just do a plain clear. framebufferManager_->NotifyClear(gstate.isClearModeColorMask(), gstate.isClearModeAlphaMask(), gstate.isClearModeDepthMask(), result.color, result.depth); - int scissorX1 = gstate.getScissorX1(); - int scissorY1 = gstate.getScissorY1(); - int scissorX2 = gstate.getScissorX2() + 1; - int scissorY2 = gstate.getScissorY2() + 1; - framebufferManager_->SetSafeSize(scissorX2, scissorY2); - if (gstate_c.Supports(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + int scissorX1 = gstate.getScissorX1(); + int scissorY1 = gstate.getScissorY1(); + int scissorX2 = gstate.getScissorX2() + 1; + int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, result.color); } } diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index cbbaeebb5b..3f46a62186 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -31,11 +31,7 @@ // The format of the various uniform buffers may vary though - vertex shaders that don't skin // won't get any bone data, etc. -#include -#include - -#include "Common/Hashmaps.h" -#include "Common/Vulkan/VulkanMemory.h" +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/Vulkan/VulkanUtil.h" @@ -55,13 +51,6 @@ class PipelineManagerVulkan; class TextureCacheVulkan; class FramebufferManagerVulkan; -// Avoiding the full include of TextureDecoder.h. -#if (defined(_M_SSE) && defined(_M_X64)) || defined(ARM64) -typedef u64 ReliableHashType; -#else -typedef u32 ReliableHashType; -#endif - class VulkanContext; class VulkanPushBuffer; struct VulkanPipeline; @@ -91,7 +80,7 @@ public: VAI_UNRELIABLE, // never cache }; - ReliableHashType hash; + uint64_t hash; u32 minihash; // These will probably always be the same, but whatever. @@ -302,4 +291,6 @@ private: // Hardware tessellation TessellationDataTransferVulkan *tessDataTransferVulkan; + + int lastRenderStepId_ = -1; }; diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index 9ce62dcb2d..25a96b9761 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -18,16 +18,17 @@ #include #include +#include "Common/GPU/OpenGL/GLFeatures.h" + +#include "Common/Log.h" #include "Common/StringUtils.h" -#include "base/logging.h" -#include "gfx_es2/gpu_features.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "Core/System.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Common/ShaderId.h" #include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Vulkan/PipelineManagerVulkan.h" @@ -195,7 +196,8 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ } } else { if (doTextureProjection) { - // We don't use textureProj because we need better control and it's probably not much of a savings anyway. + // We don't use textureProj because we need to manually offset from the divided coordinate to do filtering here. + // On older hardware it has the advantage of higher resolution math, but such old hardware can't run Vulkan. WRITE(p, " vec2 uv = %s.xy/%s.z;\n vec2 uv_round;\n", texcoord, texcoord); } else { WRITE(p, " vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord); diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp similarity index 85% rename from GPU/Vulkan/FramebufferVulkan.cpp rename to GPU/Vulkan/FramebufferManagerVulkan.cpp index 2e34182338..399aa3cd87 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -15,20 +15,19 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include #include -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" -#include "base/display.h" -#include "math/lin/matrix4x4.h" -#include "math/dataconv.h" -#include "ext/native/thin3d/thin3d.h" +#include "Common/System/Display.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/GPU/thin3d.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanMemory.h" -#include "Common/Vulkan/VulkanImage.h" -#include "thin3d/VulkanRenderManager.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanImage.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" #include "Common/ColorConv.h" #include "Core/MemMap.h" #include "Core/Config.h" @@ -41,9 +40,9 @@ #include "GPU/GPUState.h" #include "GPU/Common/TextureDecoder.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Debugger/Stepping.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/DrawEngineVulkan.h" #include "GPU/Vulkan/TextureCacheVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" @@ -78,7 +77,7 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk vulkan_(vulkan) { presentation_->SetLanguage(GLSL_VULKAN); - DeviceRestore(vulkan, draw); + InitDeviceObjects(); // After a blit we do need to rebind for the VulkanRenderManager to know what to do. needGLESRebinds_ = true; @@ -107,8 +106,8 @@ void FramebufferManagerVulkan::InitDeviceObjects() { std::string fs_errors, vs_errors; fsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, tex_fs, &fs_errors); vsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, tex_vs, &vs_errors); - assert(fsBasicTex_ != VK_NULL_HANDLE); - assert(vsBasicTex_ != VK_NULL_HANDLE); + _assert_(fsBasicTex_ != VK_NULL_HANDLE); + _assert_(vsBasicTex_ != VK_NULL_HANDLE); VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; @@ -117,11 +116,11 @@ void FramebufferManagerVulkan::InitDeviceObjects() { samp.magFilter = VK_FILTER_NEAREST; samp.minFilter = VK_FILTER_NEAREST; VkResult res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &nearestSampler_); - assert(res == VK_SUCCESS); + _assert_(res == VK_SUCCESS); samp.magFilter = VK_FILTER_LINEAR; samp.minFilter = VK_FILTER_LINEAR; res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &linearSampler_); - assert(res == VK_SUCCESS); + _assert_(res == VK_SUCCESS); } void FramebufferManagerVulkan::DestroyDeviceObjects() { @@ -259,27 +258,14 @@ void FramebufferManagerVulkan::ReformatFramebufferFrom(VirtualFramebuffer *vfb, // to exactly reproduce in 4444 and 8888 formats. if (old == GE_FORMAT_565) { - // TODO: To match other backends, would be ideal to clear alpha only and not color. - // But probably doesn't matter that much... - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); - } -} + // We have to bind here instead of clear, since it can be that no framebuffer is bound. + // The backend can sometimes directly optimize it to a clear. + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "ReformatFramebuffer"); + // draw_->Clear(Draw::FBChannel::FB_COLOR_BIT | Draw::FBChannel::FB_STENCIL_BIT, 0, 0.0f, 0); -// Except for a missing rebind and silly scissor enables, identical copy of the same function in GPU_GLES - tricky parts are in thin3d. -void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - 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; - if (matchingDepthBuffer && matchingRenderSize && matchingSize) { - // TODO: Currently, this copies depth AND stencil, which is a problem. See #9740. - draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, src->renderWidth, src->renderHeight, 1, Draw::FB_DEPTH_BIT); - dst->last_frame_depth_updated = gpuStats.numFlips; - } else if (matchingDepthBuffer && matchingSize) { - /* - int w = std::min(src->renderWidth, dst->renderWidth); - int h = std::min(src->renderHeight, dst->renderHeight); - draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST); - */ + // Need to dirty anything that has command buffer dynamic state, in case we started a new pass above. + // Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager. + gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE); } } @@ -303,7 +289,7 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V VirtualFramebuffer copyInfo = *framebuffer; copyInfo.fbo = renderCopy; CopyFramebufferForColorTexture(©Info, framebuffer, flags); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - BindFramebufferAsColorTexture"); draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0); } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); @@ -326,8 +312,10 @@ void FramebufferManagerVulkan::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) { if (!dst->fbo || !src->fbo || !useBufferedRendering_) { // This can happen if they recently switched from non-buffered. - if (useBufferedRendering_) - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + if (useBufferedRendering_) { + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer_Fail"); + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); + } return; } @@ -388,9 +376,9 @@ void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; if (sameSize && sameDepth && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { - draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT); + draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, "BlitFramebuffer_Copy"); } else { - draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST); + draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebuffer_Blit"); } } @@ -405,17 +393,6 @@ void FramebufferManagerVulkan::DeviceLost() { DestroyAllFBOs(); DestroyDeviceObjects(); presentation_->DeviceLost(); - - if (allocator_) { - allocator_->Destroy(); - - // We have to delete on queue, so this can free its queued deletions. - vulkan_->Delete().QueueCallback([](void *ptr) { - auto allocator = static_cast(ptr); - delete allocator; - }, allocator_); - allocator_ = nullptr; - } } void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw) { @@ -423,9 +400,5 @@ void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawCo draw_ = draw; presentation_->DeviceRestore(draw); - _assert_(!allocator_); - - allocator_ = new VulkanDeviceAllocator(vulkan_, 1 * 1024 * 1024, 8 * 1024 * 1024); - InitDeviceObjects(); } diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h similarity index 92% rename from GPU/Vulkan/FramebufferVulkan.h rename to GPU/Vulkan/FramebufferManagerVulkan.h index f7da052a50..a653aeb15d 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -17,9 +17,9 @@ #pragma once -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" #include "GPU/GPUInterface.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/PresentationCommon.h" #include "GPU/Vulkan/VulkanUtil.h" @@ -54,9 +54,7 @@ public: int GetLineWidth(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; - - bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; + bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; VkImageView BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); @@ -82,7 +80,6 @@ private: TextureCacheVulkan *textureCacheVulkan_ = nullptr; ShaderManagerVulkan *shaderManagerVulkan_ = nullptr; DrawEngineVulkan *drawEngineVulkan_ = nullptr; - VulkanDeviceAllocator *allocator_ = nullptr; VulkanPushBuffer *push_; enum { diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index d111a1db77..197774e8d5 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -18,12 +18,13 @@ #include -#include "base/logging.h" -#include "base/timeutil.h" -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" -#include "Common/ChunkFile.h" +#include "Common/Log.h" +#include "Common/File/FileUtil.h" #include "Common/GraphicsContext.h" +#include "Common/Serialize/Serializer.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/Debugger/Breakpoints.h" @@ -35,15 +36,15 @@ #include "GPU/GPUState.h" #include "GPU/ge_constants.h" #include "GPU/GeDisasm.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Debugger/Debugger.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Vulkan/GPU_Vulkan.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/DrawEngineVulkan.h" #include "GPU/Vulkan/TextureCacheVulkan.h" -#include "thin3d/VulkanRenderManager.h" -#include "thin3d/VulkanQueueRunner.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/GPU/Vulkan/VulkanQueueRunner.h" #include "Core/MIPS/MIPS.h" #include "Core/HLE/sceKernelThread.h" @@ -140,7 +141,7 @@ void GPU_Vulkan::LoadCache(std::string filename) { } fclose(f); if (!result) { - WARN_LOG(G3D, "Bad Vulkan pipeline cache"); + WARN_LOG(G3D, "Incompatible Vulkan pipeline cache - rebuilding."); // Bad cache file for this GPU/Driver/etc. Delete it. File::Delete(filename); } else { @@ -223,11 +224,10 @@ void GPU_Vulkan::CheckGPUFeatures() { // Mandatory features on Vulkan, which may be checked in "centralized" code features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - features |= GPU_SUPPORTS_FBO; + features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT; features |= GPU_SUPPORTS_BLEND_MINMAX; - features |= GPU_SUPPORTS_ANY_COPY_IMAGE; + features |= GPU_SUPPORTS_COPY_IMAGE; features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; - features |= GPU_SUPPORTS_LARGE_VIEWPORTS; features |= GPU_SUPPORTS_INSTANCE_RENDERING; features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; features |= GPU_SUPPORTS_TEXTURE_FLOAT; @@ -292,8 +292,8 @@ void GPU_Vulkan::BeginHostFrame() { if (vulkan_->GetDeviceFeatures().enabled.wideLines) { drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f); } + resized_ = false; } - resized_ = false; textureCacheVulkan_->StartFrame(); @@ -332,6 +332,8 @@ void GPU_Vulkan::EndHostFrame() { drawEngine_.EndFrame(); framebufferManagerVulkan_->EndFrame(); textureCacheVulkan_->EndFrame(); + + draw_->InvalidateCachedState(); } // Needs to be called on GPU thread, not reporting thread. @@ -471,10 +473,10 @@ void GPU_Vulkan::ExecuteOp(u32 op, u32 diff) { } void GPU_Vulkan::InitDeviceObjects() { - ILOG("GPU_Vulkan::InitDeviceObjects"); + INFO_LOG(G3D, "GPU_Vulkan::InitDeviceObjects"); // Initialize framedata for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { - assert(!frameData_[i].push_); + _assert_(!frameData_[i].push_); VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024, usage); } @@ -495,7 +497,7 @@ void GPU_Vulkan::InitDeviceObjects() { } void GPU_Vulkan::DestroyDeviceObjects() { - ILOG("GPU_Vulkan::DestroyDeviceObjects"); + INFO_LOG(G3D, "GPU_Vulkan::DestroyDeviceObjects"); for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { if (frameData_[i].push_) { frameData_[i].push_->Destroy(vulkan_); @@ -550,43 +552,18 @@ void GPU_Vulkan::DeviceRestore() { } void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { + size_t offset = FormatGPUStatsCommon(buffer, bufsize); + buffer += offset; + bufsize -= offset; + if ((int)bufsize < 0) + return; const DrawEngineVulkanStats &drawStats = drawEngine_.GetStats(); char texStats[256]; textureCacheVulkan_->GetStats(texStats, sizeof(texStats)); - float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; - snprintf(buffer, bufsize - 1, - "DL processing time: %0.2f ms\n" - "Draw calls: %i, flushes %i, clears %i\n" - "Cached Draw calls: %i\n" - "Num Tracked Vertex Arrays: %i\n" - "GPU cycles executed: %d (%f per vertex)\n" - "Commands per call level: %i %i %i %i\n" - "Vertices submitted: %i\n" - "Cached, Uncached Vertices Drawn: %i, %i\n" - "FBOs active: %i\n" - "Textures active: %i, decoded: %i invalidated: %i\n" - "Readbacks: %d, uploads: %d\n" + snprintf(buffer, bufsize, "Vertex, Fragment, Pipelines loaded: %i, %i, %i\n" "Pushbuffer space used: UBO %d, Vtx %d, Idx %d\n" "%s\n", - gpuStats.msProcessingDisplayLists * 1000.0f, - gpuStats.numDrawCalls, - gpuStats.numFlushes, - gpuStats.numClears, - gpuStats.numCachedDrawCalls, - gpuStats.numTrackedVertexArrays, - gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles, - vertexAverageCycles, - gpuStats.gpuCommandsAtCallLevel[0], gpuStats.gpuCommandsAtCallLevel[1], gpuStats.gpuCommandsAtCallLevel[2], gpuStats.gpuCommandsAtCallLevel[3], - gpuStats.numVertsSubmitted, - gpuStats.numCachedVertsDrawn, - gpuStats.numUncachedVertsDrawn, - (int)framebufferManager_->NumVFBs(), - (int)textureCacheVulkan_->NumLoadedTextures(), - gpuStats.numTexturesDecoded, - gpuStats.numTextureInvalidations, - gpuStats.numReadbacks, - gpuStats.numUploads, shaderManagerVulkan_->GetNumVertexShaders(), shaderManagerVulkan_->GetNumFragmentShaders(), pipelineManager_->GetNumPipelines(), diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index a56304869b..894cc295b4 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -17,18 +17,18 @@ #pragma once -#include -#include +#include +#include #include "GPU/GPUCommon.h" #include "GPU/Vulkan/DrawEngineVulkan.h" #include "GPU/Vulkan/PipelineManagerVulkan.h" -#include "GPU/Vulkan/TextureCacheVulkan.h" #include "GPU/Vulkan/DepalettizeShaderVulkan.h" class FramebufferManagerVulkan; class ShaderManagerVulkan; class LinkedShader; +class TextureCacheVulkan; class GPU_Vulkan : public GPUCommon { public: diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index d655404c5c..2aa0546a8e 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -1,19 +1,20 @@ #include #include #include +#include -#include "profiler/profiler.h" +#include "Common/Profiler/Profiler.h" #include "Common/Log.h" #include "Common/StringUtils.h" -#include "Common/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanContext.h" #include "GPU/Vulkan/VulkanUtil.h" #include "GPU/Vulkan/PipelineManagerVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Common/DrawEngineCommon.h" -#include "ext/native/thin3d/thin3d.h" -#include "ext/native/thin3d/VulkanRenderManager.h" -#include "ext/native/thin3d/VulkanQueueRunner.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/GPU/Vulkan/VulkanQueueRunner.h" PipelineManagerVulkan::PipelineManagerVulkan(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(256) { // The pipeline cache is created on demand (or explicitly through Load). @@ -76,8 +77,8 @@ static const DeclTypeInfo VComp[] = { }; static void VertexAttribSetup(VkVertexInputAttributeDescription *attr, int fmt, int offset, PspAttributeLocation location) { - assert(fmt != DEC_NONE); - assert(fmt < ARRAY_SIZE(VComp)); + _assert_(fmt != DEC_NONE); + _assert_(fmt < ARRAY_SIZE(VComp)); attr->location = (uint32_t)location; attr->binding = 0; attr->format = VComp[fmt].type; @@ -307,7 +308,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip // Bad return value seen on Adreno in Burnout :( Try to ignore? // TODO: Log all the information we can here! } else { - _dbg_assert_msg_(G3D, false, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + _dbg_assert_msg_(false, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); } ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); // Create a placeholder to avoid creating over and over if something is broken. @@ -331,11 +332,11 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); } VulkanPipelineKey key{}; - _assert_msg_(G3D, renderPass, "Can't create a pipeline with a null renderpass"); + _assert_msg_(renderPass, "Can't create a pipeline with a null renderpass"); key.raster = rasterKey; key.renderPass = renderPass; @@ -582,6 +583,8 @@ struct StoredVulkanPipelineKey { } }; +// If you're looking for how to invalidate the cache, it's done in ShaderManagerVulkan, look for CACHE_VERSION and increment it. +// (Header of the same file this is stored in). void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 0cdb4a855a..d7d47fd0ef 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -18,7 +18,7 @@ #pragma once #include -#include "Common/Hashmaps.h" +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/ShaderId.h" diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index fab02bb056..1dff1d8ce0 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -19,16 +19,16 @@ //#define SHADERLOG #endif -#include "base/logging.h" -#include "base/stringutil.h" -#include "math/lin/matrix4x4.h" -#include "math/math_util.h" -#include "math/dataconv.h" -#include "profiler/profiler.h" -#include "thin3d/thin3d.h" -#include "util/text/utf8.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanMemory.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Math/math_util.h" +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Encoding/Utf8.h" + +#include "Common/StringUtils.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" #include "Common/Log.h" #include "Common/Common.h" #include "Core/Config.h" @@ -38,7 +38,7 @@ #include "GPU/ge_constants.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Vulkan/DrawEngineVulkan.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" #include "GPU/Vulkan/VertexShaderGeneratorVulkan.h" @@ -245,16 +245,16 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader FSID = lastFSID_; } - _dbg_assert_(G3D, FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE)); - _dbg_assert_(G3D, FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE)); - _dbg_assert_(G3D, FSID.Bit(FS_BIT_ENABLE_FOG) == VSID.Bit(VS_BIT_ENABLE_FOG)); - _dbg_assert_(G3D, FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE)); + _dbg_assert_(FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE)); + _dbg_assert_(FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE)); + _dbg_assert_(FSID.Bit(FS_BIT_ENABLE_FOG) == VSID.Bit(VS_BIT_ENABLE_FOG)); + _dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE)); // Just update uniforms if this is the same shader as last time. if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) { *vshader = lastVShader_; *fshader = lastFShader_; - _dbg_assert_msg_(G3D, (*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was cached"); + _dbg_assert_msg_((*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was cached"); // Already all set, no need to look up in shader maps. return; } @@ -284,7 +284,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader *vshader = vs; *fshader = fs; - _dbg_assert_msg_(G3D, (*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was computed"); + _dbg_assert_msg_((*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was computed"); } std::vector ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType type) { @@ -361,7 +361,7 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 17 +#define CACHE_VERSION 18 struct VulkanCacheHeader { uint32_t magic; uint32_t version; diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h index bf5404acf9..92a52594ff 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.h +++ b/GPU/Vulkan/ShaderManagerVulkan.h @@ -18,16 +18,16 @@ #pragma once #include +#include -#include "base/basictypes.h" -#include "Common/Hashmaps.h" -#include "Common/Vulkan/VulkanMemory.h" +#include "Common/Data/Collections/Hashmaps.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" #include "GPU/Common/ShaderCommon.h" #include "GPU/Common/ShaderId.h" #include "GPU/Vulkan/VertexShaderGeneratorVulkan.h" #include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" #include "GPU/Vulkan/VulkanUtil.h" -#include "math/lin/matrix4x4.h" +#include "Common/Math/lin/matrix4x4.h" #include "GPU/Common/ShaderUniforms.h" class VulkanContext; diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index dde593bdd3..1dee71861d 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -15,10 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/Vulkan/VulkanLoader.h" -#include "thin3d/VulkanRenderManager.h" +#include -#include "math/dataconv.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" + +#include "Common/Data/Convert/SmallDataConvert.h" #include "GPU/Math3D.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" @@ -28,8 +30,7 @@ #include "Core/Reporting.h" #include "GPU/Vulkan/GPU_Vulkan.h" #include "GPU/Vulkan/PipelineManagerVulkan.h" -#include "GPU/Vulkan/TextureCacheVulkan.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Vulkan/DrawEngineVulkan.h" @@ -239,7 +240,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag key.colorWriteMask = (rmask ? VK_COLOR_COMPONENT_R_BIT : 0) | (gmask ? VK_COLOR_COMPONENT_G_BIT : 0) | (bmask ? VK_COLOR_COMPONENT_B_BIT : 0) | (amask ? VK_COLOR_COMPONENT_A_BIT : 0); // Workaround proposed in #10421, for bug where the color write mask is not applied correctly on Adreno. - if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_QUALCOMM) { + if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && g_Config.bVendorBugChecksEnabled && draw_->GetBugs().Has(Draw::Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST)) { key.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; if (!key.blendEnable) { key.blendEnable = true; @@ -255,14 +256,14 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag } if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) { + bool wantCull = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); + key.cullMode = wantCull ? (gstate.getCullMode() ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT) : VK_CULL_MODE_NONE; + if (gstate.isModeClear() || gstate.isModeThrough()) { - key.cullMode = VK_CULL_MODE_NONE; // TODO: Might happen in clear mode if not through... key.depthClampEnable = false; } else { // Set cull - bool wantCull = prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); - key.cullMode = wantCull ? (gstate.getCullMode() ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT) : VK_CULL_MODE_NONE; if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... diff --git a/GPU/Vulkan/StateMappingVulkan.h b/GPU/Vulkan/StateMappingVulkan.h index 9306f5051d..7719dcf857 100644 --- a/GPU/Vulkan/StateMappingVulkan.h +++ b/GPU/Vulkan/StateMappingVulkan.h @@ -1,6 +1,6 @@ #pragma once -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" #include diff --git a/GPU/Vulkan/StencilBufferVulkan.cpp b/GPU/Vulkan/StencilBufferVulkan.cpp index a99480d497..faaba54836 100644 --- a/GPU/Vulkan/StencilBufferVulkan.cpp +++ b/GPU/Vulkan/StencilBufferVulkan.cpp @@ -15,13 +15,13 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" -#include "ext/native/thin3d/thin3d.h" -#include "ext/native/thin3d/VulkanRenderManager.h" +#include "Common/Log.h" #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Vulkan/TextureCacheVulkan.h" @@ -29,6 +29,8 @@ // This shader references gl_FragDepth to prevent early fragment tests. // They shouldn't happen since it uses discard, but Adreno detects that incorrectly - see #10634. +// This only affected the 5xx generation and was fixed sometime before driver version 512.384.0.0 (whatever that means). +// Strangely, this same code appears to fix a different issue on Exynos instead so now it's enabled on Mali as well. static const char *stencil_fs_adreno = R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable @@ -96,7 +98,7 @@ void main() { // In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without // messing about with bitplane textures and the like. Or actually, maybe not... Let's start with // the traditional approach. -bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skipZero) { +bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; @@ -138,7 +140,9 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip values = 256; break; case GE_FORMAT_INVALID: - // Impossible. + case GE_FORMAT_DEPTH16: + // Inconceivable. + _assert_(false); break; } @@ -146,7 +150,8 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip if (!stencilVs_) { const char *stencil_fs_source = stencil_fs; // See comment above the stencil_fs_adreno definition. - if (vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_QUALCOMM) + u32 vendorID = vulkan_->GetPhysicalDeviceProperties().properties.vendorID; + if (g_Config.bVendorBugChecksEnabled && (draw_->GetBugs().Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL) || vendorID == VULKAN_VENDOR_ARM)) stencil_fs_source = stencil_fs_adreno; stencilVs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, stencil_vs, &error); @@ -168,7 +173,8 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip return false; if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + // Typically, STENCIL_IS_ZERO means it's already bound, so this bind will be optimized away. + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }, "Stencil"); } else { // something is wrong... } @@ -177,7 +183,6 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip renderManager->BindPipeline(pipeline); renderManager->SetViewport({ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }); renderManager->SetScissor({ { 0, 0, },{ (uint32_t)w, (uint32_t)h } }); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE); draw_->BindTextures(0, 1, &tex); VkImageView drawPixelsImageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); @@ -218,6 +223,7 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip } tex->Release(); - RebindFramebuffer(); + RebindFramebuffer("RebindFramebuffer - NotifyStencilUpload"); + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); return true; } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 0daba04381..54210f8a60 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -19,29 +19,32 @@ #include #include "ext/xxhash.h" -#include "i18n/i18n.h" -#include "math/math_util.h" -#include "profiler/profiler.h" -#include "thin3d/thin3d.h" -#include "thin3d/VulkanRenderManager.h" +#include "Common/File/VFS/VFS.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Math/math_util.h" +#include "Common/Profiler/Profiler.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" #include "Common/ColorConv.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Host.h" #include "Core/MemMap.h" #include "Core/Reporting.h" #include "Core/System.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanImage.h" -#include "Common/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanImage.h" +#include "Common/GPU/Vulkan/VulkanMemory.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" +#include "GPU/Common/PostShader.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Common/TextureDecoder.h" #include "GPU/Vulkan/TextureCacheVulkan.h" -#include "GPU/Vulkan/FramebufferVulkan.h" +#include "GPU/Vulkan/FramebufferManagerVulkan.h" #include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" #include "GPU/Vulkan/DepalettizeShaderVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" @@ -62,291 +65,6 @@ static const VkComponentMapping VULKAN_1555_SWIZZLE = { VK_COMPONENT_SWIZZLE_B, static const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; static const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; -// 4xBRZ shader - Copyright (C) 2014-2016 DeSmuME team (GPL2+) -// Hyllian's xBR-vertex code and texel mapping -// Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com -// TODO: Handles alpha badly for PSP. -const char *shader4xbrz = R"( -vec4 premultiply_alpha(vec4 c) { float a = clamp(c.a, 0.0, 1.0); return vec4(c.rgb * a, a); } -vec4 postdivide_alpha(vec4 c) { return c.a < 0.001? vec4(0.0,0.0,0.0,0.0) : vec4(c.rgb / c.a, c.a); } - -#define BLEND_ALPHA 1 -#define BLEND_NONE 0 -#define BLEND_NORMAL 1 -#define BLEND_DOMINANT 2 -#define LUMINANCE_WEIGHT 1.0 -#define EQUAL_COLOR_TOLERANCE 30.0/255.0 -#define STEEP_DIRECTION_THRESHOLD 2.2 -#define DOMINANT_DIRECTION_THRESHOLD 3.6 - -float reduce(vec4 color) { - return dot(color.rgb, vec3(65536.0, 256.0, 1.0)); -} - -float DistYCbCr(vec4 pixA, vec4 pixB) { - const vec3 w = vec3(0.2627, 0.6780, 0.0593); - const float scaleB = 0.5 / (1.0 - w.b); - const float scaleR = 0.5 / (1.0 - w.r); - vec4 diff = pixA - pixB; - float Y = dot(diff.rgb, w); - float Cb = scaleB * (diff.b - Y); - float Cr = scaleR * (diff.r - Y); - - return sqrt( ((LUMINANCE_WEIGHT * Y) * (LUMINANCE_WEIGHT * Y)) + (Cb * Cb) + (Cr * Cr) + (diff.a * diff.a)); -} - -bool IsPixEqual(const vec4 pixA, const vec4 pixB) { - return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE); -} - -bool IsBlendingNeeded(const ivec4 blend) { - ivec4 diff = blend - ivec4(BLEND_NONE); - return diff.x != 0 || diff.y != 0 || diff.z != 0 || diff.w != 0; -} - -vec4 applyScalingf(uvec2 origxy, uvec2 xy) { - float dx = 1.0 / params.width; - float dy = 1.0 / params.height; - - // A1 B1 C1 - // A0 A B C C4 - // D0 D E F F4 - // G0 G H I I4 - // G5 H5 I5 - - uvec4 t1 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y - 2); // A1 B1 C1 - uvec4 t2 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y - 1); // A B C - uvec4 t3 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y + 0); // D E F - uvec4 t4 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y + 1); // G H I - uvec4 t5 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y + 2); // G5 H5 I5 - uvec4 t6 = uvec4(origxy.x - 2, origxy.y - 1, origxy.y, origxy.y + 1); // A0 D0 G0 - uvec4 t7 = uvec4(origxy.x + 2, origxy.y - 1, origxy.y, origxy.y + 1); // C4 F4 I4 - - vec2 f = fract(vec2(float(xy.x) / float(params.scale), float(xy.y) / float(params.scale))); - - //--------------------------------------- - // Input Pixel Mapping: |21|22|23| - // 19|06|07|08|09 - // 18|05|00|01|10 - // 17|04|03|02|11 - // |15|14|13| - - vec4 src[25]; - - src[21] = premultiply_alpha(readColorf(t1.xw)); - src[22] = premultiply_alpha(readColorf(t1.yw)); - src[23] = premultiply_alpha(readColorf(t1.zw)); - src[ 6] = premultiply_alpha(readColorf(t2.xw)); - src[ 7] = premultiply_alpha(readColorf(t2.yw)); - src[ 8] = premultiply_alpha(readColorf(t2.zw)); - src[ 5] = premultiply_alpha(readColorf(t3.xw)); - src[ 0] = premultiply_alpha(readColorf(t3.yw)); - src[ 1] = premultiply_alpha(readColorf(t3.zw)); - src[ 4] = premultiply_alpha(readColorf(t4.xw)); - src[ 3] = premultiply_alpha(readColorf(t4.yw)); - src[ 2] = premultiply_alpha(readColorf(t4.zw)); - src[15] = premultiply_alpha(readColorf(t5.xw)); - src[14] = premultiply_alpha(readColorf(t5.yw)); - src[13] = premultiply_alpha(readColorf(t5.zw)); - src[19] = premultiply_alpha(readColorf(t6.xy)); - src[18] = premultiply_alpha(readColorf(t6.xz)); - src[17] = premultiply_alpha(readColorf(t6.xw)); - src[ 9] = premultiply_alpha(readColorf(t7.xy)); - src[10] = premultiply_alpha(readColorf(t7.xz)); - src[11] = premultiply_alpha(readColorf(t7.xw)); - - float v[9]; - v[0] = reduce(src[0]); - v[1] = reduce(src[1]); - v[2] = reduce(src[2]); - v[3] = reduce(src[3]); - v[4] = reduce(src[4]); - v[5] = reduce(src[5]); - v[6] = reduce(src[6]); - v[7] = reduce(src[7]); - v[8] = reduce(src[8]); - - ivec4 blendResult = ivec4(BLEND_NONE); - - // Preprocess corners - // Pixel Tap Mapping: --|--|--|--|-- - // --|--|07|08|-- - // --|05|00|01|10 - // --|04|03|02|11 - // --|--|14|13|-- - // Corner (1, 1) - if ( ((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) == false) { - float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1])); - float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2])); - bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02; - blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; - } - - // Pixel Tap Mapping: --|--|--|--|-- - // --|06|07|--|-- - // 18|05|00|01|-- - // 17|04|03|02|-- - // --|15|14|--|-- - // Corner (0, 1) - if ( ((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) == false) { - float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0])); - float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3])); - bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00; - blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; - } - - // Pixel Tap Mapping: --|--|22|23|-- - // --|06|07|08|09 - // --|05|00|01|10 - // --|--|03|02|-- - // --|--|--|--|-- - // Corner (1, 0) - if ( ((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) == false) { - float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8])); - float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1])); - bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08; - blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; - } - - // Pixel Tap Mapping: --|21|22|--|-- - // 19|06|07|08|-- - // 18|05|00|01|-- - // --|04|03|--|-- - // --|--|--|--|-- - // Corner (0, 0) - if ( ((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) == false) { - float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7])); - float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0])); - bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00; - blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; - } - - vec4 dst[16]; - dst[ 0] = src[0]; - dst[ 1] = src[0]; - dst[ 2] = src[0]; - dst[ 3] = src[0]; - dst[ 4] = src[0]; - dst[ 5] = src[0]; - dst[ 6] = src[0]; - dst[ 7] = src[0]; - dst[ 8] = src[0]; - dst[ 9] = src[0]; - dst[10] = src[0]; - dst[11] = src[0]; - dst[12] = src[0]; - dst[13] = src[0]; - dst[14] = src[0]; - dst[15] = src[0]; - - // Scale pixel - if (IsBlendingNeeded(blendResult) == true) { - float dist_01_04 = DistYCbCr(src[1], src[4]); - float dist_03_08 = DistYCbCr(src[3], src[8]); - bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]); - bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]); - bool needBlend = (blendResult[2] != BLEND_NONE); - bool doLineBlend = ( blendResult[2] >= BLEND_DOMINANT || - ((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) || - (blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) || - (IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[0], src[2]) == false) ) == false ); - - vec4 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3]; - dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); - dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); - dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); - dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); - dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); - dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); - - dist_01_04 = DistYCbCr(src[7], src[2]); - dist_03_08 = DistYCbCr(src[1], src[6]); - haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]); - haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]); - needBlend = (blendResult[1] != BLEND_NONE); - doLineBlend = ( blendResult[1] >= BLEND_DOMINANT || - !((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) || - (blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) || - (IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) ); - - blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1]; - dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); - dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); - dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); - dst[ 8] = mix(dst[ 8], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[ 9] = mix(dst[ 9], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); - dst[10] = mix(dst[10], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); - dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); - - dist_01_04 = DistYCbCr(src[5], src[8]); - dist_03_08 = DistYCbCr(src[7], src[4]); - haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]); - haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]); - needBlend = (blendResult[0] != BLEND_NONE); - doLineBlend = ( blendResult[0] >= BLEND_DOMINANT || - !((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) || - (blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) || - (IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) ); - - blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7]; - dst[ 0] = mix(dst[ 0], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); - dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); - dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); - dst[ 5] = mix(dst[ 5], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[ 6] = mix(dst[ 6], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); - dst[ 7] = mix(dst[ 7], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); - dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); - - dist_01_04 = DistYCbCr(src[3], src[6]); - dist_03_08 = DistYCbCr(src[5], src[2]); - haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]); - haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]); - needBlend = (blendResult[3] != BLEND_NONE); - doLineBlend = ( blendResult[3] >= BLEND_DOMINANT || - !((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) || - (blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) || - (IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) ); - - blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5]; - dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); - dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); - dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); - dst[14] = mix(dst[14], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[15] = mix(dst[15], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); - dst[ 4] = mix(dst[ 4], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); - dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); - dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); - } - - // select output pixel - vec4 res = mix(mix(mix(mix(dst[ 6], dst[ 7], step(0.25, f.x)), - mix(dst[ 8], dst[ 9], step(0.75, f.x)), - step(0.50, f.x)), - mix(mix(dst[ 5], dst[ 0], step(0.25, f.x)), - mix(dst[ 1], dst[10], step(0.75, f.x)), - step(0.50, f.x)), - step(0.25, f.y)), - mix(mix(mix(dst[ 4], dst[ 3], step(0.25, f.x)), - mix(dst[ 2], dst[11], step(0.75, f.x)), - step(0.50, f.x)), - mix(mix(dst[15], dst[14], step(0.25, f.x)), - mix(dst[13], dst[12], step(0.75, f.x)), - step(0.50, f.x)), - step(0.75, f.y)), - step(0.50, f.y)); - - return postdivide_alpha(res); -} - -uint applyScalingu(uvec2 origxy, uvec2 xy) { - return packUnorm4x8(applyScalingf(origxy, xy)); -} -)"; - const char *copyShader = R"( #version 450 #extension GL_ARB_separate_shader_objects : enable @@ -394,7 +112,7 @@ uint readColoru(uvec2 p) { uint a = ((data >> 15) & 0x01) == 0 ? 0x00 : 0xFF; return (a << 24) | (b << 16) | (g << 8) | r; } else if (params.fmt == 4) { - uint r = (data & 0x0F) | ((data << 4) & 0x0F); + uint r = (data & 0x0F) | ((data << 4) & 0xF0); uint g = (data & 0xF0) | ((data >> 4) & 0x0F); uint b = ((data >> 8) & 0x0F) | ((data >> 4) & 0xF0); uint a = ((data >> 12) & 0x0F) | ((data >> 8) & 0xF0); @@ -471,7 +189,7 @@ uint readColoru(uvec2 p) { uint a = ((data >> 15) & 0x01) == 0 ? 0x00 : 0xFF; return (a << 24) | (b << 16) | (g << 8) | r; } else if (params.fmt == 4) { - uint r = (data & 0x0F) | ((data << 4) & 0x0F); + uint r = (data & 0x0F) | ((data << 4) & 0xF0); uint g = (data & 0xF0) | ((data >> 4) & 0x0F); uint b = ((data >> 8) & 0x0F) | ((data >> 4) & 0xF0); uint a = ((data >> 12) & 0x0F) | ((data >> 8) & 0xF0); @@ -537,7 +255,7 @@ VkSampler SamplerCache::GetOrCreateSampler(const SamplerCacheKey &key) { samp.mipLodBias = (float)(int32_t)key.lodBias * (1.0f / 256.0f); VkResult res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &sampler); - assert(res == VK_SUCCESS); + _assert_(res == VK_SUCCESS); cache_.Insert(key, sampler); return sampler; } @@ -634,7 +352,7 @@ void TextureCacheVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext vulkan_ = vulkan; draw_ = draw; - assert(!allocator_); + _assert_(!allocator_); allocator_ = new VulkanDeviceAllocator(vulkan_, TEXCACHE_MIN_SLAB_SIZE, TEXCACHE_MAX_SLAB_SIZE); samplerCache_.DeviceRestore(vulkan); @@ -646,24 +364,60 @@ void TextureCacheVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext samp.magFilter = VK_FILTER_NEAREST; samp.minFilter = VK_FILTER_NEAREST; samp.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &samplerNearest_); + VkResult res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &samplerNearest_); + _assert_(res == VK_SUCCESS); - std::string error; - std::string fullUploadShader = StringFromFormat(uploadShader, shader4xbrz); - std::string fullCopyShader = StringFromFormat(copyShader, shader4xbrz); - - if (g_Config.bTexHardwareScaling) { - uploadCS_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_COMPUTE_BIT, fullUploadShader.c_str(), &error); - _dbg_assert_msg_(G3D, uploadCS_ != VK_NULL_HANDLE, "failed to compile upload shader"); - copyCS_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_COMPUTE_BIT, fullCopyShader.c_str(), &error); - _dbg_assert_msg_(G3D, copyCS_!= VK_NULL_HANDLE, "failed to compile copy shader"); - } + CompileScalingShader(); computeShaderManager_.DeviceRestore(vulkan); } +void TextureCacheVulkan::NotifyConfigChanged() { + TextureCacheCommon::NotifyConfigChanged(); + CompileScalingShader(); +} + +static std::string ReadShaderSrc(const std::string &filename) { + size_t sz = 0; + char *data = (char *)VFSReadFile(filename.c_str(), &sz); + if (!data) + return ""; + + std::string src(data, sz); + free(data); + return src; +} + +void TextureCacheVulkan::CompileScalingShader() { + if (!g_Config.bTexHardwareScaling || g_Config.sTextureShaderName != textureShader_) { + if (uploadCS_ != VK_NULL_HANDLE) + vulkan_->Delete().QueueDeleteShaderModule(uploadCS_); + if (copyCS_ != VK_NULL_HANDLE) + vulkan_->Delete().QueueDeleteShaderModule(copyCS_); + textureShader_.clear(); + } + if (!g_Config.bTexHardwareScaling) + return; + + ReloadAllPostShaderInfo(); + const TextureShaderInfo *shaderInfo = GetTextureShaderInfo(g_Config.sTextureShaderName); + if (!shaderInfo || shaderInfo->computeShaderFile.empty()) + return; + + std::string shaderSource = ReadShaderSrc(shaderInfo->computeShaderFile); + std::string fullUploadShader = StringFromFormat(uploadShader, shaderSource.c_str()); + std::string fullCopyShader = StringFromFormat(copyShader, shaderSource.c_str()); + + std::string error; + uploadCS_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_COMPUTE_BIT, fullUploadShader.c_str(), &error); + _dbg_assert_msg_(uploadCS_ != VK_NULL_HANDLE, "failed to compile upload shader"); + copyCS_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_COMPUTE_BIT, fullCopyShader.c_str(), &error); + _dbg_assert_msg_(copyCS_ != VK_NULL_HANDLE, "failed to compile copy shader"); + + textureShader_ = g_Config.sTextureShaderName; +} + void TextureCacheVulkan::ReleaseTexture(TexCacheEntry *entry, bool delete_them) { - DEBUG_LOG(G3D, "Deleting texture %p", entry->vkTex); delete entry->vkTex; entry->vkTex = nullptr; } @@ -687,31 +441,6 @@ static const VkFilter MagFiltVK[2] = { VK_FILTER_LINEAR }; -void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key) { - int minFilt; - int magFilt; - bool sClamp; - bool tClamp; - float lodBias; - GETexLevelMode mode; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, mode); - - key.minFilt = minFilt & 1; - key.mipFilt = 0; - key.magFilt = magFilt & 1; - key.sClamp = sClamp; - key.tClamp = tClamp; - - // Often the framebuffer will not match the texture size. We'll wrap/clamp in the shader in that case. - // This happens whether we have OES_texture_npot or not. - int w = gstate.getTextureWidth(0); - int h = gstate.getTextureHeight(0); - if (w != bufferWidth || h != bufferHeight) { - key.sClamp = true; - key.tClamp = true; - } -} - void TextureCacheVulkan::StartFrame() { InvalidateLastTexture(); depalShaderCache_->Decimate(); @@ -740,7 +469,7 @@ void TextureCacheVulkan::EndFrame() { computeShaderManager_.EndFrame(); if (texelsScaledThisFrame_) { - // INFO_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); + VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); } } @@ -755,7 +484,10 @@ void TextureCacheVulkan::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutB // Adding clutBaseBytes may just be mitigating this for some usage patterns. const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); - clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + if (replacer_.Enabled()) + clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + else + clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF; clutBuf_ = clutBufRaw_; // Special optimization: fonts typically draw clut4 with just alpha values in a single color. @@ -778,17 +510,14 @@ void TextureCacheVulkan::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutB } void TextureCacheVulkan::BindTexture(TexCacheEntry *entry) { - if (!entry || !entry->vkTex) { - imageView_ = VK_NULL_HANDLE; - curSampler_ = VK_NULL_HANDLE; - return; - } + _assert_(entry); + _assert_(entry->vkTex); entry->vkTex->Touch(); imageView_ = entry->vkTex->GetImageView(); - SamplerCacheKey key{}; - UpdateSamplingParams(*entry, key); - curSampler_ = samplerCache_.GetOrCreateSampler(key); + int maxLevel = (entry->status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry->maxLevel; + SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry->addr); + curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey); drawEngine_->SetDepalTexture(VK_NULL_HANDLE); gstate_c.SetUseShaderDepal(false); } @@ -799,17 +528,19 @@ void TextureCacheVulkan::Unbind() { InvalidateLastTexture(); } -void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { - SamplerCacheKey samplerKey{}; - SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight, samplerKey); +void TextureCacheVulkan::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) { + SamplerCacheKey samplerKey = GetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); DepalShaderVulkan *depalShader = nullptr; uint32_t clutMode = gstate.clutformat & 0xFFFFFF; - bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer; bool expand32 = !gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS); + bool depth = channel == NOTIFY_FB_DEPTH; + bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && !depth; - if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { + bool need_depalettize = IsClutFormat(texFormat); + + if (need_depalettize && !g_Config.bDisableSlowFramebufEffects) { if (useShaderDepal) { depalShaderCache_->SetPushBuffer(drawEngine_->GetPushBufferForTextureData()); const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); @@ -828,11 +559,10 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr TexCacheEntry::TexStatus alphaStatus = CheckAlpha(clutBuf_, getClutDestFormatVulkan(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey); - InvalidateLastTexture(entry); imageView_ = framebufferManagerVulkan_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); return; } else { - depalShader = depalShaderCache_->GetDepalettizeShader(clutMode, framebuffer->drawnFormat); + depalShader = depalShaderCache_->GetDepalettizeShader(clutMode, depth ? GE_FORMAT_DEPTH16 : framebuffer->drawnFormat); drawEngine_->SetDepalTexture(VK_NULL_HANDLE); gstate_c.SetUseShaderDepal(false); } @@ -843,7 +573,7 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_, expand32); Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(TempFBO::DEPAL, framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888); - draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); Vulkan2D::Vertex verts[4] = { { -1, -1, 0.0f, 0, 0 }, @@ -900,12 +630,24 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr VkBuffer pushed; uint32_t offset = push_->PushAligned(verts, sizeof(verts), 4, &pushed); - draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, 0); VkImageView fbo = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(fbo, samplerNearest_, clutTexture->GetImageView(), samplerNearest_); VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager->BindPipeline(depalShader->pipeline); + + if (depth) { + DepthScaleFactors scaleFactors = GetDepthScaleFactors(); + struct DepthPushConstants { + float z_scale; + float z_offset; + }; + DepthPushConstants push; + push.z_scale = scaleFactors.scale; + push.z_offset = scaleFactors.offset; + renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(DepthPushConstants), &push); + } renderManager->SetScissor(VkRect2D{ {0, 0}, { framebuffer->renderWidth, framebuffer->renderHeight} }); renderManager->SetViewport(VkViewport{ 0.f, 0.f, (float)framebuffer->renderWidth, (float)framebuffer->renderHeight, 0.f, 1.f }); renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, pushed, offset, 4); @@ -917,7 +659,7 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr TexCacheEntry::TexStatus alphaStatus = CheckAlpha(clutBuf_, getClutDestFormatVulkan(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); - framebufferManager_->RebindFramebuffer(); + framebufferManager_->RebindFramebuffer("RebindFramebuffer - ApplyTextureFramebuffer"); draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); @@ -926,17 +668,14 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr // Since we may have switched render targets, we need to re-set depth/stencil etc states. gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); } else { - entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; - - framebufferManager_->RebindFramebuffer(); // TODO: This line should usually not be needed. imageView_ = framebufferManagerVulkan_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); drawEngine_->SetDepalTexture(VK_NULL_HANDLE); gstate_c.SetUseShaderDepal(false); gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650); } + curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey); - InvalidateLastTexture(entry); } ReplacedTextureFormat FromVulkanFormat(VkFormat fmt) { @@ -960,15 +699,9 @@ VkFormat ToVulkanFormat(ReplacedTextureFormat fmt) { void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK; - VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); // For the estimate, we assume cluts always point to 8888 for simplicity. cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); - if (entry->framebuffer) { - // Nothing else to do here. - return; - } - if ((entry->bufw == 0 || (gstate.texbufwidth[0] & 0xf800) != 0) && entry->addr >= PSP_GetKernelMemoryEnd()) { ERROR_LOG_REPORT(G3D, "Texture with unexpected bufw (full=%d)", gstate.texbufwidth[0] & 0xffff); // Proceeding here can cause a crash. @@ -977,7 +710,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { // Adjust maxLevel to actually present levels.. bool badMipSizes = false; + + // maxLevel here is the max level to upload. Not the count. int maxLevel = entry->maxLevel; + for (int i = 0; i <= maxLevel; i++) { // If encountering levels pointing to nothing, adjust max level. u32 levelTexaddr = gstate.getTextureAddress(i); @@ -1010,6 +746,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { maxLevel = 0; } + // We generate missing mipmaps from maxLevel+1 up to this level. maxLevel can get overwritten below + // such as when using replacement textures - but let's keep the same amount of levels. + int maxLevelToGenerate = maxLevel; + // If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient. VkFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat()); @@ -1035,17 +775,19 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } } + bool hardwareScaling = g_Config.bTexHardwareScaling && (uploadCS_ != VK_NULL_HANDLE || copyCS_ != VK_NULL_HANDLE); + // Don't scale the PPGe texture. if (entry->addr > 0x05000000 && entry->addr < PSP_GetKernelMemoryEnd()) scaleFactor = 1; - if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) != 0 && scaleFactor != 1 && !g_Config.bTexHardwareScaling) { + if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) != 0 && scaleFactor != 1 && !hardwareScaling) { // Remember for later that we /wanted/ to scale this texture. entry->status |= TexCacheEntry::STATUS_TO_SCALE; scaleFactor = 1; } if (scaleFactor != 1) { - if (!g_Config.bUnlockCachedScaling && texelsScaledThisFrame_ >= TEXCACHE_MAX_TEXELS_SCALED && !g_Config.bTexHardwareScaling) { + if (!g_Config.bUnlockCachedScaling && texelsScaledThisFrame_ >= TEXCACHE_MAX_TEXELS_SCALED && !hardwareScaling) { entry->status |= TexCacheEntry::STATUS_TO_SCALE; scaleFactor = 1; } else { @@ -1067,6 +809,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { bool computeUpload = false; bool computeCopy = false; + VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); { delete entry->vkTex; @@ -1093,11 +836,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } VkImageLayout imageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - // If we want to use the GE debugger, we should add VK_IMAGE_USAGE_TRANSFER_SRC_BIT too... + VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; // Compute experiment - if (actualFmt == VULKAN_8888_FORMAT && scaleFactor > 1 && g_Config.bTexHardwareScaling) { + if (actualFmt == VULKAN_8888_FORMAT && scaleFactor > 1 && hardwareScaling) { // Enable the experiment you want. if (uploadCS_ != VK_NULL_HANDLE) computeUpload = true; @@ -1111,10 +853,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } char texName[128]{}; - snprintf(texName, sizeof(texName), "Texture%08x", entry->addr); + snprintf(texName, sizeof(texName), "texture_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format)); image->SetTag(texName); - bool allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, imageLayout, usage, mapping); + bool allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevelToGenerate + 1, actualFmt, imageLayout, usage, mapping); if (!allocSuccess && !lowMemoryMode_) { WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode"); lowMemoryMode_ = true; @@ -1133,7 +875,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { scaleFactor = 1; actualFmt = dstFmt; - allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); + allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevelToGenerate + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); } if (!allocSuccess) { @@ -1142,7 +884,6 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { entry->vkTex = nullptr; } } - lastBoundTexture = entry->vkTex; ReplacedTextureDecodeInfo replacedInfo; if (replacer_.Enabled() && !replaced.Valid()) { @@ -1257,6 +998,11 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } } + // Generate any additional mipmap levels. + for (int level = maxLevel + 1; level <= maxLevelToGenerate; level++) { + entry->vkTex->GenerateMip(cmdInit, level); + } + if (maxLevel == 0) { entry->status |= TexCacheEntry::STATUS_BAD_MIPS; } else { @@ -1267,8 +1013,6 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } entry->vkTex->EndCreate(cmdInit, false, computeUpload ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } - - gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL); } VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { @@ -1363,7 +1107,7 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt dstFmt = (VkFormat)fmt; // We always end up at 8888. Other parts assume this. - assert(dstFmt == VULKAN_8888_FORMAT); + _assert_(dstFmt == VULKAN_8888_FORMAT); bpp = sizeof(u32); decPitch = w * bpp; @@ -1381,27 +1125,27 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt } bool TextureCacheVulkan::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) { - SetTexture(false); - if (!nextTexture_) - return false; + SetTexture(); + if (!nextTexture_) { + if (nextFramebufferTexture_) { + VirtualFramebuffer *vfb = nextFramebufferTexture_; + buffer.Allocate(vfb->bufferWidth, vfb->bufferHeight, GPU_DBG_FORMAT_8888, false); + bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->bufferWidth, vfb->bufferHeight, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), vfb->bufferWidth, "GetCurrentTextureDebug"); + // Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf. + // So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); + // We may have blitted to a temp FBO. + framebufferManager_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); + return retval; + } else { + return false; + } + } // Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer. TexCacheEntry *entry = nextTexture_; ApplyTexture(); - // TODO: Centralize? - if (entry->framebuffer) { - VirtualFramebuffer *vfb = entry->framebuffer; - buffer.Allocate(vfb->bufferWidth, vfb->bufferHeight, GPU_DBG_FORMAT_8888, false); - bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->bufferWidth, vfb->bufferHeight, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), vfb->bufferWidth); - // Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf. - // So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); - // We may have blitted to a temp FBO. - framebufferManager_->RebindFramebuffer(); - return retval; - } - if (!entry->vkTex) return false; VulkanTexture *texture = entry->vkTex; @@ -1433,12 +1177,12 @@ bool TextureCacheVulkan::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int leve int h = texture->GetHeight(); buffer.Allocate(w, h, bufferFormat); - renderManager->CopyImageToMemorySync(texture->GetImage(), level, 0, 0, w, h, drawFormat, (uint8_t *)buffer.GetData(), w); + renderManager->CopyImageToMemorySync(texture->GetImage(), level, 0, 0, w, h, drawFormat, (uint8_t *)buffer.GetData(), w, "GetCurrentTextureDebug"); // Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf. // So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends. gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE); - framebufferManager_->RebindFramebuffer(); + framebufferManager_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); return true; } diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index 3635d5299c..a61ba47d20 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -19,10 +19,10 @@ #include -#include "Common/Hashmaps.h" +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" -#include "Common/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanContext.h" #include "GPU/Vulkan/TextureScalerVulkan.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Vulkan/VulkanUtil.h" @@ -83,22 +83,15 @@ public: push_ = push; } - void ForgetLastTexture() override { - lastBoundTexture = nullptr; - gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); - } + void ForgetLastTexture() override {} + void InvalidateLastTexture() override {} - void InvalidateLastTexture(TexCacheEntry *entry = nullptr) override { - if (!entry || entry->vkTex == lastBoundTexture) { - lastBoundTexture = nullptr; - } - } + void NotifyConfigChanged() override; void GetVulkanHandles(VkImageView &imageView, VkSampler &sampler) { imageView = imageView_; sampler = curSampler_; } - void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key); bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override; @@ -120,9 +113,11 @@ private: TexCacheEntry::TexStatus CheckAlpha(const u32 *pixelData, VkFormat dstFmt, int stride, int w, int h); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; - void ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) override; + void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) override; void BuildTexture(TexCacheEntry *const entry) override; + void CompileScalingShader(); + VulkanContext *vulkan_ = nullptr; VulkanDeviceAllocator *allocator_ = nullptr; VulkanPushBuffer *push_ = nullptr; @@ -133,8 +128,6 @@ private: TextureScalerVulkan scaler; - VulkanTexture *lastBoundTexture = nullptr; - int decimationCounter_ = 0; int texelsScaledThisFrame_ = 0; int timesInvalidatedAllThisFrame_ = 0; @@ -145,6 +138,7 @@ private: DrawEngineVulkan *drawEngine_; Vulkan2D *vulkan2D_; + std::string textureShader_; VkShaderModule uploadCS_ = VK_NULL_HANDLE; VkShaderModule copyCS_ = VK_NULL_HANDLE; diff --git a/GPU/Vulkan/TextureScalerVulkan.cpp b/GPU/Vulkan/TextureScalerVulkan.cpp index 27f43bcdaf..66720c0f36 100644 --- a/GPU/Vulkan/TextureScalerVulkan.cpp +++ b/GPU/Vulkan/TextureScalerVulkan.cpp @@ -15,17 +15,13 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#if _MSC_VER == 1700 -// Has to be included before TextureScaler.h, else we get those std::bind errors in VS2012.. -#include "../native/base/basictypes.h" -#endif - #include -#include "Common/Vulkan/VulkanContext.h" +#include "Common/Common.h" +#include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/ColorConv.h" #include "Common/Log.h" -#include "Common/ThreadPools.h" +#include "Core/ThreadPools.h" #include "GPU/Common/TextureScalerCommon.h" #include "GPU/Vulkan/TextureScalerVulkan.h" diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index b63bac2c1d..36574f24ae 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -19,14 +19,14 @@ #include #include -#include "gfx_es2/gpu_features.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #if defined(_WIN32) && defined(_DEBUG) #include "Common/CommonWindows.h" #endif -#include "base/stringutil.h" -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/StringUtils.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" #include "Core/Config.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index 0e653be2b1..bcf6f655f9 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -15,10 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/basictypes.h" -#include "base/stringutil.h" #include "Common/Log.h" -#include "Common/Vulkan/VulkanContext.h" +#include "Common/StringUtils.h" +#include "Common/GPU/Vulkan/VulkanContext.h" #include "GPU/Vulkan/VulkanUtil.h" Vulkan2D::Vulkan2D(VulkanContext *vulkan) : vulkan_(vulkan) { @@ -65,7 +64,7 @@ void Vulkan2D::DestroyDeviceObjects() { void Vulkan2D::InitDeviceObjects() { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); VkDescriptorSetLayoutBinding bindings[2] = {}; // Texture. @@ -85,7 +84,7 @@ void Vulkan2D::InitDeviceObjects() { dsl.bindingCount = 2; dsl.pBindings = bindings; res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); VkDescriptorPoolSize dpTypes[1]; dpTypes[0].descriptorCount = 3000; @@ -98,7 +97,7 @@ void Vulkan2D::InitDeviceObjects() { dp.poolSizeCount = ARRAY_SIZE(dpTypes); for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { VkResult res = vkCreateDescriptorPool(vulkan_->GetDevice(), &dp, nullptr, &frameData_[i].descPool); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); } VkPushConstantRange push = {}; @@ -113,7 +112,7 @@ void Vulkan2D::InitDeviceObjects() { pl.pSetLayouts = &descriptorSetLayout_; pl.flags = 0; res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); } void Vulkan2D::DeviceLost() { @@ -188,7 +187,7 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1, descAlloc.descriptorPool = frame->descPool; descAlloc.descriptorSetCount = 1; VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); - assert(result == VK_SUCCESS); + _assert_(result == VK_SUCCESS); // We just don't write to the slots we don't care about. VkWriteDescriptorSet writes[2]{}; @@ -406,7 +405,7 @@ VulkanComputeShaderManager::~VulkanComputeShaderManager() {} void VulkanComputeShaderManager::InitDeviceObjects() { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); VkDescriptorSetLayoutBinding bindings[3] = {}; bindings[0].descriptorCount = 1; @@ -428,7 +427,7 @@ void VulkanComputeShaderManager::InitDeviceObjects() { dsl.bindingCount = ARRAY_SIZE(bindings); dsl.pBindings = bindings; res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); VkDescriptorPoolSize dpTypes[2]; dpTypes[0].descriptorCount = 8192; @@ -443,7 +442,7 @@ void VulkanComputeShaderManager::InitDeviceObjects() { dp.poolSizeCount = ARRAY_SIZE(dpTypes); for (int i = 0; i < ARRAY_SIZE(frameData_); i++) { VkResult res = vkCreateDescriptorPool(vulkan_->GetDevice(), &dp, nullptr, &frameData_[i].descPool); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); } VkPushConstantRange push = {}; @@ -458,12 +457,14 @@ void VulkanComputeShaderManager::InitDeviceObjects() { pl.pSetLayouts = &descriptorSetLayout_; pl.flags = 0; res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); - assert(VK_SUCCESS == res); + _assert_(VK_SUCCESS == res); } void VulkanComputeShaderManager::DestroyDeviceObjects() { for (int i = 0; i < ARRAY_SIZE(frameData_); i++) { - vulkan_->Delete().QueueDeleteDescriptorPool(frameData_[i].descPool); + if (frameData_[i].descPool) { + vulkan_->Delete().QueueDeleteDescriptorPool(frameData_[i].descPool); + } } if (descriptorSetLayout_) { vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); @@ -491,7 +492,7 @@ VkDescriptorSet VulkanComputeShaderManager::GetDescriptorSet(VkImageView image, descAlloc.descriptorPool = frameData.descPool; descAlloc.descriptorSetCount = 1; VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); - assert(result == VK_SUCCESS); + _assert_(result == VK_SUCCESS); VkWriteDescriptorSet writes[2]{}; int n = 0; @@ -549,7 +550,8 @@ VkPipeline VulkanComputeShaderManager::GetPipeline(VkShaderModule cs) { pci.layout = pipelineLayout_; pci.flags = 0; - vkCreateComputePipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pci, nullptr, &pipeline); + VkResult res = vkCreateComputePipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pci, nullptr, &pipeline); + _assert_(res == VK_SUCCESS); pipelines_.Insert(key, pipeline); return pipeline; diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h index 53fd2ff858..8e837df544 100644 --- a/GPU/Vulkan/VulkanUtil.h +++ b/GPU/Vulkan/VulkanUtil.h @@ -20,10 +20,10 @@ #include #include -#include "Common/Hashmaps.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanLoader.h" -#include "Common/Vulkan/VulkanImage.h" +#include "Common/Data/Collections/Hashmaps.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanImage.h" // Vulkan doesn't really have the concept of an FBO that owns the images, // but it does have the concept of a framebuffer as a set of attachments. @@ -154,7 +154,6 @@ private: void DestroyDeviceObjects(); VulkanContext *vulkan_ = nullptr; - VkPipelineCache cache_ = VK_NULL_HANDLE; VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE; VkPipelineCache pipelineCache_ = VK_NULL_HANDLE; @@ -163,7 +162,7 @@ private: VkDescriptorPool descPool; int numDescriptors; }; - FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]; + FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]{}; struct PipelineKey { VkShaderModule module; diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index e9509767f0..5facb4ad05 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -282,9 +282,12 @@ enum GEBufferFormat GE_FORMAT_5551 = 1, GE_FORMAT_4444 = 2, GE_FORMAT_8888 = 3, + GE_FORMAT_DEPTH16 = 4, // Virtual format, just used to pass into Depal GE_FORMAT_INVALID = 0xFF, }; +const char *GeBufferFormatToString(GEBufferFormat fmt); + #define GE_VTYPE_TRANSFORM (0<<23) #define GE_VTYPE_THROUGH (1<<23) #define GE_VTYPE_THROUGH_MASK (1<<23) @@ -413,6 +416,14 @@ enum GETextureFormat GE_TFMT_DXT5 = 10, }; +const char *GeTextureFormatToString(GETextureFormat fmt); +inline bool IsClutFormat(GETextureFormat fmt) { + return fmt == GE_TFMT_CLUT4 || fmt == GE_TFMT_CLUT8 || fmt == GE_TFMT_CLUT16 || fmt == GE_TFMT_CLUT32; +} +inline bool IsDXTFormat(GETextureFormat fmt) { + return fmt == GE_TFMT_DXT1 || fmt == GE_TFMT_DXT3 || fmt == GE_TFMT_DXT5; +} + enum GETexLevelMode { GE_TEXLEVEL_MODE_AUTO = 0, GE_TEXLEVEL_MODE_CONST = 1, diff --git a/Qt/NKCodeFromQt.h b/Qt/NKCodeFromQt.h index 2a87141720..b53b09ffff 100644 --- a/Qt/NKCodeFromQt.h +++ b/Qt/NKCodeFromQt.h @@ -1,6 +1,6 @@ #pragma once -#include "util/const_map.h" +#include "Common/Data/Collections/ConstMap.h" #include // TODO: Add any missing keys diff --git a/Qt/QtHost.h b/Qt/QtHost.h index 1a15740806..e0c7ef4b7e 100644 --- a/Qt/QtHost.h +++ b/Qt/QtHost.h @@ -67,6 +67,9 @@ public: auto fn = SymbolMapFilename(PSP_CoreParameter().fileToStart); return g_symbolMap->LoadSymbolMap(fn.c_str()); } + + virtual void NotifySymbolMapUpdated() override { g_symbolMap->SortSymbols(); } + void PrepareShutdown() { auto fn = SymbolMapFilename(PSP_CoreParameter().fileToStart); g_symbolMap->SaveSymbolMap(fn.c_str()); diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 7713b6587d..cb2e2ab26a 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -30,12 +30,16 @@ #include "SDL/SDLJoystick.h" #include "SDL_audio.h" #endif + +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Math/math_util.h" + #include "QtMain.h" -#include "gfx_es2/gpu_features.h" -#include "i18n/i18n.h" -#include "math/math_util.h" -#include "thread/threadutil.h" -#include "util/text/utf8.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Utf8.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/HW/Camera.h" @@ -48,9 +52,9 @@ static int browseFileEvent = -1; static int browseFolderEvent = -1; QTCamera *qtcamera = nullptr; +#ifdef SDL SDL_AudioSpec g_retFmt; -#ifdef SDL static SDL_AudioDeviceID audioDev = 0; extern void mixaudio(void *userdata, Uint8 *stream, int len) { @@ -71,23 +75,23 @@ static void InitSDLAudioDevice() { if (!g_Config.sAudioDevice.empty()) { audioDev = SDL_OpenAudioDevice(g_Config.sAudioDevice.c_str(), 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (audioDev <= 0) { - WLOG("Failed to open preferred audio device %s", g_Config.sAudioDevice.c_str()); + WARN_LOG(AUDIO, "Failed to open preferred audio device %s", g_Config.sAudioDevice.c_str()); } } if (audioDev <= 0) { audioDev = SDL_OpenAudioDevice(nullptr, 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); } if (audioDev <= 0) { - ELOG("Failed to open audio: %s", SDL_GetError()); + ERROR_LOG(AUDIO, "Failed to open audio: %s", SDL_GetError()); } else { if (g_retFmt.samples != fmt.samples) // Notify, but still use it - ELOG("Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); + ERROR_LOG(AUDIO, "Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); if (g_retFmt.format != fmt.format || g_retFmt.channels != fmt.channels) { - ELOG("Sound buffer format does not match requested format."); - ELOG("Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); - ELOG("Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); - ELOG("Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); - ELOG("Provided output format does not match requirement, turning audio off"); + ERROR_LOG(AUDIO, "Sound buffer format does not match requested format."); + ERROR_LOG(AUDIO, "Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); + ERROR_LOG(AUDIO, "Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); + ERROR_LOG(AUDIO, "Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); + ERROR_LOG(AUDIO, "Provided output format does not match requirement, turning audio off"); SDL_CloseAudioDevice(audioDev); } SDL_PauseAudioDevice(audioDev, 0); @@ -147,10 +151,12 @@ std::string System_GetProperty(SystemProperty prop) { int System_GetPropertyInt(SystemProperty prop) { switch (prop) { +#if defined(SDL) case SYSPROP_AUDIO_SAMPLE_RATE: return g_retFmt.freq; case SYSPROP_AUDIO_FRAMES_PER_BUFFER: return g_retFmt.samples; +#endif case SYSPROP_DEVICE_TYPE: #if defined(__ANDROID__) return DEVICE_TYPE_MOBILE; @@ -341,9 +347,9 @@ MainUI::MainUI(QWidget *parent) } MainUI::~MainUI() { - ILOG("MainUI::Destructor"); + INFO_LOG(SYSTEM, "MainUI::Destructor"); if (emuThreadState != (int)EmuThreadState::DISABLED) { - ILOG("EmuThreadStop"); + INFO_LOG(SYSTEM, "EmuThreadStop"); EmuThreadStop(); while (graphicsContext->ThreadFrame()) { // Need to keep eating frames to allow the EmuThread to exit correctly. @@ -523,7 +529,7 @@ bool MainUI::event(QEvent *e) { void MainUI::initializeGL() { if (g_Config.iGPUBackend != (int)GPUBackend::OPENGL) { - ILOG("Only GL supported under Qt - switching."); + INFO_LOG(SYSTEM, "Only GL supported under Qt - switching."); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; } @@ -543,12 +549,12 @@ void MainUI::initializeGL() { #endif if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) { // OpenGL uses a background thread to do the main processing and only renders on the gl thread. - ILOG("Initializing GL graphics context"); + INFO_LOG(SYSTEM, "Initializing GL graphics context"); graphicsContext = new QtGLGraphicsContext(); - ILOG("Using thread, starting emu thread"); + INFO_LOG(SYSTEM, "Using thread, starting emu thread"); EmuThreadStart(); } else { - ILOG("Not using thread, backend=%d", (int)g_Config.iGPUBackend); + INFO_LOG(SYSTEM, "Not using thread, backend=%d", (int)g_Config.iGPUBackend); } graphicsContext->ThreadStart(); } @@ -712,7 +718,7 @@ int main(int argc, char *argv[]) g_Config.iGPUBackend = (int)GPUBackend::OPENGL; int ret = mainInternal(a); - ILOG("Left mainInternal here."); + INFO_LOG(SYSTEM, "Left mainInternal here."); #ifdef SDL if (audioDev > 0) { diff --git a/Qt/QtMain.h b/Qt/QtMain.h index 93bf5ccb75..afb97149f4 100644 --- a/Qt/QtMain.h +++ b/Qt/QtMain.h @@ -4,7 +4,7 @@ #include #include #include -#include "gfx_es2/glsl_program.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" #include #ifndef SDL @@ -22,17 +22,16 @@ QTM_USE_NAMESPACE #include #include -#include "base/display.h" -#include "base/logging.h" -#include "base/timeutil.h" -#include "file/zip_read.h" -#include "gfx/gl_common.h" -#include "gfx_es2/gpu_features.h" -#include "input/input_state.h" -#include "input/keycodes.h" -#include "thin3d/thin3d.h" -#include "base/NativeApp.h" -#include "net/resolve.h" +#include "Common/System/Display.h" +#include "Common/TimeUtil.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/GPU/thin3d.h" +#include "Common/Net/Resolve.h" #include "NKCodeFromQt.h" #include "Common/GraphicsContext.h" @@ -40,8 +39,8 @@ QTM_USE_NAMESPACE #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" -#include "thin3d/thin3d_create.h" -#include "thin3d/GLRenderManager.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" // Input void SimulateGamepad(); @@ -55,7 +54,9 @@ public: renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager_->SetInflightFrames(g_Config.iInflightFrames); bool success = draw_->CreatePresets(); - _assert_msg_(G3D, success, "Failed to compile preset shaders"); + _assert_msg_(success, "Failed to compile preset shaders"); + + // TODO: Need to figure out how to implement SetSwapInterval for Qt. } ~QtGLGraphicsContext() { @@ -65,7 +66,10 @@ public: } void Shutdown() override {} - void SwapInterval(int interval) override {} + void SwapInterval(int interval) override { + // See TODO in constructor. + // renderManager_->SwapInterval(interval); + } void SwapBuffers() override {} void Resize() override {} diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index b1c303f434..c2301004d3 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -7,8 +7,9 @@ #include #include -#include "base/display.h" -#include "base/NativeApp.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" #include "Core/MIPS/MIPSDebugInterface.h" #include "Core/Debugger/SymbolMap.h" #include "Core/HLE/sceUmd.h" @@ -602,7 +603,7 @@ void MainWindow::createMenus() MenuTree* windowMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("&Window size")); windowGroup = new MenuActionGroup(this, windowMenu, SLOT(windowGroup_triggered(QAction *)), QStringList() << "&1x" << "&2x" << "&3x" << "&4x" << "&5x" << "&6x" << "&7x" << "&8x" << "&9x" << "1&0x", - QList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10); + QList() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9); MenuTree* renderingModeMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("Rendering m&ode")); renderingModeGroup = new MenuActionGroup(this, renderingModeMenu, SLOT(renderingModeGroup_triggered(QAction *)), diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 150fc53471..cdc08ca196 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -8,6 +8,8 @@ #include #include +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" #include "ConsoleListener.h" #include "Core/Core.h" #include "Core/Config.h" diff --git a/README.md b/README.md index de5ec3a992..dfb30088c6 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,69 @@ Originally released under the GPL 2.0 (and later) in November 2012 No BIOS file required to play, PPSSPP is an "HLE" emulator. Default settings balance good compatibility and speed. +For the latest source code, see [our GitHub page](https://github.com/hrydgard/ppsspp). Luna version includes various compatibility improvements(hackfixes) as well as features to make testing and working around some problems easier. Includes adhoc between multiply instances of PPSSPP on same PC with some additional options to make that easier. ~ LunaMoo +For build instructions and other development tutorials, see [the wiki](https://github.com/hrydgard/ppsspp/wiki). + +If you want to download regularly updated builds for Android, Windows x86 and x64, proceed to this [page](https://buildbot.orphis.net/ppsspp/) + +For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). + +What's new in 1.10.3 +-------------------- +* Fix for control layout editor ([#13125][]) + +What's new in 1.10.2 +-------------------- +* More crashfixes ([#13094][], [#13093][]) +* Improve download performance and cancel behavior ([#13095][]) +* Restore the removed I/O on Thread option ([#13096][]) + +What's new in 1.10.1 +-------------------- +* Fixes for common crashes ([#13077][], [#13076][], see [#13057][]) +* Fix for offset rendering in D3D9 ([#13071][]) + +What's new in 1.10.0 +-------------------- +* Graphics and compatibility fixes ([#12800][], [#12670][], [#12635][], [#12857][], [#12941][], [#11898][], [#12695][], more) +* Assorted minor performance improvements, game load speedup ([#12462][], [#12652][]) +* Screen inset (notch) support on Android ([#12779][]) +* Analog stick support for menu navigation ([#12685][]) +* Fixed audio glitches in SDL builds ([#12916][], [#12920][]) +* Support more languages in in-game dialogs ([#12702][]). Croatian language added to PPSSPP. +* Simple multiplayer chat ([#12667][]) +* More advanced postprocessing (multipass, parameters) ([#12905][], [#12901][]) +* Add PPSSPP-specific CWCheat ([#12816][], [#12912][]) +* Reintroduce Cardboard VR, allow more resolutions ([#12449][], [#8714][]) +* Fix some crashes ([#12908][], [#12876][]) +* Ghost in the Shell graphics fixed (JIT inaccuracy with inf*0) ([#12519][]) +* Mac build now supports Vulkan on top of MoltenVK ([#12583][]) +* Raspberry Pi 4 EGL crash fixed ([#12474][]) +* VSync now supported on all backends, frame duplication option added for 30 Hz games ([#12659][], [#12602][]) +* Camera supported on Windows, Linux and Mac (still no microphone though) ([#12572][], [#12580][], [#12607][]) +* Darkstalkers fixed and working through software rendering. SW rendering fixed on GLES 2.0 ([#12443][], [#12898][]) +* Hot Shots Golf slowdown and flicker on Vulkan fixed ([#12873][], [#12746][]) +* Pangya Golf crashes and hangs fixed ([#12718][]) +* Allow rebinding of right touch screen analog ([#12486][]) +* Add option to prevent mipmaps from being dumped ([#12818][]) +* Tilt control now have a base radius to help with deadzone ([#12756][]) +* Mappable auto rotating analog stick to pass some game checks ([#12749][]) +* Touch control position can now be snapped to a grid ([#12517][]) +* HiDPI retina display support ([#12552][]) +* Rapid-fire on touch control ([#12601][]) +* Toggle mute button ([#12643][]) +* Add option to resize game icons and more ([#12646][], [#12637][]) +* Frames in-flight now configurable to reduce input lag at the cost of speed ([#12660][]) +* Add toggle mode to combo button ([#12623][]) +* SDL mouse support, Qt menu upgrades ([#12612][], [#12817][]) +* Real support for chinese patched version of Hatsune Miku Project Diva Extend ([#13007][]) +* Some minor kernel module support ([#13028][], [#12225][], [#13026][], [#13004][], [#13038][], [#13023][]) +* Fixed fullscreen toggling with Vulkan in SDL builds ([#11974][]) + What's new in 1.9.0/1.9.3 ------------------------- * Sizing/touch fixes on Android @@ -21,62 +80,62 @@ What's new in 1.9.0/1.9.3 What's new in 1.9.0/1.9.2 ------------------------- -* Flicker fixed in God of War that appeared with newer drivers for Mali GPUs (#12224) -* Improve performance of God of War on Vulkan (#12242), implement built-in GPU profiler (#12262, #12266) -* Vertex range culling fixed on ARM Mali (#12227) -* Started to improve VFPU precision, resulting so far in a fix for the long standing Tekken 6 leg shaking problem (#12217) -* Fixed a VFPU precision snafu on ARM64, fixing disappearing officers in Warriors Orochi (#11299) and some problems in Tomb Raider (#11179). +* Flicker fixed in God of War that appeared with newer drivers for Mali GPUs ([#12224][]) +* Improve performance of God of War on Vulkan ([#12242][]), implement built-in GPU profiler ([#12262][], [#12266][]) +* Vertex range culling fixed on ARM Mali ([#12227][]) +* Started to improve VFPU precision, resulting so far in a fix for the long standing Tekken 6 leg shaking problem ([#12217][]) +* Fixed a VFPU precision snafu on ARM64, fixing disappearing officers in Warriors Orochi ([#11299][]) and some problems in Tomb Raider ([#11179][]). * Vulkan is the default again on Android versions newer than Pie * Fix various homebrew store issues -* GPU pause signal handling fixed, fixing some hangs in Bleach and Armored Core games (#12160) -* Audio sample rate conversion handling fixes (#12147) -* Some Vulkan optimizations (pre-rotation (#12216), perf fix in Metal Gear Acid, etc) -* Multiple fixes for the UWP build (#12036, others) -* MP3 playback fixes (#12005) -* Audio in Motorstorm: Arctic Edge fixed by returning errors correctly (#12121) -* Audio glitches in Final Fantasy Tactics fixed (#9956) -* Camera display in Invizimals fixed (#12278, #8521) -* Added hotkeys for texture dump and replace (#11938) -* Added Visual Studio 2019 support. Windows XP is no longer supported (#11995, others) -* Fixes for video capture (#12069) -* Added a separate sound volume for alternative speed (#12124) -* Improved mouse control (Windows only) (#12173, #12176) -* Support for installing texture packs and ISOs from zips (#12175) -* Right analog support for touch controls (only used by patched games and some HD remasters) (#12182) -* Android: Fix OpenSL initialization, possibly helps audio crackle a little. (#12333). +* GPU pause signal handling fixed, fixing some hangs in Bleach and Armored Core games ([#12160][]) +* Audio sample rate conversion handling fixes ([#12147][]) +* Some Vulkan optimizations (pre-rotation ([#12216][]), perf fix in Metal Gear Acid, etc) +* Multiple fixes for the UWP build ([#12036][], others) +* MP3 playback fixes ([#12005][]) +* Audio in Motorstorm: Arctic Edge fixed by returning errors correctly ([#12121][]) +* Audio glitches in Final Fantasy Tactics fixed ([#9956][]) +* Camera display in Invizimals fixed ([#12278][], [#8521][]) +* Added hotkeys for texture dump and replace ([#11938][]) +* Added Visual Studio 2019 support. Windows XP is no longer supported ([#11995][], others) +* Fixes for video capture ([#12069][]) +* Added a separate sound volume for alternative speed ([#12124][]) +* Improved mouse control (Windows only) ([#12173][], [#12176][]) +* Support for installing texture packs and ISOs from zips ([#12175][]) +* Right analog support for touch controls (only used by patched games and some HD remasters) ([#12182][]) +* Android: Fix OpenSL initialization, possibly helps audio crackle a little. ([#12333][]). * Fix graphics on Amazon Fire TV Stick 4K -* Fixed strange vehicle behavior in MGS:PW (somehow) (#12342) +* Fixed strange vehicle behavior in MGS:PW (somehow) ([#12342][]) What's new in 1.8.0 ------------------- -* Avoid crash when starting PPSSPP due to bad AMD Vulkan drivers (#11802) -* PowerVR Vulkan display corruption fixed (#11744, #11747) -* Naruto Shippuden 3 hang fixed (#11780) -* Fixes to various lighting bugs (#11567, #11574, #11577) -* Fix control issue in Sonic Rivals and Rock Band (#11878, #11798, #11879) -* Significant performance improvement in Earth Defense Force 2 (#11172) -* Fix "real clock sync" setting (helps with latency for music games - #11813) -* More speed in FF4 effects and other generated curves (#11425) -* Support for resizing Vulkan on Linux (#11451) -* Improved support for GLES on Linux/IoT (#11507, #11537, #11541, #11632, #11746, #11806, #11845) -* Percentage based frameskipping (#11523) -* DXT accuracy improved, fixing thick white line in Gran Turismo sky (#11530) -* Fix Motorstorm freeze on non-Windows (#11618) -* Faster block transfer in some games like Digimon Adventures (#11531, #11553, #11776) -* Blending optimizations and improvements (#11543, #11620) -* Improve D3D11 rendering issues (#11584) -* Change default graphics backend to D3D11 or OpenGL (#11621, #11658) -* Remove some outdated settings (#11665, #11666, #11667) -* Fix remote disc streaming with ipv6 (#11689, #11700) -* Vulkan: Workarounds for some driver bugs for 5xx series Qualcomm GPUs (#11691, #11694) -* Fix some Qt port issues with recent performance improvements (#11720, #11807, #11808) -* UWP Xbox One: fix X/Back button confusion (#11740) -* Fix Formula 1 2006 timing issue (#11767) -* Fixes and workarounds for some vertex range culling bugs that broke a few games (#11785, #11859), and disable it on older GPUs (#11712, #11773, #11787) -* Android: Allow putting PSP storage on custom paths like SD cards (#11812) -* Corrected vocp instruction, fixing models in Artdink games (#11822, #11835) -* Bundle SDL in binary for macOS builds (#11831) -* Prevent keeping games open on Windows (#11842) +* Avoid crash when starting PPSSPP due to bad AMD Vulkan drivers ([#11802][]) +* PowerVR Vulkan display corruption fixed ([#11744][], [#11747][]) +* Naruto Shippuden 3 hang fixed ([#11780][]) +* Fixes to various lighting bugs ([#11567][], [#11574][], [#11577][]) +* Fix control issue in Sonic Rivals and Rock Band ([#11878][], [#11798][], [#11879][]) +* Significant performance improvement in Earth Defense Force 2 ([#11172][]) +* Fix "real clock sync" setting (helps with latency for music games - [#11813][]) +* More speed in FF4 effects and other generated curves ([#11425][]) +* Support for resizing Vulkan on Linux ([#11451][]) +* Improved support for GLES on Linux/IoT ([#11507][], [#11537][], [#11541][], [#11632][], [#11746][], [#11806][], [#11845][]) +* Percentage based frameskipping ([#11523][]) +* DXT accuracy improved, fixing thick white line in Gran Turismo sky ([#11530][]) +* Fix Motorstorm freeze on non-Windows ([#11618][]) +* Faster block transfer in some games like Digimon Adventures ([#11531][], [#11553][], [#11776][]) +* Blending optimizations and improvements ([#11543][], [#11620][]) +* Improve D3D11 rendering issues ([#11584][]) +* Change default graphics backend to D3D11 or OpenGL ([#11621][], [#11658][]) +* Remove some outdated settings ([#11665][], [#11666][], [#11667][]) +* Fix remote disc streaming with ipv6 ([#11689][], [#11700][]) +* Vulkan: Workarounds for some driver bugs for 5xx series Qualcomm GPUs ([#11691][], [#11694][]) +* Fix some Qt port issues with recent performance improvements ([#11720][], [#11807][], [#11808][]) +* UWP Xbox One: fix X/Back button confusion ([#11740][]) +* Fix Formula 1 2006 timing issue ([#11767][]) +* Fixes and workarounds for some vertex range culling bugs that broke a few games ([#11785][], [#11859][]), and disable it on older GPUs ([#11712][], [#11773][], [#11787][]) +* Android: Allow putting PSP storage on custom paths like SD cards ([#11812][]) +* Corrected vocp instruction, fixing models in Artdink games ([#11822][], [#11835][]) +* Bundle SDL in binary for macOS builds ([#11831][]) +* Prevent keeping games open on Windows ([#11842][]) What's new in 1.7.3/1.7.4/1.7.5 ------------------- @@ -91,19 +150,178 @@ What's new in 1.7.2 What's new in 1.7.1 ------------------- * Minor crashfixes, lang updates -* Save bug fixed (#11508) +* Save bug fixed ([#11508][]) What's new in 1.7.0 ------------------- -* Fix for insta-crash on Galaxy Note 9, some Xiaomi devices, and the new nVidia Shield (#11441) -* Vertex range culling on most platforms, fixes DTM: Race Driver and similar (#11393) -* Major speed boost in some Gundam and Earth Defense Force games (#10973) -* Fix for issues with post processing shaders in GL 3+ (#11182) -* Fixes to sound output switching on Windows (WASAPI) (#11438) -* Detects DirectInput devices when running (#11461) -* Simple Discord integration (#11307) -* New debugging APIs (#10909) -* Task switching made a lot more robust (fixes GPD XD problems) (#11447) -* Texture decoding optimizations (#11350) +* Fix for insta-crash on Galaxy Note 9, some Xiaomi devices, and the new nVidia Shield ([#11441][]) +* Vertex range culling on most platforms, fixes DTM: Race Driver and similar ([#11393][]) +* Major speed boost in some Gundam and Earth Defense Force games ([#10973][]) +* Fix for issues with post processing shaders in GL 3+ ([#11182][]) +* Fixes to sound output switching on Windows (WASAPI) ([#11438][]) +* Detects DirectInput devices when running ([#11461][]) +* Simple Discord integration ([#11307][]) +* New debugging APIs ([#10909][]) +* Task switching made a lot more robust (fixes GPD XD problems) ([#11447][]) +* Texture decoding optimizations ([#11350][]) * Tons and tons of miscellaneous bugfixes and compatibility fixes +[#13125]: https://github.com/hrydgard/ppsspp/issues/13125 "Refactor and fix touch control layout screen for notch" +[#13094]: https://github.com/hrydgard/ppsspp/issues/13094 "Camera initialization crash fix" +[#13093]: https://github.com/hrydgard/ppsspp/issues/13093 "Add a try/catch to Android camera device listing." +[#13095]: https://github.com/hrydgard/ppsspp/issues/13095 "http: Check cancel flag more often" +[#13096]: https://github.com/hrydgard/ppsspp/issues/13096 "Revert \"Remove the I/O on Thread option - treat it as always on.\"" +[#13077]: https://github.com/hrydgard/ppsspp/issues/13077 "SaveState: Make sure to default init net data" +[#13076]: https://github.com/hrydgard/ppsspp/issues/13076 "Add some excessive null checks to GameScreen::render()" +[#13057]: https://github.com/hrydgard/ppsspp/issues/13057 "The 1.10 Android mystery crash thread!" +[#13071]: https://github.com/hrydgard/ppsspp/issues/13071 "D3D9: Fix a sign mistake generating the projection matrix." +[#12800]: https://github.com/hrydgard/ppsspp/issues/12800 "x86jit: Force INF * 0 to +NAN" +[#12670]: https://github.com/hrydgard/ppsspp/issues/12670 "Attempts to replace 0 frame width with valid frame width.(sceMpegAvcCsc)" +[#12635]: https://github.com/hrydgard/ppsspp/issues/12635 "Kernel: Delay better in sceKernelReferThreadStatus" +[#12857]: https://github.com/hrydgard/ppsspp/issues/12857 "Mumbo Jumbo games freeze on loading screen since v1.6" +[#12941]: https://github.com/hrydgard/ppsspp/issues/12941 "Vulkan: Deal with the reformat clear better" +[#11898]: https://github.com/hrydgard/ppsspp/issues/11898 "Strike Witches - Hakugin no Tsubasa missing intro video" +[#12695]: https://github.com/hrydgard/ppsspp/issues/12695 "New heuristic for getting rid of unnecessary \"antialias-lines\"." +[#12462]: https://github.com/hrydgard/ppsspp/issues/12462 "Vulkan: Enable renderpass merging for all games" +[#12652]: https://github.com/hrydgard/ppsspp/issues/12652 "ScanForFunctions: Speed up game loading" +[#12779]: https://github.com/hrydgard/ppsspp/issues/12779 "Support drawing around notches on Android displays. Fixes #12261" +[#12685]: https://github.com/hrydgard/ppsspp/issues/12685 "UI: Simple joystick navigation. Fixes #10996." +[#12916]: https://github.com/hrydgard/ppsspp/issues/12916 "More audio buffering fixes (primarily affects SDL)" +[#12920]: https://github.com/hrydgard/ppsspp/issues/12920 "Remove the Audio Resampling setting (now always on)." +[#12702]: https://github.com/hrydgard/ppsspp/issues/12702 "PPGe: Use TextDrawer for save UI if available" +[#12667]: https://github.com/hrydgard/ppsspp/issues/12667 "Chat feature based on Adenovan's Rechat branch" +[#12905]: https://github.com/hrydgard/ppsspp/issues/12905 "Allow chained post-processing shaders" +[#12901]: https://github.com/hrydgard/ppsspp/issues/12901 "Post shader setting uniform" +[#12816]: https://github.com/hrydgard/ppsspp/issues/12816 "Implement Xinput vibration CWCheat (PPSSPP specific 0xA code type)" +[#12912]: https://github.com/hrydgard/ppsspp/issues/12912 "Add CWCHEAT for postprocessing" +[#12449]: https://github.com/hrydgard/ppsspp/issues/12449 "Reintroduce Cardboard VR" +[#8714]: https://github.com/hrydgard/ppsspp/issues/8714 "Allow > 5x PSP resolution for devices like iPad Pro 12.9" +[#12908]: https://github.com/hrydgard/ppsspp/issues/12908 "Fix \"Improved compatibility of sceGeListEnQueue: verify that stackDepth < 256\"" +[#12876]: https://github.com/hrydgard/ppsspp/issues/12876 "Windows: Add safety checks to WASAPI code" +[#12519]: https://github.com/hrydgard/ppsspp/issues/12519 "Ghost In The Shell - Stand Alone Complex (ULUS10020) - Black Textures and missing screens." +[#12583]: https://github.com/hrydgard/ppsspp/issues/12583 "macOS: Initial support for vulkan on macOS ( MoltenVK )" +[#12474]: https://github.com/hrydgard/ppsspp/issues/12474 "Egl bug on rpi4 with master mesa?" +[#12659]: https://github.com/hrydgard/ppsspp/issues/12659 "Support vsync in all hardware backends, support runtime update" +[#12602]: https://github.com/hrydgard/ppsspp/issues/12602 "Add option to improve frame pacing through duplicate frames if below 60hz." +[#12572]: https://github.com/hrydgard/ppsspp/issues/12572 "Add camera support for windows." +[#12580]: https://github.com/hrydgard/ppsspp/issues/12580 "Add camera support for linux (V4L2)" +[#12607]: https://github.com/hrydgard/ppsspp/issues/12607 "QT API for camera (Linux/macOS)" +[#12443]: https://github.com/hrydgard/ppsspp/issues/12443 "Darkstalkers Chronicle: Add specializations and speedhacks to get it kinda playable" +[#12898]: https://github.com/hrydgard/ppsspp/issues/12898 "[Android] [Mali GPU] [OpenGL] Lastest build blackscreen on buffered rendering mode" +[#12873]: https://github.com/hrydgard/ppsspp/issues/12873 "Vulkan: Framebuffer manager: Use an allocator for \"MakePixelTexture\" images." +[#12746]: https://github.com/hrydgard/ppsspp/issues/12746 "GPU: Assume a scissor of 481x273 is a mistake" +[#12718]: https://github.com/hrydgard/ppsspp/issues/12718 "Vpl: Correct allocation order when splitting block" +[#12486]: https://github.com/hrydgard/ppsspp/issues/12486 "Rebindable touch right analog" +[#12818]: https://github.com/hrydgard/ppsspp/issues/12818 "Add option to prevent Mipmaps from being dumped" +[#12756]: https://github.com/hrydgard/ppsspp/issues/12756 "Skip deadzone option on tilt" +[#12749]: https://github.com/hrydgard/ppsspp/issues/12749 "Auto rotating analog" +[#12517]: https://github.com/hrydgard/ppsspp/issues/12517 "Touch control grid snap" +[#12552]: https://github.com/hrydgard/ppsspp/issues/12552 "Qt/macOS: enable HiDPI ( retina display ) support" +[#12601]: https://github.com/hrydgard/ppsspp/issues/12601 "Add rapid fire to touch control" +[#12643]: https://github.com/hrydgard/ppsspp/issues/12643 "Toggle mute button" +[#12646]: https://github.com/hrydgard/ppsspp/issues/12646 "Resizable game icons" +[#12637]: https://github.com/hrydgard/ppsspp/issues/12637 "Region flag and game ID on game selection screen" +[#12660]: https://github.com/hrydgard/ppsspp/issues/12660 "GPU: Add setting to control inflight frame usage" +[#12623]: https://github.com/hrydgard/ppsspp/issues/12623 "Add toggle flag to combo button" +[#12612]: https://github.com/hrydgard/ppsspp/issues/12612 "SDL analog mouse input" +[#12817]: https://github.com/hrydgard/ppsspp/issues/12817 "Unification of the menu of Linux and Windows versions" +[#13007]: https://github.com/hrydgard/ppsspp/issues/13007 "Real support \"Hatsune Miku Project Diva Extend\" chinese patched version" +[#13028]: https://github.com/hrydgard/ppsspp/issues/13028 "Real support Code Geass: Lost Colors chinese patched version" +[#12225]: https://github.com/hrydgard/ppsspp/issues/12225 "Rebased: Wrap some SysMemForKernel's nids, fixing #7960" +[#13026]: https://github.com/hrydgard/ppsspp/issues/13026 "Add some ThreadManForKernel nids" +[#13004]: https://github.com/hrydgard/ppsspp/issues/13004 "Warp some ThreadManForKernel and sceKernelExitVSHKernel" +[#13038]: https://github.com/hrydgard/ppsspp/issues/13038 "Add sysclib_strncmp,sysclib_memmove" +[#13023]: https://github.com/hrydgard/ppsspp/issues/13023 "Add sysclib_strstr" +[#11974]: https://github.com/hrydgard/ppsspp/issues/11974 "[Linux] [Vulkan] Toggle fullscreen doesn't update display properly" +[#12224]: https://github.com/hrydgard/ppsspp/issues/12224 "Vulkan: Add missing barrier between multiple passes to the same target." +[#12242]: https://github.com/hrydgard/ppsspp/issues/12242 "Vulkan: Automatically merge render passes to the same target when possible" +[#12262]: https://github.com/hrydgard/ppsspp/issues/12262 "Vulkan: Implement basic integrated GPU profiling." +[#12266]: https://github.com/hrydgard/ppsspp/issues/12266 "Vulkan: Further improvements to GPU profiling" +[#12227]: https://github.com/hrydgard/ppsspp/issues/12227 "Vulkan/GL: Set all four coordinates to NaN instead of just W." +[#12217]: https://github.com/hrydgard/ppsspp/issues/12217 "Merge vfpu-dot changes and add compat flag for Tekken" +[#11299]: https://github.com/hrydgard/ppsspp/issues/11299 "Warrior Orochi Enemy Missing" +[#11179]: https://github.com/hrydgard/ppsspp/issues/11179 "Tomb Raider Anniversary jump to horizontal bar issue" +[#12160]: https://github.com/hrydgard/ppsspp/issues/12160 "GPU: Forget pause signal on new list" +[#12147]: https://github.com/hrydgard/ppsspp/issues/12147 "Handle audio SRC mixing more correctly" +[#12216]: https://github.com/hrydgard/ppsspp/issues/12216 "Cant get Invizimals to work on PPSSPP (Video source not rendered)" +[#12036]: https://github.com/hrydgard/ppsspp/issues/12036 "Several UWP fixes" +[#12005]: https://github.com/hrydgard/ppsspp/issues/12005 "Correct mp3 looping, frame num, and sum decoded" +[#12121]: https://github.com/hrydgard/ppsspp/issues/12121 "Return errors on Audio2 release when channel busy" +[#9956]: https://github.com/hrydgard/ppsspp/issues/9956 "Audio crackle/distortion in Final Fantasy Tactics" +[#12278]: https://github.com/hrydgard/ppsspp/issues/12278 "UsbCam/jpeg: Cleanups, notify framebuffer manager" +[#8521]: https://github.com/hrydgard/ppsspp/issues/8521 "PSP Camera Support (Android)" +[#11938]: https://github.com/hrydgard/ppsspp/issues/11938 "Add texture dump/replace hotkeys." +[#11995]: https://github.com/hrydgard/ppsspp/issues/11995 "Fix VS2019 builds and remove _xp dependency" +[#12069]: https://github.com/hrydgard/ppsspp/issues/12069 "Fix avi dump feature" +[#12124]: https://github.com/hrydgard/ppsspp/issues/12124 "Audio: Add volume for alternate speed" +[#12173]: https://github.com/hrydgard/ppsspp/issues/12173 "Ignore mapped mouse input for UI" +[#12176]: https://github.com/hrydgard/ppsspp/issues/12176 "Mouse improvements" +[#12175]: https://github.com/hrydgard/ppsspp/issues/12175 "UI: Allow installing texture packs from zips" +[#12182]: https://github.com/hrydgard/ppsspp/issues/12182 "Add right analog for touch controls." +[#12333]: https://github.com/hrydgard/ppsspp/issues/12333 "Android OpenSL initial queue fix" +[#12342]: https://github.com/hrydgard/ppsspp/issues/12342 "Serious MGS Peace Walker bug fixed post-1.8.0" +[#11802]: https://github.com/hrydgard/ppsspp/issues/11802 "Windows: Detect Vulkan in separate process" +[#11744]: https://github.com/hrydgard/ppsspp/issues/11744 "VulkanDeviceAlloc: Memorytype per slab" +[#11747]: https://github.com/hrydgard/ppsspp/issues/11747 "Vk validation fixes, plus PowerVR swapchain hack" +[#11780]: https://github.com/hrydgard/ppsspp/issues/11780 "Naruto Shippuden Ultimate Ninja 3: Probably a better fix for the video hang issue." +[#11567]: https://github.com/hrydgard/ppsspp/issues/11567 "Correct shade mapping when light pos is all zeros" +[#11574]: https://github.com/hrydgard/ppsspp/issues/11574 "Correct various light param issues based on tests" +[#11577]: https://github.com/hrydgard/ppsspp/issues/11577 "Correct provoking vertex for lighting when flat shading" +[#11878]: https://github.com/hrydgard/ppsspp/issues/11878 "Sonic Rivals controls semi-broken" +[#11798]: https://github.com/hrydgard/ppsspp/issues/11798 "User report: Long notes in Rock Band Unplugged are not registered correctly" +[#11879]: https://github.com/hrydgard/ppsspp/issues/11879 "Fix apparent bug in #11094, fixes #11878 and likely #11798" +[#11172]: https://github.com/hrydgard/ppsspp/issues/11172 "handle cullface, help to #10597" +[#11813]: https://github.com/hrydgard/ppsspp/issues/11813 "Core: Fix lag sync on game start / after pause" +[#11425]: https://github.com/hrydgard/ppsspp/issues/11425 "[Refactoring] Improve spline/bezier." +[#11451]: https://github.com/hrydgard/ppsspp/issues/11451 "SDL/Vulkan window resize improvements" +[#11507]: https://github.com/hrydgard/ppsspp/issues/11507 "Improve support of Qt + USING_GLES2" +[#11537]: https://github.com/hrydgard/ppsspp/issues/11537 "CMake: Allow disabling Wayland support with USE_WAYLAND_WSI" +[#11541]: https://github.com/hrydgard/ppsspp/issues/11541 "CMake: Fix linking X11 when using EGL and not fbdev" +[#11632]: https://github.com/hrydgard/ppsspp/issues/11632 "SDL: Allow toggling fullscreen for GLES2 on desktops." +[#11746]: https://github.com/hrydgard/ppsspp/issues/11746 "CMakeLists: fix EGL detection for ARM devices" +[#11806]: https://github.com/hrydgard/ppsspp/issues/11806 "SDL: Force fullscreen desktop for USING_FBDEV" +[#11845]: https://github.com/hrydgard/ppsspp/issues/11845 "EGL: Avoid HDR mode. Uses unknownbrackets' changes from #11839." +[#11523]: https://github.com/hrydgard/ppsspp/issues/11523 "Add frameskip setting" +[#11530]: https://github.com/hrydgard/ppsspp/issues/11530 "Make DXT alpha and color calculation more accurate" +[#11618]: https://github.com/hrydgard/ppsspp/issues/11618 "Io: Ensure sign extension for error codes" +[#11531]: https://github.com/hrydgard/ppsspp/issues/11531 "WIP: Virtual readbacks" +[#11553]: https://github.com/hrydgard/ppsspp/issues/11553 "Remove constraint that virtual framebuffers have to represent VRAM." +[#11776]: https://github.com/hrydgard/ppsspp/issues/11776 "Only gate really expensive block transfers behind the setting." +[#11543]: https://github.com/hrydgard/ppsspp/issues/11543 "GPU: Dirty frag shader on depth write" +[#11620]: https://github.com/hrydgard/ppsspp/issues/11620 "Optimize out some stencil emulation, try to avoid depth write" +[#11584]: https://github.com/hrydgard/ppsspp/issues/11584 "D3D11: Allow shader blend to self" +[#11621]: https://github.com/hrydgard/ppsspp/issues/11621 "Vulkan: Avoid using Vulkan" +[#11658]: https://github.com/hrydgard/ppsspp/issues/11658 "Windows: Hide Vulkan/D3D11 if not available" +[#11665]: https://github.com/hrydgard/ppsspp/issues/11665 "Remove the \"Disable stencil test\" hack setting" +[#11666]: https://github.com/hrydgard/ppsspp/issues/11666 "Remove \"Timer Hack\" setting." +[#11667]: https://github.com/hrydgard/ppsspp/issues/11667 "Remove outdated TrueColor setting." +[#11689]: https://github.com/hrydgard/ppsspp/issues/11689 "Correct remote disc streaming with ipv6" +[#11700]: https://github.com/hrydgard/ppsspp/issues/11700 "http: Report errors reading discs" +[#11691]: https://github.com/hrydgard/ppsspp/issues/11691 "WIP: Vulkan/adreno: Apply workaround for Harvest Moon issue #10421" +[#11694]: https://github.com/hrydgard/ppsspp/issues/11694 "Vulkan: Limit stencil workaround to Adreno 5xx" +[#11720]: https://github.com/hrydgard/ppsspp/issues/11720 "Try to support Qt keyboard input directly. Fixes #11653" +[#11807]: https://github.com/hrydgard/ppsspp/issues/11807 "Qt: Re-enable Load button to browse for file" +[#11808]: https://github.com/hrydgard/ppsspp/issues/11808 "Qt: Correct text bind on first draw of string" +[#11740]: https://github.com/hrydgard/ppsspp/issues/11740 "Fix for weird Xbox B button behavior, see #10948." +[#11767]: https://github.com/hrydgard/ppsspp/issues/11767 "Compat: Force realistic UMD timing for F1 2006." +[#11785]: https://github.com/hrydgard/ppsspp/issues/11785 "GPU: Correct depth clamp range in range cull" +[#11859]: https://github.com/hrydgard/ppsspp/issues/11859 "GPU: Handle cull range properly drawing at offset" +[#11712]: https://github.com/hrydgard/ppsspp/issues/11712 "GLES: Detect Vivante GPU, disable vertex range culling" +[#11773]: https://github.com/hrydgard/ppsspp/issues/11773 "D3D9: Disable range culling on really old NVIDIA cards" +[#11787]: https://github.com/hrydgard/ppsspp/issues/11787 "GLES: Disable range culling on VideoCore/Vivante" +[#11812]: https://github.com/hrydgard/ppsspp/issues/11812 "Android: Allow using a custom Memory Stick storage path" +[#11822]: https://github.com/hrydgard/ppsspp/issues/11822 "interp: Correct vocp prefix handling" +[#11835]: https://github.com/hrydgard/ppsspp/issues/11835 "Correct vocp / vsocp prefix handling" +[#11831]: https://github.com/hrydgard/ppsspp/issues/11831 "Bundle libSDL inside app on macOS, fixes #11830" +[#11842]: https://github.com/hrydgard/ppsspp/issues/11842 "Win32 handle leak fix" +[#11508]: https://github.com/hrydgard/ppsspp/issues/11508 "Savedata: Write only one secure entry" +[#11441]: https://github.com/hrydgard/ppsspp/issues/11441 "Vulkan: Apply Themaister's patch, removing illegal pre-transitions of swapchain images. Fixes #11417 (crash on Note 9)" +[#11393]: https://github.com/hrydgard/ppsspp/issues/11393 "Implement vertex range culling" +[#10973]: https://github.com/hrydgard/ppsspp/issues/10973 "handle cull mode" +[#11182]: https://github.com/hrydgard/ppsspp/issues/11182 "GLES: Use accurate GLSL ver in postshader convert" +[#11438]: https://github.com/hrydgard/ppsspp/issues/11438 "Allow WASAPI device switching" +[#11461]: https://github.com/hrydgard/ppsspp/issues/11461 "Windows: Detect DirectInput devices after launch" +[#11307]: https://github.com/hrydgard/ppsspp/issues/11307 "Enable Discord integration for Mac and Linux." +[#10909]: https://github.com/hrydgard/ppsspp/issues/10909 "WebSocket based debugger interface" +[#11447]: https://github.com/hrydgard/ppsspp/issues/11447 "Avoid calling any GL calls during shutdown on Android. Should help #11063" +[#11350]: https://github.com/hrydgard/ppsspp/issues/11350 "TexCache: Optimize DXT3/DXT5 decode to single pass" diff --git a/SDL/NKCodeFromSDL.h b/SDL/NKCodeFromSDL.h index d71654c945..bd184eef01 100644 --- a/SDL/NKCodeFromSDL.h +++ b/SDL/NKCodeFromSDL.h @@ -1,6 +1,6 @@ #pragma once -#include "util/const_map.h" +#include "Common/Data/Collections/ConstMap.h" #include // TODO: Add any missing keys diff --git a/SDL/SDLCocoaMetalLayer.mm b/SDL/SDLCocoaMetalLayer.mm index d0df82716b..c45158ff5d 100644 --- a/SDL/SDLCocoaMetalLayer.mm +++ b/SDL/SDLCocoaMetalLayer.mm @@ -5,7 +5,6 @@ #endif #import -#include "base/logging.h" #include "SDLCocoaMetalLayer.h" void *makeWindowMetalCompatible(void *window) { diff --git a/SDL/SDLGLGraphicsContext.cpp b/SDL/SDLGLGraphicsContext.cpp index f7e142f595..83fd2cd873 100644 --- a/SDL/SDLGLGraphicsContext.cpp +++ b/SDL/SDLGLGraphicsContext.cpp @@ -1,12 +1,16 @@ #include + #include "SDLGLGraphicsContext.h" + +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/thin3d_create.h" + +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/System/Display.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" -#include "base/NativeApp.h" -#include "base/display.h" -#include "gfx_es2/gpu_features.h" -#include "thin3d/thin3d_create.h" #if defined(USING_EGL) #include "EGL/egl.h" @@ -23,6 +27,7 @@ static EGLSurface g_eglSurface = nullptr; static EGLNativeDisplayType g_Display = nullptr; static bool g_XDisplayOpen = false; static EGLNativeWindowType g_Window = (EGLNativeWindowType)nullptr; +static bool useEGLSwap = false; int CheckEGLErrors(const char *file, int line) { EGLenum error; @@ -328,7 +333,7 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: SetGLCoreContext(true); #endif - window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode); + window = SDL_CreateWindow("PPSSPP", x, y, pixel_xres, pixel_yres, mode); if (!window) { // Definitely don't shutdown here: we'll keep trying more GL versions. fprintf(stderr, "SDL_CreateWindow failed for GL %d.%d: %s\n", ver.major, ver.minor, SDL_GetError()); @@ -353,7 +358,7 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SetGLCoreContext(false); - window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode); + window = SDL_CreateWindow("PPSSPP", x, y, pixel_xres, pixel_yres, mode); if (window == nullptr) { NativeShutdown(); fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); @@ -376,11 +381,10 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: #ifdef USING_EGL if (EGL_Open(window) != 0) { printf("EGL_Open() failed\n"); - return 1; - } - if (EGL_Init(window) != 0) { + } else if (EGL_Init(window) != 0) { printf("EGL_Init() failed\n"); - return 1; + } else { + useEGLSwap = true; } #endif @@ -412,18 +416,30 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); SetGPUBackend(GPUBackend::OPENGL); bool success = draw_->CreatePresets(); - assert(success); + _assert_(success); renderManager_->SetSwapFunction([&]() { #ifdef USING_EGL - eglSwapBuffers(g_eglDisplay, g_eglSurface); + if (useEGLSwap) + eglSwapBuffers(g_eglDisplay, g_eglSurface); + else + SDL_GL_SwapWindow(window_); #else SDL_GL_SwapWindow(window_); #endif }); + + renderManager_->SetSwapIntervalFunction([&](int interval) { + INFO_LOG(G3D, "SDL SwapInterval: %d", interval); + SDL_GL_SetSwapInterval(interval); + }); window_ = window; return 0; } +void SDLGLGraphicsContext::SwapInterval(int interval) { + renderManager_->SwapInterval(interval); +} + void SDLGLGraphicsContext::Shutdown() { } @@ -433,7 +449,6 @@ void SDLGLGraphicsContext::ShutdownFromRenderThread() { #ifdef USING_EGL EGL_Close(); -#else - SDL_GL_DeleteContext(glContext); #endif + SDL_GL_DeleteContext(glContext); } diff --git a/SDL/SDLGLGraphicsContext.h b/SDL/SDLGLGraphicsContext.h index 666aa72774..1910ce8f56 100644 --- a/SDL/SDLGLGraphicsContext.h +++ b/SDL/SDLGLGraphicsContext.h @@ -1,11 +1,11 @@ #include "SDL_syswm.h" #include "SDL.h" -#include "thin3d/GLRenderManager.h" -#include "gfx/gl_common.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLCommon.h" #include "Common/GraphicsContext.h" -class SDLGLGraphicsContext : public DummyGraphicsContext { +class SDLGLGraphicsContext : public GraphicsContext { public: SDLGLGraphicsContext() { } @@ -20,6 +20,11 @@ public: // Do nothing, the render thread takes care of this. } + // Gets forwarded to the render thread. + void SwapInterval(int interval) override; + + void Resize() override {} + Draw::DrawContext *GetDrawContext() override { return draw_; } diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index 72254a1534..1dfedeac51 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -1,11 +1,14 @@ -#include "SDL/SDLJoystick.h" -#include "Core/Config.h" -#include "Common/FileUtil.h" -#include "file/vfs.h" - #include #include +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/File/VFS/VFS.h" + +#include "Common/File/FileUtil.h" +#include "Core/Config.h" +#include "SDL/SDLJoystick.h" + using namespace std; static int SDLJoystickEventHandlerWrapper(void* userdata, SDL_Event* event) @@ -55,15 +58,19 @@ void SDLJoystick::setUpController(int deviceIndex) { int cbGUID = 33; char pszGUID[cbGUID]; SDL_Joystick* joystick = SDL_JoystickOpen(deviceIndex); - SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), pszGUID, cbGUID); - // create default mapping - this is the PS3 dual shock mapping - std::string mapping = string(pszGUID) + "," + string(SDL_JoystickName(joystick)) + ",x:b3,a:b0,b:b1,y:b2,back:b8,guide:b10,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:a5,leftstick:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4"; - if (SDL_GameControllerAddMapping(mapping.c_str()) == 1){ - cout << "Added default mapping ok" << endl; + if (joystick) { + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), pszGUID, cbGUID); + // create default mapping - this is the PS3 dual shock mapping + std::string mapping = string(pszGUID) + "," + string(SDL_JoystickName(joystick)) + ",x:b3,a:b0,b:b1,y:b2,back:b8,guide:b10,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:a5,leftstick:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4"; + if (SDL_GameControllerAddMapping(mapping.c_str()) == 1){ + cout << "Added default mapping ok" << endl; + } else { + cout << "Failed to add default mapping" << endl; + } + SDL_JoystickClose(joystick); } else { - cout << "Failed to add default mapping" << endl; + cout << "Failed to get joystick identifier. Read-only device? Control pad device " + std::to_string(deviceIndex) << endl; } - SDL_JoystickClose(joystick); } SDL_GameController *controller = SDL_GameControllerOpen(deviceIndex); if (controller) { diff --git a/SDL/SDLJoystick.h b/SDL/SDLJoystick.h index 970b105199..057e332b25 100644 --- a/SDL/SDLJoystick.h +++ b/SDL/SDLJoystick.h @@ -7,10 +7,9 @@ #include "SDL_thread.h" #endif -#include "input/input_state.h" -#include "input/keycodes.h" -#include "net/resolve.h" -#include "base/NativeApp.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Net/Resolve.h" class SDLJoystick{ public: diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 52028d0879..8d43dfdb66 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -16,26 +16,19 @@ SDLJoystick *joystick = NULL; #include #include -#include #include #include #include -#include "base/display.h" -#include "base/logging.h" -#include "base/timeutil.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" #include "ext/glslang/glslang/Public/ShaderLang.h" -#include "image/png_load.h" -#include "input/input_state.h" -#include "input/keycodes.h" -#include "net/resolve.h" +#include "Common/Data/Format/PNGLoad.h" +#include "Common/Net/Resolve.h" #include "NKCodeFromSDL.h" -#include "util/const_map.h" -#include "util/text/utf8.h" -#include "math/math_util.h" -#include "thin3d/GLRenderManager.h" -#include "thread/threadutil.h" -#include "math.h" +#include "Common/Math/math_util.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "SDL_syswm.h" @@ -48,11 +41,17 @@ SDLJoystick *joystick = NULL; #include #endif +#include "Common/GraphicsContext.h" +#include "Common/TimeUtil.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Data/Collections/ConstMap.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Thread/ThreadUtil.h" #include "Core/System.h" #include "Core/Core.h" #include "Core/Config.h" #include "Core/ConfigValues.h" -#include "Common/GraphicsContext.h" #include "SDLGLGraphicsContext.h" #include "SDLVulkanGraphicsContext.h" @@ -110,24 +109,24 @@ static void InitSDLAudioDevice(const std::string &name = "") { if (!startDevice.empty()) { audioDev = SDL_OpenAudioDevice(startDevice.c_str(), 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (audioDev <= 0) { - WLOG("Failed to open audio device: %s", startDevice.c_str()); + WARN_LOG(AUDIO, "Failed to open audio device: %s", startDevice.c_str()); } } if (audioDev <= 0) { - ILOG("SDL: Trying a different device"); + INFO_LOG(AUDIO, "SDL: Trying a different audio device"); audioDev = SDL_OpenAudioDevice(nullptr, 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); } if (audioDev <= 0) { - ELOG("Failed to open audio: %s", SDL_GetError()); + ERROR_LOG(AUDIO, "Failed to open audio device: %s", SDL_GetError()); } else { if (g_retFmt.samples != fmt.samples) // Notify, but still use it - ELOG("Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); + ERROR_LOG(AUDIO, "Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); if (g_retFmt.format != fmt.format || g_retFmt.channels != fmt.channels) { - ELOG("Sound buffer format does not match requested format."); - ELOG("Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); - ELOG("Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); - ELOG("Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); - ELOG("Provided output format does not match requirement, turning audio off"); + ERROR_LOG(AUDIO, "Sound buffer format does not match requested format."); + ERROR_LOG(AUDIO, "Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); + ERROR_LOG(AUDIO, "Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); + ERROR_LOG(AUDIO, "Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); + ERROR_LOG(AUDIO, "Provided output format does not match requirement, turning audio off"); SDL_CloseAudioDevice(audioDev); } SDL_PauseAudioDevice(audioDev, 0); @@ -206,7 +205,7 @@ void LaunchBrowser(const char *url) { webWifiCreate(&conf, NULL, url, uuid, 0); webWifiShow(&conf, NULL); #elif defined(MOBILE_DEVICE) - ILOG("Would have gone to %s but LaunchBrowser is not implemented on this platform", url); + INFO_LOG(SYSTEM, "Would have gone to %s but LaunchBrowser is not implemented on this platform", url); #elif defined(_WIN32) std::wstring wurl = ConvertUTF8ToWString(url); ShellExecute(NULL, L"open", wurl.c_str(), NULL, NULL, SW_SHOWNORMAL); @@ -217,7 +216,7 @@ void LaunchBrowser(const char *url) { std::string command = std::string("xdg-open ") + url; int err = system(command.c_str()); if (err) { - ILOG("Would have gone to %s but xdg-utils seems not to be installed", url) + INFO_LOG(SYSTEM, "Would have gone to %s but xdg-utils seems not to be installed", url); } #endif } @@ -229,7 +228,7 @@ void LaunchMarket(const char *url) { webWifiCreate(&conf, NULL, url, uuid, 0); webWifiShow(&conf, NULL); #elif defined(MOBILE_DEVICE) - ILOG("Would have gone to %s but LaunchMarket is not implemented on this platform", url); + INFO_LOG(SYSTEM, "Would have gone to %s but LaunchMarket is not implemented on this platform", url); #elif defined(_WIN32) std::wstring wurl = ConvertUTF8ToWString(url); ShellExecute(NULL, L"open", wurl.c_str(), NULL, NULL, SW_SHOWNORMAL); @@ -240,14 +239,14 @@ void LaunchMarket(const char *url) { std::string command = std::string("xdg-open ") + url; int err = system(command.c_str()); if (err) { - ILOG("Would have gone to %s but xdg-utils seems not to be installed", url) + INFO_LOG(SYSTEM, "Would have gone to %s but xdg-utils seems not to be installed", url); } #endif } void LaunchEmail(const char *email_address) { #if defined(MOBILE_DEVICE) - ILOG("Would have opened your email client for %s but LaunchEmail is not implemented on this platform", email_address); + INFO_LOG(SYSTEM, "Would have opened your email client for %s but LaunchEmail is not implemented on this platform", email_address); #elif defined(_WIN32) std::wstring mailto = std::wstring(L"mailto:") + ConvertUTF8ToWString(email_address); ShellExecute(NULL, L"open", mailto.c_str(), NULL, NULL, SW_SHOWNORMAL); @@ -258,7 +257,7 @@ void LaunchEmail(const char *email_address) { std::string command = std::string("xdg-email ") + email_address; int err = system(command.c_str()); if (err) { - ILOG("Would have gone to %s but xdg-utils seems not to be installed", email_address) + INFO_LOG(SYSTEM, "Would have gone to %s but xdg-utils seems not to be installed", email_address); } #endif } @@ -284,12 +283,19 @@ std::string System_GetProperty(SystemProperty prop) { // Set c and c++ strings back to POSIX std::locale::global(std::locale("POSIX")); if (!locale.empty()) { + // Technically, this is an opaque string, but try to find the locale code. + size_t messagesPos = locale.find("LC_MESSAGES="); + if (messagesPos != std::string::npos) { + messagesPos += strlen("LC_MESSAGES="); + size_t semi = locale.find(';', messagesPos); + locale = locale.substr(messagesPos, semi - messagesPos); + } + if (locale.find("_", 0) != std::string::npos) { if (locale.find(".", 0) != std::string::npos) { return locale.substr(0, locale.find(".",0)); - } else { - return locale; } + return locale; } } return "en_US"; @@ -473,6 +479,10 @@ int main(int argc, char *argv[]) { putenv((char*)"SDL_VIDEO_CENTERED=1"); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); +#ifdef SDL_HINT_TOUCH_MOUSE_EVENTS + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); +#endif + if (VulkanMayBeAvailable()) { printf("DEBUG: Vulkan might be available.\n"); } else { @@ -687,7 +697,7 @@ int main(int argc, char *argv[]) { snprintf(iconPath, PATH_MAX, "%sassets/icon_regular_72.png", SDL_GetBasePath() ? SDL_GetBasePath() : ""); int width = 0, height = 0; unsigned char *imageData; - if (pngLoad(iconPath, &width, &height, &imageData, false) == 1) { + if (pngLoad(iconPath, &width, &height, &imageData) == 1) { SDL_Surface *surface = SDL_CreateRGBSurface(0, width, height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); memcpy(surface->pixels, imageData, width*height*4); @@ -776,19 +786,18 @@ int main(int argc, char *argv[]) { case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_SIZE_CHANGED: // better than RESIZED, more general - case SDL_WINDOWEVENT_MAXIMIZED: - case SDL_WINDOWEVENT_RESTORED: { + int new_width = event.window.data1; + int new_height = event.window.data2; + windowHidden = false; Core_NotifyWindowHidden(windowHidden); Uint32 window_flags = SDL_GetWindowFlags(window); bool fullscreen = (window_flags & SDL_WINDOW_FULLSCREEN); - if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { - UpdateScreenScale(event.window.data1, event.window.data2); - } - NativeMessageReceived("gpu_resized", ""); + // This one calls NativeResized if the size changed. + UpdateScreenScale(new_width, new_height); // Set variable here in case fullscreen was toggled by hotkey g_Config.bFullScreen = fullscreen; @@ -858,68 +867,56 @@ int main(int argc, char *argv[]) { NativeKey(key); break; } -#if !SDL_VERSION_ATLEAST(2, 0, 10) // This behavior doesn't feel right on a macbook with a touchpad. #if !PPSSPP_PLATFORM(MAC) case SDL_FINGERMOTION: { SDL_GetWindowSize(window, &w, &h); - touchEvent.type = SDL_MOUSEMOTION; - touchEvent.motion.type = SDL_MOUSEMOTION; - touchEvent.motion.timestamp = event.tfinger.timestamp; - touchEvent.motion.windowID = SDL_GetWindowID(window); - touchEvent.motion.state = SDL_GetMouseState(NULL, NULL); - touchEvent.motion.x = event.tfinger.x * w; - touchEvent.motion.y = event.tfinger.y * h; - - SDL_WarpMouseInWindow(window, event.tfinger.x * w, event.tfinger.y * h); - - SDL_PushEvent(&touchEvent); + TouchInput input; + input.id = event.tfinger.fingerId; + input.x = event.tfinger.x * w; + input.y = event.tfinger.y * h; + input.flags = TOUCH_MOVE; + input.timestamp = event.tfinger.timestamp; + NativeTouch(input); break; } case SDL_FINGERDOWN: { SDL_GetWindowSize(window, &w, &h); - touchEvent.type = SDL_MOUSEBUTTONDOWN; - touchEvent.button.type = SDL_MOUSEBUTTONDOWN; - touchEvent.button.timestamp = SDL_GetTicks(); - touchEvent.button.windowID = SDL_GetWindowID(window); - touchEvent.button.button = SDL_BUTTON_LEFT; - touchEvent.button.state = SDL_PRESSED; - touchEvent.button.clicks = 1; - touchEvent.button.x = event.tfinger.x * w; - touchEvent.button.y = event.tfinger.y * h; + TouchInput input; + input.id = event.tfinger.fingerId; + input.x = event.tfinger.x * w; + input.y = event.tfinger.y * h; + input.flags = TOUCH_DOWN; + input.timestamp = event.tfinger.timestamp; + NativeTouch(input); - touchEvent.motion.type = SDL_MOUSEMOTION; - touchEvent.motion.timestamp = SDL_GetTicks(); - touchEvent.motion.windowID = SDL_GetWindowID(window); - touchEvent.motion.x = event.tfinger.x * w; - touchEvent.motion.y = event.tfinger.y * h; - // Any real mouse cursor should also move - SDL_WarpMouseInWindow(window, event.tfinger.x * w, event.tfinger.y * h); - // First finger down event also has to be a motion to that position - SDL_PushEvent(&touchEvent); - touchEvent.motion.type = SDL_MOUSEBUTTONDOWN; - // Now we push the mouse button event - SDL_PushEvent(&touchEvent); + KeyInput key; + key.deviceId = DEVICE_ID_MOUSE; + key.keyCode = NKCODE_EXT_MOUSEBUTTON_1; + key.flags = KEY_DOWN; + NativeKey(key); break; } case SDL_FINGERUP: { SDL_GetWindowSize(window, &w, &h); - touchEvent.type = SDL_MOUSEBUTTONUP; - touchEvent.button.type = SDL_MOUSEBUTTONUP; - touchEvent.button.timestamp = SDL_GetTicks(); - touchEvent.button.windowID = SDL_GetWindowID(window); - touchEvent.button.button = SDL_BUTTON_LEFT; - touchEvent.button.state = SDL_RELEASED; - touchEvent.button.clicks = 1; - touchEvent.button.x = event.tfinger.x * w; - touchEvent.button.y = event.tfinger.y * h; - SDL_PushEvent(&touchEvent); + TouchInput input; + input.id = event.tfinger.fingerId; + input.x = event.tfinger.x * w; + input.y = event.tfinger.y * h; + input.flags = TOUCH_UP; + input.timestamp = event.tfinger.timestamp; + NativeTouch(input); + + KeyInput key; + key.deviceId = DEVICE_ID_MOUSE; + key.keyCode = NKCODE_EXT_MOUSEBUTTON_1; + key.flags = KEY_UP; + NativeKey(key); break; } -#endif #endif case SDL_MOUSEBUTTONDOWN: switch (event.button.button) { @@ -1125,7 +1122,6 @@ int main(int argc, char *argv[]) { ToggleFullScreenIfFlagSet(window); // Simple throttling to not burn the GPU in the menu. - time_update(); if (GetUIState() != UISTATE_INGAME || !PSP_IsInited() || renderThreadPaused) { double diffTime = time_now_d() - startTime; int sleepTime = (int)(1000.0 / 60.0) - (int)(diffTime * 1000.0); @@ -1133,7 +1129,6 @@ int main(int argc, char *argv[]) { sleep_ms(sleepTime); } - time_update(); framecount++; } @@ -1157,6 +1152,7 @@ int main(int argc, char *argv[]) { // Destroys Draw, which is used in NativeShutdown to shutdown. graphicsContext->ShutdownFromRenderThread(); + graphicsContext->Shutdown(); delete graphicsContext; if (audioDev > 0) { @@ -1169,7 +1165,7 @@ int main(int argc, char *argv[]) { #endif glslang::FinalizeProcess(); - ILOG("Leaving main"); + printf("Leaving main"); #ifdef HAVE_LIBNX socketExit(); #endif diff --git a/SDL/SDLVulkanGraphicsContext.cpp b/SDL/SDLVulkanGraphicsContext.cpp index 02123b105d..d8cf460bfc 100644 --- a/SDL/SDLVulkanGraphicsContext.cpp +++ b/SDL/SDLVulkanGraphicsContext.cpp @@ -1,17 +1,35 @@ #include "Core/Config.h" #include "Core/ConfigValues.h" -#include "base/NativeApp.h" -#include "base/display.h" -#include "thin3d/thin3d.h" -#include "thin3d/thin3d_create.h" -#include "util/text/parsers.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/Data/Text/Parsers.h" #include "Core/System.h" #include "SDLVulkanGraphicsContext.h" + #if defined(VK_USE_PLATFORM_METAL_EXT) #include "SDLCocoaMetalLayer.h" #endif +#ifdef _DEBUG +static const bool g_Validate = true; +#else +static const bool g_Validate = false; +#endif + +static uint32_t FlagsFromConfig() { + uint32_t flags = 0; + flags = g_Config.bVSync ? VULKAN_FLAG_PRESENT_FIFO : VULKAN_FLAG_PRESENT_MAILBOX; + if (g_Validate) { + flags |= VULKAN_FLAG_VALIDATE; + } + return flags; +} + bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) { window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode); if (!window) { @@ -33,8 +51,8 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, } vulkan_ = new VulkanContext(); - int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX; - // vulkanFlags |= VULKAN_FLAG_VALIDATE; + int vulkanFlags = FlagsFromConfig(); + VulkanContext::CreateInfo info{}; info.app_name = "PPSSPP"; info.app_ver = gitVer.ToInteger(); @@ -91,7 +109,7 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, break; } - if (!vulkan_->InitObjects()) { + if (!vulkan_->InitSwapchain()) { *error_message = vulkan_->InitError(); Shutdown(); return false; @@ -100,9 +118,12 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, draw_ = Draw::T3DCreateVulkanContext(vulkan_, false); SetGPUBackend(GPUBackend::VULKAN); bool success = draw_->CreatePresets(); - assert(success); + _assert_(success); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + renderManager_ = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + renderManager_->SetInflightFrames(g_Config.iInflightFrames); + return true; } @@ -112,11 +133,26 @@ void SDLVulkanGraphicsContext::Shutdown() { delete draw_; draw_ = nullptr; vulkan_->WaitUntilQueueIdle(); - vulkan_->DestroyObjects(); + vulkan_->DestroySwapchain(); + vulkan_->DestroySurface(); vulkan_->DestroyDevice(); - vulkan_->DestroyDebugMsgCallback(); vulkan_->DestroyInstance(); delete vulkan_; vulkan_ = nullptr; finalize_glslang(); } + +void SDLVulkanGraphicsContext::Resize() { + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + vulkan_->DestroySwapchain(); + vulkan_->UpdateFlags(FlagsFromConfig()); + vulkan_->InitSwapchain(); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); +} + +void SDLVulkanGraphicsContext::Poll() { + // Check for existing swapchain to avoid issues during shutdown. + if (vulkan_->GetSwapchain() && renderManager_->NeedsSwapchainRecreate()) { + Resize(); + } +} diff --git a/SDL/SDLVulkanGraphicsContext.h b/SDL/SDLVulkanGraphicsContext.h index 6ecfecfe1e..d654212342 100644 --- a/SDL/SDLVulkanGraphicsContext.h +++ b/SDL/SDLVulkanGraphicsContext.h @@ -2,10 +2,12 @@ #include "SDL_syswm.h" #include "Common/GraphicsContext.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanDebug.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanDebug.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" + +class VulkanRenderManager; class SDLVulkanGraphicsContext : public GraphicsContext { public: @@ -22,13 +24,9 @@ public: // We don't do it this way. } - void Resize() override { - draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - vulkan_->DestroyObjects(); - vulkan_->ReinitSurface(); - vulkan_->InitObjects(); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - } + void Resize() override; + + void Poll() override; void SwapInterval(int interval) override { } @@ -42,5 +40,5 @@ public: private: Draw::DrawContext *draw_ = nullptr; VulkanContext *vulkan_ = nullptr; - VulkanLogOptions g_LogOptions; + VulkanRenderManager *renderManager_ = nullptr; }; diff --git a/UI/BackgroundAudio.cpp b/UI/BackgroundAudio.cpp index f5bdd81da4..ba03df8ca2 100644 --- a/UI/BackgroundAudio.cpp +++ b/UI/BackgroundAudio.cpp @@ -1,183 +1,208 @@ #include #include -#include "base/logging.h" -#include "base/timeutil.h" -#include "file/chunk_file.h" +#include "Common/File/VFS/VFS.h" +#include "Common/UI/Root.h" #include "Common/CommonTypes.h" +#include "Common/Data/Format/RIFF.h" +#include "Common/Log.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/TimeUtil.h" +#include "Common/Data/Collections/FixedSizeQueue.h" #include "Core/HW/SimpleAudioDec.h" #include "Core/HLE/__sceAudio.h" -#include "Common/FixedSizeQueue.h" #include "GameInfoCache.h" #include "Core/Config.h" +#include "UI/BackgroundAudio.h" + +struct WavData { + int num_channels = -1; + int sample_rate = -1; + int numFrames = -1; + int samplesPerSec = -1; + int avgBytesPerSec = -1; + int raw_offset_loop_start = 0; + int raw_offset_loop_end = 0; + int loop_start_offset = 0; + int loop_end_offset = 0; + int codec = 0; + int raw_bytes_per_frame = 0; + uint8_t *raw_data = nullptr; + int raw_data_size = 0; + u8 at3_extradata[16]; + + void Read(RIFFReader &riff); + + ~WavData() { + free(raw_data); + raw_data = nullptr; + } +}; + +void WavData::Read(RIFFReader &file_) { + // If we have no loop start info, we'll just loop the entire audio. + raw_offset_loop_start = 0; + raw_offset_loop_end = 0; + + if (file_.Descend('RIFF')) { + file_.ReadInt(); //get past 'WAVE' + if (file_.Descend('fmt ')) { //enter the format chunk + int temp = file_.ReadInt(); + int format = temp & 0xFFFF; + switch (format) { + case 0xFFFE: + codec = PSP_CODEC_AT3PLUS; + break; + case 0x270: + codec = PSP_CODEC_AT3; + break; + case 1: + // Raw wave data, no codec + codec = 0; + break; + default: + ERROR_LOG(SCEAUDIO, "Unexpected wave format %04x", format); + return; + } + + num_channels = temp >> 16; + + samplesPerSec = file_.ReadInt(); + /*avgBytesPerSec =*/ file_.ReadInt(); + + temp = file_.ReadInt(); + raw_bytes_per_frame = temp & 0xFFFF; + + if (codec == PSP_CODEC_AT3) { + // The first two bytes are actually not a useful part of the extradata. + // We already read 16 bytes, so make sure there's enough left. + if (file_.GetCurrentChunkSize() >= 32) { + file_.ReadData(at3_extradata, 16); + } else { + memset(at3_extradata, 0, sizeof(at3_extradata)); + } + } + file_.Ascend(); + // INFO_LOG(AUDIO, "got fmt data: %i", samplesPerSec); + } else { + ERROR_LOG(AUDIO, "Error - no format chunk in wav"); + file_.Ascend(); + return; + } + + if (file_.Descend('smpl')) { + std::vector smplData; + smplData.resize(file_.GetCurrentChunkSize()); + file_.ReadData(&smplData[0], (int)smplData.size()); + + int numLoops = *(int *)&smplData[28]; + struct AtracLoopInfo { + int cuePointID; + int type; + int startSample; + int endSample; + int fraction; + int playCount; + }; + + if (numLoops > 0 && smplData.size() >= 36 + sizeof(AtracLoopInfo) * numLoops) { + AtracLoopInfo *loops = (AtracLoopInfo *)&smplData[36]; + int samplesPerFrame = codec == PSP_CODEC_AT3PLUS ? 2048 : 1024; + + for (int i = 0; i < numLoops; ++i) { + // Only seen forward loops, so let's ignore others. + if (loops[i].type != 0) + continue; + + // We ignore loop interpolation (fraction) and play count for now. + raw_offset_loop_start = (loops[i].startSample / samplesPerFrame) * raw_bytes_per_frame; + loop_start_offset = loops[i].startSample % samplesPerFrame; + raw_offset_loop_end = (loops[i].endSample / samplesPerFrame) * raw_bytes_per_frame; + loop_end_offset = loops[i].endSample % samplesPerFrame; + + if (loops[i].playCount == 0) { + // This was an infinite loop, so ignore the rest. + // In practice, there's usually only one and it's usually infinite. + break; + } + } + } + + file_.Ascend(); + } + + // enter the data chunk + if (file_.Descend('data')) { + int numBytes = file_.GetCurrentChunkSize(); + numFrames = numBytes / raw_bytes_per_frame; // numFrames + + raw_data = (uint8_t *)malloc(numBytes); + raw_data_size = numBytes; + if (num_channels == 1 || num_channels == 2) { + file_.ReadData(raw_data, numBytes); + } else { + ERROR_LOG(AUDIO, "Error - bad blockalign or channels"); + free(raw_data); + raw_data = nullptr; + return; + } + file_.Ascend(); + } else { + ERROR_LOG(AUDIO, "Error - no data chunk in wav"); + file_.Ascend(); + return; + } + file_.Ascend(); + } else { + ERROR_LOG(AUDIO, "Could not descend into RIFF file."); + return; + } + sample_rate = samplesPerSec; +} // Really simple looping in-memory AT3 player that also takes care of reading the file format. // Turns out that AT3 files used for this are modified WAVE files so fairly easy to parse. class AT3PlusReader { public: - AT3PlusReader(const std::string &data) + explicit AT3PlusReader(const std::string &data) : file_((const uint8_t *)&data[0], (int32_t)data.size()) { // Normally 8k but let's be safe. buffer_ = new short[32 * 1024]; - int codec = PSP_CODEC_AT3PLUS; - u8 at3_extradata[16]; + skip_next_samples_ = 0; - int num_channels, sample_rate, numFrames, samplesPerSec, avgBytesPerSec, Nothing; - if (file_.Descend('RIFF')) { - file_.ReadInt(); //get past 'WAVE' - if (file_.Descend('fmt ')) { //enter the format chunk - int temp = file_.ReadInt(); - int format = temp & 0xFFFF; - switch (format) { - case 0xFFFE: - codec = PSP_CODEC_AT3PLUS; - break; - case 0x270: - codec = PSP_CODEC_AT3; - break; - default: - ERROR_LOG(SCEAUDIO, "Unexpected SND0.AT3 format %04x", format); - return; - } + wave_.Read(file_); - num_channels = temp >> 16; - - samplesPerSec = file_.ReadInt(); - avgBytesPerSec = file_.ReadInt(); - - temp = file_.ReadInt(); - raw_bytes_per_frame_ = temp & 0xFFFF; - Nothing = temp >> 16; - - // Not currently used, but part of the format. - (void)avgBytesPerSec; - (void)Nothing; - - if (codec == PSP_CODEC_AT3) { - // The first two bytes are actually not a useful part of the extradata. - // We already read 16 bytes, so make sure there's enough left. - if (file_.GetCurrentChunkSize() >= 32) { - file_.ReadData(at3_extradata, 16); - } else { - memset(at3_extradata, 0, sizeof(at3_extradata)); - } - } - file_.Ascend(); - // ILOG("got fmt data: %i", samplesPerSec); - } else { - ELOG("Error - no format chunk in wav"); - file_.Ascend(); - return; - } - - // If we have no loop info, we'll just loop the entire audio. - raw_offset_loop_start_ = 0; - raw_offset_loop_end_ = 0; - skip_next_samples_ = 0; - - if (file_.Descend('smpl')) { - std::vector smplData; - smplData.resize(file_.GetCurrentChunkSize()); - file_.ReadData(&smplData[0], (int)smplData.size()); - - int numLoops = *(int *)&smplData[28]; - struct AtracLoopInfo { - int cuePointID; - int type; - int startSample; - int endSample; - int fraction; - int playCount; - }; - - if (numLoops > 0 && smplData.size() >= 36 + sizeof(AtracLoopInfo) * numLoops) { - AtracLoopInfo *loops = (AtracLoopInfo *)&smplData[36]; - int samplesPerFrame = codec == PSP_CODEC_AT3PLUS ? 2048 : 1024; - - for (int i = 0; i < numLoops; ++i) { - // Only seen forward loops, so let's ignore others. - if (loops[i].type != 0) - continue; - - // We ignore loop interpolation (fraction) and play count for now. - raw_offset_loop_start_ = (loops[i].startSample / samplesPerFrame) * raw_bytes_per_frame_; - loop_start_offset_ = loops[i].startSample % samplesPerFrame; - raw_offset_loop_end_ = (loops[i].endSample / samplesPerFrame) * raw_bytes_per_frame_; - loop_end_offset_ = loops[i].endSample % samplesPerFrame; - - if (loops[i].playCount == 0) { - // This was an infinite loop, so ignore the rest. - // In practice, there's usually only one and it's usually infinite. - break; - } - } - } - - file_.Ascend(); - } - - if (file_.Descend('data')) { //enter the data chunk - int numBytes = file_.GetCurrentChunkSize(); - numFrames = numBytes / raw_bytes_per_frame_; // numFrames - - raw_data_ = (uint8_t *)malloc(numBytes); - raw_data_size_ = numBytes; - if (num_channels == 1 || num_channels == 2) { - file_.ReadData(raw_data_, numBytes); - } else { - ELOG("Error - bad blockalign or channels"); - free(raw_data_); - raw_data_ = nullptr; - return; - } - file_.Ascend(); - } else { - ELOG("Error - no data chunk in wav"); - file_.Ascend(); - return; - } - file_.Ascend(); - } else { - ELOG("Could not descend into RIFF file. Data size=%d", (int32_t)data.size()); - return; + decoder_ = new SimpleAudio(wave_.codec, wave_.sample_rate, wave_.num_channels); + if (wave_.codec == PSP_CODEC_AT3) { + decoder_->SetExtraData(&wave_.at3_extradata[2], 14, wave_.raw_bytes_per_frame); } - sample_rate = samplesPerSec; - decoder_ = new SimpleAudio(codec, sample_rate, num_channels); - if (codec == PSP_CODEC_AT3) { - decoder_->SetExtraData(&at3_extradata[2], 14, raw_bytes_per_frame_); - } - ILOG("read ATRAC, frames: %i, rate %i", numFrames, sample_rate); + INFO_LOG(AUDIO, "read ATRAC, frames: %d, rate %d", wave_.numFrames, wave_.sample_rate); } ~AT3PlusReader() { - } - - void Shutdown() { - free(raw_data_); - raw_data_ = nullptr; delete[] buffer_; buffer_ = nullptr; delete decoder_; decoder_ = nullptr; } - bool IsOK() { return raw_data_ != nullptr; } + bool IsOK() { return wave_.raw_data != nullptr; } bool Read(int *buffer, int len) { - if (!raw_data_) + if (!wave_.raw_data) return false; while (bgQueue.size() < (size_t)(len * 2)) { int outBytes = 0; - decoder_->Decode(raw_data_ + raw_offset_, raw_bytes_per_frame_, (uint8_t *)buffer_, &outBytes); + decoder_->Decode(wave_.raw_data + raw_offset_, wave_.raw_bytes_per_frame, (uint8_t *)buffer_, &outBytes); if (!outBytes) return false; - if (raw_offset_loop_end_ != 0 && raw_offset_ == raw_offset_loop_end_) { + if (wave_.raw_offset_loop_end != 0 && raw_offset_ == wave_.raw_offset_loop_end) { // Only take the remaining bytes, but convert to stereo s16. - outBytes = std::min(outBytes, loop_end_offset_ * 4); + outBytes = std::min(outBytes, wave_.loop_end_offset * 4); } int start = skip_next_samples_; @@ -187,16 +212,16 @@ public: bgQueue.push(buffer_[i]); } - if (raw_offset_loop_end_ != 0 && raw_offset_ == raw_offset_loop_end_) { + if (wave_.raw_offset_loop_end != 0 && raw_offset_ == wave_.raw_offset_loop_end) { // Time to loop. Account for the addition below. - raw_offset_ = raw_offset_loop_start_ - raw_bytes_per_frame_; + raw_offset_ = wave_.raw_offset_loop_start - wave_.raw_bytes_per_frame; // This time we're counting each stereo sample. - skip_next_samples_ = loop_start_offset_ * 2; + skip_next_samples_ = wave_.loop_start_offset * 2; } // Handle loops when there's no loop info. - raw_offset_ += raw_bytes_per_frame_; - if (raw_offset_ >= raw_data_size_) { + raw_offset_ += wave_.raw_bytes_per_frame; + if (raw_offset_ >= wave_.raw_data_size) { raw_offset_ = 0; } } @@ -209,123 +234,179 @@ public: private: RIFFReader file_; - uint8_t *raw_data_ = nullptr; - int raw_data_size_ = 0; + + WavData wave_; + int raw_offset_ = 0; - int raw_bytes_per_frame_; - int raw_offset_loop_start_ = 0; - int raw_offset_loop_end_ = 0; - int loop_start_offset_ = 0; - int loop_end_offset_ = 0; int skip_next_samples_ = 0; FixedSizeQueue bgQueue; short *buffer_ = nullptr; SimpleAudio *decoder_ = nullptr; }; -static std::mutex g_bgMutex; -static std::string bgGamePath; -static int playbackOffset; -static AT3PlusReader *at3Reader; -static double gameLastChanged; -static double lastPlaybackTime; -static int buffer[44100]; -static bool fadingOut = true; -static float volume; -static float delta = -0.0001f; +BackgroundAudio g_BackgroundAudio; -static void ClearBackgroundAudio(bool hard) { - if (!hard) { - fadingOut = true; - volume = 1.0f; - return; - } - if (at3Reader) { - at3Reader->Shutdown(); - delete at3Reader; - at3Reader = nullptr; - } - playbackOffset = 0; +BackgroundAudio::BackgroundAudio() { + buffer = new int[BUFSIZE](); } -void SetBackgroundAudioGame(const std::string &path) { - time_update(); +BackgroundAudio::~BackgroundAudio() { + delete[] buffer; +} - std::lock_guard lock(g_bgMutex); - if (path == bgGamePath) { +BackgroundAudio::Sample *BackgroundAudio::LoadSample(const std::string &path) { + size_t bytes; + uint8_t *data = VFSReadFile(path.c_str(), &bytes); + if (!data) { + return nullptr; + } + + RIFFReader reader(data, (int)bytes); + + WavData wave; + wave.Read(reader); + + delete [] data; + + if (wave.num_channels != 2 || wave.sample_rate != 44100 || wave.raw_bytes_per_frame != 4) { + ERROR_LOG(AUDIO, "Wave format not supported for mixer playback. Must be 16-bit raw stereo. '%s'", path.c_str()); + return nullptr; + } + + int16_t *samples = new int16_t[2 * wave.numFrames]; + memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame); + + return new BackgroundAudio::Sample(samples, wave.numFrames); +} + +void BackgroundAudio::LoadSamples() { + samples_.resize((size_t)UI::UISound::COUNT); + samples_[(size_t)UI::UISound::BACK] = std::unique_ptr(LoadSample("sfx_back.wav")); + samples_[(size_t)UI::UISound::SELECT] = std::unique_ptr(LoadSample("sfx_select.wav")); + samples_[(size_t)UI::UISound::CONFIRM] = std::unique_ptr(LoadSample("sfx_confirm.wav")); + samples_[(size_t)UI::UISound::TOGGLE_ON] = std::unique_ptr(LoadSample("sfx_toggle_on.wav")); + samples_[(size_t)UI::UISound::TOGGLE_OFF] = std::unique_ptr(LoadSample("sfx_toggle_off.wav")); + + UI::SetSoundCallback([](UI::UISound sound) { + g_BackgroundAudio.PlaySFX(sound); + }); +} + +void BackgroundAudio::PlaySFX(UI::UISound sfx) { + std::lock_guard lock(mutex_); + plays_.push_back(PlayInstance{ sfx, 0, 64, false }); +} + +void BackgroundAudio::Clear(bool hard) { + if (!hard) { + fadingOut_ = true; + volume_ = 1.0f; + return; + } + if (at3Reader_) { + delete at3Reader_; + at3Reader_ = nullptr; + } + playbackOffset_ = 0; +} + +void BackgroundAudio::SetGame(const std::string &path) { + std::lock_guard lock(mutex_); + if (path == bgGamePath_) { // Do nothing return; } if (path.size() == 0) { - ClearBackgroundAudio(false); - fadingOut = true; + Clear(false); + fadingOut_ = true; } else { - ClearBackgroundAudio(true); - gameLastChanged = time_now_d(); - fadingOut = false; + Clear(true); + gameLastChanged_ = time_now_d(); + fadingOut_ = false; } - volume = 1.0f; - bgGamePath = path; + volume_ = 1.0f; + bgGamePath_ = path; } -int PlayBackgroundAudio() { - time_update(); - - std::lock_guard lock(g_bgMutex); +int BackgroundAudio::Play() { + std::lock_guard lock(mutex_); // Immediately stop the sound if it is turned off while playing. if (!g_Config.bEnableSound) { - ClearBackgroundAudio(true); + Clear(true); __PushExternalAudio(0, 0); return 0; } - double now = time_now(); - if (at3Reader) { - int sz = lastPlaybackTime <= 0.0 ? 44100 / 60 : (int)((now - lastPlaybackTime) * 44100); - sz = std::min((int)ARRAY_SIZE(buffer) / 2, sz); + double now = time_now_d(); + int sz = lastPlaybackTime_ <= 0.0 ? 44100 / 60 : (int)((now - lastPlaybackTime_) * 44100); + sz = std::min(BUFSIZE / 2, sz); + if (at3Reader_) { if (sz >= 16) { - if (at3Reader->Read(buffer, sz)) { - if (!fadingOut) { - __PushExternalAudio(buffer, sz); - } else { + if (at3Reader_->Read(buffer, sz)) { + if (fadingOut_) { for (int i = 0; i < sz*2; i += 2) { - buffer[i] *= volume; - buffer[i + 1] *= volume; - volume += delta; - } - __PushExternalAudio(buffer, sz); - if (volume <= 0.0f) { - ClearBackgroundAudio(true); - fadingOut = false; - gameLastChanged = 0; + buffer[i] *= volume_; + buffer[i + 1] *= volume_; + volume_ += delta_; } } } - lastPlaybackTime = now; } } else { - __PushExternalAudio(0, 0); - lastPlaybackTime = now; + for (int i = 0; i < sz * 2; i += 2) { + buffer[i] = 0; + buffer[i + 1] = 0; + } } + // Mix in menu sound effects. Terribly slow mixer but meh. + if (!plays_.empty()) { + for (int i = 0; i < sz * 2; i += 2) { + std::vector::iterator iter = plays_.begin(); + while (iter != plays_.end()) { + PlayInstance inst = *iter; + auto sample = samples_[(int)inst.sound].get(); + if (!sample || iter->offset >= sample->length_) { + iter->done = true; + iter = plays_.erase(iter); + } else { + if (!iter->done) { + buffer[i] += sample->data_[inst.offset * 2] * inst.volume >> 8; + buffer[i + 1] += sample->data_[inst.offset * 2 + 1] * inst.volume >> 8; + } + iter->offset++; + iter++; + } + } + } + } + + __PushExternalAudio(buffer, sz); + + if (at3Reader_ && fadingOut_ && volume_ <= 0.0f) { + Clear(true); + fadingOut_ = false; + gameLastChanged_ = 0; + } + + lastPlaybackTime_ = now; + return 0; } -// Stuff that should be on the UI thread only, like anything to do with -// g_gameInfoCache. -void UpdateBackgroundAudio() { +void BackgroundAudio::Update() { // If there's a game, and some time has passed since the selected game // last changed... (to prevent crazy amount of reads when skipping through a list) - if (bgGamePath.size() && (time_now_d() - gameLastChanged > 0.5)) { - std::lock_guard lock(g_bgMutex); - if (!at3Reader) { + if (bgGamePath_.size() && (time_now_d() - gameLastChanged_ > 0.5)) { + std::lock_guard lock(mutex_); + if (!at3Reader_) { // Grab some audio from the current game and play it. if (!g_gameInfoCache) return; - std::shared_ptr gameInfo = g_gameInfoCache->GetInfo(NULL, bgGamePath, GAMEINFO_WANTSND); + std::shared_ptr gameInfo = g_gameInfoCache->GetInfo(NULL, bgGamePath_, GAMEINFO_WANTSND); if (!gameInfo) return; @@ -336,8 +417,8 @@ void UpdateBackgroundAudio() { if (gameInfo->sndFileData.size()) { const std::string &data = gameInfo->sndFileData; - at3Reader = new AT3PlusReader(data); - lastPlaybackTime = 0.0; + at3Reader_ = new AT3PlusReader(data); + lastPlaybackTime_ = 0.0; } } } diff --git a/UI/BackgroundAudio.h b/UI/BackgroundAudio.h index 5d9ae1e040..fb572f52a7 100644 --- a/UI/BackgroundAudio.h +++ b/UI/BackgroundAudio.h @@ -1,7 +1,63 @@ #pragma once #include +#include +#include -void SetBackgroundAudioGame(const std::string &path); -int PlayBackgroundAudio(); -void UpdateBackgroundAudio(); +#include "Common/UI/Root.h" + +class AT3PlusReader; + +class BackgroundAudio { +public: + BackgroundAudio(); + ~BackgroundAudio(); + + void Clear(bool hard); + void SetGame(const std::string &path); + void Update(); + int Play(); + + void LoadSamples(); + void PlaySFX(UI::UISound sfx); + +private: + enum { + BUFSIZE = 44100, + }; + + std::mutex mutex_; + std::string bgGamePath_; + int playbackOffset_ = 0; + AT3PlusReader *at3Reader_; + double gameLastChanged_ = 0.0; + double lastPlaybackTime_ = 0.0; + int *buffer = nullptr; + bool fadingOut_ = true; + float volume_ = 0.0f; + float delta_ = -0.0001f; + + struct PlayInstance { + UI::UISound sound; + int offset; + int volume; // 0..255 + bool done; + }; + + struct Sample { + // data must be new-ed. + Sample(int16_t *data, int length) : data_(data), length_(length) {} + ~Sample() { + delete[] data_; + } + int16_t *data_; + int length_; // stereo samples. + }; + + static Sample *LoadSample(const std::string &path); + + std::vector plays_; + std::vector> samples_; +}; + +extern BackgroundAudio g_BackgroundAudio; diff --git a/UI/ChatScreen.cpp b/UI/ChatScreen.cpp index aa5478befe..c09d92708a 100644 --- a/UI/ChatScreen.cpp +++ b/UI/ChatScreen.cpp @@ -1,18 +1,19 @@ -#include "ppsspp_config.h" -#include "ui/root.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "ui/ui.h" -#include "ChatScreen.h" -#include "Core/Config.h" -#include "Core/Host.h" -#include "Core/System.h" -#include "Common/LogManager.h" -#include "Core/HLE/proAdhoc.h" -#include "i18n/i18n.h" #include -#include "util/text/utf8.h" +#include "ppsspp_config.h" + +#include "Common/UI/Root.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/UI/UI.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/System/System.h" +#include "Core/Config.h" +#include "Core/System.h" +#include "Core/HLE/proAdhoc.h" +#include "UI/ChatScreen.h" void ChatMenu::CreatePopupContents(UI::ViewGroup *parent) { using namespace UI; @@ -23,7 +24,7 @@ void ChatMenu::CreatePopupContents(UI::ViewGroup *parent) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(SDL) chatEdit_ = bottom->Add(new TextEdit("", n->T("Chat Here"), new LinearLayoutParams(1.0))); #if defined(USING_WIN_UI) - //freeze the ui when using ctrl + C hotkey need workaround + // freeze the ui when using ctrl + C hotkey need workaround if (g_Config.bBypassOSKWithKeyboard && !g_Config.bFullScreen) { System_InputBoxGetString(n->T("Chat"), n->T("Chat Here"), [](bool result, const std::string &value) { if (result) { @@ -159,47 +160,12 @@ UI::EventReturn ChatMenu::OnQuickChat5(UI::EventParams &e) { return UI::EVENT_DONE; } -/* - maximum chat length in one message from server is only 64 character - need to split the chat to fit the static chat screen size - if the chat screen size become dynamic from device resolution - we need to change split function logic also. -*/ -std::vector Split(const std::string& str) -{ - std::vector ret; - int counter = 0; - int firstSentenceEnd = 0; - int secondSentenceEnd = 0; - int spliton = 45; - - for (int i = 0; i<(int)str.length(); i++) { - if (isspace(str[i])) { - if (i < spliton) { - if(str[i-1]!=':') - firstSentenceEnd = i+1; - } - else if (i > spliton) { - firstSentenceEnd = spliton; - } - } - } - - if (firstSentenceEnd == 0) { - firstSentenceEnd = spliton; - } - ret.push_back(str.substr(0, firstSentenceEnd)); - ret.push_back(str.substr(firstSentenceEnd)); - return ret; -} - void ChatMenu::UpdateChat() { using namespace UI; if (chatVert_ != nullptr) { chatVert_->Clear(); //read Access violation is proadhoc.cpp use NULL_->Clear() pointer? std::vector chatLog = getChatLog(); for (auto i : chatLog) { - //split long text uint32_t namecolor = 0x29B6F6; uint32_t textcolor = 0xFFFFFF; uint32_t infocolor = 0xFDD835; @@ -213,25 +179,16 @@ void ChatMenu::UpdateChat() { } if (i.length() <= displayname.length() || i[displayname.length()] != ':') { - TextView *v = chatVert_->Add(new TextView(i, FLAG_DYNAMIC_ASCII, true)); + TextView *v = chatVert_->Add(new TextView(i, ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); v->SetTextColor(0xFF000000 | infocolor); } else { LinearLayout *line = chatVert_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, FILL_PARENT))); - TextView *nameView = line->Add(new TextView(displayname, FLAG_DYNAMIC_ASCII, true)); + line->SetSpacing(0.0f); + TextView *nameView = line->Add(new TextView(displayname, ALIGN_LEFT, true, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 0.0f))); nameView->SetTextColor(0xFF000000 | namecolor); - if (chattext.length() > 45) { - std::vector splitted = Split(chattext); - std::string one = splitted[0]; - std::string two = splitted[1]; - TextView *oneview = line->Add(new TextView(one, FLAG_DYNAMIC_ASCII, true)); - oneview->SetTextColor(0xFF000000 | textcolor); - TextView *twoview = chatVert_->Add(new TextView(two, FLAG_DYNAMIC_ASCII, true)); - twoview->SetTextColor(0xFF000000 | textcolor); - } - else { - TextView *chatView = line->Add(new TextView(chattext, FLAG_DYNAMIC_ASCII, true)); - chatView->SetTextColor(0xFF000000 | textcolor); - } + + TextView *chatView = line->Add(new TextView(chattext, ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f))); + chatView->SetTextColor(0xFF000000 | textcolor); } } toBottom_ = true; diff --git a/UI/ChatScreen.h b/UI/ChatScreen.h index ff67d8ce2c..48fe7165f1 100644 --- a/UI/ChatScreen.h +++ b/UI/ChatScreen.h @@ -1,8 +1,7 @@ #pragma once #include "ppsspp_config.h" -#include "file/file_util.h" -#include "ui/ui_screen.h" +#include "Common/UI/UIScreen.h" class ChatMenu : public PopupScreen { public: diff --git a/UI/ComboKeyMappingScreen.cpp b/UI/ComboKeyMappingScreen.cpp index e309ba35b3..d5742c575a 100644 --- a/UI/ComboKeyMappingScreen.cpp +++ b/UI/ComboKeyMappingScreen.cpp @@ -15,21 +15,23 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "TouchControlVisibilityScreen.h" +#include "Common/System/Display.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/File/PathBrowser.h" +#include "Common/Math/curves.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" #include "Core/Config.h" -#include "i18n/i18n.h" -#include "ComboKeyMappingScreen.h" -#include "base/colorutil.h" -#include "base/display.h" -#include "base/timeutil.h" -#include "file/path.h" -#include "gfx_es2/draw_buffer.h" -#include "gfx/texture_atlas.h" -#include "math/curves.h" -#include "base/stringutil.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" + +#include "TouchControlVisibilityScreen.h" +#include "UI/ComboKeyMappingScreen.h" void ComboKeyScreen::CreateViews() { using namespace UI; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 0652c656f3..0859c52f63 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -19,23 +19,24 @@ #include #include -#include "base/colorutil.h" -#include "base/logging.h" -#include "base/display.h" -#include "gfx/texture_atlas.h" -#include "i18n/i18n.h" -#include "input/keycodes.h" -#include "input/input_state.h" -#include "ui/root.h" -#include "ui/ui.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/UI/Root.h" +#include "Common/UI/UI.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/Log.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Input/InputState.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Core/KeyMap.h" #include "Core/Host.h" #include "Core/HLE/sceCtrl.h" #include "Core/System.h" -#include "Common/KeyMap.h" #include "Core/Config.h" #include "UI/ControlMappingScreen.h" #include "UI/GameSettingsScreen.h" @@ -582,7 +583,7 @@ bool TouchTestScreen::touch(const TouchInput &touch) { bool found = false; for (int i = 0; i < MAX_TOUCH_POINTS; i++) { if (touches_[i].id == touch.id) { - WLOG("Double touch"); + WARN_LOG(SYSTEM, "Double touch"); touches_[i].x = touch.x; touches_[i].y = touch.y; found = true; @@ -609,7 +610,7 @@ bool TouchTestScreen::touch(const TouchInput &touch) { } } if (!found) { - WLOG("Move without touch down: %d", touch.id); + WARN_LOG(SYSTEM, "Move without touch down: %d", touch.id); } } if (touch.flags & TOUCH_UP) { @@ -622,7 +623,7 @@ bool TouchTestScreen::touch(const TouchInput &touch) { } } if (!found) { - WLOG("Touch release without touch down"); + WARN_LOG(SYSTEM, "Touch release without touch down"); } } return true; diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index 3d7b6879e5..d9f7776fd4 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -22,10 +22,10 @@ #include #include -#include "i18n/i18n.h" -#include "ui/view.h" -#include "ui/ui_screen.h" +#include "Common/UI/View.h" +#include "Common/UI/UIScreen.h" +#include "Common/Data/Text/I18n.h" #include "UI/MiscScreens.h" class ControlMapper; diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 1695a0aa21..65c7e07644 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -15,12 +15,14 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "ext/cityhash/city.h" -#include "i18n/i18n.h" -#include "ui/ui.h" -#include "util/text/utf8.h" +#include "ext/xxhash.h" +#include "Common/UI/UI.h" -#include "Common/FileUtil.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/File/FileUtil.h" +#include "Common/StringUtils.h" +#include "Common/System/System.h" #include "Core/Core.h" #include "Core/Config.h" #include "Core/CwCheat.h" @@ -61,7 +63,7 @@ void CwCheatScreen::LoadCheatInfo() { // We won't parse this, just using it to detect changes to the file. std::string str; if (readFileToString(true, engine_->CheatFilename().c_str(), str)) { - fileCheckHash_ = CityHash64(str.c_str(), str.size()); + fileCheckHash_ = XXH3_64bits(str.c_str(), str.size()); } fileCheckCounter_ = 0; @@ -118,7 +120,7 @@ void CwCheatScreen::update() { // Check if the file has changed. If it has, we'll reload. std::string str; if (readFileToString(true, engine_->CheatFilename().c_str(), str)) { - uint64_t newHash = CityHash64(str.c_str(), str.size()); + uint64_t newHash = XXH3_64bits(str.c_str(), str.size()); if (newHash != fileCheckHash_) { // This will update the hash. RecreateViews(); diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index a0bd4ed190..dd545da301 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -18,9 +18,9 @@ #include #include -#include "ui/view.h" -#include "ui/ui_screen.h" -#include "ui/ui_context.h" +#include "Common/UI/View.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/Context.h" #include "UI/MiscScreens.h" struct CheatFileInfo; diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index f993d5aa34..937859af6e 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -17,17 +17,21 @@ #include -#include "base/display.h" -#include "gfx_es2/gpu_features.h" -#include "i18n/i18n.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "ui/ui.h" -#include "profiler/profiler.h" +#include "ppsspp_config.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Data/Text/I18n.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/UI/UI.h" +#include "Common/Profiler/Profiler.h" #include "Common/LogManager.h" #include "Common/CPUDetect.h" +#include "Common/StringUtils.h" #include "Core/MemMap.h" #include "Core/Config.h" @@ -48,12 +52,8 @@ #ifdef _WIN32 #include "Common/CommonWindows.h" // Want to avoid including the full header here as it includes d3dx.h -#if PPSSPP_API(D3DX9) -int GetD3DXVersion(); -#elif PPSSPP_API(D3D9_D3DCOMPILER) int GetD3DCompilerVersion(); #endif -#endif static const char *logLevelList[] = { "Notice", @@ -457,7 +457,7 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new ItemHeader(si->T("CPU Information"))); deviceSpecs->Add(new InfoItem(si->T("CPU Name", "Name"), cpu_info.brand_string)); -#if defined(ARM) || defined(ARM64) || defined(MIPS) +#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) || PPSSPP_ARCH(MIPS) || PPSSPP_ARCH(MIPS64) deviceSpecs->Add(new InfoItem(si->T("Cores"), StringFromInt(cpu_info.num_cores))); #else int totalThreads = cpu_info.num_cores * cpu_info.logical_cpu_count; @@ -481,11 +481,7 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem(si->T("Driver Version"), System_GetProperty(SYSPROP_GPUDRIVER_VERSION))); #if !PPSSPP_PLATFORM(UWP) if (GetGPUBackend() == GPUBackend::DIRECT3D9) { -#if PPSSPP_API(D3DX9) - deviceSpecs->Add(new InfoItem(si->T("D3DX Version"), StringFromFormat("%d", GetD3DXVersion()))); -#elif PPSSPP_API(D3D9_D3DCOMPILER) deviceSpecs->Add(new InfoItem(si->T("D3DCompiler Version"), StringFromFormat("%d", GetD3DCompilerVersion()))); -#endif } #endif #endif diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 8b98b022c6..28e8c38bda 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -23,9 +23,8 @@ #include #include -#include "file/file_util.h" -#include "i18n/i18n.h" -#include "ui/ui_screen.h" +#include "Common/Data/Text/I18n.h" +#include "Common/UI/UIScreen.h" #include "UI/MiscScreens.h" #include "GPU/Common/ShaderCommon.h" @@ -182,3 +181,4 @@ private: }; void DrawProfile(UIContext &ui); +const char *GetCompilerABI(); diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index f8006763c1..52c40cbd62 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -1,12 +1,11 @@ #include -#include #include "ppsspp_config.h" #include "Common/Log.h" #include "Core/Config.h" #include "DiscordIntegration.h" -#include "i18n/i18n.h" +#include "Common/Data/Text/I18n.h" #if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(LINUX)) && !PPSSPP_PLATFORM(ANDROID) && !PPSSPP_PLATFORM(UWP) @@ -50,8 +49,8 @@ bool Discord::IsEnabled() const { } void Discord::Init() { - assert(IsEnabled()); - assert(!initialized_); + _assert_(IsEnabled()); + _assert_(!initialized_); #ifdef ENABLE_DISCORD DiscordEventHandlers eventHandlers{}; diff --git a/UI/DisplayLayoutEditor.cpp b/UI/DisplayLayoutEditor.cpp index 77da5f407e..f6556ca39a 100644 --- a/UI/DisplayLayoutEditor.cpp +++ b/UI/DisplayLayoutEditor.cpp @@ -16,7 +16,8 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "ui/ui_context.h" + +#include "Common/UI/Context.h" #include "UI/DisplayLayoutEditor.h" void MultiTouchDisplay::GetContentDimensions(const UIContext &dc, float &w, float &h) const { diff --git a/UI/DisplayLayoutEditor.h b/UI/DisplayLayoutEditor.h index 6cdd7a454d..6855c127ca 100644 --- a/UI/DisplayLayoutEditor.h +++ b/UI/DisplayLayoutEditor.h @@ -17,10 +17,10 @@ #pragma once -#include "gfx/texture_atlas.h" -#include "gfx_es2/draw_buffer.h" -#include "ui/view.h" -#include "ui/viewgroup.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" class MultiTouchDisplay : public UI::View { public: diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 5514cc5bbd..96b224c573 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -18,20 +18,21 @@ #include #include -#include "base/colorutil.h" -#include "base/display.h" -#include "gfx/texture_atlas.h" -#include "gfx_es2/draw_buffer.h" -#include "i18n/i18n.h" -#include "ui/ui_context.h" -#include "ui/view.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" -#include "DisplayLayoutScreen.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Data/Text/I18n.h" +#include "UI/DisplayLayoutScreen.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" #include "DisplayLayoutEditor.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" static const int leftColumnWidth = 200; static const float orgRatio = 1.764706f; @@ -84,7 +85,9 @@ private: }; DisplayLayoutScreen::DisplayLayoutScreen() { -}; + // Ignore insets - just couldn't get the logic to work. + ignoreInsets_ = true; +} bool DisplayLayoutScreen::touch(const TouchInput &touch) { UIScreen::touch(touch); @@ -253,11 +256,14 @@ void DisplayLayoutScreen::CreateViews() { // This makes it have at least 10.0f padding below at 1x. const float vertBoundariesHeight = 52.0f; + // We manually implement insets here for the buttons. This file defied refactoring :( + float leftInset = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT); + // Left side, right, top, bottom. - root_->Add(new Boundary(new AnchorLayoutParams(horizBoundariesWidth, FILL_PARENT, NONE, 0, horizPreviewPadding + previewWidth, 0))); + root_->Add(new Boundary(new AnchorLayoutParams(horizBoundariesWidth, FILL_PARENT, horizPreviewPadding - horizBoundariesWidth, 0, NONE, 0))); root_->Add(new Boundary(new AnchorLayoutParams(horizBoundariesWidth, FILL_PARENT, horizPreviewPadding + previewWidth, 0, NONE, 0))); root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding - vertBoundariesHeight, NONE, NONE))); - root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, NONE, NONE, vertPreviewPadding - vertBoundariesHeight))); + root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding + previewHeight, NONE, NONE))); bool displayRotEnable = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) || g_Config.bSoftwareRendering; bRotated_ = false; @@ -290,16 +296,16 @@ void DisplayLayoutScreen::CreateViews() { g_Config.fSmallDisplayOffsetX = 0.5f; g_Config.fSmallDisplayOffsetY = 0.5f; } else { // Manual Scaling - Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 74)); + Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 74)); center->OnClick.Handle(this, &DisplayLayoutScreen::OnCenter); root_->Add(center); float minZoom = 1.0f; if (g_dpi_scale_x > 1.0f) { minZoom /= g_dpi_scale_x; } - PopupSliderChoiceFloat *zoomlvl = new PopupSliderChoiceFloat(&g_Config.fSmallDisplayZoomLevel, minZoom, 10.0f, di->T("Zoom"), 1.0f, screenManager(), di->T("* PSP res"), new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10 + 64 + 64)); + PopupSliderChoiceFloat *zoomlvl = new PopupSliderChoiceFloat(&g_Config.fSmallDisplayZoomLevel, minZoom, 10.0f, di->T("Zoom"), 1.0f, screenManager(), di->T("* PSP res"), new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); root_->Add(zoomlvl); - mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158 + 64 + 10)); + mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); mode_->AddChoice(di->T("Move")); mode_->AddChoice(di->T("Resize")); mode_->SetSelection(0); @@ -359,7 +365,7 @@ void DisplayLayoutScreen::CreateViews() { }); root_->Add(rotation); - Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10)); + Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10)); back->OnClick.Handle(this, &UIScreen::OnBack); root_->Add(back); } diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 1a38ea706f..9db82c612c 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -17,8 +17,8 @@ #pragma once -#include "ui/view.h" -#include "ui/viewgroup.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" #include "MiscScreens.h" #include diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index f9293d2c78..c4f9cdfc33 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -19,25 +19,25 @@ #include -#include "base/display.h" -#include "base/logging.h" -#include "base/timeutil.h" -#include "profiler/profiler.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Render/Text/draw_text.h" -#include "gfx/texture_atlas.h" -#include "gfx_es2/gpu_features.h" -#include "gfx_es2/draw_text.h" +#include "Common/UI/Root.h" +#include "Common/UI/UI.h" +#include "Common/UI/Context.h" +#include "Common/UI/Tween.h" +#include "Common/UI/View.h" -#include "input/input_state.h" -#include "math/curves.h" -#include "ui/root.h" -#include "ui/ui.h" -#include "ui/ui_context.h" -#include "ui/ui_tween.h" -#include "ui/view.h" -#include "i18n/i18n.h" - -#include "Common/KeyMap.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Input/InputState.h" +#include "Common/Log.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Math/curves.h" +#include "Common/TimeUtil.h" #ifndef MOBILE_DEVICE #include "Core/AVIDump.h" @@ -48,11 +48,12 @@ #include "Core/CoreParameter.h" #include "Core/Core.h" #include "Core/Host.h" +#include "Core/KeyMap.h" #include "Core/Reporting.h" #include "Core/System.h" #include "GPU/GPUState.h" #include "GPU/GPUInterface.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #if !PPSSPP_PLATFORM(UWP) #include "GPU/Vulkan/DebugVisVulkan.h" #endif @@ -77,7 +78,6 @@ #include "UI/ControlMappingScreen.h" #include "UI/DisplayLayoutScreen.h" #include "UI/GameSettingsScreen.h" -#include "UI/InstallZipScreen.h" #include "UI/ProfilerDraw.h" #include "UI/DiscordIntegration.h" #include "UI/ChatScreen.h" @@ -136,7 +136,9 @@ EmuScreen::EmuScreen(const std::string &filename) frameStep_ = false; lastNumFlips = gpuStats.numFlips; startDumping = false; + // Make sure we don't leave it at powerdown after the last game. + // TODO: This really should be handled elsewhere if it isn't. if (coreState == CORE_POWERDOWN) coreState = CORE_STEPPING; @@ -192,7 +194,7 @@ void EmuScreen::bootGame(const std::string &filename) { return; } - SetBackgroundAudioGame(""); + g_BackgroundAudio.SetGame(""); // Check permission status first, in case we came from a shortcut. if (!bootAllowStorage(filename)) @@ -403,7 +405,7 @@ void EmuScreen::sendMessage(const char *message, const char *value) { std::string resetError; if (!PSP_InitStart(PSP_CoreParameter(), &resetError)) { - ELOG("Error resetting: %s", resetError.c_str()); + ERROR_LOG(LOADER, "Error resetting: %s", resetError.c_str()); stopRender_ = true; screenManager()->switchScreen(new MainScreen()); System_SendMessage("event", "failstartgame"); @@ -878,7 +880,7 @@ void EmuScreen::pspKey(int pspKeyCode, int flags) { onVKeyUp(pspKeyCode); } } else { - // ILOG("pspKey %i %i", pspKeyCode, flags); + // INFO_LOG(SYSTEM, "pspKey %i %i", pspKeyCode, flags); if (flags & KEY_DOWN) __CtrlButtonDown(pspKeyCode); if (flags & KEY_UP) @@ -1050,6 +1052,7 @@ void EmuScreen::CreateViews() { cardboardDisableButton_ = root_->Add(new Button(sc->T("Cardboard VR OFF"), new AnchorLayoutParams(bounds.centerX(), NONE, NONE, 30, true))); cardboardDisableButton_->OnClick.Handle(this, &EmuScreen::OnDisableCardboard); cardboardDisableButton_->SetVisibility(V_GONE); + cardboardDisableButton_->SetScale(0.65f); // make it smaller - this button can be in the way otherwise. if (g_Config.bEnableNetworkChat) { switch (g_Config.iChatButtonPosition) { @@ -1112,7 +1115,6 @@ void EmuScreen::CreateViews() { loadingSpinner->SetTag("LoadingSpinner"); // Don't really need this, and it creates a lot of strings to translate... - // Maybe just show "Loading game..." only? loadingTextView->SetVisibility(V_GONE); loadingTextView->SetShadow(true); @@ -1179,19 +1181,11 @@ void EmuScreen::update() { PSP_CoreParameter().pixelHeight = pixel_yres * bounds.h / dp_yres; #endif - if (!invalid_) { + if (!invalid_ && coreState != CORE_RUNTIME_ERROR) { UpdateUIState(UISTATE_INGAME); } if (errorMessage_.size()) { - // Special handling for ZIP files. It's not very robust to check an error message but meh, - // at least it's pre-translation. - if (errorMessage_.find("ZIP") != std::string::npos) { - screenManager()->push(new InstallZipScreen(gamePath_)); - errorMessage_ = ""; - quit_ = true; - return; - } auto err = GetI18NCategory("Error"); std::string errLoadingFile = gamePath_ + "\n"; errLoadingFile.append(err->T("Error loading file", "Could not load game")); @@ -1261,7 +1255,7 @@ void EmuScreen::checkPowerDown() { if (PSP_IsInited()) { PSP_Shutdown(); } - ILOG("SELF-POWERDOWN!"); + INFO_LOG(SYSTEM, "SELF-POWERDOWN!"); screenManager()->switchScreen(new MainScreen()); bootPending_ = false; invalid_ = true; @@ -1286,6 +1280,67 @@ static void DrawDebugStats(DrawBuffer *draw2d, const Bounds &bounds) { draw2d->SetFontScale(1.0f, 1.0f); } +static void DrawCrashDump(DrawBuffer *draw2d) { + const ExceptionInfo &info = Core_GetExceptionInfo(); + + FontID ubuntu24("UBUNTU24"); + char statbuf[4096]; + char versionString[256]; + snprintf(versionString, sizeof(versionString), "%s", PPSSPP_GIT_VERSION); + + // TODO: Draw a lot more information. Full register set, and so on. + +#ifdef _DEBUG + char build[] = "Debug"; +#else + char build[] = "Release"; +#endif + snprintf(statbuf, sizeof(statbuf), R"(%s +Game ID (Title): %s (%s) +PPSSPP build: %s (%s) +ABI: %s +)", + ExceptionTypeAsString(info.type), + g_paramSFO.GetDiscID().c_str(), + g_paramSFO.GetValueString("TITLE").c_str(), + versionString, + build, + GetCompilerABI() + ); + + draw2d->SetFontScale(.7f, .7f); + int x = 20; + int y = 50; + draw2d->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF); + y += 100; + + if (info.type == ExceptionType::MEMORY) { + snprintf(statbuf, sizeof(statbuf), R"( +Access: %s at %08x +PC: %08x +%s)", + MemoryExceptionTypeAsString(info.memory_type), + info.address, + info.pc, + info.info.c_str()); + draw2d->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF); + y += 180; + } else if (info.type == ExceptionType::BAD_EXEC_ADDR) { + snprintf(statbuf, sizeof(statbuf), R"( +Destination: %s to %08x +PC: %08x)", + ExecExceptionTypeAsString(info.exec_type), + info.address, + info.pc); + draw2d->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF); + y += 120; + } + + std::string kernelState = __KernelStateSummary(); + + draw2d->DrawTextShadow(ubuntu24, kernelState.c_str(), x, y, 0xFFFFFFFF); +} + static void DrawAudioDebugStats(DrawBuffer *draw2d, const Bounds &bounds) { FontID ubuntu24("UBUNTU24"); char statbuf[4096] = { 0 }; @@ -1362,9 +1417,9 @@ void EmuScreen::preRender() { if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) { // We need to clear here already so that drawing during the frame is done on a clean slate. if (Core_IsStepping() && gpuStats.numFlips != 0) { - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }); + draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer"); } else { - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }); + draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer"); } Viewport viewport; @@ -1403,18 +1458,20 @@ void EmuScreen::render() { // It's possible this might be set outside PSP_RunLoopFor(). // In this case, we need to double check it here. checkPowerDown(); - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid"); renderUI(); return; } + // Freeze-frame functionality (loads a savestate on every frame). if (PSP_CoreParameter().freezeNext) { PSP_CoreParameter().frozen = true; PSP_CoreParameter().freezeNext = false; SaveState::SaveToRam(freezeState_); } else if (PSP_CoreParameter().frozen) { - if (CChunkFileReader::ERROR_NONE != SaveState::LoadFromRam(freezeState_)) { - ERROR_LOG(SAVESTATE, "Failed to load freeze state. Unfreezing."); + std::string errorString; + if (CChunkFileReader::ERROR_NONE != SaveState::LoadFromRam(freezeState_, &errorString)) { + ERROR_LOG(SAVESTATE, "Failed to load freeze state (%s). Unfreezing.", errorString.c_str()); PSP_CoreParameter().frozen = false; } } @@ -1426,23 +1483,39 @@ void EmuScreen::render() { PSP_RunLoopWhileState(); // Hopefully coreState is now CORE_NEXTFRAME - if (coreState == CORE_NEXTFRAME) { - // set back to running for the next frame + switch (coreState) { + case CORE_NEXTFRAME: + // Reached the end of the frame, all good. Set back to running for the next frame coreState = CORE_RUNNING; - } else if (coreState == CORE_STEPPING) { - // If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output. - // This won't work in non-buffered, but that's fine. - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }); - // Just to make sure. - if (PSP_IsInited()) { - gpu->CopyDisplayToOutput(true); + break; + case CORE_STEPPING: + case CORE_RUNTIME_ERROR: + { + // If there's an exception, display information. + const ExceptionInfo &info = Core_GetExceptionInfo(); + if (info.type != ExceptionType::NONE) { + // Clear to blue background screen + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, 0xFF900000 }, "EmuScreen_RuntimeError"); + // The info is drawn later in renderUI + } else { + // If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output. + // This won't work in non-buffered, but that's fine. + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); + // Just to make sure. + if (PSP_IsInited()) { + gpu->CopyDisplayToOutput(true); + } } - } else { + break; + } + default: // Didn't actually reach the end of the frame, ran out of the blockTicks cycles. // In this case we need to bind and wipe the backbuffer, at least. // It's possible we never ended up outputted anything - make sure we have the backbuffer cleared - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame"); + break; } + checkPowerDown(); PSP_EndHostFrame(); @@ -1451,28 +1524,11 @@ void EmuScreen::render() { if (hasVisibleUI()) { // In most cases, this should already be bound and a no-op. - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_UI"); cardboardDisableButton_->SetVisibility(g_Config.bEnableCardboardVR ? UI::V_VISIBLE : UI::V_GONE); screenManager()->getUIContext()->BeginFrame(); renderUI(); } - - // We have no use for backbuffer depth or stencil, so let tiled renderers discard them after tiling. - /* - if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) { - GLenum attachments[2] = { GL_DEPTH, GL_STENCIL }; - glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); - } else if (!gl_extensions.GLES3) { -#ifdef USING_GLES2 - // Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it? - bool hasDiscard = gl_extensions.EXT_discard_framebuffer; // TODO - if (hasDiscard) { - //const GLenum targets[3] = { GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT }; - //glDiscardFramebufferEXT(GL_FRAMEBUFFER, 3, targets); - } -#endif - } - */ } bool EmuScreen::hasVisibleUI() { @@ -1487,6 +1543,11 @@ bool EmuScreen::hasVisibleUI() { if (g_Config.bShowDebugStats || g_Config.bShowDeveloperMenu || g_Config.bShowAudioDebug || g_Config.bShowFrameProfiler || g_Config.bSimpleFrameStats) return true; + // Exception information. + if (coreState == CORE_RUNTIME_ERROR || coreState == CORE_STEPPING) { + return true; + } + return false; } @@ -1510,7 +1571,7 @@ void EmuScreen::renderUI() { DrawBuffer *draw2d = ctx->Draw(); if (root_) { - UI::LayoutViewHierarchy(*ctx, root_); + UI::LayoutViewHierarchy(*ctx, root_, false); root_->Draw(*ctx); } @@ -1544,6 +1605,14 @@ void EmuScreen::renderUI() { if ((g_Config.bShowFrameProfiler || g_Config.bSimpleFrameStats) && !invalid_) { DrawProfile(*ctx); } + + if (coreState == CORE_RUNTIME_ERROR || coreState == CORE_STEPPING) { + const ExceptionInfo &info = Core_GetExceptionInfo(); + if (info.type != ExceptionType::NONE) { + DrawCrashDump(draw2d); + } + } + ctx->Flush(); } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 9279944c6e..77a072f433 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -21,11 +21,11 @@ #include #include -#include "input/keycodes.h" -#include "ui/screen.h" -#include "ui/ui_screen.h" -#include "ui/ui_tween.h" -#include "Common/KeyMap.h" +#include "Common/Input/KeyCodes.h" +#include "Common/UI/Screen.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/Tween.h" +#include "Core/KeyMap.h" struct AxisInput; diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index dfad8aecb4..56547cd8b9 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -1,6 +1,6 @@ #include "GPUDriverTestScreen.h" -#include "i18n/i18n.h" -#include "ui/view.h" +#include "Common/Data/Text/I18n.h" +#include "Common/UI/View.h" static const std::vector fsDiscard = { {Draw::ShaderLanguage::GLSL_ES_200, @@ -24,7 +24,7 @@ static const std::vector fsDiscard = { })" }, {Draw::ShaderLanguage::GLSL_VULKAN, - R"(#version 140 + R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable layout(location = 0) in vec4 oColor0; diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h index bf5c56a02c..7f20ecab82 100644 --- a/UI/GPUDriverTestScreen.h +++ b/UI/GPUDriverTestScreen.h @@ -1,16 +1,14 @@ #pragma once -#include - -#include "base/display.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "ui/ui.h" +#include "Common/System/Display.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/UI/UI.h" #include "Common/LogManager.h" #include "UI/MiscScreens.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" class GPUDriverTestScreen : public UIDialogScreenWithBackground { public: diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 32c9684db0..c0cf42d56f 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -22,15 +22,12 @@ #include #include -#include "base/logging.h" -#include "base/timeutil.h" -#include "base/stringutil.h" -#include "file/file_util.h" -#include "file/zip_read.h" -#include "thin3d/thin3d.h" -#include "thread/prioritizedworkqueue.h" -#include "Common/FileUtil.h" +#include "Common/GPU/thin3d.h" +#include "Common/Thread/PrioritizedWorkQueue.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/FileUtil.h" #include "Common/StringUtils.h" +#include "Common/TimeUtil.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/FileSystems/DirectoryFileSystem.h" #include "Core/FileSystems/VirtualDiscFileSystem.h" @@ -634,7 +631,7 @@ handleELF: info_->pending = false; info_->working = false; - // ILOG("Completed writing info for %s", info_->GetTitle().c_str()); + // INFO_LOG(SYSTEM, "Completed writing info for %s", info_->GetTitle().c_str()); } float priority() override { @@ -789,7 +786,7 @@ void GameInfoCache::SetupTexture(std::shared_ptr &info, Draw::DrawCont using namespace Draw; if (tex.data.size()) { if (!tex.texture) { - tex.texture = CreateTextureFromFileData(thin3d, (const uint8_t *)tex.data.data(), (int)tex.data.size(), ImageFileType::DETECT); + tex.texture = CreateTextureFromFileData(thin3d, (const uint8_t *)tex.data.data(), (int)tex.data.size(), ImageFileType::DETECT, false, info->GetTitle().c_str()); if (tex.texture) { tex.timeLoaded = time_now_d(); } else { diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 565331c14a..8563d111f9 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -23,7 +23,6 @@ #include #include -#include "file/file_util.h" #include "Core/ELF/ParamSFO.h" #include "UI/TextureUtil.h" diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index f584f45faa..697a2145c9 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -18,13 +18,17 @@ #include #include "ppsspp_config.h" -#include "gfx_es2/draw_buffer.h" -#include "i18n/i18n.h" -#include "util/text/utf8.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "Common/FileUtil.h" + +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/File/FileUtil.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" #include "Core/Host.h" #include "Core/Config.h" #include "Core/System.h" @@ -38,7 +42,7 @@ #include "UI/BackgroundAudio.h" GameScreen::GameScreen(const std::string &gamePath) : UIDialogScreenWithGameBackground(gamePath) { - SetBackgroundAudioGame(gamePath); + g_BackgroundAudio.SetGame(gamePath); } GameScreen::~GameScreen() { @@ -47,8 +51,9 @@ GameScreen::~GameScreen() { void GameScreen::CreateViews() { std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); - if (info && !info->id.empty()) + if (info && !info->id.empty()) { saveDirs = info->GetSaveDataDirectories(); // Get's very heavy, let's not do it in update() + } auto di = GetI18NCategory("Dialog"); auto ga = GetI18NCategory("Game"); @@ -119,9 +124,7 @@ void GameScreen::CreateViews() { rightColumnItems->Add(btnDeleteSaveData_)->OnClick.Handle(this, &GameScreen::OnDeleteSaveData); btnDeleteSaveData_->SetVisibility(V_GONE); - if (info && !info->pending) { - otherChoices_.clear(); - } + otherChoices_.clear(); rightColumnItems->Add(AddOtherChoice(new Choice(ga->T("Delete Game"))))->OnClick.Handle(this, &GameScreen::OnDeleteGame); if (host->CanCreateShortcut()) { @@ -200,29 +203,35 @@ void GameScreen::render() { if (info->gameSize) { char temp[256]; - snprintf(temp, sizeof(temp), "%s: %1.1f %s", ga->T("Game"), (float) (info->gameSize) / 1024.f / 1024.f, ga->T("MB")); - tvGameSize_->SetText(temp); - snprintf(temp, sizeof(temp), "%s: %1.2f %s", ga->T("SaveData"), (float) (info->saveDataSize) / 1024.f / 1024.f, ga->T("MB")); - tvSaveDataSize_->SetText(temp); - if (info->installDataSize > 0) { + if (tvGameSize_) { + snprintf(temp, sizeof(temp), "%s: %1.1f %s", ga->T("Game"), (float)(info->gameSize) / 1024.f / 1024.f, ga->T("MB")); + tvGameSize_->SetText(temp); + } + if (tvSaveDataSize_) { + snprintf(temp, sizeof(temp), "%s: %1.2f %s", ga->T("SaveData"), (float)(info->saveDataSize) / 1024.f / 1024.f, ga->T("MB")); + tvSaveDataSize_->SetText(temp); + } + if (info->installDataSize > 0 && tvInstallDataSize_) { snprintf(temp, sizeof(temp), "%s: %1.2f %s", ga->T("InstallData"), (float) (info->installDataSize) / 1024.f / 1024.f, ga->T("MB")); tvInstallDataSize_->SetText(temp); tvInstallDataSize_->SetVisibility(UI::V_VISIBLE); } } - if (info->region >= 0 && info->region < GAMEREGION_MAX && info->region != GAMEREGION_OTHER) { - static const char *regionNames[GAMEREGION_MAX] = { - "Japan", - "USA", - "Europe", - "Hong Kong", - "Asia", - "Korea" - }; - tvRegion_->SetText(ga->T(regionNames[info->region])); - } else if (info->region > GAMEREGION_MAX){ - tvRegion_->SetText(ga->T("Homebrew")); + if (tvRegion_) { + if (info->region >= 0 && info->region < GAMEREGION_MAX && info->region != GAMEREGION_OTHER) { + static const char *regionNames[GAMEREGION_MAX] = { + "Japan", + "USA", + "Europe", + "Hong Kong", + "Asia", + "Korea" + }; + tvRegion_->SetText(ga->T(regionNames[info->region])); + } else if (info->region > GAMEREGION_MAX) { + tvRegion_->SetText(ga->T("Homebrew")); + } } if (!info->id.empty()) { diff --git a/UI/GameScreen.h b/UI/GameScreen.h index b68c7f28c2..2e7fa3f596 100644 --- a/UI/GameScreen.h +++ b/UI/GameScreen.h @@ -20,7 +20,7 @@ #include #include "UI/MiscScreens.h" -#include "ui/ui_screen.h" +#include "Common/UI/UIScreen.h" // Game screen: Allows you to start a game, delete saves, delete the game, // set game specific settings, etc. diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 798a5868ab..7216d628ea 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -17,21 +17,23 @@ #include "ppsspp_config.h" -#include "base/display.h" // Only to check screen aspect ratio with pixel_yres/pixel_xres +#include -#include "base/colorutil.h" -#include "base/stringutil.h" -#include "base/timeutil.h" -#include "math/curves.h" -#include "net/resolve.h" -#include "gfx_es2/gpu_features.h" -#include "gfx_es2/draw_buffer.h" -#include "i18n/i18n.h" -#include "util/text/utf8.h" -#include "ui/root.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "ui/ui_context.h" +#include "Common/Net/Resolve.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/Root.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/UI/Context.h" + +#include "Common/System/Display.h" // Only to check screen aspect ratio with pixel_yres/pixel_xres +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Math/curves.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Encoding/Utf8.h" #include "UI/EmuScreen.h" #include "UI/GameSettingsScreen.h" #include "UI/GameInfoCache.h" @@ -49,21 +51,25 @@ #include "UI/ComboKeyMappingScreen.h" #include "UI/GPUDriverTestScreen.h" -#include "Common/KeyMap.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" #include "Common/OSVersion.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Host.h" +#include "Core/KeyMap.h" +#include "Core/Instance.h" #include "Core/System.h" #include "Core/Reporting.h" #include "Core/TextureReplacer.h" #include "Core/WebServer.h" #include "Core/HLE/sceUsbCam.h" +#include "Core/HLE/sceUsbMic.h" #include "GPU/Common/PostShader.h" #include "android/jni/TestRunner.h" #include "GPU/GPUInterface.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) #pragma warning(disable:4091) // workaround bug in VS2015 headers @@ -72,6 +78,8 @@ #include "Windows/W32Util/ShellUtil.h" #endif +extern bool g_ShaderNameListChanged; + GameSettingsScreen::GameSettingsScreen(std::string gamePath, std::string gameID, bool editThenRestore) : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), enableReports_(false), editThenRestore_(editThenRestore) { lastVertical_ = UseVerticalLayout(); @@ -111,6 +119,21 @@ bool DoesBackendSupportHWTess() { } } +static bool UsingHardwareTextureScaling() { + // For now, Vulkan only. + return g_Config.bTexHardwareScaling && GetGPUBackend() == GPUBackend::VULKAN && !g_Config.bSoftwareRendering; +} + +static std::string TextureTranslateName(const char *value) { + auto ps = GetI18NCategory("TextureShaders"); + const TextureShaderInfo *info = GetTextureShaderInfo(value); + if (info) { + return ps->T(value, info ? info->name.c_str() : value); + } else { + return value; + } +} + static std::string PostShaderTranslateName(const char *value) { auto ps = GetI18NCategory("PostShaders"); const ShaderInfo *info = GetPostShaderInfo(value); @@ -214,6 +237,11 @@ void GameSettingsScreen::CreateViews() { renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D11); if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN)) renderingBackendChoice->HideChoice((int)GPUBackend::VULKAN); + + if (!IsFirstInstance()) { + // If we're not the first instance, can't save the setting, and it requires a restart, so... + renderingBackendChoice->SetEnabled(false); + } #endif Draw::DrawContext *draw = screenManager()->getDrawContext(); @@ -285,24 +313,51 @@ void GameSettingsScreen::CreateViews() { altSpeed2->SetZeroLabel(gr->T("Unlimited")); altSpeed2->SetNegativeDisable(gr->T("Disabled")); - graphicsSettings->Add(new ItemHeader(gr->T("Features"))); - postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sPostShaderName, gr->T("Postprocessing Shader"), &PostShaderTranslateName)); - postProcChoice_->OnClick.Handle(this, &GameSettingsScreen::OnPostProcShader); - postProcChoice_->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - }); + graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); - auto shaderChain = GetPostShaderChain(g_Config.sPostShaderName); - for (auto shaderInfo : shaderChain) { - for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { - auto &setting = shaderInfo->settings[i]; - if (!setting.name.empty()) { - auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; - graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + std::vector alreadyAddedShader; + for (int i = 0; i < g_Config.vPostShaderNames.size() && i < ARRAY_SIZE(shaderNames_); ++i) { + // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread + shaderNames_[i] = g_Config.vPostShaderNames[i]; + postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&shaderNames_[i], StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1), &PostShaderTranslateName)); + postProcChoice_->OnClick.Add([=](EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i); + procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange); + if (e.v) + procScreen->SetPopupOrigin(e.v); + screenManager()->push(procScreen); + return UI::EVENT_DONE; + }); + postProcChoice_->SetEnabledFunc([] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + }); + + auto shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + for (auto shaderInfo : shaderChain) { + // Disable duplicated shader slider + bool duplicated = std::find(alreadyAddedShader.begin(), alreadyAddedShader.end(), shaderInfo->section) != alreadyAddedShader.end(); + alreadyAddedShader.push_back(shaderInfo->section); + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; + if (duplicated) { + auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); + PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); + settingValue->SetEnabled(false); + } else { + PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetEnabledFunc([] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + }); + } + } } } } + graphicsSettings->Add(new ItemHeader(gr->T("Screen layout"))); #if !defined(MOBILE_DEVICE) graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { @@ -315,7 +370,16 @@ void GameSettingsScreen::CreateViews() { displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor"))); displayEditor_->OnClick.Handle(this, &GameSettingsScreen::OnDisplayLayoutEditor); -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(ANDROID) + // Hide insets option if no insets, or OS too old. + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 29 && + (System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) != 0.0f)) { + graphicsSettings->Add(new CheckBox(&g_Config.bIgnoreScreenInsets, gr->T("Ignore camera notch when centering"))); + } + // Hide Immersive Mode on pre-kitkat Android if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) { // Let's reuse the Fullscreen translation string from desktop. @@ -335,7 +399,7 @@ void GameSettingsScreen::CreateViews() { return !g_Config.bSoftwareRendering && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; }); -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(ANDROID) if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_TV) { static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" }; int max_res_temp = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2; @@ -348,7 +412,7 @@ void GameSettingsScreen::CreateViews() { #endif if (!g_Config.bSimpleUI) { -#ifdef _WIN32 +#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); vSync->OnClick.Add([=](EventParams &e) { NativeResized(); @@ -361,13 +425,13 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_CONTINUE; }); CheckBox *frameDuplication = graphicsSettings->Add(new CheckBox(&g_Config.bRenderDuplicateFrames, gr->T("Render duplicate frames to 60hz"))); - frameDuplication->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE || (g_Config.bSoftwareRendering && g_Config.iFrameSkip != 0); - }); frameDuplication->OnClick.Add([=](EventParams &e) { settingInfo_->Show(gr->T("RenderDuplicateFrames Tip", "Can make framerate smoother in games that run at lower framerates"), e.v); return UI::EVENT_CONTINUE; }); + frameDuplication->SetEnabledFunc([] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && g_Config.iFrameSkip == 0; + }); if (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::OPENGL) { static const char *bufferOptions[] = { "No buffer", "Up to 1", "Up to 2" }; @@ -395,6 +459,15 @@ void GameSettingsScreen::CreateViews() { return !g_Config.bSoftwareRendering && g_Config.bHardwareTransform; }); + CheckBox *clearHack = graphicsSettings->Add(new CheckBox(&g_Config.bClearFramebuffersOnFirstUseHack, gr->T("Clear Speedhack", "Clear framebuffers on first use (speedhack)"))); + clearHack->OnClick.Add([=](EventParams &e) { + settingInfo_->Show(gr->T("ClearSpeedhack Tip", "Sometimes faster (mostly on mobile devices), may cause glitches"), e.v); + return UI::EVENT_CONTINUE; + }); + clearHack->SetEnabledFunc([] { + return !g_Config.bSoftwareRendering; + }); + CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)"))); texBackoff->SetDisabledPtr(&g_Config.bSoftwareRendering); @@ -449,20 +522,17 @@ void GameSettingsScreen::CreateViews() { texScalingChoice->HideChoice(5); // 5x } texScalingChoice->OnChoice.Add([=](EventParams &e) { - if (g_Config.iTexScalingLevel != 1) { + if (g_Config.iTexScalingLevel != 1 && !UsingHardwareTextureScaling()) { settingInfo_->Show(gr->T("UpscaleLevel Tip", "CPU heavy - some scaling may be delayed to avoid stutter"), e.v); } return UI::EVENT_CONTINUE; }); - texScalingChoice->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering && (!g_Config.iGPUBackend == (int)GPUBackend::VULKAN || !g_Config.bTexHardwareScaling); - }); if (!g_Config.bSimpleUI) { static const char *texScaleAlgos[] = { "xBRZ", "Hybrid", "Bicubic", "Hybrid + Bicubic" }; PopupMultiChoice *texScalingType = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexScalingType, gr->T("Upscale Type"), texScaleAlgos, 0, ARRAY_SIZE(texScaleAlgos), gr->GetName(), screenManager())); - texScalingType->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering && (!g_Config.iGPUBackend == (int)GPUBackend::VULKAN || !g_Config.bTexHardwareScaling); + texScalingType->SetEnabledFunc([]() { + return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling(); }); CheckBox *deposterize = graphicsSettings->Add(new CheckBox(&g_Config.bTexDeposterize, gr->T("Deposterize"))); @@ -472,46 +542,43 @@ void GameSettingsScreen::CreateViews() { } return UI::EVENT_CONTINUE; }); - deposterize->SetDisabledPtr(&g_Config.bSoftwareRendering); + deposterize->SetEnabledFunc([]() { + return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling(); + }); + + ChoiceWithValueDisplay *textureShaderChoice = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sTextureShaderName, gr->T("Texture Shader"), &TextureTranslateName)); + textureShaderChoice->OnClick.Handle(this, &GameSettingsScreen::OnTextureShader); + textureShaderChoice->SetEnabledFunc([]() { + return GetGPUBackend() == GPUBackend::VULKAN && !g_Config.bSoftwareRendering; + }); - if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { - CheckBox* hardware4xBRZScaling = graphicsSettings->Add(new CheckBox(&g_Config.bTexHardwareScaling, gr->T("Hardware 4xBRZ Scaling(experimental)"))); - hardware4xBRZScaling->OnClick.Add([=](EventParams& e) { - if (g_Config.bTexHardwareScaling == true) { - settingInfo_->Show(gr->T("Hardware 4xBRZ Scaling Tip", "Apply 4xBRZ texture scaling filter with compute shader"), e.v); - } - return UI::EVENT_CONTINUE; - }); - hardware4xBRZScaling->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering; - }); - } else { - Choice* hardware4xBRZScaling = graphicsSettings->Add(new Choice(gr->T("Hardware 4xBRZ Scaling(experimental) requires Vulkan backend!"))); - hardware4xBRZScaling->SetEnabledFunc([] { - return false; - }); - } graphicsSettings->Add(new ItemHeader(gr->T("Texture Filtering"))); static const char *anisoLevels[] = { "Off", "2x", "4x", "8x", "16x" }; PopupMultiChoice *anisoFiltering = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAnisotropyLevel, gr->T("Anisotropic Filtering"), anisoLevels, 0, ARRAY_SIZE(anisoLevels), gr->GetName(), screenManager())); anisoFiltering->SetDisabledPtr(&g_Config.bSoftwareRendering); - static const char *texFilters[] = { "Auto", "Nearest", "Linear", "Linear on FMV", }; + static const char *texFilters[] = { "Auto", "Nearest", "Linear" }; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexFiltering, gr->T("Texture Filter"), texFilters, 1, ARRAY_SIZE(texFilters), gr->GetName(), screenManager())); static const char *bufFilters[] = { "Linear", "Nearest", }; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) - graphicsSettings->Add(new ItemHeader(gr->T("Cardboard VR Settings", "Cardboard VR Settings"))); - graphicsSettings->Add(new CheckBox(&g_Config.bEnableCardboardVR, gr->T("Enable Cardboard VR", "Enable Cardboard VR"))); - PopupSliderChoice *cardboardScreenSize = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardScreenSize, 30, 100, gr->T("Cardboard Screen Size", "Screen Size (in % of the viewport)"), 1, screenManager(), gr->T("% of viewport"))); - cardboardScreenSize->SetEnabledPtr(&g_Config.bEnableCardboardVR); - PopupSliderChoice *cardboardXShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardXShift, -100, 100, gr->T("Cardboard Screen X Shift", "X Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void"))); - cardboardXShift->SetEnabledPtr(&g_Config.bEnableCardboardVR); - PopupSliderChoice *cardboardYShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardYShift, -100, 100, gr->T("Cardboard Screen Y Shift", "Y Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void"))); - cardboardYShift->SetEnabledPtr(&g_Config.bEnableCardboardVR); + bool showCardboardSettings = true; +#else + // If you enabled it through the ini, you can see this. Useful for testing. + bool showCardboardSettings = g_Config.bEnableCardboardVR; #endif + if (showCardboardSettings) { + graphicsSettings->Add(new ItemHeader(gr->T("Cardboard VR Settings", "Cardboard VR Settings"))); + graphicsSettings->Add(new CheckBox(&g_Config.bEnableCardboardVR, gr->T("Enable Cardboard VR", "Enable Cardboard VR"))); + PopupSliderChoice *cardboardScreenSize = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardScreenSize, 30, 100, gr->T("Cardboard Screen Size", "Screen Size (in % of the viewport)"), 1, screenManager(), gr->T("% of viewport"))); + cardboardScreenSize->SetEnabledPtr(&g_Config.bEnableCardboardVR); + PopupSliderChoice *cardboardXShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardXShift, -100, 100, gr->T("Cardboard Screen X Shift", "X Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void"))); + cardboardXShift->SetEnabledPtr(&g_Config.bEnableCardboardVR); + PopupSliderChoice *cardboardYShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardYShift, -100, 100, gr->T("Cardboard Screen Y Shift", "Y Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void"))); + cardboardYShift->SetEnabledPtr(&g_Config.bEnableCardboardVR); + } std::vector cameraList = Camera::getDeviceList(); if (cameraList.size() >= 1) { @@ -571,6 +638,13 @@ void GameSettingsScreen::CreateViews() { } #endif + std::vector micList = Microphone::getDeviceList(); + if (micList.size() >= 1) { + audioSettings->Add(new ItemHeader(gr->T("Microphone"))); + PopupMultiChoiceDynamic *MicChoice = audioSettings->Add(new PopupMultiChoiceDynamic(&g_Config.sMicDevice, gr->T("Microphone Device"), micList, nullptr, screenManager())); + MicChoice->OnChoice.Handle(this, &GameSettingsScreen::OnMicDeviceChange); + } + #if defined(SDL) std::vector audioDeviceList; SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList); @@ -721,17 +795,26 @@ void GameSettingsScreen::CreateViews() { networkingSettingsScroll->Add(networkingSettings); tabHolder->AddTab(ms->T("Networking"), networkingSettingsScroll); - networkingSettings->Add(new ItemHeader(ms->T("Networking"))); + networkingSettings->Add(new ItemHeader(n->T("Networking"))); networkingSettings->Add(new Choice(n->T("Adhoc Multiplayer forum")))->OnClick.Handle(this, &GameSettingsScreen::OnAdhocGuides); networkingSettings->Add(new CheckBox(&g_Config.bEnableWlan, n->T("Enable networking", "Enable networking/wlan (beta)"))); + networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.sMACAddress, n->T("Change Mac Address"), (const char*)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeMacAddress); + static const char* wlanChannels[] = { "Auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11" }; + auto wlanChannelChoice = networkingSettings->Add(new PopupMultiChoice(&g_Config.iWlanAdhocChannel, n->T("WLAN Channel"), wlanChannels, 0, ARRAY_SIZE(wlanChannels), n->GetName(), screenManager())); + for (int i = 0; i < 4; i++) { + wlanChannelChoice->HideChoice(i + 2); + wlanChannelChoice->HideChoice(i + 7); + } - networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeproAdhocServerAddress); + networkingSettings->Add(new ItemHeader(n->T("AdHoc Server"))); networkingSettings->Add(new CheckBox(&g_Config.bEnableAdhocServer, n->T("Enable built-in PRO Adhoc Server", "Enable built-in PRO Adhoc Server"))); - networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.sMACAddress, n->T("Change Mac Address"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeMacAddress); - networkingSettings->Add(new PopupSliderChoice(&g_Config.iPortOffset, 0, 60000, n->T("Port offset", "Port offset(0 = PSP compatibility)"), 100, screenManager())); - networkingSettings->Add(new CheckBox(&g_Config.bMOHH2hack, n->T("Medal of Honor Heroes 2 hack", "Medal of Honor Heroes 2 hack"))); + networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address (localhost = multiple instance)"), (const char*)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeproAdhocServerAddress); + + networkingSettings->Add(new ItemHeader(n->T("UPnP (port-forwarding)"))); + networkingSettings->Add(new CheckBox(&g_Config.bEnableUPnP, n->T("Enable UPnP", "Enable UPnP (need a few seconds to detect)"))); + networkingSettings->Add(new CheckBox(&g_Config.bUPnPUseOriginalPort, n->T("UPnP use original port", "UPnP use original port (Enabled = PSP compatibility)")))->SetEnabledPtr(&g_Config.bEnableUPnP); networkingSettings->Add(new ItemHeader(n->T("Chat"))); networkingSettings->Add(new CheckBox(&g_Config.bEnableNetworkChat, n->T("Enable network chat", "Enable network chat"))); @@ -786,6 +869,11 @@ void GameSettingsScreen::CreateViews() { qc5->SetEnabledPtr(&g_Config.bEnableQuickChat); #endif + networkingSettings->Add(new ItemHeader(n->T("Misc (default = compatiblity)"))); + networkingSettings->Add(new PopupSliderChoice(&g_Config.iPortOffset, 0, 60000, n->T("Port offset", "Port offset (0 = PSP compatibility)"), 100, screenManager())); + networkingSettings->Add(new PopupSliderChoice(&g_Config.iMinTimeout, 1, 15000, n->T("Minimum Timeout", "Minimum Timeout (override low latency in ms)"), 100, screenManager())); + networkingSettings->Add(new CheckBox(&g_Config.bTCPNoDelay, n->T("TCP No Delay", "TCP No Delay (faster TCP)"))); + ViewGroup *toolsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); toolsScroll->SetTag("GameSettingsTools"); LinearLayout *tools = new LinearLayout(ORIENT_VERTICAL); @@ -812,8 +900,9 @@ void GameSettingsScreen::CreateViews() { tabHolder->AddTab(ms->T("System"), systemSettingsScroll); if (!g_Config.bSimpleUI) { - systemSettings->Add(new ItemHeader(sy->T("UI Language"))); + systemSettings->Add(new ItemHeader(sy->T("UI Language"))); // Should be renamed "UI"? systemSettings->Add(new Choice(dev->T("Language", "Language")))->OnClick.Handle(this, &GameSettingsScreen::OnLanguage); + systemSettings->Add(new CheckBox(&g_Config.bUISound, dev->T("UI Sound"))); systemSettings->Add(new ItemHeader(sy->T("Help the PPSSPP team"))); enableReports_ = Reporting::IsEnabled(); @@ -824,9 +913,12 @@ void GameSettingsScreen::CreateViews() { systemSettings->Add(new ItemHeader(sy->T("Emulation"))); systemSettings->Add(new CheckBox(&g_Config.bFastMemory, sy->T("Fast Memory", "Fast Memory (Unstable)")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting); + systemSettings->Add(new CheckBox(&g_Config.bIgnoreBadMemAccess, sy->T("Ignore bad memory accesses"))); + systemSettings->Add(new CheckBox(&g_Config.bSeparateIOThread, sy->T("I/O on thread (experimental)")))->SetEnabled(!PSP_IsInited()); static const char *ioTimingMethods[] = { "Fast (lag on slow storage)", "Host (bugs, less lag)", "Simulate UMD delays" }; View *ioTimingMethod = systemSettings->Add(new PopupMultiChoice(&g_Config.iIOTimingMethod, sy->T("IO timing method"), ioTimingMethods, 0, ARRAY_SIZE(ioTimingMethods), sy->GetName(), screenManager())); + ioTimingMethod->SetEnabledPtr(&g_Config.bSeparateIOThread); systemSettings->Add(new CheckBox(&g_Config.bForceLagSync, sy->T("Force real clock sync (slower, less lag)"))); PopupSliderChoice *lockedMhz = systemSettings->Add(new PopupSliderChoice(&g_Config.iLockedCPUSpeed, 0, 1000, sy->T("Change CPU Clock", "Change CPU Clock (unstable)"), screenManager(), sy->T("MHz, 0:default"))); lockedMhz->OnChange.Add([&](UI::EventParams &) { @@ -969,9 +1061,9 @@ void GameSettingsScreen::CreateViews() { if (!g_Config.bSimpleUI) { systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving"))); static const char *dateFormat[] = { "YYYYMMDD", "MMDDYYYY", "DDMMYYYY" }; - systemSettings->Add(new PopupMultiChoice(&g_Config.iDateFormat, sy->T("Date Format"), dateFormat, 1, 3, sy->GetName(), screenManager())); - static const char *timeFormat[] = { "12HR", "24HR" }; - systemSettings->Add(new PopupMultiChoice(&g_Config.iTimeFormat, sy->T("Time Format"), timeFormat, 1, 2, sy->GetName(), screenManager())); + systemSettings->Add(new PopupMultiChoice(&g_Config.iDateFormat, sy->T("Date Format"), dateFormat, 0, 3, sy->GetName(), screenManager())); + static const char *timeFormat[] = { "24HR", "12HR" }; + systemSettings->Add(new PopupMultiChoice(&g_Config.iTimeFormat, sy->T("Time Format"), timeFormat, 0, 2, sy->GetName(), screenManager())); static const char *buttonPref[] = { "Use O to confirm", "Use X to confirm" }; systemSettings->Add(new PopupMultiChoice(&g_Config.iButtonPreference, sy->T("Confirmation Button"), buttonPref, 0, 2, sy->GetName(), screenManager())); } @@ -998,19 +1090,19 @@ UI::EventReturn GameSettingsScreen::OnHardwareTransform(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnScreenRotation(UI::EventParams &e) { - ILOG("New display rotation: %d", g_Config.iScreenRotation); - ILOG("Sending rotate"); + INFO_LOG(SYSTEM, "New display rotation: %d", g_Config.iScreenRotation); + INFO_LOG(SYSTEM, "Sending rotate"); System_SendMessage("rotate", ""); - ILOG("Got back from rotate"); + INFO_LOG(SYSTEM, "Got back from rotate"); return UI::EVENT_DONE; } void RecreateActivity() { const int SYSTEM_JELLYBEAN = 16; if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= SYSTEM_JELLYBEAN) { - ILOG("Sending recreate"); + INFO_LOG(SYSTEM, "Sending recreate"); System_SendMessage("recreate", ""); - ILOG("Got back from recreate"); + INFO_LOG(SYSTEM, "Got back from recreate"); } else { auto gr = GetI18NCategory("Graphics"); System_SendMessage("toast", gr->T("Must Restart", "You must restart PPSSPP for this change to take effect")); @@ -1211,6 +1303,11 @@ void GameSettingsScreen::update() { RecreateViews(); lastVertical_ = vertical; } + if (g_ShaderNameListChanged) { + g_ShaderNameListChanged = false; + g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); + RecreateViews(); + } } void GameSettingsScreen::onFinish(DialogResult result) { @@ -1276,6 +1373,8 @@ void GameSettingsScreen::TriggerRestart(const char *why) { } else if (!gamePath_.empty()) { param += " \"" + ReplaceAll(ReplaceAll(gamePath_, "\\", "\\\\"), "\"", "\\\"") + "\""; } + // Make sure the new instance is considered the first. + ShutdownInstanceCounter(); System_SendMessage("graphics_restart", param.c_str()); } @@ -1348,6 +1447,11 @@ UI::EventReturn GameSettingsScreen::OnCameraDeviceChange(UI::EventParams& e) { return UI::EVENT_DONE; } +UI::EventReturn GameSettingsScreen::OnMicDeviceChange(UI::EventParams& e) { + Microphone::onMicDeviceChange(); + return UI::EVENT_DONE; +} + UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) { auto a = GetI18NCategory("Audio"); if (g_Config.sAudioDevice == a->T("Auto")) { @@ -1430,17 +1534,9 @@ UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnChangeproAdhocServerAddress(UI::EventParams &e) { - auto sy = GetI18NCategory("System"); + auto n = GetI18NCategory("Networking"); -#if defined(__ANDROID__) - System_InputBoxGetString(sy->T("proAdhocServer Address:"), g_Config.proAdhocServer, [](bool result, const std::string &value) { - if (result) { - g_Config.proAdhocServer = value; - } - }); -#else - screenManager()->push(new HostnameSelectScreen(&g_Config.proAdhocServer, sy->T("proAdhocServer Address:"))); -#endif + screenManager()->push(new HostnameSelectScreen(&g_Config.proAdhocServer, n->T("proAdhocServer Address:"))); return UI::EVENT_DONE; } @@ -1475,19 +1571,28 @@ UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnPostProcShader(UI::EventParams &e) { - auto gr = GetI18NCategory("Graphics"); - auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader")); - procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange); - if (e.v) - procScreen->SetPopupOrigin(e.v); - screenManager()->push(procScreen); +UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { + g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); + g_Config.vPostShaderNames.push_back("Off"); + g_ShaderNameListChanged = true; + NativeMessageReceived("gpu_resized", ""); return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { +UI::EventReturn GameSettingsScreen::OnTextureShader(UI::EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto shaderScreen = new TextureShaderScreen(gr->T("Texture Shader")); + shaderScreen->OnChoice.Handle(this, &GameSettingsScreen::OnTextureShaderChange); + if (e.v) + shaderScreen->SetPopupOrigin(e.v); + screenManager()->push(shaderScreen); + return UI::EVENT_DONE; +} + +UI::EventReturn GameSettingsScreen::OnTextureShaderChange(UI::EventParams &e) { NativeMessageReceived("gpu_resized", ""); RecreateViews(); // Update setting name + g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off"; return UI::EVENT_DONE; } @@ -1638,7 +1743,6 @@ void OtherSettingsScreen::CreateViews() { workerThreads->SetFormat("%i Threads"); list->Add(new CheckBox(&g_Config.bEncryptSave, sy->T("Encrypt savedata"))); list->Add(new CheckBox(&g_Config.bSavedataUpgrade, sy->T("Allow savedata with wrong encryption(unsafe workaround for outdated PSP savedata)"))); - list->Add(new CheckBox(&g_Config.bFrameSkipUnthrottle, gr->T("Frameskip unthrottle(good for CPU benchmark)"))); list->Add(new CheckBox(&g_Config.bShowFrameProfiler, gr->T("Display frame profiler(heavy!)"))); list->Add(new CheckBox(&g_Config.bSimpleFrameStats, gr->T("Display simple frame stats(heavy!)"))); list->Add(new CheckBox(&g_Config.bDrawFrameGraph, dev->T("Draw Frametimes Graph"))); @@ -1812,10 +1916,35 @@ void HostnameSelectScreen::CreatePopupContents(UI::ViewGroup *parent) { buttonsRow1->Add(new Spacer(new LinearLayoutParams(1.0, G_RIGHT))); buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, G_LEFT))); +#if defined(__ANDROID__) + buttonsRow2->Add(new Button(di->T("Edit")))->OnClick.Handle(this, &HostnameSelectScreen::OnEditClick); // Since we don't have OnClick Event triggered from TextEdit's Touch().. here we go! +#endif buttonsRow2->Add(new Button(di->T("Delete")))->OnClick.Handle(this, &HostnameSelectScreen::OnDeleteClick); buttonsRow2->Add(new Button(di->T("Delete all")))->OnClick.Handle(this, &HostnameSelectScreen::OnDeleteAllClick); + buttonsRow2->Add(new Button(di->T("Toggle List")))->OnClick.Handle(this, &HostnameSelectScreen::OnShowIPListClick); buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, G_RIGHT))); + std::vector listIP = {"myneighborsushicat.com", "localhost"}; + net::GetIPList(listIP); + ipRows_ = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0)); + ScrollView* scrollView = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + LinearLayout* innerView = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + if (listIP.size() > 0) { + for (const auto& label : listIP) { + // Filter out IP prefixed with "127." and "169.254." also "0." since they can be rendundant or unusable + if (label.find("127.") != 0 && label.find("169.254.") != 0 && label.find("0.") != 0) { + auto button = innerView->Add(new Button(label, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + button->OnClick.Handle(this, &HostnameSelectScreen::OnIPClick); + button->SetTag(label); + } + } + } + scrollView->Add(innerView); + ipRows_->Add(scrollView); + ipRows_->SetVisibility(V_GONE); + parent->Add(ipRows_); + listIP.clear(); listIP.shrink_to_fit(); + errorView_ = parent->Add(new TextView(n->T("Invalid IP or hostname"), ALIGN_HCENTER, false, new LinearLayoutParams(Margins(0, 10, 0, 0)))); errorView_->SetTextColor(0xFF3030FF); errorView_->SetVisibility(V_GONE); @@ -1855,6 +1984,38 @@ UI::EventReturn HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn HostnameSelectScreen::OnEditClick(UI::EventParams& e) { + auto n = GetI18NCategory("Networking"); +#if defined(__ANDROID__) + System_InputBoxGetString(n->T("proAdhocServer Address:"), addrView_->GetText(), [this](bool result, const std::string& value) { + if (result) { + addrView_->SetText(value); + } + }); +#endif + return UI::EVENT_DONE; +} + +UI::EventReturn HostnameSelectScreen::OnShowIPListClick(UI::EventParams& e) { + if (ipRows_->GetVisibility() == UI::V_GONE) { + ipRows_->SetVisibility(UI::V_VISIBLE); + } + else { + ipRows_->SetVisibility(UI::V_GONE); + } + return UI::EVENT_DONE; +} + +UI::EventReturn HostnameSelectScreen::OnIPClick(UI::EventParams& e) { + std::string text = e.v ? e.v->Tag() : ""; + if (text.length() > 0) { + addrView_->SetText(text); + // TODO: Copy the IP to clipboard for the host to easily share their IP through chatting apps. + System_SendMessage("setclipboardtext", text.c_str()); // Doesn't seems to be working on windows (yet?) + } + return UI::EVENT_DONE; +} + void HostnameSelectScreen::ResolverThread() { std::unique_lock guard(resolverLock_); @@ -1932,7 +2093,7 @@ bool HostnameSelectScreen::CanComplete(DialogResult result) { void HostnameSelectScreen::OnCompleted(DialogResult result) { if (result == DR_OK) - *value_ = addrView_->GetText(); + *value_ = StripSpaces(addrView_->GetText()); } SettingInfoMessage::SettingInfoMessage(int align, UI::AnchorLayoutParams *lp) diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 997a9e011a..a09ae1363b 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -21,7 +21,7 @@ #include #include #include -#include "ui/ui_screen.h" +#include "Common/UI/UIScreen.h" #include "UI/MiscScreens.h" class SettingInfoMessage; @@ -80,8 +80,9 @@ private: UI::EventReturn OnLanguage(UI::EventParams &e); UI::EventReturn OnLanguageChange(UI::EventParams &e); UI::EventReturn OnAutoFrameskip(UI::EventParams &e); - UI::EventReturn OnPostProcShader(UI::EventParams &e); UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); + UI::EventReturn OnTextureShader(UI::EventParams &e); + UI::EventReturn OnTextureShaderChange(UI::EventParams &e); UI::EventReturn OnDeveloperTools(UI::EventParams &e); UI::EventReturn OnOtherSettings(UI::EventParams &e); UI::EventReturn OnRemoteISO(UI::EventParams &e); @@ -104,6 +105,7 @@ private: UI::EventReturn OnRenderingDevice(UI::EventParams &e); UI::EventReturn OnInflightFramesChoice(UI::EventParams &e); UI::EventReturn OnCameraDeviceChange(UI::EventParams& e); + UI::EventReturn OnMicDeviceChange(UI::EventParams& e); UI::EventReturn OnAudioDevice(UI::EventParams &e); UI::EventReturn OnJitAffectingSetting(UI::EventParams &e); #if PPSSPP_PLATFORM(ANDROID) @@ -130,6 +132,7 @@ private: int prevInflightFrames_; bool enableReports_; bool tessHWEnable_; + std::string shaderNames_[256]; //edit the game-specific settings and restore the global settings after exiting bool editThenRestore_; @@ -222,6 +225,9 @@ private: UI::EventReturn OnPointClick(UI::EventParams &e); UI::EventReturn OnDeleteClick(UI::EventParams &e); UI::EventReturn OnDeleteAllClick(UI::EventParams &e); + UI::EventReturn OnEditClick(UI::EventParams& e); + UI::EventReturn OnShowIPListClick(UI::EventParams& e); + UI::EventReturn OnIPClick(UI::EventParams& e); enum class ResolverState { WAITING, @@ -235,6 +241,7 @@ private: UI::TextEdit *addrView_ = nullptr; UI::TextView *errorView_ = nullptr; UI::TextView *progressView_ = nullptr; + UI::LinearLayout *ipRows_ = nullptr; std::thread resolver_; ResolverState resolverState_ = ResolverState::WAITING; diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index ef3a1ad2be..e84c43f3fe 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -16,25 +16,27 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include + +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Math/math_util.h" +#include "Common/UI/Context.h" + #include "Common/Log.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/Core.h" #include "Core/System.h" #include "Core/HLE/sceCtrl.h" #include "UI/GamepadEmu.h" -#include "base/colorutil.h" -#include "base/display.h" -#include "base/NativeApp.h" -#include "base/timeutil.h" -#include "gfx/texture_atlas.h" -#include "math/math_util.h" -#include "ui/ui_context.h" static u32 GetButtonColor() { return g_Config.iTouchButtonStyle != 0 ? 0xFFFFFF : 0xc0b080; } -GamepadView::GamepadView(UI::LayoutParams *layoutParams) : UI::View(layoutParams), secondsWithoutTouch_(0) { +GamepadView::GamepadView(UI::LayoutParams *layoutParams) : UI::View(layoutParams) { lastFrameTime_ = time_now_d(); } @@ -43,7 +45,7 @@ void GamepadView::Touch(const TouchInput &input) { } void GamepadView::Update() { - const float now = time_now(); + const double now = time_now_d(); float delta = now - lastFrameTime_; if (delta > 0) { secondsWithoutTouch_ += delta; @@ -193,7 +195,7 @@ void AnalogRotationButton::Touch(const TouchInput &input) { } void AnalogRotationButton::Update() { - const float now = time_now(); + const float now = time_now_d(); float delta = now - lastFrameTime_; if (delta > 0) { secondsWithoutTouch_ += delta; diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index 9f2fbc2a1f..3cacb147c4 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -17,11 +17,11 @@ #pragma once -#include "input/input_state.h" -#include "gfx_es2/draw_buffer.h" +#include "Common/Input/InputState.h" +#include "Common/Render/DrawBuffer.h" -#include "ui/view.h" -#include "ui/viewgroup.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" #include "Core/CoreParameter.h" class GamepadView : public UI::View { @@ -37,8 +37,8 @@ public: protected: virtual float GetButtonOpacity(); - float lastFrameTime_; - float secondsWithoutTouch_; + double lastFrameTime_; + float secondsWithoutTouch_ = 0.0; }; class MultiTouchButton : public GamepadView { diff --git a/UI/HostTypes.h b/UI/HostTypes.h index e489aa668d..134c808862 100644 --- a/UI/HostTypes.h +++ b/UI/HostTypes.h @@ -43,6 +43,7 @@ public: bool IsDebuggingEnabled() override {return false;} bool AttemptLoadSymbolMap() override {return false;} + void NotifySymbolMapUpdated() override {} void SetWindowTitle(const char *message) override {} void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) override { diff --git a/UI/InstallZipScreen.cpp b/UI/InstallZipScreen.cpp index 2a7bda7d1c..0f5f79551d 100644 --- a/UI/InstallZipScreen.cpp +++ b/UI/InstallZipScreen.cpp @@ -15,14 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/logging.h" -#include "i18n/i18n.h" -#include "ui/ui.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "file/file_util.h" +#include "Common/UI/UI.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" #include "Common/StringUtils.h" +#include "Common/Data/Text/I18n.h" #include "Core/Util/GameManager.h" #include "UI/InstallZipScreen.h" #include "UI/MainScreen.h" @@ -81,6 +79,9 @@ void InstallZipScreen::CreateViews() { returnToHomebrew_ = false; } else { leftColumn->Add(new TextView(iz->T("Zip file does not contain PSP software"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); + doneView_ = nullptr; + progressBar_ = nullptr; + installChoice_ = nullptr; backChoice_ = rightColumnItems->Add(new Choice(di->T("Back"))); } @@ -99,7 +100,9 @@ bool InstallZipScreen::key(const KeyInput &key) { UI::EventReturn InstallZipScreen::OnInstall(UI::EventParams ¶ms) { if (g_GameManager.InstallGameOnThread(zipPath_, zipPath_, deleteZipFile_)) { installStarted_ = true; - installChoice_->SetEnabled(false); + if (installChoice_) { + installChoice_->SetEnabled(false); + } } return UI::EVENT_DONE; } diff --git a/UI/InstallZipScreen.h b/UI/InstallZipScreen.h index e8015fdfa5..e8e8d05701 100644 --- a/UI/InstallZipScreen.h +++ b/UI/InstallZipScreen.h @@ -19,8 +19,8 @@ #include -#include "ui/view.h" -#include "ui/ui_screen.h" +#include "Common/UI/View.h" +#include "Common/UI/UIScreen.h" #include "UI/MiscScreens.h" diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 80dfe61361..9838bb8dfd 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -19,21 +19,23 @@ #include #include "ppsspp_config.h" -#include "base/colorutil.h" -#include "base/display.h" -#include "base/timeutil.h" -#include "file/path.h" -#include "gfx/texture_atlas.h" -#include "gfx_es2/draw_buffer.h" -#include "math/curves.h" -#include "base/stringutil.h" -#include "ui/root.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "util/text/utf8.h" -#include "Common/FileUtil.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/Root.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" + +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/File/PathBrowser.h" +#include "Common/Math/curves.h" +#include "Common/File/FileUtil.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" #include "Core/System.h" #include "Core/Host.h" #include "Core/Reporting.h" @@ -52,10 +54,11 @@ #include "UI/DisplayLayoutScreen.h" #include "UI/SavedataScreen.h" #include "UI/Store.h" +#include "UI/InstallZipScreen.h" #include "Core/Config.h" #include "Core/Loaders.h" #include "GPU/GPUInterface.h" -#include "i18n/i18n.h" +#include "Common/Data/Text/I18n.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceUmd.h" @@ -74,6 +77,28 @@ bool MainScreen::showHomebrewTab = false; +bool LaunchFile(ScreenManager *screenManager, std::string path) { + // Depending on the file type, we don't want to launch EmuScreen at all. + auto loader = ConstructFileLoader(path); + if (!loader) { + return false; + } + + IdentifiedFileType type = Identify_File(loader); + delete loader; + + switch (type) { + case IdentifiedFileType::ARCHIVE_ZIP: + screenManager->push(new InstallZipScreen(path)); + break; + default: + // Let the EmuScreen take care of it. + screenManager->switchScreen(new EmuScreen(path)); + break; + } + return true; +} + static bool IsTempPath(const std::string &str) { std::string item = str; @@ -294,7 +319,7 @@ void GameButton::Draw(UIContext &dc) { if (HasFocus()) { dc.Draw()->Flush(); dc.RebindTexture(); - float pulse = sinf(time_now() * 7.0f) * 0.25 + 0.8; + float pulse = sin(time_now_d() * 7.0) * 0.25 + 0.8; dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid, x - dropsize*1.5f, y - dropsize*1.5f, x + w + dropsize*1.5f, y + h + dropsize*1.5f, alphaMul(color, pulse), 1.0f); dc.Draw()->Flush(); } else { @@ -912,12 +937,12 @@ UI::EventReturn GameBrowser::OnHomebrewStore(UI::EventParams &e) { MainScreen::MainScreen() { System_SendMessage("event", "mainscreen"); - SetBackgroundAudioGame(""); + g_BackgroundAudio.SetGame(""); lastVertical_ = UseVerticalLayout(); } MainScreen::~MainScreen() { - SetBackgroundAudioGame(""); + g_BackgroundAudio.SetGame(""); } void MainScreen::CreateViews() { @@ -1151,7 +1176,7 @@ void MainScreen::sendMessage(const char *message, const char *value) { if (screenManager()->topScreen() == this) { if (!strcmp(message, "boot")) { - screenManager()->switchScreen(new EmuScreen(value)); + LaunchFile(screenManager(), std::string(value)); } if (!strcmp(message, "browse_folderSelect")) { int tab = tabHolder_->GetCurrentTab(); @@ -1256,7 +1281,7 @@ UI::EventReturn MainScreen::OnGameSelected(UI::EventParams &e) { // Restore focus if it was highlighted (e.g. by gamepad.) restoreFocusGamePath_ = highlightedGamePath_; - SetBackgroundAudioGame(path); + g_BackgroundAudio.SetGame(path); lockBackgroundAudio_ = true; screenManager()->push(new GameScreen(path)); return UI::EVENT_DONE; @@ -1287,7 +1312,7 @@ UI::EventReturn MainScreen::OnGameHighlight(UI::EventParams &e) { } if ((!highlightedGamePath_.empty() || e.a == FF_LOSTFOCUS) && !lockBackgroundAudio_) { - SetBackgroundAudioGame(highlightedGamePath_); + g_BackgroundAudio.SetGame(highlightedGamePath_); } lockBackgroundAudio_ = false; @@ -1300,8 +1325,8 @@ UI::EventReturn MainScreen::OnGameSelectedInstant(UI::EventParams &e) { #else std::string path = e.s; #endif - // Go directly into the game. - screenManager()->switchScreen(new EmuScreen(path)); + ScreenManager *screen = screenManager(); + LaunchFile(screen, path); return UI::EVENT_DONE; } @@ -1382,7 +1407,7 @@ void MainScreen::dialogFinished(const Screen *dialog, DialogResult result) { restoreFocusGamePath_.clear(); } else { // Not refocusing, so we need to stop the audio. - SetBackgroundAudioGame(""); + g_BackgroundAudio.SetGame(""); } } } diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 9f90ea7bb6..09da7f7289 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -19,10 +19,10 @@ #include -#include "file/path.h" -#include "ui/ui_screen.h" -#include "ui/viewgroup.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" +#include "Common/File/PathBrowser.h" enum GameBrowserFlags { FLAG_HOMEBREWSTOREBUTTON = 1 @@ -36,14 +36,7 @@ enum class BrowseFlags { HOMEBREW_STORE = 8, STANDARD = 1 | 2 | 4, }; - -static inline BrowseFlags operator |(const BrowseFlags &lhs, const BrowseFlags &rhs) { - return BrowseFlags((int)lhs | (int)rhs); -} - -static inline bool operator &(const BrowseFlags &lhs, const BrowseFlags &rhs) { - return ((int)lhs & (int)rhs) != 0; -} +ENUM_CLASS_BITOPS(BrowseFlags); class GameBrowser : public UI::LinearLayout { public: diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 399bef89c1..2d6d5f4f3b 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -20,18 +20,31 @@ #include #include -#include "base/colorutil.h" -#include "base/display.h" -#include "base/timeutil.h" -#include "gfx_es2/draw_buffer.h" -#include "math/curves.h" -#include "i18n/i18n.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "ui/ui.h" -#include "util/random/rng.h" -#include "file/vfs.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/UI/UI.h" + +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Math/curves.h" +#include "Common/File/VFS/VFS.h" + +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Random/Rng.h" +#include "Common/TimeUtil.h" +#include "Common/File/FileUtil.h" +#include "Core/Config.h" +#include "Core/Host.h" +#include "Core/System.h" +#include "Core/MIPS/JitCommon/JitCommon.h" +#include "Core/HLE/sceUtility.h" +#include "GPU/GPUState.h" +#include "GPU/Common/PostShader.h" + #include "UI/ControlMappingScreen.h" #include "UI/DisplayLayoutScreen.h" #include "UI/EmuScreen.h" @@ -39,14 +52,6 @@ #include "UI/GameSettingsScreen.h" #include "UI/MainScreen.h" #include "UI/MiscScreens.h" -#include "Core/Config.h" -#include "Core/Host.h" -#include "Core/System.h" -#include "Core/MIPS/JitCommon/JitCommon.h" -#include "Core/HLE/sceUtility.h" -#include "Common/FileUtil.h" -#include "GPU/GPUState.h" -#include "GPU/Common/PostShader.h" #ifdef _MSC_VER #pragma execution_character_set("utf-8") @@ -121,11 +126,11 @@ void DrawBackground(UIContext &dc, float alpha) { ui_draw2d.DrawImageStretch(img, dc.GetBounds(), bgColor); } - float t = time_now(); + double t = time_now_d(); for (int i = 0; i < 100; i++) { float x = xbase[i] + dc.GetBounds().x; float y = ybase[i] + dc.GetBounds().y + 40 * cosf(i * 7.2f + t * 1.3f); - float angle = sinf(i + t); + float angle = (float)sin(i + t); int n = i & 3; ui_draw2d.DrawImageRotated(symbols[n], x, y, 1.0f, angle, colorAlpha(colors[n], alpha * 0.1f)); } @@ -299,7 +304,7 @@ void PromptScreen::TriggerFinish(DialogResult result) { UIDialogScreenWithBackground::TriggerFinish(result); } -PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title) { +PostProcScreen::PostProcScreen(const std::string &title, int id) : ListPopupScreen(title), id_(id) { auto ps = GetI18NCategory("PostShaders"); ReloadAllPostShaderInfo(); shaders_ = GetAllPostShaderInfo(); @@ -308,7 +313,7 @@ PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title for (int i = 0; i < (int)shaders_.size(); i++) { if (!shaders_[i].visible) continue; - if (shaders_[i].section == g_Config.sPostShaderName) + if (shaders_[i].section == g_Config.vPostShaderNames[id_]) selected = i; items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); } @@ -318,7 +323,27 @@ PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title void PostProcScreen::OnCompleted(DialogResult result) { if (result != DR_OK) return; - g_Config.sPostShaderName = shaders_[listView_->GetSelected()].section; + g_Config.vPostShaderNames[id_] = shaders_[listView_->GetSelected()].section; +} + +TextureShaderScreen::TextureShaderScreen(const std::string &title) : ListPopupScreen(title) { + auto ps = GetI18NCategory("TextureShaders"); + ReloadAllPostShaderInfo(); + shaders_ = GetAllTextureShaderInfo(); + std::vector items; + int selected = -1; + for (int i = 0; i < (int)shaders_.size(); i++) { + if (shaders_[i].section == g_Config.sTextureShaderName) + selected = i; + items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); + } + adaptor_ = UI::StringVectorListAdaptor(items, selected); +} + +void TextureShaderScreen::OnCompleted(DialogResult result) { + if (result != DR_OK) + return; + g_Config.sTextureShaderName = shaders_[listView_->GetSelected()].section; } NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen(title) { @@ -512,6 +537,9 @@ void LogoScreen::render() { #if (defined(_WIN32) && !PPSSPP_PLATFORM(UWP)) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX) // Draw the graphics API, except on UWP where it's always D3D11 std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME); +#ifdef _DEBUG + apiName += ", debug build"; +#endif dc.DrawText(gr->T(apiName), bounds.centerX(), ppsspp_org_y + 50, textColor, ALIGN_CENTER); #endif @@ -667,6 +695,9 @@ void CreditsScreen::render() { "LunaMoo", "AdamN/ANR2ME", "zminhquanz", + "ANR2ME", + "adenovan", + "iota97", "", cr->T("specialthanks", "Special thanks to:"), specialthanksMaxim.c_str(), diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 2609be6dfc..8c23ef3d43 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -22,10 +22,11 @@ #include #include -#include "file/file_util.h" -#include "ui/ui_screen.h" +#include "Common/UI/UIScreen.h" +#include "Common/File/DirListing.h" struct ShaderInfo; +struct TextureShaderInfo; extern std::string boot_filename; void UIBackgroundInit(UIContext &dc); @@ -104,12 +105,23 @@ private: class PostProcScreen : public ListPopupScreen { public: - PostProcScreen(const std::string &title); + PostProcScreen(const std::string &title, int id); private: void OnCompleted(DialogResult result) override; bool ShowButtons() const override { return true; } std::vector shaders_; + int id_; +}; + +class TextureShaderScreen : public ListPopupScreen { +public: + TextureShaderScreen(const std::string &title); + +private: + void OnCompleted(DialogResult result) override; + bool ShowButtons() const override { return true; } + std::vector shaders_; }; class LogoScreen : public UIScreen { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 41ff959674..94fc04123c 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -43,41 +43,45 @@ #include "Windows/CaptureDevice.h" #endif -#include "base/display.h" -#include "base/timeutil.h" -#include "base/logging.h" -#include "base/NativeApp.h" -#include "file/vfs.h" -#include "file/zip_read.h" -#include "net/http_client.h" -#include "net/resolve.h" -#include "gfx/texture_atlas.h" -#include "gfx_es2/draw_text.h" -#include "gfx_es2/gpu_features.h" -#include "i18n/i18n.h" -#include "input/input_state.h" -#include "math/fast/fast_math.h" -#include "math/math_util.h" -#include "math/lin/matrix4x4.h" -#include "profiler/profiler.h" -#include "thin3d/thin3d.h" -#include "ui/ui.h" -#include "ui/screen.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "util/text/utf8.h" +#include "Common/Net/HTTPClient.h" +#include "Common/Net/Resolve.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/Text/draw_text.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/thin3d.h" +#include "Common/UI/UI.h" +#include "Common/UI/Screen.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "android/jni/app-android.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Input/InputState.h" +#include "Common/Math/fast/fast_math.h" +#include "Common/Math/math_util.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" #include "Common/CPUDetect.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" #include "Common/LogManager.h" #include "Common/MemArena.h" #include "Common/GraphicsContext.h" #include "Common/OSVersion.h" + #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Core.h" #include "Core/FileLoaders/DiskCachingFileLoader.h" #include "Core/Host.h" +#include "Core/KeyMap.h" #include "Core/Reporting.h" #include "Core/SaveState.h" #include "Core/Screenshot.h" @@ -90,8 +94,8 @@ #include "Core/Util/GameManager.h" #include "Core/Util/AudioFormat.h" #include "Core/WebServer.h" -#include "GPU/GPUInterface.h" +#include "GPU/GPUInterface.h" #include "UI/BackgroundAudio.h" #include "UI/ControlMappingScreen.h" #include "UI/DiscordIntegration.h" @@ -105,10 +109,6 @@ #include "UI/TiltEventProcessor.h" #include "UI/TextureUtil.h" -#if !defined(MOBILE_DEVICE) -#include "Common/KeyMap.h" -#endif - #if !defined(MOBILE_DEVICE) && defined(USING_QT_UI) #include "Qt/QtHost.h" #endif @@ -125,9 +125,9 @@ static UI::Theme ui_theme; Atlas g_ui_atlas; -#if defined(ARM) && defined(__ANDROID__) +#if PPSSPP_ARCH(ARM) && defined(__ANDROID__) #include "../../android/jni/ArmEmitterTest.h" -#elif defined(ARM64) && defined(__ANDROID__) +#elif PPSSPP_ARCH(ARM64) && defined(__ANDROID__) #include "../../android/jni/Arm64EmitterTest.h" #endif @@ -148,6 +148,7 @@ std::string config_filename; // Really need to clean this mess of globals up... but instead I add more :P bool g_TakeScreenshot; +bool g_ShaderNameListChanged = false; static bool isOuya; static bool resized = false; static bool restarting = false; @@ -180,7 +181,7 @@ WindowsAudioBackend *winAudioBackend; std::thread *graphicsLoadThread; -class AndroidLogger : public LogListener { +class PrintfLogger : public LogListener { public: void Log(const LogMessage &message) override { // Log with simplified headers as Android already provides timestamp etc. @@ -188,17 +189,17 @@ public: case LogTypes::LVERBOSE: case LogTypes::LDEBUG: case LogTypes::LINFO: - ILOG("[%s] %s", message.log, message.msg.c_str()); + printf("INFO [%s] %s", message.log, message.msg.c_str()); break; case LogTypes::LERROR: - ELOG("[%s] %s", message.log, message.msg.c_str()); + printf("ERR [%s] %s", message.log, message.msg.c_str()); break; case LogTypes::LWARNING: - WLOG("[%s] %s", message.log, message.msg.c_str()); + printf("WARN [%s] %s", message.log, message.msg.c_str()); break; case LogTypes::LNOTICE: default: - ILOG("[%s] !!! %s", message.log, message.msg.c_str()); + printf("NOTE [%s] !!! %s", message.log, message.msg.c_str()); break; } } @@ -211,7 +212,7 @@ int Win32Mix(short *buffer, int numSamples, int bits, int rate, int channels) { #endif // globals -static AndroidLogger *logger = nullptr; +static LogListener *logger = nullptr; std::string boot_filename = ""; void NativeHost::InitSound() { @@ -234,7 +235,7 @@ void QtHost::ShutdownSound() { } std::string NativeQueryConfig(std::string query) { char temp[128]; if (query == "screenRotation") { - ILOG("g_Config.screenRotation = %d", g_Config.iScreenRotation); + INFO_LOG(G3D, "g_Config.screenRotation = %d", g_Config.iScreenRotation); snprintf(temp, sizeof(temp), "%d", g_Config.iScreenRotation); return std::string(temp); } else if (query == "immersiveMode") { @@ -255,8 +256,6 @@ std::string NativeQueryConfig(std::string query) { int max_res = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 1; snprintf(temp, sizeof(temp), "%d", std::min(scale, max_res)); return std::string(temp); - } else if (query == "force44khz") { - return std::string("0"); } else if (query == "androidJavaGL") { // If we're using Vulkan, we say no... need C++ to use Vulkan. if (GetGPUBackend() == GPUBackend::VULKAN) { @@ -273,7 +272,7 @@ std::string NativeQueryConfig(std::string query) { int NativeMix(short *audio, int num_samples) { if (GetUIState() != UISTATE_INGAME) { - PlayBackgroundAudio(); + g_BackgroundAudio.Play(); } int sample_rate = System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE); @@ -293,9 +292,9 @@ void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, boo *landscape = true; *version = PPSSPP_GIT_VERSION; -#if defined(ARM) && defined(__ANDROID__) +#if PPSSPP_ARCH(ARM) && defined(__ANDROID__) ArmEmitterTest(); -#elif defined(ARM64) && defined(__ANDROID__) +#elif PPSSPP_ARCH(ARM64) && defined(__ANDROID__) Arm64EmitterTest(); #endif } @@ -356,13 +355,14 @@ static void PostLoadConfig() { void CreateDirectoriesAndroid() { // On Android, create a PSP directory tree in the external_dir, // to hopefully reduce confusion a bit. - ILOG("Creating %s", (g_Config.memStickDirectory + "PSP").c_str()); + INFO_LOG(IO, "Creating %s", (g_Config.memStickDirectory + "PSP").c_str()); File::CreateFullPath(g_Config.memStickDirectory + "PSP"); File::CreateFullPath(GetSysDirectory(DIRECTORY_SAVEDATA)); File::CreateFullPath(GetSysDirectory(DIRECTORY_SAVESTATE)); File::CreateFullPath(GetSysDirectory(DIRECTORY_GAME)); File::CreateFullPath(GetSysDirectory(DIRECTORY_SYSTEM)); File::CreateFullPath(GetSysDirectory(DIRECTORY_TEXTURES)); + File::CreateFullPath(GetSysDirectory(DIRECTORY_PLUGINS)); // Avoid media scanners in PPSSPP_STATE and SAVEDATA directories, // and in the root PSP directory as well. @@ -370,12 +370,13 @@ void CreateDirectoriesAndroid() { File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SAVEDATA) + ".nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SYSTEM) + ".nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_TEXTURES) + ".nomedia"); + File::CreateEmptyFile(GetSysDirectory(DIRECTORY_PLUGINS) + ".nomedia"); } static void CheckFailedGPUBackends() { #ifdef _DEBUG // If you're in debug mode, you probably don't want a fallback. If you're in release mode, use IGNORE below. - WARN_LOG(LOADER, "Not checking for failed graphics backends in debug mode"); + NOTICE_LOG(LOADER, "Not checking for failed graphics backends in debug mode"); return; #endif @@ -530,7 +531,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } if (!LogManager::GetInstance()) - LogManager::Init(); + LogManager::Init(&g_Config.bEnableLogging); #ifndef _WIN32 g_Config.AddSearchPath(user_data_path); @@ -607,21 +608,21 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch // don't already have one. if (!gotBootFilename) { gotBootFilename = true; - ILOG("Boot filename found in args: '%s'", argv[i]); + INFO_LOG(SYSTEM, "Boot filename found in args: '%s'", argv[i]); bool okToLoad = true; bool okToCheck = true; if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) { PermissionStatus status = System_GetPermissionStatus(SYSTEM_PERMISSION_STORAGE); if (status == PERMISSION_STATUS_DENIED) { - ELOG("Storage permission denied. Launching without argument."); + ERROR_LOG(IO, "Storage permission denied. Launching without argument."); okToLoad = false; okToCheck = false; } else if (status != PERMISSION_STATUS_GRANTED) { - ELOG("Storage permission not granted. Launching without argument check."); + ERROR_LOG(IO, "Storage permission not granted. Launching without argument check."); okToCheck = false; } else { - ILOG("Storage permission granted."); + INFO_LOG(IO, "Storage permission granted."); } } if (okToLoad) { @@ -660,10 +661,13 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch PostLoadConfig(); -#if defined(__ANDROID__) || (defined(MOBILE_DEVICE) && !defined(_DEBUG)) +#if PPSSPP_PLATFORM(ANDROID) + logger = new AndroidLogger(); + logman->AddListener(logger); +#elif (defined(MOBILE_DEVICE) && !defined(_DEBUG)) // Enable basic logging for any kind of mobile device, since LogManager doesn't. // The MOBILE_DEVICE/_DEBUG condition matches LogManager.cpp. - logger = new AndroidLogger(); + logger = new PrintfLogger(); logman->AddListener(logger); #endif @@ -709,6 +713,9 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } #endif + // TODO: Load these in the background instead of synchronously. + g_BackgroundAudio.LoadSamples(); + if (!boot_filename.empty() && stateToLoad != NULL) { SaveState::Load(stateToLoad, -1, [](SaveState::Status status, const std::string &message, void *) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { @@ -805,29 +812,34 @@ static void UIThemeInit() { } void RenderOverlays(UIContext *dc, void *userdata); +bool CreateGlobalPipelines(); bool NativeInitGraphics(GraphicsContext *graphicsContext) { - ILOG("NativeInitGraphics"); - _assert_msg_(G3D, graphicsContext, "No graphics context!"); + INFO_LOG(SYSTEM, "NativeInitGraphics"); // We set this now so any resize during init is processed later. resized = false; - using namespace Draw; Core_SetGraphicsContext(graphicsContext); g_draw = graphicsContext->GetDrawContext(); - _assert_msg_(G3D, g_draw, "No draw context available!"); - _assert_msg_(G3D, g_draw->GetVshaderPreset(VS_COLOR_2D) != nullptr, "Failed to compile presets"); + + if (!CreateGlobalPipelines()) { + ERROR_LOG(G3D, "Failed to create global pipelines"); + return false; + } // Load the atlas. - size_t atlas_data_size = 0; if (!g_ui_atlas.IsMetadataLoaded()) { const uint8_t *atlas_data = VFSReadFile("ui_atlas_luna.meta", &atlas_data_size); bool load_success = atlas_data != nullptr && g_ui_atlas.Load(atlas_data, atlas_data_size); - _assert_msg_(G3D, load_success, "Failed to load ui_atlas_luna.meta"); + if (!load_success) { + ERROR_LOG(G3D, "Failed to load ui_atlas_luna.meta - graphics will be broken."); + // Stumble along with broken visuals instead of dying. + } delete[] atlas_data; } + ui_draw2d.SetAtlas(&g_ui_atlas); ui_draw2d_front.SetAtlas(&g_ui_atlas); @@ -836,43 +848,10 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { uiContext = new UIContext(); uiContext->theme = &ui_theme; - Draw::InputLayout *inputLayout = ui_draw2d.CreateInputLayout(g_draw); - Draw::BlendState *blendNormal = g_draw->CreateBlendState({ true, 0xF, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA }); - Draw::DepthStencilState *depth = g_draw->CreateDepthStencilState({ false, false, Comparison::LESS }); - Draw::RasterState *rasterNoCull = g_draw->CreateRasterState({}); - - PipelineDesc colorDesc{ - Primitive::TRIANGLE_LIST, - { g_draw->GetVshaderPreset(VS_COLOR_2D), g_draw->GetFshaderPreset(FS_COLOR_2D) }, - inputLayout, depth, blendNormal, rasterNoCull, &vsColBufDesc, - }; - PipelineDesc texColorDesc{ - Primitive::TRIANGLE_LIST, - { g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, - inputLayout, depth, blendNormal, rasterNoCull, &vsTexColBufDesc, - }; - - colorPipeline = g_draw->CreateGraphicsPipeline(colorDesc); - texColorPipeline = g_draw->CreateGraphicsPipeline(texColorDesc); - - _assert_(colorPipeline); - _assert_(texColorPipeline); - - // Release these now, reference counting should ensure that they get completely released - // once we delete both pipelines. - inputLayout->Release(); - rasterNoCull->Release(); - blendNormal->Release(); - depth->Release(); - ui_draw2d.Init(g_draw, texColorPipeline); ui_draw2d_front.Init(g_draw, texColorPipeline); uiContext->Init(g_draw, texColorPipeline, colorPipeline, &ui_draw2d, &ui_draw2d_front); - RasterStateDesc desc; - desc.cull = CullMode::NONE; - desc.frontFace = Facing::CCW; - if (uiContext->Text()) uiContext->Text()->SetFont("Tahoma", 20, 0); @@ -894,15 +873,58 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { if (IsWin7OrHigher()) { winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO); winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr }); + winMic = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::AUDIO); + winMic->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr }); } #endif g_gameInfoCache = new GameInfoCache(); - if (gpu) + if (gpu) { gpu->DeviceRestore(); + } - ILOG("NativeInitGraphics completed"); + INFO_LOG(SYSTEM, "NativeInitGraphics completed"); + return true; +} + +bool CreateGlobalPipelines() { + using namespace Draw; + + InputLayout *inputLayout = ui_draw2d.CreateInputLayout(g_draw); + BlendState *blendNormal = g_draw->CreateBlendState({ true, 0xF, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA }); + DepthStencilState *depth = g_draw->CreateDepthStencilState({ false, false, Comparison::LESS }); + RasterState *rasterNoCull = g_draw->CreateRasterState({}); + + PipelineDesc colorDesc{ + Primitive::TRIANGLE_LIST, + { g_draw->GetVshaderPreset(VS_COLOR_2D), g_draw->GetFshaderPreset(FS_COLOR_2D) }, + inputLayout, depth, blendNormal, rasterNoCull, &vsColBufDesc, + }; + PipelineDesc texColorDesc{ + Primitive::TRIANGLE_LIST, + { g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, + inputLayout, depth, blendNormal, rasterNoCull, &vsTexColBufDesc, + }; + + colorPipeline = g_draw->CreateGraphicsPipeline(colorDesc); + if (!colorPipeline) { + // Something really critical is wrong, don't care much about correct releasing of the states. + return false; + } + + texColorPipeline = g_draw->CreateGraphicsPipeline(texColorDesc); + if (!texColorPipeline) { + // Something really critical is wrong, don't care much about correct releasing of the states. + return false; + } + + // Release these now, reference counting should ensure that they get completely released + // once we delete both pipelines. + inputLayout->Release(); + rasterNoCull->Release(); + blendNormal->Release(); + depth->Release(); return true; } @@ -912,20 +934,26 @@ void NativeShutdownGraphics() { if (gpu) gpu->DeviceLost(); - ILOG("NativeShutdownGraphics"); + INFO_LOG(SYSTEM, "NativeShutdownGraphics"); -#ifdef _WIN32 +#if PPSSPP_PLATFORM(WINDOWS) delete winAudioBackend; winAudioBackend = nullptr; #endif -#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) if (winCamera) { winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::SHUTDOWN, nullptr }); while (!winCamera->isShutDown()) {};// Wait for shutting down. delete winCamera; winCamera = nullptr; } + if (winMic) { + winMic->sendMessage({ CAPTUREDEVIDE_COMMAND::SHUTDOWN, nullptr }); + while (!winMic->isShutDown()) {};// Wait for shutting down. + delete winMic; + winMic = nullptr; + } #endif UIBackgroundShutdown(); @@ -948,7 +976,7 @@ void NativeShutdownGraphics() { texColorPipeline = nullptr; } - ILOG("NativeShutdownGraphics done"); + INFO_LOG(SYSTEM, "NativeShutdownGraphics done"); } void TakeScreenshot() { @@ -1021,7 +1049,7 @@ void NativeRender(GraphicsContext *graphicsContext) { if (GetUIState() != UISTATE_INGAME) { // Note: We do this from NativeRender so that the graphics context is // guaranteed valid, to be safe - g_gameInfoCache messes around with textures. - UpdateBackgroundAudio(); + g_BackgroundAudio.Update(); } float xres = dp_xres; @@ -1065,7 +1093,7 @@ void NativeRender(GraphicsContext *graphicsContext) { } if (resized) { - ILOG("Resized flag set - recalculating bounds"); + INFO_LOG(G3D, "Resized flag set - recalculating bounds"); resized = false; if (uiContext) { @@ -1087,14 +1115,15 @@ void NativeRender(GraphicsContext *graphicsContext) { graphicsContext->Resize(); screenManager->resized(); - // TODO: Move this to new GraphicsContext objects for each backend. -#ifndef _WIN32 - if (GetGPUBackend() == GPUBackend::OPENGL) { - PSP_CoreParameter().pixelWidth = pixel_xres; - PSP_CoreParameter().pixelHeight = pixel_yres; - NativeMessageReceived("gpu_resized", ""); - } + // TODO: Move this to the GraphicsContext objects for each backend. +#if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID) + PSP_CoreParameter().pixelWidth = pixel_xres; + PSP_CoreParameter().pixelHeight = pixel_yres; + NativeMessageReceived("gpu_resized", ""); #endif + } else { + // INFO_LOG(G3D, "Polling graphics context"); + graphicsContext->Poll(); } ui_draw2d.PopDrawMatrix(); @@ -1134,7 +1163,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { if (msg == "core_powerSaving") { if (value != "false") { auto sy = GetI18NCategory("System"); -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(ANDROID) osm.Show(sy->T("WARNING: Android battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving"); #else osm.Show(sy->T("WARNING: Battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving"); @@ -1143,7 +1172,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { Core_SetPowerSaving(value != "false"); } if (msg == "permission_granted" && value == "storage") { -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(ANDROID) CreateDirectoriesAndroid(); #endif // We must have failed to load the config before, so load it now to avoid overwriting the old config @@ -1153,7 +1182,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { // Ideally we should simply reinitialize graphics to the mode from the config, but there are potential issues // and I can't risk it before 1.9.0. int gpuBackend = g_Config.iGPUBackend; - ILOG("Reloading config after storage permission grant."); + INFO_LOG(IO, "Reloading config after storage permission grant."); g_Config.Reload(); PostLoadConfig(); g_Config.iGPUBackend = gpuBackend; @@ -1185,21 +1214,23 @@ void NativeUpdate() { screenManager->update(); g_Discord.Update(); + + UI::SetSoundEnabled(g_Config.bUISound); } bool NativeIsAtTopLevel() { // This might need some synchronization? if (!screenManager) { - ELOG("No screen manager active"); + ERROR_LOG(SYSTEM, "No screen manager active"); return false; } Screen *currentScreen = screenManager->topScreen(); if (currentScreen) { bool top = currentScreen->isTopLevel(); - ILOG("Screen toplevel: %i", (int)top); + INFO_LOG(SYSTEM, "Screen toplevel: %i", (int)top); return currentScreen->isTopLevel(); } else { - ELOG("No current screen"); + ERROR_LOG(SYSTEM, "No current screen"); return false; } } @@ -1218,7 +1249,7 @@ bool NativeTouch(const TouchInput &touch) { } bool NativeKey(const KeyInput &key) { - // ILOG("Key code: %i flags: %i", key.keyCode, key.flags); + // INFO_LOG(SYSTEM, "Key code: %i flags: %i", key.keyCode, key.flags); #if !defined(MOBILE_DEVICE) if (g_Config.bPauseExitsEmulator) { static std::vector pspKeys; @@ -1336,7 +1367,7 @@ void NativeInputBoxReceived(std::function cb, b void NativeResized() { // NativeResized can come from any thread so we just set a flag, then process it later. - ILOG("NativeResized - setting flag"); + INFO_LOG(G3D, "NativeResized - setting flag"); resized = true; } @@ -1370,7 +1401,7 @@ void NativeShutdown() { moncleanup(); #endif - ILOG("NativeShutdown called"); + INFO_LOG(SYSTEM, "NativeShutdown called"); ShutdownWebServer(); @@ -1380,8 +1411,10 @@ void NativeShutdown() { g_Discord.Shutdown(); - delete logger; - logger = nullptr; + if (logger) { + delete logger; + logger = nullptr; + } // Previously we did exit() here on Android but that makes it hard to do things like restart on backend change. // I think we handle most globals correctly or correct-enough now. diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 66517ad1c0..5b89f78b57 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -1,11 +1,12 @@ #include "UI/OnScreenDisplay.h" -#include "base/colorutil.h" -#include "base/timeutil.h" -#include "gfx/texture_atlas.h" -#include "gfx_es2/draw_buffer.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Render/TextureAtlas.h" +#include "Common/Render/DrawBuffer.h" -#include "ui/ui_context.h" +#include "Common/UI/Context.h" + +#include "Common/TimeUtil.h" OnScreenMessages osm; diff --git a/UI/OnScreenDisplay.h b/UI/OnScreenDisplay.h index 6fbf093e55..6cb83aa877 100644 --- a/UI/OnScreenDisplay.h +++ b/UI/OnScreenDisplay.h @@ -4,10 +4,8 @@ #include #include -#include "base/basictypes.h" -#include "math/geom2d.h" - -#include "ui/view.h" +#include "Common/Math/geom2d.h" +#include "Common/UI/View.h" class DrawBuffer; @@ -37,7 +35,6 @@ public: const std::list &Messages() { return messages_; } private: - std::list messages_; std::mutex mutex_; }; diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index a8a15c193b..4573cd4e3e 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -17,26 +17,29 @@ #include #include -#include "i18n/i18n.h" -#include "gfx_es2/draw_buffer.h" -#include "ui/view.h" -#include "ui/viewgroup.h" -#include "ui/ui_context.h" -#include "ui/ui_screen.h" -#include "thin3d/thin3d.h" + +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" +#include "Common/UI/Context.h" +#include "Common/UI/UIScreen.h" +#include "Common/GPU/thin3d.h" + +#include "Common/Data/Text/I18n.h" +#include "Common/StringUtils.h" +#include "Common/System/System.h" #include "Core/Reporting.h" #include "Core/SaveState.h" #include "Core/System.h" #include "Core/Config.h" #include "Core/ELF/ParamSFO.h" +#include "Core/HLE/sceDisplay.h" +#include "Core/HLE/sceUmd.h" #include "GPU/GPUCommon.h" #include "GPU/GPUState.h" -#include "Core/HLE/sceDisplay.h" -#include "Core/HLE/sceUmd.h" - #include "UI/PauseScreen.h" #include "UI/GameSettingsScreen.h" #include "UI/ReportScreen.h" diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 8e951ffaf0..69c84d53af 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -20,8 +20,8 @@ #include #include -#include "ui/ui_screen.h" -#include "ui/viewgroup.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" #include "UI/TextureUtil.h" diff --git a/UI/ProfilerDraw.cpp b/UI/ProfilerDraw.cpp index f4ed990d61..c59cc6e3b9 100644 --- a/UI/ProfilerDraw.cpp +++ b/UI/ProfilerDraw.cpp @@ -20,10 +20,10 @@ #include "Core/Config.h" #include "Core/HLE/sceDisplay.h" -#include "gfx_es2/draw_buffer.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "profiler/profiler.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/Profiler/Profiler.h" #include "StringUtils.h" static const uint32_t nice_colors[] = { diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 9f0930f77d..8dfabde16a 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -25,16 +25,19 @@ #include #endif -#include "base/timeutil.h" -#include "file/path.h" // TODO: For text align flags, probably shouldn't be in gfx_es2/... -#include "gfx_es2/draw_buffer.h" -#include "i18n/i18n.h" -#include "json/json_reader.h" -#include "net/http_client.h" -#include "net/resolve.h" -#include "net/url.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Net/HTTPClient.h" +#include "Common/Net/Resolve.h" +#include "Common/Net/URL.h" + +#include "Common/File/PathBrowser.h" +#include "Common/Data/Format/JSONReader.h" +#include "Common/Data/Text/I18n.h" #include "Common/Common.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" +#include "Common/System/System.h" #include "Core/Config.h" #include "Core/WebServer.h" #include "UI/RemoteISOScreen.h" @@ -426,12 +429,12 @@ void RemoteISOConnectScreen::update() { break; case ScanStatus::FAILED: - nextRetry_ = real_time_now() + 15.0; + nextRetry_ = time_now_d() + 15.0; status_ = ScanStatus::RETRY_SCAN; break; case ScanStatus::RETRY_SCAN: - if (nextRetry_ < real_time_now()) { + if (nextRetry_ < time_now_d()) { status_ = ScanStatus::SCANNING; nextRetry_ = 0.0; diff --git a/UI/RemoteISOScreen.h b/UI/RemoteISOScreen.h index a294969259..7eab2270e0 100644 --- a/UI/RemoteISOScreen.h +++ b/UI/RemoteISOScreen.h @@ -20,8 +20,8 @@ #include #include -#include "ui/ui_screen.h" -#include "ui/viewgroup.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" #include "UI/MainScreen.h" diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index fe0988733d..1c31856a26 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -16,21 +16,24 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "base/display.h" + // TODO: For text align flags, probably shouldn't be in gfx_es2/... -#include "gfx_es2/draw_buffer.h" -#include "i18n/i18n.h" -#include "thin3d/thin3d.h" -#include "ui/ui_context.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/GPU/thin3d.h" +#include "Common/UI/Context.h" #include "UI/PauseScreen.h" #include "UI/ReportScreen.h" +#include "Common/Data/Text/I18n.h" +#include "Common/File/FileUtil.h" +#include "Common/Log.h" +#include "Common/StringUtils.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" #include "Core/Core.h" #include "Core/Reporting.h" #include "Core/Screenshot.h" #include "Core/System.h" -#include "Common/FileUtil.h" -#include "Common/Log.h" using namespace UI; @@ -161,6 +164,28 @@ ReportScreen::ReportScreen(const std::string &gamePath) ratingEnabled_ = enableReporting_; } +void ReportScreen::postRender() { + // We do this after render because we need it to be within the frame (so the screenshot works). + // We could do it mid frame, but then we have to reapply viewport/scissor. + if (!tookScreenshot_) { + std::string path = GetSysDirectory(DIRECTORY_SCREENSHOT); + if (!File::Exists(path)) { + File::CreateDir(path); + } + screenshotFilename_ = path + ".reporting.jpg"; + if (TakeGameScreenshot(screenshotFilename_.c_str(), ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, nullptr, nullptr, 4)) { + // Redo the views already, now with a screenshot included. + RecreateViews(); + } else { + // Good news (?), the views are good as-is without a screenshot. + screenshotFilename_.clear(); + } + tookScreenshot_ = true; + } + + UIDialogScreenWithGameBackground::postRender(); +} + void ReportScreen::update() { if (screenshot_) { if (includeScreenshot_) { @@ -252,18 +277,13 @@ void ReportScreen::CreateViews() { } #endif - std::string path = GetSysDirectory(DIRECTORY_SCREENSHOT); - if (!File::Exists(path)) { - File::CreateDir(path); - } - screenshotFilename_ = path + ".reporting.jpg"; - int shotWidth = 0, shotHeight = 0; - if (TakeGameScreenshot(screenshotFilename_.c_str(), ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, &shotWidth, &shotHeight, 4)) { - float scale = 340.0f * (1.0f / g_dpi_scale_y) * (1.0f / shotHeight); + if (tookScreenshot_ && !screenshotFilename_.empty()) { leftColumnItems->Add(new CheckBox(&includeScreenshot_, rp->T("FeedbackIncludeScreen", "Include a screenshot")))->SetEnabledPtr(&enableReporting_); screenshot_ = leftColumnItems->Add(new AsyncImageFileView(screenshotFilename_, IS_KEEP_ASPECT, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(12, 0)))); } else { - includeScreenshot_ = false; + if (tookScreenshot_) { + includeScreenshot_ = false; + } screenshot_ = nullptr; } @@ -333,7 +353,7 @@ EventReturn ReportScreen::HandleSubmit(EventParams &e) { g_Config.Save("ReportScreen::HandleSubmit"); } - std::string filename = includeScreenshot_ ? screenshotFilename_ : ""; + std::string filename = tookScreenshot_ && includeScreenshot_ ? screenshotFilename_ : ""; Reporting::ReportCompatibility(compat, graphics_ + 1, speed_ + 1, gameplay_ + 1, filename); TriggerFinish(DR_OK); screenManager()->push(new ReportFinishScreen(gamePath_, overall_)); diff --git a/UI/ReportScreen.h b/UI/ReportScreen.h index 18c0d2b930..b77f8a082f 100644 --- a/UI/ReportScreen.h +++ b/UI/ReportScreen.h @@ -19,8 +19,8 @@ #include -#include "ui/ui_screen.h" -#include "ui/viewgroup.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" enum class ReportingOverallScore : int { @@ -37,6 +37,7 @@ public: ReportScreen(const std::string &gamePath); protected: + void postRender() override; void update() override; void resized() override; void CreateViews() override; @@ -60,6 +61,7 @@ protected: int gameplay_ = -1; bool enableReporting_; bool ratingEnabled_; + bool tookScreenshot_ = false; bool includeScreenshot_ = true; }; diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 5ec73aa9ca..2fa6b2d474 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -18,22 +18,23 @@ #include #include -#include "base/colorutil.h" -#include "base/timeutil.h" -#include "gfx_es2/draw_buffer.h" -#include "i18n/i18n.h" -#include "math/curves.h" -#include "thread/prioritizedworkqueue.h" -#include "util/text/utf8.h" -#include "ui/ui_context.h" -#include "ui/view.h" -#include "ui/viewgroup.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Math/curves.h" +#include "Common/Thread/PrioritizedWorkQueue.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/UI/Context.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" #include "UI/SavedataScreen.h" #include "UI/MainScreen.h" #include "UI/GameInfoCache.h" #include "UI/PauseScreen.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" #include "Core/Host.h" #include "Core/Config.h" #include "Core/Loaders.h" @@ -247,7 +248,7 @@ void SavedataButton::Draw(UIContext &dc) { if (HasFocus()) { dc.Draw()->Flush(); dc.RebindTexture(); - float pulse = sinf(time_now() * 7.0f) * 0.25 + 0.8; + float pulse = sin(time_now_d() * 7.0) * 0.25 + 0.8; dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid, x - dropsize*1.5f, y - dropsize*1.5f, x + w + dropsize*1.5f, y + h + dropsize*1.5f, alphaMul(color, pulse), 1.0f); dc.Draw()->Flush(); } else { diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index 49da370483..9e02f8c9cb 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -20,9 +20,9 @@ #include #include -#include "ui/ui_screen.h" -#include "ui/view.h" -#include "ui/viewgroup.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" diff --git a/UI/Store.cpp b/UI/Store.cpp index b94dc9bab2..b7601bf927 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -17,16 +17,15 @@ #include -#include "base/basictypes.h" -#include "json/json_reader.h" - -#include "i18n/i18n.h" -#include "ui/screen.h" -#include "ui/ui_context.h" -#include "ui/viewgroup.h" -#include "gfx_es2/draw_buffer.h" +#include "Common/UI/Screen.h" +#include "Common/UI/Context.h" +#include "Common/UI/ViewGroup.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Common.h" #include "Common/Log.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Format/JSONReader.h" #include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/System.h" @@ -139,7 +138,7 @@ void HttpImageFileView::Draw(UIContext &dc) { } if (!textureData_.empty()) { - texture_ = CreateTextureFromFileData(dc.GetDrawContext(), (const uint8_t *)(textureData_.data()), (int)textureData_.size(), DETECT); + texture_ = CreateTextureFromFileData(dc.GetDrawContext(), (const uint8_t *)(textureData_.data()), (int)textureData_.size(), DETECT, false, "store_icon"); if (!texture_) textureFailed_ = true; textureData_.clear(); @@ -370,7 +369,7 @@ void StoreScreen::update() { RecreateViews(); } else { // Failed to contact store. Don't do anything. - ELOG("Download failed : error code %d", listing_->ResultCode()); + ERROR_LOG(IO, "Download failed : error code %d", listing_->ResultCode()); connectionError_ = true; loading_ = false; RecreateViews(); @@ -398,7 +397,7 @@ void StoreScreen::ParseListing(std::string json) { using namespace json; JsonReader reader(json.c_str(), json.size()); if (!reader.ok() || !reader.root()) { - ELOG("Error parsing JSON from store"); + ERROR_LOG(IO, "Error parsing JSON from store"); connectionError_ = true; RecreateViews(); return; diff --git a/UI/Store.h b/UI/Store.h index c935bcb042..b8cc7aefd0 100644 --- a/UI/Store.h +++ b/UI/Store.h @@ -19,9 +19,9 @@ #include -#include "ui/ui_screen.h" -#include "ui/viewgroup.h" -#include "net/http_client.h" +#include "Common/UI/UIScreen.h" +#include "Common/UI/ViewGroup.h" +#include "Common/Net/HTTPClient.h" #include "UI/MiscScreens.h" diff --git a/UI/TextureUtil.cpp b/UI/TextureUtil.cpp index b79459f769..cdfe9440e2 100644 --- a/UI/TextureUtil.cpp +++ b/UI/TextureUtil.cpp @@ -1,18 +1,19 @@ #include -#include "base/colorutil.h" -#include "base/timeutil.h" -#include "thin3d/thin3d.h" -#include "image/zim_load.h" -#include "image/png_load.h" -#include "math/math_util.h" -#include "math/curves.h" -#include "file/vfs.h" +#include "Common/GPU/thin3d.h" #include "ext/jpge/jpgd.h" -#include "ui/view.h" -#include "ui/ui_context.h" -#include "gfx_es2/draw_buffer.h" +#include "Common/UI/View.h" +#include "Common/UI/Context.h" +#include "Common/Render/DrawBuffer.h" + +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Data/Format/ZIMLoad.h" +#include "Common/Data/Format/PNGLoad.h" +#include "Common/Math/math_util.h" +#include "Common/Math/curves.h" +#include "Common/File/VFS/VFS.h" #include "Common/Log.h" +#include "Common/TimeUtil.h" #include "UI/TextureUtil.h" #include "UI/GameInfoCache.h" @@ -24,13 +25,16 @@ static Draw::DataFormat ZimToT3DFormat(int zim) { } static ImageFileType DetectImageFileType(const uint8_t *data, size_t size) { + if (size < 4) { + return TYPE_UNKNOWN; + } if (!memcmp(data, "ZIMG", 4)) { return ZIM; } else if (!memcmp(data, "\x89\x50\x4E\x47", 4)) { return PNG; } - else if (!memcmp(data, "\xff\xd8\xff\xe0", 4)) { + else if (!memcmp(data, "\xff\xd8\xff\xe0", 4) || !memcmp(data, "\xff\xd8\xff\xe1", 4)) { return JPEG; } else { @@ -43,7 +47,7 @@ static bool LoadTextureLevels(const uint8_t *data, size_t size, ImageFileType ty type = DetectImageFileType(data, size); } if (type == TYPE_UNKNOWN) { - ELOG("File (size: %d) has unknown format", (int)size); + ERROR_LOG(G3D, "File (size: %d) has unknown format", (int)size); return false; } @@ -59,15 +63,15 @@ static bool LoadTextureLevels(const uint8_t *data, size_t size, ImageFileType ty break; case PNG: - if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0], false)) { + if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0])) { *num_levels = 1; *fmt = Draw::DataFormat::R8G8B8A8_UNORM; if (!image[0]) { - ELOG("WTF"); + ERROR_LOG(IO, "WTF"); return false; } } else { - ELOG("PNG load failed"); + ERROR_LOG(IO, "PNG load failed"); return false; } break; @@ -85,14 +89,14 @@ static bool LoadTextureLevels(const uint8_t *data, size_t size, ImageFileType ty break; default: - ELOG("Unsupported image format %d", (int)type); + ERROR_LOG(IO, "Unsupported image format %d", (int)type); return false; } return *num_levels > 0; } -bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type, bool generateMips) { +bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type, bool generateMips, const char *name) { generateMips_ = generateMips; using namespace Draw; @@ -106,12 +110,10 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag return false; } - if (!image[0]) { - Crash(); - } + _assert_(image[0] != nullptr); if (num_levels < 0 || num_levels >= 16) { - ELOG("Invalid num_levels: %d. Falling back to one. Image: %dx%d", num_levels, width[0], height[0]); + ERROR_LOG(IO, "Invalid num_levels: %d. Falling back to one. Image: %dx%d", num_levels, width[0], height[0]); num_levels = 1; } @@ -131,7 +133,7 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag desc.depth = 1; desc.mipLevels = generateMips ? potentialLevels : num_levels; desc.generateMips = generateMips && potentialLevels > num_levels; - desc.tag = "LoadedFileData"; + desc.tag = name; for (int i = 0; i < num_levels; i++) { desc.initData.push_back(image[i]); } @@ -149,15 +151,15 @@ bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType typ uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize); if (!buffer) { filename_ = ""; - ELOG("Failed to read file '%s'", filename.c_str()); + ERROR_LOG(IO, "Failed to read file '%s'", filename.c_str()); return false; } - bool retval = LoadFromFileData(buffer, fileSize, type, generateMips); + bool retval = LoadFromFileData(buffer, fileSize, type, generateMips, filename.c_str()); if (retval) { filename_ = filename; } else { filename_ = ""; - ELOG("Failed to load texture '%s'", filename.c_str()); + ERROR_LOG(IO, "Failed to load texture '%s'", filename.c_str()); } delete[] buffer; return retval; @@ -176,14 +178,14 @@ std::unique_ptr CreateTextureFromFile(Draw::DrawContext *draw, c } void ManagedTexture::DeviceLost() { - ILOG("ManagedTexture::DeviceLost(%s)", filename_.c_str()); + INFO_LOG(G3D, "ManagedTexture::DeviceLost(%s)", filename_.c_str()); if (texture_) texture_->Release(); texture_ = nullptr; } void ManagedTexture::DeviceRestored(Draw::DrawContext *draw) { - ILOG("ManagedTexture::DeviceRestored(%s)", filename_.c_str()); + INFO_LOG(G3D, "ManagedTexture::DeviceRestored(%s)", filename_.c_str()); _assert_(!texture_); draw_ = draw; // Vulkan: Can't load textures before the first frame has started. @@ -194,7 +196,7 @@ void ManagedTexture::DeviceRestored(Draw::DrawContext *draw) { Draw::Texture *ManagedTexture::GetTexture() { if (loadPending_) { if (!LoadFromFile(filename_, ImageFileType::DETECT, generateMips_)) { - ELOG("ManagedTexture failed: '%s'", filename_.c_str()); + ERROR_LOG(IO, "ManagedTexture failed: '%s'", filename_.c_str()); } loadPending_ = false; } @@ -202,11 +204,11 @@ Draw::Texture *ManagedTexture::GetTexture() { } // TODO: Remove the code duplication between this and LoadFromFileData -std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType type, bool generateMips) { +std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType type, bool generateMips, const char *name) { if (!draw) return std::unique_ptr(); ManagedTexture *mtex = new ManagedTexture(draw); - if (mtex->LoadFromFileData(data, size, type, generateMips)) { + if (mtex->LoadFromFileData(data, size, type, generateMips, name)) { return std::unique_ptr(mtex); } else { // Best to return a null pointer if we fail! diff --git a/UI/TextureUtil.h b/UI/TextureUtil.h index 6a93f4809b..5a4710a65a 100644 --- a/UI/TextureUtil.h +++ b/UI/TextureUtil.h @@ -2,8 +2,8 @@ #include -#include "thin3d/thin3d.h" -#include "ui/view.h" +#include "Common/GPU/thin3d.h" +#include "Common/UI/View.h" enum ImageFileType { PNG, @@ -23,7 +23,7 @@ public: } bool LoadFromFile(const std::string &filename, ImageFileType type = ImageFileType::DETECT, bool generateMips = false); - bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type = ImageFileType::DETECT, bool generateMips = false); + bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type, bool generateMips, const char *name); Draw::Texture *GetTexture(); // For immediate use, don't store. int Width() const { return texture_->Width(); } int Height() const { return texture_->Height(); } @@ -39,8 +39,8 @@ private: bool loadPending_ = false; }; -std::unique_ptr CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType, bool generateMips = false); -std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType, bool generateMips = false); +std::unique_ptr CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType, bool generateMips); +std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType, bool generateMips, const char *name); class GameIconView : public UI::InertView { public: diff --git a/UI/TiltAnalogSettingsScreen.cpp b/UI/TiltAnalogSettingsScreen.cpp index 1281c5658f..e4379606e7 100644 --- a/UI/TiltAnalogSettingsScreen.cpp +++ b/UI/TiltAnalogSettingsScreen.cpp @@ -18,7 +18,7 @@ #include "TiltAnalogSettingsScreen.h" #include "Core/Config.h" #include "Core/System.h" -#include "i18n/i18n.h" +#include "Common/Data/Text/I18n.h" void TiltAnalogSettingsScreen::CreateViews() { using namespace UI; diff --git a/UI/TiltAnalogSettingsScreen.h b/UI/TiltAnalogSettingsScreen.h index 172675c2c6..41692bb46f 100644 --- a/UI/TiltAnalogSettingsScreen.h +++ b/UI/TiltAnalogSettingsScreen.h @@ -19,7 +19,7 @@ #include -#include "ui/view.h" +#include "Common/UI/View.h" #include "MiscScreens.h" class TiltAnalogSettingsScreen : public UIDialogScreenWithBackground { diff --git a/UI/TiltEventProcessor.cpp b/UI/TiltEventProcessor.cpp index 97b5bcd90a..2f66906239 100644 --- a/UI/TiltEventProcessor.cpp +++ b/UI/TiltEventProcessor.cpp @@ -1,11 +1,10 @@ #define _USE_MATH_DEFINES + #include -#include "UI/TiltEventProcessor.h" + #include "Core/Config.h" #include "Core/HLE/sceCtrl.h" -#include "math.h" -#include "base/logging.h" - +#include "UI/TiltEventProcessor.h" using namespace TiltEventProcessor; diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 3e454c5190..c180541833 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -18,21 +18,20 @@ #include #include -#include "base/colorutil.h" -#include "gfx_es2/draw_buffer.h" -#include "i18n/i18n.h" -#include "math/math_util.h" -#include "ui/ui_context.h" +#include "Common/Data/Color/RGBAUtil.h" +#include "Common/Render/DrawBuffer.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Math/math_util.h" +#include "Common/UI/Context.h" #include "Common/Common.h" +#include "Common/Log.h" #include "Core/Config.h" #include "Core/System.h" #include "UI/GamepadEmu.h" #include "UI/TouchControlLayoutScreen.h" #include "UI/TouchControlVisibilityScreen.h" -static const int leftColumnWidth = 140; - static u32 GetButtonColor() { return g_Config.iTouchButtonStyle != 0 ? 0xFFFFFF : 0xc0b080; } @@ -40,7 +39,7 @@ static u32 GetButtonColor() { class DragDropButton : public MultiTouchButton { public: DragDropButton(ConfigTouchPos &pos, ImageID bgImg, ImageID img, const Bounds &screenBounds) - : MultiTouchButton(bgImg, bgImg, img, pos.scale, new UI::AnchorLayoutParams(fromFullscreenCoord(pos.x, screenBounds), pos.y * screenBounds.h, UI::NONE, UI::NONE, true)), + : MultiTouchButton(bgImg, bgImg, img, pos.scale, new UI::AnchorLayoutParams(pos.x * screenBounds.w, pos.y * screenBounds.h, UI::NONE, UI::NONE, true)), x_(pos.x), y_(pos.y), theScale_(pos.scale), screenBounds_(screenBounds) { scale_ = theScale_; } @@ -52,8 +51,8 @@ public: }; virtual void SavePosition() { - x_ = toFullscreenCoord(bounds_.centerX()); - y_ = bounds_.centerY() / screenBounds_.h; + x_ = (bounds_.centerX() - screenBounds_.x) / screenBounds_.w; + y_ = (bounds_.centerY() - screenBounds_.y) / screenBounds_.h; scale_ = theScale_; } @@ -70,16 +69,6 @@ protected: } private: - // convert from screen coordinates (leftColumnWidth to dp_xres) to actual fullscreen coordinates (0 to 1.0) - inline float toFullscreenCoord(int screenx) { - return (float)(screenx - leftColumnWidth) / (screenBounds_.w - leftColumnWidth); - } - - // convert from external fullscreen coordinates(0 to 1.0) to the current partial coordinates (leftColumnWidth to dp_xres) - inline int fromFullscreenCoord(float controllerX, const Bounds &screenBounds) { - return leftColumnWidth + (screenBounds.w - leftColumnWidth) * controllerX; - }; - float &x_, &y_; float &theScale_; const Bounds &screenBounds_; @@ -93,19 +82,19 @@ public: roundId_ = g_Config.iTouchButtonStyle ? ImageID("I_ROUND_LINE") : ImageID("I_ROUND"); }; - void setCircleVisibility(bool visible){ + void setCircleVisibility(bool visible) { circleVisible_ = visible; } - void setCrossVisibility(bool visible){ + void setCrossVisibility(bool visible) { crossVisible_ = visible; } - void setTriangleVisibility(bool visible){ + void setTriangleVisibility(bool visible) { triangleVisible_ = visible; } - void setSquareVisibility(bool visible){ + void setSquareVisibility(bool visible) { squareVisible_ = visible; } @@ -221,10 +210,12 @@ public: if (g_Config.bTouchSnapToGrid) { dc.Flush(); dc.BeginNoTex(); + float xOffset = bounds_.x; + float yOffset = bounds_.y; for (int x = x1; x < x2; x += g_Config.iTouchSnapGridSize) - dc.Draw()->vLine(x, y1, y2, col); + dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col); for (int y = y1; y < y2; y += g_Config.iTouchSnapGridSize) - dc.Draw()->hLine(x1, y, x2, col); + dc.Draw()->hLine(x1 + xOffset, y + yOffset, x2 + xOffset, col); dc.Flush(); dc.Begin(); } @@ -235,51 +226,77 @@ private: u32 col; }; -TouchControlLayoutScreen::TouchControlLayoutScreen() { - pickedControl_ = 0; +class DragDropButton; + +class ControlLayoutView : public UI::AnchorLayout { +public: + explicit ControlLayoutView(UI::LayoutParams *layoutParams) + : UI::AnchorLayout(layoutParams) { + } + + void Touch(const TouchInput &input) override; + void CreateViews(); + bool HasCreatedViews() const { + return !controls_.empty(); + } + + DragDropButton *pickedControl_ = nullptr; + DragDropButton *getPickedControl(const int x, const int y); + std::vector controls_; + + // Touch down state for dragging + float startObjectX_ = -1.0f; + float startObjectY_ = -1.0f; + float startDragX_ = -1.0f; + float startDragY_ = -1.0f; + float startScale_ = -1.0f; + float startSpacing_ = -1.0f; + + int mode_ = 0; }; static Point ClampTo(const Point &p, const Bounds &b) { return Point(clamp_value(p.x, b.x, b.x + b.w), clamp_value(p.y, b.y, b.y + b.h)); } -bool TouchControlLayoutScreen::touch(const TouchInput &touch) { - UIScreen::touch(touch); - +void ControlLayoutView::Touch(const TouchInput &touch) { using namespace UI; if ((touch.flags & TOUCH_MOVE) && pickedControl_ != nullptr) { - int mode = mode_->GetSelection(); - if (mode == 0) { - const Bounds &bounds = pickedControl_->GetBounds(); - const auto &prevParams = pickedControl_->GetLayoutParams()->As(); - Point newPos(prevParams->left, prevParams->top); + if (mode_ == 0) { + const Bounds &controlBounds = pickedControl_->GetBounds(); - Bounds validRange = screenManager()->getUIContext()->GetBounds(); - validRange.x += leftColumnWidth + bounds.w * 0.5f; - validRange.w -= leftColumnWidth + bounds.w; - validRange.y += bounds.h * 0.5f; - validRange.h -= bounds.h; + // Allow placing the control halfway outside the play area. + Bounds validRange = this->GetBounds(); + // Control coordinates are relative inside the bounds. + validRange.x = 0.0f; + validRange.y = 0.0f; - newPos.x = touch.x; - newPos.y = touch.y; + validRange.x += controlBounds.w * 0.5f; + validRange.w -= controlBounds.w; + validRange.y += controlBounds.h * 0.5f; + validRange.h -= controlBounds.h; + + Point newPos; + newPos.x = startObjectX_ + (touch.x - startDragX_); + newPos.y = startObjectY_ + (touch.y - startDragY_); if (g_Config.bTouchSnapToGrid) { - newPos.x -= (int)(newPos.x - bounds.w) % g_Config.iTouchSnapGridSize; - newPos.y -= (int)(newPos.y - bounds.h) % g_Config.iTouchSnapGridSize; + newPos.x -= fmod(newPos.x - controlBounds.w, g_Config.iTouchSnapGridSize); + newPos.y -= fmod(newPos.y - controlBounds.h, g_Config.iTouchSnapGridSize); } newPos = ClampTo(newPos, validRange); pickedControl_->ReplaceLayoutParams(new AnchorLayoutParams(newPos.x, newPos.y, NONE, NONE, true)); - } else if (mode == 1) { + } else if (mode_ == 1) { // Resize. Vertical = scaling, horizontal = spacing; // Up should be bigger so let's negate in that direction - float diffX = (touch.x - startX_); - float diffY = -(touch.y - startY_); + float diffX = (touch.x - startDragX_); + float diffY = -(touch.y - startDragY_); // Snap to grid if (g_Config.bTouchSnapToGrid) { - diffX -= (int)(touch.x - startX_) % (g_Config.iTouchSnapGridSize/2); - diffY += (int)(touch.y - startY_) % (g_Config.iTouchSnapGridSize/2); + diffX -= fmod(touch.x - startDragX_, g_Config.iTouchSnapGridSize/2); + diffY += fmod(touch.y - startDragY_, g_Config.iTouchSnapGridSize/2); } float movementScale = 0.02f; float newScale = startScale_ + diffY * movementScale; @@ -295,8 +312,12 @@ bool TouchControlLayoutScreen::touch(const TouchInput &touch) { if ((touch.flags & TOUCH_DOWN) && pickedControl_ == 0) { pickedControl_ = getPickedControl(touch.x, touch.y); if (pickedControl_) { - startX_ = touch.x; - startY_ = touch.y; + startDragX_ = touch.x; + startDragY_ = touch.y; + const auto &prevParams = pickedControl_->GetLayoutParams()->As(); + startObjectX_ = prevParams->left; + startObjectY_ = prevParams->top; + startSpacing_ = pickedControl_->GetSpacing(); startScale_ = pickedControl_->GetScale(); } @@ -305,91 +326,17 @@ bool TouchControlLayoutScreen::touch(const TouchInput &touch) { pickedControl_->SavePosition(); pickedControl_ = 0; } - return true; } -void TouchControlLayoutScreen::resized() { - RecreateViews(); -} - -void TouchControlLayoutScreen::onFinish(DialogResult reason) { - g_Config.Save("TouchControlLayoutScreen::onFinish"); -} - -UI::EventReturn TouchControlLayoutScreen::OnVisibility(UI::EventParams &e) { - screenManager()->push(new TouchControlVisibilityScreen()); - return UI::EVENT_DONE; -} - -UI::EventReturn TouchControlLayoutScreen::OnReset(UI::EventParams &e) { - ILOG("Resetting touch control layout"); - g_Config.ResetControlLayout(); - const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); - InitPadLayout(bounds.w, bounds.h); - RecreateViews(); - return UI::EVENT_DONE; -}; - -void TouchControlLayoutScreen::dialogFinished(const Screen *dialog, DialogResult result) { - RecreateViews(); -} - -void TouchControlLayoutScreen::CreateViews() { - // setup g_Config for button layout - const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); - InitPadLayout(bounds.w, bounds.h); - - using namespace UI; - - auto co = GetI18NCategory("Controls"); - auto di = GetI18NCategory("Dialog"); - - root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - - Choice *reset = new Choice(di->T("Reset"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 84)); - Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10)); - Choice *visibility = new Choice(co->T("Visibility"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 298)); - // controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fButtonScale, 0.80, 2.0, co->T("Button Scaling"), screenManager())) - // ->OnChange.Handle(this, &GameSettingsScreen::OnChangeControlScaling); - - CheckBox *snap = new CheckBox(&g_Config.bTouchSnapToGrid, di->T("Snap"), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 228)); - PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 2, 256, di->T("Grid"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158)); - gridSize->SetEnabledPtr(&g_Config.bTouchSnapToGrid); - - mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 140 + 158 + 64 + 10)); - mode_->AddChoice(di->T("Move")); - mode_->AddChoice(di->T("Resize")); - mode_->SetSelection(0); - - reset->OnClick.Handle(this, &TouchControlLayoutScreen::OnReset); - back->OnClick.Handle(this, &UIScreen::OnBack); - visibility->OnClick.Handle(this, &TouchControlLayoutScreen::OnVisibility); - root_->Add(mode_); - root_->Add(visibility); - root_->Add(snap); - root_->Add(gridSize); - root_->Add(reset); - root_->Add(back); - - TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, leftColumnWidth, new AnchorLayoutParams(10, 0, 10, 0, false)); - tabHolder->SetTag("TouchControlLayout"); - root_->Add(tabHolder); - - // this is more for show than anything else. It's used to provide a boundary - // so that buttons like back can be placed within the boundary. - // serves no other purpose. - AnchorLayout *controlsHolder = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - - auto ms = GetI18NCategory("MainSettings"); - - //tabHolder->AddTab(ms->T("Controls"), controlsHolder); - - if (!g_Config.bShowTouchControls) { - // Shouldn't even be able to get here as the way into this dialog should be closed. +void ControlLayoutView::CreateViews() { + const Bounds &bounds = GetBounds(); + if (bounds.w == 0.0f || bounds.h == 0.0f) { + // Layout hasn't happened yet, return. + // See comment in TouchControlLayoutScreen::update(). return; } - controls_.clear(); + // Create all the views. PSPActionButtons *actionButtons = new PSPActionButtons(g_Config.touchActionButtonCenter, g_Config.fActionButtonSpacing, bounds); actionButtons->setCircleVisibility(g_Config.bShowTouchCircle); @@ -457,15 +404,15 @@ void TouchControlLayoutScreen::CreateViews() { addDragDropButton(g_Config.touchCombo4, roundImage, comboKeyImages[4]); for (size_t i = 0; i < controls_.size(); i++) { - root_->Add(controls_[i]); + Add(controls_[i]); } - root_->Add(new SnapGrid(leftColumnWidth+10, bounds.w, 0, bounds.h, 0x3FFFFFFF)); + Add(new SnapGrid(0, bounds.w, 0, bounds.h, 0x3FFFFFFF)); } // return the control which was picked up by the touchEvent. If a control // was already picked up, then it's being dragged around, so just return that instead -DragDropButton *TouchControlLayoutScreen::getPickedControl(const int x, const int y) { +DragDropButton *ControlLayoutView::getPickedControl(const int x, const int y) { if (pickedControl_ != 0) { return pickedControl_; } @@ -473,9 +420,11 @@ DragDropButton *TouchControlLayoutScreen::getPickedControl(const int x, const in for (size_t i = 0; i < controls_.size(); i++) { DragDropButton *control = controls_[i]; const Bounds &bounds = control->GetBounds(); - const float thresholdFactor = 1.5f; + const float thresholdFactor = 0.25f; + const float thresholdW = thresholdFactor * bounds.w; + const float thresholdH = thresholdFactor * bounds.h; - Bounds tolerantBounds(bounds.x, bounds.y, bounds.w * thresholdFactor, bounds.h * thresholdFactor); + Bounds tolerantBounds(bounds.x - thresholdW * 0.5, bounds.y - thresholdH * 0.5 , bounds.w + thresholdW, bounds.h + thresholdH); if (tolerantBounds.Contains(x, y)) { return control; } @@ -483,3 +432,112 @@ DragDropButton *TouchControlLayoutScreen::getPickedControl(const int x, const in return 0; } + +TouchControlLayoutScreen::TouchControlLayoutScreen() {} + +void TouchControlLayoutScreen::resized() { + RecreateViews(); +} + +void TouchControlLayoutScreen::onFinish(DialogResult reason) { + g_Config.Save("TouchControlLayoutScreen::onFinish"); +} + +UI::EventReturn TouchControlLayoutScreen::OnVisibility(UI::EventParams &e) { + screenManager()->push(new TouchControlVisibilityScreen()); + return UI::EVENT_DONE; +} + +UI::EventReturn TouchControlLayoutScreen::OnReset(UI::EventParams &e) { + INFO_LOG(G3D, "Resetting touch control layout"); + g_Config.ResetControlLayout(); + const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); + InitPadLayout(bounds.w, bounds.h); + RecreateViews(); + return UI::EVENT_DONE; +}; + +void TouchControlLayoutScreen::dialogFinished(const Screen *dialog, DialogResult result) { + RecreateViews(); +} + +UI::EventReturn TouchControlLayoutScreen::OnMode(UI::EventParams &e) { + int mode = mode_->GetSelection(); + if (layoutView_) { + layoutView_->mode_ = mode; + } + return UI::EVENT_DONE; +} + +void TouchControlLayoutScreen::update() { + UIDialogScreenWithBackground::update(); + + // TODO: We really, really need a cleaner solution for creating sub-views + // of custom compound controls. + if (layoutView_) { + if (!layoutView_->HasCreatedViews()) { + layoutView_->CreateViews(); + } + } +} + +void TouchControlLayoutScreen::CreateViews() { + // setup g_Config for button layout + const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); + InitPadLayout(bounds.w, bounds.h); + + const float leftColumnWidth = 140.0f; + + using namespace UI; + + auto co = GetI18NCategory("Controls"); + auto di = GetI18NCategory("Dialog"); + + root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + + Choice *reset = new Choice(di->T("Reset"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 84)); + Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10)); + Choice *visibility = new Choice(co->T("Visibility"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 298)); + // controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fButtonScale, 0.80, 2.0, co->T("Button Scaling"), screenManager())) + // ->OnChange.Handle(this, &GameSettingsScreen::OnChangeControlScaling); + + CheckBox *snap = new CheckBox(&g_Config.bTouchSnapToGrid, di->T("Snap"), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 228)); + PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 2, 256, di->T("Grid"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158)); + gridSize->SetEnabledPtr(&g_Config.bTouchSnapToGrid); + + mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 140 + 158 + 64 + 10)); + mode_->AddChoice(di->T("Move")); + mode_->AddChoice(di->T("Resize")); + mode_->SetSelection(0); + mode_->OnChoice.Handle(this, &TouchControlLayoutScreen::OnMode); + + reset->OnClick.Handle(this, &TouchControlLayoutScreen::OnReset); + back->OnClick.Handle(this, &UIScreen::OnBack); + visibility->OnClick.Handle(this, &TouchControlLayoutScreen::OnVisibility); + root_->Add(mode_); + root_->Add(visibility); + root_->Add(snap); + root_->Add(gridSize); + root_->Add(reset); + root_->Add(back); + + TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, leftColumnWidth, new AnchorLayoutParams(10, 0, 10, 0, false)); + tabHolder->SetTag("TouchControlLayout"); + root_->Add(tabHolder); + + layoutView_ = root_->Add(new ControlLayoutView(new AnchorLayoutParams(leftColumnWidth + 10, 0.0f, 0.0f, 0.0f, false))); + + // this is more for show than anything else. It's used to provide a boundary + // so that buttons like back can be placed within the boundary. + // serves no other purpose. + // AnchorLayout *controlsHolder = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + + auto ms = GetI18NCategory("MainSettings"); + + //tabHolder->AddTab(ms->T("Controls"), controlsHolder); + + if (!g_Config.bShowTouchControls) { + // Shouldn't even be able to get here as the way into this dialog should be closed. + return; + } +} diff --git a/UI/TouchControlLayoutScreen.h b/UI/TouchControlLayoutScreen.h index 789d5a25e7..89305ab7d6 100644 --- a/UI/TouchControlLayoutScreen.h +++ b/UI/TouchControlLayoutScreen.h @@ -20,35 +20,28 @@ #include #include -#include "ui/view.h" -#include "ui/viewgroup.h" +#include "Common/UI/View.h" +#include "Common/UI/ViewGroup.h" #include "MiscScreens.h" -class DragDropButton; +class ControlLayoutView; class TouchControlLayoutScreen : public UIDialogScreenWithBackground { public: TouchControlLayoutScreen(); virtual void CreateViews() override; - virtual bool touch(const TouchInput &touch) override; virtual void dialogFinished(const Screen *dialog, DialogResult result) override; virtual void onFinish(DialogResult reason) override; + virtual void update() override; virtual void resized() override; protected: virtual UI::EventReturn OnReset(UI::EventParams &e); virtual UI::EventReturn OnVisibility(UI::EventParams &e); + virtual UI::EventReturn OnMode(UI::EventParams &e); private: - DragDropButton *pickedControl_; - std::vector controls_; - UI::ChoiceStrip *mode_; - DragDropButton *getPickedControl(const int x, const int y); - - // Touch down state for drag to resize etc - float startX_; - float startY_; - float startScale_; - float startSpacing_; + UI::ChoiceStrip *mode_ = nullptr; + ControlLayoutView *layoutView_ = nullptr; }; diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index 9923b7bf9e..dab63b2940 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -15,11 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "gfx/texture_atlas.h" +#include "Common/Render/TextureAtlas.h" #include "TouchControlVisibilityScreen.h" #include "Core/Config.h" -#include "i18n/i18n.h" +#include "Common/Data/Text/I18n.h" static const int leftColumnWidth = 140; @@ -104,7 +104,7 @@ void TouchControlVisibilityScreen::CreateViews() { row->Add(checkbox); if (toggle.key == rightAnalogKey) { - Choice *rightAnalog = new Choice(co->T(rightAnalogKey), "", false, new LinearLayoutParams(1.0f)); + Choice *rightAnalog = new Choice(mc->T(rightAnalogKey), "", false, new LinearLayoutParams(1.0f)); rightAnalog->SetCentered(true); row->Add(rightAnalog)->OnClick.Handle(this, &TouchControlVisibilityScreen::RightAnalogBindScreen); } else { @@ -130,6 +130,7 @@ void RightAnalogMappingScreen::CreateViews() { auto di = GetI18NCategory("Dialog"); auto co = GetI18NCategory("Controls"); + auto mc = GetI18NCategory("MappableControls"); root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth - 10, WRAP_CONTENT, 10, NONE, NONE, 10)); @@ -141,14 +142,14 @@ void RightAnalogMappingScreen::CreateViews() { LinearLayout *vert = rightPanel->Add(new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT))); vert->SetSpacing(0); - static const char *rightAnalogButton[] = {"None", "Left trigger", "Right trigger", "Square", "Triangle", "Circle", "Cross", "D-PAD Up", "D-PAD Down", "D-PAD Left", "D-PAD Right", "Start", "Select"}; + static const char *rightAnalogButton[] = {"None", "L", "R", "Square", "Triangle", "Circle", "Cross", "D-pad up", "D-pad down", "D-pad left", "D-pad right", "Start", "Select"}; vert->Add(new CheckBox(&g_Config.bRightAnalogCustom, co->T("Use custom right analog"))); - PopupMultiChoice *rightAnalogUp = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogUp, co->T("Right analog up"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), co->GetName(), screenManager())); - PopupMultiChoice *rightAnalogDown = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogDown, co->T("Right analog down"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), co->GetName(), screenManager())); - PopupMultiChoice *rightAnalogLeft = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogLeft, co->T("Right analog left"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), co->GetName(), screenManager())); - PopupMultiChoice *rightAnalogRight = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogRight, co->T("Right analog right"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), co->GetName(), screenManager())); - PopupMultiChoice *rightAnalogPress = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogPress, co->T("Keep this button pressed when right analog is pressed"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), co->GetName(), screenManager())); + PopupMultiChoice *rightAnalogUp = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogUp, mc->T("RightAn.Up"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); + PopupMultiChoice *rightAnalogDown = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogDown, mc->T("RightAn.Down"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); + PopupMultiChoice *rightAnalogLeft = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogLeft, mc->T("RightAn.Left"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); + PopupMultiChoice *rightAnalogRight = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogRight, mc->T("RightAn.Right"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); + PopupMultiChoice *rightAnalogPress = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogPress, co->T("Keep this button pressed when right analog is pressed"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); vert->Add(new CheckBox(&g_Config.touchRightAnalogStick.show, co->T("Show right analog"))); rightAnalogUp->SetEnabledPtr(&g_Config.bRightAnalogCustom); rightAnalogDown->SetEnabledPtr(&g_Config.bRightAnalogCustom); diff --git a/UI/TouchControlVisibilityScreen.h b/UI/TouchControlVisibilityScreen.h index 895078626b..04be4a1872 100644 --- a/UI/TouchControlVisibilityScreen.h +++ b/UI/TouchControlVisibilityScreen.h @@ -17,7 +17,7 @@ #pragma once -#include "gfx/texture_atlas.h" +#include "Common/Render/TextureAtlas.h" #include "MiscScreens.h" namespace UI { diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 1f69ed9e27..8c621c2f4e 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -207,7 +207,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext true false false @@ -220,10 +220,6 @@ Windows true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - @@ -231,7 +227,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext true false false @@ -245,10 +241,6 @@ Windows true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - @@ -256,7 +248,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\aarch64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext true false false @@ -270,10 +262,6 @@ Windows true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - @@ -281,7 +269,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\arm\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext true false false @@ -296,10 +284,6 @@ Windows true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - @@ -310,7 +294,7 @@ true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext false Size true @@ -325,10 +309,6 @@ true true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - @@ -339,7 +319,7 @@ true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext false true false @@ -356,10 +336,6 @@ true true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - @@ -370,7 +346,7 @@ true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\aarch64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext false true false @@ -387,10 +363,6 @@ true true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - @@ -401,7 +373,7 @@ true true USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext + ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\arm\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext false true false @@ -418,10 +390,6 @@ true true - - Updating git-version.cpp - ../Windows/git-version-gen.cmd - diff --git a/UWP/App.cpp b/UWP/App.cpp index 586d679581..94159e7602 100644 --- a/UWP/App.cpp +++ b/UWP/App.cpp @@ -5,8 +5,9 @@ #include -#include "input/input_state.h" -#include "base/NativeApp.h" +#include "Common/Input/InputState.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" #include "Core/System.h" #include "Core/Core.h" diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index a5fe599d10..e8d56b3ab6 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -200,12 +200,12 @@ - Use false true pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NotUsing Console @@ -215,12 +215,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h + NotUsing Console @@ -230,12 +230,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h + NotUsing Console @@ -245,12 +245,12 @@ - Use false true pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + NotUsing Console @@ -260,12 +260,12 @@ - Use false true pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + NotUsing Console @@ -275,12 +275,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h + NotUsing Console @@ -290,12 +290,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h + NotUsing Console @@ -305,12 +305,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h + NotUsing Console @@ -320,12 +320,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h + NotUsing Console @@ -335,12 +335,12 @@ - Use false true pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NotUsing Console @@ -350,12 +350,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h + NotUsing Console @@ -365,12 +365,12 @@ - Use false true - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h + NotUsing Console @@ -383,8 +383,76 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -398,28 +466,43 @@ - - + - - - - - - + + + + + + + + - + + + + + + + + + - + + + + + + + @@ -427,7 +510,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -435,8 +570,8 @@ - - + + @@ -445,32 +580,51 @@ - - + - - + + + + + - + + + + + + + + + - - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 566049b279..7576f5735f 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -4,20 +4,100 @@ {da855697-f7aa-49bf-b969-7a90c5b4d259} + + {c2303262-a4f0-4400-8dd7-35ad6ac5f443} + + + {b0ac485c-3153-4708-b098-f5a518a95b79} + + + {819c6967-1ed6-4fec-8415-a018ae524180} + + + {7368a8e7-cf29-49e9-87be-f1e69771555e} + + + {93937cf8-9cc6-4ea5-a9c8-bdc186aa0317} + + + {ad268930-1885-451c-969d-39871232244a} + + + {553115bf-c2fa-4c7d-a1db-587b2337c73f} + + + {4451d43c-69ec-42d2-8f0f-09032a1c46f1} + + + {c6e1a659-b5d9-4015-93b4-9e383959b19c} + + + {99f1fb79-2a8c-4ac0-8cba-57d9b2f87d32} + + + {7277c320-2c19-40d0-81a4-2f6cbb20790c} + + + {f924399b-932d-4aeb-b4e1-1da72f1fd2e3} + + + {211cb745-2675-4667-b0aa-964f33fc67dd} + + + {6f1f3b4e-8efd-4f39-b5a9-50d7c75b4616} + + + {56599f1d-b05b-4b55-b664-e6738d5edafc} + + + {4841c76f-fc06-41b0-9fbf-4d73bd591ce5} + + + {98e1f400-451f-497f-bbbc-e88c74c9aab0} + + + {b23bdba1-6007-4edb-ac75-a04cf8c5e172} + + + {6673c122-d7ed-4ccc-969a-12d317ee1f93} + + + {661f7d9d-5922-48d6-88ea-2f24bb57419f} + + + {c0424523-60b1-4886-a15d-68eda99ff01b} + + + {8e12d2c0-157a-4625-a970-665e1ec9a425} + + + {03e7b6a3-ac95-4145-b045-9c644186a0a9} + + + {4a53cf3f-fb5d-471f-8570-7dcdf479cce6} + + + {84fe421c-de5d-4732-9518-dd5ef6c46a72} + + + {2eb259f7-2735-493a-88be-96eb38f1b34e} + + + {28139b08-f8d5-41a2-a5ee-bf86cf1469c3} + - - + - - + + @@ -26,14 +106,11 @@ - - + - - - + @@ -45,16 +122,257 @@ Crypto + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + Input + + + Input + + + Thread + + + Thread + + + Thread + + + Thread + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Color + + + Data\Hash + + + Data\Text + + + Data\Text + + + Data\Text + + + Data\Convert + + + Math + + + Math + + + Math + + + Math\fast + + + Math\fast + + + Math\fast + + + Math\lin + + + Math\lin + + + File + + + File + + + Data\Format + + + File\VFS + + + File\VFS + + + Data\Format + + + Data\Format + + + Data\Format + + + Profiler + + + System + + + File + + + File + + + File + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Data\Format + + + Data\Format + + + Data\Format + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + GPU + + + GPU\D3D11 + + + Render + + + Render + + + GPU\GL + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + - - + + @@ -65,25 +383,19 @@ - - + - - - - - - + - + @@ -95,5 +407,273 @@ Crypto + + + + + + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + ext\libpng17 + + + Input + + + Input + + + Input + + + Thread + + + Thread + + + Thread + + + Thread + + + Data\Collections + + + Data\Collections + + + Data\Random + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Encoding + + + Data\Color + + + Data\Hash + + + Data\Text + + + Data\Text + + + Data\Text + + + Data\Convert + + + Math + + + Math + + + Math + + + Math + + + Math\fast + + + Math\fast + + + Math\lin + + + Math\lin + + + File + + + File + + + Data\Format + + + File\VFS + + + File\VFS + + + Data\Format + + + Data\Format + + + Data\Format + + + Profiler + + + System + + + System + + + System + + + File + + + File + + + File + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Net + + + Data\Format + + + Data\Format + + + Data\Format + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + UI + + + GPU + + + GPU + + + GPU + + + Render + + + Render + + + GPU\GL + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + + + Render\Text + + + Data\Collections + + + Data\Collections + + + Data\Collections + - + + + ext\libpng17 + + + + + Math\fast + + + Math\lin + + + \ No newline at end of file diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 0bbac0c46e..2e46086a0b 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -204,7 +204,7 @@ false true pch.h - ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -219,7 +219,7 @@ false true pch.h - ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -234,7 +234,7 @@ false true pch.h - ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -249,7 +249,7 @@ false true pch.h - ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -264,7 +264,7 @@ false true pch.h - ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -279,7 +279,7 @@ false true pch.h - ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -294,7 +294,7 @@ false true pch.h - ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -309,7 +309,7 @@ false true pch.h - ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -324,7 +324,7 @@ false true pch.h - ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -339,7 +339,7 @@ false true pch.h - ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -354,7 +354,7 @@ false true pch.h - ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -369,7 +369,7 @@ false true pch.h - ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../Common;../../ext/zlib;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) USE_FFMPEG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -400,6 +400,7 @@ + @@ -432,6 +433,7 @@ + @@ -518,7 +520,9 @@ + + @@ -558,11 +562,14 @@ + + + @@ -571,7 +578,15 @@ + + + + + + + + @@ -615,6 +630,7 @@ + @@ -647,6 +663,7 @@ + @@ -721,6 +738,7 @@ + @@ -729,7 +747,9 @@ + + @@ -796,10 +816,13 @@ + + + @@ -808,7 +831,2063 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing NotUsing @@ -825,6 +2904,8 @@ + + NotUsing NotUsing @@ -943,6 +3024,12 @@ {acb316ca-3ecb-48e5-be0a-91e72d5b0f12} + + {d31fd4f0-53eb-477c-9dc7-149796f628e2} + + + + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index 7afcc97e71..ea66a38598 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -71,6 +71,18 @@ {3b1039f9-72dc-4c7f-bd4e-25791be20df7} + + {613b4e2e-264b-4ae8-9b23-bc15590ffa11} + + + {e20f358f-a614-47ff-a5b7-164c82e613a9} + + + {69359915-04ac-4d1f-a7ba-25b282c26ae9} + + + {1ad7ee67-c496-4709-bf98-cad322fe5d97} + @@ -80,13 +92,16 @@ + + + @@ -560,6 +575,12 @@ Ext\snappy + + Ext\snappy + + + Ext\snappy + Ext\udis86 @@ -664,6 +685,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket @@ -703,9 +727,191 @@ MIPS\ARM64 + + HW + HW + + Util + + + Ext\gason + + + Ext\cityhash + + + Ext\jpge + + + Ext\jpge + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + @@ -717,14 +923,17 @@ + + + @@ -1282,6 +1491,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket @@ -1303,5 +1515,39 @@ HW + + Util + + + Ext\gason + + + Ext\cityhash + + + Ext\cityhash + + + Ext\jpge + + + Ext\jpge + + + Ext\libzip + + + Ext\libzip + + + Ext\libzip + + + - + + + Ext\gason + + + \ No newline at end of file diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index 356e226e26..be5fdc1a1f 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -204,7 +204,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -219,7 +219,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -234,7 +234,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -249,7 +249,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -264,7 +264,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -279,7 +279,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -294,7 +294,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -309,7 +309,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -324,7 +324,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) @@ -339,7 +339,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -354,7 +354,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -369,7 +369,7 @@ false true pch.h - ../..;../../ext/snappy;../../ext/native;../../Common;../../ext/native/ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) @@ -381,7 +381,7 @@ - + @@ -440,7 +440,7 @@ - + @@ -482,6 +482,7 @@ + @@ -526,4 +527,4 @@ - \ No newline at end of file + diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index c72d9173e4..261335da46 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -3,7 +3,7 @@ - + @@ -45,6 +45,7 @@ + @@ -62,7 +63,7 @@ - + @@ -118,4 +119,4 @@ - \ No newline at end of file + diff --git a/UWP/NKCodeFromWindowsSystem.h b/UWP/NKCodeFromWindowsSystem.h index 470a72456a..94905fb699 100644 --- a/UWP/NKCodeFromWindowsSystem.h +++ b/UWP/NKCodeFromWindowsSystem.h @@ -2,6 +2,6 @@ #include -#include "input/keycodes.h" +#include "Common/Input/KeyCodes.h" extern std::map virtualKeyCodeToNKCode; \ No newline at end of file diff --git a/UWP/NativeUWP/NativeUWP.vcxproj b/UWP/NativeUWP/NativeUWP.vcxproj deleted file mode 100644 index f6adacf851..0000000000 --- a/UWP/NativeUWP/NativeUWP.vcxproj +++ /dev/null @@ -1,1647 +0,0 @@ - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - UWP Gold - ARM - - - UWP Gold - ARM64 - - - UWP Gold - Win32 - - - UWP Gold - x64 - - - - {935028af-b850-4ad7-a00e-7ba84fb97d05} - StaticLibrary - NativeUWP - en-US - 14.0 - true - Windows Store - 10.0.15063.0 - 10.0 - 10.0.17763.0 - - - - StaticLibrary - true - - - StaticLibrary - true - - - StaticLibrary - true - - - StaticLibrary - true - - - StaticLibrary - false - true - - - StaticLibrary - false - true - - - StaticLibrary - false - false - - - StaticLibrary - false - false - - - StaticLibrary - false - false - - - StaticLibrary - false - false - - - StaticLibrary - false - true - - - StaticLibrary - false - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Console - false - false - - - - - Use - false - true - pch.h - ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Console - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - - - - - {ddf90203-0aae-4f38-b589-2e9637658ce6} - - - - - - diff --git a/UWP/NativeUWP/NativeUWP.vcxproj.filters b/UWP/NativeUWP/NativeUWP.vcxproj.filters deleted file mode 100644 index 5e8aaecb8d..0000000000 --- a/UWP/NativeUWP/NativeUWP.vcxproj.filters +++ /dev/null @@ -1,748 +0,0 @@ -๏ปฟ - - - - {903dae00-880d-4c12-bd10-29fca750376f} - - - {98343696-3517-451a-9b47-94d462263e3e} - - - {63177c91-8ebd-4e87-ad4e-e6b8b52879c8} - - - {58d2f6cf-2448-4095-8479-9fe5d765b573} - - - {8a254b8c-46f2-4ff1-bc53-deea7e614276} - - - {244992ec-8dcf-49f4-b63c-cae6ac437c58} - - - {6f098c49-cf71-466b-9b1e-c4287681ab26} - - - {9d02a269-6cdd-4726-ab58-34c012e37d37} - - - {8292cb5c-02c9-46a4-a8d5-ea5e8f362688} - - - {d8c0dd74-7ad2-440a-a3e0-5dbf3435a2fc} - - - {a522f449-7873-4af7-908e-7cc91eb8bfc0} - - - {2be24387-0b6a-4253-97fa-b8b6f75a8a4c} - - - {1a486fc4-bac0-4b33-9139-262272690c74} - - - {f3b2701a-3ddc-4604-a867-2ee9a0600dab} - - - {34445680-c1be-4aec-a716-1e118ef48906} - - - {96ac6deb-ad00-4ee4-9f0d-515d78d1886b} - - - {3ffe0470-9652-4d89-a3d1-7eb989d266ab} - - - {4d23e7d3-0b9b-4dbe-95df-6ab250782a66} - - - {fb517d8e-e6c4-4eaf-a579-9970daa96541} - - - {b68fe6a0-b55f-4411-91f4-63ab1eaf47a3} - - - - - - base - - - base - - - base - - - base - - - base - - - base - - - thin3d - - - thin3d - - - thread - - - thread - - - thread - - - thread - - - util - - - util - - - util - - - util - - - gfx - - - gfx - - - file - - - file - - - file - - - file - - - file - - - file - - - file - - - input - - - input - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - net - - - net - - - net - - - net - - - net - - - net - - - i18n - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\jpge - - - ext\jpge - - - gfx - - - image - - - image - - - ext\cityhash - - - gfx - - - data - - - base - - - math - - - - - ext\gason - - - ext\sha1 - - - net - - - data - - - gfx - - - - - - - base - - - base - - - base - - - base - - - base - - - base - - - base - - - base - - - base - - - base - - - thin3d - - - thread - - - thread - - - thread - - - thread - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - gfx - - - gfx - - - file - - - file - - - file - - - file - - - file - - - file - - - file - - - file - - - input - - - input - - - input - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - math - - - net - - - net - - - net - - - net - - - net - - - net - - - i18n - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\jpge - - - ext\jpge - - - gfx - - - image - - - image - - - ext\cityhash - - - ext\cityhash - - - gfx - - - data - - - data - - - - - ext\gason - - - ext\sha1 - - - net - - - data - - - gfx - - - diff --git a/UWP/NativeUWP/pch.h b/UWP/NativeUWP/pch.h deleted file mode 100644 index 529bbb17fe..0000000000 --- a/UWP/NativeUWP/pch.h +++ /dev/null @@ -1,9 +0,0 @@ -๏ปฟ#pragma once - -#include "targetver.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#include diff --git a/UWP/PPSSPP_UWP.sln b/UWP/PPSSPP_UWP.sln index 73a916158b..fc6a017b01 100644 --- a/UWP/PPSSPP_UWP.sln +++ b/UWP/PPSSPP_UWP.sln @@ -5,11 +5,12 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUWP", "CommonUWP\CommonUWP.vcxproj", "{ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CoreUWP", "CoreUWP\CoreUWP.vcxproj", "{40B76674-02DE-40EF-889B-FAD1489685E7}" + ProjectSection(ProjectDependencies) = postProject + {D31FD4F0-53EB-477C-9DC7-149796F628E2} = {D31FD4F0-53EB-477C-9DC7-149796F628E2} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPU_UWP", "GPU_UWP\GPU_UWP.vcxproj", "{5D271429-C288-4534-98AF-94475D940058}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NativeUWP", "NativeUWP\NativeUWP.vcxproj", "{935028AF-B850-4AD7-A00E-7BA84FB97D05}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UI_UWP", "UI_UWP\UI_UWP.vcxproj", "{5FAC15BD-7397-4512-99D5-66CDC03AF5B7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libkirk_UWP", "libkirk_UWP\libkirk_UWP.vcxproj", "{2F911C05-B341-4291-8BF5-09EDECBDD5F5}" @@ -17,6 +18,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib_UWP", "zlib_UWP\zlib_UWP.vcxproj", "{DDF90203-0AAE-4F38-B589-2E9637658CE6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPP_UWP", "UWP.vcxproj", "{01D7D581-09A3-4A26-94BD-A7C529B29329}" + ProjectSection(ProjectDependencies) = postProject + {D31FD4F0-53EB-477C-9DC7-149796F628E2} = {D31FD4F0-53EB-477C-9DC7-149796F628E2} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang_UWP", "glslang_UWP\glslang_UWP.vcxproj", "{D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}" EndProject @@ -24,6 +28,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRVCross_UWP", "SPIRVCros EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Armips_UWP", "Armips_UWP\Armips_UWP.vcxproj", "{75286959-E7A2-4CBE-8B95-BF05C9C540FF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc_UWP", "miniupnpc_UWP\miniupnpc_UWP.vcxproj", "{D31FD4F0-53EB-477C-9DC7-149796F628E2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -316,6 +322,30 @@ Global {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|Win32.Build.0 = Release|Win32 {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|x64.ActiveCfg = Release|x64 {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|x64.Build.0 = Release|x64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|ARM.ActiveCfg = Debug|ARM + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|ARM.Build.0 = Debug|ARM + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|ARM64.Build.0 = Debug|ARM64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|Win32.ActiveCfg = Debug|Win32 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|Win32.Build.0 = Debug|Win32 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|x64.ActiveCfg = Debug|x64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Debug|x64.Build.0 = Debug|x64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|ARM.ActiveCfg = Release|ARM + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|ARM.Build.0 = Release|ARM + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|ARM64.ActiveCfg = Release|ARM64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|ARM64.Build.0 = Release|ARM64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|Win32.ActiveCfg = Release|Win32 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|Win32.Build.0 = Release|Win32 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|x64.ActiveCfg = Release|x64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.Release|x64.Build.0 = Release|x64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|ARM64.ActiveCfg = UWP Gold|ARM64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|ARM64.Build.0 = UWP Gold|ARM64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 + {D31FD4F0-53EB-477C-9DC7-149796F628E2}.UWP Gold|x64.Build.0 = UWP Gold|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 35739b4dc8..4de2859f70 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -1,28 +1,33 @@ #include "pch.h" #include "PPSSPP_UWPMain.h" -#include #include -#include "base/basictypes.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/Net/HTTPClient.h" +#include "Common/Net/Resolve.h" +#include "Common/GPU/thin3d_create.h" + +#include "Common/Common.h" +#include "Common/Input/InputState.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/DirectXHelper.h" +#include "Common/File/FileUtil.h" #include "Common/Log.h" #include "Common/LogManager.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" + #include "Core/System.h" #include "Core/Loaders.h" -#include "base/NativeApp.h" -#include "base/timeutil.h" -#include "input/input_state.h" -#include "file/vfs.h" -#include "file/zip_read.h" -#include "file/file_util.h" -#include "net/http_client.h" -#include "net/resolve.h" -#include "base/display.h" -#include "thread/threadutil.h" -#include "thin3d/thin3d_create.h" -#include "util/text/utf8.h" -#include "Common/DirectXHelper.h" +#include "Core/Config.h" + #include "NKCodeFromWindowsSystem.h" #include "XAudioSoundStream.h" #include "UWPHost.h" @@ -100,7 +105,7 @@ PPSSPP_UWPMain::PPSSPP_UWPMain(App ^app, const std::shared_ptrGetD3DDeviceContext(); - switch (m_deviceResources->ComputeDisplayRotation()) { case DXGI_MODE_ROTATION_IDENTITY: g_display_rotation = DisplayRotation::ROTATE_0; break; case DXGI_MODE_ROTATION_ROTATE90: g_display_rotation = DisplayRotation::ROTATE_90; break; @@ -320,7 +323,7 @@ UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr reso draw_ = Draw::T3DCreateD3D11Context( resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetDeviceFeatureLevel(), 0, adapterNames); bool success = draw_->CreatePresets(); - assert(success); + _assert_(success); } void UWPGraphicsContext::Shutdown() { @@ -377,6 +380,11 @@ float System_GetPropertyFloat(SystemProperty prop) { switch (prop) { case SYSPROP_DISPLAY_REFRESH_RATE: return 60.f; + case SYSPROP_DISPLAY_SAFE_INSET_LEFT: + case SYSPROP_DISPLAY_SAFE_INSET_RIGHT: + case SYSPROP_DISPLAY_SAFE_INSET_TOP: + case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM: + return 0.0f; default: return -1; } @@ -473,12 +481,9 @@ PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } -bool System_InputBoxGetString(const char *title, const char *defaultValue, char *outValue, size_t outLength) { - return false; -} - -bool System_InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) { - return false; +void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { + // TODO + cb(false, ""); } std::string GetCPUBrandString() { @@ -503,7 +508,7 @@ std::string GetCPUBrandString() { } catch (const std::exception & e) { const char* what = e.what(); - ILOG("%s", what); + INFO_LOG(SYSTEM, "%s", what); } if (cpu_id != nullptr) { @@ -525,7 +530,7 @@ std::string GetCPUBrandString() { } catch (const std::exception & e) { const char* what = e.what(); - ILOG("%s", what); + INFO_LOG(SYSTEM, "%s", what); } } diff --git a/UWP/PPSSPP_UWPMain.h b/UWP/PPSSPP_UWPMain.h index 3b38deeb3d..3be7b25ce4 100644 --- a/UWP/PPSSPP_UWPMain.h +++ b/UWP/PPSSPP_UWPMain.h @@ -2,8 +2,8 @@ #include -#include "thin3d/thin3d.h" -#include "input/input_state.h" +#include "Common/GPU/thin3d.h" +#include "Common/Input/InputState.h" #include "Common/GraphicsContext.h" #include "Common/DeviceResources.h" diff --git a/UWP/StorageFileLoader.cpp b/UWP/StorageFileLoader.cpp index 7253288fd4..3dfced89de 100644 --- a/UWP/StorageFileLoader.cpp +++ b/UWP/StorageFileLoader.cpp @@ -1,9 +1,10 @@ #include "pch.h" #include "ppltasks.h" -#include "base/logging.h" -#include "file/file_util.h" -#include "thread/threadutil.h" +#include "Common/File/FileUtil.h" +#include "Common/File/DirListing.h" +#include "Common/Thread/ThreadUtil.h" #include "StorageFileLoader.h" +#include "Common/Log.h" #include "UWPUtil.h" using namespace Concurrency; @@ -44,7 +45,7 @@ void StorageFileLoader::threadfunc() { operationFailed_ = true; // TODO: What do we do? const char *what = e.what(); - ILOG("%s", what); + INFO_LOG(SYSTEM, "%s", what); } catch (Platform::COMException ^e) { @@ -58,11 +59,11 @@ void StorageFileLoader::threadfunc() { } catch (const std::exception& e) { const char *what = e.what(); - ILOG("%s", what); + INFO_LOG(SYSTEM, "%s", what); } catch (Platform::COMException ^e) { std::string what = FromPlatformString(e->ToString()); - ILOG("%s", what.c_str()); + INFO_LOG(SYSTEM, "%s", what.c_str()); } initMutex.unlock(); @@ -86,7 +87,7 @@ void StorageFileLoader::threadfunc() { } catch (const std::exception& e) { operationFailed_ = true; const char *what = e.what(); - ILOG("%s", what); + INFO_LOG(SYSTEM, "%s", what); } operationRequested_ = false; std::unique_lock lock(mutexResponse_); @@ -96,7 +97,7 @@ void StorageFileLoader::threadfunc() { break; } default: - ELOG("Unknown operation"); + ERROR_LOG(SYSTEM, "Unknown operation"); operationRequested_ = false; break; } diff --git a/UWP/StorageFolderBrowser.cpp b/UWP/StorageFolderBrowser.cpp index e5c6149d4c..4e86ed079f 100644 --- a/UWP/StorageFolderBrowser.cpp +++ b/UWP/StorageFolderBrowser.cpp @@ -1,8 +1,7 @@ #include "pch.h" #include "ppltasks.h" -#include "base/logging.h" -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" #include "StorageFolderBrowser.h" #include "UWPUtil.h" diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index 120a7b5f86..dd4037f7e0 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -204,7 +204,7 @@ false true NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -219,7 +219,7 @@ false true NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -234,7 +234,7 @@ false true GOLD;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -249,7 +249,7 @@ false true NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -264,7 +264,7 @@ false true NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -279,7 +279,7 @@ false true NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -294,7 +294,7 @@ false true NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -309,7 +309,7 @@ false true GOLD;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -324,7 +324,7 @@ false true GOLD;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -339,7 +339,7 @@ false true NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -354,7 +354,7 @@ false true NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -369,7 +369,7 @@ false true GOLD;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../..;../../ext/native;../../Common;../../ext/native/ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/native;../../Common;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) pch.h @@ -380,6 +380,7 @@ + @@ -414,6 +415,7 @@ + diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 3458d694de..9dfe5919aa 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -195,7 +195,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/ARM/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm @@ -220,7 +220,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/ARM64/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm @@ -245,7 +245,7 @@ - xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/ARM/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm @@ -270,7 +270,7 @@ - xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/ARM64/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm @@ -295,7 +295,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/ARM/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm @@ -320,7 +320,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/ARM64/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm @@ -345,7 +345,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/x86/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib @@ -370,7 +370,7 @@ - xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/x86/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib @@ -395,7 +395,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/x86/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib @@ -420,7 +420,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/x64/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64 @@ -445,7 +445,7 @@ - xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/x64/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64 @@ -470,7 +470,7 @@ - libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + xinputuap.lib;libavcodec.a;libavformat.a;libavutil.a;libswresample.a;libswscale.a;d2d1.lib;d3d11.lib;dxgi.lib;windowscodecs.lib;dwrite.lib; %(AdditionalDependencies) ../ffmpeg/Windows10/x64/lib;%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64 @@ -1728,9 +1728,6 @@ {2f911c05-b341-4291-8bf5-09edecbdd5f5} - - {935028af-b850-4ad7-a00e-7ba84fb97d05} - {2b2d16bd-1d37-46af-a3f8-552900951b26} @@ -1758,4 +1755,4 @@ - \ No newline at end of file + diff --git a/UWP/UWPHost.cpp b/UWP/UWPHost.cpp index 49bc413d4f..d16b730192 100644 --- a/UWP/UWPHost.cpp +++ b/UWP/UWPHost.cpp @@ -17,9 +17,12 @@ #include "ppsspp_config.h" -#include "file/file_util.h" -#include "base/NativeApp.h" -#include "input/input_state.h" +#include + +#include "Common/File/DirListing.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Input/InputState.h" #include "Common/StringUtils.h" #include "Core/Core.h" @@ -158,6 +161,10 @@ void UWPHost::SaveSymbolMap() { g_symbolMap->SaveSymbolMap(SymbolMapFilename(PSP_CoreParameter().fileToStart.c_str(), ".ppmap").c_str()); } +void UWPHost::NotifySymbolMapUpdated() { + g_symbolMap->SortSymbols(); +} + bool UWPHost::IsDebuggingEnabled() { return false; } diff --git a/UWP/UWPHost.h b/UWP/UWPHost.h index 597886189e..3c70db9991 100644 --- a/UWP/UWPHost.h +++ b/UWP/UWPHost.h @@ -30,6 +30,7 @@ public: void BootDone() override; bool AttemptLoadSymbolMap() override; void SaveSymbolMap() override; + void NotifySymbolMapUpdated() override; void SetWindowTitle(const char *message) override; void ToggleDebugConsoleVisibility() override; diff --git a/UWP/UWPUtil.h b/UWP/UWPUtil.h index de80bba6a7..685ebc396e 100644 --- a/UWP/UWPUtil.h +++ b/UWP/UWPUtil.h @@ -1,6 +1,6 @@ #pragma once -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" inline Platform::String ^ToPlatformString(std::string str) { return ref new Platform::String(ConvertUTF8ToWString(str).c_str()); diff --git a/UWP/XAudioSoundStream.cpp b/UWP/XAudioSoundStream.cpp index ad82c1e93f..fa4bc4dd29 100644 --- a/UWP/XAudioSoundStream.cpp +++ b/UWP/XAudioSoundStream.cpp @@ -1,7 +1,9 @@ #include "pch.h" + +#include #include -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" #include "XAudioSoundStream.h" #include @@ -187,4 +189,4 @@ void XAudioBackend::PollLoop() WindowsAudioBackend *CreateAudioBackend( AudioBackendType type ) { return new XAudioBackend(); -} \ No newline at end of file +} diff --git a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj new file mode 100644 index 0000000000..2ea37b7570 --- /dev/null +++ b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj @@ -0,0 +1,490 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + UWP Gold + ARM + + + UWP Gold + ARM64 + + + UWP Gold + Win32 + + + UWP Gold + x64 + + + + {d31fd4f0-53eb-477c-9dc7-149796f628e2} + StaticLibrary + miniupnpc_UWP + en-US + 14.0 + true + Windows Store + 10.0.15063.0 + 10.0 + 10.0.17763.0 + + + + StaticLibrary + true + + + StaticLibrary + true + + + StaticLibrary + true + + + StaticLibrary + true + + + StaticLibrary + false + true + + + StaticLibrary + false + true + + + StaticLibrary + false + false + + + StaticLibrary + false + false + + + StaticLibrary + false + false + + + StaticLibrary + false + false + + + StaticLibrary + false + true + + + StaticLibrary + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + Use + false + true + pch.h + _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + + + Console + false + false + + + cd ..\..\ext\miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd ..\..\..\..\UWP\miniupnpc_UWP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + + + \ No newline at end of file diff --git a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj.filters b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj.filters new file mode 100644 index 0000000000..b6e77744fd --- /dev/null +++ b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj.filters @@ -0,0 +1,102 @@ +๏ปฟ + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + {3e20a98f-6a6c-4ba1-8b5a-d44430460dd1} + + + {f940ecfb-a971-43b3-9f9d-afe3545e9798} + + + + + scripts + + + \ No newline at end of file diff --git a/UWP/NativeUWP/pch.cpp b/UWP/miniupnpc_UWP/pch.c similarity index 100% rename from UWP/NativeUWP/pch.cpp rename to UWP/miniupnpc_UWP/pch.c diff --git a/UWP/miniupnpc_UWP/pch.h b/UWP/miniupnpc_UWP/pch.h new file mode 100644 index 0000000000..be721813fc --- /dev/null +++ b/UWP/miniupnpc_UWP/pch.h @@ -0,0 +1,4 @@ +๏ปฟ#pragma once + +#include "targetver.h" + diff --git a/UWP/NativeUWP/targetver.h b/UWP/miniupnpc_UWP/targetver.h similarity index 100% rename from UWP/NativeUWP/targetver.h rename to UWP/miniupnpc_UWP/targetver.h diff --git a/Windows/CaptureDevice.cpp b/Windows/CaptureDevice.cpp index d6c453c05d..f697670992 100644 --- a/Windows/CaptureDevice.cpp +++ b/Windows/CaptureDevice.cpp @@ -16,7 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" #include "CaptureDevice.h" #include "BufferLock.h" #include "ext/jpge/jpge.h" @@ -24,8 +24,6 @@ #include "Core/HLE/sceUsbCam.h" #include "Core/Config.h" -bool isDeviceChanged = false; - namespace MFAPI { HINSTANCE Mflib; HINSTANCE Mfplatlib; @@ -87,6 +85,7 @@ bool unRegisterCMPTMFApis() { } WindowsCaptureDevice *winCamera; +WindowsCaptureDevice *winMic; // TODO: Add more formats, but need some tests. VideoFormatTransform g_VideoFormats[] = @@ -97,19 +96,30 @@ VideoFormatTransform g_VideoFormats[] = { MFVideoFormat_NV12, AV_PIX_FMT_NV12 } }; -const int g_cVideoFormats = 4; +AudioFormatTransform g_AudioFormats[] = { + { MFAudioFormat_PCM, 8, AV_SAMPLE_FMT_U8 }, + { MFAudioFormat_PCM, 16, AV_SAMPLE_FMT_S16 }, + { MFAudioFormat_PCM, 32, AV_SAMPLE_FMT_S32 }, + { MFAudioFormat_Float, 32, AV_SAMPLE_FMT_FLT } +}; -MediaParam defaultVideoParam = { 640, 480, 0, MFVideoFormat_RGB24 }; -MediaParam defaultAudioParam = { 44100, 2, 0, MFAudioFormat_PCM }; +const int g_cVideoFormats = ARRAYSIZE(g_VideoFormats); +const int g_cAudioFormats = ARRAYSIZE(g_AudioFormats); + +MediaParam defaultVideoParam = { 640, 480, 0, MFVideoFormat_RGB24 }; +MediaParam defaultAudioParam = { 44100, 2, 16, MFAudioFormat_PCM }; HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride); -ReaderCallback::ReaderCallback(WindowsCaptureDevice *device): img_convert_ctx(nullptr){ - this->device = device; -} +ReaderCallback::ReaderCallback(WindowsCaptureDevice *_device) : device(_device) {} ReaderCallback::~ReaderCallback() { - sws_freeContext(img_convert_ctx); + if (img_convert_ctx) { + sws_freeContext(img_convert_ctx); + } + if (resample_ctx) { + swr_free(&resample_ctx); + } } HRESULT ReaderCallback::QueryInterface(REFIID riid, void** ppv) @@ -130,7 +140,6 @@ HRESULT ReaderCallback::OnReadSample( IMFSample *pSample) { HRESULT hr = S_OK; IMFMediaBuffer *pBuffer = nullptr; - LONG lStride = 0; std::lock_guard lock(device->sdMutex); if (device->isShutDown()) return hr; @@ -151,6 +160,7 @@ HRESULT ReaderCallback::OnReadSample( int imgJpegSize = device->imgJpegSize; unsigned char* invertedSrcImg = nullptr; LONG srcPadding = 0; + LONG lStride = 0; UINT32 srcW = device->deviceParam.width; UINT32 srcH = device->deviceParam.height; @@ -207,14 +217,53 @@ HRESULT ReaderCallback::OnReadSample( nullptr ); } - delete videoBuffer; break; } - case CAPTUREDEVIDE_TYPE::AUDIO: - // TODO: + case CAPTUREDEVIDE_TYPE::AUDIO: { + BYTE *sampleBuf = nullptr; + DWORD length = 0; + u32 sizeAfterResample = 0; + // pSample can be null, in this case ReadSample still should be called to request next frame. + if (pSample && Microphone::isNeedInput()) { + pBuffer->Lock(&sampleBuf, nullptr, &length); + if (!device->rawAudioBuf) { + device->rawAudioBuf = new QueueBuf(length * 2); // Alloc enough space. + } + device->rawAudioBuf->push(sampleBuf, length); + if (device->needResample()) { + sizeAfterResample = device->rawAudioBuf->getAvailableSize() * device->targetMediaParam.sampleRate / device->deviceParam.sampleRate / device->deviceParam.channels; + // Wait until have enough audio data. + if (sizeAfterResample + Microphone::availableAudioBufSize() >= Microphone::numNeedSamples() * 2) { + u32 rawAudioBufSize = device->rawAudioBuf->getAvailableSize(); + u8 *tempbuf = new u8[rawAudioBufSize]; + device->rawAudioBuf->pop(tempbuf, rawAudioBufSize); + sizeAfterResample = doResample( + &device->resampleBuf, device->targetMediaParam.sampleRate, device->targetMediaParam.channels, &device->resampleBufSize, + tempbuf, device->deviceParam.sampleRate, device->deviceParam.channels, device->deviceParam.audioFormat, rawAudioBufSize, device->deviceParam.bitsPerSample); + delete[] tempbuf; + if (device->resampleBuf) + Microphone::addAudioData(device->resampleBuf, sizeAfterResample); + } + } else { + Microphone::addAudioData(sampleBuf, length); + } + pBuffer->Unlock(); + } + // Request the next frame. + if (SUCCEEDED(hr)) { + hr = device->m_pReader->ReadSample( + (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, + 0, + nullptr, + nullptr, + nullptr, + nullptr + ); + } break; } + } } SafeRelease(&pBuffer); @@ -229,6 +278,14 @@ AVPixelFormat ReaderCallback::getAVVideoFormatbyMFVideoFormat(const GUID &MFVide return AV_PIX_FMT_RGB24; } +AVSampleFormat ReaderCallback::getAVAudioFormatbyMFAudioFormat(const GUID &MFAudioFormat, const u32 &bitsPerSample) { + for (int i = 0; i < g_cAudioFormats; i++) { + if (MFAudioFormat == g_AudioFormats[i].MFAudioFormat && bitsPerSample == g_AudioFormats[i].bitsPerSample) + return g_AudioFormats[i].AVAudioFormat; + } + return AV_SAMPLE_FMT_S16; +} + void ReaderCallback::imgConvert( unsigned char *dst, unsigned int &dstW, unsigned int &dstH, int dstLineSizes[4], unsigned char *src, const unsigned int &srcW, const unsigned int &srcH, const GUID &srcFormat, @@ -237,9 +294,9 @@ void ReaderCallback::imgConvert( unsigned char *pSrc[4]; unsigned char *pDst[4]; - AVPixelFormat srcAvFormat = getAVVideoFormatbyMFVideoFormat(srcFormat); + AVPixelFormat srcAVFormat = getAVVideoFormatbyMFVideoFormat(srcFormat); - av_image_fill_linesizes(srcLineSizes, srcAvFormat, srcW); + av_image_fill_linesizes(srcLineSizes, srcAVFormat, srcW); // Is this correct? if (srcPadding != 0) { @@ -249,16 +306,14 @@ void ReaderCallback::imgConvert( } } - av_image_fill_pointers(pSrc, srcAvFormat, srcH, src, srcLineSizes); + av_image_fill_pointers(pSrc, srcAVFormat, srcH, src, srcLineSizes); av_image_fill_pointers(pDst, AV_PIX_FMT_RGB24, dstH, dst, dstLineSizes); - - if (img_convert_ctx == nullptr) { img_convert_ctx = sws_getContext( srcW, srcH, - srcAvFormat, + srcAVFormat, dstW, dstH, AV_PIX_FMT_RGB24, @@ -348,28 +403,58 @@ void ReaderCallback::imgInvertNV12(unsigned char *dst, int &dstStride, unsigned } } -WindowsCaptureDevice::WindowsCaptureDevice(CAPTUREDEVIDE_TYPE type) : - type(type), - m_pCallback(nullptr), - m_pSource(nullptr), - m_pReader(nullptr), +u32 ReaderCallback::doResample(u8 **dst, u32 &dstSampleRate, u32 &dstChannels, u32 *dstSize, u8 *src, const u32 &srcSampleRate, const u32 &srcChannels, const GUID &srcFormat, const u32& srcSize, const u32& srcBitsPerSample) { + AVSampleFormat srcAVFormat = getAVAudioFormatbyMFAudioFormat(srcFormat, srcBitsPerSample); + int outSamplesCount = 0; + if (resample_ctx == nullptr) { + resample_ctx = swr_alloc_set_opts(nullptr, + av_get_default_channel_layout(dstChannels), + AV_SAMPLE_FMT_S16, + dstSampleRate, + av_get_default_channel_layout(srcChannels), + srcAVFormat, + srcSampleRate, + 0, + nullptr); + if (resample_ctx == nullptr || swr_init(resample_ctx) < 0) { + swr_free(&resample_ctx); + return 0; + } + } + int srcSamplesCount = srcSize / srcChannels / av_get_bytes_per_sample(srcAVFormat); // per channel. + int outCount = srcSamplesCount * dstSampleRate / srcSampleRate + 256; + unsigned int outSize = av_samples_get_buffer_size(nullptr, dstChannels, outCount, AV_SAMPLE_FMT_S16, 0); + + if (!*dst) { + *dst = (u8 *)av_malloc(outSize); + *dstSize = outSize; + } + if (!*dst) + return 0; + + if(*dstSize < outSize) + av_fast_malloc(dst, dstSize, outSize); + + outSamplesCount = swr_convert(resample_ctx, dst, outCount, (const uint8_t **)&src, srcSamplesCount); + if (outSamplesCount < 0) + return 0; + return av_samples_get_buffer_size(nullptr, dstChannels, outSamplesCount, AV_SAMPLE_FMT_S16, 0); +} + +WindowsCaptureDevice::WindowsCaptureDevice(CAPTUREDEVIDE_TYPE _type) : + type(_type), error(CAPTUREDEVIDE_ERROR_NO_ERROR), errorMessage(""), state(CAPTUREDEVIDE_STATE::UNINITIALIZED) { param = { 0 }; + deviceParam = { 0 }; switch (type) { case CAPTUREDEVIDE_TYPE::VIDEO: targetMediaParam = defaultVideoParam; - imageRGB = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, targetMediaParam.width, targetMediaParam.height, 1)); - imgJpegSize = av_image_get_buffer_size(AV_PIX_FMT_YUVJ411P, targetMediaParam.width, targetMediaParam.height, 1); - imageJpeg = (unsigned char*)av_malloc(imgJpegSize); break; case CAPTUREDEVIDE_TYPE::AUDIO: - // TODO: targetMediaParam = defaultAudioParam; - imageRGB = nullptr; - imageJpeg = nullptr; break; } @@ -380,14 +465,16 @@ WindowsCaptureDevice::WindowsCaptureDevice(CAPTUREDEVIDE_TYPE type) : WindowsCaptureDevice::~WindowsCaptureDevice() { switch (type) { case CAPTUREDEVIDE_TYPE::VIDEO: - av_free(imageRGB); - av_free(imageJpeg); + av_freep(&imageRGB); + av_freep(&imageJpeg); break; case CAPTUREDEVIDE_TYPE::AUDIO: - // TODO: + av_freep(&resampleBuf); + delete rawAudioBuf; break; } } + void WindowsCaptureDevice::CheckDevices() { isDeviceChanged = true; } @@ -412,7 +499,7 @@ bool WindowsCaptureDevice::init() { return true; } -bool WindowsCaptureDevice::start(UINT32 width, UINT32 height) { +bool WindowsCaptureDevice::start(void *startParam) { HRESULT hr = S_OK; IMFAttributes *pAttributes = nullptr; IMFMediaType *pType = nullptr; @@ -434,16 +521,14 @@ bool WindowsCaptureDevice::start(UINT32 width, UINT32 height) { return false; } - targetMediaParam.width = width; - targetMediaParam.height = height; - av_image_fill_linesizes(imgRGBLineSizes, AV_PIX_FMT_RGB24, targetMediaParam.width); - m_pCallback = new ReaderCallback(this); + std::string selectedDeviceName = type == CAPTUREDEVIDE_TYPE::VIDEO ? g_Config.sCameraDevice : g_Config.sMicDevice; + switch (state) { case CAPTUREDEVIDE_STATE::STOPPED: for (auto &name : deviceList) { - if (name == g_Config.sCameraDevice) { + if (name == selectedDeviceName) { selection = count; break; } @@ -477,7 +562,21 @@ bool WindowsCaptureDevice::start(UINT32 width, UINT32 height) { if (SUCCEEDED(hr)) { switch (type) { - case CAPTUREDEVIDE_TYPE::VIDEO: + case CAPTUREDEVIDE_TYPE::VIDEO: { + if (startParam) { + std::vector *resolution = static_cast*>(startParam); + targetMediaParam.width = resolution->at(0); + targetMediaParam.height = resolution->at(1); + delete resolution; + } + + av_freep(&imageRGB); + av_freep(&imageJpeg); + imageRGB = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, targetMediaParam.width, targetMediaParam.height, 1)); + imgJpegSize = av_image_get_buffer_size(AV_PIX_FMT_YUVJ411P, targetMediaParam.width, targetMediaParam.height, 1); + imageJpeg = (unsigned char*)av_malloc(imgJpegSize); + av_image_fill_linesizes(imgRGBLineSizes, AV_PIX_FMT_RGB24, targetMediaParam.width); + for (DWORD i = 0; ; i++) { hr = m_pReader->GetNativeMediaType( (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, @@ -512,13 +611,45 @@ bool WindowsCaptureDevice::start(UINT32 width, UINT32 height) { nullptr ); } - break; + } - case CAPTUREDEVIDE_TYPE::AUDIO: - // TODO: + case CAPTUREDEVIDE_TYPE::AUDIO: { + if (startParam) { + std::vector *micParam = static_cast*>(startParam); + targetMediaParam.sampleRate = micParam->at(0); + targetMediaParam.channels = micParam->at(1); + delete micParam; + } + + for (DWORD i = 0; ; i++) { + hr = m_pReader->GetNativeMediaType( + (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, + i, + &pType + ); + + if (FAILED(hr)) { break; } + + hr = setDeviceParam(pType); + + if (SUCCEEDED(hr)) + break; + } + + if (SUCCEEDED(hr)) { + hr = m_pReader->ReadSample( + (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, + 0, + nullptr, + nullptr, + nullptr, + nullptr + ); + } break; } + } } if (FAILED(hr)) { @@ -597,13 +728,13 @@ std::vector WindowsCaptureDevice::getDeviceList(bool forceEnum, int if (SUCCEEDED(hr)) { // Get the size needed first - dwMinSize = WideCharToMultiByte(CP_OEMCP, NULL, pwstrName, -1, nullptr, 0, nullptr, FALSE); + dwMinSize = WideCharToMultiByte(CP_UTF8, NULL, pwstrName, -1, nullptr, 0, nullptr, FALSE); if (dwMinSize == 0) hr = -1; } if (SUCCEEDED(hr)) { cstrName = new char[dwMinSize]; - WideCharToMultiByte(CP_OEMCP, NULL, pwstrName, -1, cstrName, dwMinSize, NULL, FALSE); + WideCharToMultiByte(CP_UTF8, NULL, pwstrName, -1, cstrName, dwMinSize, NULL, FALSE); strName = cstrName; delete[] cstrName; @@ -670,7 +801,46 @@ HRESULT WindowsCaptureDevice::setDeviceParam(IMFMediaType *pType) { break; case CAPTUREDEVIDE_TYPE::AUDIO: - // TODO: + hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); + if (FAILED(hr)) + break; + + for (int i = 0; i < g_cVideoFormats; i++) { + if (subtype == g_AudioFormats[i].MFAudioFormat) { + deviceParam.audioFormat = subtype; + getFormat = true; + break; + } + } + + if (!getFormat) { + for (int i = 0; i < g_cAudioFormats; i++) { + hr = pType->SetGUID(MF_MT_SUBTYPE, g_AudioFormats[i].MFAudioFormat); + if (FAILED(hr)) + continue; + + hr = m_pReader->SetCurrentMediaType( + (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, + NULL, + pType + ); + + if (SUCCEEDED(hr)) { + deviceParam.audioFormat = g_AudioFormats[i].MFAudioFormat; + getFormat = true; + break; + } + } + } + if (SUCCEEDED(hr)) + hr = pType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &deviceParam.sampleRate); + + if (SUCCEEDED(hr)) + hr = pType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &deviceParam.channels); + + if (SUCCEEDED(hr)) + hr = pType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, (UINT32 *)&deviceParam.bitsPerSample); + break; } @@ -701,10 +871,11 @@ void WindowsCaptureDevice::messageHandler() { CoInitializeEx(NULL, COINIT_MULTITHREADED); MFStartup(MF_VERSION); CAPTUREDEVIDE_MESSAGE message; - std::vector* resolution; if (type == CAPTUREDEVIDE_TYPE::VIDEO) { setCurrentThreadName("Camera"); + } else if (type == CAPTUREDEVIDE_TYPE::AUDIO) { + setCurrentThreadName("Microphone"); } while ((message = getMessage()).command != CAPTUREDEVIDE_COMMAND::SHUTDOWN) { @@ -713,8 +884,7 @@ void WindowsCaptureDevice::messageHandler() { init(); break; case CAPTUREDEVIDE_COMMAND::START: - resolution = static_cast*>(message.opacity); - start(resolution->at(0), resolution->at(1)); + start(message.opacity); break; case CAPTUREDEVIDE_COMMAND::STOP: stop(); @@ -781,6 +951,13 @@ HRESULT WindowsCaptureDevice::enumDevices() { return hr; } +bool WindowsCaptureDevice::needResample() { + return deviceParam.sampleRate != targetMediaParam.sampleRate || + deviceParam.channels != targetMediaParam.channels || + deviceParam.audioFormat != targetMediaParam.audioFormat || + deviceParam.bitsPerSample != targetMediaParam.bitsPerSample; +} + //----------------------------------------------------------------------------- // GetDefaultStride // diff --git a/Windows/CaptureDevice.h b/Windows/CaptureDevice.h index aa0d0dc744..0829bdb2bc 100644 --- a/Windows/CaptureDevice.h +++ b/Windows/CaptureDevice.h @@ -26,10 +26,13 @@ #include #include +#include "Core/HLE/sceUsbMic.h" + #ifdef __cplusplus extern "C" { #include "libavformat/avformat.h" #include "libswscale/swscale.h" +#include "libswresample/swresample.h" #include "libavutil/imgutils.h" } #endif // __cplusplus @@ -39,6 +42,12 @@ struct VideoFormatTransform { AVPixelFormat AVVideoFormat; }; +struct AudioFormatTransform { + GUID MFAudioFormat; + u32 bitsPerSample; + AVSampleFormat AVAudioFormat; +}; + enum class CAPTUREDEVIDE_TYPE { VIDEO, AUDIO @@ -90,8 +99,8 @@ union MediaParam { struct { UINT32 sampleRate; UINT32 channels; - LONG padding; - GUID audioFomat; + LONG bitsPerSample; + GUID audioFormat; }; }; @@ -127,9 +136,10 @@ public: STDMETHODIMP OnFlush(DWORD) { return S_OK; } AVPixelFormat getAVVideoFormatbyMFVideoFormat(const GUID &MFVideoFormat); + AVSampleFormat getAVAudioFormatbyMFAudioFormat(const GUID &MFAudioFormat, const u32 &bitsPerSample); /* - * Always convet the image to RGB24 + * Always convert the image to RGB24 * @param dst/src pointer to destination/source image * @param dstW/srcW, dstH/srcH destination/source image's width and height in pixels * @param dstLineSizes get the linesize of each plane by av_image_fill_linesizes() @@ -149,10 +159,20 @@ public: void imgInvertYUY2(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h); void imgInvertNV12(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h); + /* + * Always resample to uncompressed signed 16bits + * @param dst pointer to pointer of dst buffer could be a nullptr, would be overwritten by a new pointer if space too small or a nullptr, should be freed by av_free/av_freep by caller + * @param dstSize pointer to size of the dst buffer, could be modified after this func + * @param srcFormat MF_MT_SUBTYPE attribute of the source audio data + * @param srcSize size of valid data in the source buffer, in bytes + * @return size of output in bytes + */ + u32 doResample(u8 **dst, u32 &dstSampleRate, u32 &dstChannels, u32 *dstSize, u8 *src, const u32 &srcSampleRate, const u32 &srcChannels, const GUID &srcFormat, const u32 &srcSize, const u32& srcBitsPerSamples); protected: WindowsCaptureDevice *device; - SwsContext *img_convert_ctx; + SwsContext *img_convert_ctx = nullptr; + SwrContext *resample_ctx = nullptr; }; class WindowsCaptureDevice { @@ -160,10 +180,10 @@ public: WindowsCaptureDevice(CAPTUREDEVIDE_TYPE type); ~WindowsCaptureDevice(); - static void CheckDevices(); + void CheckDevices(); bool init(); - bool start(UINT32 width, UINT32 height); + bool start(void *startParam); bool stop(); CAPTUREDEVIDE_ERROR getError() const { return error; } @@ -178,12 +198,15 @@ public: HRESULT setDeviceParam(IMFMediaType *pType); bool isShutDown() const { return state == CAPTUREDEVIDE_STATE::SHUTDOWN; } + bool isStarted() const { return state == CAPTUREDEVIDE_STATE::STARTED; } void sendMessage(CAPTUREDEVIDE_MESSAGE message); CAPTUREDEVIDE_MESSAGE getMessage(); HRESULT enumDevices(); + bool needResample(); + friend class ReaderCallback; protected: @@ -199,10 +222,12 @@ protected: CAPTUREDEVIDE_ERROR error; std::string errorMessage; + bool isDeviceChanged = false; + // MF interface. - ReaderCallback *m_pCallback; - IMFSourceReader *m_pReader; - IMFMediaSource *m_pSource; + ReaderCallback *m_pCallback = nullptr; + IMFSourceReader *m_pReader = nullptr; + IMFMediaSource *m_pSource = nullptr; // Message loop. std::mutex mutex; @@ -216,10 +241,16 @@ protected: std::mutex paramMutex; // Camera only - unsigned char *imageRGB; - int imgRGBLineSizes[4]; - unsigned char *imageJpeg; - int imgJpegSize; + unsigned char *imageRGB = nullptr; + int imgRGBLineSizes[4]{}; + unsigned char *imageJpeg = nullptr; + int imgJpegSize = 0; + +//Microphone only + u8 *resampleBuf = nullptr; + u32 resampleBufSize = 0; + QueueBuf *rawAudioBuf = nullptr; }; extern WindowsCaptureDevice *winCamera; +extern WindowsCaptureDevice *winMic; diff --git a/Windows/DSoundStream.cpp b/Windows/DSoundStream.cpp index 89111c8067..bd375d025e 100644 --- a/Windows/DSoundStream.cpp +++ b/Windows/DSoundStream.cpp @@ -10,7 +10,7 @@ #undef __null #endif -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" #include "Common/Log.h" #include "Common/OSVersion.h" #include "Core/ConfigValues.h" diff --git a/Windows/Debugger/BreakpointWindow.cpp b/Windows/Debugger/BreakpointWindow.cpp index b00da57324..60ed43195e 100644 --- a/Windows/Debugger/BreakpointWindow.cpp +++ b/Windows/Debugger/BreakpointWindow.cpp @@ -1,6 +1,6 @@ #include -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "BreakpointWindow.h" #include "../resource.h" diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 7717503399..e26f9644d8 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -20,9 +20,9 @@ #include "Windows/main.h" #include "Common/CommonWindows.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "ext/xxhash.h" -#include "base/display.h" +#include "Common/System/Display.h" #include #include diff --git a/Windows/Debugger/CtrlMemView.cpp b/Windows/Debugger/CtrlMemView.cpp index 331126a00e..7ae71ef331 100644 --- a/Windows/Debugger/CtrlMemView.cpp +++ b/Windows/Debugger/CtrlMemView.cpp @@ -2,15 +2,14 @@ #include #include - +#include #include "Core/Config.h" #include "Windows/resource.h" #include "Core/MemMap.h" #include "Windows/W32Util/Misc.h" #include "Windows/InputBox.h" #include "Windows/main.h" -#include "Core/Debugger/SymbolMap.h" -#include "base/display.h" +#include "Common/System/Display.h" #include "Debugger_Disasm.h" #include "DebuggerShared.h" @@ -174,8 +173,6 @@ CtrlMemView *CtrlMemView::getFrom(HWND hwnd) } - - void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) { auto memLock = Memory::Lock(); @@ -634,14 +631,49 @@ void CtrlMemView::scrollCursor(int bytes) redraw(); } + +std::vector CtrlMemView::searchString(std::string searchQuery) +{ + std::vector searchResAddrs; + std::vector searchData; + + auto memLock = Memory::Lock(); + if (!PSP_IsInited()) + return searchResAddrs; + + size_t queryLength = searchQuery.length(); + u32 segmentStart = PSP_GetKernelMemoryBase(); //RAM start + const u32 segmentEnd = PSP_GetUserMemoryEnd() - (u32)queryLength; //RAM end + u8* ptr; + + redraw(); + for (segmentStart = PSP_GetKernelMemoryBase(); segmentStart < segmentEnd; segmentStart++) { + if (KeyDownAsync(VK_ESCAPE)) + { + return searchResAddrs; + } + + ptr = Memory::GetPointer(segmentStart); + if (memcmp(ptr, searchQuery.c_str(), queryLength) == 0) { + searchResAddrs.push_back(segmentStart); + } + }; + redraw(); + + return searchResAddrs; +}; + void CtrlMemView::search(bool continueSearch) { auto memLock = Memory::Lock(); if (!PSP_IsInited()) return; - u32 searchAddress; - if (continueSearch == false || searchQuery[0] == 0) + u32 searchAddress = 0; + u32 segmentStart = 0; + u32 segmentEnd = 0; + u8* dataPointer = 0; + if (continueSearch == false || searchQuery.empty()) { if (InputBox_GetString(GetModuleHandle(NULL),wnd,L"Search for", "",searchQuery) == false) { @@ -673,7 +705,7 @@ void CtrlMemView::search(bool continueSearch) } u8 value = 0; - for (int i = 0; i < 2; i++) + for (int i = 0; i < 2 && index < searchQuery.size(); i++) { char c = tolower(searchQuery[index++]); if (c >= 'a' && c <= 'f') @@ -693,35 +725,32 @@ void CtrlMemView::search(bool continueSearch) } std::vector> memoryAreas; - memoryAreas.push_back(std::pair(0x04000000,0x04200000)); - memoryAreas.push_back(std::pair(0x08000000,0x0A000000)); + memoryAreas.push_back(std::pair(0x04000000, 0x04200000)); + memoryAreas.push_back(std::pair(0x08000000, 0x0A000000)); searching = true; redraw(); // so the cursor is disabled - for (size_t i = 0; i < memoryAreas.size(); i++) - { - u32 segmentStart = memoryAreas[i].first; - u32 segmentEnd = memoryAreas[i].second; - u8* dataPointer = Memory::GetPointer(segmentStart); + + for (size_t i = 0; i < memoryAreas.size(); i++) { + segmentStart = memoryAreas[i].first; + segmentEnd = memoryAreas[i].second; + + dataPointer = Memory::GetPointer(segmentStart); if (dataPointer == NULL) continue; // better safe than sorry, I guess if (searchAddress < segmentStart) searchAddress = segmentStart; if (searchAddress >= segmentEnd) continue; int index = searchAddress-segmentStart; - int endIndex = segmentEnd-segmentStart-(int)searchData.size(); + int endIndex = segmentEnd-segmentStart - (int)searchData.size(); - while (index < endIndex) - { + while (index < endIndex) { // cancel search - if ((index % 256) == 0 && KeyDownAsync(VK_ESCAPE)) - { + if ((index % 256) == 0 && KeyDownAsync(VK_ESCAPE)) { searching = false; return; } - - if (memcmp(&dataPointer[index],searchData.data(),searchData.size()) == 0) - { + if (memcmp(&dataPointer[index], searchData.data(), searchData.size()) == 0) { matchAddress = index+segmentStart; searching = false; gotoAddr(matchAddress); @@ -746,17 +775,15 @@ void CtrlMemView::drawOffsetScale(HDC hdc) currentX = addressStart + ((8 + 1)*charWidth); // the start offset, the size of the hex addresses and one space char temp[64]; - for (int i = 0; i < 16; i++) { sprintf(temp, "%02X", i); TextOutA(hdc, currentX, offsetPositionY, temp, 2); currentX += 3 * charWidth; // hex and space } - } -void CtrlMemView::toggleOffsetScale(OffsetToggles toggle) +void CtrlMemView::toggleOffsetScale(CommonToggles toggle) { if (toggle == On) displayOffsetScale = true; diff --git a/Windows/Debugger/CtrlMemView.h b/Windows/Debugger/CtrlMemView.h index d5f8079d7f..44ab3bcdf0 100644 --- a/Windows/Debugger/CtrlMemView.h +++ b/Windows/Debugger/CtrlMemView.h @@ -24,7 +24,7 @@ enum OffsetSpacing { offsetLine = 1, // the line on which the offsets should be written }; -enum OffsetToggles { +enum CommonToggles { On, Off, }; @@ -54,8 +54,11 @@ class CtrlMemView int visibleRows; std::string searchQuery; + + int matchAddress; bool searching; + bool searchStringValue; bool hasFocus; static wchar_t szClassName[]; @@ -78,7 +81,7 @@ public: { return debugger; } - + std::vector searchString(std::string searchQuery); void onPaint(WPARAM wParam, LPARAM lParam); void onVScroll(WPARAM wParam, LPARAM lParam); void onKeyDown(WPARAM wParam, LPARAM lParam); @@ -94,5 +97,6 @@ public: void scrollCursor(int bytes); void drawOffsetScale(HDC hdc); - void toggleOffsetScale(OffsetToggles toggle); -}; \ No newline at end of file + void toggleOffsetScale(CommonToggles toggle); + void toggleStringSearch(CommonToggles toggle); +}; diff --git a/Windows/Debugger/CtrlRegisterList.cpp b/Windows/Debugger/CtrlRegisterList.cpp index 563a2b47f1..02992e5f28 100644 --- a/Windows/Debugger/CtrlRegisterList.cpp +++ b/Windows/Debugger/CtrlRegisterList.cpp @@ -3,8 +3,8 @@ #include #include -#include "base/display.h" -#include "util/text/utf8.h" +#include "Common/System/Display.h" +#include "Common/Data/Encoding/Utf8.h" #include "Windows/resource.h" #include "Core/MemMap.h" #include "Windows/W32Util/Misc.h" @@ -19,8 +19,6 @@ #include "Windows/main.h" -static const int numCPUs = 1; - extern HMENU g_hPopupMenus; enum { REGISTER_PC = 32, REGISTER_HI, REGISTER_LO, REGISTERS_END }; @@ -520,9 +518,8 @@ void CtrlRegisterList::onMouseUp(WPARAM wParam, LPARAM lParam, int button) SendMessage(GetParent(wnd),WM_DEB_GOTOHEXEDIT,val,0); break; case ID_REGLIST_GOTOINDISASM: - for (int i=0; iGoto(val); + if (disasmWindow) + disasmWindow->Goto(val); break; case ID_REGLIST_COPYVALUE: copyRegisterValue(); diff --git a/Windows/Debugger/DebuggerShared.cpp b/Windows/Debugger/DebuggerShared.cpp index 7771edb5f2..9f3bc64313 100644 --- a/Windows/Debugger/DebuggerShared.cpp +++ b/Windows/Debugger/DebuggerShared.cpp @@ -1,4 +1,4 @@ -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "DebuggerShared.h" #include "../InputBox.h" diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index 4a2e54ee9d..39d29e7f62 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -24,19 +24,18 @@ #include "Core/CoreTiming.h" #include "Core/MIPS/MIPSAnalyst.h" -#include "base/stringutil.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "Common/CommonWindows.h" +#include "Common/StringUtils.h" + #include #include -static const int numCPUs = 1; - // How long (max) to wait for Core to pause before clearing temp breakpoints. -const int TEMP_BREAKPOINT_WAIT_MS = 100; +static const int TEMP_BREAKPOINT_WAIT_MS = 100; -FAR WNDPROC DefGotoEditProc; +static FAR WNDPROC DefGotoEditProc; LRESULT CALLBACK GotoEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { @@ -66,7 +65,7 @@ LRESULT CALLBACK GotoEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa return (LRESULT)CallWindowProc((WNDPROC)DefGotoEditProc,hDlg,message,wParam,lParam); } -FAR WNDPROC DefFuncListProc; +static FAR WNDPROC DefFuncListProc; LRESULT CALLBACK FuncListProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { @@ -94,8 +93,6 @@ LRESULT CALLBACK FuncListProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Dialog((LPCSTR)IDD_DISASM, _hInstance, _hParent) { cpu = _cpu; lastTicks = PSP_IsInited() ? CoreTiming::GetTicks() : 0; - keepStatusBarText = false; - hideBottomTabs = false; SetWindowText(m_hDlg, ConvertUTF8ToWString(_cpu->GetName()).c_str()); @@ -113,8 +110,7 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di // init status bar statusBarWnd = CreateWindowEx(0, STATUSCLASSNAME, L"", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, m_hDlg, (HMENU)IDC_DISASMSTATUSBAR, _hInstance, NULL); - if (g_Config.bDisplayStatusBar == false) - { + if (g_Config.bDisplayStatusBar == false) { ShowWindow(statusBarWnd,SW_HIDE); } @@ -238,7 +234,6 @@ void CDisasm::stepInto() Sleep(1); } - _dbg_update_(); ptr->gotoPC(); UpdateDialog(); vfpudlg->Update(); @@ -292,7 +287,6 @@ void CDisasm::stepOver() SetDebugMode(false, true); CBreakPoints::AddBreakPoint(breakpointAddress,true); - _dbg_update_(); Core_EnableStepping(false); Sleep(1); ptr->gotoAddr(breakpointAddress); @@ -331,7 +325,6 @@ void CDisasm::stepOut() SetDebugMode(false, true); CBreakPoints::AddBreakPoint(breakpointAddress,true); - _dbg_update_(); Core_EnableStepping(false); Sleep(1); ptr->gotoAddr(breakpointAddress); @@ -351,7 +344,6 @@ void CDisasm::runToLine() ptr->setDontRedraw(true); SetDebugMode(false, true); CBreakPoints::AddBreakPoint(pos,true); - _dbg_update_(); Core_EnableStepping(false); } @@ -533,7 +525,6 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) ptr->setDontRedraw(false); SetDebugMode(true, true); Core_EnableStepping(true); - _dbg_update_(); Sleep(1); //let cpu catch up ptr->gotoPC(); UpdateDialog(); @@ -573,7 +564,6 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) hleDebugBreak(); SetDebugMode(false, true); - _dbg_update_(); Core_EnableStepping(false); } break; @@ -597,10 +587,9 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) break; case IDC_ALLFUNCTIONS: - { + if (g_symbolMap) g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST),ST_FUNCTION); - break; - } + break; default: return FALSE; } @@ -860,21 +849,33 @@ void CDisasm::SetDebugMode(bool _bDebug, bool switchPC) } } -void CDisasm::NotifyMapLoaded() -{ - g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST),ST_FUNCTION); - CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg,IDC_DISASMVIEW)); +void CDisasm::Show(bool bShow) { + if (deferredSymbolFill_ && bShow) { + if (g_symbolMap) + g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), ST_FUNCTION); + deferredSymbolFill_ = false; + } + Dialog::Show(bShow); +} + +void CDisasm::NotifyMapLoaded() { + if (m_bShowState == SW_SHOW) { + if (g_symbolMap) + g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), ST_FUNCTION); + } else { + deferredSymbolFill_ = true; + } + CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg, IDC_DISASMVIEW)); ptr->clearFunctions(); ptr->redraw(); } void CDisasm::Goto(u32 addr) { - CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg,IDC_DISASMVIEW)); + CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg, IDC_DISASMVIEW)); ptr->gotoAddr(addr); SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW)); ptr->redraw(); - } void CDisasm::UpdateDialog(bool _bComplete) @@ -903,9 +904,8 @@ void CDisasm::UpdateDialog(bool _bComplete) SetDlgItemText(m_hDlg, IDC_DEBUG_COUNT, tempTicks); } // Update Register Dialog - for (int i=0; iUpdate(); + if (memoryWindow) + memoryWindow->Update(); // repaint windows at the bottom. only the memory view needs to be forced to // redraw. all others are updated manually diff --git a/Windows/Debugger/Debugger_Disasm.h b/Windows/Debugger/Debugger_Disasm.h index 5639b6e409..f743538a4f 100644 --- a/Windows/Debugger/Debugger_Disasm.h +++ b/Windows/Debugger/Debugger_Disasm.h @@ -16,7 +16,8 @@ class CDisasm : public Dialog { private: - int minWidth,minHeight; + int minWidth; + int minHeight; DebugInterface *cpu; u64 lastTicks; @@ -29,10 +30,11 @@ private: TabControl* bottomTabs; std::vector displayedBreakPoints_; std::vector displayedMemChecks_; - bool keepStatusBarText; - bool hideBottomTabs; + bool keepStatusBarText = false; + bool hideBottomTabs = false; + bool deferredSymbolFill_ = false; - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; void UpdateSize(WORD width, WORD height); void SavePosition(); void updateThreadLabel(bool clear); @@ -40,17 +42,16 @@ private: void stepOver(); void stepOut(); void runToLine(); + public: - int index; //helper + int index; CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *cpu); ~CDisasm(); - // - // --- tools --- - // - - virtual void Update() - { + + void Show(bool bShow) override; + + void Update() override { UpdateDialog(true); SetDebugMode(Core_IsStepping(), false); breakpointList->reloadBreakpoints(); @@ -58,7 +59,7 @@ public: void UpdateDialog(bool _bComplete = false); // SetDebugMode void SetDebugMode(bool _bDebug, bool switchPC); - // show dialog + void Goto(u32 addr); void NotifyMapLoaded(); }; diff --git a/Windows/Debugger/Debugger_Lists.cpp b/Windows/Debugger/Debugger_Lists.cpp index 7d08b09ee6..4463678dda 100644 --- a/Windows/Debugger/Debugger_Lists.cpp +++ b/Windows/Debugger/Debugger_Lists.cpp @@ -8,9 +8,7 @@ #include "Windows/main.h" #include "BreakpointWindow.h" #include "../../Core/HLE/sceKernelThread.h" -#include "util/text/utf8.h" - -static const int numCPUs = 1; +#include "Common/Data/Encoding/Utf8.h" enum { TL_NAME, TL_PROGRAMCOUNTER, TL_ENTRYPOINT, TL_PRIORITY, TL_STATE, TL_WAITTYPE, TL_COLUMNCOUNT }; enum { BPL_ENABLED, BPL_TYPE, BPL_OFFSET, BPL_SIZELABEL, BPL_OPCODE, BPL_CONDITION, BPL_HITS, BPL_COLUMNCOUNT }; @@ -375,22 +373,18 @@ void CtrlBreakpointList::toggleEnabled(int itemIndex) void CtrlBreakpointList::gotoBreakpointAddress(int itemIndex) { bool isMemory; - int index = getBreakpointIndex(itemIndex,isMemory); - if (index == -1) return; + int index = getBreakpointIndex(itemIndex, isMemory); + if (index == -1) + return; - if (isMemory) - { + if (isMemory) { u32 address = displayedMemChecks_[index].start; - - for (int i=0; iGoto(address); + if (memoryWindow) + memoryWindow->Goto(address); } else { u32 address = displayedBreakPoints_[index].addr; - - for (int i=0; iGoto(address); + if (disasmWindow) + disasmWindow->Goto(address); } } @@ -413,8 +407,7 @@ void CtrlBreakpointList::removeBreakpoint(int itemIndex) int CtrlBreakpointList::getTotalBreakpointCount() { int count = (int)CBreakPoints::GetMemChecks().size(); - for (size_t i = 0; i < CBreakPoints::GetBreakpoints().size(); i++) - { + for (size_t i = 0; i < CBreakPoints::GetBreakpoints().size(); i++) { if (!displayedBreakPoints_[i].temporary) count++; } diff --git a/Windows/Debugger/Debugger_MemoryDlg.cpp b/Windows/Debugger/Debugger_MemoryDlg.cpp index 6943a8b1a3..3302786160 100644 --- a/Windows/Debugger/Debugger_MemoryDlg.cpp +++ b/Windows/Debugger/Debugger_MemoryDlg.cpp @@ -1,11 +1,11 @@ // NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003. -#include "stdafx.h" +#include "Windows/stdafx.h" #include #include "..\resource.h" -#include "base/display.h" -#include "util/text/utf8.h" +#include "Common/System/Display.h" +#include "Common/Data/Encoding/Utf8.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MIPS/MIPSDebugInterface.h" // BAD @@ -13,11 +13,15 @@ #include "Debugger_MemoryDlg.h" #include "CtrlMemView.h" #include "DebuggerShared.h" +#include "LogManager.h" +#include "winnt.h" +#include +#include -RECT CMemoryDlg::slRect; +RECT CMemoryDlg::slRect; //sym list rect -FAR WNDPROC DefAddressEditProc; +FAR WNDPROC DefAddressEditProc; HWND AddressEditParentHwnd = 0; LRESULT CALLBACK AddressEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) @@ -58,22 +62,30 @@ CMemoryDlg::CMemoryDlg(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu SetWindowText(m_hDlg,temp); ShowWindow(m_hDlg,SW_HIDE); - CtrlMemView *ptr = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_MEMVIEW)); - ptr->setDebugger(_cpu); + + memViewHdl = GetDlgItem(m_hDlg, IDC_MEMVIEW); + symListHdl = GetDlgItem(m_hDlg, IDC_SYMBOLS); + searchBoxHdl = GetDlgItem(m_hDlg, IDC_SEARCH_BOX); + srcListHdl = GetDlgItem(m_hDlg, IDC_SEARCH_RESULTS); + + memView = CtrlMemView::getFrom(memViewHdl); + memView->setDebugger(_cpu); Button_SetCheck(GetDlgItem(m_hDlg,IDC_RAM), TRUE); Button_SetCheck(GetDlgItem(m_hDlg,IDC_MODESYMBOLS), TRUE); - GetWindowRect(GetDlgItem(m_hDlg,IDC_SYMBOLS),&slRect); + GetWindowRect(symListHdl, &slRect); + GetWindowRect(srcListHdl, &srRect); + // subclass the edit box - HWND editWnd = GetDlgItem(m_hDlg,IDC_ADDRESS); + editWnd = GetDlgItem(m_hDlg,IDC_ADDRESS); DefAddressEditProc = (WNDPROC)GetWindowLongPtr(editWnd,GWLP_WNDPROC); SetWindowLongPtr(editWnd,GWLP_WNDPROC,(LONG_PTR)AddressEditProc); AddressEditParentHwnd = m_hDlg; Size(); -} +} CMemoryDlg::~CMemoryDlg(void) @@ -84,21 +96,32 @@ void CMemoryDlg::Update(void) { if (m_hDlg != NULL) { - CtrlMemView *mv = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_MEMVIEW)); - if (mv != NULL) - mv->redraw(); + if (memView != NULL) + memView->redraw(); } } +void CMemoryDlg::searchBoxRedraw(std::vector results) { + wchar_t temp[256]{}; + SendMessage(srcListHdl, WM_SETREDRAW, FALSE, 0); + ListBox_ResetContent(srcListHdl); + for (int i = 0; i < results.size(); i++) { + wsprintf(temp, L"0x%08X", results[i]); + int index = (int)ListBox_AddString(srcListHdl, temp); + ListBox_SetItemData(srcListHdl, index, results[i]); + } + SendMessage(srcListHdl, WM_SETREDRAW, TRUE, 0); + RedrawWindow(srcListHdl, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); +} + + void CMemoryDlg::NotifyMapLoaded() { if (m_hDlg) { - HWND list = GetDlgItem(m_hDlg,IDC_SYMBOLS); - g_symbolMap->FillSymbolListBox(list,ST_DATA); - HWND lb = GetDlgItem(m_hDlg,IDC_REGIONS); - int sel = ComboBox_GetCurSel(lb); - ComboBox_ResetContent(lb); + g_symbolMap->FillSymbolListBox(symListHdl,ST_DATA); + int sel = ComboBox_GetCurSel(memViewHdl); + ComboBox_ResetContent(memViewHdl); /* for (int i = 0; i < cpu->getMemMap()->numRegions; i++) { @@ -106,84 +129,91 @@ void CMemoryDlg::NotifyMapLoaded() int n = ComboBox_AddString(lb,cpu->getMemMap()->regions[i].name); ComboBox_SetItemData(lb,n,cpu->getMemMap()->regions[i].start); }*/ - ComboBox_SetCurSel(lb,sel>=0?sel:0); + ComboBox_SetCurSel(memViewHdl,sel>=0?sel:0); } Update(); } - BOOL CMemoryDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { - - switch(message) - { - case WM_COMMAND: - { - CtrlMemView *mv = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_MEMVIEW)); - switch (LOWORD(wParam)) + switch(message){ + case WM_COMMAND:{ + HWND lb = GetDlgItem(m_hDlg, LOWORD(wParam)); + switch (LOWORD(wParam)){ + case IDC_REGIONS: + switch (HIWORD(wParam)) { + case LBN_DBLCLK:{ + int n = ComboBox_GetCurSel(lb); + if (n != -1) { + unsigned int addr = (unsigned int)ComboBox_GetItemData(lb,n); + memView->gotoAddr(addr); + } + } + break; + }; + break; + case IDC_SYMBOLS: + switch (HIWORD(wParam)) { + case LBN_DBLCLK:{ + int n = ListBox_GetCurSel(lb); + if (n != -1) { + unsigned int addr = (unsigned int)ListBox_GetItemData(lb,n); + memView->gotoAddr(addr); + } + } + break; + }; + case IDC_SEARCH_RESULTS: + switch (HIWORD(wParam)) { + case LBN_DBLCLK: { + int n = ListBox_GetCurSel(lb); + if (n != -1) { + unsigned int addr = (unsigned int)ListBox_GetItemData(lb, n); + memView->gotoAddr(addr); + } + } + break; + }; + break; + case IDC_SHOWOFFSETS: + switch (HIWORD(wParam)) { - case IDC_REGIONS: - switch (HIWORD(wParam)) - { - case LBN_DBLCLK: - { - HWND lb = GetDlgItem(m_hDlg,LOWORD(wParam)); - int n = ComboBox_GetCurSel(lb); - if (n!=-1) - { - unsigned int addr = (unsigned int)ComboBox_GetItemData(lb,n); - mv->gotoAddr(addr); - } - } - break; - }; + case BN_CLICKED: + if (SendDlgItemMessage(m_hDlg, IDC_SHOWOFFSETS, BM_GETCHECK, 0, 0)) + memView->toggleOffsetScale(On); + else + memView->toggleOffsetScale(Off); break; - case IDC_SYMBOLS: - switch (HIWORD(wParam)) - { - case LBN_DBLCLK: - { - - HWND lb = GetDlgItem(m_hDlg,LOWORD(wParam)); - int n = ListBox_GetCurSel(lb); - if (n!=-1) - { - unsigned int addr = (unsigned int)ListBox_GetItemData(lb,n); - mv->gotoAddr(addr); - } - } - break; - }; - break; - case IDC_SHOWOFFSETS: - switch (HIWORD(wParam)) - { - case BN_CLICKED: - if (SendDlgItemMessage(m_hDlg, IDC_SHOWOFFSETS, BM_GETCHECK, 0, 0)) - mv->toggleOffsetScale(On); - else - mv->toggleOffsetScale(Off); - break; + } + break; + case IDC_BUTTON_SEARCH: + switch (HIWORD(wParam)) + { + case BN_CLICKED: + wchar_t temp[256]; + GetWindowText(searchBoxHdl, temp, 255); + std::vector results = memView->searchString(ConvertWStringToUTF8(temp).c_str()); + if (results.size() > 0){ + searchBoxRedraw(results); } break; } } + } break; case WM_DEB_MAPLOADED: NotifyMapLoaded(); break; - case WM_DEB_GOTOADDRESSEDIT: - { - CtrlMemView *mv = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_MEMVIEW)); + case WM_DEB_GOTOADDRESSEDIT:{ wchar_t temp[256]; u32 addr; - GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),temp,255); + GetWindowText(editWnd,temp,255); if (parseExpression(ConvertWStringToUTF8(temp).c_str(),cpu,addr) == false) { displayExpressionError(m_hDlg); } else { - mv->gotoAddr(addr); - SetFocus(GetDlgItem(m_hDlg,IDC_MEMVIEW)); + memView->gotoAddr(addr); + SetFocus(memViewHdl); } break; } @@ -197,6 +227,7 @@ BOOL CMemoryDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) return TRUE; } break; + case WM_SIZE: Size(); break; @@ -211,9 +242,8 @@ BOOL CMemoryDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) void CMemoryDlg::Goto(u32 addr) { Show(true); - CtrlMemView *mv = CtrlMemView::getFrom(GetDlgItem(CMemoryDlg::m_hDlg,IDC_MEMVIEW)); - mv->gotoAddr(addr); - SetFocus(GetDlgItem(CMemoryDlg::m_hDlg,IDC_MEMVIEW)); + memView->gotoAddr(addr); + SetFocus(memViewHdl); } @@ -221,15 +251,17 @@ void CMemoryDlg::Size() { const float fontScale = 1.0f / g_dpi_scale_real_y; - RECT rc; - GetClientRect(m_hDlg,&rc); - int dw=rc.right-rc.left; - int dh=rc.bottom-rc.top; - HWND memView = GetDlgItem(m_hDlg, IDC_MEMVIEW); - HWND symList = GetDlgItem(m_hDlg, IDC_SYMBOLS); + GetClientRect(m_hDlg,&winRect); + int dlg_w = winRect.right - winRect.left; + int dlg_h = winRect.bottom - winRect.top; + + int wf = slRect.right-slRect.left; - int w = dw - 3 * fontScale - wf; + int w = dlg_w - 3 * fontScale - wf*2; int top = 48 * fontScale; - MoveWindow(symList,0,top,wf,dh-top,TRUE); - MoveWindow(memView,wf+4,top,w,dh-top,TRUE); + int height = dlg_h - top; + //HWND, X, Y, width, height, repaint + MoveWindow(symListHdl, 0 ,top, wf, height, TRUE); + MoveWindow(memViewHdl, wf+4 ,top, w, height, TRUE); + MoveWindow(srcListHdl, wf + 4 + w+ 4, top, wf-4, height, TRUE); } diff --git a/Windows/Debugger/Debugger_MemoryDlg.h b/Windows/Debugger/Debugger_MemoryDlg.h index d8e2c5fef4..91bf07e986 100644 --- a/Windows/Debugger/Debugger_MemoryDlg.h +++ b/Windows/Debugger/Debugger_MemoryDlg.h @@ -6,7 +6,7 @@ #include "Core/MemMap.h" #include "Core/Debugger/DebugInterface.h" - +#include "CtrlMemView.h" #include "Common/CommonWindows.h" class CMemoryDlg : public Dialog @@ -14,11 +14,16 @@ class CMemoryDlg : public Dialog private: DebugInterface *cpu; static RECT slRect; - + RECT winRect, srRect; + CtrlMemView *memView; + HWND memViewHdl, symListHdl, editWnd, searchBoxHdl, srcListHdl; BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + public: int index; //helper + void searchBoxRedraw(std::vector results); + // constructor CMemoryDlg(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu); @@ -29,6 +34,8 @@ public: void Update(void); void NotifyMapLoaded(); + void NotifySearchCompleted(); + void Size(void); }; diff --git a/Windows/Debugger/Debugger_VFPUDlg.cpp b/Windows/Debugger/Debugger_VFPUDlg.cpp index beb8caf41e..8851afd62e 100644 --- a/Windows/Debugger/Debugger_VFPUDlg.cpp +++ b/Windows/Debugger/Debugger_VFPUDlg.cpp @@ -4,7 +4,7 @@ #include #include #include "Windows/resource.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "Core/Debugger/SymbolMap.h" #include "Windows/Debugger/Debugger_VFPUDlg.h" diff --git a/Windows/Debugger/DumpMemoryWindow.cpp b/Windows/Debugger/DumpMemoryWindow.cpp index 1fdb549486..3676307420 100644 --- a/Windows/Debugger/DumpMemoryWindow.cpp +++ b/Windows/Debugger/DumpMemoryWindow.cpp @@ -1,6 +1,6 @@ #include #include -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "Core/Core.h" #include "Core/MemMap.h" #include "Windows/Debugger/DumpMemoryWindow.h" diff --git a/Windows/DinputDevice.cpp b/Windows/DinputDevice.cpp index 5d89e4ab54..d59874d680 100644 --- a/Windows/DinputDevice.cpp +++ b/Windows/DinputDevice.cpp @@ -23,9 +23,9 @@ #include "Core/HLE/sceCtrl.h" #include "DinputDevice.h" #include "Core/Config.h" -#include "input/input_state.h" -#include "base/NativeApp.h" -#include "input/keycodes.h" +#include "Common/Input/InputState.h" +#include "Common/System/NativeApp.h" +#include "Common/Input/KeyCodes.h" #include "Core/Reporting.h" #include "Xinput.h" #pragma comment(lib,"dinput8.lib") diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 5c60b495ad..120130161e 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -2,15 +2,17 @@ #include #include -#include "base/timeutil.h" -#include "base/NativeApp.h" -#include "i18n/i18n.h" -#include "input/input_state.h" -#include "util/text/utf8.h" - +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Input/InputState.h" +#include "Common/Data/Encoding/Utf8.h" #include "Common/Log.h" #include "Common/StringUtils.h" #include "Common/GraphicsContext.h" +#include "Common/TimeUtil.h" +#include "Common/Thread/ThreadUtil.h" + #include "Windows/EmuThread.h" #include "Windows/W32Util/Misc.h" #include "Windows/MainWindow.h" @@ -23,7 +25,6 @@ #include "Core/System.h" #include "Core/Config.h" #include "Core/ConfigValues.h" -#include "thread/threadutil.h" enum class EmuThreadState { DISABLED, @@ -104,7 +105,7 @@ static void EmuThreadStop() { static void EmuThreadJoin() { emuThread.join(); emuThread = std::thread(); - ILOG("EmuThreadJoin - joined"); + INFO_LOG(SYSTEM, "EmuThreadJoin - joined"); } void MainThreadFunc() { @@ -148,8 +149,8 @@ void MainThreadFunc() { Reporting::ReportMessage("Graphics init error: %s", "ALL"); auto err = GetI18NCategory("Error"); - const char *defaultErrorAll = "Failed initializing any graphics. Try upgrading your graphics drivers."; - const char *genericError = err->T("GenericAllGraphicsError", defaultErrorAll); + const char *defaultErrorAll = "PPSSPP failed to startup with any graphics backend. Try upgrading your graphics and other drivers."; + const char *genericError = err->T("GenericAllStartupError", defaultErrorAll); std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error")); MessageBox(0, ConvertUTF8ToWString(genericError).c_str(), title.c_str(), MB_OK); @@ -230,7 +231,6 @@ void MainThreadFunc() { } INFO_LOG(BOOT, "Done."); - _dbg_update_(); if (coreState == CORE_POWERDOWN) { INFO_LOG(BOOT, "Exit before core loop."); diff --git a/Windows/GEDebugger/CtrlDisplayListView.cpp b/Windows/GEDebugger/CtrlDisplayListView.cpp index 07cc0490db..78b3373a5e 100644 --- a/Windows/GEDebugger/CtrlDisplayListView.cpp +++ b/Windows/GEDebugger/CtrlDisplayListView.cpp @@ -1,4 +1,4 @@ -#include "base/display.h" +#include "Common/System/Display.h" #include "Windows/GEDebugger/CtrlDisplayListView.h" #include "Windows/GEDebugger/GEDebugger.h" #include "Windows/InputBox.h" @@ -9,8 +9,6 @@ #include -static const int numCPUs = 1; - const PTCHAR CtrlDisplayListView::windowClass = _T("CtrlDisplayListView"); const int POPUP_SUBMENU_ID_DISPLAYLISTVIEW = 8; @@ -308,9 +306,8 @@ void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) switch(TrackPopupMenuEx(GetSubMenu(g_hPopupMenus,POPUP_SUBMENU_ID_DISPLAYLISTVIEW),TPM_RIGHTBUTTON|TPM_RETURNCMD,pt.x,pt.y,wnd,0)) { case ID_DISASM_GOTOINMEMORYVIEW: - for (int i=0; iGoto(curAddress); + if (memoryWindow) + memoryWindow->Goto(curAddress); break; case ID_DISASM_TOGGLEBREAKPOINT: toggleBreakpoint(); diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index d3ad5e460e..ec5cedcb3f 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -20,8 +20,9 @@ #include #include -#include "base/stringutil.h" +#include "Common/Data/Text/Parsers.h" #include "Common/ColorConv.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/Screenshot.h" #include "Windows/GEDebugger/GEDebugger.h" @@ -286,7 +287,7 @@ void CGEDebugger::DescribePrimaryPreview(const GPUgstate &state, wchar_t desc[25 return; } - _assert_msg_(G3D, primaryBuffer_ != nullptr, "Must have a valid primaryBuffer_"); + _assert_msg_(primaryBuffer_ != nullptr, "Must have a valid primaryBuffer_"); switch (PrimaryDisplayType(fbTabs->CurrentTabIndex())) { case PRIMARY_FRAMEBUF: @@ -559,9 +560,12 @@ void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, break; case GPU_DBG_FORMAT_24BIT_8X: + { + DepthScaleFactors depthScale = GetDepthScaleFactors(); // These are only ever going to be depth values, so let's also show scaled to 16 bit. - _snwprintf(desc, 256, L"%d,%d: %d / %f / %f", x, y, pix & 0x00FFFFFF, (pix & 0x00FFFFFF) * (1.0f / 16777215.0f), FromScaledDepth((pix & 0x00FFFFFF) * (1.0f / 16777215.0f))); + _snwprintf(desc, 256, L"%d,%d: %d / %f / %f", x, y, pix & 0x00FFFFFF, (pix & 0x00FFFFFF) * (1.0f / 16777215.0f), depthScale.Apply((pix & 0x00FFFFFF) * (1.0f / 16777215.0f))); break; + } case GPU_DBG_FORMAT_24BIT_8X_DIV_256: { @@ -576,15 +580,24 @@ void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, (pix >> 24) & 0xFF, ((pix >> 24) & 0xFF) * (1.0f / 255.0f)); break; - case GPU_DBG_FORMAT_FLOAT: - _snwprintf(desc, 256, L"%d,%d: %f / %f", x, y, *(float *)&pix, FromScaledDepth(*(float *)&pix)); + case GPU_DBG_FORMAT_FLOAT: { + float pixf = *(float *)&pix; + DepthScaleFactors depthScale = GetDepthScaleFactors(); + _snwprintf(desc, 256, L"%d,%d: %f / %f", x, y, pixf, depthScale.Apply(pixf)); break; + } case GPU_DBG_FORMAT_FLOAT_DIV_256: { double z = *(float *)&pix; int z24 = (int)(z * 16777215.0); + + DepthScaleFactors factors = GetDepthScaleFactors(); + // TODO: Use GetDepthScaleFactors here too, verify it's the same. int z16 = z24 - 0x800000 + 0x8000; + + int z16_2 = factors.Apply(z); + _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, z16, (z - 0.5 + (1.0 / 512.0)) * 256.0); } break; diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index 07fef48e02..37e6b7bd28 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -16,9 +16,9 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include "math/lin/matrix4x4.h" -#include "gfx_es2/glsl_program.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "Common/Common.h" #include "Windows/GEDebugger/SimpleGLWindow.h" @@ -296,7 +296,7 @@ void SimpleGLWindow::Draw(const u8 *data, int w, int h, bool flipped, Format fmt glfmt = GL_UNSIGNED_BYTE; components = GL_RED; } else { - _dbg_assert_msg_(COMMON, false, "Invalid SimpleGLWindow format."); + _dbg_assert_msg_(false, "Invalid SimpleGLWindow format."); } } diff --git a/Windows/GEDebugger/SimpleGLWindow.h b/Windows/GEDebugger/SimpleGLWindow.h index 8628ab5eef..c6ebb1c104 100644 --- a/Windows/GEDebugger/SimpleGLWindow.h +++ b/Windows/GEDebugger/SimpleGLWindow.h @@ -20,7 +20,7 @@ #include #include "CommonWindows.h" -#include "gfx_es2/glsl_program.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" #include "Common/CommonWindows.h" struct SimpleGLWindow { diff --git a/Windows/GEDebugger/TabState.cpp b/Windows/GEDebugger/TabState.cpp index 3b3241b947..b72ed126a8 100644 --- a/Windows/GEDebugger/TabState.cpp +++ b/Windows/GEDebugger/TabState.cpp @@ -15,7 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/basictypes.h" +#include "Common/Common.h" #include "Windows/resource.h" #include "Windows/main.h" #include "Windows/InputBox.h" diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index bd65e87999..55eb23cc4b 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -15,7 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/basictypes.h" +#include "Common/Common.h" #include "Core/System.h" #include "Windows/resource.h" #include "Windows/GEDebugger/GEDebugger.h" diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 271302237b..cc3589eebc 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -15,9 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "math/lin/matrix4x4.h" -#include "gfx_es2/glsl_program.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "Windows/GEDebugger/GEDebugger.h" #include "Windows/GEDebugger/SimpleGLWindow.h" #include "Core/System.h" diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 31b3bcb086..8f93ebc88d 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -3,12 +3,11 @@ #include "Common/CommonWindows.h" #include #include -#include -#include "base/logging.h" -#include "Base/display.h" -#include "util/text/utf8.h" -#include "i18n/i18n.h" +#include "Common/Log.h" +#include "Common/System/Display.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Text/I18n.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -16,9 +15,9 @@ #include "Core/System.h" #include "Windows/GPU/D3D11Context.h" #include "Windows/W32Util/Misc.h" -#include "thin3d/thin3d.h" -#include "thin3d/thin3d_create.h" -#include "thin3d/d3d11_loader.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/D3D11/D3D11Loader.h" #ifdef __MINGW32__ #undef __uuidof @@ -55,7 +54,7 @@ HRESULT D3D11Context::CreateTheDevice(IDXGIAdapter *adapter) { // D3D11 has no need for display rotation. g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); -#if defined(_DEBUG) && !defined(_M_ARM) && !defined(_M_ARM64) +#if defined(_DEBUG) && !PPSSPP_ARCH(ARM) && !PPSSPP_ARCH(ARM64) UINT createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG; #else UINT createDeviceFlags = 0; @@ -187,7 +186,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, featureLevel_, hWnd_, adapterNames); SetGPUBackend(GPUBackend::DIRECT3D11, chosenAdapterName); bool success = draw_->CreatePresets(); // If we can run D3D11, there's a compiler installed. I think. - _assert_msg_(G3D, success, "Failed to compile preset shaders"); + _assert_msg_(success, "Failed to compile preset shaders"); int width; int height; diff --git a/Windows/GPU/D3D9Context.cpp b/Windows/GPU/D3D9Context.cpp index 2ea38836e0..0ccfa8364c 100644 --- a/Windows/GPU/D3D9Context.cpp +++ b/Windows/GPU/D3D9Context.cpp @@ -3,13 +3,13 @@ #include "Common/CommonWindows.h" #include -#include "gfx/d3d9_state.h" +#include "Common/GPU/D3D9/D3D9StateCache.h" -#include "base/logging.h" -#include "base/display.h" -#include "util/text/utf8.h" -#include "i18n/i18n.h" +#include "Common/System/Display.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Log.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Reporting.h" @@ -17,14 +17,9 @@ #include "Common/OSVersion.h" #include "Windows/GPU/D3D9Context.h" #include "Windows/W32Util/Misc.h" -#include "thin3d/thin3d.h" -#include "thin3d/thin3d_create.h" - -#if PPSSPP_API(D3DX9) -#include "thin3d/d3dx9_loader.h" -#elif PPSSPP_API(D3D9_D3DCOMPILER) -#include "thin3d/d3d9_d3dcompiler_loader.h" -#endif +#include "Common/GPU/thin3d.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/D3D9/D3DCompilerLoader.h" void D3D9Context::SwapBuffers() { if (has9Ex_) { @@ -71,24 +66,16 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { hD3D9_ = LoadLibrary(TEXT("d3d9.dll")); if (!hD3D9_) { - ELOG("Missing d3d9.dll"); + ERROR_LOG(G3D, "Missing d3d9.dll"); *error_message = "D3D9.dll missing - try reinstalling DirectX."; return false; } -#if PPSSPP_API(D3DX9) - int d3dx_version = LoadD3DX9Dynamic(); - if (!d3dx_version) { - *error_message = "D3DX DLL not found! Try reinstalling DirectX."; - return false; - } -#elif PPSSPP_API(D3D9_D3DCOMPILER) bool result = LoadD3DCompilerDynamic(); if (!result) { *error_message = "D3DCompiler not found! Try reinstalling DirectX."; return false; } -#endif g_pfnCreate9ex = (DIRECT3DCREATE9EX)GetProcAddress(hD3D9_, "Direct3DCreate9Ex"); has9Ex_ = (g_pfnCreate9ex != NULL) && IsVistaOrHigher(); @@ -218,7 +205,7 @@ void D3D9Context::Resize() { HRESULT hr = device_->Reset(&presentParams_); if (FAILED(hr)) { // Had to remove DXGetErrorStringA calls here because dxerr.lib is deprecated and will not link with VS 2015. - PanicAlert("Unable to reset D3D9 device"); + _assert_msg_(false, "Unable to reset D3D9 device"); } draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr); } @@ -231,11 +218,7 @@ void D3D9Context::Shutdown() { device_->EndScene(); device_->Release(); d3d_->Release(); -#if PPSSPP_API(D3DX9) - UnloadD3DXDynamic(); -#elif PPSSPP_API(D3D9_D3DCOMPILER) UnloadD3DCompiler(); -#endif DX9::pD3Ddevice = nullptr; DX9::pD3DdeviceEx = nullptr; device_ = nullptr; diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index 71e215c0bc..765321c903 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -15,21 +15,20 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include #include "Common/Log.h" #include "Common/CommonWindows.h" -#include "gfx/gl_common.h" -#include "gfx/gl_debug_log.h" -#include "gfx_es2/gpu_features.h" -#include "thin3d/thin3d_create.h" -#include "thin3d/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLDebugLog.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "GL/gl.h" #include "GL/wglew.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Core.h" -#include "util/text/utf8.h" -#include "i18n/i18n.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Data/Text/I18n.h" #include "UI/OnScreenDisplay.h" #include "ext/glslang/glslang/Public/ShaderLang.h" @@ -132,8 +131,13 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu void DebugCallbackARB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam) { // Ignore buffer mapping messages from NVIDIA - if (source == GL_DEBUG_SOURCE_API_ARB && type == GL_DEBUG_TYPE_OTHER_ARB && id == 131185) + if (source == GL_DEBUG_SOURCE_API_ARB && type == GL_DEBUG_TYPE_OTHER_ARB && id == 131185) { return; + } + // Ignore application messages + if (source == GL_DEBUG_SOURCE_APPLICATION) { + return; + } (void)length; FILE *outFile = (FILE *)userParam; @@ -367,7 +371,14 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) { hRC = m_hrc; - if (g_Config.bGfxDebugOutput) { + bool validation = g_Config.bGfxDebugOutput; + + // Always run OpenGL validation in debug mode, just like we do with Vulkan if debug layers are installed. +#ifdef _DEBUG + validation = true; +#endif + + if (validation) { if (wglewIsSupported("GL_KHR_debug") == 1) { glGetError(); glDebugMessageCallback((GLDEBUGPROC)&DebugCallbackARB, nullptr); @@ -399,17 +410,23 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) { pauseRequested = false; resumeRequested = false; + CheckGLExtensions(); + draw_ = Draw::T3DCreateGLContext(); + bool success = draw_->CreatePresets(); // if we get this far, there will always be a GLSL compiler capable of compiling these. + if (!success) { + delete draw_; + draw_ = nullptr; + ReleaseGLContext(); + return false; + } + // These are auto-reset events. pauseEvent = CreateEvent(NULL, FALSE, FALSE, NULL); resumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - CheckGLExtensions(); - draw_ = Draw::T3DCreateGLContext(); renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager_->SetInflightFrames(g_Config.iInflightFrames); SetGPUBackend(GPUBackend::OPENGL); - bool success = draw_->CreatePresets(); // if we get this far, there will always be a GLSL compiler capable of compiling these. - _assert_msg_(G3D, success, "Failed to compile preset shaders"); renderManager_->SetSwapFunction([&]() {::SwapBuffers(hDC); }); if (wglSwapIntervalEXT) { // glew loads wglSwapIntervalEXT if available @@ -430,14 +447,10 @@ void WindowsGLContext::Shutdown() { glslang::FinalizeProcess(); } -void WindowsGLContext::ShutdownFromRenderThread() { - delete draw_; - draw_ = nullptr; - CloseHandle(pauseEvent); - CloseHandle(resumeEvent); +void WindowsGLContext::ReleaseGLContext() { if (hRC) { // Are we able to release the DC and RC contexts? - if (!wglMakeCurrent(NULL,NULL)) { + if (!wglMakeCurrent(NULL, NULL)) { MessageBox(NULL, L"Release of DC and RC failed.", L"SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); } @@ -458,6 +471,14 @@ void WindowsGLContext::ShutdownFromRenderThread() { hWnd_ = NULL; } +void WindowsGLContext::ShutdownFromRenderThread() { + delete draw_; + draw_ = nullptr; + CloseHandle(pauseEvent); + CloseHandle(resumeEvent); + ReleaseGLContext(); +} + void WindowsGLContext::Resize() { } diff --git a/Windows/GPU/WindowsGLContext.h b/Windows/GPU/WindowsGLContext.h index 1303aece79..df8190f9dc 100644 --- a/Windows/GPU/WindowsGLContext.h +++ b/Windows/GPU/WindowsGLContext.h @@ -34,6 +34,8 @@ public: Draw::DrawContext *GetDrawContext() override { return draw_; } private: + void ReleaseGLContext(); + bool renderThread_; Draw::DrawContext *draw_; GLRenderManager *renderManager_; diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index c747026e38..5618e2f1f5 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -46,22 +46,19 @@ // and use the same render pass configuration (clear to black). However, we can later change this so we switch // to a non-clearing render pass in buffered mode, which might be a tiny bit faster. -#include #include #include #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" -#include "Common/Vulkan/VulkanLoader.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanDebug.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanContext.h" -#include "base/stringutil.h" -#include "thin3d/thin3d.h" -#include "thin3d/thin3d_create.h" -#include "thin3d/VulkanRenderManager.h" -#include "util/text/parsers.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/Data/Text/Parsers.h" #include "Windows/GPU/WindowsVulkanContext.h" #ifdef _DEBUG @@ -70,10 +67,6 @@ static const bool g_validate_ = true; static const bool g_validate_ = false; #endif -static VulkanContext *g_Vulkan; - -static VulkanLogOptions g_LogOptions; - static uint32_t FlagsFromConfig() { uint32_t flags = 0; flags = g_Config.bVSync ? VULKAN_FLAG_PRESENT_FIFO : VULKAN_FLAG_PRESENT_MAILBOX; @@ -86,7 +79,7 @@ static uint32_t FlagsFromConfig() { bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_message) { *error_message = "N/A"; - if (g_Vulkan) { + if (vulkan_) { *error_message = "Already initialized"; return false; } @@ -104,63 +97,51 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m return false; } - g_Vulkan = new VulkanContext(); + vulkan_ = new VulkanContext(); VulkanContext::CreateInfo info{}; info.app_name = "PPSSPP"; info.app_ver = gitVer.ToInteger(); info.flags = FlagsFromConfig(); - if (VK_SUCCESS != g_Vulkan->CreateInstance(info)) { - *error_message = g_Vulkan->InitError(); - delete g_Vulkan; - g_Vulkan = nullptr; + if (VK_SUCCESS != vulkan_->CreateInstance(info)) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; return false; } - int deviceNum = g_Vulkan->GetPhysicalDeviceByName(g_Config.sVulkanDevice); + int deviceNum = vulkan_->GetPhysicalDeviceByName(g_Config.sVulkanDevice); if (deviceNum < 0) { - deviceNum = g_Vulkan->GetBestPhysicalDevice(); + deviceNum = vulkan_->GetBestPhysicalDevice(); if (!g_Config.sVulkanDevice.empty()) - g_Config.sVulkanDevice = g_Vulkan->GetPhysicalDeviceProperties(deviceNum).properties.deviceName; + g_Config.sVulkanDevice = vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName; } - g_Vulkan->ChooseDevice(deviceNum); - if (g_Vulkan->CreateDevice() != VK_SUCCESS) { - *error_message = g_Vulkan->InitError(); - delete g_Vulkan; - g_Vulkan = nullptr; + vulkan_->ChooseDevice(deviceNum); + if (vulkan_->CreateDevice() != VK_SUCCESS) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; return false; } - if (g_validate_) { - if (g_Vulkan->DeviceExtensions().EXT_debug_utils) { - int bits = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - // We're intentionally skipping VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT and - // VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, just too spammy. - g_Vulkan->InitDebugUtilsCallback(&VulkanDebugUtilsCallback, bits, &g_LogOptions); - } else { - int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; - g_Vulkan->InitDebugMsgCallback(&VulkanDebugReportCallback, bits, &g_LogOptions); - } - } - g_Vulkan->InitSurface(WINDOWSYSTEM_WIN32, (void *)hInst, (void *)hWnd); - if (!g_Vulkan->InitObjects()) { - *error_message = g_Vulkan->InitError(); + + vulkan_->InitSurface(WINDOWSYSTEM_WIN32, (void *)hInst, (void *)hWnd); + if (!vulkan_->InitSwapchain()) { + *error_message = vulkan_->InitError(); Shutdown(); return false; } bool splitSubmit = g_Config.bGfxDebugSplitSubmit; - draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, splitSubmit); - SetGPUBackend(GPUBackend::VULKAN, g_Vulkan->GetPhysicalDeviceProperties(deviceNum).properties.deviceName); + draw_ = Draw::T3DCreateVulkanContext(vulkan_, splitSubmit); + SetGPUBackend(GPUBackend::VULKAN, vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName); bool success = draw_->CreatePresets(); - _assert_msg_(G3D, success, "Failed to compile preset shaders"); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + _assert_msg_(success, "Failed to compile preset shaders"); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - renderManager->SetInflightFrames(g_Config.iInflightFrames); - if (!renderManager->HasBackbuffers()) { + renderManager_ = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + renderManager_->SetInflightFrames(g_Config.iInflightFrames); + if (!renderManager_->HasBackbuffers()) { Shutdown(); return false; } @@ -169,35 +150,39 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m void WindowsVulkanContext::Shutdown() { if (draw_) - draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); delete draw_; draw_ = nullptr; - g_Vulkan->WaitUntilQueueIdle(); - g_Vulkan->DestroyObjects(); - g_Vulkan->DestroyDevice(); - g_Vulkan->DestroyDebugUtilsCallback(); - g_Vulkan->DestroyDebugMsgCallback(); - g_Vulkan->DestroyInstance(); + vulkan_->WaitUntilQueueIdle(); + vulkan_->DestroySwapchain(); + vulkan_->DestroySurface(); + vulkan_->DestroyDevice(); + vulkan_->DestroyInstance(); - delete g_Vulkan; - g_Vulkan = nullptr; + delete vulkan_; + vulkan_ = nullptr; + renderManager_ = nullptr; finalize_glslang(); } void WindowsVulkanContext::Resize() { - draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - g_Vulkan->DestroyObjects(); + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + vulkan_->DestroySwapchain(); + vulkan_->UpdateFlags(FlagsFromConfig()); + vulkan_->InitSwapchain(); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); +} - g_Vulkan->UpdateFlags(FlagsFromConfig()); - g_Vulkan->ReinitSurface(); - - g_Vulkan->InitObjects(); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); +void WindowsVulkanContext::Poll() { + // Check for existing swapchain to avoid issues during shutdown. + if (vulkan_->GetSwapchain() && renderManager_->NeedsSwapchainRecreate()) { + Resize(); + } } void *WindowsVulkanContext::GetAPIContext() { - return g_Vulkan; + return vulkan_; } diff --git a/Windows/GPU/WindowsVulkanContext.h b/Windows/GPU/WindowsVulkanContext.h index 0a00dfeab8..098d737e98 100644 --- a/Windows/GPU/WindowsVulkanContext.h +++ b/Windows/GPU/WindowsVulkanContext.h @@ -19,7 +19,10 @@ #include "Common/GraphicsContext.h" #include "Windows/GPU/WindowsGraphicsContext.h" -#include "thin3d/thin3d.h" +#include "Common/GPU/thin3d.h" + +class VulkanContext; +class VulkanRenderManager; class WindowsVulkanContext : public WindowsGraphicsContext { public: @@ -29,11 +32,14 @@ public: void SwapInterval(int interval) override {} void SwapBuffers() override {} void Resize() override; + void Poll() override; void *GetAPIContext(); Draw::DrawContext *GetDrawContext() override { return draw_; } private: Draw::DrawContext *draw_; + VulkanContext *vulkan_ = nullptr; + VulkanRenderManager *renderManager_ = nullptr; }; diff --git a/Windows/InputBox.cpp b/Windows/InputBox.cpp index f3aebb8582..314aac514c 100644 --- a/Windows/InputBox.cpp +++ b/Windows/InputBox.cpp @@ -2,7 +2,7 @@ #include "Common/CommonWindows.h" #include "Windows/InputBox.h" #include "Windows/resource.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" static std::wstring textBoxContents; static std::wstring out; @@ -108,10 +108,10 @@ bool InputBox_GetWString(HINSTANCE hInst, HWND hParent, const wchar_t *title, co return false; } -bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 defaultvalue, u32 &outvalue) +bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t* title, u32 defaultvalue, u32& outvalue) { wchar_t temp[256]; - wsprintf(temp,L"%08x",defaultvalue); + wsprintf(temp, L"%08x", defaultvalue); textBoxContents = temp; INT_PTR value = DialogBox(hInst, (LPCWSTR)IDD_INPUTBOX, hParent, InputBoxFunc); @@ -124,9 +124,9 @@ bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 de return true; return false; } - else + else { outvalue = 0; return false; } -} \ No newline at end of file +} diff --git a/Windows/InputDevice.cpp b/Windows/InputDevice.cpp index 3c59c8323e..28e6c2d379 100644 --- a/Windows/InputDevice.cpp +++ b/Windows/InputDevice.cpp @@ -15,18 +15,19 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "stdafx.h" #include #include -#include "input/input_state.h" -#include "thread/threadutil.h" +#include "Common/Input/InputState.h" +#include "Common/Thread/ThreadUtil.h" #include "Core/Config.h" #include "Core/Host.h" #include "Windows/InputDevice.h" static std::atomic_flag threadRunningFlag; static std::thread inputThread; -static std::atomic_bool focused = true; +static std::atomic_bool focused = ATOMIC_VAR_INIT(true); inline static void ExecuteInputPoll() { if (host && (focused.load(std::memory_order_relaxed) || !g_Config.bGamepadOnlyFocused)) { diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 310dc94265..e91446278e 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -22,7 +22,6 @@ // It's improving slowly, though. :) #include "stdafx.h" #include "Common/CommonWindows.h" -#include "Common/KeyMap.h" #include "Common/OSVersion.h" #include "ppsspp_config.h" @@ -32,19 +31,23 @@ #include #include -#include "base/display.h" -#include "base/NativeApp.h" -#include "base/timeutil.h" -#include "i18n/i18n.h" -#include "input/input_state.h" -#include "input/keycodes.h" -#include "thread/threadutil.h" -#include "util/text/utf8.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/TimeUtil.h" +#include "Common/StringUtils.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Utf8.h" #include "Core/Core.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Debugger/SymbolMap.h" +#include "Core/Instance.h" +#include "Core/KeyMap.h" #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" #include "Windows/InputBox.h" @@ -479,7 +482,11 @@ namespace MainWindow void UpdateWindowTitle() { // Seems to be fine to call now since we use a UNICODE build... - SetWindowText(hwndMain, windowTitle.c_str()); + std::wstring title = windowTitle; + if (PPSSPP_ID >= 1 && GetInstancePeerCount() > 1) { + title.append(ConvertUTF8ToWString(StringFromFormat(" (instance: %d)", (int)PPSSPP_ID))); + } + SetWindowText(hwndMain, title.c_str()); } void SetWindowTitle(const wchar_t *title) { @@ -566,23 +573,23 @@ namespace MainWindow } void CreateDebugWindows() { - disasmWindow[0] = new CDisasm(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); - DialogManager::AddDlg(disasmWindow[0]); - disasmWindow[0]->Show(g_Config.bShowDebuggerOnLoad); + disasmWindow = new CDisasm(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); + DialogManager::AddDlg(disasmWindow); + disasmWindow->Show(g_Config.bShowDebuggerOnLoad); #if PPSSPP_API(ANY_GL) geDebuggerWindow = new CGEDebugger(MainWindow::GetHInstance(), MainWindow::GetHWND()); DialogManager::AddDlg(geDebuggerWindow); #endif - memoryWindow[0] = new CMemoryDlg(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); - DialogManager::AddDlg(memoryWindow[0]); + memoryWindow = new CMemoryDlg(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); + DialogManager::AddDlg(memoryWindow); } void DestroyDebugWindows() { - DialogManager::RemoveDlg(disasmWindow[0]); - if (disasmWindow[0]) - delete disasmWindow[0]; - disasmWindow[0] = 0; + DialogManager::RemoveDlg(disasmWindow); + if (disasmWindow) + delete disasmWindow; + disasmWindow = 0; #if PPSSPP_API(ANY_GL) DialogManager::RemoveDlg(geDebuggerWindow); @@ -591,10 +598,10 @@ namespace MainWindow geDebuggerWindow = 0; #endif - DialogManager::RemoveDlg(memoryWindow[0]); - if (memoryWindow[0]) - delete memoryWindow[0]; - memoryWindow[0] = 0; + DialogManager::RemoveDlg(memoryWindow); + if (memoryWindow) + delete memoryWindow; + memoryWindow = 0; } LRESULT CALLBACK DisplayProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -644,14 +651,14 @@ namespace MainWindow // Simulate doubleclick, doesn't work with RawInput enabled static double lastMouseDown; - double now = real_time_now(); + double now = time_now_d(); if ((now - lastMouseDown) < 0.001 * GetDoubleClickTime()) { if (!g_Config.bShowTouchControls && !g_Config.bMouseControl && GetUIState() == UISTATE_INGAME && g_Config.bFullscreenOnDoubleclick) { SendToggleFullscreen(!g_Config.bFullScreen); } lastMouseDown = 0.0; } else { - lastMouseDown = real_time_now(); + lastMouseDown = time_now_d(); } } break; @@ -708,10 +715,8 @@ namespace MainWindow break; case WM_TOUCH: - { - touchHandler.handleTouchEvent(hWnd, message, wParam, lParam); - return 0; - } + touchHandler.handleTouchEvent(hWnd, message, wParam, lParam); + return 0; default: return DefWindowProc(hWnd, message, wParam, lParam); @@ -747,6 +752,7 @@ namespace MainWindow case WM_ACTIVATE: { + UpdateWindowTitle(); bool pause = true; if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) { WindowsRawInput::GainFocus(); @@ -758,8 +764,8 @@ namespace MainWindow } if (!noFocusPause && g_Config.bPauseOnLostFocus && GetUIState() == UISTATE_INGAME) { if (pause != Core_IsStepping()) { // != is xor for bools - if (disasmWindow[0]) - SendMessage(disasmWindow[0]->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); + if (disasmWindow) + SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); else Core_EnableStepping(pause); } @@ -780,6 +786,10 @@ namespace MainWindow } break; + case WM_SETFOCUS: + UpdateWindowTitle(); + break; + case WM_ERASEBKGND: // This window is always covered by DisplayWindow. No reason to erase. return 1; @@ -889,7 +899,10 @@ namespace MainWindow #ifndef _M_ARM DinputDevice::CheckDevices(); #endif - WindowsCaptureDevice::CheckDevices(); + if (winCamera) + winCamera->CheckDevices(); + if (winMic) + winMic->CheckDevices(); return DefWindowProc(hWnd, message, wParam, lParam); case WM_VERYSLEEPY_MSG: @@ -954,13 +967,13 @@ namespace MainWindow break; case WM_USER + 1: - if (disasmWindow[0]) - disasmWindow[0]->NotifyMapLoaded(); - if (memoryWindow[0]) - memoryWindow[0]->NotifyMapLoaded(); + if (disasmWindow) + disasmWindow->NotifyMapLoaded(); + if (memoryWindow) + memoryWindow->NotifyMapLoaded(); - if (disasmWindow[0]) - disasmWindow[0]->UpdateDialog(); + if (disasmWindow) + disasmWindow->UpdateDialog(); SetForegroundWindow(hwndMain); break; diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 8d3b25fa9c..8d42636f53 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -1,21 +1,25 @@ #include #include +#include #include "CommonWindows.h" #include #include "resource.h" -#include "i18n/i18n.h" -#include "util/text/utf8.h" -#include "base/NativeApp.h" +#include "Common/GPU/OpenGL/GLFeatures.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Common/File/FileUtil.h" #include "Common/Log.h" #include "Common/LogManager.h" #include "Common/ConsoleListener.h" #include "Common/OSVersion.h" -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/StringUtils.h" #if PPSSPP_API(ANY_GL) #include "GPU/GLES/TextureScalerGLES.h" #include "GPU/GLES/TextureCacheGLES.h" @@ -23,13 +27,14 @@ #endif #include "UI/OnScreenDisplay.h" #include "GPU/Common/PostShader.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Common/TextureScalerCommon.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/FileSystems/MetaFileSystem.h" +#include "Core/KeyMap.h" #include "UI/OnScreenDisplay.h" #include "Windows/MainWindowMenu.h" #include "Windows/MainWindow.h" @@ -44,10 +49,10 @@ #include "Core/Core.h" extern bool g_TakeScreenshot; +extern bool g_ShaderNameListChanged; namespace MainWindow { extern HINSTANCE hInst; - static const int numCPUs = 1; // what? extern bool noFocusPause; static W32Util::AsyncBrowseDialog *browseDialog; static W32Util::AsyncBrowseDialog *browseImageDialog; @@ -164,7 +169,7 @@ namespace MainWindow { int item = ID_SHADERS_BASE + 1; for (size_t i = 0; i < availableShaders.size(); i++) - CheckMenuItem(menu, item++, ((g_Config.sPostShaderName == availableShaders[i]) ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, item++, ((g_Config.vPostShaderNames[0] == availableShaders[i] && (g_Config.vPostShaderNames[0] == "Off" || g_Config.vPostShaderNames[1] == "Off")) ? MF_CHECKED : MF_UNCHECKED)); } bool CreateShadersSubmenu(HMENU menu) { @@ -198,7 +203,7 @@ namespace MainWindow { continue; int checkedStatus = MF_UNCHECKED; availableShaders.push_back(i->section); - if (g_Config.sPostShaderName == i->section) { + if (g_Config.vPostShaderNames[0] == i->section && (g_Config.vPostShaderNames[0] == "Off" || g_Config.vPostShaderNames[1] == "Off")) { checkedStatus = MF_CHECKED; } @@ -241,6 +246,7 @@ namespace MainWindow { TranslateMenuItem(menu, ID_FILE_LOAD); TranslateMenuItem(menu, ID_FILE_LOAD_DIR); TranslateMenuItem(menu, ID_FILE_LOAD_MEMSTICK); + TranslateMenuItem(menu, ID_FILE_OPEN_NEW_INSTANCE); TranslateMenuItem(menu, ID_FILE_MEMSTICK); TranslateMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, useDefHotkey(VIRTKEY_NEXT_SLOT) ? L"\tF3" : L""); TranslateMenuItem(menu, ID_FILE_QUICKLOADSTATE, useDefHotkey(VIRTKEY_LOAD_STATE) ? L"\tF4" : L""); @@ -323,7 +329,6 @@ namespace MainWindow { TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_AUTO); TranslateMenuItem(menu, ID_OPTIONS_NEARESTFILTERING); TranslateMenuItem(menu, ID_OPTIONS_LINEARFILTERING); - TranslateMenuItem(menu, ID_OPTIONS_LINEARFILTERING_CG); TranslateMenuItem(menu, ID_OPTIONS_SCREENFILTER_MENU); TranslateMenuItem(menu, ID_OPTIONS_BUFLINEARFILTER); TranslateMenuItem(menu, ID_OPTIONS_BUFNEARESTFILTER); @@ -410,14 +415,14 @@ namespace MainWindow { } void BrowseBackground() { - static std::wstring filter = L"All supported images (*.jpg *.png)|*.jpg;*.png|All files (*.*)|*.*||"; + static std::wstring filter = L"All supported images (*.jpg *.jpeg *.png)|*.jpg;*.jpeg;*.png|All files (*.*)|*.*||"; for (size_t i = 0; i < filter.length(); i++) { if (filter[i] == '|') filter[i] = '\0'; } W32Util::MakeTopMost(GetHWND(), false); - browseImageDialog = new W32Util::AsyncBrowseDialog(W32Util::AsyncBrowseDialog::OPEN, GetHWND(), WM_USER_BROWSE_BG_DONE, L"LoadFile", L"", filter, L"*.jpg;*.png;"); + browseImageDialog = new W32Util::AsyncBrowseDialog(W32Util::AsyncBrowseDialog::OPEN, GetHWND(), WM_USER_BROWSE_BG_DONE, L"LoadFile", L"", filter, L"*.jpg;*.jpeg;*.png;"); } void BrowseBackgroundDone() { @@ -425,7 +430,7 @@ namespace MainWindow { if (browseImageDialog->GetResult(filename)) { std::wstring src = ConvertUTF8ToWString(filename); std::wstring dest; - if (filename.size() >= 4 && filename.substr(filename.size() - 4) == ".jpg") { + if (filename.size() >= 5 && (filename.substr(filename.size() - 4) == ".jpg" || filename.substr(filename.size() - 5) == ".jpeg")) { dest = ConvertUTF8ToWString(GetSysDirectory(DIRECTORY_SYSTEM) + "background.jpg"); } else { dest = ConvertUTF8ToWString(GetSysDirectory(DIRECTORY_SYSTEM) + "background.png"); @@ -584,6 +589,10 @@ namespace MainWindow { BrowseAndBoot(GetSysDirectory(DIRECTORY_GAME)); break; + case ID_FILE_OPEN_NEW_INSTANCE: + W32Util::SpawnNewInstance(false); + break; + case ID_FILE_MEMSTICK: ShellExecute(NULL, L"open", ConvertUTF8ToWString(g_Config.memStickDirectory).c_str(), 0, 0, SW_SHOW); break; @@ -593,16 +602,16 @@ namespace MainWindow { // Causes hang //NativeMessageReceived("run", ""); - if (disasmWindow[0]) - SendMessage(disasmWindow[0]->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); + if (disasmWindow) + SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); } else if (Core_IsStepping()) { // It is paused, then continue to run. - if (disasmWindow[0]) - SendMessage(disasmWindow[0]->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); + if (disasmWindow) + SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); else Core_EnableStepping(false); } else { - if (disasmWindow[0]) - SendMessage(disasmWindow[0]->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); + if (disasmWindow) + SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); else Core_EnableStepping(true); } @@ -862,11 +871,11 @@ namespace MainWindow { if (W32Util::BrowseForFileName(true, hWnd, L"Load .ppmap", 0, L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) { g_symbolMap->LoadSymbolMap(fn.c_str()); - if (disasmWindow[0]) - disasmWindow[0]->NotifyMapLoaded(); + if (disasmWindow) + disasmWindow->NotifyMapLoaded(); - if (memoryWindow[0]) - memoryWindow[0]->NotifyMapLoaded(); + if (memoryWindow) + memoryWindow->NotifyMapLoaded(); } break; @@ -879,11 +888,11 @@ namespace MainWindow { if (W32Util::BrowseForFileName(true, hWnd, L"Load .sym", 0, L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) { g_symbolMap->LoadNocashSym(fn.c_str()); - if (disasmWindow[0]) - disasmWindow[0]->NotifyMapLoaded(); + if (disasmWindow) + disasmWindow->NotifyMapLoaded(); - if (memoryWindow[0]) - memoryWindow[0]->NotifyMapLoaded(); + if (memoryWindow) + memoryWindow->NotifyMapLoaded(); } break; @@ -895,18 +904,16 @@ namespace MainWindow { case ID_DEBUG_RESETSYMBOLTABLE: g_symbolMap->Clear(); - for (int i = 0; i < numCPUs; i++) - if (disasmWindow[i]) - disasmWindow[i]->NotifyMapLoaded(); + if (disasmWindow) + disasmWindow->NotifyMapLoaded(); - for (int i = 0; i < numCPUs; i++) - if (memoryWindow[i]) - memoryWindow[i]->NotifyMapLoaded(); + if (memoryWindow) + memoryWindow->NotifyMapLoaded(); break; case ID_DEBUG_DISASSEMBLY: - if (disasmWindow[0]) - disasmWindow[0]->Show(true); + if (disasmWindow) + disasmWindow->Show(true); break; case ID_DEBUG_GEDEBUGGER: @@ -917,8 +924,8 @@ namespace MainWindow { break; case ID_DEBUG_MEMORYVIEW: - if (memoryWindow[0]) - memoryWindow[0]->Show(true); + if (memoryWindow) + memoryWindow->Show(true); break; case ID_DEBUG_EXTRACTFILE: @@ -944,7 +951,7 @@ namespace MainWindow { u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ, ""); // Note: len may be in blocks. size_t len = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END); - bool isBlockMode = pspFileSystem.DevType(handle) == PSP_DEV_TYPE_BLOCK; + bool isBlockMode = pspFileSystem.DevType(handle) & PSPDevType::BLOCK; FILE *fp = File::OpenCFile(fn, "wb"); pspFileSystem.SeekFile(handle, 0, FILEMOVE_BEGIN); @@ -987,9 +994,8 @@ namespace MainWindow { break; case ID_OPTIONS_TEXTUREFILTERING_AUTO: setTexFiltering(TEX_FILTER_AUTO); break; - case ID_OPTIONS_NEARESTFILTERING: setTexFiltering(TEX_FILTER_NEAREST); break; - case ID_OPTIONS_LINEARFILTERING: setTexFiltering(TEX_FILTER_LINEAR); break; - case ID_OPTIONS_LINEARFILTERING_CG: setTexFiltering(TEX_FILTER_LINEAR_VIDEO); break; + case ID_OPTIONS_NEARESTFILTERING: setTexFiltering(TEX_FILTER_FORCE_NEAREST); break; + case ID_OPTIONS_LINEARFILTERING: setTexFiltering(TEX_FILTER_FORCE_LINEAR); break; case ID_OPTIONS_BUFLINEARFILTER: setBufFilter(SCALE_LINEAR); break; case ID_OPTIONS_BUFNEARESTFILTER: setBufFilter(SCALE_NEAREST); break; @@ -1073,8 +1079,12 @@ namespace MainWindow { // ID_SHADERS_BASE and an additional 1 off it. u32 index = (wParam - ID_SHADERS_BASE - 1); if (index < availableShaders.size()) { - g_Config.sPostShaderName = availableShaders[index]; - + g_Config.vPostShaderNames.clear(); + if (availableShaders[index] != "Off") + g_Config.vPostShaderNames.push_back(availableShaders[index]); + g_Config.vPostShaderNames.push_back("Off"); + g_ShaderNameListChanged = true; + g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); NativeMessageReceived("gpu_resized", ""); break; } @@ -1233,12 +1243,11 @@ namespace MainWindow { ID_OPTIONS_TEXTUREFILTERING_AUTO, ID_OPTIONS_NEARESTFILTERING, ID_OPTIONS_LINEARFILTERING, - ID_OPTIONS_LINEARFILTERING_CG, }; if (g_Config.iTexFiltering < TEX_FILTER_AUTO) g_Config.iTexFiltering = TEX_FILTER_AUTO; - else if (g_Config.iTexFiltering > TEX_FILTER_LINEAR_VIDEO) - g_Config.iTexFiltering = TEX_FILTER_LINEAR_VIDEO; + else if (g_Config.iTexFiltering > TEX_FILTER_FORCE_LINEAR) + g_Config.iTexFiltering = TEX_FILTER_FORCE_LINEAR; for (int i = 0; i < ARRAY_SIZE(texfilteringitems); i++) { CheckMenuItem(menu, texfilteringitems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iTexFiltering ? MF_CHECKED : MF_UNCHECKED)); @@ -1374,7 +1383,7 @@ namespace MainWindow { void UpdateCommands() { static GlobalUIState lastGlobalUIState = UISTATE_PAUSEMENU; - static CoreState lastCoreState = CORE_ERROR; + static CoreState lastCoreState = CORE_BOOT_ERROR; HMENU menu = GetMenu(GetHWND()); EnableMenuItem(menu, ID_DEBUG_LOG, !g_Config.bEnableLogging); diff --git a/Windows/MainWindowMenu.h b/Windows/MainWindowMenu.h index 673681a292..26bdfc608e 100644 --- a/Windows/MainWindowMenu.h +++ b/Windows/MainWindowMenu.h @@ -1,7 +1,6 @@ #pragma once #include "Common/CommonWindows.h" -#include "Common/KeyMap.h" #include namespace MainWindow { diff --git a/Windows/PPSSPP.sln b/Windows/PPSSPP.sln index daf8a56189..ee3d5e3512 100644 --- a/Windows/PPSSPP.sln +++ b/Windows/PPSSPP.sln @@ -8,7 +8,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPPWindows", "PPSSPP.vcx {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} = {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} {533F1D30-D04D-47CC-AD71-20F658907E36} = {533F1D30-D04D-47CC-AD71-20F658907E36} {F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34} - {C4DF647E-80EA-4111-A0A8-218B1B711E18} = {C4DF647E-80EA-4111-A0A8-218B1B711E18} {3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE} = {3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE} {457F45D2-556F-47BC-A31D-AFF0D15BEAED} = {457F45D2-556F-47BC-A31D-AFF0D15BEAED} {3FCDBAE2-5103-4350-9A8E-848CE9C73195} = {3FCDBAE2-5103-4350-9A8E-848CE9C73195} @@ -16,7 +15,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPPWindows", "PPSSPP.vcx EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\Common\Common.vcxproj", "{3FCDBAE2-5103-4350-9A8E-848CE9C73195}" ProjectSection(ProjectDependencies) = postProject - {C4DF647E-80EA-4111-A0A8-218B1B711E18} = {C4DF647E-80EA-4111-A0A8-218B1B711E18} + {F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\ext\zlib\zlib.vcxproj", "{F761046E-6C38-4428-A5F1-38391A37BB34}" @@ -31,17 +30,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "..\Core\Core.vcxpro ProjectSection(ProjectDependencies) = postProject {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} = {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} {F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34} - {C4DF647E-80EA-4111-A0A8-218B1B711E18} = {C4DF647E-80EA-4111-A0A8-218B1B711E18} {457F45D2-556F-47BC-A31D-AFF0D15BEAED} = {457F45D2-556F-47BC-A31D-AFF0D15BEAED} {3FCDBAE2-5103-4350-9A8E-848CE9C73195} = {3FCDBAE2-5103-4350-9A8E-848CE9C73195} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "native", "..\ext\native\native.vcxproj", "{C4DF647E-80EA-4111-A0A8-218B1B711E18}" - ProjectSection(ProjectDependencies) = postProject - {F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34} - {EDFA2E87-8AC1-4853-95D4-D7594FF81947} = {EDFA2E87-8AC1-4853-95D4-D7594FF81947} - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPPHeadless", "..\headless\Headless.vcxproj", "{EE9BD869-CAA3-447D-8328-294D90DE2C1F}" ProjectSection(ProjectDependencies) = postProject {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} = {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} @@ -60,13 +52,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTest", "..\unittest\Uni {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} = {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} {533F1D30-D04D-47CC-AD71-20F658907E36} = {533F1D30-D04D-47CC-AD71-20F658907E36} {F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34} - {C4DF647E-80EA-4111-A0A8-218B1B711E18} = {C4DF647E-80EA-4111-A0A8-218B1B711E18} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UI", "..\UI\UI.vcxproj", "{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}" ProjectSection(ProjectDependencies) = postProject {533F1D30-D04D-47CC-AD71-20F658907E36} = {533F1D30-D04D-47CC-AD71-20F658907E36} - {C4DF647E-80EA-4111-A0A8-218B1B711E18} = {C4DF647E-80EA-4111-A0A8-218B1B711E18} {457F45D2-556F-47BC-A31D-AFF0D15BEAED} = {457F45D2-556F-47BC-A31D-AFF0D15BEAED} {3FCDBAE2-5103-4350-9A8E-848CE9C73195} = {3FCDBAE2-5103-4350-9A8E-848CE9C73195} EndProjectSection @@ -83,6 +73,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtlasTool", "..\ext\native\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZimTool", "..\ext\native\tools\ZimTool\ZimTool.vcxproj", "{B7DED405-40A2-48F8-9382-538F10D442F1}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "..\ext\miniupnpc.vcxproj", "{D8A71225-178B-424E-96C1-CC3BE2C1B047}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -175,22 +167,6 @@ Global {533F1D30-D04D-47CC-AD71-20F658907E36}.Release|Win32.Build.0 = Release|Win32 {533F1D30-D04D-47CC-AD71-20F658907E36}.Release|x64.ActiveCfg = Release|x64 {533F1D30-D04D-47CC-AD71-20F658907E36}.Release|x64.Build.0 = Release|x64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|ARM.ActiveCfg = Debug|ARM - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|ARM.Build.0 = Debug|ARM - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|ARM64.Build.0 = Debug|ARM64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|Win32.ActiveCfg = Debug|Win32 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|Win32.Build.0 = Debug|Win32 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|x64.ActiveCfg = Debug|x64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|x64.Build.0 = Debug|x64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|ARM.ActiveCfg = Release|ARM - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|ARM.Build.0 = Release|ARM - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|ARM64.ActiveCfg = Release|ARM64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|ARM64.Build.0 = Release|ARM64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|Win32.ActiveCfg = Release|Win32 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|Win32.Build.0 = Release|Win32 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|x64.ActiveCfg = Release|x64 - {C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|x64.Build.0 = Release|x64 {EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug|ARM.ActiveCfg = Debug|ARM {EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug|ARM.Build.0 = Debug|ARM {EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -337,6 +313,18 @@ Global {B7DED405-40A2-48F8-9382-538F10D442F1}.Release|Win32.ActiveCfg = Release|x64 {B7DED405-40A2-48F8-9382-538F10D442F1}.Release|x64.ActiveCfg = Release|x64 {B7DED405-40A2-48F8-9382-538F10D442F1}.Release|x64.Build.0 = Release|x64 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Debug|ARM.ActiveCfg = Debug|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Debug|ARM64.ActiveCfg = Debug|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Debug|Win32.ActiveCfg = Debug|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Debug|Win32.Build.0 = Debug|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Debug|x64.ActiveCfg = Debug|x64 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Debug|x64.Build.0 = Debug|x64 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Release|ARM.ActiveCfg = Release|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Release|ARM64.ActiveCfg = Release|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Release|Win32.ActiveCfg = Release|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Release|Win32.Build.0 = Release|Win32 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Release|x64.ActiveCfg = Release|x64 + {D8A71225-178B-424E-96C1-CC3BE2C1B047}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 56ab76c30e..55a21f5a1d 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -119,7 +119,6 @@ Application Unicode $(DefaultPlatformToolset) - Spectre true @@ -238,7 +237,7 @@ Use Level3 ProgramDatabase - ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h;Common/DbgNew.h MultiThreadedDebug StreamingSIMDExtensions2 @@ -261,7 +260,7 @@ /ignore:4049 /ignore:4217 %(AdditionalOptions) - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -276,7 +275,7 @@ Use Level3 ProgramDatabase - ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h;Common/DbgNew.h MultiThreadedDebug false @@ -298,7 +297,7 @@ Windows - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -311,7 +310,7 @@ Use Level3 ProgramDatabase - ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h;Common/DbgNew.h MultiThreadedDebug false @@ -333,7 +332,7 @@ Windows - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -345,11 +344,10 @@ Use Level3 ProgramDatabase - ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h MultiThreadedDebug false - NotSet Precise true false @@ -367,7 +365,7 @@ Windows - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -386,7 +384,7 @@ Use Level3 ProgramDatabase - ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h stdafx.h true @@ -409,7 +407,7 @@ true - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -435,7 +433,7 @@ Use Level3 ProgramDatabase - ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h true false @@ -453,7 +451,7 @@ true - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -477,7 +475,7 @@ Use Level3 ProgramDatabase - ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h true false @@ -494,7 +492,7 @@ true - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -513,12 +511,11 @@ Sync MultiThreaded false - NotSet Precise Use Level3 ProgramDatabase - ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/glew;../ext/zlib stdafx.h true false @@ -535,7 +532,7 @@ true - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd PPSSPPWindows Updating git-version.cpp @@ -603,7 +600,7 @@ true true - + true true true @@ -613,7 +610,7 @@ true true - + true true true @@ -654,6 +651,76 @@ true true + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true true @@ -674,6 +741,116 @@ true true + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true true @@ -684,6 +861,16 @@ true true + + true + true + true + true + true + true + true + true + @@ -829,10 +1016,19 @@ true true - + + true + true + true + true + true + true + true + true + - + true true true @@ -842,7 +1038,7 @@ true true - + true true true @@ -853,9 +1049,197 @@ true - + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + - + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true true @@ -866,6 +1250,136 @@ true true + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true true @@ -876,6 +1390,26 @@ true true + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + @@ -955,26 +1489,174 @@ + + + + + + + + - - - + + + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + + + + + + + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + @@ -1007,9 +1689,6 @@ {457f45d2-556f-47bc-a31d-aff0d15beaed} - - {C4DF647E-80EA-4111-A0A8-218B1B711E18} - {f761046e-6c38-4428-a5f1-38391a37bb34} @@ -1023,6 +1702,10 @@ + + + + @@ -1031,4 +1714,4 @@ - + \ No newline at end of file diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index cbc6580847..ffbdc51429 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -35,6 +35,24 @@ {1d0cc0ee-fdbd-419e-b322-b35075d9d9db} + + {5bfed059-8636-4b1e-a3cf-f948d645babb} + + + {950b34a4-d66c-4e7a-aada-e364887cb614} + + + {edf0716f-a255-4061-ad58-702e4b51b0ce} + + + {30a32908-a72f-4728-a721-1f44e700bcea} + + + {68db42ae-cf1b-42cd-b17a-c3e99211a7d8} + + + {21c262bc-bc21-49d7-a332-2e2614e89217} + @@ -154,37 +172,15 @@ Windows\System - Other Platforms\Qt Windows\System - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - Other Platforms\Qt - - Other Platforms - Windows\System @@ -194,6 +190,87 @@ Windows\Input + + Windows\System + + + Other Platforms\Android + + + Other Platforms\Android + + + Other Platforms\Android + + + Other Platforms\Android + + + Other Platforms\iOS + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\Qt + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\Android + + + Other Platforms\Android + @@ -289,9 +366,6 @@ Windows\Debugger - - Other Platforms - Windows\Input @@ -316,40 +390,15 @@ Windows\System - Other Platforms\Qt Windows\System - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - Other Platforms\Qt - - Other Platforms - Windows\System @@ -363,6 +412,132 @@ Windows\Input + + Windows\System + + + Other Platforms\Android + + + Other Platforms\Android + + + Other Platforms\Android + + + Other Platforms\Android + + + Other Platforms\Android + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\Qt + + + Other Platforms\Qt + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\UWP + + + Other Platforms\Android + + + Other Platforms\Android + @@ -371,50 +546,23 @@ Resource Files - - Other Platforms - Resource Files - - Other Platforms - - - Windows - - - Resource Files Resource Files - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - - - Other Platforms - Resource Files Resource Files - Other Platforms\Qt @@ -439,6 +587,130 @@ Other Platforms\Qt + + Resource Files + + + Resource Files + + + Resource Files + + + Other Platforms\Android + + + Build + + + Build + + + Build + + + Build + + + Build + + + Build + + + Build + + + Build + + + Build + + + Build + + + Build + + + + Build + + + Build + + + Other Platforms\Android + + + Other Platforms\iOS + + + Other Platforms\Android + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Build + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Build + + + Other Platforms\iOS + + + Other Platforms\iOS + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\libretro + + + Other Platforms\Qt + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + + + Other Platforms\SDL + @@ -450,4 +722,12 @@ Resource Files - + + + Build + + + Other Platforms\libretro + + + \ No newline at end of file diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index 36d639a4ba..c23efbcf88 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -19,14 +19,15 @@ #include #include -#include "base/NativeApp.h" -#include "base/display.h" -#include "input/input_state.h" +#include "Common/System/NativeApp.h" +#include "Common/System/Display.h" +#include "Common/Input/InputState.h" #include "Common/Log.h" #include "Windows/RawInput.h" #include "Windows/MainWindow.h" #include "Windows/WindowsHost.h" #include "Common/CommonFuncs.h" +#include "Common/SysError.h" #include "Core/Config.h" #ifndef HID_USAGE_PAGE_GENERIC @@ -194,7 +195,7 @@ namespace WindowsRawInput { dev[2].dwFlags = 0; if (!RegisterRawInputDevices(dev, 3, sizeof(RAWINPUTDEVICE))) { - WARN_LOG(SYSTEM, "Unable to register raw input devices: %s", GetLastErrorMsg()); + WARN_LOG(SYSTEM, "Unable to register raw input devices: %s", GetLastErrorMsg().c_str()); } } @@ -283,7 +284,7 @@ namespace WindowsRawInput { LRESULT ProcessChar(HWND hWnd, WPARAM wParam, LPARAM lParam) { KeyInput key; - key.keyCode = wParam; // Note that this is NOT a NKCODE but a Unicode character! + key.keyCode = (int)wParam; // Note that this is NOT a NKCODE but a Unicode character! key.flags = KEY_CHAR; key.deviceId = DEVICE_ID_KEYBOARD; NativeKey(key); diff --git a/Windows/TouchInputHandler.cpp b/Windows/TouchInputHandler.cpp index b4f4bd38c7..f216e8ac80 100644 --- a/Windows/TouchInputHandler.cpp +++ b/Windows/TouchInputHandler.cpp @@ -4,11 +4,14 @@ #include -#include "base/display.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" + #include "Common/CommonWindows.h" #include "Common/CommonFuncs.h" +#include "Common/Input/InputState.h" #include "Common/Log.h" -#include "base/NativeApp.h" +#include "Common/SysError.h" #include "Windows/MainWindow.h" TouchInputHandler::TouchInputHandler() { @@ -95,7 +98,7 @@ void TouchInputHandler::handleTouchEvent(HWND hWnd, UINT message, WPARAM wParam, } closeTouch(touchInputData); } else { - WARN_LOG(SYSTEM, "Failed to read input data: %s", GetLastErrorMsg()); + WARN_LOG(SYSTEM, "Failed to read input data: %s", GetLastErrorMsg().c_str()); } delete [] inputs; } diff --git a/Windows/W32Util/DialogManager.cpp b/Windows/W32Util/DialogManager.cpp index b40563bc00..fdb89ac600 100644 --- a/Windows/W32Util/DialogManager.cpp +++ b/Windows/W32Util/DialogManager.cpp @@ -8,7 +8,7 @@ Dialog::Dialog(LPCSTR res, HINSTANCE _hInstance, HWND _hParent) { m_hInstance = _hInstance; m_hParent = _hParent; - m_hResource=res; + m_hResource = res; m_bValid = true; Create(); } @@ -32,12 +32,12 @@ void Dialog::Destroy() void Dialog::Show(bool _bShow) { - ShowWindow(m_hDlg, _bShow ? SW_NORMAL : SW_HIDE); + m_bShowState = _bShow ? SW_NORMAL : SW_HIDE; + ShowWindow(m_hDlg, m_bShowState); if (_bShow) BringWindowToTop(m_hDlg); } - INT_PTR Dialog::DlgProcStatic(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { Dialog *dis = (Dialog*)GetWindowLongPtr(hdlg, GWLP_USERDATA); @@ -106,4 +106,4 @@ void DialogManager::DestroyAll() for (iter=dialogs.begin(); iter!=dialogs.end(); iter++) delete (*iter); dialogs.clear(); -} \ No newline at end of file +} diff --git a/Windows/W32Util/DialogManager.h b/Windows/W32Util/DialogManager.h index 7203b04603..f1093deb14 100644 --- a/Windows/W32Util/DialogManager.h +++ b/Windows/W32Util/DialogManager.h @@ -4,32 +4,31 @@ class Dialog { +public: + Dialog(LPCSTR res, HINSTANCE _hInstance, HWND _hParent); + virtual ~Dialog(); + + virtual void Show(bool _bShow); + virtual void Update() {} + + HWND GetDlgHandle() { + return m_hDlg; + } protected: - HINSTANCE m_hInstance; + virtual void Create(); + void Destroy(); + HWND m_hParent; HWND m_hDlg; LPCSTR m_hResource; bool m_bValid; + UINT m_bShowState = SW_HIDE; - virtual BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) - { - MessageBox(0,L"WTF? Pure Call",0,0); - return 0; - } + virtual BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) = 0; static INT_PTR CALLBACK DlgProcStatic(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - virtual void Create(); - void Destroy(); -public: - Dialog(LPCSTR res, HINSTANCE _hInstance, HWND _hParent); - virtual ~Dialog(); - void Show(bool _bShow); - virtual void Update() {} - - HWND GetDlgHandle() - { - return m_hDlg; - } +private: + HINSTANCE m_hInstance; }; @@ -42,4 +41,4 @@ public: static void EnableAll(BOOL enable); static void DestroyAll(); static void UpdateAll(); -}; \ No newline at end of file +}; diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp index 3bb86f6bf6..d646302986 100644 --- a/Windows/W32Util/Misc.cpp +++ b/Windows/W32Util/Misc.cpp @@ -1,4 +1,3 @@ -#include "stdafx.h" #include "ppsspp_config.h" #include "CommonWindows.h" @@ -7,7 +6,7 @@ #include #include "Misc.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" bool KeyDownAsync(int vkey) { #if PPSSPP_PLATFORM(UWP) @@ -154,6 +153,12 @@ namespace W32Util } void ExitAndRestart(bool overrideArgs, const std::string &args) { + SpawnNewInstance(overrideArgs, args); + + ExitProcess(0); + } + + void SpawnNewInstance(bool overrideArgs, const std::string &args) { // This preserves arguments (for example, config file) and working directory. std::wstring workingDirectory; std::wstring moduleFilename; @@ -168,13 +173,9 @@ namespace W32Util cmdline = RemoveExecutableFromCommandLine(GetCommandLineW()); } ShellExecute(nullptr, nullptr, moduleFilename.c_str(), cmdline, workingDirectory.c_str(), SW_SHOW); - - ExitProcess(0); } } - - GenericListControl::GenericListControl(HWND hwnd, const GenericListViewDef& def) : handle(hwnd), columns(def.columns),columnCount(def.columnCount),valid(false), inResizeColumns(false),updating(false) @@ -199,7 +200,7 @@ GenericListControl::GenericListControl(HWND hwnd, const GenericListViewDef& def) int totalListSize = rect.right-rect.left; for (int i = 0; i < columnCount; i++) { - lvc.cx = columns[i].size * totalListSize; + lvc.cx = (int)(columns[i].size * totalListSize); lvc.pszText = (LPTSTR)columns[i].name; if (columns[i].flags & GLVC_CENTERED) diff --git a/Windows/W32Util/Misc.h b/Windows/W32Util/Misc.h index 623de73233..fa447de78d 100644 --- a/Windows/W32Util/Misc.h +++ b/Windows/W32Util/Misc.h @@ -12,6 +12,7 @@ namespace W32Util BOOL CopyTextToClipboard(HWND hwnd, const std::wstring &wtext); void MakeTopMost(HWND hwnd, bool topMost); void ExitAndRestart(bool overrideArgs = false, const std::string &args = ""); + void SpawnNewInstance(bool overrideArgs = false, const std::string &args = ""); void GetSelfExecuteParams(std::wstring &workingDirectory, std::wstring &moduleFilename); } diff --git a/Windows/W32Util/PropertySheet.cpp b/Windows/W32Util/PropertySheet.cpp index 0ca68dcedd..be56607b5f 100644 --- a/Windows/W32Util/PropertySheet.cpp +++ b/Windows/W32Util/PropertySheet.cpp @@ -1,7 +1,7 @@ -#include "stdafx.h" +#include "Windows/stdafx.h" #include "Misc.h" #include "PropertySheet.h" -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include @@ -184,4 +184,4 @@ namespace W32Util } return 0; } -} \ No newline at end of file +} diff --git a/Windows/W32Util/ShellUtil.cpp b/Windows/W32Util/ShellUtil.cpp index 39938b3fc0..c6d3a2bc49 100644 --- a/Windows/W32Util/ShellUtil.cpp +++ b/Windows/W32Util/ShellUtil.cpp @@ -2,12 +2,12 @@ #pragma warning(disable:4091) // workaround bug in VS2015 headers -#include "stdafx.h" +#include "Windows/stdafx.h" #include #include -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" #include "ShellUtil.h" #include diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp index 3b04029bf8..9e11d558c5 100644 --- a/Windows/WASAPIStream.cpp +++ b/Windows/WASAPIStream.cpp @@ -1,10 +1,12 @@ +#include "stdafx.h" + #include "WindowsAudio.h" #include "WASAPIStream.h" #include "Common/Log.h" #include "Core/Reporting.h" #include "Core/Util/AudioFormat.h" -#include "thread/threadutil.h" +#include "Common/Thread/ThreadUtil.h" #include #include @@ -35,8 +37,7 @@ public: } ~CMMNotificationClient() { - if (currentDevice_) - CoTaskMemFree(currentDevice_); + CoTaskMemFree(currentDevice_); currentDevice_ = nullptr; SAFE_RELEASE(_pEnumerator) } @@ -44,8 +45,8 @@ public: void SetCurrentDevice(IMMDevice *device) { std::lock_guard guard(lock_); - if (currentDevice_) - CoTaskMemFree(currentDevice_); + CoTaskMemFree(currentDevice_); + currentDevice_ = nullptr; if (!device || FAILED(device->GetId(¤tDevice_))) { currentDevice_ = nullptr; } @@ -196,6 +197,8 @@ private: bool InitAudioDevice(); void ShutdownAudioDevice(); bool DetectFormat(); + bool ValidateFormat(const WAVEFORMATEXTENSIBLE *fmt); + bool PrepareFormat(); std::atomic &threadData_; int &sampleRate_; @@ -232,12 +235,12 @@ WASAPIAudioThread::~WASAPIAudioThread() { } bool WASAPIAudioThread::ActivateDefaultDevice() { - assert(device_ == nullptr); + _assert_(device_ == nullptr); HRESULT hresult = deviceEnumerator_->GetDefaultAudioEndpoint(eRender, eMultimedia, &device_); if (FAILED(hresult) || device_ == nullptr) return false; - assert(audioInterface_ == nullptr); + _assert_(audioInterface_ == nullptr); hresult = device_->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&audioInterface_); if (FAILED(hresult) || audioInterface_ == nullptr) return false; @@ -247,15 +250,20 @@ bool WASAPIAudioThread::ActivateDefaultDevice() { bool WASAPIAudioThread::InitAudioDevice() { REFERENCE_TIME hnsBufferDuration = REFTIMES_PER_SEC; - assert(deviceFormat_ == nullptr); + _assert_(deviceFormat_ == nullptr); HRESULT hresult = audioInterface_->GetMixFormat((WAVEFORMATEX **)&deviceFormat_); if (FAILED(hresult) || !deviceFormat_) return false; + if (!DetectFormat()) { + // Format unsupported - let's not even try to initialize. + return false; + } + hresult = audioInterface_->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsBufferDuration, 0, &deviceFormat_->Format, nullptr); if (FAILED(hresult)) return false; - assert(renderClient_ == nullptr); + _assert_(renderClient_ == nullptr); hresult = audioInterface_->GetService(IID_IAudioRenderClient, (void **)&renderClient_); if (FAILED(hresult) || !renderClient_) return false; @@ -279,33 +287,84 @@ void WASAPIAudioThread::ShutdownAudioDevice() { } bool WASAPIAudioThread::DetectFormat() { + if (!ValidateFormat(deviceFormat_)) { + // Last chance, let's try to ask for one we support instead. + WAVEFORMATEXTENSIBLE fmt{}; + fmt.Format.cbSize = sizeof(fmt); + fmt.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + fmt.Format.nChannels = 2; + fmt.Format.nSamplesPerSec = 44100; + if (deviceFormat_->Format.nSamplesPerSec >= 22050 && deviceFormat_->Format.nSamplesPerSec <= 192000) + fmt.Format.nSamplesPerSec = deviceFormat_->Format.nSamplesPerSec; + fmt.Format.nBlockAlign = 2 * sizeof(float); + fmt.Format.nAvgBytesPerSec = fmt.Format.nSamplesPerSec * fmt.Format.nBlockAlign; + fmt.Format.wBitsPerSample = sizeof(float) * 8; + fmt.Samples.wReserved = 0; + fmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + fmt.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + + WAVEFORMATEXTENSIBLE *closest = nullptr; + HRESULT hr = audioInterface_->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &fmt.Format, (WAVEFORMATEX **)&closest); + if (hr == S_OK) { + // Okay, great. Let's just use ours. + CoTaskMemFree(closest); + CoTaskMemFree(deviceFormat_); + deviceFormat_ = (WAVEFORMATEXTENSIBLE *)CoTaskMemAlloc(sizeof(fmt)); + memcpy(deviceFormat_, &fmt, sizeof(fmt)); + + // In case something above gets out of date. + return ValidateFormat(deviceFormat_); + } else if (hr == S_FALSE && closest != nullptr) { + // This means check closest. We'll allow it only if it's less specific on channels. + if (ValidateFormat(closest)) { + CoTaskMemFree(deviceFormat_); + deviceFormat_ = closest; + } else { + ERROR_LOG_REPORT_ONCE(badfallbackclosest, SCEAUDIO, "WASAPI fallback and closest unsupported"); + CoTaskMemFree(closest); + return false; + } + } else { + CoTaskMemFree(closest); + ERROR_LOG_REPORT_ONCE(badfallback, SCEAUDIO, "WASAPI fallback format was unsupported"); + return false; + } + } + + return true; +} + +bool WASAPIAudioThread::ValidateFormat(const WAVEFORMATEXTENSIBLE *fmt) { // Don't know if PCM16 ever shows up here, the documentation only talks about float... but let's blindly // try to support it :P format_ = Format::UNKNOWN; - if (deviceFormat_->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - if (!memcmp(&deviceFormat_->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(deviceFormat_->SubFormat))) { - format_ = Format::IEEE_FLOAT; + if (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + if (!memcmp(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(fmt->SubFormat))) { + if (fmt->Format.nChannels >= 2) + format_ = Format::IEEE_FLOAT; } else { ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format, expected float!"); - if (deviceFormat_->Format.wBitsPerSample == 16 && deviceFormat_->Format.nChannels == 2) { + if (fmt->Format.wBitsPerSample == 16 && fmt->Format.nChannels == 2) { format_ = Format::PCM16; } } - } else if (deviceFormat_->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { - format_ = Format::IEEE_FLOAT; + } else if (fmt->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { + if (fmt->Format.nChannels >= 2) + format_ = Format::IEEE_FLOAT; } else { ERROR_LOG_REPORT_ONCE(unexpectedformat2, SCEAUDIO, "Got unexpected non-extensible WASAPI stream format, expected extensible float!"); - if (deviceFormat_->Format.wBitsPerSample == 16 && deviceFormat_->Format.nChannels == 2) { + if (fmt->Format.wBitsPerSample == 16 && fmt->Format.nChannels == 2) { format_ = Format::PCM16; } } + return format_ != Format::UNKNOWN; +} + +bool WASAPIAudioThread::PrepareFormat() { delete [] shortBuf_; shortBuf_ = nullptr; - if (format_ == Format::UNKNOWN) { - return false; - } BYTE *pData = nullptr; HRESULT hresult = renderClient_->GetBuffer(numBufferFrames, &pData); @@ -331,7 +390,7 @@ bool WASAPIAudioThread::DetectFormat() { void WASAPIAudioThread::Run() { // Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/dd316756(v=vs.85).aspx - assert(deviceEnumerator_ == nullptr); + _assert_(deviceEnumerator_ == nullptr); HRESULT hresult = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, /* Object is not created as the part of the aggregate */ CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&deviceEnumerator_); @@ -356,7 +415,7 @@ void WASAPIAudioThread::Run() { ERROR_LOG(SCEAUDIO, "WASAPI: Could not init audio device"); return; } - if (!DetectFormat()) { + if (!PrepareFormat()) { ERROR_LOG(SCEAUDIO, "WASAPI: Could not find a suitable audio output format"); return; } @@ -384,14 +443,14 @@ void WASAPIAudioThread::Run() { if (FAILED(hresult) || pData == nullptr) { // What to do? } else if (pNumAvFrames) { + int chans = deviceFormat_->Format.nChannels; switch (format_) { case Format::IEEE_FLOAT: - callback_(shortBuf_, pNumAvFrames, 16, sampleRate_, 2); - if (deviceFormat_->Format.nChannels == 2) { - ConvertS16ToF32((float *)pData, shortBuf_, pNumAvFrames * deviceFormat_->Format.nChannels); - } else { + callback_(shortBuf_, pNumAvFrames, 16, sampleRate_, chans); + if (chans == 2) { + ConvertS16ToF32((float *)pData, shortBuf_, pNumAvFrames * chans); + } else if (chans > 2) { float *ptr = (float *)pData; - int chans = deviceFormat_->Format.nChannels; memset(ptr, 0, pNumAvFrames * chans * sizeof(float)); for (UINT32 i = 0; i < pNumAvFrames; i++) { ptr[i * chans + 0] = (float)shortBuf_[i * 2] * (1.0f / 32768.0f); @@ -400,7 +459,7 @@ void WASAPIAudioThread::Run() { } break; case Format::PCM16: - callback_((short *)pData, pNumAvFrames, 16, sampleRate_, 2); + callback_((short *)pData, pNumAvFrames, 16, sampleRate_, chans); break; } } @@ -430,7 +489,7 @@ void WASAPIAudioThread::Run() { ERROR_LOG(SCEAUDIO, "WASAPI: Could not init audio device"); return; } - if (!DetectFormat()) { + if (!PrepareFormat()) { ERROR_LOG(SCEAUDIO, "WASAPI: Could not find a suitable audio output format"); return; } diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 84d09875bd..210344033f 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -32,20 +32,22 @@ #pragma warning(pop) // native stuff -#include "base/display.h" -#include "base/NativeApp.h" -#include "file/file_util.h" -#include "input/input_state.h" -#include "input/keycodes.h" -#include "util/text/utf8.h" - +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/File/DirListing.h" #include "Common/StringUtils.h" + #include "Core/Core.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/CoreParameter.h" #include "Core/System.h" #include "Core/Debugger/SymbolMap.h" +#include "Core/Instance.h" + #include "Windows/EmuThread.h" #include "Windows/WindowsAudio.h" #include "Windows/WindowsHost.h" @@ -70,8 +72,6 @@ #include "Windows/main.h" #include "UI/OnScreenDisplay.h" -static const int numCPUs = 1; - float g_mouseDeltaX = 0; float g_mouseDeltaY = 0; @@ -101,8 +101,9 @@ WindowsHost::WindowsHost(HINSTANCE hInstance, HWND mainWindow, HWND displayWindo void WindowsHost::SetConsolePosition() { HWND console = GetConsoleWindow(); - if (console != NULL && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) + if (console != NULL && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) { SetWindowPos(console, NULL, g_Config.iConsoleWindowX, g_Config.iConsoleWindowY, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } } void WindowsHost::UpdateConsolePosition() { @@ -167,6 +168,7 @@ void WindowsHost::SetWindowTitle(const char *message) { #ifdef _DEBUG winTitle.append(L" (debug)"); #endif + lastTitle_ = winTitle; MainWindow::SetWindowTitle(winTitle.c_str()); PostMessage(mainWindow_, MainWindow::WM_USER_WINDOW_TITLE_CHANGED, 0, 0); @@ -188,24 +190,27 @@ void WindowsHost::ShutdownSound() { void WindowsHost::UpdateUI() { PostMessage(mainWindow_, MainWindow::WM_USER_UPDATE_UI, 0, 0); + + int peers = GetInstancePeerCount(); + if (PPSSPP_ID >= 1 && peers != lastNumInstances_) { + lastNumInstances_ = peers; + PostMessage(mainWindow_, MainWindow::WM_USER_WINDOW_TITLE_CHANGED, 0, 0); + } } void WindowsHost::UpdateMemView() { - for (int i = 0; i < numCPUs; i++) - if (memoryWindow[i]) - PostDialogMessage(memoryWindow[i], WM_DEB_UPDATE); + if (memoryWindow) + PostDialogMessage(memoryWindow, WM_DEB_UPDATE); } void WindowsHost::UpdateDisassembly() { - for (int i = 0; i < numCPUs; i++) - if (disasmWindow[i]) - PostDialogMessage(disasmWindow[i], WM_DEB_UPDATE); + if (disasmWindow) + PostDialogMessage(disasmWindow, WM_DEB_UPDATE); } void WindowsHost::SetDebugMode(bool mode) { - for (int i = 0; i < numCPUs; i++) - if (disasmWindow[i]) - PostDialogMessage(disasmWindow[i], WM_DEB_SETDEBUGLPARAM, 0, (LPARAM)mode); + if (disasmWindow) + PostDialogMessage(disasmWindow, WM_DEB_SETDEBUGLPARAM, 0, (LPARAM)mode); } void WindowsHost::PollControllers() { @@ -280,7 +285,7 @@ static std::string SymbolMapFilename(const char *currentFilename, const char* ex return result + ".ppsspp-symbols" + ext; } else { - size_t dot = result.rfind('.'); + const size_t dot = result.rfind('.'); if (dot == result.npos) return result + ext; @@ -302,6 +307,11 @@ void WindowsHost::SaveSymbolMap() { g_symbolMap->SaveSymbolMap(SymbolMapFilename(PSP_CoreParameter().fileToStart.c_str(),".ppmap").c_str()); } +void WindowsHost::NotifySymbolMapUpdated() { + g_symbolMap->SortSymbols(); + PostMessage(mainWindow_, WM_USER + 1, 0, 0); +} + bool WindowsHost::IsDebuggingEnabled() { #ifdef _DEBUG return true; @@ -360,8 +370,8 @@ bool WindowsHost::CreateDesktopShortcut(std::string argumentPath, std::string ga // Sanitize the game title for banned characters. const char bannedChars[] = "<>:\"/\\|?*"; for (size_t i = 0; i < gameTitle.size(); i++) { - for (size_t c = 0; c < strlen(bannedChars); c++) { - if (gameTitle[i] == bannedChars[c]) { + for (char c : bannedChars) { + if (gameTitle[i] == c) { gameTitle[i] = '_'; break; } diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index 3aadb76dc8..581a8064d3 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -52,6 +52,7 @@ public: void BootDone() override; bool AttemptLoadSymbolMap() override; void SaveSymbolMap() override; + void NotifySymbolMapUpdated() override; void SetWindowTitle(const char *message) override; void ToggleDebugConsoleVisibility() override; @@ -73,6 +74,8 @@ private: HWND mainWindow_; GraphicsContext *gfx_ = nullptr; size_t numDinputDevices_ = 0; + std::wstring lastTitle_; + int lastNumInstances_ = 0; std::list> input; }; diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index 8dee2e71f8..b93c8bf4c7 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -3,17 +3,19 @@ #include #include -#include "base/NativeApp.h" +#include "Common/System/NativeApp.h" #include "Core/Config.h" #include "Common/CommonWindows.h" -#include "Common/KeyMap.h" #include "Common/Log.h" -#include "input/input_state.h" -#include "input/keycodes.h" +#include "Common/TimeUtil.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" #include "XinputDevice.h" #include "Core/Core.h" +#include "Core/KeyMap.h" #include "Core/HLE/sceCtrl.h" -#include "Common/Timer.h" + +static double newVibrationTime = 0.0; // Utilities to dynamically load XInput. Adapted from SDL. @@ -22,12 +24,11 @@ typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState); typedef DWORD (WINAPI *XInputSetState_t) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration); -static XInputGetState_t PPSSPP_XInputGetState = NULL; -static XInputSetState_t PPSSPP_XInputSetState = NULL; +static XInputGetState_t PPSSPP_XInputGetState = nullptr; +static XInputSetState_t PPSSPP_XInputSetState = nullptr; static DWORD PPSSPP_XInputVersion = 0; static HMODULE s_pXInputDLL = 0; static int s_XInputDLLRefCount = 0; -static int newVibrationTime = 0; static void UnloadXInputDLL(); @@ -363,11 +364,11 @@ void XinputDevice::ApplyButtons(int pad, const XINPUT_STATE &state) { void XinputDevice::ApplyVibration(int pad, XINPUT_VIBRATION &vibration) { if (PSP_IsInited()) { - newVibrationTime = Common::Timer::GetTimeMs() >> 6; + newVibrationTime = time_now_d(); // We have to run PPSSPP_XInputSetState at time intervals // since it bugs otherwise with very high unthrottle speeds // and freezes at constant vibration or no vibration at all. - if (abs(newVibrationTime - prevVibrationTime) >= 1) { + if (newVibrationTime - prevVibrationTime >= 1.0 / 64.0) { if (GetUIState() == UISTATE_INGAME) { vibration.wLeftMotorSpeed = sceCtrlGetLeftVibration(); // use any value between 0-65535 here vibration.wRightMotorSpeed = sceCtrlGetRightVibration(); // use any value between 0-65535 here @@ -376,7 +377,7 @@ void XinputDevice::ApplyVibration(int pad, XINPUT_VIBRATION &vibration) { vibration.wRightMotorSpeed = 0; } - if ((prevVibration[pad].wLeftMotorSpeed != vibration.wLeftMotorSpeed || prevVibration[pad].wRightMotorSpeed != vibration.wRightMotorSpeed)) { + if (prevVibration[pad].wLeftMotorSpeed != vibration.wLeftMotorSpeed || prevVibration[pad].wRightMotorSpeed != vibration.wRightMotorSpeed) { PPSSPP_XInputSetState(pad, &vibration); prevVibration[pad] = vibration; } diff --git a/Windows/aboutbox.rc b/Windows/aboutbox.rc index 1e669a134b..43e3b72005 100644 Binary files a/Windows/aboutbox.rc and b/Windows/aboutbox.rc differ diff --git a/Windows/git-version-gen.cmd b/Windows/git-version-gen.cmd index d6305522a4..f7d666f6a6 100644 --- a/Windows/git-version-gen.cmd +++ b/Windows/git-version-gen.cmd @@ -25,45 +25,46 @@ rem // If git is not installed, "unknown" is the version. setlocal ENABLEDELAYEDEXPANSION set GIT_VERSION_FILE=%~p0..\git-version.cpp +set GIT_VERSION_TEMP=%~p0..\git-version-%1%RANDOM%.tmp set WIN_VERSION_FILE=%~p0.\win-version.h +set WIN_VERSION_TEMP=%~p0.\win-version-%1%RANDOM%.tmp set GIT_MISSING=0 if not defined GIT ( set GIT="git" ) -call %GIT% describe --always > NUL 2> NUL -if errorlevel 1 ( - echo Git not on path, trying default Msysgit paths... - set GIT="%ProgramFiles(x86)%\Git\bin\git.exe" - call !GIT! describe > NUL 2> NUL - if errorlevel 1 ( - echo !GIT! - set GIT="%ProgramFiles%\Git\bin\git.exe" - call !GIT! describe > NUL 2> NUL - if errorlevel 1 ( - set GIT="%ProgramW6432%\Git\bin\git.exe" - ) - ) -) +call %GIT% describe --always > "%GIT_VERSION_TEMP%" 2> NUL +if not errorlevel 1 goto gitfound -call %GIT% describe --always > NUL 2> NUL -if errorlevel 1 ( - echo Git not on path, trying GitHub Desktop.. - rem // Cheating using short filenames. - set GIT="%USERPROFILE%\AppData\Local\GitHub\PORTAB~1\bin\git.exe" - call !GIT! describe > NUL 2> NUL - if errorlevel 1 ( - set GIT="%USERPROFILE%\AppData\Local\GitHub\PORTAB~2\bin\git.exe" - ) -) +echo Git not on path, trying default Msysgit paths... +set GIT="%ProgramFiles(x86)%\Git\bin\git.exe" +call %GIT% describe --always > "%GIT_VERSION_TEMP%" 2> NUL +if not errorlevel 1 goto gitfound -call %GIT% describe --always > NUL 2> NUL -if errorlevel 1 ( - set GIT_MISSING=1 -) +set GIT="%ProgramFiles%\Git\bin\git.exe" +call %GIT% describe --always > "%GIT_VERSION_TEMP%" 2> NUL +if not errorlevel 1 goto gitfound +set GIT="%ProgramW6432%\Git\bin\git.exe" +call %GIT% describe --always > "%GIT_VERSION_TEMP%" 2> NUL +if not errorlevel 1 goto gitfound + +echo Git not on path, trying GitHub Desktop.. +rem // Cheating using short filenames. +set GIT="%USERPROFILE%\AppData\Local\GitHub\PORTAB~1\bin\git.exe" +call %GIT% describe --always > "%GIT_VERSION_TEMP%" 2> NUL +if not errorlevel 1 goto gitfound + +set GIT="%USERPROFILE%\AppData\Local\GitHub\PORTAB~2\bin\git.exe" +call %GIT% describe --always > "%GIT_VERSION_TEMP%" 2> NUL +if not errorlevel 1 goto gitfound + +set GIT_MISSING=1 + +:gitfound if not "%GIT_MISSING%" == "1" ( - for /F %%I in ('call %GIT% describe --always') do set GIT_VERSION=%%I + for /F %%I in ('type "%GIT_VERSION_TEMP%"') do set GIT_VERSION=%%I + del "%GIT_VERSION_TEMP%" > NUL 2> NUL ) if exist "%GIT_VERSION_FILE%" ( @@ -78,28 +79,36 @@ if "%GIT_MISSING%" == "1" ( echo WARNING: Unable to update git-version.cpp, git not found. echo If you don't want to add it to your path, set the GIT environment variable. - echo // This is a generated file, by git-version-gen.cmd. > "%GIT_VERSION_FILE%" - echo. >> "%GIT_VERSION_FILE%" - echo // ERROR: Unable to determine version - git not on path. > "%GIT_VERSION_FILE%" - echo const char *PPSSPP_GIT_VERSION = "unknown"; >> "%GIT_VERSION_FILE%" + echo // This is a generated file, by git-version-gen.cmd. > "%GIT_VERSION_TEMP%" + echo. >> "%GIT_VERSION_TEMP%" + echo // ERROR: Unable to determine version - git not on path. > "%GIT_VERSION_TEMP%" + echo const char *PPSSPP_GIT_VERSION = "unknown"; >> "%GIT_VERSION_TEMP%" + + move /y "%GIT_VERSION_TEMP%" "%GIT_VERSION_FILE%" > NUL goto gitdone ) -rem // Don't modify the file if it already has the current version. if exist "%GIT_VERSION_FILE%" ( + rem // Don't modify the file if it already has the current version. findstr /C:"%GIT_VERSION%" "%GIT_VERSION_FILE%" > NUL if not errorlevel 1 ( goto gitdone ) ) -echo // This is a generated file, by git-version-gen.cmd. > "%GIT_VERSION_FILE%" -echo. >> "%GIT_VERSION_FILE%" -echo const char *PPSSPP_GIT_VERSION = "Luna Edition %GIT_VERSION%"; >> "%GIT_VERSION_FILE%" -echo. >> "%GIT_VERSION_FILE%" -echo // If you don't want this file to update/recompile, change to 1. >> "%GIT_VERSION_FILE%" -echo #define PPSSPP_GIT_VERSION_NO_UPDATE 0 >> "%GIT_VERSION_FILE%" +echo // This is a generated file, by git-version-gen.cmd. > "%GIT_VERSION_TEMP%" +echo. >> "%GIT_VERSION_TEMP%" +echo const char *PPSSPP_GIT_VERSION = "Luna Edition %GIT_VERSION%"; >> "%GIT_VERSION_TEMP%" +echo. >> "%GIT_VERSION_TEMP%" +echo // If you don't want this file to update/recompile, change to 1. >> "%GIT_VERSION_TEMP%" +echo #define PPSSPP_GIT_VERSION_NO_UPDATE 0 >> "%GIT_VERSION_TEMP%" +move /y "%GIT_VERSION_TEMP%" "%GIT_VERSION_FILE%" > NUL +if errorlevel 1 ( + rem // Cheap delay tactic. + call %GIT% describe --always > NUL 2> NUL + move /y "%GIT_VERSION_TEMP%" "%GIT_VERSION_FILE%" > NUL +) :gitdone if exist "%WIN_VERSION_FILE%" ( @@ -113,12 +122,13 @@ if exist "%WIN_VERSION_FILE%" ( if "%GIT_MISSING%" == "1" ( echo WARNING: Unable to update Windows/win-version.h, git not found. - echo // This is a generated file, by git-version-gen.cmd. > "%WIN_VERSION_FILE%" - echo. >> "%WIN_VERSION_FILE%" - echo // ERROR: Unable to determine version - git not on path. > "%WIN_VERSION_FILE%" - echo #define PPSSPP_WIN_VERSION_STRING "unknown" > "%WIN_VERSION_FILE%" - echo #define PPSSPP_WIN_VERSION_COMMA 0,0,0,0 > "%WIN_VERSION_FILE%" + echo // This is a generated file, by git-version-gen.cmd. > "%WIN_VERSION_TEMP%" + echo. >> "%WIN_VERSION_TEMP%" + echo // ERROR: Unable to determine version - git not on path. > "%WIN_VERSION_TEMP%" + echo #define PPSSPP_WIN_VERSION_STRING "unknown" > "%WIN_VERSION_TEMP%" + echo #define PPSSPP_WIN_VERSION_COMMA 0,0,0,0 > "%WIN_VERSION_TEMP%" + move /y "%WIN_VERSION_TEMP%" "%WIN_VERSION_FILE%" > NUL goto done ) @@ -143,13 +153,20 @@ if /i "%GIT_VERSION:~0,1%" == "v" ( set WIN_VERSION_COMMA=0,0,0x%GIT_VERSION:~0,4%,0x%GIT_VERSION:~4,4% ) -echo // This is a generated file, by git-version-gen.cmd. > "%WIN_VERSION_FILE%" -echo // GIT_VERSION=%GIT_VERSION% >> "%WIN_VERSION_FILE%" -echo. >> "%WIN_VERSION_FILE%" -echo #define PPSSPP_WIN_VERSION_STRING "%GIT_VERSION%" >> "%WIN_VERSION_FILE%" -echo #define PPSSPP_WIN_VERSION_COMMA %WIN_VERSION_COMMA% >> "%WIN_VERSION_FILE%" -echo. >> "%WIN_VERSION_FILE%" -echo // If you don't want this file to update/recompile, change to 1. >> "%WIN_VERSION_FILE%" -echo #define PPSSPP_WIN_VERSION_NO_UPDATE 0 >> "%WIN_VERSION_FILE%" +echo // This is a generated file, by git-version-gen.cmd. > "%WIN_VERSION_TEMP%" +echo // GIT_VERSION=%GIT_VERSION% >> "%WIN_VERSION_TEMP%" +echo. >> "%WIN_VERSION_TEMP%" +echo #define PPSSPP_WIN_VERSION_STRING "%GIT_VERSION%" >> "%WIN_VERSION_TEMP%" +echo #define PPSSPP_WIN_VERSION_COMMA %WIN_VERSION_COMMA% >> "%WIN_VERSION_TEMP%" +echo. >> "%WIN_VERSION_TEMP%" +echo // If you don't want this file to update/recompile, change to 1. >> "%WIN_VERSION_TEMP%" +echo #define PPSSPP_WIN_VERSION_NO_UPDATE 0 >> "%WIN_VERSION_TEMP%" + +move /y "%WIN_VERSION_TEMP%" "%WIN_VERSION_FILE%" > NUL +if errorlevel 1 ( + rem // Cheap delay tactic. + call %GIT% describe --always > NUL 2> NUL + move /y "%WIN_VERSION_TEMP%" "%WIN_VERSION_FILE%" > NUL +) :done diff --git a/Windows/main.cpp b/Windows/main.cpp index 3795597e26..3abdd7dfb0 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -21,8 +21,9 @@ #include #include "Common/CommonWindows.h" +#include "Common/File/FileUtil.h" #include "Common/OSVersion.h" -#include "Common/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" #include "ppsspp_config.h" #include @@ -30,15 +31,16 @@ #include #include -#include "base/NativeApp.h" -#include "base/display.h" -#include "file/vfs.h" -#include "file/zip_read.h" -#include "i18n/i18n.h" -#include "profiler/profiler.h" -#include "thread/threadutil.h" -#include "util/text/utf8.h" -#include "net/resolve.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" +#include "Common/Data/Text/I18n.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Net/Resolve.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -49,6 +51,7 @@ #include "Common/LogManager.h" #include "Common/ConsoleListener.h" +#include "Common/StringUtils.h" #include "Commctrl.h" @@ -86,11 +89,11 @@ extern "C" { __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } #if PPSSPP_API(ANY_GL) -CGEDebugger* geDebuggerWindow = 0; +CGEDebugger* geDebuggerWindow = nullptr; #endif -CDisasm *disasmWindow[MAX_CPUCOUNT] = {0}; -CMemoryDlg *memoryWindow[MAX_CPUCOUNT] = {0}; +CDisasm *disasmWindow = nullptr; +CMemoryDlg *memoryWindow = nullptr; static std::string langRegion; static std::string osName; @@ -294,7 +297,7 @@ void System_SendMessage(const char *command, const char *parameter) { } } else if (!strcmp(command, "graphics_failedBackend")) { auto err = GetI18NCategory("Error"); - const char *backendSwitchError = err->T("GenericBackendSwitchError", "PPSSPP crashed while initializing graphics. Try upgrading your graphics drivers.\n\nGraphics backend has been switched:"); + const char *backendSwitchError = err->T("GenericBackendSwitchCrash", "PPSSPP crashed while starting. This usually means a graphics driver problem. Try upgrading your graphics drivers.\n\nGraphics backend has been switched:"); std::wstring full_error = ConvertUTF8ToWString(StringFromFormat("%s %s", backendSwitchError, parameter)); std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error")); MessageBox(MainWindow::GetHWND(), full_error.c_str(), title.c_str(), MB_OK); @@ -507,13 +510,29 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin } } - LogManager::Init(); + LogManager::Init(&g_Config.bEnableLogging); // On Win32 it makes more sense to initialize the system directories here // because the next place it was called was in the EmuThread, and it's too late by then. g_Config.internalDataDirectory = W32Util::UserDocumentsPath(); InitSysDirectories(); + // Check for the Vulkan workaround before any serious init. + for (size_t i = 1; i < wideArgs.size(); ++i) { + if (wideArgs[i][0] == L'-') { + // This should only be called by DetectVulkanInExternalProcess(). + if (wideArgs[i] == L"--vulkan-available-check") { + // Just call it, this way it will crash here if it doesn't work. + // (this is an external process.) + bool result = VulkanMayBeAvailable(); + + LogManager::Shutdown(); + WinMainCleanup(); + return result ? EXIT_CODE_VULKAN_WORKS : EXIT_FAILURE; + } + } + } + // Load config up here, because those changes below would be overwritten // if it's not loaded here first. g_Config.AddSearchPath(""); @@ -572,17 +591,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin g_Config.bSoftwareRendering = true; } } - - // This should only be called by DetectVulkanInExternalProcess(). - if (wideArgs[i] == L"--vulkan-available-check") { - // Just call it, this way it will crash here if it doesn't work. - // (this is an external process.) - bool result = VulkanMayBeAvailable(); - - LogManager::Shutdown(); - WinMainCleanup(); - return result ? EXIT_CODE_VULKAN_WORKS : EXIT_FAILURE; - } } } #ifdef _DEBUG @@ -608,8 +616,9 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin // - It should be possible to log to a file without showing the console. LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console"); - if (debugLogLevel) + if (debugLogLevel) { LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG); + } timeBeginPeriod(1); // TODO: Evaluate if this makes sense to keep. @@ -670,7 +679,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin accel = hAccelTable; break; case WINDOW_CPUDEBUGGER: - wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0; + wnd = disasmWindow ? disasmWindow->GetDlgHandle() : 0; accel = hDebugAccelTable; break; case WINDOW_GEDEBUGGER: diff --git a/Windows/main.h b/Windows/main.h index d25d8ed006..a47bc081b5 100644 --- a/Windows/main.h +++ b/Windows/main.h @@ -22,10 +22,8 @@ #include "Debugger/Debugger_MemoryDlg.h" #include "Common/CommonWindows.h" -#define MAX_CPUCOUNT 1 - -extern CDisasm *disasmWindow[MAX_CPUCOUNT]; -extern CMemoryDlg *memoryWindow[MAX_CPUCOUNT]; +extern CDisasm *disasmWindow; +extern CMemoryDlg *memoryWindow; #if PPSSPP_API(ANY_GL) #include "Windows/GEDebugger/GEDebugger.h" diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 52cec06ebf..9f72a764b8 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -65,6 +65,7 @@ IDB_IMAGE_PSP IMAGE "pspmode.png" IDR_ACCELS ACCELERATORS BEGIN "O", ID_FILE_LOAD, VIRTKEY, CONTROL, NOINVERT + "I", ID_FILE_OPEN_NEW_INSTANCE, VIRTKEY, CONTROL, NOINVERT "W", ID_EMULATION_STOP, VIRTKEY, CONTROL, NOINVERT "B", ID_EMULATION_RESET, VIRTKEY, CONTROL, NOINVERT "T", ID_EMULATION_CHEATS, VIRTKEY, CONTROL, NOINVERT @@ -306,7 +307,7 @@ END #include "aboutbox.rc" #endif -IDD_MEMORY DIALOGEX 0, 0, 566, 287 +IDD_MEMORY DIALOGEX 0, 0, 700, 287 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME EXSTYLE WS_EX_TOOLWINDOW CAPTION "Memory View" @@ -316,11 +317,18 @@ BEGIN EDITTEXT IDC_ADDRESS,23,5,61,13,ES_AUTOHSCROLL CONTROL "Custom2",IDC_MEMVIEW,"CtrlMemView",WS_BORDER | WS_TABSTOP,126,23,316,263 LISTBOX IDC_SYMBOLS,1,23,120,263,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - CONTROL "Normal",IDC_MODENORMAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,248,9,40,9 - CONTROL "Symbols",IDC_MODESYMBOLS,"Button",BS_AUTORADIOBUTTON,291,9,43,8 - GROUPBOX "Mode",IDC_STATIC,241,0,104,22 - AUTOCHECKBOX "Show Offsets",IDC_SHOWOFFSETS,365,9,55,8 + + CONTROL "Normal",IDC_MODENORMAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,198,9,40,9 + CONTROL "Symbols",IDC_MODESYMBOLS,"Button",BS_AUTORADIOBUTTON,241,9,43,8 + GROUPBOX "Mode",IDC_STATIC,191,0,104,22 + AUTOCHECKBOX "Show Offsets",IDC_SHOWOFFSETS,300,9,55,8 COMBOBOX IDC_REGIONS,87,5,88,139,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LISTBOX IDC_SEARCH_RESULTS,557,14,140,272,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + + EDITTEXT IDC_SEARCH_BOX,397,6,100,13,ES_AUTOHSCROLL + PUSHBUTTON "Search",IDC_BUTTON_SEARCH,504,5,50,14 + LTEXT "Search:",IDC_STATIC,369,6,27,8 END IDD_INPUTBOX DIALOGEX 0, 0, 163, 55 @@ -343,7 +351,7 @@ BEGIN CONTROL "",IDC_TABDATATYPE,"SysTabControl32",TCS_BUTTONS,0,1,205,15 END -IDD_BREAKPOINT DIALOGEX 0, 0, 236, 109 +IDD_BREAKPOINT DIALOGEX 0, 0, 236, 119 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Breakpoint" FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -361,10 +369,11 @@ BEGIN EDITTEXT IDC_BREAKPOINT_CONDITION,41,49,187,14,ES_AUTOHSCROLL LTEXT "Log fmt",IDC_STATIC,7,71,31,8 EDITTEXT IDC_BREAKPOINT_LOG_FORMAT,41,69,187,14,ES_AUTOHSCROLL - CONTROL "Break",IDC_BREAKPOINT_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,41,91,41,10 - CONTROL "Log",IDC_BREAKPOINT_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,96,91,27,10 - DEFPUSHBUTTON "OK",IDC_BREAKPOINT_OK,144,88,41,14 - PUSHBUTTON "Cancel",IDC_BREAKPOINT_CANCEL,186,88,42,14 + LTEXT "Use {a1+a2} or {s1:d} to log expressions",IDC_STATIC,41,85,187,8 + CONTROL "Break",IDC_BREAKPOINT_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,41,101,41,10 + CONTROL "Log",IDC_BREAKPOINT_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,96,101,27,10 + DEFPUSHBUTTON "OK",IDC_BREAKPOINT_OK,144,98,41,14 + PUSHBUTTON "Cancel",IDC_BREAKPOINT_CANCEL,186,98,42,14 END IDD_DUMPMEMORY DIALOGEX 0, 0, 230, 85 @@ -469,6 +478,8 @@ BEGIN MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Open Memory Stick", ID_FILE_MEMSTICK MENUITEM "", 0, MFT_SEPARATOR + MENUITEM "Open New Instance", ID_FILE_OPEN_NEW_INSTANCE + MENUITEM "", 0, MFT_SEPARATOR POPUP "Savestate Slot", ID_FILE_SAVESTATE_SLOT_MENU BEGIN @@ -614,7 +625,6 @@ BEGIN MENUITEM "Auto", ID_OPTIONS_TEXTUREFILTERING_AUTO MENUITEM "Nearest", ID_OPTIONS_NEARESTFILTERING MENUITEM "Linear", ID_OPTIONS_LINEARFILTERING - MENUITEM "Linear on FMV", ID_OPTIONS_LINEARFILTERING_CG END POPUP "Screen Scaling Filter", ID_OPTIONS_SCREENFILTER_MENU BEGIN diff --git a/Windows/resource.h b/Windows/resource.h index 2a90462d4f..1c82abbf5e 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -22,6 +22,7 @@ #define WHEEL_DELTA 120 #define ID_DEBUG_LOG 121 #define ID_DEBUG_BREAKPOINTS 122 +#define ID_FILE_OPEN_NEW_INSTANCE 123 #define ID_FILE_LOADSTATEFILE 126 #define ID_FILE_SAVESTATEFILE 127 #define ID_EMULATION_RESET 130 @@ -86,6 +87,7 @@ #define IDC_STOPGO 1001 #define IDC_ADDRESS 1002 #define IDC_DEBUG_COUNT 1003 +#define IDC_SEARCH_BOX 1004 #define IDC_MEMORY 1006 #define IDC_SH4REGISTERS 1007 #define IDC_REGISTERS 1007 @@ -115,6 +117,7 @@ #define IDC_MODENORMAL 1099 #define IDC_MODESYMBOLS 1100 #define IDC_LOG_SHOW 1101 +#define IDC_SEARCH_RESULTS 1102 #define IDC_UPDATELOG 1108 #define IDC_SETPC 1118 #define IDC_UPDATEMISC 1134 @@ -167,6 +170,7 @@ #define IDC_BREAKPOINT_LOG_FORMAT 1199 #define IDC_SHOWOFFSETS 1200 #define IDC_GEDBG_PRIMCOUNTER 1201 +#define IDC_BUTTON_SEARCH 1204 #define ID_SHADERS_BASE 5000 @@ -238,7 +242,6 @@ #define ID_OPTIONS_TEXTUREFILTERING_AUTO 40067 #define ID_OPTIONS_NEARESTFILTERING 40068 #define ID_DISASM_DISASSEMBLETOFILE 40069 -#define ID_OPTIONS_LINEARFILTERING_CG 40070 #define ID_DISASM_DISABLEBREAKPOINT 40071 #define ID_DISASM_THREAD_FORCERUN 40072 #define ID_DISASM_THREAD_KILL 40073 diff --git a/Windows/version.rc b/Windows/version.rc index dbefa2cef8..1c6d3982b1 100644 Binary files a/Windows/version.rc and b/Windows/version.rc differ diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 3c5a48a78a..11e2682563 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,10 +2,10 @@ - - + android:versionCode="110030000" + android:versionName="1.10.3.0"> + + diff --git a/android/ab.cmd b/android/ab.cmd index 6befeb03b3..33347178f4 100644 --- a/android/ab.cmd +++ b/android/ab.cmd @@ -5,6 +5,7 @@ copy ..\assets\langregion.ini assets\langregion.ini copy ..\assets\compat.ini assets\compat.ini copy ..\assets\Roboto-Condensed.ttf assets\Roboto-Condensed.ttf copy ..\assets\*.png assets\ -SET NDK=C:\AndroidNDK +SET NDK=C:\Android\sdk\ndk\21.3.6528147 +REM SET NDK=C:\Android\ndk SET NDK_MODULE_PATH=..\ext;..\ext\native\ext -%NDK%/ndk-build -j9 %* +%NDK%/ndk-build -j32 %* diff --git a/android/ab.sh b/android/ab.sh index 25ed476eb2..08520d1a28 100755 --- a/android/ab.sh +++ b/android/ab.sh @@ -5,4 +5,4 @@ cp ../assets/langregion.ini assets/langregion.ini cp ../assets/compat.ini assets/compat.ini cp ../assets/Roboto-Condensed.ttf assets/Roboto-Condensed.ttf cp ../assets/*.png assets/ -NDK_MODULE_PATH=../ext:../ext/native/ext $NDK/ndk-build -j3 $* +NDK_MODULE_PATH=../ext $NDK/ndk-build -j3 $* diff --git a/android/build.gradle b/android/build.gradle index dc47ae6db1..494156f873 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -4,7 +4,7 @@ plugins { apply plugin: 'com.android.application' androidGitVersion { - codeFormat = "MNPPBBBB" + codeFormat = "MNNPPBBBB" format = "%tag%%-count%%-branch%%-dirty%" prefix = "v" // Only tags beginning with v are considered. untrackedIsDirty = false diff --git a/android/custom_rules.xml b/android/custom_rules.xml index e7edd4ff7e..292a376101 100644 --- a/android/custom_rules.xml +++ b/android/custom_rules.xml @@ -7,13 +7,13 @@ - + - + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 5bdf22bd18..5772dbc805 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -15,6 +15,7 @@ ifeq ($(TARGET_ARCH_ABI),x86) ARCH_FILES := \ $(SRC)/Common/ABI.cpp \ $(SRC)/Common/x64Emitter.cpp \ + $(SRC)/Common/x64Analyzer.cpp \ $(SRC)/Common/CPUDetect.cpp \ $(SRC)/Common/Thunk.cpp \ $(SRC)/Core/MIPS/x86/CompALU.cpp \ @@ -36,6 +37,7 @@ ifeq ($(TARGET_ARCH_ABI),x86_64) ARCH_FILES := \ $(SRC)/Common/ABI.cpp \ $(SRC)/Common/x64Emitter.cpp \ + $(SRC)/Common/x64Analyzer.cpp \ $(SRC)/Common/CPUDetect.cpp \ $(SRC)/Common/Thunk.cpp \ $(SRC)/Core/MIPS/x86/CompALU.cpp \ @@ -99,25 +101,15 @@ ARCH_FILES := \ Arm64EmitterTest.cpp endif -ifeq ($(TARGET_ARCH_ABI),armeabi) -ARCH_FILES := \ - $(SRC)/Common/ArmEmitter.cpp \ - $(SRC)/Common/ArmCPUDetect.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompALU.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompBranch.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompFPU.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompLoadStore.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompVFPU.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompVFPUNEON.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp \ - $(SRC)/Core/MIPS/ARM/ArmCompReplace.cpp \ - $(SRC)/Core/MIPS/ARM/ArmAsm.cpp \ - $(SRC)/Core/MIPS/ARM/ArmJit.cpp \ - $(SRC)/Core/MIPS/ARM/ArmRegCache.cpp \ - $(SRC)/Core/MIPS/ARM/ArmRegCacheFPU.cpp \ - $(SRC)/GPU/Common/VertexDecoderArm.cpp \ - ArmEmitterTest.cpp -endif +NATIVE_FILES :=\ + $(SRC)/Common/GPU/OpenGL/gl3stub.c \ + $(SRC)/Common/GPU/OpenGL/thin3d_gl.cpp \ + $(SRC)/Common/GPU/OpenGL/GLDebugLog.cpp \ + $(SRC)/Common/GPU/OpenGL/GLSLProgram.cpp \ + $(SRC)/Common/GPU/OpenGL/GLFeatures.cpp \ + $(SRC)/Common/GPU/OpenGL/GLRenderManager.cpp \ + $(SRC)/Common/GPU/OpenGL/GLQueueRunner.cpp \ + $(SRC)/Common/GPU/OpenGL/DataFormatGL.cpp EGL_FILES := \ $(SRC)/Common/GL/GLInterface/EGL.cpp \ @@ -125,14 +117,17 @@ EGL_FILES := \ $(SRC)/Common/GL/GLInterface/GLInterface.cpp VULKAN_FILES := \ - $(SRC)/Common/Vulkan/VulkanLoader.cpp \ - $(SRC)/Common/Vulkan/VulkanContext.cpp \ - $(SRC)/Common/Vulkan/VulkanDebug.cpp \ - $(SRC)/Common/Vulkan/VulkanImage.cpp \ - $(SRC)/Common/Vulkan/VulkanMemory.cpp \ + $(SRC)/Common/GPU/Vulkan/thin3d_vulkan.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanQueueRunner.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanRenderManager.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanLoader.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanContext.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanDebug.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanImage.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanMemory.cpp \ $(SRC)/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp \ $(SRC)/GPU/Vulkan/DrawEngineVulkan.cpp \ - $(SRC)/GPU/Vulkan/FramebufferVulkan.cpp \ + $(SRC)/GPU/Vulkan/FramebufferManagerVulkan.cpp \ $(SRC)/GPU/Vulkan/GPU_Vulkan.cpp \ $(SRC)/GPU/Vulkan/PipelineManagerVulkan.cpp \ $(SRC)/GPU/Vulkan/ShaderManagerVulkan.cpp \ @@ -154,11 +149,56 @@ SPIRV_CROSS_FILES := \ $(SRC)/ext/SPIRV-Cross/spirv_parser.cpp \ $(SRC)/ext/SPIRV-Cross/spirv_cross_parsed_ir.cpp +EXT_FILES := \ + $(SRC)/ext/cityhash/city.cpp \ + $(SRC)/ext/libpng17/png.c \ + $(SRC)/ext/libpng17/pngerror.c \ + $(SRC)/ext/libpng17/pngget.c \ + $(SRC)/ext/libpng17/pngmem.c \ + $(SRC)/ext/libpng17/pngpread.c \ + $(SRC)/ext/libpng17/pngread.c \ + $(SRC)/ext/libpng17/pngrio.c \ + $(SRC)/ext/libpng17/pngrtran.c \ + $(SRC)/ext/libpng17/pngrutil.c \ + $(SRC)/ext/libpng17/pngset.c \ + $(SRC)/ext/libpng17/pngtest.c \ + $(SRC)/ext/libpng17/pngtrans.c \ + $(SRC)/ext/libpng17/pngwio.c \ + $(SRC)/ext/libpng17/pngwrite.c \ + $(SRC)/ext/libpng17/pngwtran.c \ + $(SRC)/ext/libpng17/pngwutil.c \ + $(SRC)/ext/jpge/jpgd.cpp \ + $(SRC)/ext/jpge/jpge.cpp \ + $(SRC)/ext/sha1/sha1.cpp \ + $(SRC)/ext/gason/gason.cpp \ + $(SRC)/ext/libkirk/AES.c \ + $(SRC)/ext/libkirk/amctrl.c \ + $(SRC)/ext/libkirk/SHA1.c \ + $(SRC)/ext/libkirk/bn.c \ + $(SRC)/ext/libkirk/ec.c \ + $(SRC)/ext/libkirk/kirk_engine.c \ + $(SRC)/ext/sfmt19937/SFMT.c \ + $(SRC)/ext/snappy/snappy-c.cpp \ + $(SRC)/ext/snappy/snappy-sinksource.cpp \ + $(SRC)/ext/snappy/snappy-stubs-internal.cpp \ + $(SRC)/ext/snappy/snappy.cpp \ + $(SRC)/ext/udis86/decode.c \ + $(SRC)/ext/udis86/itab.c \ + $(SRC)/ext/udis86/syn-att.c \ + $(SRC)/ext/udis86/syn-intel.c \ + $(SRC)/ext/udis86/syn.c \ + $(SRC)/ext/udis86/udis86.c \ + $(SRC)/ext/xbrz/xbrz.cpp \ + $(SRC)/ext/xxhash.c \ + + EXEC_AND_LIB_FILES := \ $(ARCH_FILES) \ $(EGL_FILES) \ $(VULKAN_FILES) \ $(SPIRV_CROSS_FILES) \ + $(EXT_FILES) \ + $(NATIVE_FILES) \ TestRunner.cpp \ $(SRC)/Core/MIPS/MIPS.cpp.arm \ $(SRC)/Core/MIPS/MIPSAnalyst.cpp \ @@ -183,48 +223,92 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/MIPS/IR/IRInterpreter.cpp \ $(SRC)/Core/MIPS/IR/IRPassSimplify.cpp \ $(SRC)/Core/MIPS/IR/IRRegCache.cpp \ - $(SRC)/ext/libkirk/AES.c \ - $(SRC)/ext/libkirk/amctrl.c \ - $(SRC)/ext/libkirk/SHA1.c \ - $(SRC)/ext/libkirk/bn.c \ - $(SRC)/ext/libkirk/ec.c \ - $(SRC)/ext/libkirk/kirk_engine.c \ - $(SRC)/ext/sfmt19937/SFMT.c \ - $(SRC)/ext/snappy/snappy-c.cpp \ - $(SRC)/ext/snappy/snappy.cpp \ - $(SRC)/ext/udis86/decode.c \ - $(SRC)/ext/udis86/itab.c \ - $(SRC)/ext/udis86/syn-att.c \ - $(SRC)/ext/udis86/syn-intel.c \ - $(SRC)/ext/udis86/syn.c \ - $(SRC)/ext/udis86/udis86.c \ - $(SRC)/ext/xbrz/xbrz.cpp \ - $(SRC)/ext/xxhash.c \ + $(SRC)/Common/Buffer.cpp \ $(SRC)/Common/Crypto/md5.cpp \ $(SRC)/Common/Crypto/sha1.cpp \ $(SRC)/Common/Crypto/sha256.cpp \ - $(SRC)/Common/ChunkFile.cpp \ + $(SRC)/Common/Data/Color/RGBAUtil.cpp \ + $(SRC)/Common/Data/Convert/SmallDataConvert.cpp \ + $(SRC)/Common/Data/Encoding/Base64.cpp \ + $(SRC)/Common/Data/Encoding/Compression.cpp \ + $(SRC)/Common/Data/Encoding/Utf8.cpp \ + $(SRC)/Common/Data/Format/RIFF.cpp \ + $(SRC)/Common/Data/Format/IniFile.cpp \ + $(SRC)/Common/Data/Format/JSONReader.cpp \ + $(SRC)/Common/Data/Format/JSONWriter.cpp \ + $(SRC)/Common/Data/Format/PNGLoad.cpp \ + $(SRC)/Common/Data/Format/PNGLoad.h \ + $(SRC)/Common/Data/Format/ZIMLoad.cpp \ + $(SRC)/Common/Data/Format/ZIMLoad.h \ + $(SRC)/Common/Data/Format/ZIMSave.cpp \ + $(SRC)/Common/Data/Format/ZIMSave.h \ + $(SRC)/Common/Data/Hash/Hash.cpp \ + $(SRC)/Common/Data/Text/I18n.cpp \ + $(SRC)/Common/Data/Text/Parsers.cpp \ + $(SRC)/Common/Data/Text/WrapText.cpp \ + $(SRC)/Common/File/VFS/VFS.cpp \ + $(SRC)/Common/File/VFS/AssetReader.cpp \ + $(SRC)/Common/File/DiskFree.cpp \ + $(SRC)/Common/File/PathBrowser.cpp \ + $(SRC)/Common/File/FileUtil.cpp \ + $(SRC)/Common/File/DirListing.cpp \ + $(SRC)/Common/File/FileDescriptor.cpp \ + $(SRC)/Common/GPU/thin3d.cpp \ + $(SRC)/Common/Render/DrawBuffer.cpp \ + $(SRC)/Common/Render/TextureAtlas.cpp \ + $(SRC)/Common/Render/Text/draw_text.cpp \ + $(SRC)/Common/Render/Text/draw_text_android.cpp \ + $(SRC)/Common/Input/GestureDetector.cpp \ + $(SRC)/Common/Input/InputState.cpp \ + $(SRC)/Common/Math/fast/fast_math.c \ + $(SRC)/Common/Math/fast/fast_matrix.c \ + $(SRC)/Common/Math/math_util.cpp \ + $(SRC)/Common/Math/curves.cpp \ + $(SRC)/Common/Math/expression_parser.cpp \ + $(SRC)/Common/Math/lin/vec3.cpp.arm \ + $(SRC)/Common/Math/lin/matrix4x4.cpp.arm \ + $(SRC)/Common/Net/HTTPClient.cpp \ + $(SRC)/Common/Net/HTTPHeaders.cpp \ + $(SRC)/Common/Net/HTTPServer.cpp \ + $(SRC)/Common/Net/Resolve.cpp \ + $(SRC)/Common/Net/Sinks.cpp \ + $(SRC)/Common/Net/URL.cpp \ + $(SRC)/Common/Net/WebsocketServer.cpp \ + $(SRC)/Common/Profiler/Profiler.cpp \ + $(SRC)/Common/System/Display.cpp \ + $(SRC)/Common/Thread/Executor.cpp \ + $(SRC)/Common/Thread/PrioritizedWorkQueue.cpp \ + $(SRC)/Common/Thread/ThreadPool.cpp \ + $(SRC)/Common/Thread/ThreadUtil.cpp \ + $(SRC)/Common/UI/Root.cpp \ + $(SRC)/Common/UI/Screen.cpp \ + $(SRC)/Common/UI/UI.cpp \ + $(SRC)/Common/UI/Context.cpp \ + $(SRC)/Common/UI/UIScreen.cpp \ + $(SRC)/Common/UI/Tween.cpp \ + $(SRC)/Common/UI/View.cpp \ + $(SRC)/Common/UI/ViewGroup.cpp \ + $(SRC)/Common/Serialize/Serializer.cpp \ $(SRC)/Common/ColorConv.cpp \ - $(SRC)/Common/KeyMap.cpp \ + $(SRC)/Common/ExceptionHandlerSetup.cpp \ + $(SRC)/Common/Log.cpp \ $(SRC)/Common/LogManager.cpp \ $(SRC)/Common/MemArenaAndroid.cpp \ $(SRC)/Common/MemArenaDarwin.cpp \ $(SRC)/Common/MemArenaWin32.cpp \ $(SRC)/Common/MemArenaPosix.cpp \ $(SRC)/Common/MemoryUtil.cpp \ - $(SRC)/Common/MsgHandler.cpp \ - $(SRC)/Common/FileUtil.cpp \ $(SRC)/Common/StringUtils.cpp \ - $(SRC)/Common/ThreadPools.cpp \ - $(SRC)/Common/Timer.cpp \ - $(SRC)/Common/Misc.cpp \ + $(SRC)/Common/SysError.cpp \ + $(SRC)/Common/TimeUtil.cpp \ $(SRC)/GPU/Math3D.cpp \ $(SRC)/GPU/GPU.cpp \ $(SRC)/GPU/GPUCommon.cpp \ $(SRC)/GPU/GPUState.cpp \ + $(SRC)/GPU/GeConstants.cpp \ $(SRC)/GPU/GeDisasm.cpp \ $(SRC)/GPU/Common/DepalettizeShaderCommon.cpp \ - $(SRC)/GPU/Common/FramebufferCommon.cpp \ + $(SRC)/GPU/Common/FramebufferManagerCommon.cpp \ $(SRC)/GPU/Common/PresentationCommon.cpp \ $(SRC)/GPU/Common/GPUDebugInterface.cpp \ $(SRC)/GPU/Common/IndexGenerator.cpp.arm \ @@ -275,6 +359,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/ELF/ParamSFO.cpp \ $(SRC)/Core/HW/SimpleAudioDec.cpp \ $(SRC)/Core/HW/AsyncIOManager.cpp \ + $(SRC)/Core/HW/BufferQueue.cpp \ $(SRC)/Core/HW/Camera.cpp \ $(SRC)/Core/HW/MemoryStick.cpp \ $(SRC)/Core/HW/MpegDemux.cpp.arm \ @@ -288,6 +373,8 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/CoreTiming.cpp \ $(SRC)/Core/CwCheat.cpp \ $(SRC)/Core/HDRemaster.cpp \ + $(SRC)/Core/Instance.cpp \ + $(SRC)/Core/KeyMap.cpp \ $(SRC)/Core/Host.cpp \ $(SRC)/Core/Loaders.cpp \ $(SRC)/Core/PSPLoaders.cpp \ @@ -297,6 +384,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/FileLoaders/LocalFileLoader.cpp \ $(SRC)/Core/FileLoaders/RamCachingFileLoader.cpp \ $(SRC)/Core/FileLoaders/RetryingFileLoader.cpp \ + $(SRC)/Core/MemFault.cpp \ $(SRC)/Core/MemMap.cpp \ $(SRC)/Core/MemMapFunctions.cpp \ $(SRC)/Core/Reporting.cpp \ @@ -305,6 +393,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/Screenshot.cpp \ $(SRC)/Core/System.cpp \ $(SRC)/Core/TextureReplacer.cpp \ + $(SRC)/Core/ThreadPools.cpp \ $(SRC)/Core/WebServer.cpp \ $(SRC)/Core/Debugger/Breakpoints.cpp \ $(SRC)/Core/Debugger/DisassemblyManager.cpp \ @@ -319,6 +408,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/Debugger/WebSocket/GPURecordSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/HLESubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \ + $(SRC)/Core/Debugger/WebSocket/MemorySubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/SteppingBroadcaster.cpp \ $(SRC)/Core/Debugger/WebSocket/SteppingSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/WebSocketUtils.cpp \ @@ -337,6 +427,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/HLE/ReplaceTables.cpp \ $(SRC)/Core/HLE/HLE.cpp \ $(SRC)/Core/HLE/KUBridge.cpp \ + $(SRC)/Core/HLE/Plugins.cpp \ $(SRC)/Core/HLE/sceAdler.cpp \ $(SRC)/Core/HLE/sceAtrac.cpp \ $(SRC)/Core/HLE/__sceAudio.cpp.arm \ @@ -416,6 +507,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/MIPS/JitCommon/JitBlockCache.cpp \ $(SRC)/Core/MIPS/JitCommon/JitState.cpp \ $(SRC)/Core/Util/AudioFormat.cpp \ + $(SRC)/Core/Util/PortManager.cpp \ $(SRC)/Core/Util/GameManager.cpp \ $(SRC)/Core/Util/BlockAllocator.cpp \ $(SRC)/Core/Util/PPGeDraw.cpp \ @@ -492,8 +584,8 @@ LOCAL_SRC_FILES := \ $(SRC)/android/jni/AndroidEGLContext.cpp \ $(SRC)/android/jni/AndroidJavaGLContext.cpp \ $(SRC)/android/jni/AndroidVulkanContext.cpp \ - $(SRC)/android/jni/native_audio.cpp \ - $(SRC)/android/jni/native-audio-so.cpp \ + $(SRC)/android/jni/AndroidAudio.cpp \ + $(SRC)/android/jni/OpenSLContext.cpp \ $(SRC)/UI/BackgroundAudio.cpp \ $(SRC)/UI/DiscordIntegration.cpp \ $(SRC)/UI/ChatScreen.cpp \ @@ -526,11 +618,26 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/TextureUtil.cpp \ $(SRC)/UI/ComboKeyMappingScreen.cpp +ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a) +LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM +LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ + $(SRC)/Common/Math/fast/fast_matrix_neon.S.neon \ + $(SRC)/ext/libpng17/arm/arm_init.c \ + $(SRC)/ext/libpng17/arm/filter_neon_intrinsics.c \ + $(SRC)/ext/libpng17/arm/filter_neon.S.neon + +else ifeq ($(TARGET_ARCH_ABI),x86) +LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ + $(SRC)/Common/Math/fast/fast_matrix_sse.c +else ifeq ($(TARGET_ARCH_ABI),x86_64) +LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ + $(SRC)/Common/Math/fast/fast_matrix_sse.c +endif + ifneq ($(SKIPAPP),1) include $(BUILD_SHARED_LIBRARY) endif - ifeq ($(HEADLESS),1) include $(CLEAR_VARS) include $(LOCAL_PATH)/Locals.mk @@ -585,8 +692,8 @@ ifeq ($(UNITTEST),1) endif $(call import-module,libzip) -$(call import-module,native) $(call import-module,glslang-build) +$(call import-module,miniupnp-build) ifeq ($(ANDROID_NDK_PROFILER),1) $(call import-module,android-ndk-profiler) diff --git a/android/jni/native_audio.cpp b/android/jni/AndroidAudio.cpp similarity index 55% rename from android/jni/native_audio.cpp rename to android/jni/AndroidAudio.cpp index a06159a89c..56145b516e 100644 --- a/android/jni/native_audio.cpp +++ b/android/jni/AndroidAudio.cpp @@ -1,6 +1,19 @@ -#include "base/logging.h" -#include "android/jni/native_audio.h" -#include "android/jni/native-audio-so.h" +#include "Common/Log.h" + +#include "android/jni/AndroidAudio.h" +#include "android/jni/OpenSLContext.h" + +AudioContext::AudioContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate) + : audioCallback(cb), framesPerBuffer(_FramesPerBuffer), sampleRate(_SampleRate) { + if (framesPerBuffer == 0) + framesPerBuffer = 256; + if (framesPerBuffer < 32) + framesPerBuffer = 32; + if (framesPerBuffer > 4096) + framesPerBuffer = 4096; + + sampleRate = _SampleRate; +} struct AndroidAudioState { AudioContext *ctx = nullptr; @@ -19,13 +32,13 @@ AndroidAudioState *AndroidAudio_Init(AndroidAudioCallback callback, int optimalF bool AndroidAudio_Resume(AndroidAudioState *state) { if (!state) { - ELOG("Audio was shutdown, cannot resume!"); + ERROR_LOG(AUDIO, "Audio was shutdown, cannot resume!"); return false; } if (!state->ctx) { - ILOG("Calling OpenSLWrap_Init_T..."); + INFO_LOG(AUDIO, "Calling OpenSLWrap_Init_T..."); state->ctx = new OpenSLContext(state->callback, state->frames_per_buffer, state->sample_rate); - ILOG("Returned from OpenSLWrap_Init_T"); + INFO_LOG(AUDIO, "Returned from OpenSLWrap_Init_T"); bool init_retval = state->ctx->Init(); if (!init_retval) { delete state->ctx; @@ -38,14 +51,14 @@ bool AndroidAudio_Resume(AndroidAudioState *state) { bool AndroidAudio_Pause(AndroidAudioState *state) { if (!state) { - ELOG("Audio was shutdown, cannot pause!"); + ERROR_LOG(AUDIO, "Audio was shutdown, cannot pause!"); return false; } if (state->ctx) { - ILOG("Calling OpenSLWrap_Shutdown_T..."); + INFO_LOG(AUDIO, "Calling OpenSLWrap_Shutdown_T..."); delete state->ctx; state->ctx = nullptr; - ILOG("Returned from OpenSLWrap_Shutdown_T ..."); + INFO_LOG(AUDIO, "Returned from OpenSLWrap_Shutdown_T ..."); return true; } return false; @@ -53,14 +66,14 @@ bool AndroidAudio_Pause(AndroidAudioState *state) { bool AndroidAudio_Shutdown(AndroidAudioState *state) { if (!state) { - ELOG("Audio already shutdown!"); + ERROR_LOG(AUDIO, "Audio already shutdown!"); return false; } if (state->ctx) { - ELOG("Should not shut down when playing! Something is wrong!"); + ERROR_LOG(AUDIO, "Should not shut down when playing! Something is wrong!"); return false; } delete state; - ILOG("OpenSLWrap completely unloaded."); + INFO_LOG(AUDIO, "OpenSLWrap completely unloaded."); return true; } diff --git a/android/jni/native_audio.h b/android/jni/AndroidAudio.h similarity index 55% rename from android/jni/native_audio.h rename to android/jni/AndroidAudio.h index 427f29ca36..a3d1ab8ee8 100644 --- a/android/jni/native_audio.h +++ b/android/jni/AndroidAudio.h @@ -1,8 +1,22 @@ #pragma once -#include "native-audio-so.h" #include +typedef int (*AndroidAudioCallback)(short *buffer, int num_samples); + +class AudioContext { +public: + AudioContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate); + virtual bool Init() { return false; } + virtual ~AudioContext() {} + +protected: + AndroidAudioCallback audioCallback; + + int framesPerBuffer; + int sampleRate; +}; + struct AndroidAudioState; // It's okay for optimalFramesPerBuffer and optimalSampleRate to be 0. Defaults will be used. diff --git a/android/jni/AndroidEGLContext.cpp b/android/jni/AndroidEGLContext.cpp index 5e7604a0c0..55d54dff77 100644 --- a/android/jni/AndroidEGLContext.cpp +++ b/android/jni/AndroidEGLContext.cpp @@ -1,25 +1,24 @@ -#include -#include "base/logging.h" -#include "base/NativeApp.h" -#include "gfx_es2/gpu_features.h" -#include "thin3d/thin3d_create.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/Log.h" +#include "Common/System/System.h" #include "AndroidEGLContext.h" #include "GL/GLInterface/EGLAndroid.h" #include "Core/ConfigValues.h" #include "Core/System.h" bool AndroidEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { - ILOG("AndroidEGLGraphicsContext::Init()"); + INFO_LOG(G3D, "AndroidEGLGraphicsContext::Init()"); wnd_ = wnd; gl = HostGL_CreateGLInterface(); if (!gl) { - ELOG("ERROR: Failed to create GL interface"); + ERROR_LOG(G3D, "ERROR: Failed to create GL interface"); return false; } int backbufferWidth = desiredBackbufferSizeX; int backbufferHeight = desiredBackbufferSizeY; - ILOG("EGL interface created. Desired backbuffer size: %dx%d", backbufferWidth, backbufferHeight); + INFO_LOG(G3D, "EGL interface created. Desired backbuffer size: %dx%d", backbufferWidth, backbufferHeight); // Apparently we still have to set this through Java through setFixedSize on the bufferHolder for it to take effect... gl->SetBackBufferDimensions(backbufferWidth, backbufferHeight); @@ -39,7 +38,7 @@ bool AndroidEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int des } if (!gl->Create(wnd, false, use565)) { - ELOG("EGL creation failed! (use565=%d)", (int)use565); + ERROR_LOG(G3D, "EGL creation failed! (use565=%d)", (int)use565); // TODO: What do we do now? delete gl; return false; @@ -53,12 +52,12 @@ bool AndroidEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int des renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager_->SetInflightFrames(g_Config.iInflightFrames); bool success = draw_->CreatePresets(); // There will always be a GLSL compiler capable of compiling these. - _assert_msg_(G3D, success, "Failed to compile preset shaders"); + _assert_msg_(success, "Failed to compile preset shaders"); return true; } void AndroidEGLGraphicsContext::ShutdownFromRenderThread() { - ILOG("AndroidEGLGraphicsContext::Shutdown"); + INFO_LOG(G3D, "AndroidEGLGraphicsContext::Shutdown"); renderManager_->WaitUntilQueueIdle(); renderManager_ = nullptr; // owned by draw_. delete draw_; diff --git a/android/jni/AndroidEGLContext.h b/android/jni/AndroidEGLContext.h index 45b33f8241..49a89739b2 100644 --- a/android/jni/AndroidEGLContext.h +++ b/android/jni/AndroidEGLContext.h @@ -1,6 +1,6 @@ #pragma once -#include "thin3d/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" #include "AndroidGraphicsContext.h" #include "Common/GL/GLInterfaceBase.h" diff --git a/android/jni/AndroidGraphicsContext.h b/android/jni/AndroidGraphicsContext.h index 096a5653f3..434017e077 100644 --- a/android/jni/AndroidGraphicsContext.h +++ b/android/jni/AndroidGraphicsContext.h @@ -2,8 +2,7 @@ #include -#include "thin3d/thin3d.h" - +#include "Common/GPU/thin3d.h" #include "Common/GraphicsContext.h" enum { diff --git a/android/jni/AndroidJavaGLContext.cpp b/android/jni/AndroidJavaGLContext.cpp index b60f87cfb4..9fefc59c90 100644 --- a/android/jni/AndroidJavaGLContext.cpp +++ b/android/jni/AndroidJavaGLContext.cpp @@ -1,9 +1,7 @@ -#include - #include "AndroidJavaGLContext.h" -#include "base/display.h" -#include "base/NativeApp.h" -#include "gfx_es2/gpu_features.h" +#include "Common/System/Display.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/Log.h" #include "Core/ConfigValues.h" #include "Core/System.h" @@ -12,21 +10,20 @@ AndroidJavaEGLGraphicsContext::AndroidJavaEGLGraphicsContext() { } bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { - ILOG("AndroidJavaEGLGraphicsContext::InitFromRenderThread"); + INFO_LOG(G3D, "AndroidJavaEGLGraphicsContext::InitFromRenderThread"); CheckGLExtensions(); // OpenGL handles rotated rendering in the driver. g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); - draw_ = Draw::T3DCreateGLContext(); + draw_ = Draw::T3DCreateGLContext(); // Can't fail renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager_->SetInflightFrames(g_Config.iInflightFrames); - bool success = draw_->CreatePresets(); - _assert_msg_(G3D, success, "Failed to compile preset shaders"); - return success; + draw_->CreatePresets(); + return true; } void AndroidJavaEGLGraphicsContext::ShutdownFromRenderThread() { - ILOG("AndroidJavaEGLGraphicsContext::Shutdown"); + INFO_LOG(G3D, "AndroidJavaEGLGraphicsContext::Shutdown"); renderManager_->WaitUntilQueueIdle(); renderManager_ = nullptr; // owned by draw_. delete draw_; diff --git a/android/jni/AndroidJavaGLContext.h b/android/jni/AndroidJavaGLContext.h index 05d3966896..69f8d2bb40 100644 --- a/android/jni/AndroidJavaGLContext.h +++ b/android/jni/AndroidJavaGLContext.h @@ -5,8 +5,8 @@ #include #include "AndroidGraphicsContext.h" -#include "thin3d/GLRenderManager.h" -#include "thin3d/thin3d_create.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" +#include "Common/GPU/thin3d_create.h" // Doesn't do much. Just to fit in. class AndroidJavaEGLGraphicsContext : public AndroidGraphicsContext { @@ -29,6 +29,7 @@ public: void SwapBuffers() override {} void SwapInterval(int interval) override {} void Resize() override {} + Draw::DrawContext *GetDrawContext() override { return draw_; } diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 5a5b67b2f8..dc68a8d75a 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -1,80 +1,19 @@ -#include - #include "AndroidVulkanContext.h" -#include "base/NativeApp.h" -#include "base/display.h" -#include "Common/Vulkan/VulkanLoader.h" -#include "Common/Vulkan/VulkanContext.h" -#include "thin3d/VulkanRenderManager.h" -#include "thin3d/thin3d_create.h" -#include "util/text/parsers.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Log.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanDebug.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/Data/Text/Parsers.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" -static VulkanLogOptions g_LogOptions; - -const char *ObjTypeToString(VkDebugReportObjectTypeEXT type) { - switch (type) { - case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT: return "Instance"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT: return "PhysicalDevice"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT: return "Device"; - case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT: return "Queue"; - case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT: return "CommandBuffer"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: return "DeviceMemory"; - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: return "Buffer"; - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: return "BufferView"; - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: return "Image"; - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: return "ImageView"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT: return "ShaderModule"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: return "Pipeline"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT: return "PipelineLayout"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: return "Sampler"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: return "DescriptorSet"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT: return "DescriptorSetLayout"; - case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: return "DescriptorPool"; - case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT: return "Fence"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT: return "Semaphore"; - case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: return "Event"; - case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: return "QueryPool"; - case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: return "Framebuffer"; - case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: return "RenderPass"; - case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT: return "PipelineCache"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT: return "SurfaceKHR"; - case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: return "SwapChainKHR"; - case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: return "CommandPool"; - default: return "Unknown"; - } -} - -static VKAPI_ATTR 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) { - const VulkanLogOptions *options = (const VulkanLogOptions *)pUserData; - int loglevel = ANDROID_LOG_INFO; - if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { - loglevel = ANDROID_LOG_ERROR; - } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - loglevel = ANDROID_LOG_WARN; - } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { - loglevel = ANDROID_LOG_WARN; - } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { - loglevel = ANDROID_LOG_WARN; - } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { - loglevel = ANDROID_LOG_WARN; - } - - __android_log_print(loglevel, APP_NAME, "[%s] %s Code %d : %s", - pLayerPrefix, ObjTypeToString(objType), msgCode, pMsg); - - // 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; -} - -AndroidVulkanContext::AndroidVulkanContext() { -} +AndroidVulkanContext::AndroidVulkanContext() {} AndroidVulkanContext::~AndroidVulkanContext() { delete g_Vulkan; @@ -89,18 +28,18 @@ static uint32_t FlagsFromConfig() { } bool AndroidVulkanContext::InitAPI() { - ILOG("AndroidVulkanContext::Init"); + INFO_LOG(G3D, "AndroidVulkanContext::Init"); init_glslang(); g_LogOptions.breakOnError = true; g_LogOptions.breakOnWarning = true; g_LogOptions.msgBoxOnError = false; - ILOG("Creating Vulkan context"); + INFO_LOG(G3D, "Creating Vulkan context"); Version gitVer(PPSSPP_GIT_VERSION); if (!VulkanLoad()) { - ELOG("Failed to load Vulkan driver library"); + ERROR_LOG(G3D, "Failed to load Vulkan driver library"); return false; } @@ -115,7 +54,7 @@ bool AndroidVulkanContext::InitAPI() { info.flags = FlagsFromConfig(); VkResult res = g_Vulkan->CreateInstance(info); if (res != VK_SUCCESS) { - ELOG("Failed to create vulkan context: %s", g_Vulkan->InitError().c_str()); + ERROR_LOG(G3D, "Failed to create vulkan context: %s", g_Vulkan->InitError().c_str()); VulkanSetAvailable(false); delete g_Vulkan; g_Vulkan = nullptr; @@ -124,7 +63,7 @@ bool AndroidVulkanContext::InitAPI() { int physicalDevice = g_Vulkan->GetBestPhysicalDevice(); if (physicalDevice < 0) { - ELOG("No usable Vulkan device found."); + ERROR_LOG(G3D, "No usable Vulkan device found."); g_Vulkan->DestroyInstance(); delete g_Vulkan; g_Vulkan = nullptr; @@ -132,45 +71,40 @@ bool AndroidVulkanContext::InitAPI() { } g_Vulkan->ChooseDevice(physicalDevice); - // Here we can enable device extensions if we like. - ILOG("Creating Vulkan device"); + INFO_LOG(G3D, "Creating Vulkan device"); if (g_Vulkan->CreateDevice() != VK_SUCCESS) { - ILOG("Failed to create vulkan device: %s", g_Vulkan->InitError().c_str()); + INFO_LOG(G3D, "Failed to create vulkan device: %s", g_Vulkan->InitError().c_str()); System_SendMessage("toast", "No Vulkan driver found. Using OpenGL instead."); g_Vulkan->DestroyInstance(); delete g_Vulkan; g_Vulkan = nullptr; return false; } - ILOG("Vulkan device created!"); + + INFO_LOG(G3D, "Vulkan device created!"); return true; } bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { - ILOG("AndroidVulkanContext::InitFromRenderThread: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY); + INFO_LOG(G3D, "AndroidVulkanContext::InitFromRenderThread: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY); if (!g_Vulkan) { - ELOG("AndroidVulkanContext::InitFromRenderThread: No Vulkan context"); + ERROR_LOG(G3D, "AndroidVulkanContext::InitFromRenderThread: No Vulkan context"); return false; } VkResult res = g_Vulkan->InitSurface(WINDOWSYSTEM_ANDROID, (void *)wnd, nullptr); if (res != VK_SUCCESS) { - ELOG("g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res)); + ERROR_LOG(G3D, "g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res)); return false; } - if (g_validate_) { - int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; - g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions); - } - bool success = true; - if (g_Vulkan->InitObjects()) { + if (g_Vulkan->InitSwapchain()) { draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, g_Config.bGfxDebugSplitSubmit); SetGPUBackend(GPUBackend::VULKAN); success = draw_->CreatePresets(); // Doesn't fail, we ship the compiler. - _assert_msg_(G3D, success, "Failed to compile preset shaders"); + _assert_msg_(success, "Failed to compile preset shaders"); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); @@ -180,55 +114,53 @@ bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredB success = false; } - ILOG("AndroidVulkanContext::Init completed, %s", success ? "successfully" : "but failed"); + INFO_LOG(G3D, "AndroidVulkanContext::Init completed, %s", success ? "successfully" : "but failed"); if (!success) { - g_Vulkan->DestroyObjects(); + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); g_Vulkan->DestroyDevice(); - g_Vulkan->DestroyDebugUtilsCallback(); - g_Vulkan->DestroyDebugMsgCallback(); - g_Vulkan->DestroyInstance(); } return success; } void AndroidVulkanContext::ShutdownFromRenderThread() { - ILOG("AndroidVulkanContext::Shutdown"); + INFO_LOG(G3D, "AndroidVulkanContext::Shutdown"); draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); delete draw_; draw_ = nullptr; g_Vulkan->WaitUntilQueueIdle(); g_Vulkan->PerformPendingDeletes(); - g_Vulkan->DestroyObjects(); // Also destroys the surface, a bit asymmetric - ILOG("Done with ShutdownFromRenderThread"); + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); + INFO_LOG(G3D, "Done with ShutdownFromRenderThread"); } void AndroidVulkanContext::Shutdown() { - ILOG("Calling NativeShutdownGraphics"); + INFO_LOG(G3D, "Calling NativeShutdownGraphics"); g_Vulkan->DestroyDevice(); - g_Vulkan->DestroyDebugUtilsCallback(); - g_Vulkan->DestroyDebugMsgCallback(); - g_Vulkan->DestroyInstance(); // We keep the g_Vulkan context around to avoid invalidating a ton of pointers around the app. finalize_glslang(); - ILOG("AndroidVulkanContext::Shutdown completed"); + INFO_LOG(G3D, "AndroidVulkanContext::Shutdown completed"); } void AndroidVulkanContext::SwapBuffers() { } void AndroidVulkanContext::Resize() { - ILOG("AndroidVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + INFO_LOG(G3D, "AndroidVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - g_Vulkan->DestroyObjects(); + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); g_Vulkan->UpdateFlags(FlagsFromConfig()); + g_Vulkan->ReinitSurface(); - g_Vulkan->InitObjects(); + g_Vulkan->InitSwapchain(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - ILOG("AndroidVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + INFO_LOG(G3D, "AndroidVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); } void AndroidVulkanContext::SwapInterval(int interval) { diff --git a/android/jni/AndroidVulkanContext.h b/android/jni/AndroidVulkanContext.h index adb47e2806..2e5cfb7328 100644 --- a/android/jni/AndroidVulkanContext.h +++ b/android/jni/AndroidVulkanContext.h @@ -2,8 +2,6 @@ #include "AndroidGraphicsContext.h" -static const bool g_validate_ = true; - class VulkanContext; class AndroidVulkanContext : public AndroidGraphicsContext { @@ -34,9 +32,3 @@ private: VulkanContext *g_Vulkan = nullptr; Draw::DrawContext *draw_ = nullptr; }; - -struct VulkanLogOptions { - bool breakOnWarning; - bool breakOnError; - bool msgBoxOnError; -}; diff --git a/android/jni/Arm64EmitterTest.cpp b/android/jni/Arm64EmitterTest.cpp index b9240fc352..3a04f6fb18 100644 --- a/android/jni/Arm64EmitterTest.cpp +++ b/android/jni/Arm64EmitterTest.cpp @@ -1,9 +1,7 @@ -#include "base/logging.h" -#include "Arm64EmitterTest.h" - #include "Common/Arm64Emitter.h" #include "Common/BitSet.h" #include "Common/CPUDetect.h" +#include "Common/Log.h" static bool functionWasCalled; @@ -68,11 +66,11 @@ void Arm64EmitterTest() { return; for (int i = 0; i < 6; i++) { - ILOG("---------------------------"); + INFO_LOG(SYSTEM, "---------------------------"); } - ILOG("---------------------------"); - ILOG("Running ARM64 emitter test!"); - ILOG("---------------------------"); + INFO_LOG(SYSTEM, "---------------------------"); + INFO_LOG(SYSTEM, "Running ARM64 emitter test!"); + INFO_LOG(SYSTEM, "---------------------------"); TestCode gen; gen.ReserveCodeSpace(0x1000); @@ -80,15 +78,15 @@ void Arm64EmitterTest() { gen.Generate(); u32 retval = CallPtr(gen.testCodePtr); - ILOG("Returned %d", retval); - // ILOG("ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); + INFO_LOG(SYSTEM, "Returned %d", retval); + // INFO_LOG(SYSTEM, "ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); /* - ILOG("x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); - ILOG("y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); - ILOG("z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); - ILOG("c: %f %f %f %f", c[0], c[1], c[2], c[3]);*/ + INFO_LOG(SYSTEM, "x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); + INFO_LOG(SYSTEM, "y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); + INFO_LOG(SYSTEM, "z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); + INFO_LOG(SYSTEM, "c: %f %f %f %f", c[0], c[1], c[2], c[3]);*/ for (int i = 0; i < 6; i++) { - ILOG("--------------------------"); + INFO_LOG(SYSTEM, "--------------------------"); } // DisassembleArm(codeStart, gen.GetCodePtr()-codeStart); } diff --git a/android/jni/ArmEmitterTest.cpp b/android/jni/ArmEmitterTest.cpp index 8090c1e94c..5af9643f07 100644 --- a/android/jni/ArmEmitterTest.cpp +++ b/android/jni/ArmEmitterTest.cpp @@ -1,4 +1,3 @@ -#include "base/logging.h" #include "ArmEmitterTest.h" #include "Common/ArmEmitter.h" @@ -70,7 +69,7 @@ void TestCode::Generate() VST1(I_32, D6, R3, 2); PLD(R1, 32); u32 word = *(u32 *)(GetCodePtr() - 4); - ILOG("Instruction Word: %08x", word); + INFO_LOG(SYSTEM, "Instruction Word: %08x", word); // This works! @@ -122,11 +121,11 @@ void ArmEmitterTest() return; for (int i = 0; i < 6; i++) { - ILOG("--------------------------"); + INFO_LOG(SYSTEM, "--------------------------"); } - ILOG("--------------------------"); - ILOG("Running ARM emitter test!"); - ILOG("--------------------------"); + INFO_LOG(SYSTEM, "--------------------------"); + INFO_LOG(SYSTEM, "Running ARM emitter test!"); + INFO_LOG(SYSTEM, "--------------------------"); TestCode gen; gen.ReserveCodeSpace(0x1000); @@ -134,13 +133,13 @@ void ArmEmitterTest() gen.Generate(); u32 retval = CallPtr(gen.testCodePtr); - // ILOG("ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); - ILOG("x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); - ILOG("y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); - ILOG("z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); - ILOG("c: %f %f %f %f", c[0], c[1], c[2], c[3]); + // INFO_LOG(SYSTEM, "ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); + INFO_LOG(SYSTEM, "x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); + INFO_LOG(SYSTEM, "y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); + INFO_LOG(SYSTEM, "z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); + INFO_LOG(SYSTEM, "c: %f %f %f %f", c[0], c[1], c[2], c[3]); for (int i = 0; i < 6; i++) { - ILOG("--------------------------"); + INFO_LOG(SYSTEM, "--------------------------"); } // DisassembleArm(codeStart, gen.GetCodePtr()-codeStart); } diff --git a/android/jni/Locals.mk b/android/jni/Locals.mk index c8a209cf85..d18d5d6e85 100644 --- a/android/jni/Locals.mk +++ b/android/jni/Locals.mk @@ -11,14 +11,15 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../../ext \ $(LOCAL_PATH)/../../ext/snappy \ $(LOCAL_PATH)/../../ext/glslang \ + $(LOCAL_PATH)/../../ext/miniupnp \ + $(LOCAL_PATH)/../../ext/miniupnp-build \ $(LOCAL_PATH)/$(NATIVE)/base \ - $(LOCAL_PATH)/$(NATIVE)/ext \ - $(LOCAL_PATH)/$(NATIVE)/ext/libpng17 \ - $(LOCAL_PATH)/$(NATIVE)/ext/libzip \ + $(LOCAL_PATH)/../../ext/libpng17 \ + $(LOCAL_PATH)/../../ext/libzip \ $(LOCAL_PATH)/$(NATIVE) \ $(LOCAL_PATH) -LOCAL_STATIC_LIBRARIES := native libzip glslang-build +LOCAL_STATIC_LIBRARIES := libzip glslang-build miniupnp-build LOCAL_LDLIBS := -lz -landroid -lGLESv2 -lOpenSLES -lEGL -ldl -llog -latomic ifneq ($(NDK_DEBUG),1) # Prettier stack traces are nice on other platforms. @@ -68,7 +69,7 @@ ifeq ($(TARGET_ARCH_ABI),x86_64) LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/x86_64/lib/libavutil.a LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ffmpeg/android/x86_64/include - LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_ARCH_64 -D_M_X64 -fomit-frame-pointer -mtune=atom -mfpmath=sse -mssse3 -mstackrealign + LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_X64 -fomit-frame-pointer -mtune=atom -mfpmath=sse -mssse3 -mstackrealign endif ifeq ($(TARGET_ARCH_ABI),arm64-v8a) @@ -78,8 +79,6 @@ ifeq ($(TARGET_ARCH_ABI),arm64-v8a) LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/arm64/lib/libswscale.a LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/arm64/lib/libavutil.a LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ffmpeg/android/arm64/include - - LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_ARCH_64 -DARM64 endif # Compile with profiling. diff --git a/android/jni/native-audio-so.cpp b/android/jni/OpenSLContext.cpp similarity index 79% rename from android/jni/native-audio-so.cpp rename to android/jni/OpenSLContext.cpp index 17e665d2de..77ccfde2eb 100644 --- a/android/jni/native-audio-so.cpp +++ b/android/jni/OpenSLContext.cpp @@ -2,28 +2,15 @@ // // Loosely based on the Android NDK sample code. -#include -#include +#include #include // for native audio #include #include -#include "base/logging.h" -#include "native-audio-so.h" - -AudioContext::AudioContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate) - : audioCallback(cb), framesPerBuffer(_FramesPerBuffer), sampleRate(_SampleRate) { - if (framesPerBuffer == 0) - framesPerBuffer = 256; - if (framesPerBuffer < 32) - framesPerBuffer = 32; - if (framesPerBuffer > 4096) - framesPerBuffer = 4096; - - sampleRate = _SampleRate; -} +#include "Common/Log.h" +#include "OpenSLContext.h" // This callback handler is called every time a buffer finishes playing. // The documentation available is very unclear about how to best manage buffers. @@ -36,7 +23,7 @@ void OpenSLContext::bqPlayerCallbackWrap(SLAndroidSimpleBufferQueueItf bq, void void OpenSLContext::BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq) { if (bq != bqPlayerBufferQueue) { - ELOG("Wrong bq!"); + ERROR_LOG(AUDIO, "OpenSL: Wrong bq!"); return; } @@ -53,7 +40,7 @@ void OpenSLContext::BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq) { // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, // which for this code example would indicate a programming error if (result != SL_RESULT_SUCCESS) { - ELOG("OpenSL ES: Failed to enqueue! %i %i", renderedFrames, sizeInBytes); + ERROR_LOG(AUDIO, "OpenSL: Failed to enqueue! %i %i", renderedFrames, sizeInBytes); } curBuffer += 1; // Switch buffer @@ -70,24 +57,26 @@ bool OpenSLContext::Init() { // create engine result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); if (result != SL_RESULT_SUCCESS) { - ELOG("OpenSL ES: Failed to create the engine: %d", (int)result); + ERROR_LOG(AUDIO, "OpenSL: Failed to create the engine: %d", (int)result); engineObject = nullptr; return false; } result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); + result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); + result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0); if (result != SL_RESULT_SUCCESS) { - ELOG("OpenSL ES: Failed to create output mix: %d", (int)result); + ERROR_LOG(AUDIO, "OpenSL: Failed to create output mix: %d", (int)result); (*engineObject)->Destroy(engineObject); engineEngine = nullptr; engineObject = nullptr; return false; } result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); // The constants, such as SL_SAMPLINGRATE_44_1, are just 44100000. SLuint32 sr = (SLuint32)sampleRate * 1000; @@ -114,7 +103,7 @@ bool OpenSLContext::Init() { const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req); if (result != SL_RESULT_SUCCESS) { - ELOG("OpenSL ES: CreateAudioPlayer failed: %d", (int)result); + ERROR_LOG(AUDIO, "OpenSL: CreateAudioPlayer failed: %d", (int)result); (*outputMixObject)->Destroy(outputMixObject); outputMixObject = nullptr; @@ -126,18 +115,18 @@ bool OpenSLContext::Init() { } result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, &bqPlayerCallbackWrap, this); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); - assert(SL_RESULT_SUCCESS == result); + _assert_(SL_RESULT_SUCCESS == result); // Allocate and enqueue N empty buffers. for (int i = 0; i < NUM_BUFFERS; i++) { @@ -159,15 +148,15 @@ bool OpenSLContext::Init() { // shut down the native audio system OpenSLContext::~OpenSLContext() { if (bqPlayerPlay) { - ILOG("OpenSLWrap_Shutdown - stopping playback"); + INFO_LOG(AUDIO, "OpenSL: Shutdown - stopping playback"); SLresult result; result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED); if (SL_RESULT_SUCCESS != result) { - ELOG("SetPlayState failed"); + ERROR_LOG(AUDIO, "SetPlayState failed"); } } - ILOG("OpenSLWrap_Shutdown - deleting player object"); + INFO_LOG(AUDIO, "OpenSL: Shutdown - deleting player object"); if (bqPlayerObject) { (*bqPlayerObject)->Destroy(bqPlayerObject); @@ -177,14 +166,14 @@ OpenSLContext::~OpenSLContext() { bqPlayerVolume = nullptr; } - ILOG("OpenSLWrap_Shutdown - deleting mix object"); + INFO_LOG(AUDIO, "OpenSL: Shutdown - deleting mix object"); if (outputMixObject) { (*outputMixObject)->Destroy(outputMixObject); outputMixObject = nullptr; } - ILOG("OpenSLWrap_Shutdown - deleting engine object"); + INFO_LOG(AUDIO, "OpenSL: Shutdown - deleting engine object"); if (engineObject) { (*engineObject)->Destroy(engineObject); @@ -196,6 +185,6 @@ OpenSLContext::~OpenSLContext() { delete[] buffer[i]; buffer[i] = nullptr; } - ILOG("OpenSLWrap_Shutdown - finished"); + INFO_LOG(AUDIO, "OpenSL: Shutdown - finished"); } diff --git a/android/jni/native-audio-so.h b/android/jni/OpenSLContext.h similarity index 73% rename from android/jni/native-audio-so.h rename to android/jni/OpenSLContext.h index 9623e51709..3705f66b82 100644 --- a/android/jni/native-audio-so.h +++ b/android/jni/OpenSLContext.h @@ -3,20 +3,7 @@ #include #include -typedef int (*AndroidAudioCallback)(short *buffer, int num_samples); - -class AudioContext { -public: - AudioContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate); - virtual bool Init() { return false; } - virtual ~AudioContext() {} - -protected: - AndroidAudioCallback audioCallback; - - int framesPerBuffer; - int sampleRate; -}; +#include "AndroidAudio.h" class OpenSLContext : public AudioContext { public: diff --git a/android/jni/TestRunner.cpp b/android/jni/TestRunner.cpp index 2a24811289..e5489fd0c1 100644 --- a/android/jni/TestRunner.cpp +++ b/android/jni/TestRunner.cpp @@ -26,11 +26,10 @@ #include #include "ppsspp_config.h" -#include "base/basictypes.h" -#include "base/display.h" -#include "base/logging.h" +#include "Common/System/Display.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/Log.h" #include "Core/Core.h" #include "Core/System.h" #include "Core/Config.h" @@ -112,11 +111,11 @@ bool RunTests() { coreParam.fileToStart = baseDirectory + "pspautotests/tests/" + testName + ".prx"; std::string expectedFile = baseDirectory + "pspautotests/tests/" + testName + ".expected"; - ILOG("Preparing to execute '%s'", testName); + INFO_LOG(SYSTEM, "Preparing to execute '%s'", testName); std::string error_string; output = ""; if (!PSP_Init(coreParam, &error_string)) { - ELOG("Failed to init unittest %s : %s", testsToRun[i], error_string.c_str()); + ERROR_LOG(SYSTEM, "Failed to init unittest %s : %s", testsToRun[i], error_string.c_str()); PSP_CoreParameter().pixelWidth = pixel_xres; PSP_CoreParameter().pixelHeight = pixel_yres; return false; @@ -125,7 +124,7 @@ bool RunTests() { PSP_BeginHostFrame(); // Run the emu until the test exits - ILOG("Test: Entering runloop."); + INFO_LOG(SYSTEM, "Test: Entering runloop."); while (true) { int blockTicks = usToCycles(1000000 / 10); while (coreState == CORE_RUNNING) { @@ -136,7 +135,7 @@ bool RunTests() { // set back to running for the next frame coreState = CORE_RUNNING; } else if (coreState == CORE_POWERDOWN) { - ILOG("Finished running test %s", testName); + INFO_LOG(SYSTEM, "Finished running test %s", testName); break; } } @@ -144,7 +143,7 @@ bool RunTests() { std::ifstream expected(expectedFile.c_str(), std::ios_base::in); if (!expected) { - ELOG("Error opening expectedFile %s", expectedFile.c_str()); + ERROR_LOG(SYSTEM, "Error opening expectedFile %s", expectedFile.c_str()); break; } @@ -160,9 +159,9 @@ bool RunTests() { e = TrimNewlines(e); o = TrimNewlines(o); if (e != o) { - ELOG("DIFF on line %i!", line); - ELOG("O: %s", o.c_str()); - ELOG("E: %s", e.c_str()); + ERROR_LOG(SYSTEM, "DIFF on line %i!", line); + ERROR_LOG(SYSTEM, "O: %s", o.c_str()); + ERROR_LOG(SYSTEM, "E: %s", e.c_str()); } if (expected.eof()) { break; diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 086371085d..54687fc1e8 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -4,7 +4,6 @@ // It calls a set of methods defined in NativeApp.h. These should be implemented // by your game or app. -#include #include #include @@ -16,8 +15,9 @@ #ifndef _MSC_VER #include -#include #include +#include + #elif !defined(JNIEXPORT) // Just for better highlighting in MSVC if opening this file. // Not having types makes it get confused and say everything is wrong. @@ -49,25 +49,28 @@ struct JNIEnv {}; #define JNI_VERSION_1_6 16 #endif -#include "base/basictypes.h" -#include "base/stringutil.h" -#include "base/display.h" -#include "base/NativeApp.h" -#include "base/logging.h" -#include "base/timeutil.h" -#include "thread/threadutil.h" -#include "file/zip_read.h" -#include "input/input_state.h" -#include "input/keycodes.h" -#include "profiler/profiler.h" -#include "math/math_util.h" -#include "net/resolve.h" -#include "util/text/parsers.h" -#include "android/jni/native_audio.h" -#include "gfx/gl_common.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Net/Resolve.h" +#include "android/jni/AndroidAudio.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/Profiler/Profiler.h" +#include "Common/Math/math_util.h" +#include "Common/Data/Text/Parsers.h" + +#include "Common/Log.h" #include "Common/GraphicsContext.h" +#include "Common/StringUtils.h" +#include "Common/TimeUtil.h" + #include "AndroidGraphicsContext.h" #include "AndroidVulkanContext.h" #include "AndroidEGLContext.h" @@ -175,6 +178,44 @@ static std::map permissions; AndroidGraphicsContext *graphicsContext; +#ifndef LOG_APP_NAME +#define LOG_APP_NAME "PPSSPP" +#endif + +#ifdef _DEBUG +#define DLOG(...) __android_log_print(ANDROID_LOG_INFO, LOG_APP_NAME, __VA_ARGS__); +#else +#define DLOG(...) +#endif + +#define ILOG(...) __android_log_print(ANDROID_LOG_INFO, LOG_APP_NAME, __VA_ARGS__); +#define WLOG(...) __android_log_print(ANDROID_LOG_WARN, LOG_APP_NAME, __VA_ARGS__); +#define ELOG(...) __android_log_print(ANDROID_LOG_ERROR, LOG_APP_NAME, __VA_ARGS__); +#define FLOG(...) __android_log_print(ANDROID_LOG_FATAL, LOG_APP_NAME, __VA_ARGS__); + +#define MessageBox(a, b, c, d) __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s %s", (b), (c)); + +void AndroidLogger::Log(const LogMessage &message) { + // Log with simplified headers as Android already provides timestamp etc. + switch (message.level) { + case LogTypes::LVERBOSE: + case LogTypes::LDEBUG: + case LogTypes::LINFO: + ILOG("[%s] %s", message.log, message.msg.c_str()); + break; + case LogTypes::LERROR: + ELOG("[%s] %s", message.log, message.msg.c_str()); + break; + case LogTypes::LWARNING: + WLOG("[%s] %s", message.log, message.msg.c_str()); + break; + case LogTypes::LNOTICE: + default: + ILOG("[%s] !!! %s", message.log, message.msg.c_str()); + break; + } +} + JNIEnv* getEnv() { JNIEnv *env; int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6); @@ -192,7 +233,7 @@ jclass findClass(const char* name) { } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) { - ILOG("JNI_OnLoad"); + INFO_LOG(SYSTEM, "JNI_OnLoad"); gJvm = pjvm; // cache the JavaVM pointer auto env = getEnv(); //replace with one of your classes in the line below @@ -212,20 +253,20 @@ static void EmuThreadFunc() { gJvm->AttachCurrentThread(&env, nullptr); setCurrentThreadName("Emu"); - ILOG("Entering emu thread"); + INFO_LOG(SYSTEM, "Entering emu thread"); // Wait for render loop to get started. if (!graphicsContext || !graphicsContext->Initialized()) { - ILOG("Runloop: Waiting for displayInit..."); + INFO_LOG(SYSTEM, "Runloop: Waiting for displayInit..."); while (!graphicsContext || !graphicsContext->Initialized()) { sleep_ms(20); } } else { - ILOG("Runloop: Graphics context available! %p", graphicsContext); + INFO_LOG(SYSTEM, "Runloop: Graphics context available! %p", graphicsContext); } NativeInitGraphics(graphicsContext); - ILOG("Graphics initialized. Entering loop."); + INFO_LOG(SYSTEM, "Graphics initialized. Entering loop."); // There's no real requirement that NativeInit happen on this thread. // We just call the update/render loop here. @@ -233,7 +274,7 @@ static void EmuThreadFunc() { while (emuThreadState != (int)EmuThreadState::QUIT_REQUESTED) { UpdateRunLoopAndroid(env); } - ILOG("QUIT_REQUESTED found, left loop. Setting state to STOPPED."); + INFO_LOG(SYSTEM, "QUIT_REQUESTED found, left loop. Setting state to STOPPED."); emuThreadState = (int)EmuThreadState::STOPPED; NativeShutdownGraphics(); @@ -242,11 +283,11 @@ static void EmuThreadFunc() { graphicsContext->StopThread(); gJvm->DetachCurrentThread(); - ILOG("Leaving emu thread"); + INFO_LOG(SYSTEM, "Leaving emu thread"); } static void EmuThreadStart() { - ILOG("EmuThreadStart"); + INFO_LOG(SYSTEM, "EmuThreadStart"); emuThreadState = (int)EmuThreadState::START_REQUESTED; emuThread = std::thread(&EmuThreadFunc); } @@ -255,14 +296,14 @@ static void EmuThreadStart() { // as long as emuThreadState isn't STOPPED and/or there are still things queued up. // Only after that, call EmuThreadJoin. static void EmuThreadStop(const char *caller) { - ILOG("EmuThreadStop - stopping (%s)...", caller); + INFO_LOG(SYSTEM, "EmuThreadStop - stopping (%s)...", caller); emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; } static void EmuThreadJoin() { emuThread.join(); emuThread = std::thread(); - ILOG("EmuThreadJoin - joined"); + INFO_LOG(SYSTEM, "EmuThreadJoin - joined"); } static void ProcessFrameCommands(JNIEnv *env); @@ -497,7 +538,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init // Makes sure we get early permission grants. ProcessFrameCommands(env); - ILOG("NativeApp.init() -- begin"); + INFO_LOG(SYSTEM, "NativeApp.init() -- begin"); PROFILE_INIT(); renderer_inited = false; @@ -517,7 +558,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init systemName = GetJavaString(env, jmodel); langRegion = GetJavaString(env, jlangRegion); - ILOG("NativeApp.init(): device name: '%s'", systemName.c_str()); + INFO_LOG(SYSTEM, "NativeApp.init(): device name: '%s'", systemName.c_str()); std::string externalDir = GetJavaString(env, jexternalDir); std::string user_data_path = GetJavaString(env, jdataDir); @@ -528,8 +569,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init std::string cacheDir = GetJavaString(env, jcacheDir); std::string buildBoard = GetJavaString(env, jboard); boardName = buildBoard; - ILOG("NativeApp.init(): External storage path: %s", externalDir.c_str()); - ILOG("NativeApp.init(): Launch shortcut parameter: %s", shortcut_param.c_str()); + INFO_LOG(SYSTEM, "NativeApp.init(): External storage path: %s", externalDir.c_str()); + INFO_LOG(SYSTEM, "NativeApp.init(): Launch shortcut parameter: %s", shortcut_param.c_str()); std::string app_name; std::string app_nice_name; @@ -568,7 +609,7 @@ retry: case (int)GPUBackend::OPENGL: useCPUThread = true; if (javaGL) { - ILOG("NativeApp.init() -- creating OpenGL context (JavaGL)"); + INFO_LOG(SYSTEM, "NativeApp.init() -- creating OpenGL context (JavaGL)"); graphicsContext = new AndroidJavaEGLGraphicsContext(); } else { graphicsContext = new AndroidEGLGraphicsContext(); @@ -576,12 +617,12 @@ retry: break; case (int)GPUBackend::VULKAN: { - ILOG("NativeApp.init() -- creating Vulkan context"); + INFO_LOG(SYSTEM, "NativeApp.init() -- creating Vulkan context"); useCPUThread = false; // The Vulkan render manager manages its own thread. // We create and destroy the Vulkan graphics context in the "EGL" thread. AndroidVulkanContext *ctx = new AndroidVulkanContext(); if (!ctx->InitAPI()) { - ILOG("Failed to initialize Vulkan, switching to OpenGL"); + INFO_LOG(SYSTEM, "Failed to initialize Vulkan, switching to OpenGL"); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; SetGPUBackend(GPUBackend::OPENGL); goto retry; @@ -591,21 +632,20 @@ retry: break; } default: - ELOG("NativeApp.init(): iGPUBackend %d not supported. Switching to OpenGL.", (int)g_Config.iGPUBackend); + ERROR_LOG(SYSTEM, "NativeApp.init(): iGPUBackend %d not supported. Switching to OpenGL.", (int)g_Config.iGPUBackend); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; goto retry; - // Crash(); } if (useCPUThread) { - ILOG("NativeApp.init() - launching emu thread"); + INFO_LOG(SYSTEM, "NativeApp.init() - launching emu thread"); EmuThreadStart(); } } extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioInit(JNIEnv *, jclass) { sampleRate = optimalSampleRate; - if (NativeQueryConfig("force44khz") != "0" || optimalSampleRate == 0) { + if (optimalSampleRate == 0) { sampleRate = 44100; } if (optimalFramesPerBuffer > 0) { @@ -621,11 +661,11 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioInit(JNIEnv *, jclass) { sampleRate = 44100; } - ILOG("NativeApp.audioInit() -- Using OpenSL audio! frames/buffer: %i optimal sr: %i actual sr: %i", optimalFramesPerBuffer, optimalSampleRate, sampleRate); + INFO_LOG(AUDIO, "NativeApp.audioInit() -- Using OpenSL audio! frames/buffer: %i optimal sr: %i actual sr: %i", optimalFramesPerBuffer, optimalSampleRate, sampleRate); if (!g_audioState) { g_audioState = AndroidAudio_Init(&NativeMix, framesPerBuffer, sampleRate); } else { - ELOG("Audio state already initialized"); + ERROR_LOG(AUDIO, "Audio state already initialized"); } } @@ -634,17 +674,17 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioShutdown(JNIEnv *, jclass) AndroidAudio_Shutdown(g_audioState); g_audioState = nullptr; } else { - ELOG("Audio state already shutdown!"); + ERROR_LOG(AUDIO, "Audio state already shutdown!"); } } extern "C" void Java_org_ppsspp_ppsspp_NativeApp_resume(JNIEnv *, jclass) { - ILOG("NativeApp.resume() - resuming audio"); + INFO_LOG(SYSTEM, "NativeApp.resume() - resuming audio"); AndroidAudio_Resume(g_audioState); } extern "C" void Java_org_ppsspp_ppsspp_NativeApp_pause(JNIEnv *, jclass) { - ILOG("NativeApp.pause() - pausing audio"); + INFO_LOG(SYSTEM, "NativeApp.pause() - pausing audio"); AndroidAudio_Pause(g_audioState); } @@ -652,31 +692,31 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { if (renderer_inited && useCPUThread && graphicsContext) { // Only used in Java EGL path. EmuThreadStop("shutdown"); - ILOG("BeginAndroidShutdown"); + INFO_LOG(SYSTEM, "BeginAndroidShutdown"); graphicsContext->BeginAndroidShutdown(); // Skipping GL calls, the old context is gone. while (graphicsContext->ThreadFrame()) { - ILOG("graphicsContext->ThreadFrame executed to clear buffers"); + INFO_LOG(SYSTEM, "graphicsContext->ThreadFrame executed to clear buffers"); } - ILOG("Joining emuthread"); + INFO_LOG(SYSTEM, "Joining emuthread"); EmuThreadJoin(); - ILOG("Joined emuthread"); + INFO_LOG(SYSTEM, "Joined emuthread"); graphicsContext->ThreadEnd(); graphicsContext->ShutdownFromRenderThread(); - ILOG("Graphics context now shut down from NativeApp_shutdown"); + INFO_LOG(SYSTEM, "Graphics context now shut down from NativeApp_shutdown"); } - ILOG("NativeApp.shutdown() -- begin"); + INFO_LOG(SYSTEM, "NativeApp.shutdown() -- begin"); if (renderer_inited) { - ILOG("Shutting down renderer"); + INFO_LOG(G3D, "Shutting down renderer"); // This will be from the wrong thread? :/ graphicsContext->Shutdown(); delete graphicsContext; graphicsContext = nullptr; renderer_inited = false; } else { - ILOG("Not shutting down renderer - not initialized"); + INFO_LOG(G3D, "Not shutting down renderer - not initialized"); } inputBoxCallbacks.clear(); @@ -684,25 +724,25 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { VFSShutdown(); while (frameCommands.size()) frameCommands.pop(); - ILOG("NativeApp.shutdown() -- end"); + INFO_LOG(SYSTEM, "NativeApp.shutdown() -- end"); } // JavaEGL -extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) { +extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) { // We should be running on the render thread here. std::string errorMessage; if (renderer_inited) { // Would be really nice if we could get something on the GL thread immediately when shutting down. - ILOG("NativeApp.displayInit() restoring"); + INFO_LOG(G3D, "NativeApp.displayInit() restoring"); if (useCPUThread) { EmuThreadStop("displayInit"); graphicsContext->BeginAndroidShutdown(); - ILOG("BeginAndroidShutdown. Looping until emu thread done..."); + INFO_LOG(G3D, "BeginAndroidShutdown. Looping until emu thread done..."); // Skipping GL calls here because the old context is lost. while (graphicsContext->ThreadFrame()) { continue; } - ILOG("Joining emu thread"); + INFO_LOG(G3D, "Joining emu thread"); EmuThreadJoin(); } else { NativeShutdownGraphics(); @@ -710,23 +750,36 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, graphicsContext->ThreadEnd(); graphicsContext->ShutdownFromRenderThread(); - ILOG("Shut down both threads. Now let's bring it up again!"); + INFO_LOG(G3D, "Shut down both threads. Now let's bring it up again!"); + + if (!graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0)) { + SystemToast("Graphics initialization failed. Quitting."); + return false; + } - graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0); if (useCPUThread) { EmuThreadStart(); } else { - NativeInitGraphics(graphicsContext); + if (!NativeInitGraphics(graphicsContext)) { + // Gonna be in a weird state here, not good. + SystemToast("Failed to initialize graphics."); + return false; + } } + graphicsContext->ThreadStart(); - ILOG("Restored."); + INFO_LOG(G3D, "Restored."); } else { - ILOG("NativeApp.displayInit() first time"); - graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0); + INFO_LOG(G3D, "NativeApp.displayInit() first time"); + if (!graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0)) { + SystemToast("Graphics initialization failed. Quitting."); + return false; + } graphicsContext->ThreadStart(); renderer_inited = true; } NativeMessageReceived("recreateviews", ""); + return true; } static void recalculateDpi() { @@ -747,15 +800,15 @@ static void recalculateDpi() { pixel_in_dps_x = (float)pixel_xres / dp_xres; pixel_in_dps_y = (float)pixel_yres / dp_yres; - ILOG("RecalcDPI: display_xres=%d display_yres=%d", display_xres, display_yres); - ILOG("RecalcDPI: g_dpi=%f g_dpi_scale_x=%f g_dpi_scale_y=%f", g_dpi, g_dpi_scale_x, g_dpi_scale_y); - ILOG("RecalcDPI: dp_xscale=%f dp_yscale=%f", dp_xscale, dp_yscale); - ILOG("RecalcDPI: dp_xres=%d dp_yres=%d", dp_xres, dp_yres); - ILOG("RecalcDPI: pixel_xres=%d pixel_yres=%d", pixel_xres, pixel_yres); + INFO_LOG(G3D, "RecalcDPI: display_xres=%d display_yres=%d", display_xres, display_yres); + INFO_LOG(G3D, "RecalcDPI: g_dpi=%f g_dpi_scale_x=%f g_dpi_scale_y=%f", g_dpi, g_dpi_scale_x, g_dpi_scale_y); + INFO_LOG(G3D, "RecalcDPI: dp_xscale=%f dp_yscale=%f", dp_xscale, dp_yscale); + INFO_LOG(G3D, "RecalcDPI: dp_xres=%d dp_yres=%d", dp_xres, dp_yres); + INFO_LOG(G3D, "RecalcDPI: pixel_xres=%d pixel_yres=%d", pixel_xres, pixel_yres); } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint bufw, jint bufh, jint format) { - ILOG("NativeApp.backbufferResize(%d x %d)", bufw, bufh); + INFO_LOG(SYSTEM, "NativeApp.backbufferResize(%d x %d)", bufw, bufh); bool new_size = pixel_xres != bufw || pixel_yres != bufh; int old_w = pixel_xres; @@ -768,10 +821,10 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv recalculateDpi(); if (new_size) { - ILOG("Size change detected (previously %d,%d) - calling NativeResized()", old_w, old_h); + INFO_LOG(G3D, "Size change detected (previously %d,%d) - calling NativeResized()", old_w, old_h); NativeResized(); } else { - ILOG("NativeApp::backbufferResize: Size didn't change."); + INFO_LOG(G3D, "NativeApp::backbufferResize: Size didn't change."); } } @@ -790,20 +843,20 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendInputBox(JNIEnv *en static std::string lastSeqID = ""; if (lastSeqID == seqID) { // We send this on dismiss, so twice in many cases. - DLOG("Ignoring duplicate sendInputBox"); + DEBUG_LOG(SYSTEM, "Ignoring duplicate sendInputBox"); return; } lastSeqID = seqID; int seq = 0; if (!TryParse(seqID, &seq)) { - ELOG("Invalid inputbox seqID value: %s", seqID.c_str()); + ERROR_LOG(SYSTEM, "Invalid inputbox seqID value: %s", seqID.c_str()); return; } auto entry = inputBoxCallbacks.find(seq); if (entry == inputBoxCallbacks.end()) { - ELOG("Did not find inputbox callback for %s, shutdown?", seqID.c_str()); + ERROR_LOG(SYSTEM, "Did not find inputbox callback for %s, shutdown?", seqID.c_str()); return; } @@ -814,7 +867,6 @@ void UpdateRunLoopAndroid(JNIEnv *env) { NativeUpdate(); NativeRender(graphicsContext); - time_update(); std::lock_guard guard(frameCommandLock); if (!nativeActivity) { @@ -977,19 +1029,19 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env if (msg == "moga") { mogaVersion = prm; } else if (msg == "permission_pending") { - ILOG("STORAGE PERMISSION: PENDING"); + INFO_LOG(SYSTEM, "STORAGE PERMISSION: PENDING"); // TODO: Add support for other permissions permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_PENDING; } else if (msg == "permission_denied") { - ILOG("STORAGE PERMISSION: DENIED"); + INFO_LOG(SYSTEM, "STORAGE PERMISSION: DENIED"); permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_DENIED; } else if (msg == "permission_granted") { - ILOG("STORAGE PERMISSION: GRANTED"); + INFO_LOG(SYSTEM, "STORAGE PERMISSION: GRANTED"); permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_GRANTED; } else if (msg == "sustained_perf_supported") { sustainedPerfSupported = true; } else if (msg == "safe_insets") { - ILOG("Got insets: %s", prm.c_str()); + INFO_LOG(SYSTEM, "Got insets: %s", prm.c_str()); // We don't bother with supporting exact rectangular regions. Safe insets are good enough. int left, right, top, bottom; if (4 == sscanf(prm.c_str(), "%d:%d:%d:%d", &left, &right, &top, &bottom)) { @@ -1006,7 +1058,7 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeActivity_exitEGLRenderLoop(JNIEnv *env, jobject obj) { if (!renderLoopRunning) { - ELOG("Render loop already exited"); + ERROR_LOG(SYSTEM, "Render loop already exited"); return; } exitRenderLoop = true; @@ -1019,7 +1071,7 @@ void correctRatio(int &sz_x, int &sz_y, float scale) { float x = (float)sz_x; float y = (float)sz_y; float ratio = x / y; - ILOG("CorrectRatio: Considering size: %0.2f/%0.2f=%0.2f for scale %f", x, y, ratio, scale); + INFO_LOG(G3D, "CorrectRatio: Considering size: %0.2f/%0.2f=%0.2f for scale %f", x, y, ratio, scale); float targetRatio; // Try to get the longest dimension to match scale*PSP resolution. @@ -1034,7 +1086,7 @@ void correctRatio(int &sz_x, int &sz_y, float scale) { } float correction = targetRatio / ratio; - ILOG("Target ratio: %0.2f ratio: %0.2f correction: %0.2f", targetRatio, ratio, correction); + INFO_LOG(G3D, "Target ratio: %0.2f ratio: %0.2f correction: %0.2f", targetRatio, ratio, correction); if (ratio < targetRatio) { y *= correction; } else { @@ -1043,7 +1095,7 @@ void correctRatio(int &sz_x, int &sz_y, float scale) { sz_x = x; sz_y = y; - ILOG("Corrected ratio: %dx%d", sz_x, sz_y); + INFO_LOG(G3D, "Corrected ratio: %dx%d", sz_x, sz_y); } void getDesiredBackbufferSize(int &sz_x, int &sz_y) { @@ -1060,7 +1112,7 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) { } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) { - ILOG("NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate); + INFO_LOG(G3D, "NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate); bool changed = false; changed = changed || display_xres != xres || display_yres != yres; changed = changed || display_dpi_x != dpi || display_dpi_y != dpi; @@ -1145,7 +1197,7 @@ static void ProcessFrameCommands(JNIEnv *env) { frameCmd = frameCommands.front(); frameCommands.pop(); - ILOG("frameCommand '%s' '%s'", frameCmd.command.c_str(), frameCmd.params.c_str()); + INFO_LOG(SYSTEM, "frameCommand '%s' '%s'", frameCmd.command.c_str(), frameCmd.params.c_str()); jstring cmd = env->NewStringUTF(frameCmd.command.c_str()); jstring param = env->NewStringUTF(frameCmd.params.c_str()); @@ -1156,6 +1208,11 @@ static void ProcessFrameCommands(JNIEnv *env) { } extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(JNIEnv *env, jobject obj, jobject _surf) { + if (!graphicsContext) { + ERROR_LOG(G3D, "runEGLRenderLoop: Tried to enter without a created graphics context."); + return false; + } + // Needed for Vulkan, even if we're not using the old EGL path. exitRenderLoop = false; @@ -1164,10 +1221,10 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J ANativeWindow *wnd = _surf ? ANativeWindow_fromSurface(env, _surf) : nullptr; - WLOG("runEGLRenderLoop. display_xres=%d display_yres=%d", display_xres, display_yres); + WARN_LOG(G3D, "runEGLRenderLoop. display_xres=%d display_yres=%d", display_xres, display_yres); if (wnd == nullptr) { - ELOG("Error: Surface is null."); + ERROR_LOG(G3D, "Error: Surface is null."); renderLoopRunning = false; return false; } @@ -1175,16 +1232,17 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J auto tryInit = [&]() { if (graphicsContext->InitFromRenderThread(wnd, desiredBackbufferSizeX, desiredBackbufferSizeY, backbuffer_format, androidVersion)) { return true; + } else { + ERROR_LOG(G3D, "Failed to initialize graphics context."); + SystemToast("Failed to initialize graphics context."); + return false; } - - ELOG("Failed to initialize graphics context."); - return false; }; bool initSuccess = tryInit(); if (!initSuccess) { if (!exitRenderLoop && g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { - ILOG("Trying again, this time with OpenGL."); + INFO_LOG(G3D, "Trying again, this time with OpenGL."); SetGPUBackend(GPUBackend::OPENGL); g_Config.iGPUBackend = (int)GetGPUBackend(); @@ -1202,7 +1260,10 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J if (!exitRenderLoop) { if (!useCPUThread) { - NativeInitGraphics(graphicsContext); + if (!NativeInitGraphics(graphicsContext)) { + ERROR_LOG(G3D, "Failed to initialize graphics."); + // Gonna be in a weird state here.. + } } graphicsContext->ThreadStart(); renderer_inited = true; @@ -1217,7 +1278,7 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J } if (useCPUThread) { - ELOG("Running graphics loop"); + ERROR_LOG(SYSTEM, "Running graphics loop"); while (!exitRenderLoop) { // This is the "GPU thread". graphicsContext->ThreadFrame(); @@ -1228,7 +1289,6 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J NativeUpdate(); NativeRender(graphicsContext); - time_update(); graphicsContext->SwapBuffers(); @@ -1236,7 +1296,7 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J } } - ILOG("Leaving EGL/Vulkan render loop."); + INFO_LOG(G3D, "Leaving EGL/Vulkan render loop."); if (useCPUThread) { EmuThreadStop("exitrenderloop"); @@ -1251,10 +1311,10 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J graphicsContext->ThreadEnd(); // Shut the graphics context down to the same state it was in when we entered the render thread. - ILOG("Shutting down graphics context from render thread..."); + INFO_LOG(G3D, "Shutting down graphics context from render thread..."); graphicsContext->ShutdownFromRenderThread(); renderLoopRunning = false; - WLOG("Render loop function exited."); + WARN_LOG(G3D, "Render loop function exited."); return true; } diff --git a/android/jni/app-android.h b/android/jni/app-android.h index 49d0dab435..aa21dd9ade 100644 --- a/android/jni/app-android.h +++ b/android/jni/app-android.h @@ -2,6 +2,8 @@ #include "ppsspp_config.h" +#include "Common/LogManager.h" + #if PPSSPP_PLATFORM(ANDROID) #include @@ -10,3 +12,8 @@ jclass findClass(const char* name); JNIEnv* getEnv(); #endif + +class AndroidLogger : public LogListener { +public: + void Log(const LogMessage &message) override; +}; diff --git a/android/src/org/ppsspp/ppsspp/CameraHelper.java b/android/src/org/ppsspp/ppsspp/CameraHelper.java index 2b46fe8393..d324d50819 100644 --- a/android/src/org/ppsspp/ppsspp/CameraHelper.java +++ b/android/src/org/ppsspp/ppsspp/CameraHelper.java @@ -33,6 +33,8 @@ class CameraHelper { private long mLastFrameTime = 0; private SurfaceTexture mSurfaceTexture; + private static boolean firstRotation = true; + private int getCameraRotation() { int displayRotation = mDisplay.getRotation(); int displayDegrees = 0; @@ -49,8 +51,13 @@ class CameraHelper { } } + // Does not work if the source is smaller than the destination! static byte[] rotateNV21(final byte[] input, final int inWidth, final int inHeight, final int outWidth, final int outHeight, final int rotation) { + if (firstRotation) { + Log.i(TAG, "rotateNV21: in: " + inWidth + "x" + inHeight + " out: " + outWidth + "x" + outHeight + " rotation: " + rotation); + firstRotation = false; + } final int inFrameSize = inWidth * inHeight; final int outFrameSize = outWidth * outHeight; @@ -59,6 +66,12 @@ class CameraHelper { if (rotation == 0 || rotation == 180) { final int crop_left = (inWidth - outWidth) / 2; final int crop_top = (inHeight - outHeight) / 2; + + if (crop_left < 0 || crop_top < 0) { + // Math will fail. Return a black image. + return output; + } + for (int j = 0; j < outHeight; j++) { final int yInCol = (crop_top + j) * inWidth + crop_left; final int uvInCol = inFrameSize + ((crop_top + j) >> 1) * inWidth + crop_left; @@ -79,8 +92,14 @@ class CameraHelper { } } } else if (rotation == 90 || rotation == 270) { - int crop_left = (inWidth - outHeight) / 2; - int crop_top = (inHeight - outWidth) / 2; + final int crop_left = (inWidth - outHeight) / 2; + final int crop_top = (inHeight - outWidth) / 2; + + if (crop_left < 0 || crop_top < 0) { + // Math will fail. Return a black image. + return output; + } + for (int j = 0; j < outWidth; j++) { final int yInCol = (crop_top + j) * inWidth + crop_left; final int uvInCol = inFrameSize + ((crop_top + j) >> 1) * inWidth + crop_left; @@ -98,6 +117,8 @@ class CameraHelper { output[vOut] = input[vIn]; } } + } else { + Log.e(TAG, "Unknown rotation " + rotation); } return output; } @@ -140,10 +161,14 @@ class CameraHelper { ArrayList deviceList = new ArrayList<>(); int nrCam = Camera.getNumberOfCameras(); for (int index = 0; index < nrCam; index++) { - Camera.CameraInfo info = new Camera.CameraInfo(); - Camera.getCameraInfo(index, info); - String devName = index + ":" + (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK ? "Back Camera" : "Front Camera"); - deviceList.add(devName); + try { + Camera.CameraInfo info = new Camera.CameraInfo(); + Camera.getCameraInfo(index, info); + String devName = index + ":" + (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK ? "Back Camera" : "Front Camera"); + deviceList.add(devName); + } catch (Exception e) { + Log.e(TAG, "Failed to get camera info: " + e.toString()); + } } return deviceList; } @@ -168,14 +193,34 @@ class CameraHelper { // Set preview size List previewSizes = param.getSupportedPreviewSizes(); - mPreviewSize = previewSizes.get(0); + mPreviewSize = null; + + // Find the preview size that's the closest above or equal the requested size. + // We can not depend on the ordering of the incoming sizes. for (int i = 0; i < previewSizes.size(); i++) { - Log.d(TAG, "getSupportedPreviewSizes[" + i + "]: " + previewSizes.get(i).height + " " + previewSizes.get(i).width); - if (previewSizes.get(i).width <= 640 && previewSizes.get(i).height <= 480) { + int width = previewSizes.get(i).width; + int height = previewSizes.get(i).height; + Log.d(TAG, "getSupportedPreviewSizes[" + i + "]: " + width + "x" + height); + + // Reject too small preview sizes. + if (width < mTargetWidth || height < mTargetHeight) { + continue; + } + + if (mPreviewSize == null) { + Log.i(TAG, "Selected first viable preview size: " + width + "x" + height); + mPreviewSize = previewSizes.get(i); + } else if (width < mPreviewSize.width || height < mPreviewSize.height) { + // Only select the new size if it's smaller. + Log.i(TAG, "Selected better viable preview size: " + width + "x" + height); mPreviewSize = previewSizes.get(i); - break; } } + + if (mPreviewSize == null) { + throw new Exception("Couldn't find a viable preview size"); + } + Log.d(TAG, "setPreviewSize(" + mPreviewSize.width + ", " + mPreviewSize.height + ")"); param.setPreviewSize(mPreviewSize.width, mPreviewSize.height); @@ -197,7 +242,7 @@ class CameraHelper { mCamera.setPreviewCallback(mPreviewCallback); mCamera.startPreview(); mIsCameraRunning = true; - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, "Cannot start camera: " + e.toString()); } } diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 2b6f2d4890..477d7b42cf 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -18,7 +18,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.PixelFormat; -import android.graphics.Point; import android.media.AudioManager; import android.net.Uri; import android.os.Build; @@ -51,11 +50,12 @@ import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; +@SuppressWarnings("ConstantConditions") public abstract class NativeActivity extends Activity { // Remember to loadLibrary your JNI .so in a static {} block // Adjust these as necessary - private static String TAG = "PPSSPPNativeActivity"; + private static final String TAG = "PPSSPPNativeActivity"; // Allows us to skip a lot of initialization on secondary calls to onCreate. private static boolean initialized = false; @@ -98,7 +98,7 @@ public abstract class NativeActivity extends Activity { // This is to avoid losing the game/menu state etc when we are just // switched-away from or rotated etc. private boolean shuttingDown; - private static int RESULT_LOAD_IMAGE = 1; + private static final int RESULT_LOAD_IMAGE = 1; // Allow for multiple connected gamepads but just consider them the same for now. // Actually this is not entirely true, see the code. @@ -132,10 +132,6 @@ public abstract class NativeActivity extends Activity { public native void registerCallbacks(); public native void unregisterCallbacks(); - public boolean useLowProfileButtons() { - return true; - } - NativeRenderer getRenderer() { return nativeRenderer; } @@ -209,7 +205,7 @@ public abstract class NativeActivity extends Activity { } @Override - public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { + public void onRequestPermissionsResult(int requestCode, String [] permissions, int[] grantResults) { switch (requestCode) { case REQUEST_CODE_STORAGE_PERMISSION: if (permissionsGranted(permissions, grantResults)) { @@ -248,7 +244,7 @@ public abstract class NativeActivity extends Activity { } powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - if (powerManager.isSustainedPerformanceModeSupported()) { + if (powerManager != null && powerManager.isSustainedPerformanceModeSupported()) { sustainedPerfSupported = true; NativeApp.sendMessage("sustained_perf_supported", "1"); } @@ -259,10 +255,10 @@ public abstract class NativeActivity extends Activity { Log.d(TAG, "Landscape: " + landscape); // Get system information - ApplicationInfo appInfo = null; - PackageManager packMgmr = getPackageManager(); String packageName = getPackageName(); + + ApplicationInfo appInfo; try { appInfo = packMgmr.getApplicationInfo(packageName, 0); } catch (NameNotFoundException e) { @@ -345,22 +341,20 @@ public abstract class NativeActivity extends Activity { private void updateSustainedPerformanceMode() { if (sustainedPerfSupported) { // Query the native application on the desired rotation. - int enable = 0; String str = NativeApp.queryConfig("sustainedPerformanceMode"); try { - enable = Integer.parseInt(str); + int enable = Integer.parseInt(str); + getWindow().setSustainedPerformanceMode(enable != 0); } catch (NumberFormatException e) { Log.e(TAG, "Invalid perf mode: " + str); - return; } - getWindow().setSustainedPerformanceMode(enable != 0); } } @TargetApi(Build.VERSION_CODES.GINGERBREAD) private void updateScreenRotation(String cause) { // Query the native application on the desired rotation. - int rot = 0; + int rot; String rotString = NativeApp.queryConfig("screenRotation"); try { rot = Integer.parseInt(rotString); @@ -407,12 +401,11 @@ public abstract class NativeActivity extends Activity { } // Compute our _desired_ systemUiVisibility - int flags = 0; - if (useLowProfileButtons()) { - flags |= View.SYSTEM_UI_FLAG_LOW_PROFILE; - } + int flags = View.SYSTEM_UI_FLAG_LOW_PROFILE; if (useImmersive()) { - flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; + flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; + flags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; + flags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; } View decorView = getWindow().peekDecorView(); @@ -434,7 +427,7 @@ public abstract class NativeActivity extends Activity { } } - private Runnable mEmulationRunner = new Runnable() { + private final Runnable mEmulationRunner = new Runnable() { @Override public void run() { Log.i(TAG, "Starting the render loop: " + mSurface); @@ -536,6 +529,9 @@ public abstract class NativeActivity extends Activity { public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); updateSustainedPerformanceMode(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + updateSystemUiVisibility(); + } } public void notifySurface(Surface surface) { @@ -611,6 +607,7 @@ public abstract class NativeActivity extends Activity { @Override protected void onDestroy() { super.onDestroy(); + Log.i(TAG, "onDestroy"); if (javaGL) { if (nativeRenderer.isRenderingFrame()) { Log.i(TAG, "Waiting for renderer to finish."); @@ -623,21 +620,23 @@ public abstract class NativeActivity extends Activity { tries--; } while (nativeRenderer.isRenderingFrame() && tries > 0); } - Log.i(TAG, "onDestroy"); mGLSurfaceView.onDestroy(); - // Probably vain attempt to help the garbage collector... mGLSurfaceView = null; - audioFocusChangeListener = null; - audioManager = null; } else { mSurfaceView.onDestroy(); mSurfaceView = null; } + + // Probably vain attempt to help the garbage collector... + audioFocusChangeListener = null; + audioManager = null; + sizeManager.setSurfaceView(null); if (mPowerSaveModeReceiver != null) { mPowerSaveModeReceiver.destroy(this); mPowerSaveModeReceiver = null; } + // TODO: Can we ensure that the GL thread has stopped rendering here? // I've seen crashes that seem to indicate that sometimes it hasn't... NativeApp.audioShutdown(); @@ -692,6 +691,7 @@ public abstract class NativeActivity extends Activity { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { updateSystemUiVisibility(); } + // OK, config should be initialized, we can query for screen rotation. if (javaGL || Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { updateScreenRotation("onResume"); @@ -986,30 +986,29 @@ public abstract class NativeActivity extends Activity { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) { Uri selectedImage = data.getData(); - String[] filePathColumn = {MediaStore.Images.Media.DATA}; - Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null); - cursor.moveToFirst(); - int columnIndex = cursor.getColumnIndex(filePathColumn[0]); - String picturePath = cursor.getString(columnIndex); - cursor.close(); - NativeApp.sendMessage("bgImage_updated", picturePath); + if (selectedImage != null) { + String[] filePathColumn = {MediaStore.Images.Media.DATA}; + Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null); + cursor.moveToFirst(); + int columnIndex = cursor.getColumnIndex(filePathColumn[0]); + String picturePath = cursor.getString(columnIndex); + cursor.close(); + NativeApp.sendMessage("bgImage_updated", picturePath); + } } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) - @SuppressWarnings("deprecation") private AlertDialog.Builder createDialogBuilderWithTheme() { return new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - @SuppressWarnings("deprecation") private AlertDialog.Builder createDialogBuilderWithDeviceTheme() { return new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_DARK); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - @SuppressWarnings("deprecation") private AlertDialog.Builder createDialogBuilderWithDeviceThemeAndUiVisibility() { AlertDialog.Builder bld = new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_DARK); bld.setOnDismissListener(new DialogInterface.OnDismissListener() { @@ -1060,7 +1059,7 @@ public abstract class NativeActivity extends Activity { else bld = createDialogBuilderNew(); - AlertDialog dlg = bld + AlertDialog.Builder builder = bld .setView(fl) .setTitle(title) .setPositiveButton(defaultAction, new DialogInterface.OnClickListener() { @@ -1076,15 +1075,17 @@ public abstract class NativeActivity extends Activity { NativeApp.sendInputBox(seqID, false, ""); d.cancel(); } - }) - .setOnDismissListener(new DialogInterface.OnDismissListener() { + }); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) { + builder.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface d) { NativeApp.sendInputBox(seqID, false, ""); updateSystemUiVisibility(); } - }) - .create(); + }); + } + AlertDialog dlg = builder.create(); dlg.setCancelable(true); dlg.show(); @@ -1183,11 +1184,10 @@ public abstract class NativeActivity extends Activity { inputMethodManager.toggleSoftInputFromWindow(surfView.getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0); return true; } else if (command.equals("inputbox")) { - String seqID = ""; String title = "Input"; String defString = ""; String[] param = params.split(":@:", 3); - seqID = param[0]; + String seqID = param[0]; if (param.length > 1 && param[1].length() > 0) title = param[1]; if (param.length > 2) @@ -1197,7 +1197,7 @@ public abstract class NativeActivity extends Activity { return true; } else if (command.equals("vibrate")) { int milliseconds = -1; - if (params != "") { + if (!params.equals("")) { try { milliseconds = Integer.parseInt(params); } catch (NumberFormatException e) { diff --git a/android/src/org/ppsspp/ppsspp/NativeRenderer.java b/android/src/org/ppsspp/ppsspp/NativeRenderer.java index 31df096943..58d4de48d8 100644 --- a/android/src/org/ppsspp/ppsspp/NativeRenderer.java +++ b/android/src/org/ppsspp/ppsspp/NativeRenderer.java @@ -2,6 +2,7 @@ package org.ppsspp.ppsspp; import android.opengl.GLSurfaceView; import android.util.Log; +import android.widget.Toast; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; @@ -12,7 +13,8 @@ import javax.microedition.khronos.opengles.GL10; public class NativeRenderer implements GLSurfaceView.Renderer { private static String TAG = "NativeRenderer"; private NativeActivity mActivity; - private boolean inFrame; + private boolean inFrame = false; + private boolean failed = false; NativeRenderer(NativeActivity act) { mActivity = act; @@ -22,6 +24,9 @@ public class NativeRenderer implements GLSurfaceView.Renderer { return inFrame; } + // TODO: Make use of this somehow. + public boolean hasFailedInit() { return failed; } + public void onDrawFrame(GL10 unused /*use GLES20*/) { inFrame = true; displayRender(); @@ -29,6 +34,7 @@ public class NativeRenderer implements GLSurfaceView.Renderer { } public void onSurfaceCreated(GL10 gl, EGLConfig config) { + failed = false; Log.i(TAG, "NativeRenderer: onSurfaceCreated"); EGL10 egl = (EGL10)EGLContext.getEGL(); @@ -47,17 +53,18 @@ public class NativeRenderer implements GLSurfaceView.Renderer { } else { Log.e(TAG, "egl == null"); } - // Log.i(TAG, "onSurfaceCreated - EGL context is new or was lost"); - // Actually, it seems that it is here we should recreate lost GL objects. - displayInit(); + + if (!displayInit()) { + Log.e(TAG, "Display init failed"); + Toast.makeText(mActivity, "Failed to initialize rendering. Close the app and try again.", Toast.LENGTH_LONG); + failed = true; + } } - public void onSurfaceChanged(GL10 unused, int width, int height) { - } + public void onSurfaceChanged(GL10 unused, int width, int height) {} // Note: This also means "device lost" and you should reload // all buffered objects. - public native void displayInit(); - + public native boolean displayInit(); public native void displayRender(); } diff --git a/assets/compat.ini b/assets/compat.ini index 21b9db4bbb..267dd21712 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -85,6 +85,15 @@ ULJM05404 = true NPJH50558 = true ULJS00456 = true ULJS00454 = true + +# Tales of Phantasia: Full Voice Edition +# Attempted workaround for stencil testing driver bug on Arm Exynos (similar to the previous Adreno bug). +# Seems that writing to depth disables a faulty optimization it's trying to do (as we saw in stencil draw). +ULJS00079 = true +ULJS19016 = true +UCAS40110 = true +NPJH50854 = true + # Heroes Phantasia Limited Edition Disc requires pixel depth rounding. ULJS00455 = true # Phantasy Star games flickering @@ -115,6 +124,12 @@ NPJH90157 = true # Infinity demo # Nayuta no Kiseki see #8744 - flickering textures at some locations NPJH50625 = true +# Nayuta no Kiseki might improve with pixel depth rounding. See issue #8744. +ULJM06113 = true +NPJH50625 = true +ULJM08069 = true +NPJH50625 = true + [DepthRangeHack] # Phantasy Star Portable 2 and Infinity both use viewport depth outside [0, 1]. # This gets clamped in our current implementation, but attempts to fix it run into @@ -150,6 +165,32 @@ ULES00637 = true ULKS46126 = true ULUS10249 = true +# Metal Gear Solid : Peace Walker (see issue #12348) +ULUS10509 = true +ULES01372 = true +ULJM08038 = true +NPJH50045 = true +ULJM05630 = true +NPJH90082 = true +NPJH90063 = true + +# Metal Gear Solid : Peace Walker Demo Ops (see issue #12348) +NPUH90066 = true +NPHH00145 = true +NPEH90023 = true + +# Metal Gear Solid: Portable Ops (see issue #12348) +ULES00645 = true +ULJM05193 = true +ULJM05227 = true +ULUS10202 = true +ULES01003 = true +ULJM05261 = true +ULUS10290 = true +ULED90040 = true +ULJM05284 = true +ULES00645 = true + [ClearToRAM] # SOCOM Navy Seals games require this. See issue #8973. # Navy Seals : Tactical Strike @@ -432,6 +473,8 @@ ULES01372 = true ULJM08038 = true NPJH50045 = true ULJM05630 = true +NPJH90082 = true +NPJH90063 = true # Star Ocean : Second Evolution ULUS10375 = true ULES01187 = true @@ -602,6 +645,29 @@ NPEH00065 = true # Ys Seven NPJH50350 = true # Ys Seven ULJM08041 = true # Ys Seven +# Burnout Legends +ULES00125 = true +ULUS10025 = true +ULJM05228 = true +NPJH50305 = true +ULJM05049 = true +ULKS46027 = true +ULAS42019 = true + +# Burnout Dominator +ULUS10236 = true +ULES00750 = true +ULJM05242 = true +ULJM05371 = true +NPJH50304 = true +ULES00703 = true + +# Test Drive Unlimited +ULET00386 = true +ULUS10249 = true +ULES00637 = true +ULKS46126 = true + # Note! This whole flag is disabled temporarily by appending "Disabled" to its name). See 7914 [YugiohSaveFixDisabled] # The cause of Yu-gi-oh series 's bad save (cannot save) are load "save status" and use cwcheat, @@ -749,6 +815,9 @@ ULES01037 = true # 7 Wonders of the Ancient World ULES00364 = true ULUS10132 = true +# Homebrew Kurok (we don't normally add homebrew here but it has a distinctive GameID) +KURO00767 = true + [JitInvalidationHack] # This is an absolutely awful hack that somehow prevents issues when clearing the JIT, # if the game has copied code with EmuHack opcodes or something. Hopefully will be able @@ -814,3 +883,15 @@ ULJM05005 = true ULES00016 = true ULUS10005 = true ULJM05005 = true + +[ReportSmallMemStick] +# Harry Potter and the Goblet of Fire - issue #13266 +ULUS10032 = true +ULES00210 = true +# Street Fighter Alpha 3 MAX - issue #10462 +ULJM05082 = true +ULUS10062 = true +ULES00235 = true +ULJM05225 = true +CPCS01043 = true +ULUS10062 = true diff --git a/assets/gamecontrollerdb.txt b/assets/gamecontrollerdb.txt index 76ba6498a5..8913052eaa 100644 --- a/assets/gamecontrollerdb.txt +++ b/assets/gamecontrollerdb.txt @@ -195,3 +195,4 @@ bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,b 030000000d0f0000ee00000011010000,HORI CO.,LTD. HORIPAD mini4,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, 030000000d0f0000c100000011010000,HORI CO.,LTD. HORIPAD S,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, 03000000ad1b000003f5000033050000,Hori Fighting Stick VX,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,-leftx:h0.8,+leftx:h0.2,-lefty:h0.1,+lefty:h0.4,lefttrigger:b6,righttrigger:b7, +03000000c82d00000260000011010000,8Bitdo SF30 Pro 8BitDo SN30 Pro+,platform:Linux,a:b1,b:b0,x:b4,y:b3,back:b10,guide:b2,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, diff --git a/assets/lang b/assets/lang index 3a5eb3fcb4..d5a2a51942 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 3a5eb3fcb4852cb28c9138e78492effa0c227253 +Subproject commit d5a2a51942377820764604d9bb424fa9a879c4bd diff --git a/assets/sfx_back.wav b/assets/sfx_back.wav new file mode 100644 index 0000000000..85ae898c11 Binary files /dev/null and b/assets/sfx_back.wav differ diff --git a/assets/sfx_confirm.wav b/assets/sfx_confirm.wav new file mode 100644 index 0000000000..87d7b4eb2b Binary files /dev/null and b/assets/sfx_confirm.wav differ diff --git a/assets/sfx_select.wav b/assets/sfx_select.wav new file mode 100644 index 0000000000..3e65be69a5 Binary files /dev/null and b/assets/sfx_select.wav differ diff --git a/assets/sfx_toggle_off.wav b/assets/sfx_toggle_off.wav new file mode 100644 index 0000000000..bab33853f8 Binary files /dev/null and b/assets/sfx_toggle_off.wav differ diff --git a/assets/sfx_toggle_on.wav b/assets/sfx_toggle_on.wav new file mode 100644 index 0000000000..74f9ff2220 Binary files /dev/null and b/assets/sfx_toggle_on.wav differ diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index 4771bdfe09..6c01db9bd0 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -170,7 +170,7 @@ SettingDefaultValue2=1.0 SettingMaxValue2=2.0 SettingMinValue2=0.0 SettingStep2=0.1 -SettingName3=Constrast +SettingName3=Contrast SettingDefaultValue3=1.0 SettingMaxValue3=3.0 SettingMinValue3=0.1 @@ -180,4 +180,8 @@ SettingDefaultValue4=1.0 SettingMaxValue4=2.0 SettingMinValue4=0.1 SettingStep4=0.05 - +[Tex4xBRZ] +Type=Texture +Name=4xBRZ +Author=Hyllian +Compute=tex_4xbrz.csh diff --git a/assets/shaders/psp_color.fsh b/assets/shaders/psp_color.fsh new file mode 100644 index 0000000000..aad99df883 --- /dev/null +++ b/assets/shaders/psp_color.fsh @@ -0,0 +1,58 @@ +/* + psp_color vertex shader + + Original code written by hunterk, modified by Pokefan531 and + released into the public domain + + 'Ported' (i.e. copy/paste) to PPSSPP format by jdgleaver + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + Notes: This shader replicates the LCD dynamics of the PSP 1000 and PSP 2000 +*/ + +//================ +#ifdef GL_ES +precision mediump float; +precision mediump int; +// For android, use this instead... +//precision highp float; +//precision highp int; +// +#endif + +//================ +#define target_gamma 2.21 +#define display_gamma 2.2 +#define r 0.98 +#define g 0.795 +#define b 0.98 +#define rg 0.04 +#define rb 0.01 +#define gr 0.20 +#define gb 0.01 +#define br -0.18 +#define bg 0.165 + +//================ +uniform sampler2D sampler0; +varying vec2 v_texcoord0; + +//================ +void main() +{ + // Apply colour correction + vec3 screen = pow(texture2D(sampler0, v_texcoord0.xy).rgb, vec3(target_gamma)); + screen = clamp(screen, 0.0, 1.0); + screen = pow( + mat3(r, rg, rb, + gr, g, gb, + br, bg, b) * screen, + vec3(1.0 / display_gamma) + ); + + gl_FragColor = vec4(screen, 1.0); +} diff --git a/assets/shaders/psp_color.ini b/assets/shaders/psp_color.ini new file mode 100644 index 0000000000..73cae04bb2 --- /dev/null +++ b/assets/shaders/psp_color.ini @@ -0,0 +1,6 @@ +[PSP Color] +Name=PSP Color +Author=hunterk, Pokefan531 (ported by jdgleaver) +Fragment=psp_color.fsh +Vertex=psp_color.vsh +OutputResolution=True diff --git a/assets/shaders/psp_color.vsh b/assets/shaders/psp_color.vsh new file mode 100644 index 0000000000..0353e17dae --- /dev/null +++ b/assets/shaders/psp_color.vsh @@ -0,0 +1,23 @@ +/* + psp_color vertex shader + + Original code written by hunterk, modified by Pokefan531 and + released into the public domain + + 'Ported' (i.e. copy/paste) to PPSSPP format by jdgleaver + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. +*/ + +attribute vec4 a_position; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; + +void main() +{ + v_texcoord0 = a_texcoord0; // + 0.000001; // HLSL precision workaround (is this needed???) + gl_Position = a_position; +} diff --git a/assets/shaders/tex_4xbrz.csh b/assets/shaders/tex_4xbrz.csh new file mode 100644 index 0000000000..2a72a7f3b5 --- /dev/null +++ b/assets/shaders/tex_4xbrz.csh @@ -0,0 +1,279 @@ +// 4xBRZ shader - Copyright (C) 2014-2016 DeSmuME team (GPL2+) +// Hyllian's xBR-vertex code and texel mapping +// Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com +#define BLEND_ALPHA 1 +#define BLEND_NONE 0 +#define BLEND_NORMAL 1 +#define BLEND_DOMINANT 2 +#define LUMINANCE_WEIGHT 1.0 +#define EQUAL_COLOR_TOLERANCE 30.0/255.0 +#define STEEP_DIRECTION_THRESHOLD 2.2 +#define DOMINANT_DIRECTION_THRESHOLD 3.6 + +float reduce(vec4 color) { + return dot(color.rgb, vec3(65536.0, 256.0, 1.0)); +} + +float DistYCbCr(vec4 pixA, vec4 pixB) { + // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.2020_conversion + const vec3 K = vec3(0.2627, 0.6780, 0.0593); + const mat3 MATRIX = mat3(K, + -.5 * K.r / (1.0 - K.b), -.5 * K.g / (1.0 - K.b), .5, + .5, -.5 * K.g / (1.0 - K.r), -.5 * K.b / (1.0 - K.r)); + vec4 diff = pixA - pixB; + vec3 YCbCr = diff.rgb * MATRIX; + YCbCr.x *= LUMINANCE_WEIGHT; + float d = length(YCbCr); + return sqrt(pixA.a * pixB.a * d * d + diff.a * diff.a); +} + +bool IsPixEqual(const vec4 pixA, const vec4 pixB) { + return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE); +} + +bool IsBlendingNeeded(const ivec4 blend) { + ivec4 diff = blend - ivec4(BLEND_NONE); + return diff.x != 0 || diff.y != 0 || diff.z != 0 || diff.w != 0; +} + +vec4 applyScalingf(uvec2 origxy, uvec2 xy) { + float dx = 1.0 / params.width; + float dy = 1.0 / params.height; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + uvec4 t1 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y - 2); // A1 B1 C1 + uvec4 t2 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y - 1); // A B C + uvec4 t3 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y + 0); // D E F + uvec4 t4 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y + 1); // G H I + uvec4 t5 = uvec4(origxy.x - 1, origxy.x, origxy.x + 1, origxy.y + 2); // G5 H5 I5 + uvec4 t6 = uvec4(origxy.x - 2, origxy.y - 1, origxy.y, origxy.y + 1); // A0 D0 G0 + uvec4 t7 = uvec4(origxy.x + 2, origxy.y - 1, origxy.y, origxy.y + 1); // C4 F4 I4 + + vec2 f = fract(vec2(float(xy.x) / float(params.scale), float(xy.y) / float(params.scale))); + + //--------------------------------------- + // Input Pixel Mapping: |21|22|23| + // 19|06|07|08|09 + // 18|05|00|01|10 + // 17|04|03|02|11 + // |15|14|13| + + vec4 src[25]; + + src[21] = readColorf(t1.xw); + src[22] = readColorf(t1.yw); + src[23] = readColorf(t1.zw); + src[ 6] = readColorf(t2.xw); + src[ 7] = readColorf(t2.yw); + src[ 8] = readColorf(t2.zw); + src[ 5] = readColorf(t3.xw); + src[ 0] = readColorf(t3.yw); + src[ 1] = readColorf(t3.zw); + src[ 4] = readColorf(t4.xw); + src[ 3] = readColorf(t4.yw); + src[ 2] = readColorf(t4.zw); + src[15] = readColorf(t5.xw); + src[14] = readColorf(t5.yw); + src[13] = readColorf(t5.zw); + src[19] = readColorf(t6.xy); + src[18] = readColorf(t6.xz); + src[17] = readColorf(t6.xw); + src[ 9] = readColorf(t7.xy); + src[10] = readColorf(t7.xz); + src[11] = readColorf(t7.xw); + + float v[9]; + v[0] = reduce(src[0]); + v[1] = reduce(src[1]); + v[2] = reduce(src[2]); + v[3] = reduce(src[3]); + v[4] = reduce(src[4]); + v[5] = reduce(src[5]); + v[6] = reduce(src[6]); + v[7] = reduce(src[7]); + v[8] = reduce(src[8]); + + ivec4 blendResult = ivec4(BLEND_NONE); + + // Preprocess corners + // Pixel Tap Mapping: --|--|--|--|-- + // --|--|07|08|-- + // --|05|00|01|10 + // --|04|03|02|11 + // --|--|14|13|-- + // Corner (1, 1) + if ( ((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) == false) { + float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1])); + float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02; + blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: --|--|--|--|-- + // --|06|07|--|-- + // 18|05|00|01|-- + // 17|04|03|02|-- + // --|15|14|--|-- + // Corner (0, 1) + if ( ((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) == false) { + float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0])); + float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00; + blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: --|--|22|23|-- + // --|06|07|08|09 + // --|05|00|01|10 + // --|--|03|02|-- + // --|--|--|--|-- + // Corner (1, 0) + if ( ((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) == false) { + float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8])); + float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08; + blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: --|21|22|--|-- + // 19|06|07|08|-- + // 18|05|00|01|-- + // --|04|03|--|-- + // --|--|--|--|-- + // Corner (0, 0) + if ( ((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) == false) { + float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7])); + float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00; + blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + vec4 dst[16]; + dst[ 0] = src[0]; + dst[ 1] = src[0]; + dst[ 2] = src[0]; + dst[ 3] = src[0]; + dst[ 4] = src[0]; + dst[ 5] = src[0]; + dst[ 6] = src[0]; + dst[ 7] = src[0]; + dst[ 8] = src[0]; + dst[ 9] = src[0]; + dst[10] = src[0]; + dst[11] = src[0]; + dst[12] = src[0]; + dst[13] = src[0]; + dst[14] = src[0]; + dst[15] = src[0]; + + // Scale pixel + if (IsBlendingNeeded(blendResult) == true) { + float dist_01_04 = DistYCbCr(src[1], src[4]); + float dist_03_08 = DistYCbCr(src[3], src[8]); + bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]); + bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]); + bool needBlend = (blendResult[2] != BLEND_NONE); + bool doLineBlend = ( blendResult[2] >= BLEND_DOMINANT || + ((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) || + (blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) || + (IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[0], src[2]) == false) ) == false ); + + vec4 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3]; + dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + + dist_01_04 = DistYCbCr(src[7], src[2]); + dist_03_08 = DistYCbCr(src[1], src[6]); + haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]); + haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]); + needBlend = (blendResult[1] != BLEND_NONE); + doLineBlend = ( blendResult[1] >= BLEND_DOMINANT || + !((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) || + (blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) || + (IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) ); + + blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1]; + dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[ 8] = mix(dst[ 8], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 9] = mix(dst[ 9], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[10] = mix(dst[10], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + + dist_01_04 = DistYCbCr(src[5], src[8]); + dist_03_08 = DistYCbCr(src[7], src[4]); + haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]); + haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]); + needBlend = (blendResult[0] != BLEND_NONE); + doLineBlend = ( blendResult[0] >= BLEND_DOMINANT || + !((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) || + (blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) || + (IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) ); + + blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7]; + dst[ 0] = mix(dst[ 0], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[ 5] = mix(dst[ 5], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 6] = mix(dst[ 6], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[ 7] = mix(dst[ 7], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + + dist_01_04 = DistYCbCr(src[3], src[6]); + dist_03_08 = DistYCbCr(src[5], src[2]); + haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]); + haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]); + needBlend = (blendResult[3] != BLEND_NONE); + doLineBlend = ( blendResult[3] >= BLEND_DOMINANT || + !((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) || + (blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) || + (IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) ); + + blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5]; + dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[14] = mix(dst[14], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[15] = mix(dst[15], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[ 4] = mix(dst[ 4], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + } + + // select output pixel + vec4 res = mix(mix(mix(mix(dst[ 6], dst[ 7], step(0.25, f.x)), + mix(dst[ 8], dst[ 9], step(0.75, f.x)), + step(0.50, f.x)), + mix(mix(dst[ 5], dst[ 0], step(0.25, f.x)), + mix(dst[ 1], dst[10], step(0.75, f.x)), + step(0.50, f.x)), + step(0.25, f.y)), + mix(mix(mix(dst[ 4], dst[ 3], step(0.25, f.x)), + mix(dst[ 2], dst[11], step(0.75, f.x)), + step(0.50, f.x)), + mix(mix(dst[15], dst[14], step(0.25, f.x)), + mix(dst[13], dst[12], step(0.75, f.x)), + step(0.50, f.x)), + step(0.75, f.y)), + step(0.50, f.y)); + + return res; +} + +uint applyScalingu(uvec2 origxy, uvec2 xy) { + return packUnorm4x8(applyScalingf(origxy, xy)); +} diff --git a/b.sh b/b.sh index c901e4fadc..a707c92f79 100755 --- a/b.sh +++ b/b.sh @@ -22,6 +22,9 @@ do --rpi) CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/raspberry.armv7.cmake ${CMAKE_ARGS}" ;; + --rpi64) + CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/raspberry.armv8.cmake ${CMAKE_ARGS}" + ;; --android) CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=android/android.toolchain.cmake ${CMAKE_ARGS}" TARGET_OS=Android PACKAGE=1 diff --git a/build.gradle b/build.gradle index 8e0dd83012..dad9ef0a6c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' + classpath 'com.android.tools.build:gradle:4.0.1' } } diff --git a/cmake/Toolchains/beagleboard.cmake b/cmake/Toolchains/beagleboard.cmake index 310d13f071..a8648f26f6 100644 --- a/cmake/Toolchains/beagleboard.cmake +++ b/cmake/Toolchains/beagleboard.cmake @@ -1,4 +1,3 @@ -set(ARMV7 ON) set(USING_FBDEV ON) set(ARCH_FLAGS "-march=armv7-a -mfpu=neon -mcpu=cortex-a8") diff --git a/cmake/Toolchains/generic.armv7.cmake b/cmake/Toolchains/generic.armv7.cmake index 65a60943f4..a87da96179 100644 --- a/cmake/Toolchains/generic.armv7.cmake +++ b/cmake/Toolchains/generic.armv7.cmake @@ -1,5 +1,3 @@ -set(ARMV7 ON) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a -mfpu=neon -mcpu=cortex-a9") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a -mfpu=neon -mcpu=cortex-a9") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=armv7-a -mfpu=neon -mcpu=cortex-a9") diff --git a/cmake/Toolchains/raspberry.armv7.cmake b/cmake/Toolchains/raspberry.armv7.cmake index b9a8b46a65..8fa4dc6888 100644 --- a/cmake/Toolchains/raspberry.armv7.cmake +++ b/cmake/Toolchains/raspberry.armv7.cmake @@ -38,5 +38,4 @@ if(NOT PPSSPP_PI_MODEL4) set(USING_FBDEV ON) endif() set(USING_GLES2 ON) -set(ARMV7 ON) set(USE_WAYLAND_WSI OFF) diff --git a/cmake/Toolchains/raspberry.armv8.cmake b/cmake/Toolchains/raspberry.armv8.cmake new file mode 100644 index 0000000000..1bac90de9f --- /dev/null +++ b/cmake/Toolchains/raspberry.armv8.cmake @@ -0,0 +1,41 @@ +file(READ "/sys/firmware/devicetree/base/compatible" PPSSPP_PI_MODEL) + +if(PPSSPP_PI_MODEL MATCHES "raspberrypi,4") + set(PPSSPP_PI_MODEL4 ON) +endif() + +if(NOT PPSSPP_PI_MODEL4 AND NOT EXISTS "/opt/vc/include/bcm_host.h") + message(FATAL_ERROR "RaspberryPI platform not recognized") +endif() + +include_directories(SYSTEM + /opt/vc/include + /opt/vc/include/interface/vcos/pthreads + /opt/vc/include/interface/vmcx_host/linux +) + +if(NOT PPSSPP_PI_MODEL4) + add_definitions( + -DPPSSPP_PLATFORM_RPI=1 + -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + ) +endif() + +if(PPSSPP_PI_MODEL4) + set(ARCH_FLAGS "-march=armv8-a+crc -mtune=cortex-a72 -funsafe-math-optimizations") +else() + set(ARCH_FLAGS "-mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard") +endif() +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH_FLAGS}" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_FLAGS}" CACHE STRING "" FORCE) +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${ARCH_FLAGS}" CACHE STRING "" FORCE) + +set(CMAKE_EXE_LINKER_FLAGS "-L/opt/vc/lib" CACHE STRING "" FORCE) + +if(NOT PPSSPP_PI_MODEL4) + set(OPENGL_LIBRARIES brcmGLESv2 bcm_host) + set(EGL_LIBRARIES brcmEGL) + set(USING_FBDEV ON) +endif() +set(USING_GLES2 ON) +set(USE_WAYLAND_WSI OFF) diff --git a/cmake/Toolchains/vero4k.armv8.cmake b/cmake/Toolchains/vero4k.armv8.cmake index 28720127b3..9ce852199a 100644 --- a/cmake/Toolchains/vero4k.armv8.cmake +++ b/cmake/Toolchains/vero4k.armv8.cmake @@ -17,6 +17,5 @@ set(EGL_LIBRARIES /opt/vero3/lib/libEGL.so) set(USING_GLES2 ON) set(USING_EGL ON) set(USING_FBDEV ON) -set(ARMV7 ON) set(FORCED_CPU armv7) set(USING_X11_VULKAN OFF CACHE BOOL "" FORCE) diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 322d1c368b..16b4adbd7e 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -13,7 +13,7 @@ if(ANDROID) set(ENABLE_HLSL OFF CACHE BOOL "let's not build HLSL support we don't need" FORCE) endif() -add_subdirectory(glslang) +add_subdirectory(glslang EXCLUDE_FROM_ALL) add_subdirectory(snappy) add_subdirectory(udis86) add_subdirectory(SPIRV-Cross-build) diff --git a/ext/native/ext/cityhash/COPYING b/ext/cityhash/COPYING similarity index 100% rename from ext/native/ext/cityhash/COPYING rename to ext/cityhash/COPYING diff --git a/ext/native/ext/cityhash/README b/ext/cityhash/README similarity index 100% rename from ext/native/ext/cityhash/README rename to ext/cityhash/README diff --git a/ext/native/ext/cityhash/city.cpp b/ext/cityhash/city.cpp similarity index 100% rename from ext/native/ext/cityhash/city.cpp rename to ext/cityhash/city.cpp diff --git a/ext/native/ext/cityhash/city.h b/ext/cityhash/city.h similarity index 100% rename from ext/native/ext/cityhash/city.h rename to ext/cityhash/city.h diff --git a/ext/native/ext/cityhash/citycrc.h b/ext/cityhash/citycrc.h similarity index 100% rename from ext/native/ext/cityhash/citycrc.h rename to ext/cityhash/citycrc.h diff --git a/ext/disarm.cpp b/ext/disarm.cpp index 90c89c16b5..57b34b0b53 100644 --- a/ext/disarm.cpp +++ b/ext/disarm.cpp @@ -66,12 +66,12 @@ #pragma GCC diagnostic ignored "-Wstring-plus-int" #endif -#include -#include -#include +#include +#include +#include -#include "base/basictypes.h" #include "Common/ArmEmitter.h" +#include "ext/disarm.h" static const char *CCFlagsStr[] = { "EQ", // Equal @@ -759,30 +759,14 @@ static bool DisasmNeon(uint32_t op, char *text) { return false; } +bool ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info) { + *info = {}; + info->instructionSize = 4; + // TODO - - - - - - - - - - - - - - - - - - - - - - + return false; +} typedef unsigned int word; diff --git a/ext/disarm.h b/ext/disarm.h index 9bae68f215..901e74cd4f 100644 --- a/ext/disarm.h +++ b/ext/disarm.h @@ -17,18 +17,34 @@ #pragma once +#include -// This stuff only disassembles very old ARM but should be sufficient -// for the basics except for MOVW/MOVT. - - +// This stuff used to only disassemble very old ARM but has now +// been extended to support most (but not all) modern instructions, including NEON. // Disarm itself has the license you can see in the cpp file. // I'm not entirely sure it's 100% gpl compatible but it's nearly // public domain so meh. -// The only changes I've done is C++ compat and replaced the main -// program with this function. - const char *ArmRegName(int r); void ArmDis(unsigned int addr, unsigned int w, char *output, int bufsize, bool includeWord); + +// Information about a load/store instruction. +struct ArmLSInstructionInfo { + int instructionSize; + + bool isIntegerLoadStore; + bool isFPLoadStore; + bool isMultiLoadStore; + + int size; // 0 = 8-bit, 1 = 16-bit, 2 = 32-bit, 3 = 64-bit + bool isMemoryWrite; + + int Rt; + int Rn; + int Rm; + + // TODO: more. +}; + +bool ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info); diff --git a/ext/native/ext/gason/LICENSE b/ext/gason/LICENSE similarity index 100% rename from ext/native/ext/gason/LICENSE rename to ext/gason/LICENSE diff --git a/ext/native/ext/gason/gason.cpp b/ext/gason/gason.cpp similarity index 100% rename from ext/native/ext/gason/gason.cpp rename to ext/gason/gason.cpp diff --git a/ext/native/ext/gason/gason.h b/ext/gason/gason.h similarity index 100% rename from ext/native/ext/gason/gason.h rename to ext/gason/gason.h diff --git a/ext/glslang-build/Android.mk b/ext/glslang-build/Android.mk index 48b9ec9a42..8125efa02b 100644 --- a/ext/glslang-build/Android.mk +++ b/ext/glslang-build/Android.mk @@ -64,8 +64,6 @@ ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a) LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM -DARMEABI_V7A else ifeq ($(TARGET_ARCH_ABI),armeabi) LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM -DARMEABI -march=armv6 -else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) -LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_ARCH_64 -DARM64 else ifeq ($(TARGET_ARCH_ABI),x86) LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_IX86 else ifeq ($(TARGET_ARCH_ABI),x86_64) diff --git a/ext/native/ext/jpge/jpgd.cpp b/ext/jpge/jpgd.cpp similarity index 100% rename from ext/native/ext/jpge/jpgd.cpp rename to ext/jpge/jpgd.cpp diff --git a/ext/native/ext/jpge/jpgd.h b/ext/jpge/jpgd.h similarity index 100% rename from ext/native/ext/jpge/jpgd.h rename to ext/jpge/jpgd.h diff --git a/ext/native/ext/jpge/jpge.cpp b/ext/jpge/jpge.cpp similarity index 100% rename from ext/native/ext/jpge/jpge.cpp rename to ext/jpge/jpge.cpp diff --git a/ext/native/ext/jpge/jpge.h b/ext/jpge/jpge.h similarity index 100% rename from ext/native/ext/jpge/jpge.h rename to ext/jpge/jpge.h diff --git a/ext/native/ext/jpge/publicdomain.txt b/ext/jpge/publicdomain.txt similarity index 100% rename from ext/native/ext/jpge/publicdomain.txt rename to ext/jpge/publicdomain.txt diff --git a/ext/libkirk/amctrl.c b/ext/libkirk/amctrl.c index 86fbbf9b36..d144ca792c 100644 --- a/ext/libkirk/amctrl.c +++ b/ext/libkirk/amctrl.c @@ -41,7 +41,7 @@ static int do_kirk4(u8 *buf, int size, int type) header[3] = type; header[4] = size; - retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 4); + retv = kirk_sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 4); if(retv) return 0x80510311; @@ -60,7 +60,7 @@ static int do_kirk7(u8 *buf, int size, int type) header[3] = type; header[4] = size; - retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 7); + retv = kirk_sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 7); if(retv) return 0x80510311; @@ -78,7 +78,7 @@ static int kirk5(u8 *buf, int size) header[3] = 0x0100; header[4] = size; - retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 5); + retv = kirk_sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 5); if(retv) return 0x80510312; @@ -96,7 +96,7 @@ static int kirk8(u8 *buf, int size) header[3] = 0x0100; header[4] = size; - retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 8); + retv = kirk_sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 8); if(retv) return 0x80510312; @@ -107,7 +107,7 @@ static int kirk14(u8 *buf) { int retv; - retv = sceUtilsBufferCopyWithRange(buf, 0x14, 0, 0, 14); + retv = kirk_sceUtilsBufferCopyWithRange(buf, 0x14, 0, 0, 14); if(retv) return 0x80510315; diff --git a/ext/libkirk/kirk_engine.c b/ext/libkirk/kirk_engine.c index 1ff4c267e4..69a300a702 100644 --- a/ext/libkirk/kirk_engine.c +++ b/ext/libkirk/kirk_engine.c @@ -334,7 +334,7 @@ void kirk4(u8* outbuff, const u8* inbuff, size_t size, int keyId) AES_ctx aesKey; u8* key = kirk_4_7_get_key(keyId); AES_set_key(&aesKey, key, 128); - AES_cbc_encrypt(&aesKey, inbuff, outbuff, size); + AES_cbc_encrypt(&aesKey, inbuff, outbuff, (int)size); } int kirk_CMD7(u8* outbuff, u8* inbuff, int size) @@ -362,7 +362,7 @@ void kirk7(u8* outbuff, const u8* inbuff, size_t size, int keyId) AES_ctx aesKey; u8* key = kirk_4_7_get_key(keyId); AES_set_key(&aesKey, key, 128); - AES_cbc_decrypt(&aesKey, inbuff, outbuff, size); + AES_cbc_decrypt(&aesKey, inbuff, outbuff, (int)size); } int kirk_CMD10(u8* inbuff, int insize) @@ -725,21 +725,21 @@ int kirk_CMD1_ex(u8* outbuff, u8* inbuff, int size, KIRK_CMD1_HEADER* header) return ret; } - -int sceUtilsBufferCopyWithRange(u8* outbuff, int outsize, u8* inbuff, int insize, int cmd) +int kirk_sceUtilsBufferCopyWithRange(u8* outbuff, int outsize, const u8* inbuff, int insize, int cmd) { + // TODO: propagate const-correctness into all these functions. switch(cmd) { - case KIRK_CMD_DECRYPT_PRIVATE: return kirk_CMD1(outbuff, inbuff, insize); break; - case KIRK_CMD_ENCRYPT_IV_0: return kirk_CMD4(outbuff, inbuff, insize); break; - case KIRK_CMD_DECRYPT_IV_0: return kirk_CMD7(outbuff, inbuff, insize); break; - case KIRK_CMD_PRIV_SIGN_CHECK: return kirk_CMD10(inbuff, insize); break; - case KIRK_CMD_SHA1_HASH: return kirk_CMD11(outbuff, inbuff, insize); break; - case KIRK_CMD_ECDSA_GEN_KEYS: return kirk_CMD12(outbuff,outsize); break; - case KIRK_CMD_ECDSA_MULTIPLY_POINT: return kirk_CMD13(outbuff,outsize, inbuff, insize); break; - case KIRK_CMD_PRNG: return kirk_CMD14(outbuff,outsize); break; - case KIRK_CMD_ECDSA_SIGN: return kirk_CMD16(outbuff, outsize, inbuff, insize); break; - case KIRK_CMD_ECDSA_VERIFY: return kirk_CMD17(inbuff, insize); break; + case KIRK_CMD_DECRYPT_PRIVATE: return kirk_CMD1(outbuff, (u8 *)inbuff, insize); break; + case KIRK_CMD_ENCRYPT_IV_0: return kirk_CMD4(outbuff, (u8 *)inbuff, insize); break; + case KIRK_CMD_DECRYPT_IV_0: return kirk_CMD7(outbuff, (u8 *)inbuff, insize); break; + case KIRK_CMD_PRIV_SIGN_CHECK: return kirk_CMD10((u8 *)inbuff, insize); break; + case KIRK_CMD_SHA1_HASH: return kirk_CMD11(outbuff, (u8 *)inbuff, insize); break; + case KIRK_CMD_ECDSA_GEN_KEYS: return kirk_CMD12(outbuff, outsize); break; + case KIRK_CMD_ECDSA_MULTIPLY_POINT: return kirk_CMD13(outbuff, outsize, (u8 *)inbuff, insize); break; + case KIRK_CMD_PRNG: return kirk_CMD14(outbuff, outsize); break; + case KIRK_CMD_ECDSA_SIGN: return kirk_CMD16(outbuff, outsize, (u8 *)inbuff, insize); break; + case KIRK_CMD_ECDSA_VERIFY: return kirk_CMD17((u8 *)inbuff, insize); break; } return -1; } diff --git a/ext/libkirk/kirk_engine.h b/ext/libkirk/kirk_engine.h index c91795277c..5c7be012b7 100644 --- a/ext/libkirk/kirk_engine.h +++ b/ext/libkirk/kirk_engine.h @@ -218,9 +218,8 @@ u8* kirk_4_7_get_key(int key_type); //kirk "ex" functions int kirk_CMD1_ex(u8* outbuff, u8* inbuff, int size, KIRK_CMD1_HEADER* header); -//sce-like funcs -int sceUtilsSetFuseID(u8*fuse); -int sceUtilsBufferCopyWithRange(u8* outbuff, int outsize, u8* inbuff, int insize, int cmd); +//sce-like func. sceUtilsBufferCopyWithRange is clearly intentionally confusingly named. +int kirk_sceUtilsBufferCopyWithRange(u8* outbuff, int outsize, const u8* inbuff, int insize, int cmd); void decrypt_kirk16_private(u8 *dA_out, u8 *dA_enc); void encrypt_kirk16_private(u8 *dA_out, u8 *dA_dec); diff --git a/ext/native/ext/libpng17/CMakeLists.txt b/ext/libpng17/CMakeLists.txt similarity index 100% rename from ext/native/ext/libpng17/CMakeLists.txt rename to ext/libpng17/CMakeLists.txt diff --git a/ext/native/ext/libpng17/arm/arm_init.c b/ext/libpng17/arm/arm_init.c similarity index 100% rename from ext/native/ext/libpng17/arm/arm_init.c rename to ext/libpng17/arm/arm_init.c diff --git a/ext/native/ext/libpng17/arm/filter_neon.S b/ext/libpng17/arm/filter_neon.S similarity index 100% rename from ext/native/ext/libpng17/arm/filter_neon.S rename to ext/libpng17/arm/filter_neon.S diff --git a/ext/native/ext/libpng17/arm/filter_neon_intrinsics.c b/ext/libpng17/arm/filter_neon_intrinsics.c similarity index 100% rename from ext/native/ext/libpng17/arm/filter_neon_intrinsics.c rename to ext/libpng17/arm/filter_neon_intrinsics.c diff --git a/ext/native/ext/libpng17/png.c b/ext/libpng17/png.c similarity index 100% rename from ext/native/ext/libpng17/png.c rename to ext/libpng17/png.c diff --git a/ext/native/ext/libpng17/png.h b/ext/libpng17/png.h similarity index 100% rename from ext/native/ext/libpng17/png.h rename to ext/libpng17/png.h diff --git a/ext/native/ext/libpng17/pngconf.h b/ext/libpng17/pngconf.h similarity index 100% rename from ext/native/ext/libpng17/pngconf.h rename to ext/libpng17/pngconf.h diff --git a/ext/native/ext/libpng17/pngdebug.h b/ext/libpng17/pngdebug.h similarity index 100% rename from ext/native/ext/libpng17/pngdebug.h rename to ext/libpng17/pngdebug.h diff --git a/ext/native/ext/libpng17/pngerror.c b/ext/libpng17/pngerror.c similarity index 100% rename from ext/native/ext/libpng17/pngerror.c rename to ext/libpng17/pngerror.c diff --git a/ext/native/ext/libpng17/pngget.c b/ext/libpng17/pngget.c similarity index 100% rename from ext/native/ext/libpng17/pngget.c rename to ext/libpng17/pngget.c diff --git a/ext/native/ext/libpng17/pnginfo.h b/ext/libpng17/pnginfo.h similarity index 100% rename from ext/native/ext/libpng17/pnginfo.h rename to ext/libpng17/pnginfo.h diff --git a/ext/native/ext/libpng17/pnglibconf.h b/ext/libpng17/pnglibconf.h similarity index 100% rename from ext/native/ext/libpng17/pnglibconf.h rename to ext/libpng17/pnglibconf.h diff --git a/ext/native/ext/libpng17/pngmem.c b/ext/libpng17/pngmem.c similarity index 100% rename from ext/native/ext/libpng17/pngmem.c rename to ext/libpng17/pngmem.c diff --git a/ext/native/ext/libpng17/pngpread.c b/ext/libpng17/pngpread.c similarity index 100% rename from ext/native/ext/libpng17/pngpread.c rename to ext/libpng17/pngpread.c diff --git a/ext/native/ext/libpng17/pngpriv.h b/ext/libpng17/pngpriv.h similarity index 100% rename from ext/native/ext/libpng17/pngpriv.h rename to ext/libpng17/pngpriv.h diff --git a/ext/native/ext/libpng17/pngread.c b/ext/libpng17/pngread.c similarity index 100% rename from ext/native/ext/libpng17/pngread.c rename to ext/libpng17/pngread.c diff --git a/ext/native/ext/libpng17/pngrio.c b/ext/libpng17/pngrio.c similarity index 100% rename from ext/native/ext/libpng17/pngrio.c rename to ext/libpng17/pngrio.c diff --git a/ext/native/ext/libpng17/pngrtran.c b/ext/libpng17/pngrtran.c similarity index 100% rename from ext/native/ext/libpng17/pngrtran.c rename to ext/libpng17/pngrtran.c diff --git a/ext/native/ext/libpng17/pngrutil.c b/ext/libpng17/pngrutil.c similarity index 100% rename from ext/native/ext/libpng17/pngrutil.c rename to ext/libpng17/pngrutil.c diff --git a/ext/native/ext/libpng17/pngset.c b/ext/libpng17/pngset.c similarity index 100% rename from ext/native/ext/libpng17/pngset.c rename to ext/libpng17/pngset.c diff --git a/ext/native/ext/libpng17/pngstruct.h b/ext/libpng17/pngstruct.h similarity index 100% rename from ext/native/ext/libpng17/pngstruct.h rename to ext/libpng17/pngstruct.h diff --git a/ext/native/ext/libpng17/pngtest.c b/ext/libpng17/pngtest.c similarity index 100% rename from ext/native/ext/libpng17/pngtest.c rename to ext/libpng17/pngtest.c diff --git a/ext/native/ext/libpng17/pngtrans.c b/ext/libpng17/pngtrans.c similarity index 100% rename from ext/native/ext/libpng17/pngtrans.c rename to ext/libpng17/pngtrans.c diff --git a/ext/native/ext/libpng17/pngwio.c b/ext/libpng17/pngwio.c similarity index 100% rename from ext/native/ext/libpng17/pngwio.c rename to ext/libpng17/pngwio.c diff --git a/ext/native/ext/libpng17/pngwrite.c b/ext/libpng17/pngwrite.c similarity index 100% rename from ext/native/ext/libpng17/pngwrite.c rename to ext/libpng17/pngwrite.c diff --git a/ext/native/ext/libpng17/pngwtran.c b/ext/libpng17/pngwtran.c similarity index 100% rename from ext/native/ext/libpng17/pngwtran.c rename to ext/libpng17/pngwtran.c diff --git a/ext/native/ext/libpng17/pngwutil.c b/ext/libpng17/pngwutil.c similarity index 100% rename from ext/native/ext/libpng17/pngwutil.c rename to ext/libpng17/pngwutil.c diff --git a/ext/native/ext/libzip/Android.mk b/ext/libzip/Android.mk similarity index 100% rename from ext/native/ext/libzip/Android.mk rename to ext/libzip/Android.mk diff --git a/ext/native/ext/libzip/CMakeLists.txt b/ext/libzip/CMakeLists.txt similarity index 100% rename from ext/native/ext/libzip/CMakeLists.txt rename to ext/libzip/CMakeLists.txt diff --git a/ext/native/ext/libzip/config.h b/ext/libzip/config.h similarity index 100% rename from ext/native/ext/libzip/config.h rename to ext/libzip/config.h diff --git a/ext/native/ext/libzip/libzip.la b/ext/libzip/libzip.la similarity index 100% rename from ext/native/ext/libzip/libzip.la rename to ext/libzip/libzip.la diff --git a/ext/native/ext/libzip/mkstemp.c b/ext/libzip/mkstemp.c similarity index 100% rename from ext/native/ext/libzip/mkstemp.c rename to ext/libzip/mkstemp.c diff --git a/ext/native/ext/libzip/zip.h b/ext/libzip/zip.h similarity index 100% rename from ext/native/ext/libzip/zip.h rename to ext/libzip/zip.h diff --git a/ext/native/ext/libzip/zip_add.c b/ext/libzip/zip_add.c similarity index 100% rename from ext/native/ext/libzip/zip_add.c rename to ext/libzip/zip_add.c diff --git a/ext/native/ext/libzip/zip_add_dir.c b/ext/libzip/zip_add_dir.c similarity index 100% rename from ext/native/ext/libzip/zip_add_dir.c rename to ext/libzip/zip_add_dir.c diff --git a/ext/native/ext/libzip/zip_close.c b/ext/libzip/zip_close.c similarity index 100% rename from ext/native/ext/libzip/zip_close.c rename to ext/libzip/zip_close.c diff --git a/ext/native/ext/libzip/zip_delete.c b/ext/libzip/zip_delete.c similarity index 100% rename from ext/native/ext/libzip/zip_delete.c rename to ext/libzip/zip_delete.c diff --git a/ext/native/ext/libzip/zip_dirent.c b/ext/libzip/zip_dirent.c similarity index 100% rename from ext/native/ext/libzip/zip_dirent.c rename to ext/libzip/zip_dirent.c diff --git a/ext/native/ext/libzip/zip_entry_free.c b/ext/libzip/zip_entry_free.c similarity index 100% rename from ext/native/ext/libzip/zip_entry_free.c rename to ext/libzip/zip_entry_free.c diff --git a/ext/native/ext/libzip/zip_entry_new.c b/ext/libzip/zip_entry_new.c similarity index 100% rename from ext/native/ext/libzip/zip_entry_new.c rename to ext/libzip/zip_entry_new.c diff --git a/ext/native/ext/libzip/zip_err_str.c b/ext/libzip/zip_err_str.c similarity index 100% rename from ext/native/ext/libzip/zip_err_str.c rename to ext/libzip/zip_err_str.c diff --git a/ext/native/ext/libzip/zip_error.c b/ext/libzip/zip_error.c similarity index 100% rename from ext/native/ext/libzip/zip_error.c rename to ext/libzip/zip_error.c diff --git a/ext/native/ext/libzip/zip_error_clear.c b/ext/libzip/zip_error_clear.c similarity index 100% rename from ext/native/ext/libzip/zip_error_clear.c rename to ext/libzip/zip_error_clear.c diff --git a/ext/native/ext/libzip/zip_error_get.c b/ext/libzip/zip_error_get.c similarity index 100% rename from ext/native/ext/libzip/zip_error_get.c rename to ext/libzip/zip_error_get.c diff --git a/ext/native/ext/libzip/zip_error_get_sys_type.c b/ext/libzip/zip_error_get_sys_type.c similarity index 100% rename from ext/native/ext/libzip/zip_error_get_sys_type.c rename to ext/libzip/zip_error_get_sys_type.c diff --git a/ext/native/ext/libzip/zip_error_strerror.c b/ext/libzip/zip_error_strerror.c similarity index 100% rename from ext/native/ext/libzip/zip_error_strerror.c rename to ext/libzip/zip_error_strerror.c diff --git a/ext/native/ext/libzip/zip_error_to_str.c b/ext/libzip/zip_error_to_str.c similarity index 100% rename from ext/native/ext/libzip/zip_error_to_str.c rename to ext/libzip/zip_error_to_str.c diff --git a/ext/native/ext/libzip/zip_fclose.c b/ext/libzip/zip_fclose.c similarity index 100% rename from ext/native/ext/libzip/zip_fclose.c rename to ext/libzip/zip_fclose.c diff --git a/ext/native/ext/libzip/zip_file_error_clear.c b/ext/libzip/zip_file_error_clear.c similarity index 100% rename from ext/native/ext/libzip/zip_file_error_clear.c rename to ext/libzip/zip_file_error_clear.c diff --git a/ext/native/ext/libzip/zip_file_error_get.c b/ext/libzip/zip_file_error_get.c similarity index 100% rename from ext/native/ext/libzip/zip_file_error_get.c rename to ext/libzip/zip_file_error_get.c diff --git a/ext/native/ext/libzip/zip_file_get_offset.c b/ext/libzip/zip_file_get_offset.c similarity index 100% rename from ext/native/ext/libzip/zip_file_get_offset.c rename to ext/libzip/zip_file_get_offset.c diff --git a/ext/native/ext/libzip/zip_file_strerror.c b/ext/libzip/zip_file_strerror.c similarity index 100% rename from ext/native/ext/libzip/zip_file_strerror.c rename to ext/libzip/zip_file_strerror.c diff --git a/ext/native/ext/libzip/zip_filerange_crc.c b/ext/libzip/zip_filerange_crc.c similarity index 100% rename from ext/native/ext/libzip/zip_filerange_crc.c rename to ext/libzip/zip_filerange_crc.c diff --git a/ext/native/ext/libzip/zip_fopen.c b/ext/libzip/zip_fopen.c similarity index 100% rename from ext/native/ext/libzip/zip_fopen.c rename to ext/libzip/zip_fopen.c diff --git a/ext/native/ext/libzip/zip_fopen_index.c b/ext/libzip/zip_fopen_index.c similarity index 100% rename from ext/native/ext/libzip/zip_fopen_index.c rename to ext/libzip/zip_fopen_index.c diff --git a/ext/native/ext/libzip/zip_fread.c b/ext/libzip/zip_fread.c similarity index 100% rename from ext/native/ext/libzip/zip_fread.c rename to ext/libzip/zip_fread.c diff --git a/ext/native/ext/libzip/zip_free.c b/ext/libzip/zip_free.c similarity index 100% rename from ext/native/ext/libzip/zip_free.c rename to ext/libzip/zip_free.c diff --git a/ext/native/ext/libzip/zip_get_archive_comment.c b/ext/libzip/zip_get_archive_comment.c similarity index 100% rename from ext/native/ext/libzip/zip_get_archive_comment.c rename to ext/libzip/zip_get_archive_comment.c diff --git a/ext/native/ext/libzip/zip_get_archive_flag.c b/ext/libzip/zip_get_archive_flag.c similarity index 100% rename from ext/native/ext/libzip/zip_get_archive_flag.c rename to ext/libzip/zip_get_archive_flag.c diff --git a/ext/native/ext/libzip/zip_get_file_comment.c b/ext/libzip/zip_get_file_comment.c similarity index 100% rename from ext/native/ext/libzip/zip_get_file_comment.c rename to ext/libzip/zip_get_file_comment.c diff --git a/ext/native/ext/libzip/zip_get_name.c b/ext/libzip/zip_get_name.c similarity index 100% rename from ext/native/ext/libzip/zip_get_name.c rename to ext/libzip/zip_get_name.c diff --git a/ext/native/ext/libzip/zip_get_num_files.c b/ext/libzip/zip_get_num_files.c similarity index 100% rename from ext/native/ext/libzip/zip_get_num_files.c rename to ext/libzip/zip_get_num_files.c diff --git a/ext/native/ext/libzip/zip_memdup.c b/ext/libzip/zip_memdup.c similarity index 100% rename from ext/native/ext/libzip/zip_memdup.c rename to ext/libzip/zip_memdup.c diff --git a/ext/native/ext/libzip/zip_name_locate.c b/ext/libzip/zip_name_locate.c similarity index 100% rename from ext/native/ext/libzip/zip_name_locate.c rename to ext/libzip/zip_name_locate.c diff --git a/ext/native/ext/libzip/zip_new.c b/ext/libzip/zip_new.c similarity index 100% rename from ext/native/ext/libzip/zip_new.c rename to ext/libzip/zip_new.c diff --git a/ext/native/ext/libzip/zip_open.c b/ext/libzip/zip_open.c similarity index 100% rename from ext/native/ext/libzip/zip_open.c rename to ext/libzip/zip_open.c diff --git a/ext/native/ext/libzip/zip_rename.c b/ext/libzip/zip_rename.c similarity index 100% rename from ext/native/ext/libzip/zip_rename.c rename to ext/libzip/zip_rename.c diff --git a/ext/native/ext/libzip/zip_replace.c b/ext/libzip/zip_replace.c similarity index 100% rename from ext/native/ext/libzip/zip_replace.c rename to ext/libzip/zip_replace.c diff --git a/ext/native/ext/libzip/zip_set_archive_comment.c b/ext/libzip/zip_set_archive_comment.c similarity index 100% rename from ext/native/ext/libzip/zip_set_archive_comment.c rename to ext/libzip/zip_set_archive_comment.c diff --git a/ext/native/ext/libzip/zip_set_archive_flag.c b/ext/libzip/zip_set_archive_flag.c similarity index 100% rename from ext/native/ext/libzip/zip_set_archive_flag.c rename to ext/libzip/zip_set_archive_flag.c diff --git a/ext/native/ext/libzip/zip_set_file_comment.c b/ext/libzip/zip_set_file_comment.c similarity index 100% rename from ext/native/ext/libzip/zip_set_file_comment.c rename to ext/libzip/zip_set_file_comment.c diff --git a/ext/native/ext/libzip/zip_set_name.c b/ext/libzip/zip_set_name.c similarity index 100% rename from ext/native/ext/libzip/zip_set_name.c rename to ext/libzip/zip_set_name.c diff --git a/ext/native/ext/libzip/zip_source_buffer.c b/ext/libzip/zip_source_buffer.c similarity index 100% rename from ext/native/ext/libzip/zip_source_buffer.c rename to ext/libzip/zip_source_buffer.c diff --git a/ext/native/ext/libzip/zip_source_file.c b/ext/libzip/zip_source_file.c similarity index 100% rename from ext/native/ext/libzip/zip_source_file.c rename to ext/libzip/zip_source_file.c diff --git a/ext/native/ext/libzip/zip_source_filep.c b/ext/libzip/zip_source_filep.c similarity index 100% rename from ext/native/ext/libzip/zip_source_filep.c rename to ext/libzip/zip_source_filep.c diff --git a/ext/native/ext/libzip/zip_source_free.c b/ext/libzip/zip_source_free.c similarity index 100% rename from ext/native/ext/libzip/zip_source_free.c rename to ext/libzip/zip_source_free.c diff --git a/ext/native/ext/libzip/zip_source_function.c b/ext/libzip/zip_source_function.c similarity index 100% rename from ext/native/ext/libzip/zip_source_function.c rename to ext/libzip/zip_source_function.c diff --git a/ext/native/ext/libzip/zip_source_zip.c b/ext/libzip/zip_source_zip.c similarity index 100% rename from ext/native/ext/libzip/zip_source_zip.c rename to ext/libzip/zip_source_zip.c diff --git a/ext/native/ext/libzip/zip_stat.c b/ext/libzip/zip_stat.c similarity index 100% rename from ext/native/ext/libzip/zip_stat.c rename to ext/libzip/zip_stat.c diff --git a/ext/native/ext/libzip/zip_stat_index.c b/ext/libzip/zip_stat_index.c similarity index 100% rename from ext/native/ext/libzip/zip_stat_index.c rename to ext/libzip/zip_stat_index.c diff --git a/ext/native/ext/libzip/zip_stat_init.c b/ext/libzip/zip_stat_init.c similarity index 100% rename from ext/native/ext/libzip/zip_stat_init.c rename to ext/libzip/zip_stat_init.c diff --git a/ext/native/ext/libzip/zip_strerror.c b/ext/libzip/zip_strerror.c similarity index 100% rename from ext/native/ext/libzip/zip_strerror.c rename to ext/libzip/zip_strerror.c diff --git a/ext/native/ext/libzip/zip_unchange.c b/ext/libzip/zip_unchange.c similarity index 100% rename from ext/native/ext/libzip/zip_unchange.c rename to ext/libzip/zip_unchange.c diff --git a/ext/native/ext/libzip/zip_unchange_all.c b/ext/libzip/zip_unchange_all.c similarity index 100% rename from ext/native/ext/libzip/zip_unchange_all.c rename to ext/libzip/zip_unchange_all.c diff --git a/ext/native/ext/libzip/zip_unchange_archive.c b/ext/libzip/zip_unchange_archive.c similarity index 100% rename from ext/native/ext/libzip/zip_unchange_archive.c rename to ext/libzip/zip_unchange_archive.c diff --git a/ext/native/ext/libzip/zip_unchange_data.c b/ext/libzip/zip_unchange_data.c similarity index 100% rename from ext/native/ext/libzip/zip_unchange_data.c rename to ext/libzip/zip_unchange_data.c diff --git a/ext/native/ext/libzip/zipint.h b/ext/libzip/zipint.h similarity index 100% rename from ext/native/ext/libzip/zipint.h rename to ext/libzip/zipint.h diff --git a/ext/miniupnp b/ext/miniupnp new file mode 160000 index 0000000000..7e229ddd63 --- /dev/null +++ b/ext/miniupnp @@ -0,0 +1 @@ +Subproject commit 7e229ddd635933239583ab190d9b614bde018157 diff --git a/ext/miniupnp-build/Android.mk b/ext/miniupnp-build/Android.mk new file mode 100644 index 0000000000..6675d326a5 --- /dev/null +++ b/ext/miniupnp-build/Android.mk @@ -0,0 +1,40 @@ +# Basic Android.mk for miniupnpc in PPSSPP + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libminiupnp-build +LOCAL_ARM_MODE := arm +LOCAL_SRC_FILES := \ + ../miniupnp/miniupnpc/connecthostport.c \ + ../miniupnp/miniupnpc/igd_desc_parse.c \ + ../miniupnp/miniupnpc/minisoap.c \ + ../miniupnp/miniupnpc/minissdpc.c \ + ../miniupnp/miniupnpc/miniupnpc.c \ + ../miniupnp/miniupnpc/miniwget.c \ + ../miniupnp/miniupnpc/minixml.c \ + ../miniupnp/miniupnpc/minixmlvalid.c \ + ../miniupnp/miniupnpc/portlistingparse.c \ + ../miniupnp/miniupnpc/receivedata.c \ + ../miniupnp/miniupnpc/upnpcommands.c \ + ../miniupnp/miniupnpc/upnpdev.c \ + ../miniupnp/miniupnpc/upnperrors.c \ + ../miniupnp/miniupnpc/upnpreplyparse.c + +LOCAL_CFLAGS := -O3 -fsigned-char -fno-strict-aliasing -Wall -Wno-multichar -D__STDC_CONSTANT_MACROS +LOCAL_CPPFLAGS := -fno-exceptions -std=gnu++11 -fno-rtti -Wno-reorder +# Note: LOCAL_PATH is the directory this file is in. +LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/../miniupnp .. + +ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a) +LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM -DARMEABI_V7A +else ifeq ($(TARGET_ARCH_ABI),armeabi) +LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM -DARMEABI -march=armv6 +else ifeq ($(TARGET_ARCH_ABI),x86) +LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_IX86 +else ifeq ($(TARGET_ARCH_ABI),x86_64) +LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_X64 +endif + +include $(BUILD_STATIC_LIBRARY) diff --git a/ext/miniupnp-build/miniupnpcstrings.h b/ext/miniupnp-build/miniupnpcstrings.h new file mode 100644 index 0000000000..1489a91134 --- /dev/null +++ b/ext/miniupnp-build/miniupnpcstrings.h @@ -0,0 +1,23 @@ +/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPCSTRINGS_H_INCLUDED +#define MINIUPNPCSTRINGS_H_INCLUDED + +#define OS_STRING "Android" +#define MINIUPNPC_VERSION_STRING "2.1" + +#if 0 +/* according to "UPnP Device Architecture 1.0" */ +#define UPNP_VERSION_STRING "UPnP/1.0" +#else +/* according to "UPnP Device Architecture 1.1" */ +#define UPNP_VERSION_STRING "UPnP/1.1" +#endif + +#endif + diff --git a/ext/miniupnpc.vcxproj b/ext/miniupnpc.vcxproj new file mode 100644 index 0000000000..686ca48b1d --- /dev/null +++ b/ext/miniupnpc.vcxproj @@ -0,0 +1,327 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + 16.0 + {D8A71225-178B-424E-96C1-CC3BE2C1B047} + Win32Proj + miniupnpc + 10.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + StaticLibrary + true + $(DefaultPlatformToolset) + Unicode + + + StaticLibrary + false + $(DefaultPlatformToolset) + false + Unicode + + + StaticLibrary + true + $(DefaultPlatformToolset) + Unicode + + + StaticLibrary + false + $(DefaultPlatformToolset) + false + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + + + true + $(Platform)\$(Configuration)\$(ProjectName)\ + + + false + $(Configuration)\$(ProjectName)\ + + + false + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + NotUsing + Level3 + + + false + stdafx.h + DEBUG;_DEBUG;WIN32;_LIB;MINIUPNP_STATICLIB;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + Default + false + ProgramDatabase + true + MultiThreadedDebug + + + Windows + true + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + $(OutDir)$(TargetName)$(TargetExt) + iphlpapi.lib + + + + + NotUsing + Level3 + + + DEBUG;_DEBUG;WIN32;_LIB;MINIUPNP_STATICLIB;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + stdafx.h + ProgramDatabase + true + Default + MultiThreadedDebug + false + + + Windows + true + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + iphlpapi.lib + + + + + NotUsing + Level3 + true + true + + + false + stdafx.h + NDEBUG;WIN32;_LIB;MINIUPNP_STATICLIB;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + Speed + false + true + false + MultiThreaded + + + Windows + true + true + true + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + $(OutDir)$(TargetName)$(TargetExt) + iphlpapi.lib + + + + + NotUsing + Level3 + true + true + + + NDEBUG;WIN32;_LIB;MINIUPNP_STATICLIB;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + stdafx.h + true + Speed + MultiThreaded + false + false + + + Windows + true + true + true + + + iphlpapi.lib + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + + + cd miniupnp\miniupnpc\msvc +genminiupnpcstrings.vbs +cd..\..\.. + + + + + + \ No newline at end of file diff --git a/ext/miniupnpc.vcxproj.filters b/ext/miniupnpc.vcxproj.filters new file mode 100644 index 0000000000..bda1ac6d7d --- /dev/null +++ b/ext/miniupnpc.vcxproj.filters @@ -0,0 +1,44 @@ +๏ปฟ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {c82edf03-bf88-478d-aaf5-2854df756cab} + + + + + scripts + + + \ No newline at end of file diff --git a/ext/native/Android.mk b/ext/native/Android.mk deleted file mode 100644 index 0373665117..0000000000 --- a/ext/native/Android.mk +++ /dev/null @@ -1,134 +0,0 @@ -# Basic Android.mk for libnative - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libnative -LOCAL_ARM_MODE := arm -LOCAL_SRC_FILES :=\ - base/backtrace.cpp \ - base/buffer.cpp \ - base/display.cpp \ - base/timeutil.cpp \ - base/colorutil.cpp \ - base/stringutil.cpp \ - data/base64.cpp \ - data/compression.cpp \ - ext/cityhash/city.cpp \ - ext/libpng17/png.c \ - ext/libpng17/pngerror.c \ - ext/libpng17/pngget.c \ - ext/libpng17/pngmem.c \ - ext/libpng17/pngpread.c \ - ext/libpng17/pngread.c \ - ext/libpng17/pngrio.c \ - ext/libpng17/pngrtran.c \ - ext/libpng17/pngrutil.c \ - ext/libpng17/pngset.c \ - ext/libpng17/pngtest.c \ - ext/libpng17/pngtrans.c \ - ext/libpng17/pngwio.c \ - ext/libpng17/pngwrite.c \ - ext/libpng17/pngwtran.c \ - ext/libpng17/pngwutil.c \ - ext/jpge/jpgd.cpp \ - ext/jpge/jpge.cpp \ - ext/sha1/sha1.cpp \ - ext/gason/gason.cpp \ - file/fd_util.cpp \ - file/chunk_file.cpp \ - file/file_util.cpp \ - file/free.cpp \ - file/path.cpp \ - file/ini_file.cpp \ - file/zip_read.cpp \ - json/json_reader.cpp \ - json/json_writer.cpp \ - i18n/i18n.cpp \ - input/gesture_detector.cpp \ - input/input_state.cpp \ - math/fast/fast_math.c \ - math/fast/fast_matrix.c \ - math/dataconv.cpp \ - math/math_util.cpp \ - math/curves.cpp \ - math/expression_parser.cpp \ - math/lin/plane.cpp.arm \ - math/lin/quat.cpp.arm \ - math/lin/vec3.cpp.arm \ - math/lin/matrix4x4.cpp.arm \ - net/http_client.cpp \ - net/http_server.cpp \ - net/http_headers.cpp \ - net/resolve.cpp \ - net/sinks.cpp \ - net/url.cpp \ - net/websocket_server.cpp \ - profiler/profiler.cpp \ - thread/executor.cpp \ - thread/threadutil.cpp \ - thread/prioritizedworkqueue.cpp \ - thread/threadpool.cpp \ - gfx_es2/glsl_program.cpp \ - gfx_es2/gpu_features.cpp \ - gfx_es2/gl3stub.c \ - gfx_es2/draw_buffer.cpp.arm \ - gfx_es2/draw_text.cpp.arm \ - gfx_es2/draw_text_android.cpp.arm \ - gfx/gl_debug_log.cpp \ - gfx/texture_atlas.cpp \ - image/zim_load.cpp \ - image/zim_save.cpp \ - image/png_load.cpp \ - thin3d/thin3d.cpp \ - thin3d/thin3d_gl.cpp \ - thin3d/thin3d_vulkan.cpp \ - thin3d/GLRenderManager.cpp \ - thin3d/GLQueueRunner.cpp \ - thin3d/VulkanRenderManager.cpp \ - thin3d/VulkanQueueRunner.cpp \ - thin3d/DataFormatGL.cpp \ - ui/root.cpp \ - ui/view.cpp \ - ui/viewgroup.cpp \ - ui/ui.cpp \ - ui/ui_screen.cpp \ - ui/ui_tween.cpp \ - ui/ui_context.cpp \ - ui/screen.cpp \ - util/text/utf8.cpp \ - util/text/parsers.cpp \ - util/text/wrap_text.cpp \ - util/hash/hash.cpp - -LOCAL_CFLAGS := -O3 -DUSING_GLES2 -fsigned-char -fno-strict-aliasing -Wall -Wno-multichar -D__STDC_CONSTANT_MACROS -LOCAL_CPPFLAGS := -fno-exceptions -std=gnu++11 -fno-rtti -Wno-reorder -LOCAL_C_INCLUDES := $(LOCAL_PATH)/ext $(LOCAL_PATH)/ext/libpng17 $(LOCAL_PATH)/ext/libzip $(LOCAL_PATH)/ext/glslang .. - -#Portable native and separate code on android in future is easy you needs add files -#by ($(target_arch_ABI),arquitecture (armeabi-v7a , armeabi , x86 , MIPS) -# ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a) -LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM -DARMEABI_V7A -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - math/fast/fast_matrix_neon.S.neon \ - ext/libpng17/arm/arm_init.c \ - ext/libpng17/arm/filter_neon_intrinsics.c \ - ext/libpng17/arm/filter_neon.S.neon - -else ifeq ($(TARGET_ARCH_ABI),armeabi) -LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM -DARMEABI -march=armv6 -else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) -LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_ARCH_64 -DARM64 -else ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_IX86 -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - math/fast/fast_matrix_sse.c -else ifeq ($(TARGET_ARCH_ABI),x86_64) -LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_X64 -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - math/fast/fast_matrix_sse.c -endif - -include $(BUILD_STATIC_LIBRARY) diff --git a/ext/native/LICENSE.TXT b/ext/native/LICENSE.TXT deleted file mode 100644 index e92ab68fef..0000000000 --- a/ext/native/LICENSE.TXT +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (C) 2012 Henrik Rydgard - -This applies to all the code here not covered under other licenses, see README.md. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/ext/native/base/CMakeLists.txt b/ext/native/base/CMakeLists.txt deleted file mode 100644 index 9915f73bec..0000000000 --- a/ext/native/base/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(SRCS - colorutil.cpp - timeutil.cpp - ../thread/threadutil.cpp - display.cpp - buffer.cpp - backtrace.cpp) - -add_library(base STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) - -add_library(timeutil STATIC timeutil.cpp) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/base/backtrace.cpp b/ext/native/base/backtrace.cpp deleted file mode 100644 index 2b5cddb972..0000000000 --- a/ext/native/base/backtrace.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "base/backtrace.h" - -#if (defined(__GLIBC__) && !defined(__UCLIBC__)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) -#include -#include - -static void *backtrace_buffer[128]; - -void PrintBacktraceToStderr() { - int num_addrs = backtrace(backtrace_buffer, 128); - backtrace_symbols_fd(backtrace_buffer, num_addrs, STDERR_FILENO); -} - -#else - -#include - -void PrintBacktraceToStderr() { - fprintf(stderr, "No backtrace available to print on this platform\n"); -} - -#endif diff --git a/ext/native/base/backtrace.h b/ext/native/base/backtrace.h deleted file mode 100644 index 4ff0917f30..0000000000 --- a/ext/native/base/backtrace.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void PrintBacktraceToStderr(); diff --git a/ext/native/base/basictypes.h b/ext/native/base/basictypes.h deleted file mode 100644 index 8cd0fd0e1e..0000000000 --- a/ext/native/base/basictypes.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include // for byte swapping - -#ifdef _WIN32 -#pragma warning(disable:4244) -#pragma warning(disable:4996) -#endif - -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(t) \ - t(const t &other) = delete; \ - void operator =(const t &other) = delete; -#endif - -#ifdef _WIN32 - -typedef intptr_t ssize_t; - -#include - -#endif // _WIN32 - -// Byteswapping -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) -#endif - -inline uint8_t swap8(uint8_t _data) {return _data;} - -// Just in case this has been defined by platform -#undef swap16 -#undef swap32 -#undef swap64 - -#ifdef _WIN32 -inline uint16_t swap16(uint16_t _data) {return _byteswap_ushort(_data);} -inline uint32_t swap32(uint32_t _data) {return _byteswap_ulong (_data);} -inline uint64_t swap64(uint64_t _data) {return _byteswap_uint64(_data);} -#elif defined(__GNUC__) -inline uint16_t swap16(uint16_t _data) {return __builtin_bswap16(_data);} -inline uint32_t swap32(uint32_t _data) {return __builtin_bswap32(_data);} -inline uint64_t swap64(uint64_t _data) {return __builtin_bswap64(_data);} -#else -// Slow generic implementation. Hopefully this never hits -inline uint16_t swap16(uint16_t data) {return (data >> 8) | (data << 8);} -inline uint32_t swap32(uint32_t data) {return (swap16(data) << 16) | swap16(data >> 16);} -inline uint64_t swap64(uint64_t data) {return ((uint64_t)swap32(data) << 32) | swap32(data >> 32);} -#endif - -inline uint16_t swap16(const uint8_t* _pData) {return swap16(*(const uint16_t*)_pData);} -inline uint32_t swap32(const uint8_t* _pData) {return swap32(*(const uint32_t*)_pData);} -inline uint64_t swap64(const uint8_t* _pData) {return swap64(*(const uint64_t*)_pData);} - -// Thread local storage -#ifdef _MSC_VER -#define __THREAD __declspec( thread ) -#else -#define __THREAD __thread -#endif - -// For really basic windows code compat -#ifndef _TCHAR_DEFINED -typedef char TCHAR; -#endif - diff --git a/ext/native/base/linked_ptr.h b/ext/native/base/linked_ptr.h deleted file mode 100644 index 7eec84eed6..0000000000 --- a/ext/native/base/linked_ptr.h +++ /dev/null @@ -1,60 +0,0 @@ -// From http://ootips.org/yonat/4dev/linked_ptr.h - -/* -* linked_ptr - simple reference linked pointer -* (like reference counting, just using a linked list of the references -* instead of their count.) -* -* The implementation stores three pointers for every linked_ptr, but -* does not allocate anything on the free store. -*/ - -#pragma once - -template class linked_ptr -{ -public: - explicit linked_ptr(X* p = 0) throw() : itsPtr(p) {itsPrev = itsNext = this;} - ~linked_ptr() {release();} - linked_ptr(const linked_ptr& r) throw() {acquire(r);} - - linked_ptr& operator=(const linked_ptr& r) - { - if (this != &r) { - release(); - acquire(r); - } - return *this; - } - - X& operator*() const throw() {return *itsPtr;} - X* operator->() const throw() {return itsPtr;} - X* get() const throw() {return itsPtr;} - bool unique() const throw() {return itsPrev ? itsPrev==this : true;} - -private: - X* itsPtr; - mutable const linked_ptr* itsPrev; - mutable const linked_ptr* itsNext; - - void acquire(const linked_ptr& r) throw() - { // insert this to the list - itsPtr = r.itsPtr; - itsNext = r.itsNext; - itsNext->itsPrev = this; - itsPrev = &r; - r.itsNext = this; - } - - void release() - { // erase this from the list, delete if unique - if (unique()) delete itsPtr; - else { - itsPrev->itsNext = itsNext; - itsNext->itsPrev = itsPrev; - itsPrev = itsNext = 0; - } - itsPtr = 0; - } -}; - diff --git a/ext/native/base/logging.cpp b/ext/native/base/logging.cpp deleted file mode 100644 index b4f40fa8c7..0000000000 --- a/ext/native/base/logging.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "base/logging.h" - -const char *GetFn(const char *fn) { - const char *p = strrchr(fn, '\\'); - if (p) - return p + 1; - else - return fn; -} diff --git a/ext/native/base/logging.h b/ext/native/base/logging.h deleted file mode 100644 index f411bb7f28..0000000000 --- a/ext/native/base/logging.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once - -#include - -#include "../../ppsspp_config.h" -#include "base/backtrace.h" - -// Simple wrapper around Android's logging interface that also allows other -// implementations, and also some misc utilities. - -#ifdef _MSC_VER -// Disable annoying warnings in VS -#pragma warning (disable:4996) //strcpy may be dangerous, etc. -#endif - -#undef Crash - -#include -// Logging -#ifdef _WIN32 - -#ifdef _M_X64 -inline void Crash() { int *x = (int *)1337; *x = 1; } -#elif defined(_M_IX86) -inline void Crash() { __asm { int 3 }; } -#elif defined(_M_ARM) -inline void Crash() { int *x = (int *)1337; *x = 1; } -#elif defined(_M_ARM64) -inline void Crash() { int* x = (int*)1337; *x = 1; } -#endif - -#else - -#if defined(_M_IX86) || defined(_M_X64) -inline void Crash() { - PrintBacktraceToStderr(); - asm("int $0x3"); -} -#else -inline void Crash() { - PrintBacktraceToStderr(); - char *p = (char *)1337; - *p = 1; -} -#endif - -#endif - -// Just ILOGs on nonWindows. On Windows it outputs to the VS output console. -void OutputDebugStringUTF8(const char *p); - -#if defined(__ANDROID__) - -#include - -// Must only be used for logging -#ifndef APP_NAME -#define APP_NAME "PPSSPP" -#endif - -#ifdef _DEBUG -#define DLOG(...) __android_log_print(ANDROID_LOG_INFO, APP_NAME, __VA_ARGS__); -#else -#define DLOG(...) -#endif - -#define ILOG(...) __android_log_print(ANDROID_LOG_INFO, APP_NAME, __VA_ARGS__); -#define WLOG(...) __android_log_print(ANDROID_LOG_WARN, APP_NAME, __VA_ARGS__); -#define ELOG(...) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__); -#define FLOG(...) __android_log_print(ANDROID_LOG_FATAL, APP_NAME, __VA_ARGS__); - -#define MessageBox(a, b, c, d) __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s %s", (b), (c)); - -#else - -#ifdef _WIN32 - -const char *GetFn(const char *fn); - -#define XLOG_IMPL(type, ...) do {\ - char temp[512]; \ - char *p = temp; \ - int len = snprintf(p, sizeof(temp), type ": %s:%i: ", GetFn(__FILE__), __LINE__); \ - if (len < sizeof(temp)) { \ - p += len; \ - p += snprintf(p, sizeof(temp) - len - 3, type ": " __VA_ARGS__); \ - if (p > temp + sizeof(temp) - 3) \ - p = temp + sizeof(temp) - 3; \ - p += sprintf(p, "\n"); \ - OutputDebugStringUTF8(temp); \ - } \ -} while (false) - -#define DUMPLOG(x) OutputDebugStringUTF8(x) - -#ifdef _DEBUG -#define DLOG(...) XLOG_IMPL("D", __VA_ARGS__) -#else -#define DLOG(...) -#endif - -#define ILOG(...) XLOG_IMPL("I", __VA_ARGS__) -#define WLOG(...) XLOG_IMPL("W", __VA_ARGS__) -#define ELOG(...) XLOG_IMPL("E", __VA_ARGS__) -#define FLOG(...) do {XLOG_IMPL("F", __VA_ARGS__); Crash();} while (false) - -#else - -#include - -inline const char *removePath(const char *str) { - const char *slash = strrchr(str, '/'); - return slash ? (slash + 1) : str; -} - -#ifdef _DEBUG -#define DLOG(...) {printf("D: %s:%i: ", removePath(__FILE__), __LINE__); printf("D: " __VA_ARGS__); printf("\n");} -#else -#define DLOG(...) -#endif -#define ILOG(...) {printf("I: %s:%i: ", removePath(__FILE__), __LINE__); printf(__VA_ARGS__); printf("\n");} -#define WLOG(...) {printf("W: %s:%i: ", removePath(__FILE__), __LINE__); printf(__VA_ARGS__); printf("\n");} -#define ELOG(...) {printf("E: %s:%i: ", removePath(__FILE__), __LINE__); printf(__VA_ARGS__); printf("\n");} -#define FLOG(...) {printf("F: %s:%i: ", removePath(__FILE__), __LINE__); printf(__VA_ARGS__); printf("\n"); Crash();} - -#endif -#endif - -#undef CHECK - -#define CHECK(a) {if (!(a)) {FLOG("%i: CHECK failed on this line", __LINE__);}} -#define CHECK_P(a, ...) {if (!(a)) {FLOG("CHECK failed: " __VA_ARGS__);}} -#define CHECK_EQ(a, b) CHECK((a) == (b)); -#define CHECK_NE(a, b) CHECK((a) != (b)); -#define CHECK_GT(a, b) CHECK((a) > (b)); -#define CHECK_GE(a, b) CHECK((a) >= (b)); -#define CHECK_LT(a, b) CHECK((a) < (b)); -#define CHECK_LE(a, b) CHECK((a) <= (b)); diff --git a/ext/native/base/stringutil.cpp b/ext/native/base/stringutil.cpp deleted file mode 100644 index 2861f844d3..0000000000 --- a/ext/native/base/stringutil.cpp +++ /dev/null @@ -1,329 +0,0 @@ -#include "ppsspp_config.h" -#ifdef _WIN32 -#include -#undef min -#undef max -#endif -#if PPSSPP_PLATFORM(SWITCH) -#define _GNU_SOURCE -#include -#endif -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "base/buffer.h" -#include "base/stringutil.h" - -#ifdef _WIN32 -// Function Cross-Compatibility -#define strcasecmp _stricmp - -void OutputDebugStringUTF8(const char *p) { - wchar_t temp[4096]; - - int len = std::min(4095, (int)strlen(p)); - int size = (int)MultiByteToWideChar(CP_UTF8, 0, p, len, NULL, 0); - MultiByteToWideChar(CP_UTF8, 0, p, len, temp, size); - temp[size] = 0; - - OutputDebugString(temp); -} - -#else - -void OutputDebugStringUTF8(const char *p) { - ILOG("%s", p); -} - -#endif - -std::string LineNumberString(const std::string &str) { - std::stringstream input(str); - std::stringstream output; - std::string line; - - int lineNumber = 1; - while (std::getline(input, line)) { - output << std::setw(4) << lineNumber++ << ": " << line << std::endl; - } - - return output.str(); -} - -void StringTrimEndNonAlphaNum(char *str) { - ssize_t n = strlen(str); - while (!isalnum(str[n]) && n >= 0) { - str[n--] = '\0'; - } -} - -void SkipSpace(const char **ptr) { - while (**ptr && isspace(**ptr)) { - (*ptr)++; - } -} - -void StringUpper(char *str) { - while (*str) { - *str = toupper(*str); - str++; - } -} - -void StringUpper(char *str, int len) { - while (len--) { - *str = toupper(*str); - str++; - } -} - - -unsigned int parseHex(const char *_szValue) -{ - int Value = 0; - size_t Finish = strlen(_szValue); - if (Finish > 8 ) { Finish = 8; } - - for (size_t Count = 0; Count < Finish; Count++) { - Value = (Value << 4); - switch( _szValue[Count] ) { - case '0': break; - case '1': Value += 1; break; - case '2': Value += 2; break; - case '3': Value += 3; break; - case '4': Value += 4; break; - case '5': Value += 5; break; - case '6': Value += 6; break; - case '7': Value += 7; break; - case '8': Value += 8; break; - case '9': Value += 9; break; - case 'A': Value += 10; break; - case 'a': Value += 10; break; - case 'B': Value += 11; break; - case 'b': Value += 11; break; - case 'C': Value += 12; break; - case 'c': Value += 12; break; - case 'D': Value += 13; break; - case 'd': Value += 13; break; - case 'E': Value += 14; break; - case 'e': Value += 14; break; - case 'F': Value += 15; break; - case 'f': Value += 15; break; - default: - Value = (Value >> 4); - Count = Finish; - } - } - return Value; -} - -void DataToHexString(const uint8_t *data, size_t size, std::string *output) { - Buffer buffer; - for (size_t i = 0; i < size; i++) { - buffer.Printf("%02x ", data[i]); - if (i && !(i & 15)) - buffer.Printf("\n"); - } - buffer.TakeAll(output); -} - -std::string StringFromFormat(const char* format, ...) -{ - va_list args; - std::string temp = ""; -#ifdef _WIN32 - int required = 0; - - va_start(args, format); - required = _vscprintf(format, args); - // Using + 2 to be safe between MSVC versions. - // In MSVC 2015 and later, vsnprintf counts the trailing zero (per c++11.) - temp.resize(required + 2); - if (vsnprintf(&temp[0], required + 1, format, args) < 0) { - temp.resize(0); - } else { - temp.resize(required); - } - va_end(args); -#else - char *buf = nullptr; - - va_start(args, format); - if (vasprintf(&buf, format, args) < 0) - buf = nullptr; - va_end(args); - - if (buf != nullptr) { - temp = buf; - free(buf); - } -#endif - return temp; -} - -std::string StringFromInt(int value) -{ - char temp[16]; - sprintf(temp, "%i", value); - return temp; -} - -std::string StringFromBool(bool value) -{ - return value ? "True" : "False"; -} - -// Turns " hej " into "hej". Also handles tabs. -std::string StripSpaces(const std::string &str) -{ - const size_t s = str.find_first_not_of(" \t\r\n"); - - if (str.npos != s) - return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); - else - return ""; -} - -// "\"hello\"" is turned to "hello" -// This one assumes that the string has already been space stripped in both -// ends, as done by StripSpaces above, for example. -std::string StripQuotes(const std::string& s) -{ - if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) - return s.substr(1, s.size() - 2); - else - return s; -} - -// For Debugging. Read out an u8 array. -std::string ArrayToString(const uint8_t *data, uint32_t size, int line_len, bool spaces) -{ - std::ostringstream oss; - oss << std::setfill('0') << std::hex; - - for (int line = 0; size; ++data, --size) - { - oss << std::setw(2) << (int)*data; - if (line_len == ++line) - { - oss << '\n'; - line = 0; - } - else if (spaces) - oss << ' '; - } - - return oss.str(); -} - -bool TryParse(const std::string &str, uint32_t *const output) -{ - char *endptr = NULL; - - // Holy crap this is ugly. - - // Reset errno to a value other than ERANGE - errno = 0; - - unsigned long value = strtoul(str.c_str(), &endptr, 0); - - if (!endptr || *endptr) - return false; - - if (errno == ERANGE) - return false; - - if (ULONG_MAX > UINT_MAX) { -#ifdef _MSC_VER -#pragma warning (disable:4309) -#endif - // Note: The typecasts avoid GCC warnings when long is 32 bits wide. - if (value >= static_cast(0x100000000ull) - && value <= static_cast(0xFFFFFFFF00000000ull)) - return false; - } - - *output = static_cast(value); - return true; -} - -bool TryParse(const std::string &str, bool *const output) -{ - if ("1" == str || !strcasecmp("true", str.c_str())) - *output = true; - else if ("0" == str || !strcasecmp("false", str.c_str())) - *output = false; - else - return false; - - return true; -} - -void SplitString(const std::string& str, const char delim, std::vector& output) -{ - size_t next = 0; - for (size_t pos = 0, len = str.length(); pos < len; ++pos) { - if (str[pos] == delim) { - output.push_back(str.substr(next, pos - next)); - // Skip the delimiter itself. - next = pos + 1; - } - } - - if (next == 0) { - output.push_back(str); - } else if (next < str.length()) { - output.push_back(str.substr(next)); - } -} - -void GetQuotedStrings(const std::string& str, std::vector& output) -{ - size_t next = 0; - bool even = 0; - for (size_t pos = 0, len = str.length(); pos < len; ++pos) { - if (str[pos] == '\"' || str[pos] == '\'') { - if (even) { - //quoted text - output.push_back(str.substr(next, pos - next)); - even = 0; - } else { - //non quoted text - even = 1; - } - // Skip the delimiter itself. - next = pos + 1; - } - } -} - -std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) -{ - size_t pos = 0; - - if (src == dest) - return result; - - while(1) - { - pos = result.find(src, pos); - if (pos == result.npos) - break; - result.replace(pos, src.size(), dest); - pos += dest.size(); - } - return result; -} - -int strcmpIgnore(std::string str1, std::string str2, std::string ignorestr1, std::string ignorestr2) { - str1 = ReplaceAll(str1, ignorestr1, ignorestr2); - str2 = ReplaceAll(str2, ignorestr1, ignorestr2); - return strcmp(str1.c_str(),str2.c_str()); -} diff --git a/ext/native/base/stringutil.h b/ext/native/base/stringutil.h deleted file mode 100644 index 6a06a739db..0000000000 --- a/ext/native/base/stringutil.h +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "base/basictypes.h" - -#ifdef _MSC_VER -#pragma warning (disable:4996) -#define strncasecmp _strnicmp -#else -#include -#endif - -// Dumb wrapper around itoa, providing a buffer. Declare this on the stack. -class ITOA { -public: - char buffer[16]; - const char *p(int i) { - sprintf(buffer, "%i", i); - return &buffer[0]; - } -}; - -// Useful for shaders with error messages.. -std::string LineNumberString(const std::string &str); - -// Other simple string utilities. - -inline bool startsWith(const std::string &str, const std::string &what) { - if (str.size() < what.size()) - return false; - return str.substr(0, what.size()) == what; -} - -inline bool endsWith(const std::string &str, const std::string &what) { - if (str.size() < what.size()) - return false; - return str.substr(str.size() - what.size()) == what; -} - -// Only use on strings where you're only concerned about ASCII. -inline bool startsWithNoCase(const std::string &str, const std::string &what) { - if (str.size() < what.size()) - return false; - return strncasecmp(str.c_str(), what.c_str(), what.size()) == 0; -} - -inline bool endsWithNoCase(const std::string &str, const std::string &what) { - if (str.size() < what.size()) - return false; - const size_t offset = str.size() - what.size(); - return strncasecmp(str.c_str() + offset, what.c_str(), what.size()) == 0; -} - -void DataToHexString(const uint8_t *data, size_t size, std::string *output); -inline void StringToHexString(const std::string &data, std::string *output) { - DataToHexString((uint8_t *)(&data[0]), data.size(), output); -} - - -// highly unsafe and not recommended. -unsigned int parseHex(const char* _szValue); - - -// Suitable for inserting into maps, unlike char*, and cheaper than std::string. -// Strings must be constant and preferably be stored in the read-only part -// of the binary. -class ConstString { -public: - ConstString(const char *ptr) { - ptr_ = ptr; - } - bool operator <(const ConstString &other) const { - return strcmp(ptr_, other.ptr_) < 0; - } - bool operator ==(const ConstString &other) const { - return ptr_ == other.ptr_ || !strcmp(ptr_, other.ptr_); - } - const char *get() const { return ptr_; } -private: - const char *ptr_; -}; - -std::string StringFromFormat(const char* format, ...); -std::string StringFromInt(int value); -std::string StringFromBool(bool value); - -std::string ArrayToString(const uint8_t *data, uint32_t size, int line_len = 20, bool spaces = true); - -std::string StripSpaces(const std::string &s); -std::string StripQuotes(const std::string &s); - -bool TryParse(const std::string &str, bool *const output); -bool TryParse(const std::string &str, uint32_t *const output); - -template -static bool TryParse(const std::string &str, N *const output) -{ - std::istringstream iss(str); - - N tmp = 0; - if (iss >> tmp) - { - *output = tmp; - return true; - } - else - return false; -} -void SplitString(const std::string& str, const char delim, std::vector& output); - -void GetQuotedStrings(const std::string& str, std::vector& output); - -std::string ReplaceAll(std::string input, const std::string& src, const std::string& dest); - -// Compare two strings, ignore the difference between the ignorestr1 and the ignorestr2 in str1 and str2. -int strcmpIgnore(std::string str1, std::string str2, std::string ignorestr1, std::string ignorestr2); - -template -static std::string ValueToString(const N value) -{ - std::stringstream string; - string << value; - return string.str(); -} - -void StringTrimEndNonAlphaNum(char *str); -void SkipSpace(const char **ptr); -void StringUpper(char *str); -void StringUpper(char *str, int len); diff --git a/ext/native/base/timeutil.cpp b/ext/native/base/timeutil.cpp deleted file mode 100644 index 5c70e80053..0000000000 --- a/ext/native/base/timeutil.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/timeutil.h" - -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -#ifdef HAVE_LIBNX -#include -#endif // HAVE_LIBNX - -static double curtime = 0; -static float curtime_f = 0; - -#ifdef _WIN32 - -LARGE_INTEGER frequency; -double frequencyMult; -LARGE_INTEGER startTime; - -double real_time_now() { - if (frequency.QuadPart == 0) { - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&startTime); - curtime = 0.0; - frequencyMult = 1.0 / static_cast(frequency.QuadPart); - } - LARGE_INTEGER time; - QueryPerformanceCounter(&time); - double elapsed = static_cast(time.QuadPart - startTime.QuadPart); - return elapsed * frequencyMult; -} - -#else - -uint64_t _frequency = 0; -uint64_t _starttime = 0; - -double real_time_now() { - static time_t start; - struct timeval tv; - gettimeofday(&tv, NULL); - if (start == 0) { - start = tv.tv_sec; - } - tv.tv_sec -= start; - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; -} - -#endif - -void time_update() { - curtime = real_time_now(); - curtime_f = (float)curtime; - - //printf("curtime: %f %f\n", curtime, curtime_f); - // also smooth time. - //curtime+=float((double) (time-_starttime) / (double) _frequency); - //curtime*=0.5f; - //curtime+=1.0f/60.0f; - //lastTime=curtime; - //curtime_f = (float)curtime; -} - -float time_now() { - return curtime_f; -} - -double time_now_d() { - return curtime; -} - -int time_now_ms() { - return int(curtime*1000.0); -} - -void sleep_ms(int ms) { -#ifdef _WIN32 - Sleep(ms); -#elif defined(HAVE_LIBNX) - svcSleepThread(ms * 1000000); -#else - usleep(ms * 1000); -#endif -} - -LoggingDeadline::LoggingDeadline(const char *name, int ms) : name_(name), endCalled_(false) { - totalTime_ = (double)ms * 0.001; - time_update(); - endTime_ = time_now_d() + totalTime_; -} - -LoggingDeadline::~LoggingDeadline() { - if (!endCalled_) - End(); -} - -bool LoggingDeadline::End() { - endCalled_ = true; - time_update(); - if (time_now_d() > endTime_) { - double late = (time_now_d() - endTime_); - double totalTime = late + totalTime_; - ELOG("===== %0.2fms DEADLINE PASSED FOR %s at %0.2fms - %0.2fms late =====", totalTime_ * 1000.0, name_, 1000.0 * totalTime, 1000.0 * late); - return false; - } - return true; -} - diff --git a/ext/native/base/timeutil.h b/ext/native/base/timeutil.h deleted file mode 100644 index 8ba68ca8ad..0000000000 --- a/ext/native/base/timeutil.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -// http://linux.die.net/man/3/clock_gettime - -// This time implementation caches the time for max performance (call time_now() as much as you like). -// You need to call time_update() once per frame (or whenever you need the correct time right now). - -void time_update(); - -// Seconds. -float time_now(); -double time_now_d(); - -// Uncached time. Slower than the above cached time functions. Does not update cached time, call time_update for that. -double real_time_now(); - -int time_now_ms(); - - -// Sleep. Does not necessarily have millisecond granularity, especially on Windows. -void sleep_ms(int ms); - - -// Can be sprinkled around the code to make sure that thing don't take -// unexpectedly long. What that means is up to you. -class LoggingDeadline { -public: - LoggingDeadline(const char *name, int deadline_in_ms); - ~LoggingDeadline(); - bool End(); - -private: - const char *name_; - bool endCalled_; - double totalTime_; - double endTime_; -}; \ No newline at end of file diff --git a/ext/native/data/compression.h b/ext/native/data/compression.h deleted file mode 100644 index e37ff85794..0000000000 --- a/ext/native/data/compression.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -bool compress_string(const std::string& str, std::string *dest, int compressionlevel = 9); -bool decompress_string(const std::string& str, std::string *dest); - - -// Delta encoding/decoding - many formats benefit from a pass of this before zlibbing. -// WARNING : Do not use these with floating point data, especially not float16... - -template -inline void delta(T *data, int length) { - T prev = data[0]; - for (int i = 1; i < length; i++) { - T temp = data[i] - prev; - prev = data[i]; - data[i] = temp; - } -} - -template -inline void dedelta(T *data, int length) { - for (int i = 1; i < length; i++) { - data[i] += data[i - 1]; - } -} - diff --git a/ext/native/data/listable.h b/ext/native/data/listable.h deleted file mode 100644 index 017cacf1b9..0000000000 --- a/ext/native/data/listable.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include -#include - -class Listable -{ -public: - virtual ~Listable() {} - virtual const char *getItem(size_t i) const = 0; - virtual size_t numItems() const = 0; - - // Returns -1 for not found. - // Child classes are meant to specialize this if they have a faster way - // than brute force search. - virtual int getIndex(const char *text) { - for (size_t i = 0; i < numItems(); i++) { - if (!strcmp(getItem(i), text)) - return i; - } - return -1; - } -}; - -class ArrayListable : public Listable -{ -public: - ArrayListable(const char * const*arr, size_t count) : arr_(arr), count_(count) {} - virtual ~ArrayListable() {} - - virtual const char *getItem(size_t i) const { return arr_[i]; } - virtual size_t numItems() const { return count_; } - -private: - const char *const*arr_; - size_t count_; -}; - -class VectorListable : public Listable -{ - VectorListable(const std::vector &vec) : vec_(vec) {} - virtual ~VectorListable() {} - - virtual const char *getItem(size_t i) const { return vec_[i].c_str(); } - virtual size_t numItems() const { return vec_.size(); } - -private: - const std::vector &vec_; -}; \ No newline at end of file diff --git a/ext/native/file/CMakeLists.txt b/ext/native/file/CMakeLists.txt deleted file mode 100644 index 6cb73d143a..0000000000 --- a/ext/native/file/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(SRCS - chunk_file.cpp - zip_read.cpp - file_util.cpp - free.cpp) - -set(SRCS ${SRCS}) - -add_library(file STATIC ${SRCS}) -target_link_libraries(file general zip) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/file/ini_file.h b/ext/native/file/ini_file.h deleted file mode 100644 index ba63ab1ab5..0000000000 --- a/ext/native/file/ini_file.h +++ /dev/null @@ -1,194 +0,0 @@ -// IniFile -// Taken from Dolphin but relicensed by me, Henrik Rydgard, under the MIT -// license as I wrote the whole thing originally and it has barely changed. - -#pragma once - -#include -#include -#include - -#include "base/stringutil.h" - -class IniFile -{ -public: - class Section - { - friend class IniFile; - - public: - Section() {} - Section(const std::string& name) : name_(name) {} - - bool Exists(const char *key) const; - bool Delete(const char *key); - - void Clear(); - - std::map ToMap() const; - - std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut); - void Set(const char* key, const char* newValue); - void Set(const char* key, const std::string& newValue, const std::string& defaultValue); - - void Set(const std::string &key, const std::string &value) { - Set(key.c_str(), value.c_str()); - } - bool Get(const char* key, std::string* value, const char* defaultValue); - - void Set(const char* key, uint32_t newValue) { - Set(key, StringFromFormat("0x%08x", newValue).c_str()); - } - void Set(const char* key, float newValue) { - Set(key, StringFromFormat("%f", newValue).c_str()); - } - void Set(const char* key, const float newValue, const float defaultValue); - void Set(const char* key, double newValue) { - Set(key, StringFromFormat("%f", newValue).c_str()); - } - - void Set(const char* key, int newValue, int defaultValue); - void Set(const char* key, int newValue) { - Set(key, StringFromInt(newValue).c_str()); - } - - void Set(const char* key, bool newValue, bool defaultValue); - void Set(const char* key, bool newValue) { - Set(key, StringFromBool(newValue).c_str()); - } - void Set(const char* key, const std::vector& newValues); - - template - void Set(const char* key, const std::map& newValues) - { - std::vector temp; - for(typename std::map::const_iterator it = newValues.begin(); it != newValues.end(); it++) - { - temp.push_back(ValueToString(it->first)+"_"+ValueToString(it->second)); - } - Set(key,temp); - } - - // Declare without a body to make it fail to compile. This is to prevent accidentally - // setting a pointer as a bool. The failure is in the linker unfortunately, but that's better - // than accidentally succeeding in a bad way. - template - void Set(const char *key, T *ptr); - - void AddComment(const std::string &comment); - - bool Get(const char* key, int* value, int defaultValue = 0); - bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0); - bool Get(const char* key, bool* value, bool defaultValue = false); - bool Get(const char* key, float* value, float defaultValue = false); - bool Get(const char* key, double* value, double defaultValue = false); - bool Get(const char* key, std::vector& values); - template - bool Get(const char* key, std::map& values) - { - std::vector temp; - if(!Get(key,temp)) - { - return false; - } - values.clear(); - for(size_t i = 0; i < temp.size(); i++) - { - std::vector key_val; - SplitString(temp[i],'_',key_val); - if(key_val.size() < 2) - continue; - U mapKey; - V mapValue; - if(!TryParse(key_val[0],&mapKey)) - continue; - if(!TryParse(key_val[1],&mapValue)) - continue; - values[mapKey] = mapValue; - } - return true; - } - - bool operator < (const Section& other) const { - return name_ < other.name_; - } - - const std::string &name() const { - return name_; - } - - protected: - std::vector lines; - std::string name_; - std::string comment; - }; - - bool Load(const char* filename); - bool Load(const std::string &filename) { return Load(filename.c_str()); } - bool Load(std::istream &istream); - bool LoadFromVFS(const std::string &filename); - - bool Save(const char* filename); - bool Save(const std::string &filename) { return Save(filename.c_str()); } - - // Returns true if key exists in section - bool Exists(const char* sectionName, const char* key) const; - - // TODO: Get rid of these, in favor of the Section ones. - void Set(const char* sectionName, const char* key, const char* newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, const std::string& newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue.c_str()); - } - void Set(const char* sectionName, const char* key, int newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, uint32_t newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, bool newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, const std::vector& newValues) { - GetOrCreateSection(sectionName)->Set(key, newValues); - } - - // TODO: Get rid of these, in favor of the Section ones. - bool Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue = ""); - bool Get(const char* sectionName, const char* key, int* value, int defaultValue = 0); - bool Get(const char* sectionName, const char* key, uint32_t* value, uint32_t defaultValue = 0); - bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false); - bool Get(const char* sectionName, const char* key, std::vector& values); - - template bool GetIfExists(const char* sectionName, const char* key, T value) - { - if (Exists(sectionName, key)) - return Get(sectionName, key, value); - return false; - } - - bool GetKeys(const char* sectionName, std::vector& keys) const; - - void SetLines(const char* sectionName, const std::vector &lines); - bool GetLines(const char* sectionName, std::vector& lines, const bool remove_comments = true) const; - - bool DeleteKey(const char* sectionName, const char* key); - bool DeleteSection(const char* sectionName); - - void SortSections(); - std::vector
&Sections() { return sections; } - - bool HasSection(const char *section) { return GetSection(section) != 0; } - - Section* GetOrCreateSection(const char* section); - -private: - std::vector
sections; - - const Section* GetSection(const char* section) const; - Section* GetSection(const char* section); - std::string* GetLine(const char* section, const char* key); - void CreateSection(const char* section); -}; diff --git a/ext/native/gfx/CMakeLists.txt b/ext/native/gfx/CMakeLists.txt deleted file mode 100644 index 19b9e236ed..0000000000 --- a/ext/native/gfx/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -set(SRCS - gl_debug_log.cpp - #gl_lost_manager.cpp - texture_atlas.cpp) - -set(SRCS ${SRCS}) - -add_library(gfx STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/gfx_es2/CMakeLists.txt b/ext/native/gfx_es2/CMakeLists.txt deleted file mode 100644 index 75fbdd6ea8..0000000000 --- a/ext/native/gfx_es2/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(SRCS - draw_buffer.cpp - draw_text.cpp - glsl_program.cpp - gpu_features.cpp - gl_state.cpp) - -set(SRCS ${SRCS}) - -add_library(gfx_es2 STATIC ${SRCS}) -target_link_libraries(gfx_es2 general gfx) -target_link_libraries(gfx_es2 general file) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/image/CMakeLists.txt b/ext/native/image/CMakeLists.txt deleted file mode 100644 index c835ef7134..0000000000 --- a/ext/native/image/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(SRCS - png_load.cpp - zim_load.cpp - zim_save.cpp -) - -set(SRCS ${SRCS}) - -add_library(image STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) - diff --git a/ext/native/image/png_load.cpp b/ext/native/image/png_load.cpp deleted file mode 100644 index c6be6b5c38..0000000000 --- a/ext/native/image/png_load.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include -#include - -#ifdef USING_QT_UI -#include -#else -#include -#endif - -#include "png_load.h" -#include "base/logging.h" - -// *image_data_ptr should be deleted with free() -// return value of 1 == success. -int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_data_ptr, bool flip) { -#ifdef USING_QT_UI - QImage image(file, "PNG"); - if (image.isNull()) { - ELOG("pngLoad: Error loading image %s", file); - return 0; - } - - if (flip) - image = image.mirrored(); - *pwidth = image.width(); - *pheight = image.height(); - image = image.convertToFormat(QImage::Format_ARGB32); - *image_data_ptr = (unsigned char *)malloc(image.byteCount()); - uint32_t *src = (uint32_t*) image.bits(); - uint32_t *dest = (uint32_t*) *image_data_ptr; - // Qt4 does not support RGBA - for (size_t sz = 0; sz < (size_t)image.byteCount(); sz+=4, ++src, ++dest) { - const uint32_t v = *src; - *dest = (v & 0xFF00FF00) | ((v & 0xFF) << 16) | (( v >> 16 ) & 0xFF); // ARGB -> RGBA - } -#else - if (flip) - ELOG("pngLoad: flip flag not supported, image will be loaded upside down"); - png_image png; - memset(&png, 0, sizeof(png)); - png.version = PNG_IMAGE_VERSION; - - png_image_begin_read_from_file(&png, file); - - if (PNG_IMAGE_FAILED(png)) - { - ELOG("pngLoad: %s", png.message); - return 0; - } - *pwidth = png.width; - *pheight = png.height; - png.format = PNG_FORMAT_RGBA; - - int stride = PNG_IMAGE_ROW_STRIDE(png); - *image_data_ptr = (unsigned char *)malloc(PNG_IMAGE_SIZE(png)); - png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL); -#endif - - return 1; -} - -int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, int *pheight, unsigned char **image_data_ptr, - bool flip) { -#ifdef USING_QT_UI - QImage image; - if (!image.loadFromData(input_ptr, input_len, "PNG")) { - ELOG("pngLoad: Error loading image"); - return 0; - } - if (flip) - image = image.mirrored(); - *pwidth = image.width(); - *pheight = image.height(); - image = image.convertToFormat(QImage::Format_ARGB32); - *image_data_ptr = (unsigned char *)malloc(image.byteCount()); - uint32_t *src = (uint32_t*) image.bits(); - uint32_t *dest = (uint32_t*) *image_data_ptr; - // Qt4 does not support RGBA - for (size_t sz = 0; sz < (size_t)image.byteCount(); sz+=4, ++src, ++dest) { - const uint32_t v = *src; - *dest = (v & 0xFF00FF00) | ((v & 0xFF) << 16) | (( v >> 16 ) & 0xFF); // convert it! - } -#else - if (flip) - ELOG("pngLoad: flip flag not supported, image will be loaded upside down"); - png_image png{}; - png.version = PNG_IMAGE_VERSION; - - png_image_begin_read_from_memory(&png, input_ptr, input_len); - - if (PNG_IMAGE_FAILED(png)) { - ELOG("pngLoad: %s", png.message); - return 0; - } - *pwidth = png.width; - *pheight = png.height; - png.format = PNG_FORMAT_RGBA; - - int stride = PNG_IMAGE_ROW_STRIDE(png); - - size_t size = PNG_IMAGE_SIZE(png); - if (!size) { - ELOG("pngLoad: empty image"); - return 0; - } - - *image_data_ptr = (unsigned char *)malloc(size); - png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL); -#endif - - return 1; -} diff --git a/ext/native/input/CMakeLists.txt b/ext/native/input/CMakeLists.txt deleted file mode 100644 index 266cff4ba7..0000000000 --- a/ext/native/input/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(SRCS - input_state.cpp - gesture_detector.cpp) - -set(SRCS ${SRCS}) - -add_library(input STATIC ${SRCS}) -target_link_libraries(input general gfx) -target_link_libraries(input general file) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/json/CMakeLists.txt b/ext/native/json/CMakeLists.txt deleted file mode 100644 index 9c3ec2f57f..0000000000 --- a/ext/native/json/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(SRCS - json_writer.cpp) - -set(SRCS ${SRCS}) - -add_library(jsonwriter STATIC ${SRCS}) - - - -add_executable(json_writer_test json_writer_test.cpp) -target_link_libraries(json_writer_test jsonwriter) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/json/json_writer_test.cpp b/ext/native/json/json_writer_test.cpp deleted file mode 100644 index 46875ac12b..0000000000 --- a/ext/native/json/json_writer_test.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "json/json_writer.h" -#include - -int main() { - JsonWriter j; - j.begin(); - j.pushDict("settings"); - j.writeInt("volume", 50); - j.writeInt("sound", 60); - j.pop(); - j.pushDict("user"); - j.writeFloat("level", 1.5); - j.writeString("name", "hello"); - j.pop(); - j.writeInt("outer", 3); - j.pushArray("ints"); - j.writeInt(3); - j.writeInt(4); - j.writeInt(6); - j.pop(); - j.writeString("yo!", "yo"); - j.end(); - std::cout << j.str(); - return 0; -} diff --git a/ext/native/math/CMakeLists.txt b/ext/native/math/CMakeLists.txt deleted file mode 100644 index 4093973f06..0000000000 --- a/ext/native/math/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(SRCS - lin/matrix4x4.cpp - lin/vec3.cpp - lin/quat.cpp - curves.cpp - math_util.cpp - ) - -set(SRCS ${SRCS}) - -add_library(lin STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/math/lin/matrix4x4.cpp b/ext/native/math/lin/matrix4x4.cpp deleted file mode 100644 index 007b8a8d17..0000000000 --- a/ext/native/math/lin/matrix4x4.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include "math/lin/matrix4x4.h" - -#include - -#include "math/lin/vec3.h" -#include "math/lin/quat.h" -#include "math/fast/fast_matrix.h" - -#ifdef _WIN32 -#undef far -#undef near -#endif - -// See http://code.google.com/p/oolongengine/source/browse/trunk/Oolong+Engine2/Math/neonmath/neon_matrix_impl.cpp?spec=svn143&r=143 when we need speed -// no wait. http://code.google.com/p/math-neon/ - -namespace Lin { - -Matrix4x4 Matrix4x4::simpleInverse() const { - Matrix4x4 out; - out.xx = xx; - out.xy = yx; - out.xz = zx; - - out.yx = xy; - out.yy = yy; - out.yz = zy; - - out.zx = xz; - out.zy = yz; - out.zz = zz; - - out.wx = -(xx * wx + xy * wy + xz * wz); - out.wy = -(yx * wx + yy * wy + yz * wz); - out.wz = -(zx * wx + zy * wy + zz * wz); - - out.xw = 0.0f; - out.yw = 0.0f; - out.zw = 0.0f; - out.ww = 1.0f; - - return out; -} - -Matrix4x4 Matrix4x4::transpose() const -{ - Matrix4x4 out; - out.xx = xx;out.xy = yx;out.xz = zx;out.xw = wx; - out.yx = xy;out.yy = yy;out.yz = zy;out.yw = wy; - out.zx = xz;out.zy = yz;out.zz = zz;out.zw = wz; - out.wx = xw;out.wy = yw;out.wz = zw;out.ww = ww; - return out; -} - -Matrix4x4 Matrix4x4::operator * (const Matrix4x4 &other) const -{ - Matrix4x4 temp; - fast_matrix_mul_4x4(temp.m, other.m, this->m); - return temp; -} - -Matrix4x4 Matrix4x4::inverse() const { - Matrix4x4 temp; - float dW = 1.0f / (xx*(yy*zz - yz*zy) - xy*(yx*zz - yz*zx) - xz*(yy*zx - yx*zy)); - - temp.xx = (yy*zz - yz*zy) * dW; - temp.xy = (xz*zy - xy*zz) * dW; - temp.xz = (xy*yz - xz*yy) * dW; - temp.xw = xw; - - temp.yx = (yz*zx - yx*zz) * dW; - temp.yy = (xx*zz - xz*zx) * dW; - temp.yz = (xz*yx - xx*zx) * dW; - temp.yw = yw; - - temp.zx = (yx*zy - yy*zx) * dW; - temp.zy = (xy*zx - xx*zy) * dW; - temp.zz = (xx*yy - xy*yx) * dW; - temp.zw = zw; - - temp.wx = (yy*(zx*wz - zz*wx) + yz*(zy*wx - zx*wy) - yx*(zy*wz - zz*wy)) * dW; - temp.wy = (xx*(zy*wz - zz*wy) + xy*(zz*wx - zx*wz) + xz*(zx*wy - zy*wx)) * dW; - temp.wz = (xy*(yx*wz - yz*wx) + xz*(yy*wx - yx*wy) - xx*(yy*wz - yz*wy)) * dW; - temp.ww = ww; - - return temp; -} - -void Matrix4x4::setViewLookAt(const Vec3 &vFrom, const Vec3 &vAt, const Vec3 &vWorldUp) { - Vec3 vView = vFrom - vAt; // OpenGL, sigh... - vView.normalize(); - float DotProduct = vWorldUp * vView; - Vec3 vUp = vWorldUp - vView * DotProduct; - float Length = vUp.length(); - - if (1e-6f > Length) { - // EMERGENCY - vUp = Vec3(0.0f, 1.0f, 0.0f) - vView * vView.y; - // If we still have near-zero length, resort to a different axis. - Length = vUp.length(); - if (1e-6f > Length) - { - vUp = Vec3(0.0f, 0.0f, 1.0f) - vView * vView.z; - Length = vUp.length(); - if (1e-6f > Length) - return; - } - } - vUp.normalize(); - Vec3 vRight = vUp % vView; - empty(); - - xx = vRight.x; xy = vUp.x; xz=vView.x; - yx = vRight.y; yy = vUp.y; yz=vView.y; - zx = vRight.z; zy = vUp.z; zz=vView.z; - - wx = -vFrom * vRight; - wy = -vFrom * vUp; - wz = -vFrom * vView; - ww = 1.0f; -} - -void Matrix4x4::setViewLookAtD3D(const Vec3 &vFrom, const Vec3 &vAt, const Vec3 &vWorldUp) { - Vec3 vView = vAt - vFrom; - vView.normalize(); - float DotProduct = vWorldUp * vView; - Vec3 vUp = vWorldUp - vView * DotProduct; - float Length = vUp.length(); - - if (1e-6f > Length) { - vUp = Vec3(0.0f, 1.0f, 0.0f) - vView * vView.y; - // If we still have near-zero length, resort to a different axis. - Length = vUp.length(); - if (1e-6f > Length) - { - vUp = Vec3(0.0f, 0.0f, 1.0f) - vView * vView.z; - Length = vUp.length(); - if (1e-6f > Length) - return; - } - } - vUp.normalize(); - Vec3 vRight = vUp % vView; - empty(); - - xx = vRight.x; xy = vUp.x; xz=vView.x; - yx = vRight.y; yy = vUp.y; yz=vView.y; - zx = vRight.z; zy = vUp.z; zz=vView.z; - - wx = -vFrom * vRight; - wy = -vFrom * vUp; - wz = -vFrom * vView; - ww = 1.0f; -} - -void Matrix4x4::setViewFrame(const Vec3 &pos, const Vec3 &vRight, const Vec3 &vView, const Vec3 &vUp) { - xx = vRight.x; xy = vUp.x; xz=vView.x; xw = 0.0f; - yx = vRight.y; yy = vUp.y; yz=vView.y; yw = 0.0f; - zx = vRight.z; zy = vUp.z; zz=vView.z; zw = 0.0f; - - wx = -pos * vRight; - wy = -pos * vUp; - wz = -pos * vView; - ww = 1.0f; -} - -//YXZ euler angles -void Matrix4x4::setRotation(float x,float y, float z) -{ - setRotationY(y); - Matrix4x4 temp; - temp.setRotationX(x); - *this *= temp; - temp.setRotationZ(z); - *this *= temp; -} - -void Matrix4x4::setProjection(float near, float far, float fov_horiz, float aspect) { - // Now OpenGL style. - empty(); - - float xFac = tanf(fov_horiz * 3.14f/360); - float yFac = xFac * aspect; - xx = 1.0f / xFac; - yy = 1.0f / yFac; - zz = -(far+near)/(far-near); - zw = -1.0f; - wz = -(2*far*near)/(far-near); -} - -void Matrix4x4::setProjectionD3D(float near_plane, float far_plane, float fov_horiz, float aspect) { - empty(); - float Q, f; - - f = fov_horiz*0.5f; - Q = far_plane / (far_plane - near_plane); - - xx = (float)(1.0f / tanf(f));; - yy = (float)(1.0f / tanf(f*aspect)); - zz = Q; - wz = -Q * near_plane; - zw = 1.0f; -} - -void Matrix4x4::setOrtho(float left, float right, float bottom, float top, float near, float far) { - empty(); - xx = 2.0f / (right - left); - yy = 2.0f / (top - bottom); - zz = 2.0f / (far - near); - wx = -(right + left) / (right - left); - wy = -(top + bottom) / (top - bottom); - wz = -(far + near) / (far - near); - ww = 1.0f; -} - -void Matrix4x4::setOrthoD3D(float left, float right, float bottom, float top, float near, float far) { - empty(); - xx = 2.0f / (right - left); - yy = 2.0f / (top - bottom); - zz = 1.0f / (far - near); - wx = -(right + left) / (right - left); - wy = -(top + bottom) / (top - bottom); - wz = -near / (far - near); - ww = 1.0f; -} - -void Matrix4x4::setOrthoVulkan(float left, float right, float top, float bottom, float near, float far) { - empty(); - xx = 2.0f / (right - left); - yy = 2.0f / (bottom - top); - zz = 1.0f / (far - near); - wx = -(right + left) / (right - left); - wy = -(top + bottom) / (bottom - top); - wz = -near / (far - near); - ww = 1.0f; -} - -void Matrix4x4::toText(char *buffer, int len) const { - snprintf(buffer, len, "%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", - xx,xy,xz,xw, - yx,yy,yz,yw, - zx,zy,zz,zw, - wx,wy,wz,ww); - buffer[len - 1] = '\0'; -} - -void Matrix4x4::print() const { - char buffer[256]; - toText(buffer, 256); - puts(buffer); -} - -} diff --git a/ext/native/math/lin/plane.cpp b/ext/native/math/lin/plane.cpp deleted file mode 100644 index d62277889d..0000000000 --- a/ext/native/math/lin/plane.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "math/lin/matrix4x4.h" -#include "math/lin/plane.h" - -namespace Lin { - -void Plane::TransformByIT(const Matrix4x4 &m, Plane *out) { - out->x = x * m.xx + y * m.yx + z * m.zx + d * m.wx; - out->y = x * m.xy + y * m.yy + z * m.zy + d * m.wy; - out->z = x * m.xz + y * m.yz + z * m.zz + d * m.wz; - out->d = x * m.xw + y * m.yw + z * m.zw + d * m.ww; -} - -} // namespace Lin diff --git a/ext/native/math/lin/plane.h b/ext/native/math/lin/plane.h deleted file mode 100644 index 295c3f250a..0000000000 --- a/ext/native/math/lin/plane.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _PLANE_H -#define _PLANE_H - -#include "math/lin/vec3.h" - -namespace Lin { - -class Matrix4x4; - -class Plane { -public: - float x, y, z, d; - Plane() {} - Plane(float x_, float y_, float z_, float d_) - : x(x_), y(y_), z(z_), d(d_) { } - ~Plane() {} - - float Distance(const Vec3 &v) const { - return x * v.x + y * v.y + z * v.z + d; - } - - float Distance(float px, float py, float pz) const { - return x * px + y * py + z * pz + d; - } - - void Normalize() { - float inv_length = sqrtf(x * x + y * y + z * z); - x *= inv_length; - y *= inv_length; - z *= inv_length; - d *= inv_length; - } - - // Matrix is the inverse transpose of the wanted transform. - // out cannot be equal to this. - void TransformByIT(const Matrix4x4 &matrix, Plane *out); -}; - -} // namespace Lin - -#endif diff --git a/ext/native/math/lin/quat.cpp b/ext/native/math/lin/quat.cpp deleted file mode 100644 index f5479a51f5..0000000000 --- a/ext/native/math/lin/quat.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "math/lin/quat.h" -#include "math/lin/matrix4x4.h" - -namespace Lin { - -void Quaternion::toMatrix(Matrix4x4 *out) const { - Matrix4x4 temp; - temp.setIdentity(); - float ww, xx, yy, zz, wx, wy, wz, xy, xz, yz; - ww = w*w; xx = x*x; yy = y*y; zz = z*z; - wx = w*x*2; wy = w*y*2; wz = w*z*2; - xy = x*y*2; xz = x*z*2; yz = y*z*2; - - temp.xx = ww + xx - yy - zz; - temp.xy = xy + wz; - temp.xz = xz - wy; - - temp.yx = xy - wz; - temp.yy = ww - xx + yy - zz; - temp.yz = yz + wx; - - temp.zx = xz + wy; - temp.zy = yz - wx; - temp.zz = ww - xx - yy + zz; - - *out = temp; -} - -Quaternion Quaternion::fromMatrix(Matrix4x4 &m) -{ - // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes - // article "Quaternion Calculus and Fast Animation". - Quaternion q(0,0,0,1); - /* - float fTrace = m[0][0] + m[1][1] + m[2][2]; - float fRoot; - - if( fTrace > 0.0 ) - { - fRoot = sqrtf( fTrace + 1.0f ); - - q.w = 0.5f * fRoot; - - fRoot = 0.5f / fRoot; - - q.x = ( m[2][1] - m[1][2] ) * fRoot; - q.y = ( m[0][2] - m[2][0] ) * fRoot; - q.z = ( m[1][0] - m[0][1] ) * fRoot; - } - else - { - int iNext[3] = { 1, 2, 0 }; - - int i = 0; - if( m[1][1] > m[0][0] ) - i = 1; - - if( m[2][2] > m[i][i] ) - i = 2; - - int j = iNext[i]; - int k = iNext[j]; - - fRoot = sqrtf( m[i][i] - m[j][j] - m[k][k] + 1.0f ); - - float *apfQuat = &q.x; - - apfQuat[i] = 0.5f * fRoot; - - fRoot = 0.5f / fRoot; - - q.w = ( m[k][j] - m[j][k] ) * fRoot; - - apfQuat[j] = ( m[j][i] + m[i][j] ) * fRoot; - apfQuat[k] = ( m[k][i] + m[i][k] ) * fRoot; - } - q.normalize(); */ - return q; -}; - -// TODO: Allegedly, lerp + normalize can achieve almost as good results. -Quaternion Quaternion::slerp(const Quaternion &to, const float a) const { - Quaternion to2; - float angle, cos_angle, scale_from, scale_to, sin_angle; - - cos_angle = (x * to.x) + (y * to.y) + (z * to.z) + (w * to.w); //4D dot product - - if (cos_angle < 0.0f) - { - cos_angle = -cos_angle; - to2.w = -to.w; to2.x = -to.x; to2.y = -to.y; to2.z = -to.z; - } - else - { - to2 = to; - } - - if ((1.0f - fabsf(cos_angle)) > 0.00001f) - { - /* spherical linear interpolation (SLERP) */ - angle = acosf(cos_angle); - sin_angle = sinf(angle); - scale_from = sinf((1.0f - a) * angle) / sin_angle; - scale_to = sinf(a * angle) / sin_angle; - } - else - { - /* to prevent divide-by-zero, resort to linear interpolation */ - // This is okay in 99% of cases anyway, maybe should be the default? - scale_from = 1.0f - a; - scale_to = a; - } - - return Quaternion( - scale_from*x + scale_to*to2.x, - scale_from*y + scale_to*to2.y, - scale_from*z + scale_to*to2.z, - scale_from*w + scale_to*to2.w - ); -} - -Quaternion Quaternion::multiply(const Quaternion &q) const { - return Quaternion((w * q.x) + (x * q.w) + (y * q.z) - (z * q.y), - (w * q.y) + (y * q.w) + (z * q.x) - (x * q.z), - (w * q.z) + (z * q.w) + (x * q.y) - (y * q.x), - (w * q.w) - (x * q.x) - (y * q.y) - (z * q.z)); -} - -} diff --git a/ext/native/math/lin/quat.h b/ext/native/math/lin/quat.h deleted file mode 100644 index 8be9a94f5c..0000000000 --- a/ext/native/math/lin/quat.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef _MATH_LIN_QUAT_H -#define _MATH_LIN_QUAT_H - -#include "math/lin/vec3.h" - -namespace Lin { - -class Matrix4x4; - -class Quaternion -{ -public: - float x,y,z,w; - - Quaternion() { } - Quaternion(const float _x, const float _y, const float _z, const float _w) { - x=_x; y=_y; z=_z; w=_w; - } - void setIdentity() - { - x=y=z=0; w=1.0f; - } - void setXRotation(const float r) { w = cosf(r / 2); x = sinf(r / 2); y = z = 0; } - void setYRotation(const float r) { w = cosf(r / 2); y = sinf(r / 2); x = z = 0; } - void setZRotation(const float r) { w = cosf(r / 2); z = sinf(r / 2); x = y = 0; } - void toMatrix(Matrix4x4 *out) const; - static Quaternion fromMatrix(Matrix4x4 &m); - - Quaternion operator *(Quaternion &q) const - { - return Quaternion( - (w * q.w) - (x * q.x) - (y * q.y) - (z * q.z), - (w * q.x) + (x * q.w) + (y * q.z) - (z * q.y), - (w * q.y) + (y * q.w) + (z * q.x) - (x * q.z), - (w * q.z) + (z * q.w) + (x * q.y) - (y * q.x) - ); - } - Quaternion operator -() - { - return Quaternion(-x,-y,-z,-w); - } - void setRotation(Vec3 axis, float angle) - { - axis /= axis.length(); - angle *= .5f; - float sine = sinf(angle); - w = cosf(angle); - x = sine * axis.x; - y = sine * axis.y; - z = sine * axis.z; - } - void toAxisAngle(Vec3 &v, float &angle) - { - normalize(); - if (w==1.0f && x==0.0f && y==0.0f && z==0.0f) - { - v = Vec3(0,1,0); - angle = 0.0f; - return; - } - float cos_a = w; - angle = acosf(cos_a) * 2; - float sin_a = sqrtf( 1.0f - cos_a * cos_a ); - if (fabsf(sin_a) < 0.00005f) sin_a = 1; - float inv_sin_a=1.0f/sin_a; - v.x = x * inv_sin_a; - v.y = y * inv_sin_a; - v.z = z * inv_sin_a; - } - enum { - QUAT_SHORT, - QUAT_LONG, - QUAT_CW, - QUAT_CCW - }; - Quaternion slerp(const Quaternion &to, const float a) const; - Quaternion multiply(const Quaternion &q) const; - float &operator [] (int i) { - return *((&x) + i); - } - float operator [] (int i) const { - return *((&x) + i); - } - //not sure about this, maybe mag is supposed to sqrt - float magnitude() const { - return x*x + y*y + z*z + w*w; - } - void normalize() { - float f = 1.0f/sqrtf(magnitude()); - x*=f; y*=f; z*=f; w*=f; - } -}; - -} // namespace Lin - -#endif // _MATH_LIN_QUAT_H diff --git a/ext/native/math/lin/ray.h b/ext/native/math/lin/ray.h deleted file mode 100644 index 2287460fbb..0000000000 --- a/ext/native/math/lin/ray.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "vec3.h" - -/* __declspec(align(16)) */ struct Ray -{ - Vec3 origin; - int pad; - Vec3 dir; - int pad2; - Vec3 invdir; - int pad3; -}; - diff --git a/ext/native/math/lin/vec3.cpp b/ext/native/math/lin/vec3.cpp deleted file mode 100644 index 95c2469fc3..0000000000 --- a/ext/native/math/lin/vec3.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - -#include "math/lin/vec3.h" -#include "math/lin/matrix4x4.h" - -namespace Lin { - -Vec3 Vec3::operator *(const Matrix4x4 &m) const { - return Vec3(x*m.xx + y*m.yx + z*m.zx + m.wx, - x*m.xy + y*m.yy + z*m.zy + m.wy, - x*m.xz + y*m.yz + z*m.zz + m.wz); -} -Vec4 Vec3::multiply4D(const Matrix4x4 &m) const { - return Vec4(x*m.xx + y*m.yx + z*m.zx + m.wx, - x*m.xy + y*m.yy + z*m.zy + m.wy, - x*m.xz + y*m.yz + z*m.zz + m.wz, - x*m.xw + y*m.yw + z*m.zw + m.ww); -} -Vec4 Vec4::multiply4D(Matrix4x4 &m) const { - return Vec4(x*m.xx + y*m.yx + z*m.zx + w*m.wx, - x*m.xy + y*m.yy + z*m.zy + w*m.wy, - x*m.xz + y*m.yz + z*m.zz + w*m.wz, - x*m.xw + y*m.yw + z*m.zw + w*m.ww); -} - -Vec3 Vec3::rotatedBy(const Matrix4x4 &m) const { - return Vec3(x*m.xx + y*m.yx + z*m.zx, - x*m.xy + y*m.yy + z*m.zy, - x*m.xz + y*m.yz + z*m.zz); -} - -} // namespace Lin diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj deleted file mode 100644 index 60f361b959..0000000000 --- a/ext/native/native.vcxproj +++ /dev/null @@ -1,1219 +0,0 @@ - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - - {C4DF647E-80EA-4111-A0A8-218B1B711E18} - Win32Proj - native - 10.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StaticLibrary - true - Unicode - $(DefaultPlatformToolset) - - - StaticLibrary - true - Unicode - $(DefaultPlatformToolset) - - - StaticLibrary - true - Unicode - $(DefaultPlatformToolset) - true - - - StaticLibrary - true - Unicode - $(DefaultPlatformToolset) - true - - - StaticLibrary - false - false - Unicode - $(DefaultPlatformToolset) - - - StaticLibrary - false - Unicode - $(DefaultPlatformToolset) - - - StaticLibrary - false - Unicode - $(DefaultPlatformToolset) - true - - - StaticLibrary - false - Unicode - $(DefaultPlatformToolset) - true - - - - - - - - - $(VC_IncludePath);$(WindowsSDK_IncludePath) - - - $(VC_IncludePath);$(WindowsSDK_IncludePath) - - - - - - - - - $(VC_IncludePath);$(WindowsSDK_IncludePath) - - - $(VC_IncludePath);$(WindowsSDK_IncludePath) - - - - - - Level3 - _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - true - false - false - MultiThreadedDebug - ../../Common/DbgNew.h - ProgramDatabase - - - Windows - true - - - Ws2_32.lib - - - - - - - Level3 - _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - true - false - false - MultiThreadedDebug - false - ../../Common/DbgNew.h - ProgramDatabase - - - Windows - true - - - Ws2_32.lib - - - - - - - Level3 - _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - true - false - false - MultiThreadedDebug - false - ../../Common/DbgNew.h - ProgramDatabase - - - Windows - true - - - Ws2_32.lib - - - - - - - Level3 - _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - true - false - false - MultiThreadedDebug - false - - - ProgramDatabase - - - Windows - true - - - Ws2_32.lib - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - StreamingSIMDExtensions2 - Precise - true - false - MultiThreaded - ProgramDatabase - false - - - Windows - true - true - true - - - Ws2_32.lib - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - NotSet - Precise - true - false - MultiThreaded - ProgramDatabase - false - true - false - - - Windows - true - true - true - - - Ws2_32.lib - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - NotSet - Precise - true - false - MultiThreaded - ProgramDatabase - false - true - false - - - Windows - true - true - true - - - Ws2_32.lib - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\native\ext\libpng17;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - NotSet - Precise - true - false - MultiThreaded - ProgramDatabase - false - true - false - - - Windows - true - true - true - - - Ws2_32.lib - - - - - true - true - true - true - true - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - - - - - - - AnySuitable - true - Speed - AnySuitable - Speed - AnySuitable - AnySuitable - AnySuitable - true - true - true - Speed - Speed - Speed - false - false - false - AnySuitable - AnySuitable - AnySuitable - Speed - Speed - Speed - false - false - false - StreamingSIMDExtensions2 - Precise - StreamingSIMDExtensions2 - StreamingSIMDExtensions2 - StreamingSIMDExtensions2 - Precise - Precise - Precise - MaxSpeed - MaxSpeed - MaxSpeed - MaxSpeed - Default - Default - Default - Default - - - - - - - - - - - - - - - - - - - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - CompileAsCpp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - true - true - true - true - true - true - true - - - - - - - - - - - - - - - - - - - - - AssemblyAndSourceCode - AssemblyAndSourceCode - AssemblyAndSourceCode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters deleted file mode 100644 index 9c6af13184..0000000000 --- a/ext/native/native.vcxproj.filters +++ /dev/null @@ -1,910 +0,0 @@ -๏ปฟ - - - - file - - - - base - - - - ext - - - tools - - - ui - - - ext\libzip - - - math\fast - - - base - - - - - gfx - - - image - - - image - - - image - - - math - - - math - - - math - - - gfx - - - gfx - - - profiler - - - input - - - file - - - file - - - file - - - base - - - gfx - - - math - - - base - - - input - - - base - - - ext - - - base - - - json - - - file - - - file - - - base - - - base - - - ui - - - data - - - base - - - net - - - base - - - file - - - net - - - ui - - - base - - - math - - - util - - - math - - - ui - - - gfx - - - util - - - ext - - - ext - - - thread - - - thread - - - i18n - - - file - - - thread - - - ui - - - ui - - - math - - - net - - - ui - - - data - - - math - - - gfx - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - util - - - ext\jpge - - - ext\jpge - - - gfx - - - math\fast - - - math\fast - - - util - - - util - - - thin3d - - - thin3d - - - net - - - net - - - thread - - - gfx - - - input - - - file - - - math - - - net - - - util - - - gfx - - - gfx - - - thin3d - - - gfx - - - gfx - - - gfx - - - thin3d - - - thin3d - - - thin3d - - - ui - - - base - - - thin3d - - - thin3d - - - thin3d - - - thin3d - - - ext\gason - - - json - - - net - - - data - - - thin3d - - - ui - - - util - - - - - gfx - - - image - - - image - - - image - - - math - - - math - - - math - - - gfx - - - gfx - - - profiler - - - file - - - file - - - gfx - - - base - - - input - - - ext - - - base - - - json - - - file - - - file - - - base - - - ui - - - math - - - net - - - base - - - file - - - base - - - net - - - ui - - - base - - - math - - - math - - - ui - - - gfx - - - util - - - ext - - - thread - - - thread - - - i18n - - - file - - - thread - - - ui - - - ui - - - net - - - ui - - - data - - - math - - - input - - - gfx - - - util - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libpng17 - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - ext\libzip - - - util - - - ext\jpge - - - ext\jpge - - - gfx - - - math\fast - - - math\fast - - - math\fast - - - thin3d - - - thin3d - - - thin3d - - - thin3d - - - net - - - net - - - thread - - - base - - - base - - - file - - - thin3d - - - net - - - util - - - thin3d - - - gfx - - - gfx - - - thin3d - - - base - - - gfx - - - gfx - - - gfx - - - math - - - thin3d - - - thin3d - - - ui - - - thin3d - - - thin3d - - - thin3d - - - ext\gason - - - json - - - net - - - data - - - thin3d - - - ui - - - - - {9da89505-72a1-40e6-86e5-705372db1608} - - - {828bddaf-63e5-4311-985b-bf377f86ff00} - - - {f3f83007-7c3b-473f-a2f7-423c5087fbfa} - - - {5c54b5e2-1bb2-4783-9df6-de4ff7105570} - - - {c57b41dd-cc33-46ac-b479-19676455ae54} - - - {4ba4474c-b80f-40da-95e8-2de57eb1b327} - - - {49afd06e-eb44-41ac-b038-e109e444a834} - - - {95e41110-57a2-497f-a938-b4c8e9dd6a27} - - - {cda27e9f-5763-4bf2-b6bc-85a377f7020e} - - - {d738c2d1-749d-4b60-b98f-f3da0bbbf40c} - - - {e36ca540-863c-496b-b0f4-b1ece3e72feb} - - - {d5fa3d62-88bf-4dc4-9814-28f3c0444e62} - - - {1e85f968-7106-483c-ae7d-77d0ef58d787} - - - {6a548b3d-3a4c-4114-aa2f-0b42bf7bf2ce} - - - {4515306f-4664-46bf-a89b-abfec5520a15} - - - {caa41117-1d90-47cc-9fba-f7e670e315a3} - - - {02e8ef95-82c7-4420-b029-a189a5e0fcbd} - - - {aa8b9b49-2ff8-4961-b6cc-9c33ea674130} - - - {6c47ee5b-0375-40f0-ab2a-402d001cc9c7} - - - {3721adbc-1a4a-4017-bc1d-893c7e86bc22} - - - {5ce64c0e-98e4-4411-86cc-aacaf2f60b21} - - - {06c6305a-a646-485b-85b9-645a24dd6553} - - - {5b740c6f-8dbc-4529-9114-6564b37b3548} - - - \ No newline at end of file diff --git a/ext/native/net/CMakeLists.txt b/ext/native/net/CMakeLists.txt deleted file mode 100644 index 10d69f4d51..0000000000 --- a/ext/native/net/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(SRCS - http_client.cpp - resolve.cpp) - -set(SRCS ${SRCS}) - -add_library(net STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/profiler/CMakeLists.txt b/ext/native/profiler/CMakeLists.txt deleted file mode 100644 index f3f9673dac..0000000000 --- a/ext/native/profiler/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(SRCS - profiler.cpp -) - -# LGUIFileList.cpp - -add_library(profiler STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) diff --git a/ext/native/thin3d/d3dx9_loader.cpp b/ext/native/thin3d/d3dx9_loader.cpp deleted file mode 100644 index f269ecbe04..0000000000 --- a/ext/native/thin3d/d3dx9_loader.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "base/logging.h" -#include "thin3d/d3dx9_loader.h" - -// TODO: See if we can use the bundled D3Dcompiler_47.dll to compiler for DX9 as well. - -typedef BOOL(__stdcall *TFunc_D3DXCheckVersion)(UINT D3DSDKVersion, UINT D3DXSDKVersion); -typedef HRESULT(__stdcall *TFunc_D3DXCompileShader)( - LPCSTR pSrcData, - UINT srcDataLen, - CONST D3DXMACRO* pDefines, - LPD3DXINCLUDE pInclude, - LPCSTR pFunctionName, - LPCSTR pProfile, - DWORD Flags, - LPD3DXBUFFER* ppShader, - LPD3DXBUFFER* ppErrorMsgs, - LPD3DXCONSTANTTABLE * ppConstantTable); - -typedef HRESULT(__stdcall *TFunc_D3DXAssembleShader)( - LPCSTR pSrcData, - UINT SrcDataLen, - CONST D3DXMACRO* pDefines, - LPD3DXINCLUDE pInclude, - DWORD Flags, - LPD3DXBUFFER* ppShader, - LPD3DXBUFFER * ppErrorMsgs - ); - -static HMODULE hm_d3dx; -static unsigned int d3dx_version; -static int failedFunctions; - -static TFunc_D3DXCheckVersion m_TFunc_D3DXCheckVersion; -static TFunc_D3DXAssembleShader m_TFunc_D3DXAssembleShader; -static TFunc_D3DXCompileShader m_TFunc_D3DXCompileShader; - -void makeD3DX9dllFilename_by_versionW(std::wstring& strOut, unsigned int versionNumber, bool debugVersion = false) { - wchar_t buf[256]; - wsprintf(buf, L"d3dx9%s_%02i.dll", debugVersion ? L"d" : L"", versionNumber); - strOut = buf; -} - -bool checkDllExistsW(const WCHAR* fname, bool bIncludeExeDir) { - return ::GetFileAttributesW(fname) != DWORD(-1); -} - -bool checkExistsDllW(const WCHAR *sDllFilename) { - std::wstring sfullpath(MAX_PATH, '\0'); - size_t sz = ::GetSystemDirectoryW(&sfullpath[0], (UINT)sfullpath.size()); - if (sz >= sfullpath.size()) { - sfullpath.resize(sz); - sz = ::GetSystemDirectoryW(&sfullpath[0], (UINT)sfullpath.size()); - } - sfullpath.resize(sz); - if (sz == 0) { - throw (std::runtime_error("system error")); - } - - sfullpath += L'\\'; - sfullpath += sDllFilename; - - if (checkDllExistsW(sfullpath.c_str(), true)) { - return true; - } - - return false; -} - -bool getLatestInstalledD3DXVersion(unsigned int* piOutVers, bool debugVersion) { - *piOutVers = 0; - std::wstring fname; - for (unsigned int cvers = 45; cvers > 0; cvers--) { - makeD3DX9dllFilename_by_versionW(fname, cvers, debugVersion); - if (checkExistsDllW(fname.c_str())) { - *piOutVers = cvers; - return true; - } - } - return false; -} - -HMODULE loadDllLastVersion(unsigned int* version, bool debugVersion) { - failedFunctions = 0; - - if (version) - *version = 0; - - if (!getLatestInstalledD3DXVersion(version, debugVersion)) { - return 0; - } - - std::wstring dllfname; - makeD3DX9dllFilename_by_versionW(dllfname, version ? *version : 0, debugVersion); - HMODULE hm = ::LoadLibraryW(dllfname.c_str()); - return hm; -} - -#define GB_MAKE_STR(s) # s -#define GB_MAKE_STR2(x) GB_MAKE_STR(x) - -#define __HANDLE_DLL_ENTRY(funcname) m_TFunc_##funcname = \ - ( TFunc_##funcname ) ::GetProcAddress(hm_d3dx, GB_MAKE_STR(funcname) ); \ - \ - if(!m_TFunc_##funcname) {\ - handleNotFoundAddr( GB_MAKE_STR(funcname) ); \ - } - -void handleNotFoundAddr(const char* sFuncName) { - ELOG("Failed to find D3DX function %s", sFuncName); - failedFunctions++; -} - -int LoadD3DX9Dynamic(bool debugVersion) { - if (hm_d3dx) { - // Already loaded - return d3dx_version; - } - - hm_d3dx = loadDllLastVersion(&d3dx_version, debugVersion); - if (!hm_d3dx) { - ELOG("Failed to find D3DX dll."); - return 0; - } - const int NERROR = -1; - int _begin = 0; - - __HANDLE_DLL_ENTRY(D3DXCheckVersion); - __HANDLE_DLL_ENTRY(D3DXAssembleShader); - __HANDLE_DLL_ENTRY(D3DXCompileShader); - - if (failedFunctions > 0) { - ELOG("Failed to load %i D3DX functions. This will not go well.", failedFunctions); - } - - return failedFunctions > 0 ? 0 : d3dx_version; -} - -int GetD3DXVersion() { - return d3dx_version; -} - -void UnloadD3DXDynamic() { - if (hm_d3dx) { - FreeLibrary(hm_d3dx); - hm_d3dx = NULL; - d3dx_version = 0; - } -} - -// version function - -#define GB_D3D9_D3DXDLL_LOADER_CHECK_ENTRY_NULL_PTR(funcname) assert(false && GB_MAKE_STR2(funcname) ); - - -BOOL dyn_D3DXCheckVersion(UINT D3DSDKVersion, UINT D3DXSDKVersion) { - if (!m_TFunc_D3DXCheckVersion) { - GB_D3D9_D3DXDLL_LOADER_CHECK_ENTRY_NULL_PTR(D3DXCheckVersion) - } - return m_TFunc_D3DXCheckVersion(D3DSDKVersion, D3DXSDKVersion); -} - -HRESULT dyn_D3DXAssembleShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines, - LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER * ppErrorMsgs) -{ - if (!m_TFunc_D3DXAssembleShader) { - GB_D3D9_D3DXDLL_LOADER_CHECK_ENTRY_NULL_PTR(D3DXAssembleShader); - } - return m_TFunc_D3DXAssembleShader(pSrcData, SrcDataLen, pDefines, - pInclude, Flags, ppShader, ppErrorMsgs); -} - -HRESULT dyn_D3DXCompileShader(LPCSTR pSrcData, UINT srcDataLen, CONST D3DXMACRO* pDefines, - LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, - DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, - LPD3DXCONSTANTTABLE * ppConstantTable) -{ - if (!m_TFunc_D3DXCompileShader) { - GB_D3D9_D3DXDLL_LOADER_CHECK_ENTRY_NULL_PTR(D3DXCompileShader); - } - return m_TFunc_D3DXCompileShader(pSrcData, srcDataLen, pDefines, - pInclude, pFunctionName, pProfile, - Flags, ppShader, ppErrorMsgs, ppConstantTable); -} diff --git a/ext/native/thin3d/d3dx9_loader.h b/ext/native/thin3d/d3dx9_loader.h deleted file mode 100644 index 36dad3f96b..0000000000 --- a/ext/native/thin3d/d3dx9_loader.h +++ /dev/null @@ -1,26 +0,0 @@ -// Cut-down version of https://code.google.com/p/d3dx9-dynamic-load/ -// by ksacvet777, licensed under the MIT - -#pragma once - -#include -#ifdef USE_CRT_DBG -#undef new -#endif -#include -#ifdef USE_CRT_DBG -#define new DBG_NEW -#endif -// Returns the D3DX9 version we got. 0 if none. -int LoadD3DX9Dynamic(bool debugVersion = false); // If debugVersion is set, load d3dx9d.dll -int GetD3DXVersion(); -void UnloadD3DXDynamic(); - -// Call these instead of the real D3DX9 functions. -BOOL dyn_D3DXCheckVersion(UINT D3DSDKVersion, UINT D3DXSDKVersion); -HRESULT dyn_D3DXAssembleShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines, - LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER * ppErrorMsgs); -HRESULT dyn_D3DXCompileShader(LPCSTR pSrcData, UINT srcDataLen, CONST D3DXMACRO* pDefines, - LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, - DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, - LPD3DXCONSTANTTABLE * ppConstantTable); diff --git a/ext/native/thin3d/vulkan_utils.cpp b/ext/native/thin3d/vulkan_utils.cpp deleted file mode 100644 index ec46b011a9..0000000000 --- a/ext/native/thin3d/vulkan_utils.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2015- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#undef min -#undef max - -#endif - -#include -#include -#include - -#ifdef USE_CRT_DBG -#undef new -#endif - -#include "ext/glslang/SPIRV/GlslangToSpv.h" -#include "ext/glslang/SPIRV/disassemble.h" - -#ifdef USE_CRT_DBG -#define new DBG_NEW -#endif - -#include "thin3d/vulkan_utils.h" - -void VulkanImage::Create2D(VulkanContext *vulkan, VkFormat format, VkFlags required_props, VkImageTiling tiling, VkImageUsageFlags usage, int width, int height) { - VkDevice device = vulkan->GetDevice(); - width_ = width; - height_ = height; - - VkImageCreateInfo i = {}; - i.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - i.pNext = NULL; - i.imageType = VK_IMAGE_TYPE_2D; - i.format = format; - i.extent = { (uint32_t)width, (uint32_t)height, 1 }; - i.mipLevels = 1; - i.arrayLayers = 1; - i.samples = VK_SAMPLE_COUNT_1_BIT; - i.tiling = tiling; - i.usage = usage; - i.flags = 0; - i.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - i.queueFamilyIndexCount = 0; - i.pQueueFamilyIndices = nullptr; - i.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - VkMemoryRequirements mem_reqs; - - VkResult err = vkCreateImage(device, &i, nullptr, &image_); - assert(!err); - - vkGetImageMemoryRequirements(device, image_, &mem_reqs); - - mem_alloc_.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - mem_alloc_.pNext = NULL; - mem_alloc_.allocationSize = mem_reqs.size; - mem_alloc_.memoryTypeIndex = 0; - - bool res = vulkan->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, required_props, &mem_alloc_.memoryTypeIndex); - assert(res); - - err = vkAllocateMemory(device, &mem_alloc_, nullptr, &memory_); - assert(!err); - - err = vkBindImageMemory(device, image_, memory_, 0); // at offset 0. - assert(!err); -} - -void VulkanImage::SetImageData2D(VkDevice device, const uint8_t *data, int width, int height, int pitch) { - VkImageSubresource subres; - subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subres.mipLevel = 0; - subres.arrayLayer = 0; - - VkSubresourceLayout layout; - void *destData; - vkGetImageSubresourceLayout(device, image_, &subres, &layout); - - VkResult err = vkMapMemory(device, memory_, 0, mem_alloc_.allocationSize, 0, &destData); - assert(!err); - - uint8_t *writePtr = (uint8_t *)destData + layout.offset; - int bpp = 4; // TODO - for (int y = 0; y < height; y++) { - memcpy(writePtr + y * layout.rowPitch, data + y * pitch, bpp * width); - } - - vkUnmapMemory(device, memory_); -} - - -void VulkanImage::ChangeLayout(VkCommandBuffer cmd, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) { - VkImageMemoryBarrier image_memory_barrier; - image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_memory_barrier.pNext = NULL; - image_memory_barrier.dstAccessMask = 0; - image_memory_barrier.srcAccessMask = 0; - image_memory_barrier.oldLayout = old_image_layout; - image_memory_barrier.newLayout = new_image_layout; - image_memory_barrier.image = image_; - image_memory_barrier.subresourceRange.aspectMask = aspectMask; - image_memory_barrier.subresourceRange.layerCount = 1; - image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.baseMipLevel = 0; - image_memory_barrier.subresourceRange.levelCount = 1; - - if (old_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - } - - if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - // Make sure anything that was copying from this image has completed - image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - } - - if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - // Make sure any Copy or CPU writes to image are flushed - image_memory_barrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; - } - - VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkCmdPipelineBarrier(cmd, src_stages, dest_stages, false, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); -} diff --git a/ext/native/tools/atlastool.cpp b/ext/native/tools/atlastool.cpp index 9aec9704ff..53bda41e86 100644 --- a/ext/native/tools/atlastool.cpp +++ b/ext/native/tools/atlastool.cpp @@ -18,6 +18,7 @@ // line height // dist-per-pixel +#include #include #include #include @@ -28,11 +29,10 @@ #include #include -#include "base/logging.h" -#include "gfx/texture_atlas.h" +#include "Common/Render/TextureAtlas.h" -#include "image/png_load.h" -#include "image/zim_save.h" +#include "Common/Data/Format/PNGLoad.h" +#include "Common/Data/Format/ZIMSave.h" #include "kanjifilter.h" // extracted only JIS Kanji on the CJK Unified Ideographs of UCS2. Cannot reading BlockAllocator. (texture size over) @@ -46,7 +46,7 @@ // add kanjiFilter Array with KANJI_LEARNING_ORDER_ADDTIONAL. #define USE_KANJI KANJI_LEARNING_ORDER_ALL -#include "util/text/utf8.h" +#include "Common/Data/Encoding/Utf8.h" using namespace std; static int global_id; @@ -109,8 +109,8 @@ struct Image { return (int)dat.size(); } void copyfrom(const Image &img, int ox, int oy, Effect effect) { - CHECK(img.dat[0].size() + ox <= dat[0].size()); - CHECK(img.dat.size() + oy <= dat.size()); + assert(img.dat[0].size() + ox <= dat[0].size()); + assert(img.dat.size() + oy <= dat.size()); for (int y = 0; y < (int)img.dat.size(); y++) { for (int x = 0; x < (int)img.dat[y].size(); x++) { switch (effect) { @@ -152,7 +152,7 @@ struct Image { bool LoadPNG(const char *png_name) { unsigned char *img_data; int w, h; - if (1 != pngLoad(png_name, &w, &h, &img_data, false)) { + if (1 != pngLoad(png_name, &w, &h, &img_data)) { printf("Failed to load %s\n", png_name); exit(1); return false; @@ -171,9 +171,9 @@ struct Image { png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - CHECK(png_ptr); + assert(png_ptr); info_ptr = png_create_info_struct(png_ptr); - CHECK(info_ptr); + assert(info_ptr); png_init_io(png_ptr, fil); //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); png_set_IHDR(png_ptr, info_ptr, (uint32_t)dat[0].size(), (uint32_t)dat.size(), 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); @@ -248,7 +248,7 @@ struct Bucket { int idx = (int)items[i].first.dat[0].size(); int idy = (int)items[i].first.dat.size(); if (idx > 1 && idy > 1) { - CHECK(idx <= image_width); + assert(idx <= image_width); for (int ty = 0; ty < 2047; ty++) { if (ty + idy + 1 > (int)dest.dat.size()) { masq.resize(image_width, ty + idy + 16); @@ -354,8 +354,8 @@ inline vector merge(const vector &a, const vector &ranges, float *metrics_height, Bucket *bucket) { - FT_Library freetype; - CHECK(FT_Init_FreeType(&freetype) == 0); + FT_Library freetype = 0; + assert(FT_Init_FreeType(&freetype) == 0); vector fonts; fonts.resize(fontRefs.size()); @@ -374,7 +374,7 @@ void RasterizeFonts(const FontReferenceList &fontRefs, vector &ranges } printf("TTF info: %d glyphs, %08x flags, %d units, %d strikes\n", (int)font->num_glyphs, (int)font->face_flags, (int)font->units_per_EM, (int)font->num_fixed_sizes); - CHECK(FT_Set_Pixel_Sizes(font, 0, fontRefs[i].size_ * supersample) == 0); + assert(FT_Set_Pixel_Sizes(font, 0, fontRefs[i].size_ * supersample) == 0); ranges = merge(ranges, fontRefs[i].ranges_); for (size_t r = 0, rn = fontRefs[i].ranges_.size(); r < rn; ++r) { @@ -858,10 +858,10 @@ int main(int argc, char **argv) { // /usr/share/fonts/truetype/msttcorefonts/Arial_Black.ttf // /usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-R.ttf if (argc < 3) { - FLOG("Not enough arguments"); + printf("Not enough arguments"); return 1; } - CHECK(argc >= 3); + assert(argc >= 3); if (argc > 3) { if (!strcmp(argv[3], "8888")) { highcolor = true; diff --git a/ext/native/tools/atlastool/atlastool.vcxproj b/ext/native/tools/atlastool/atlastool.vcxproj index 60613f1c54..afd5ad8b43 100644 --- a/ext/native/tools/atlastool/atlastool.vcxproj +++ b/ext/native/tools/atlastool/atlastool.vcxproj @@ -17,9 +17,6 @@ {f761046e-6c38-4428-a5f1-38391a37bb34} - - {c4df647e-80ea-4111-a0a8-218b1b711e18} - @@ -81,7 +78,7 @@ Console true ../prebuilt/win64 - freetype.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winmm.lib;freetype.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -97,6 +94,7 @@ true ../../../../;../../ext;../../;../../../../ext;../prebuilt MultiThreaded + false Console @@ -104,10 +102,10 @@ true true ../prebuilt/win64 - freetype.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + winmm.lib;freetype.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - \ No newline at end of file + diff --git a/ext/native/tools/audiotool.cpp b/ext/native/tools/audiotool.cpp deleted file mode 100644 index 68cfee7ae3..0000000000 --- a/ext/native/tools/audiotool.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// TODO - -#include - -#include "audio/wav_load.h" -#include "base/logging.h" - - -struct AudioClip { - int length; - -}; - - -int main(int argc, char **argv) { - CHECK(argc == 3); -} diff --git a/ext/native/tools/zimtool.cpp b/ext/native/tools/zimtool.cpp index 3692881643..88f9e9da16 100644 --- a/ext/native/tools/zimtool.cpp +++ b/ext/native/tools/zimtool.cpp @@ -2,14 +2,14 @@ #include #include -#include "base/logging.h" -#include "image/png_load.h" -#include "image/zim_save.h" +#include "Common/Data/Format/PNGLoad.h" +#include "Common/Data/Format/ZIMLoad.h" +#include "Common/Data/Format/ZIMSave.h" + +#include "Common/Common.h" char magic[5] = "ZIMG"; -bool FLAGS_flip = false; - const char *format_strings[4] = { "8888", "4444", "565", "ETC1" }; int formats[3] = { ZIM_RGBA8888, ZIM_RGBA4444, ZIM_RGB565 }; @@ -80,7 +80,7 @@ int main(int argc, char **argv) { uint8_t *image_data; int width, height; - if (1 != pngLoad(FLAGS_infile, &width, &height, &image_data, FLAGS_flip)) { + if (1 != pngLoad(FLAGS_infile, &width, &height, &image_data)) { fprintf(stderr, "Input not a PNG file\n"); printusage(); return 1; diff --git a/ext/native/tools/zimtool/zimtool.vcxproj b/ext/native/tools/zimtool/zimtool.vcxproj index 3c9e0d3c2d..5c91fc8a23 100644 --- a/ext/native/tools/zimtool/zimtool.vcxproj +++ b/ext/native/tools/zimtool/zimtool.vcxproj @@ -17,9 +17,6 @@ {f761046e-6c38-4428-a5f1-38391a37bb34} - - {c4df647e-80ea-4111-a0a8-218b1b711e18} - @@ -84,6 +81,7 @@ true true true + winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -101,9 +99,10 @@ Console true + winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - \ No newline at end of file + diff --git a/ext/native/ui/CMakeLists.txt b/ext/native/ui/CMakeLists.txt deleted file mode 100644 index 016db5350c..0000000000 --- a/ext/native/ui/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(SRCS - ui.cpp - ui_context.cpp - view.cpp - viewgroup.cpp - screen.cpp - root.cpp -) - -set(SRCS ${SRCS}) - -add_library(ui STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) - diff --git a/ext/native/util/CMakeLists.txt b/ext/native/util/CMakeLists.txt deleted file mode 100644 index 9d632a0ad9..0000000000 --- a/ext/native/util/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(SRCS - hash/hash.cpp - text/utf8.cpp - text/wrap_text.cpp -) - -set(SRCS ${SRCS}) - -add_library(util STATIC ${SRCS}) - -if(UNIX) - add_definitions(-fPIC) -endif(UNIX) - diff --git a/ext/native/util/text/parsers.cpp b/ext/native/util/text/parsers.cpp deleted file mode 100644 index 8024324b08..0000000000 --- a/ext/native/util/text/parsers.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -#include "util/text/parsers.h" - -bool Version::ParseVersionString(std::string str) { - if (str.empty()) - return false; - if (str[0] == 'v') - str = str.substr(1); - if (3 != sscanf(str.c_str(), "%i.%i.%i", &major, &minor, &sub)) { - sub = 0; - if (2 != sscanf(str.c_str(), "%i.%i", &major, &minor)) - return false; - } - return true; -} - -std::string Version::ToString() const { - char temp[128]; - sprintf(temp, "%i.%i.%i", major, minor, sub); - return std::string(temp); -} - -int Version::ToInteger() const { - // This allows for ~2000 major versions, ~100 minor versions, and ~10000 sub versions. - return major * 1000000 + minor * 10000 + sub; -} - -bool ParseMacAddress(std::string str, uint8_t macAddr[6]) { - unsigned int mac[6]; - if (6 != sscanf(str.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])) { - return false; - } - for (int i = 0; i < 6; i++) { - macAddr[i] = mac[i]; - } - return true; -} diff --git a/ext/native/ext/sha1/CMakeLists.txt b/ext/sha1/CMakeLists.txt similarity index 100% rename from ext/native/ext/sha1/CMakeLists.txt rename to ext/sha1/CMakeLists.txt diff --git a/ext/native/ext/sha1/sha1.cpp b/ext/sha1/sha1.cpp similarity index 100% rename from ext/native/ext/sha1/sha1.cpp rename to ext/sha1/sha1.cpp diff --git a/ext/native/ext/sha1/sha1.h b/ext/sha1/sha1.h similarity index 100% rename from ext/native/ext/sha1/sha1.h rename to ext/sha1/sha1.h diff --git a/ext/snappy/CMakeLists.txt b/ext/snappy/CMakeLists.txt index 6ab38acd0e..f25386b63a 100644 --- a/ext/snappy/CMakeLists.txt +++ b/ext/snappy/CMakeLists.txt @@ -9,7 +9,9 @@ else() snappy-c.cpp snappy-c.h snappy-internal.h + snappy-sinksource.cpp snappy-sinksource.h + snappy-stubs-internal.cpp snappy-stubs-internal.h snappy-stubs-public.h snappy.cpp diff --git a/ext/snappy/snappy-c.h b/ext/snappy/snappy-c.h index c6c2a860a4..32aa0c6b8b 100644 --- a/ext/snappy/snappy-c.h +++ b/ext/snappy/snappy-c.h @@ -30,8 +30,8 @@ * Plain C interface (a wrapper around the C++ implementation). */ -#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_C_H_ -#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_C_H_ +#ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_C_H_ +#define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_C_H_ #ifdef __cplusplus extern "C" { @@ -135,4 +135,4 @@ snappy_status snappy_validate_compressed_buffer(const char* compressed, } // extern "C" #endif -#endif /* UTIL_SNAPPY_OPENSOURCE_SNAPPY_C_H_ */ +#endif /* THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_C_H_ */ diff --git a/ext/snappy/snappy-internal.h b/ext/snappy/snappy-internal.h index c99d33130b..1e1c307fef 100644 --- a/ext/snappy/snappy-internal.h +++ b/ext/snappy/snappy-internal.h @@ -28,29 +28,38 @@ // // Internals shared between the Snappy implementation and its unittest. -#ifndef UTIL_SNAPPY_SNAPPY_INTERNAL_H_ -#define UTIL_SNAPPY_SNAPPY_INTERNAL_H_ +#ifndef THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_ +#define THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_ #include "snappy-stubs-internal.h" namespace snappy { namespace internal { +// Working memory performs a single allocation to hold all scratch space +// required for compression. class WorkingMemory { public: - WorkingMemory() : large_table_(NULL) { } - ~WorkingMemory() { delete[] large_table_; } + explicit WorkingMemory(size_t input_size); + ~WorkingMemory(); // Allocates and clears a hash table using memory in "*this", // stores the number of buckets in "*table_size" and returns a pointer to // the base of the hash table. - uint16* GetHashTable(size_t input_size, int* table_size); + uint16* GetHashTable(size_t fragment_size, int* table_size) const; + char* GetScratchInput() const { return input_; } + char* GetScratchOutput() const { return output_; } private: - uint16 small_table_[1<<10]; // 2KB - uint16* large_table_; // Allocated only when needed + char* mem_; // the allocated memory, never nullptr + size_t size_; // the size of the allocated memory, never 0 + uint16* table_; // the pointer to the hashtable + char* input_; // the pointer to the input scratch buffer + char* output_; // the pointer to the output scratch buffer - DISALLOW_COPY_AND_ASSIGN(WorkingMemory); + // No copying + WorkingMemory(const WorkingMemory&); + void operator=(const WorkingMemory&); }; // Flat array compression that does not emit the "uncompressed length" @@ -70,57 +79,72 @@ char* CompressFragment(const char* input, uint16* table, const int table_size); -// Return the largest n such that +// Find the largest n such that // // s1[0,n-1] == s2[0,n-1] // and n <= (s2_limit - s2). // +// Return make_pair(n, n < 8). // Does not read *s2_limit or beyond. // Does not read *(s1 + (s2_limit - s2)) or beyond. // Requires that s2_limit >= s2. // -// Separate implementation for x86_64, for speed. Uses the fact that -// x86_64 is little endian. -#if defined(ARCH_K8) -static inline int FindMatchLength(const char* s1, - const char* s2, - const char* s2_limit) { +// Separate implementation for 64-bit, little-endian cpus. +#if !defined(SNAPPY_IS_BIG_ENDIAN) && \ + (defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)) +static inline std::pair FindMatchLength(const char* s1, + const char* s2, + const char* s2_limit) { assert(s2_limit >= s2); - int matched = 0; + size_t matched = 0; + + // This block isn't necessary for correctness; we could just start looping + // immediately. As an optimization though, it is useful. It creates some not + // uncommon code paths that determine, without extra effort, whether the match + // length is less than 8. In short, we are hoping to avoid a conditional + // branch, and perhaps get better code layout from the C++ compiler. + if (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 8)) { + uint64 a1 = UNALIGNED_LOAD64(s1); + uint64 a2 = UNALIGNED_LOAD64(s2); + if (a1 != a2) { + return std::pair(Bits::FindLSBSetNonZero64(a1 ^ a2) >> 3, + true); + } else { + matched = 8; + s2 += 8; + } + } // Find out how long the match is. We loop over the data 64 bits at a // time until we find a 64-bit block that doesn't match; then we find // the first non-matching bit and use that to calculate the total // length of the match. - while (PREDICT_TRUE(s2 <= s2_limit - 8)) { - if (PREDICT_FALSE(UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched))) { + while (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 8)) { + if (UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched)) { s2 += 8; matched += 8; } else { - // On current (mid-2008) Opteron models there is a 3% more - // efficient code sequence to find the first non-matching byte. - // However, what follows is ~10% better on Intel Core 2 and newer, - // and we expect AMD's bsf instruction to improve. uint64 x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched); int matching_bits = Bits::FindLSBSetNonZero64(x); matched += matching_bits >> 3; - return matched; + assert(matched >= 8); + return std::pair(matched, false); } } - while (PREDICT_TRUE(s2 < s2_limit)) { - if (PREDICT_TRUE(s1[matched] == *s2)) { + while (SNAPPY_PREDICT_TRUE(s2 < s2_limit)) { + if (s1[matched] == *s2) { ++s2; ++matched; } else { - return matched; + return std::pair(matched, matched < 8); } } - return matched; + return std::pair(matched, matched < 8); } #else -static inline int FindMatchLength(const char* s1, - const char* s2, - const char* s2_limit) { +static inline std::pair FindMatchLength(const char* s1, + const char* s2, + const char* s2_limit) { // Implementation based on the x86-64 version, above. assert(s2_limit >= s2); int matched = 0; @@ -140,11 +164,68 @@ static inline int FindMatchLength(const char* s1, ++matched; } } - return matched; + return std::pair(matched, matched < 8); } #endif +// Lookup tables for decompression code. Give --snappy_dump_decompression_table +// to the unit test to recompute char_table. + +enum { + LITERAL = 0, + COPY_1_BYTE_OFFSET = 1, // 3 bit length + 3 bits of offset in opcode + COPY_2_BYTE_OFFSET = 2, + COPY_4_BYTE_OFFSET = 3 +}; +static const int kMaximumTagLength = 5; // COPY_4_BYTE_OFFSET plus the actual offset. + +// Data stored per entry in lookup table: +// Range Bits-used Description +// ------------------------------------ +// 1..64 0..7 Literal/copy length encoded in opcode byte +// 0..7 8..10 Copy offset encoded in opcode byte / 256 +// 0..4 11..13 Extra bytes after opcode +// +// We use eight bits for the length even though 7 would have sufficed +// because of efficiency reasons: +// (1) Extracting a byte is faster than a bit-field +// (2) It properly aligns copy offset so we do not need a <<8 +static const uint16 char_table[256] = { + 0x0001, 0x0804, 0x1001, 0x2001, 0x0002, 0x0805, 0x1002, 0x2002, + 0x0003, 0x0806, 0x1003, 0x2003, 0x0004, 0x0807, 0x1004, 0x2004, + 0x0005, 0x0808, 0x1005, 0x2005, 0x0006, 0x0809, 0x1006, 0x2006, + 0x0007, 0x080a, 0x1007, 0x2007, 0x0008, 0x080b, 0x1008, 0x2008, + 0x0009, 0x0904, 0x1009, 0x2009, 0x000a, 0x0905, 0x100a, 0x200a, + 0x000b, 0x0906, 0x100b, 0x200b, 0x000c, 0x0907, 0x100c, 0x200c, + 0x000d, 0x0908, 0x100d, 0x200d, 0x000e, 0x0909, 0x100e, 0x200e, + 0x000f, 0x090a, 0x100f, 0x200f, 0x0010, 0x090b, 0x1010, 0x2010, + 0x0011, 0x0a04, 0x1011, 0x2011, 0x0012, 0x0a05, 0x1012, 0x2012, + 0x0013, 0x0a06, 0x1013, 0x2013, 0x0014, 0x0a07, 0x1014, 0x2014, + 0x0015, 0x0a08, 0x1015, 0x2015, 0x0016, 0x0a09, 0x1016, 0x2016, + 0x0017, 0x0a0a, 0x1017, 0x2017, 0x0018, 0x0a0b, 0x1018, 0x2018, + 0x0019, 0x0b04, 0x1019, 0x2019, 0x001a, 0x0b05, 0x101a, 0x201a, + 0x001b, 0x0b06, 0x101b, 0x201b, 0x001c, 0x0b07, 0x101c, 0x201c, + 0x001d, 0x0b08, 0x101d, 0x201d, 0x001e, 0x0b09, 0x101e, 0x201e, + 0x001f, 0x0b0a, 0x101f, 0x201f, 0x0020, 0x0b0b, 0x1020, 0x2020, + 0x0021, 0x0c04, 0x1021, 0x2021, 0x0022, 0x0c05, 0x1022, 0x2022, + 0x0023, 0x0c06, 0x1023, 0x2023, 0x0024, 0x0c07, 0x1024, 0x2024, + 0x0025, 0x0c08, 0x1025, 0x2025, 0x0026, 0x0c09, 0x1026, 0x2026, + 0x0027, 0x0c0a, 0x1027, 0x2027, 0x0028, 0x0c0b, 0x1028, 0x2028, + 0x0029, 0x0d04, 0x1029, 0x2029, 0x002a, 0x0d05, 0x102a, 0x202a, + 0x002b, 0x0d06, 0x102b, 0x202b, 0x002c, 0x0d07, 0x102c, 0x202c, + 0x002d, 0x0d08, 0x102d, 0x202d, 0x002e, 0x0d09, 0x102e, 0x202e, + 0x002f, 0x0d0a, 0x102f, 0x202f, 0x0030, 0x0d0b, 0x1030, 0x2030, + 0x0031, 0x0e04, 0x1031, 0x2031, 0x0032, 0x0e05, 0x1032, 0x2032, + 0x0033, 0x0e06, 0x1033, 0x2033, 0x0034, 0x0e07, 0x1034, 0x2034, + 0x0035, 0x0e08, 0x1035, 0x2035, 0x0036, 0x0e09, 0x1036, 0x2036, + 0x0037, 0x0e0a, 0x1037, 0x2037, 0x0038, 0x0e0b, 0x1038, 0x2038, + 0x0039, 0x0f04, 0x1039, 0x2039, 0x003a, 0x0f05, 0x103a, 0x203a, + 0x003b, 0x0f06, 0x103b, 0x203b, 0x003c, 0x0f07, 0x103c, 0x203c, + 0x0801, 0x0f08, 0x103d, 0x203d, 0x1001, 0x0f09, 0x103e, 0x203e, + 0x1801, 0x0f0a, 0x103f, 0x203f, 0x2001, 0x0f0b, 0x1040, 0x2040 +}; + } // end namespace internal } // end namespace snappy -#endif // UTIL_SNAPPY_SNAPPY_INTERNAL_H_ +#endif // THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_ diff --git a/ext/snappy/snappy-sinksource.cpp b/ext/snappy/snappy-sinksource.cpp new file mode 100644 index 0000000000..369a13215b --- /dev/null +++ b/ext/snappy/snappy-sinksource.cpp @@ -0,0 +1,104 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "snappy-sinksource.h" + +namespace snappy { + +Source::~Source() { } + +Sink::~Sink() { } + +char* Sink::GetAppendBuffer(size_t length, char* scratch) { + return scratch; +} + +char* Sink::GetAppendBufferVariable( + size_t min_size, size_t desired_size_hint, char* scratch, + size_t scratch_size, size_t* allocated_size) { + *allocated_size = scratch_size; + return scratch; +} + +void Sink::AppendAndTakeOwnership( + char* bytes, size_t n, + void (*deleter)(void*, const char*, size_t), + void *deleter_arg) { + Append(bytes, n); + (*deleter)(deleter_arg, bytes, n); +} + +ByteArraySource::~ByteArraySource() { } + +size_t ByteArraySource::Available() const { return left_; } + +const char* ByteArraySource::Peek(size_t* len) { + *len = left_; + return ptr_; +} + +void ByteArraySource::Skip(size_t n) { + left_ -= n; + ptr_ += n; +} + +UncheckedByteArraySink::~UncheckedByteArraySink() { } + +void UncheckedByteArraySink::Append(const char* data, size_t n) { + // Do no copying if the caller filled in the result of GetAppendBuffer() + if (data != dest_) { + memcpy(dest_, data, n); + } + dest_ += n; +} + +char* UncheckedByteArraySink::GetAppendBuffer(size_t len, char* scratch) { + return dest_; +} + +void UncheckedByteArraySink::AppendAndTakeOwnership( + char* data, size_t n, + void (*deleter)(void*, const char*, size_t), + void *deleter_arg) { + if (data != dest_) { + memcpy(dest_, data, n); + (*deleter)(deleter_arg, data, n); + } + dest_ += n; +} + +char* UncheckedByteArraySink::GetAppendBufferVariable( + size_t min_size, size_t desired_size_hint, char* scratch, + size_t scratch_size, size_t* allocated_size) { + *allocated_size = desired_size_hint; + return dest_; +} + +} // namespace snappy diff --git a/ext/snappy/snappy-sinksource.h b/ext/snappy/snappy-sinksource.h index faabfa1e6f..8afcdaaa2c 100644 --- a/ext/snappy/snappy-sinksource.h +++ b/ext/snappy/snappy-sinksource.h @@ -26,12 +26,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ -#define UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ +#ifndef THIRD_PARTY_SNAPPY_SNAPPY_SINKSOURCE_H_ +#define THIRD_PARTY_SNAPPY_SNAPPY_SINKSOURCE_H_ #include - namespace snappy { // A Sink is an interface that consumes a sequence of bytes. @@ -60,6 +59,47 @@ class Sink { // The default implementation always returns the scratch buffer. virtual char* GetAppendBuffer(size_t length, char* scratch); + // For higher performance, Sink implementations can provide custom + // AppendAndTakeOwnership() and GetAppendBufferVariable() methods. + // These methods can reduce the number of copies done during + // compression/decompression. + + // Append "bytes[0,n-1] to the sink. Takes ownership of "bytes" + // and calls the deleter function as (*deleter)(deleter_arg, bytes, n) + // to free the buffer. deleter function must be non NULL. + // + // The default implementation just calls Append and frees "bytes". + // Other implementations may avoid a copy while appending the buffer. + virtual void AppendAndTakeOwnership( + char* bytes, size_t n, void (*deleter)(void*, const char*, size_t), + void *deleter_arg); + + // Returns a writable buffer for appending and writes the buffer's capacity to + // *allocated_size. Guarantees *allocated_size >= min_size. + // May return a pointer to the caller-owned scratch buffer which must have + // scratch_size >= min_size. + // + // The returned buffer is only valid until the next operation + // on this ByteSink. + // + // After writing at most *allocated_size bytes, call Append() with the + // pointer returned from this function and the number of bytes written. + // Many Append() implementations will avoid copying bytes if this function + // returned an internal buffer. + // + // If the sink implementation allocates or reallocates an internal buffer, + // it should use the desired_size_hint if appropriate. If a caller cannot + // provide a reasonable guess at the desired capacity, it should set + // desired_size_hint = 0. + // + // If a non-scratch buffer is returned, the caller may only pass + // a prefix to it to Append(). That is, it is not correct to pass an + // interior pointer to Append(). + // + // The default implementation always returns the scratch buffer. + virtual char* GetAppendBufferVariable( + size_t min_size, size_t desired_size_hint, char* scratch, + size_t scratch_size, size_t* allocated_size); private: // No copying @@ -122,6 +162,12 @@ class UncheckedByteArraySink : public Sink { virtual ~UncheckedByteArraySink(); virtual void Append(const char* data, size_t n); virtual char* GetAppendBuffer(size_t len, char* scratch); + virtual char* GetAppendBufferVariable( + size_t min_size, size_t desired_size_hint, char* scratch, + size_t scratch_size, size_t* allocated_size); + virtual void AppendAndTakeOwnership( + char* bytes, size_t n, void (*deleter)(void*, const char*, size_t), + void *deleter_arg); // Return the current output pointer so that a caller can see how // many bytes were produced. @@ -131,7 +177,6 @@ class UncheckedByteArraySink : public Sink { char* dest_; }; +} // namespace snappy -} - -#endif // UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ +#endif // THIRD_PARTY_SNAPPY_SNAPPY_SINKSOURCE_H_ diff --git a/ext/snappy/snappy-stubs-internal.cpp b/ext/snappy/snappy-stubs-internal.cpp new file mode 100644 index 0000000000..66ed2e9039 --- /dev/null +++ b/ext/snappy/snappy-stubs-internal.cpp @@ -0,0 +1,42 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include "snappy-stubs-internal.h" + +namespace snappy { + +void Varint::Append32(std::string* s, uint32 value) { + char buf[Varint::kMax32]; + const char* p = Varint::Encode32(buf, value); + s->append(buf, p - buf); +} + +} // namespace snappy diff --git a/ext/snappy/snappy-stubs-internal.h b/ext/snappy/snappy-stubs-internal.h index eae1e4fae8..4854689d17 100644 --- a/ext/snappy/snappy-stubs-internal.h +++ b/ext/snappy/snappy-stubs-internal.h @@ -28,8 +28,8 @@ // // Various stubs for the open-source version of Snappy. -#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ -#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ +#ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ +#define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ #ifdef HAVE_CONFIG_H #include "config.h" @@ -45,13 +45,41 @@ #include #endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#if defined(_MSC_VER) +#include +#endif // defined(_MSC_VER) + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_feature(memory_sanitizer) +#include +#define SNAPPY_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + __msan_unpoison((address), (size)) +#else +#define SNAPPY_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ +#endif // __has_feature(memory_sanitizer) + #include "snappy-stubs-public.h" -#if defined(__x86_64__) || defined(_M_X64) +#if defined(__x86_64__) // Enable 64-bit optimized versions of some routines. #define ARCH_K8 1 +#elif defined(__ppc64__) + +#define ARCH_PPC 1 + +#elif defined(__aarch64__) + +#define ARCH_ARM 1 + #endif // Needed by OS X, among others. @@ -59,10 +87,6 @@ #define MAP_ANONYMOUS MAP_ANON #endif -// Pull in std::min, std::ostream, and the likes. This is safe because this -// header file is never used from any public header files. -using namespace std; - // The size of an array, if known at compile-time. // Will give unexpected results if used on a pointer. // We undefine it first, since some compilers already have a definition. @@ -73,11 +97,11 @@ using namespace std; // Static prediction hints. #ifdef HAVE_BUILTIN_EXPECT -#define PREDICT_FALSE(x) (__builtin_expect(x, 0)) -#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#define SNAPPY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) #else -#define PREDICT_FALSE(x) x -#define PREDICT_TRUE(x) x +#define SNAPPY_PREDICT_FALSE(x) x +#define SNAPPY_PREDICT_TRUE(x) x #endif // This is only used for recomputing the tag byte table used during @@ -96,13 +120,10 @@ static const int64 kint64max = static_cast(0x7FFFFFFFFFFFFFFFLL); // Potentially unaligned loads and stores. -// x86 and PowerPC can simply do these loads and stores native. +// x86, PowerPC, and ARM64 can simply do these loads and stores native. -#if defined(_M_IX86) && defined(_MSC_VER) && !defined(ARM) && !defined(MIPS) && !defined(__i386__) -#define __i386__ 1 -#endif - -#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || defined(_M_X64) +#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \ + defined(__aarch64__) #define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) #define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) @@ -120,6 +141,15 @@ static const int64 kint64max = static_cast(0x7FFFFFFFFFFFFFFFLL); // sub-architectures. // // This is a mess, but there's not much we can do about it. +// +// To further complicate matters, only LDR instructions (single reads) are +// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we +// explicitly tell the compiler that these accesses can be unaligned, it can and +// will combine accesses. On armcc, the way to signal this is done by accessing +// through the type (uint32 __packed *), but GCC has no such attribute +// (it ignores __attribute__((packed)) on individual variables). However, +// we can tell it that a _struct_ is unaligned, which has the same effect, +// so we do that. #elif defined(__arm__) && \ !defined(__ARM_ARCH_4__) && \ @@ -135,13 +165,41 @@ static const int64 kint64max = static_cast(0x7FFFFFFFFFFFFFFFLL); !defined(__ARM_ARCH_6ZK__) && \ !defined(__ARM_ARCH_6T2__) -#define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) -#define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) +#if __GNUC__ +#define ATTRIBUTE_PACKED __attribute__((__packed__)) +#else +#define ATTRIBUTE_PACKED +#endif -#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) -#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) +namespace base { +namespace internal { -// TODO(user): NEON supports unaligned 64-bit loads and stores. +struct Unaligned16Struct { + uint16 value; + uint8 dummy; // To make the size non-power-of-two. +} ATTRIBUTE_PACKED; + +struct Unaligned32Struct { + uint32 value; + uint8 dummy; // To make the size non-power-of-two. +} ATTRIBUTE_PACKED; + +} // namespace internal +} // namespace base + +#define UNALIGNED_LOAD16(_p) \ + ((reinterpret_cast(_p))->value) +#define UNALIGNED_LOAD32(_p) \ + ((reinterpret_cast(_p))->value) + +#define UNALIGNED_STORE16(_p, _val) \ + ((reinterpret_cast< ::snappy::base::internal::Unaligned16Struct *>(_p))->value = \ + (_val)) +#define UNALIGNED_STORE32(_p, _val) \ + ((reinterpret_cast< ::snappy::base::internal::Unaligned32Struct *>(_p))->value = \ + (_val)) + +// TODO: NEON supports unaligned 64-bit loads and stores. // See if that would be more efficient on platforms supporting it, // at least for copies. @@ -192,22 +250,8 @@ inline void UNALIGNED_STORE64(void *p, uint64 v) { #endif -// This can be more efficient than UNALIGNED_LOAD64 + UNALIGNED_STORE64 -// on some platforms, in particular ARM. -inline void UnalignedCopy64(const void *src, void *dst) { - if (sizeof(void *) == 8) { - UNALIGNED_STORE64(dst, UNALIGNED_LOAD64(src)); - } else { - const char *src_char = reinterpret_cast(src); - char *dst_char = reinterpret_cast(dst); - - UNALIGNED_STORE32(dst_char, UNALIGNED_LOAD32(src_char)); - UNALIGNED_STORE32(dst_char + 4, UNALIGNED_LOAD32(src_char + 4)); - } -} - // The following guarantees declaration of the byte swap functions. -#ifdef WORDS_BIGENDIAN +#if defined(SNAPPY_IS_BIG_ENDIAN) #ifdef HAVE_SYS_BYTEORDER_H #include @@ -264,7 +308,7 @@ inline uint64 bswap_64(uint64 x) { #endif -#endif // WORDS_BIGENDIAN +#endif // defined(SNAPPY_IS_BIG_ENDIAN) // Convert to little-endian storage, opposite of network format. // Convert x from host to little endian: x = LittleEndian.FromHost(x); @@ -278,7 +322,7 @@ inline uint64 bswap_64(uint64 x) { class LittleEndian { public: // Conversion functions. -#ifdef WORDS_BIGENDIAN +#if defined(SNAPPY_IS_BIG_ENDIAN) static uint16 FromHost16(uint16 x) { return bswap_16(x); } static uint16 ToHost16(uint16 x) { return bswap_16(x); } @@ -288,7 +332,7 @@ class LittleEndian { static bool IsLittleEndian() { return false; } -#else // !defined(WORDS_BIGENDIAN) +#else // !defined(SNAPPY_IS_BIG_ENDIAN) static uint16 FromHost16(uint16 x) { return x; } static uint16 ToHost16(uint16 x) { return x; } @@ -298,7 +342,7 @@ class LittleEndian { static bool IsLittleEndian() { return true; } -#endif // !defined(WORDS_BIGENDIAN) +#endif // !defined(SNAPPY_IS_BIG_ENDIAN) // Functions to do unaligned loads and stores in little-endian order. static uint16 Load16(const void *p) { @@ -321,6 +365,9 @@ class LittleEndian { // Some bit-manipulation functions. class Bits { public: + // Return floor(log2(n)) for positive integer n. + static int Log2FloorNonZero(uint32 n); + // Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0. static int Log2Floor(uint32 n); @@ -328,31 +375,85 @@ class Bits { // undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except // that it's 0-indexed. static int FindLSBSetNonZero(uint32 n); + +#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) static int FindLSBSetNonZero64(uint64 n); +#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) private: - DISALLOW_COPY_AND_ASSIGN(Bits); + // No copying + Bits(const Bits&); + void operator=(const Bits&); }; #ifdef HAVE_BUILTIN_CTZ +inline int Bits::Log2FloorNonZero(uint32 n) { + assert(n != 0); + // (31 ^ x) is equivalent to (31 - x) for x in [0, 31]. An easy proof + // represents subtraction in base 2 and observes that there's no carry. + // + // GCC and Clang represent __builtin_clz on x86 as 31 ^ _bit_scan_reverse(x). + // Using "31 ^" here instead of "31 -" allows the optimizer to strip the + // function body down to _bit_scan_reverse(x). + return 31 ^ __builtin_clz(n); +} + inline int Bits::Log2Floor(uint32 n) { - return n == 0 ? -1 : 31 ^ __builtin_clz(n); + return (n == 0) ? -1 : Bits::Log2FloorNonZero(n); } inline int Bits::FindLSBSetNonZero(uint32 n) { + assert(n != 0); return __builtin_ctz(n); } +#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) inline int Bits::FindLSBSetNonZero64(uint64 n) { + assert(n != 0); return __builtin_ctzll(n); } +#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) + +#elif defined(_MSC_VER) + +inline int Bits::Log2FloorNonZero(uint32 n) { + assert(n != 0); + unsigned long where; + _BitScanReverse(&where, n); + return static_cast(where); +} + +inline int Bits::Log2Floor(uint32 n) { + unsigned long where; + if (_BitScanReverse(&where, n)) + return static_cast(where); + return -1; +} + +inline int Bits::FindLSBSetNonZero(uint32 n) { + assert(n != 0); + unsigned long where; + if (_BitScanForward(&where, n)) + return static_cast(where); + return 32; +} + +#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) +inline int Bits::FindLSBSetNonZero64(uint64 n) { + assert(n != 0); + unsigned long where; + if (_BitScanForward64(&where, n)) + return static_cast(where); + return 64; +} +#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) #else // Portable versions. -inline int Bits::Log2Floor(uint32 n) { - if (n == 0) - return -1; +inline int Bits::Log2FloorNonZero(uint32 n) { + assert(n != 0); + int log = 0; uint32 value = n; for (int i = 4; i >= 0; --i) { @@ -367,7 +468,13 @@ inline int Bits::Log2Floor(uint32 n) { return log; } +inline int Bits::Log2Floor(uint32 n) { + return (n == 0) ? -1 : Bits::Log2FloorNonZero(n); +} + inline int Bits::FindLSBSetNonZero(uint32 n) { + assert(n != 0); + int rc = 31; for (int i = 4, shift = 1 << 4; i >= 0; --i) { const uint32 x = n << shift; @@ -380,8 +487,11 @@ inline int Bits::FindLSBSetNonZero(uint32 n) { return rc; } +#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) // FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero(). inline int Bits::FindLSBSetNonZero64(uint64 n) { + assert(n != 0); + const uint32 bottombits = static_cast(n); if (bottombits == 0) { // Bottom bits are zero, so scan in top bits @@ -390,6 +500,7 @@ inline int Bits::FindLSBSetNonZero64(uint64 n) { return FindLSBSetNonZero(bottombits); } } +#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM) #endif // End portable versions. @@ -413,7 +524,7 @@ class Varint { static char* Encode32(char* ptr, uint32 v); // EFFECTS Appends the varint representation of "value" to "*s". - static void Append32(string* s, uint32 value); + static void Append32(std::string* s, uint32 value); }; inline const char* Varint::Parse32WithLimit(const char* p, @@ -470,7 +581,7 @@ inline char* Varint::Encode32(char* sptr, uint32 v) { // replace this function with one that resizes the string without // filling the new space with zeros (if applicable) -- // it will be non-portable but faster. -inline void STLStringResizeUninitialized(string* s, size_t new_size) { +inline void STLStringResizeUninitialized(std::string* s, size_t new_size) { s->resize(new_size); } @@ -486,10 +597,10 @@ inline void STLStringResizeUninitialized(string* s, size_t new_size) { // (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530) // proposes this as the method. It will officially be part of the standard // for C++0x. This should already work on all current implementations. -inline char* string_as_array(string* str) { +inline char* string_as_array(std::string* str) { return str->empty() ? NULL : &*str->begin(); } } // namespace snappy -#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ +#endif // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ diff --git a/ext/snappy/snappy-stubs-public.h b/ext/snappy/snappy-stubs-public.h index f5cd2fca59..fddafbc8c7 100644 --- a/ext/snappy/snappy-stubs-public.h +++ b/ext/snappy/snappy-stubs-public.h @@ -1,5 +1,4 @@ // Copyright 2011 Google Inc. All Rights Reserved. -// Author: sesse@google.com (Steinar H. Gunderson) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -33,10 +32,9 @@ // which is a public header. Instead, snappy-stubs-public.h is generated by // from snappy-stubs-public.h.in at configure time. -#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ -#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ +#ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ +#define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ -#include "base/basictypes.h" #include namespace snappy { @@ -65,4 +63,4 @@ struct iovec { } // namespace snappy -#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ +#endif // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ diff --git a/ext/snappy/snappy.cpp b/ext/snappy/snappy.cpp index 42a217883f..ce1eef4630 100644 --- a/ext/snappy/snappy.cpp +++ b/ext/snappy/snappy.cpp @@ -30,6 +30,44 @@ #include "snappy-internal.h" #include "snappy-sinksource.h" +#if !defined(SNAPPY_HAVE_SSSE3) +// __SSSE3__ is defined by GCC and Clang. Visual Studio doesn't target SIMD +// support between SSE2 and AVX (so SSSE3 instructions require AVX support), and +// defines __AVX__ when AVX support is available. +#if defined(__SSSE3__) || defined(__AVX__) +#define SNAPPY_HAVE_SSSE3 1 +#else +#define SNAPPY_HAVE_SSSE3 0 +#endif +#endif // !defined(SNAPPY_HAVE_SSSE3) + +#if !defined(SNAPPY_HAVE_BMI2) +// __BMI2__ is defined by GCC and Clang. Visual Studio doesn't target BMI2 +// specifically, but it does define __AVX2__ when AVX2 support is available. +// Fortunately, AVX2 was introduced in Haswell, just like BMI2. +// +// BMI2 is not defined as a subset of AVX2 (unlike SSSE3 and AVX above). So, +// GCC and Clang can build code with AVX2 enabled but BMI2 disabled, in which +// case issuing BMI2 instructions results in a compiler error. +#if defined(__BMI2__) || (defined(_MSC_VER) && defined(__AVX2__)) +#define SNAPPY_HAVE_BMI2 1 +#else +#define SNAPPY_HAVE_BMI2 0 +#endif +#endif // !defined(SNAPPY_HAVE_BMI2) + +#if SNAPPY_HAVE_SSSE3 +// Please do not replace with . or with headers that assume more +// advanced SSE versions without checking with all the OWNERS. +#include +#endif + +#if SNAPPY_HAVE_BMI2 +// Please do not replace with . or with headers that assume more +// advanced SSE versions without checking with all the OWNERS. +#include +#endif + #include #include @@ -38,46 +76,11 @@ namespace snappy { - Source::~Source() { } - - Sink::~Sink() { } - - char* Sink::GetAppendBuffer(size_t length, char* scratch) { - return scratch; - } - - ByteArraySource::~ByteArraySource() { } - - size_t ByteArraySource::Available() const { return left_; } - - const char* ByteArraySource::Peek(size_t* len) { - *len = left_; - return ptr_; - } - - void ByteArraySource::Skip(size_t n) { - left_ -= n; - ptr_ += n; - } - - UncheckedByteArraySink::~UncheckedByteArraySink() { } - - void UncheckedByteArraySink::Append(const char* data, size_t n) { - // Do no copying if the caller filled in the result of GetAppendBuffer() - if (data != dest_) { - memcpy(dest_, data, n); - } - dest_ += n; - } - - char* UncheckedByteArraySink::GetAppendBuffer(size_t len, char* scratch) { - return dest_; - } - -} - - -namespace snappy { +using internal::COPY_1_BYTE_OFFSET; +using internal::COPY_2_BYTE_OFFSET; +using internal::LITERAL; +using internal::char_table; +using internal::kMaximumTagLength; // Any hash function will produce a valid compressed bitstream, but a good // hash function reduces the number of collisions and thus yields better @@ -116,168 +119,314 @@ size_t MaxCompressedLength(size_t source_len) { return 32 + source_len + source_len/6; } -enum { - LITERAL = 0, - COPY_1_BYTE_OFFSET = 1, // 3 bit length + 3 bits of offset in opcode - COPY_2_BYTE_OFFSET = 2, - COPY_4_BYTE_OFFSET = 3 -}; -static const int kMaximumTagLength = 5; // COPY_4_BYTE_OFFSET plus the actual offset. - -void Varint::Append32(string* s, uint32 value) { - char buf[Varint::kMax32]; - const char* p = Varint::Encode32(buf, value); - s->append(buf, p - buf); -} - -// Copy "len" bytes from "src" to "op", one byte at a time. Used for -// handling COPY operations where the input and output regions may -// overlap. For example, suppose: -// src == "ab" -// op == src + 2 -// len == 20 -// After IncrementalCopy(src, op, len), the result will have -// eleven copies of "ab" -// ababababababababababab -// Note that this does not match the semantics of either memcpy() -// or memmove(). -static inline void IncrementalCopy(const char* src, char* op, ssize_t len) { - assert(len > 0); - do { - *op++ = *src++; - } while (--len > 0); -} - -// Equivalent to IncrementalCopy except that it can write up to ten extra -// bytes after the end of the copy, and that it is faster. -// -// The main part of this loop is a simple copy of eight bytes at a time until -// we've copied (at least) the requested amount of bytes. However, if op and -// src are less than eight bytes apart (indicating a repeating pattern of -// length < 8), we first need to expand the pattern in order to get the correct -// results. For instance, if the buffer looks like this, with the eight-byte -// and patterns marked as intervals: -// -// abxxxxxxxxxxxx -// [------] src -// [------] op -// -// a single eight-byte copy from to will repeat the pattern once, -// after which we can move two bytes without moving : -// -// ababxxxxxxxxxx -// [------] src -// [------] op -// -// and repeat the exercise until the two no longer overlap. -// -// This allows us to do very well in the special case of one single byte -// repeated many times, without taking a big hit for more general cases. -// -// The worst case of extra writing past the end of the match occurs when -// op - src == 1 and len == 1; the last copy will read from byte positions -// [0..7] and write to [4..11], whereas it was only supposed to write to -// position 1. Thus, ten excess bytes. - namespace { -const int kMaxIncrementCopyOverflow = 10; +void UnalignedCopy64(const void* src, void* dst) { + char tmp[8]; + memcpy(tmp, src, 8); + memcpy(dst, tmp, 8); +} -inline void IncrementalCopyFastPath(const char* src, char* op, ssize_t len) { - while (op - src < 8) { - UnalignedCopy64(src, op); - len -= op - src; - op += op - src; +void UnalignedCopy128(const void* src, void* dst) { + // memcpy gets vectorized when the appropriate compiler options are used. + // For example, x86 compilers targeting SSE2+ will optimize to an SSE2 load + // and store. + char tmp[16]; + memcpy(tmp, src, 16); + memcpy(dst, tmp, 16); +} + +// Copy [src, src+(op_limit-op)) to [op, (op_limit-op)) a byte at a time. Used +// for handling COPY operations where the input and output regions may overlap. +// For example, suppose: +// src == "ab" +// op == src + 2 +// op_limit == op + 20 +// After IncrementalCopySlow(src, op, op_limit), the result will have eleven +// copies of "ab" +// ababababababababababab +// Note that this does not match the semantics of either memcpy() or memmove(). +inline char* IncrementalCopySlow(const char* src, char* op, + char* const op_limit) { + // TODO: Remove pragma when LLVM is aware this + // function is only called in cold regions and when cold regions don't get + // vectorized or unrolled. +#ifdef __clang__ +#pragma clang loop unroll(disable) +#endif + while (op < op_limit) { + *op++ = *src++; } - while (len > 0) { + return op_limit; +} + +#if SNAPPY_HAVE_SSSE3 + +// This is a table of shuffle control masks that can be used as the source +// operand for PSHUFB to permute the contents of the destination XMM register +// into a repeating byte pattern. +alignas(16) const char pshufb_fill_patterns[7][16] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, + {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0}, + {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}, + {0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0}, + {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3}, + {0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1}, +}; + +#endif // SNAPPY_HAVE_SSSE3 + +// Copy [src, src+(op_limit-op)) to [op, (op_limit-op)) but faster than +// IncrementalCopySlow. buf_limit is the address past the end of the writable +// region of the buffer. +inline char* IncrementalCopy(const char* src, char* op, char* const op_limit, + char* const buf_limit) { + // Terminology: + // + // slop = buf_limit - op + // pat = op - src + // len = limit - op + assert(src < op); + assert(op <= op_limit); + assert(op_limit <= buf_limit); + // NOTE: The compressor always emits 4 <= len <= 64. It is ok to assume that + // to optimize this function but we have to also handle other cases in case + // the input does not satisfy these conditions. + + size_t pattern_size = op - src; + // The cases are split into different branches to allow the branch predictor, + // FDO, and static prediction hints to work better. For each input we list the + // ratio of invocations that match each condition. + // + // input slop < 16 pat < 8 len > 16 + // ------------------------------------------ + // html|html4|cp 0% 1.01% 27.73% + // urls 0% 0.88% 14.79% + // jpg 0% 64.29% 7.14% + // pdf 0% 2.56% 58.06% + // txt[1-4] 0% 0.23% 0.97% + // pb 0% 0.96% 13.88% + // bin 0.01% 22.27% 41.17% + // + // It is very rare that we don't have enough slop for doing block copies. It + // is also rare that we need to expand a pattern. Small patterns are common + // for incompressible formats and for those we are plenty fast already. + // Lengths are normally not greater than 16 but they vary depending on the + // input. In general if we always predict len <= 16 it would be an ok + // prediction. + // + // In order to be fast we want a pattern >= 8 bytes and an unrolled loop + // copying 2x 8 bytes at a time. + + // Handle the uncommon case where pattern is less than 8 bytes. + if (SNAPPY_PREDICT_FALSE(pattern_size < 8)) { +#if SNAPPY_HAVE_SSSE3 + // Load the first eight bytes into an 128-bit XMM register, then use PSHUFB + // to permute the register's contents in-place into a repeating sequence of + // the first "pattern_size" bytes. + // For example, suppose: + // src == "abc" + // op == op + 3 + // After _mm_shuffle_epi8(), "pattern" will have five copies of "abc" + // followed by one byte of slop: abcabcabcabcabca. + // + // The non-SSE fallback implementation suffers from store-forwarding stalls + // because its loads and stores partly overlap. By expanding the pattern + // in-place, we avoid the penalty. + if (SNAPPY_PREDICT_TRUE(op <= buf_limit - 16)) { + const __m128i shuffle_mask = _mm_load_si128( + reinterpret_cast(pshufb_fill_patterns) + + pattern_size - 1); + const __m128i pattern = _mm_shuffle_epi8( + _mm_loadl_epi64(reinterpret_cast(src)), shuffle_mask); + // Uninitialized bytes are masked out by the shuffle mask. + // TODO: remove annotation and macro defs once MSan is fixed. + SNAPPY_ANNOTATE_MEMORY_IS_INITIALIZED(&pattern, sizeof(pattern)); + pattern_size *= 16 / pattern_size; + char* op_end = std::min(op_limit, buf_limit - 15); + while (op < op_end) { + _mm_storeu_si128(reinterpret_cast<__m128i*>(op), pattern); + op += pattern_size; + } + if (SNAPPY_PREDICT_TRUE(op >= op_limit)) return op_limit; + } + return IncrementalCopySlow(src, op, op_limit); +#else // !SNAPPY_HAVE_SSSE3 + // If plenty of buffer space remains, expand the pattern to at least 8 + // bytes. The way the following loop is written, we need 8 bytes of buffer + // space if pattern_size >= 4, 11 bytes if pattern_size is 1 or 3, and 10 + // bytes if pattern_size is 2. Precisely encoding that is probably not + // worthwhile; instead, invoke the slow path if we cannot write 11 bytes + // (because 11 are required in the worst case). + if (SNAPPY_PREDICT_TRUE(op <= buf_limit - 11)) { + while (pattern_size < 8) { + UnalignedCopy64(src, op); + op += pattern_size; + pattern_size *= 2; + } + if (SNAPPY_PREDICT_TRUE(op >= op_limit)) return op_limit; + } else { + return IncrementalCopySlow(src, op, op_limit); + } +#endif // SNAPPY_HAVE_SSSE3 + } + assert(pattern_size >= 8); + + // Copy 2x 8 bytes at a time. Because op - src can be < 16, a single + // UnalignedCopy128 might overwrite data in op. UnalignedCopy64 is safe + // because expanding the pattern to at least 8 bytes guarantees that + // op - src >= 8. + // + // Typically, the op_limit is the gating factor so try to simplify the loop + // based on that. + if (SNAPPY_PREDICT_TRUE(op_limit <= buf_limit - 16)) { + // There is at least one, and at most four 16-byte blocks. Writing four + // conditionals instead of a loop allows FDO to layout the code with respect + // to the actual probabilities of each length. + // TODO: Replace with loop with trip count hint. + UnalignedCopy64(src, op); + UnalignedCopy64(src + 8, op + 8); + + if (op + 16 < op_limit) { + UnalignedCopy64(src + 16, op + 16); + UnalignedCopy64(src + 24, op + 24); + } + if (op + 32 < op_limit) { + UnalignedCopy64(src + 32, op + 32); + UnalignedCopy64(src + 40, op + 40); + } + if (op + 48 < op_limit) { + UnalignedCopy64(src + 48, op + 48); + UnalignedCopy64(src + 56, op + 56); + } + return op_limit; + } + + // Fall back to doing as much as we can with the available slop in the + // buffer. This code path is relatively cold however so we save code size by + // avoiding unrolling and vectorizing. + // + // TODO: Remove pragma when when cold regions don't get vectorized + // or unrolled. +#ifdef __clang__ +#pragma clang loop unroll(disable) +#endif + for (char *op_end = buf_limit - 16; op < op_end; op += 16, src += 16) { + UnalignedCopy64(src, op); + UnalignedCopy64(src + 8, op + 8); + } + if (op >= op_limit) + return op_limit; + + // We only take this branch if we didn't have enough slop and we can do a + // single 8 byte copy. + if (SNAPPY_PREDICT_FALSE(op <= buf_limit - 8)) { UnalignedCopy64(src, op); src += 8; op += 8; - len -= 8; } + return IncrementalCopySlow(src, op, op_limit); } } // namespace +template static inline char* EmitLiteral(char* op, const char* literal, - int len, - bool allow_fast_path) { - int n = len - 1; // Zero-length literals are disallowed - if (n < 60) { + int len) { + // The vast majority of copies are below 16 bytes, for which a + // call to memcpy is overkill. This fast path can sometimes + // copy up to 15 bytes too much, but that is okay in the + // main loop, since we have a bit to go on for both sides: + // + // - The input will always have kInputMarginBytes = 15 extra + // available bytes, as long as we're in the main loop, and + // if not, allow_fast_path = false. + // - The output will always have 32 spare bytes (see + // MaxCompressedLength). + assert(len > 0); // Zero-length literals are disallowed + int n = len - 1; + if (allow_fast_path && len <= 16) { // Fits in tag byte *op++ = LITERAL | (n << 2); - // The vast majority of copies are below 16 bytes, for which a - // call to memcpy is overkill. This fast path can sometimes - // copy up to 15 bytes too much, but that is okay in the - // main loop, since we have a bit to go on for both sides: - // - // - The input will always have kInputMarginBytes = 15 extra - // available bytes, as long as we're in the main loop, and - // if not, allow_fast_path = false. - // - The output will always have 32 spare bytes (see - // MaxCompressedLength). - if (allow_fast_path && len <= 16) { - UnalignedCopy64(literal, op); - UnalignedCopy64(literal + 8, op + 8); - return op + len; - } + UnalignedCopy128(literal, op); + return op + len; + } + + if (n < 60) { + // Fits in tag byte + *op++ = LITERAL | (n << 2); } else { - // Encode in upcoming bytes - char* base = op; - int count = 0; - op++; - while (n > 0) { - *op++ = n & 0xff; - n >>= 8; - count++; - } + int count = (Bits::Log2Floor(n) >> 3) + 1; assert(count >= 1); assert(count <= 4); - *base = LITERAL | ((59+count) << 2); + *op++ = LITERAL | ((59 + count) << 2); + // Encode in upcoming bytes. + // Write 4 bytes, though we may care about only 1 of them. The output buffer + // is guaranteed to have at least 3 more spaces left as 'len >= 61' holds + // here and there is a memcpy of size 'len' below. + LittleEndian::Store32(op, n); + op += count; } memcpy(op, literal, len); return op + len; } -static inline char* EmitCopyLessThan64(char* op, size_t offset, int len) { +template +static inline char* EmitCopyAtMost64(char* op, size_t offset, size_t len) { assert(len <= 64); assert(len >= 4); assert(offset < 65536); + assert(len_less_than_12 == (len < 12)); - if ((len < 12) && (offset < 2048)) { - size_t len_minus_4 = len - 4; - assert(len_minus_4 < 8); // Must fit in 3 bits - *op++ = static_cast(COPY_1_BYTE_OFFSET + ((len_minus_4) << 2) + ((offset >> 8) << 5)); + if (len_less_than_12 && SNAPPY_PREDICT_TRUE(offset < 2048)) { + // offset fits in 11 bits. The 3 highest go in the top of the first byte, + // and the rest go in the second byte. + *op++ = COPY_1_BYTE_OFFSET + ((len - 4) << 2) + ((offset >> 3) & 0xe0); *op++ = offset & 0xff; } else { - *op++ = COPY_2_BYTE_OFFSET + ((len-1) << 2); - LittleEndian::Store16(op, static_cast(offset)); - op += 2; + // Write 4 bytes, though we only care about 3 of them. The output buffer + // is required to have some slack, so the extra byte won't overrun it. + uint32 u = COPY_2_BYTE_OFFSET + ((len - 1) << 2) + (offset << 8); + LittleEndian::Store32(op, u); + op += 3; } return op; } -static inline char* EmitCopy(char* op, size_t offset, int len) { - // Emit 64 byte copies but make sure to keep at least four bytes reserved - while (len >= 68) { - op = EmitCopyLessThan64(op, offset, 64); - len -= 64; - } +template +static inline char* EmitCopy(char* op, size_t offset, size_t len) { + assert(len_less_than_12 == (len < 12)); + if (len_less_than_12) { + return EmitCopyAtMost64(op, offset, len); + } else { + // A special case for len <= 64 might help, but so far measurements suggest + // it's in the noise. - // Emit an extra 60 byte copy if have too much data to fit in one copy - if (len > 64) { - op = EmitCopyLessThan64(op, offset, 60); - len -= 60; - } + // Emit 64 byte copies but make sure to keep at least four bytes reserved. + while (SNAPPY_PREDICT_FALSE(len >= 68)) { + op = EmitCopyAtMost64(op, offset, 64); + len -= 64; + } - // Emit remainder - op = EmitCopyLessThan64(op, offset, len); - return op; + // One or two copies will now finish the job. + if (len > 64) { + op = EmitCopyAtMost64(op, offset, 60); + len -= 60; + } + + // Emit remainder. + if (len < 12) { + op = EmitCopyAtMost64(op, offset, len); + } else { + op = EmitCopyAtMost64(op, offset, len); + } + return op; + } } - bool GetUncompressedLength(const char* start, size_t n, size_t* result) { uint32 v = 0; const char* limit = start + n; @@ -289,31 +438,45 @@ bool GetUncompressedLength(const char* start, size_t n, size_t* result) { } } +namespace { +uint32 CalculateTableSize(uint32 input_size) { + static_assert( + kMaxHashTableSize >= kMinHashTableSize, + "kMaxHashTableSize should be greater or equal to kMinHashTableSize."); + if (input_size > kMaxHashTableSize) { + return kMaxHashTableSize; + } + if (input_size < kMinHashTableSize) { + return kMinHashTableSize; + } + // This is equivalent to Log2Ceiling(input_size), assuming input_size > 1. + // 2 << Log2Floor(x - 1) is equivalent to 1 << (1 + Log2Floor(x - 1)). + return 2u << Bits::Log2Floor(input_size - 1); +} +} // namespace + namespace internal { -uint16* WorkingMemory::GetHashTable(size_t input_size, int* table_size) { - // Use smaller hash table when input.size() is smaller, since we - // fill the table, incurring O(hash table size) overhead for - // compression, and if the input is short, we won't need that - // many hash table entries anyway. - assert(kMaxHashTableSize >= 256); - size_t htsize = 256; - while (htsize < kMaxHashTableSize && htsize < input_size) { - htsize <<= 1; - } +WorkingMemory::WorkingMemory(size_t input_size) { + const size_t max_fragment_size = std::min(input_size, kBlockSize); + const size_t table_size = CalculateTableSize(max_fragment_size); + size_ = table_size * sizeof(*table_) + max_fragment_size + + MaxCompressedLength(max_fragment_size); + mem_ = std::allocator().allocate(size_); + table_ = reinterpret_cast(mem_); + input_ = mem_ + table_size * sizeof(*table_); + output_ = input_ + max_fragment_size; +} - uint16* table; - if (htsize <= ARRAYSIZE(small_table_)) { - table = small_table_; - } else { - if (large_table_ == NULL) { - large_table_ = new uint16[kMaxHashTableSize]; - } - table = large_table_; - } +WorkingMemory::~WorkingMemory() { + std::allocator().deallocate(mem_, size_); +} - *table_size = static_cast(htsize); - memset(table, 0, htsize * sizeof(*table)); - return table; +uint16* WorkingMemory::GetHashTable(size_t fragment_size, + int* table_size) const { + const size_t htsize = CalculateTableSize(fragment_size); + memset(table_, 0, htsize * sizeof(*table_)); + *table_size = htsize; + return table_; } } // end namespace internal @@ -380,7 +543,7 @@ char* CompressFragment(const char* input, // "ip" is the input pointer, and "op" is the output pointer. const char* ip = input; assert(input_size <= kBlockSize); - assert((table_size & (table_size - 1)) == 0); // table must be power of two + assert((table_size & (table_size - 1)) == 0); // table must be power of two const int shift = 32 - Bits::Log2Floor(table_size); assert(static_cast(kuint32max >> shift) == table_size - 1); const char* ip_end = input + input_size; @@ -390,7 +553,7 @@ char* CompressFragment(const char* input, const char* next_emit = ip; const size_t kInputMarginBytes = 15; - if (PREDICT_TRUE(input_size >= kInputMarginBytes)) { + if (SNAPPY_PREDICT_TRUE(input_size >= kInputMarginBytes)) { const char* ip_limit = input + input_size - kInputMarginBytes; for (uint32 next_hash = Hash(++ip, shift); ; ) { @@ -410,9 +573,9 @@ char* CompressFragment(const char* input, // // Heuristic match skipping: If 32 bytes are scanned with no matches // found, start looking only at every other byte. If 32 more bytes are - // scanned, look at every third byte, etc.. When a match is found, - // immediately go back to looking at every byte. This is a small loss - // (~5% performance, ~0.1% density) for compressible data due to more + // scanned (or skipped), look at every third byte, etc.. When a match is + // found, immediately go back to looking at every byte. This is a small + // loss (~5% performance, ~0.1% density) for compressible data due to more // bookkeeping, but for non-compressible data (such as JPEG) it's a huge // win since the compressor quickly "realizes" the data is incompressible // and doesn't bother looking for matches everywhere. @@ -428,9 +591,10 @@ char* CompressFragment(const char* input, ip = next_ip; uint32 hash = next_hash; assert(hash == Hash(ip, shift)); - uint32 bytes_between_hash_lookups = skip++ >> 5; + uint32 bytes_between_hash_lookups = skip >> 5; + skip += bytes_between_hash_lookups; next_ip = ip + bytes_between_hash_lookups; - if (PREDICT_FALSE(next_ip > ip_limit)) { + if (SNAPPY_PREDICT_FALSE(next_ip > ip_limit)) { goto emit_remainder; } next_hash = Hash(next_ip, shift); @@ -439,14 +603,14 @@ char* CompressFragment(const char* input, assert(candidate < ip); table[hash] = ip - base_ip; - } while (PREDICT_TRUE(UNALIGNED_LOAD32(ip) != - UNALIGNED_LOAD32(candidate))); + } while (SNAPPY_PREDICT_TRUE(UNALIGNED_LOAD32(ip) != + UNALIGNED_LOAD32(candidate))); // Step 2: A 4-byte match has been found. We'll later see if more // than 4 bytes match. But, prior to the match, input // bytes [next_emit, ip) are unmatched. Emit them as "literal bytes." assert(next_emit + 16 <= ip_end); - op = EmitLiteral(op, next_emit, ip - next_emit, true); + op = EmitLiteral(op, next_emit, ip - next_emit); // Step 3: Call EmitCopy, and then see if another EmitCopy could // be our next move. Repeat until we find no match for the @@ -463,19 +627,25 @@ char* CompressFragment(const char* input, // We have a 4-byte match at ip, and no need to emit any // "literal bytes" prior to ip. const char* base = ip; - int matched = 4 + FindMatchLength(candidate + 4, ip + 4, ip_end); + std::pair p = + FindMatchLength(candidate + 4, ip + 4, ip_end); + size_t matched = 4 + p.first; ip += matched; size_t offset = base - candidate; assert(0 == memcmp(base, candidate, matched)); - op = EmitCopy(op, offset, matched); - // We could immediately start working at ip now, but to improve - // compression we first update table[Hash(ip - 1, ...)]. - const char* insert_tail = ip - 1; + if (p.second) { + op = EmitCopy(op, offset, matched); + } else { + op = EmitCopy(op, offset, matched); + } next_emit = ip; - if (PREDICT_FALSE(ip >= ip_limit)) { + if (SNAPPY_PREDICT_FALSE(ip >= ip_limit)) { goto emit_remainder; } - input_bytes = GetEightBytesAt(insert_tail); + // We are now looking for a 4-byte match again. We read + // table[Hash(ip, shift)] for that. To improve compression, + // we also update table[Hash(ip - 1, shift)] and table[Hash(ip, shift)]. + input_bytes = GetEightBytesAt(ip - 1); uint32 prev_hash = HashBytes(GetUint32AtOffset(input_bytes, 0), shift); table[prev_hash] = ip - base_ip - 1; uint32 cur_hash = HashBytes(GetUint32AtOffset(input_bytes, 1), shift); @@ -492,13 +662,18 @@ char* CompressFragment(const char* input, emit_remainder: // Emit the remaining bytes as a literal if (next_emit < ip_end) { - op = EmitLiteral(op, next_emit, ip_end - next_emit, false); + op = EmitLiteral(op, next_emit, + ip_end - next_emit); } return op; } } // end namespace internal +// Called back at avery compression call to trace parameters and sizes. +static inline void Report(const char *algorithm, size_t compressed_size, + size_t uncompressed_size) {} + // Signature of output types needed by decompression code. // The decompression code is templatized on a type that obeys this // signature so that we do not pay virtual function call overhead in @@ -539,162 +714,28 @@ char* CompressFragment(const char* input, // bool TryFastAppend(const char* ip, size_t available, size_t length); // }; -// ----------------------------------------------------------------------- -// Lookup table for decompression code. Generated by ComputeTable() below. -// ----------------------------------------------------------------------- - -// Mapping from i in range [0,4] to a mask to extract the bottom 8*i bits -static const uint32 wordmask[] = { - 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu -}; - -// Data stored per entry in lookup table: -// Range Bits-used Description -// ------------------------------------ -// 1..64 0..7 Literal/copy length encoded in opcode byte -// 0..7 8..10 Copy offset encoded in opcode byte / 256 -// 0..4 11..13 Extra bytes after opcode -// -// We use eight bits for the length even though 7 would have sufficed -// because of efficiency reasons: -// (1) Extracting a byte is faster than a bit-field -// (2) It properly aligns copy offset so we do not need a <<8 -static const uint16 char_table[256] = { - 0x0001, 0x0804, 0x1001, 0x2001, 0x0002, 0x0805, 0x1002, 0x2002, - 0x0003, 0x0806, 0x1003, 0x2003, 0x0004, 0x0807, 0x1004, 0x2004, - 0x0005, 0x0808, 0x1005, 0x2005, 0x0006, 0x0809, 0x1006, 0x2006, - 0x0007, 0x080a, 0x1007, 0x2007, 0x0008, 0x080b, 0x1008, 0x2008, - 0x0009, 0x0904, 0x1009, 0x2009, 0x000a, 0x0905, 0x100a, 0x200a, - 0x000b, 0x0906, 0x100b, 0x200b, 0x000c, 0x0907, 0x100c, 0x200c, - 0x000d, 0x0908, 0x100d, 0x200d, 0x000e, 0x0909, 0x100e, 0x200e, - 0x000f, 0x090a, 0x100f, 0x200f, 0x0010, 0x090b, 0x1010, 0x2010, - 0x0011, 0x0a04, 0x1011, 0x2011, 0x0012, 0x0a05, 0x1012, 0x2012, - 0x0013, 0x0a06, 0x1013, 0x2013, 0x0014, 0x0a07, 0x1014, 0x2014, - 0x0015, 0x0a08, 0x1015, 0x2015, 0x0016, 0x0a09, 0x1016, 0x2016, - 0x0017, 0x0a0a, 0x1017, 0x2017, 0x0018, 0x0a0b, 0x1018, 0x2018, - 0x0019, 0x0b04, 0x1019, 0x2019, 0x001a, 0x0b05, 0x101a, 0x201a, - 0x001b, 0x0b06, 0x101b, 0x201b, 0x001c, 0x0b07, 0x101c, 0x201c, - 0x001d, 0x0b08, 0x101d, 0x201d, 0x001e, 0x0b09, 0x101e, 0x201e, - 0x001f, 0x0b0a, 0x101f, 0x201f, 0x0020, 0x0b0b, 0x1020, 0x2020, - 0x0021, 0x0c04, 0x1021, 0x2021, 0x0022, 0x0c05, 0x1022, 0x2022, - 0x0023, 0x0c06, 0x1023, 0x2023, 0x0024, 0x0c07, 0x1024, 0x2024, - 0x0025, 0x0c08, 0x1025, 0x2025, 0x0026, 0x0c09, 0x1026, 0x2026, - 0x0027, 0x0c0a, 0x1027, 0x2027, 0x0028, 0x0c0b, 0x1028, 0x2028, - 0x0029, 0x0d04, 0x1029, 0x2029, 0x002a, 0x0d05, 0x102a, 0x202a, - 0x002b, 0x0d06, 0x102b, 0x202b, 0x002c, 0x0d07, 0x102c, 0x202c, - 0x002d, 0x0d08, 0x102d, 0x202d, 0x002e, 0x0d09, 0x102e, 0x202e, - 0x002f, 0x0d0a, 0x102f, 0x202f, 0x0030, 0x0d0b, 0x1030, 0x2030, - 0x0031, 0x0e04, 0x1031, 0x2031, 0x0032, 0x0e05, 0x1032, 0x2032, - 0x0033, 0x0e06, 0x1033, 0x2033, 0x0034, 0x0e07, 0x1034, 0x2034, - 0x0035, 0x0e08, 0x1035, 0x2035, 0x0036, 0x0e09, 0x1036, 0x2036, - 0x0037, 0x0e0a, 0x1037, 0x2037, 0x0038, 0x0e0b, 0x1038, 0x2038, - 0x0039, 0x0f04, 0x1039, 0x2039, 0x003a, 0x0f05, 0x103a, 0x203a, - 0x003b, 0x0f06, 0x103b, 0x203b, 0x003c, 0x0f07, 0x103c, 0x203c, - 0x0801, 0x0f08, 0x103d, 0x203d, 0x1001, 0x0f09, 0x103e, 0x203e, - 0x1801, 0x0f0a, 0x103f, 0x203f, 0x2001, 0x0f0b, 0x1040, 0x2040 -}; - -// In debug mode, allow optional computation of the table at startup. -// Also, check that the decompression table is correct. -#ifdef _DEBUG -DEFINE_bool(snappy_dump_decompression_table, false, - "If true, we print the decompression table at startup."); - -static uint16 MakeEntry(unsigned int extra, - unsigned int len, - unsigned int copy_offset) { - // Check that all of the fields fit within the allocated space - assert(extra == (extra & 0x7)); // At most 3 bits - assert(copy_offset == (copy_offset & 0x7)); // At most 3 bits - assert(len == (len & 0x7f)); // At most 7 bits - return len | (copy_offset << 8) | (extra << 11); +static inline uint32 ExtractLowBytes(uint32 v, int n) { + assert(n >= 0); + assert(n <= 4); +#if SNAPPY_HAVE_BMI2 + return _bzhi_u32(v, 8 * n); +#else + // This needs to be wider than uint32 otherwise `mask << 32` will be + // undefined. + uint64 mask = 0xffffffff; + return v & ~(mask << (8 * n)); +#endif } -static void ComputeTable() { - uint16 dst[256]; - - // Place invalid entries in all places to detect missing initialization - int assigned = 0; - for (int i = 0; i < 256; i++) { - dst[i] = 0xffff; - } - - // Small LITERAL entries. We store (len-1) in the top 6 bits. - for (unsigned int len = 1; len <= 60; len++) { - dst[LITERAL | ((len-1) << 2)] = MakeEntry(0, len, 0); - assigned++; - } - - // Large LITERAL entries. We use 60..63 in the high 6 bits to - // encode the number of bytes of length info that follow the opcode. - for (unsigned int extra_bytes = 1; extra_bytes <= 4; extra_bytes++) { - // We set the length field in the lookup table to 1 because extra - // bytes encode len-1. - dst[LITERAL | ((extra_bytes+59) << 2)] = MakeEntry(extra_bytes, 1, 0); - assigned++; - } - - // COPY_1_BYTE_OFFSET. - // - // The tag byte in the compressed data stores len-4 in 3 bits, and - // offset/256 in 5 bits. offset%256 is stored in the next byte. - // - // This format is used for length in range [4..11] and offset in - // range [0..2047] - for (unsigned int len = 4; len < 12; len++) { - for (unsigned int offset = 0; offset < 2048; offset += 256) { - dst[COPY_1_BYTE_OFFSET | ((len-4)<<2) | ((offset>>8)<<5)] = - MakeEntry(1, len, offset>>8); - assigned++; - } - } - - // COPY_2_BYTE_OFFSET. - // Tag contains len-1 in top 6 bits, and offset in next two bytes. - for (unsigned int len = 1; len <= 64; len++) { - dst[COPY_2_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(2, len, 0); - assigned++; - } - - // COPY_4_BYTE_OFFSET. - // Tag contents len-1 in top 6 bits, and offset in next four bytes. - for (unsigned int len = 1; len <= 64; len++) { - dst[COPY_4_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(4, len, 0); - assigned++; - } - - // Check that each entry was initialized exactly once. - if (assigned != 256) { - fprintf(stderr, "ComputeTable: assigned only %d of 256\n", assigned); - abort(); - } - for (int i = 0; i < 256; i++) { - if (dst[i] == 0xffff) { - fprintf(stderr, "ComputeTable: did not assign byte %d\n", i); - abort(); - } - } - - if (FLAGS_snappy_dump_decompression_table) { - printf("static const uint16 char_table[256] = {\n "); - for (int i = 0; i < 256; i++) { - printf("0x%04x%s", - dst[i], - ((i == 255) ? "\n" : (((i%8) == 7) ? ",\n " : ", "))); - } - printf("};\n"); - } - - // Check that computed table matched recorded table - for (int i = 0; i < 256; i++) { - if (dst[i] != char_table[i]) { - fprintf(stderr, "ComputeTable: byte %d: computed (%x), expect (%x)\n", - i, static_cast(dst[i]), static_cast(char_table[i])); - abort(); - } - } +static inline bool LeftShiftOverflows(uint8 value, uint32 shift) { + assert(shift < 32); + static const uint8 masks[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe}; + return (value & masks[shift]) != 0; } -#endif /* !NDEBUG */ // Helper class for decompression class SnappyDecompressor { @@ -733,7 +774,7 @@ class SnappyDecompressor { } // Read the uncompressed length stored at the start of the compressed data. - // On succcess, stores the length in *result and returns true. + // On success, stores the length in *result and returns true. // On failure, returns false. bool ReadUncompressedLength(uint32* result) { assert(ip_ == NULL); // Must not have read anything yet @@ -747,7 +788,9 @@ class SnappyDecompressor { if (n == 0) return false; const unsigned char c = *(reinterpret_cast(ip)); reader_->Skip(1); - *result |= static_cast(c & 0x7f) << shift; + uint32 val = c & 0x7f; + if (LeftShiftOverflows(static_cast(val), shift)) return false; + *result |= val << shift; if (c < 128) { break; } @@ -759,9 +802,27 @@ class SnappyDecompressor { // Process the next item found in the input. // Returns true if successful, false on error or end of input. template +#if defined(__GNUC__) && defined(__x86_64__) + __attribute__((aligned(32))) +#endif void DecompressAllTags(Writer* writer) { - const char* ip = ip_; + // In x86, pad the function body to start 16 bytes later. This function has + // a couple of hotspots that are highly sensitive to alignment: we have + // observed regressions by more than 20% in some metrics just by moving the + // exact same code to a different position in the benchmark binary. + // + // Putting this code on a 32-byte-aligned boundary + 16 bytes makes us hit + // the "lucky" case consistently. Unfortunately, this is a very brittle + // workaround, and future differences in code generation may reintroduce + // this regression. If you experience a big, difficult to explain, benchmark + // performance regression here, first try removing this hack. +#if defined(__GNUC__) && defined(__x86_64__) + // Two 8-byte "NOP DWORD ptr [EAX + EAX*1 + 00000000H]" instructions. + asm(".byte 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00"); + asm(".byte 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00"); +#endif + const char* ip = ip_; // We could have put this refill fragment only at the beginning of the loop. // However, duplicating it at the end of each branch gives the compiler more // scope to optimize the expression based on the local @@ -777,21 +838,34 @@ class SnappyDecompressor { for ( ;; ) { const unsigned char c = *(reinterpret_cast(ip++)); - if ((c & 0x3) == LITERAL) { + // Ratio of iterations that have LITERAL vs non-LITERAL for different + // inputs. + // + // input LITERAL NON_LITERAL + // ----------------------------------- + // html|html4|cp 23% 77% + // urls 36% 64% + // jpg 47% 53% + // pdf 19% 81% + // txt[1-4] 25% 75% + // pb 24% 76% + // bin 24% 76% + if (SNAPPY_PREDICT_FALSE((c & 0x3) == LITERAL)) { size_t literal_length = (c >> 2) + 1u; if (writer->TryFastAppend(ip, ip_limit_ - ip, literal_length)) { assert(literal_length < 61); ip += literal_length; - // NOTE(user): There is no MAYBE_REFILL() here, as TryFastAppend() + // NOTE: There is no MAYBE_REFILL() here, as TryFastAppend() // will not return true unless there's already at least five spare // bytes in addition to the literal. continue; } - if (PREDICT_FALSE(literal_length >= 61)) { + if (SNAPPY_PREDICT_FALSE(literal_length >= 61)) { // Long literal. const size_t literal_length_length = literal_length - 60; literal_length = - (LittleEndian::Load32(ip) & wordmask[literal_length_length]) + 1; + ExtractLowBytes(LittleEndian::Load32(ip), literal_length_length) + + 1; ip += literal_length_length; } @@ -803,7 +877,7 @@ class SnappyDecompressor { size_t n; ip = reader_->Peek(&n); avail = n; - peeked_ = static_cast(avail); + peeked_ = avail; if (avail == 0) return; // Premature end of input ip_limit_ = ip + avail; } @@ -813,15 +887,16 @@ class SnappyDecompressor { ip += literal_length; MAYBE_REFILL(); } else { - const uint32 entry = char_table[c]; - const uint32 trailer = LittleEndian::Load32(ip) & wordmask[entry >> 11]; - const uint32 length = entry & 0xff; + const size_t entry = char_table[c]; + const size_t trailer = + ExtractLowBytes(LittleEndian::Load32(ip), entry >> 11); + const size_t length = entry & 0xff; ip += entry >> 11; // copy_offset/256 is encoded in bits 8..10. By just fetching // those bits, we get copy_offset (since the bit-field starts at // bit 8). - const uint32 copy_offset = entry & 0x700; + const size_t copy_offset = entry & 0x700; if (!writer->AppendFromSelf(copy_offset + trailer, length)) { return; } @@ -840,11 +915,9 @@ bool SnappyDecompressor::RefillTag() { reader_->Skip(peeked_); // All peeked bytes are used up size_t n; ip = reader_->Peek(&n); - peeked_ = static_cast(n); - if (n == 0) { - eof_ = true; - return false; - } + peeked_ = n; + eof_ = (n == 0); + if (eof_) return false; ip_limit_ = ip + n; } @@ -869,7 +942,7 @@ bool SnappyDecompressor::RefillTag() { size_t length; const char* src = reader_->Peek(&length); if (length == 0) return false; - uint32 to_add = min(needed - nbuf, static_cast(length)); + uint32 to_add = std::min(needed - nbuf, length); memcpy(scratch_ + nbuf, src, to_add); nbuf += to_add; reader_->Skip(to_add); @@ -898,17 +971,23 @@ static bool InternalUncompress(Source* r, Writer* writer) { SnappyDecompressor decompressor(r); uint32 uncompressed_len = 0; if (!decompressor.ReadUncompressedLength(&uncompressed_len)) return false; - return InternalUncompressAllTags(&decompressor, writer, uncompressed_len); + + return InternalUncompressAllTags(&decompressor, writer, r->Available(), + uncompressed_len); } template static bool InternalUncompressAllTags(SnappyDecompressor* decompressor, Writer* writer, + uint32 compressed_len, uint32 uncompressed_len) { + Report("snappy_uncompress", compressed_len, uncompressed_len); + writer->SetExpectedLength(uncompressed_len); // Process the entire input decompressor->DecompressAllTags(writer); + writer->Flush(); return (decompressor->eof() && writer->CheckLength()); } @@ -920,21 +999,20 @@ bool GetUncompressedLength(Source* source, uint32* result) { size_t Compress(Source* reader, Sink* writer) { size_t written = 0; size_t N = reader->Available(); + const size_t uncompressed_size = N; char ulength[Varint::kMax32]; - char* p = Varint::Encode32(ulength, static_cast(N)); + char* p = Varint::Encode32(ulength, N); writer->Append(ulength, p-ulength); written += (p - ulength); - internal::WorkingMemory wmem; - char* scratch = NULL; - char* scratch_output = NULL; + internal::WorkingMemory wmem(N); while (N > 0) { // Get next block to compress (without copying if possible) size_t fragment_size; const char* fragment = reader->Peek(&fragment_size); assert(fragment_size != 0); // premature end of input - const size_t num_to_read = min(N, kBlockSize); + const size_t num_to_read = std::min(N, kBlockSize); size_t bytes_read = fragment_size; size_t pending_advance = 0; @@ -943,19 +1021,13 @@ size_t Compress(Source* reader, Sink* writer) { pending_advance = num_to_read; fragment_size = num_to_read; } else { - // Read into scratch buffer - if (scratch == NULL) { - // If this is the last iteration, we want to allocate N bytes - // of space, otherwise the max possible kBlockSize space. - // num_to_read contains exactly the correct value - scratch = new char[num_to_read]; - } + char* scratch = wmem.GetScratchInput(); memcpy(scratch, fragment, bytes_read); reader->Skip(bytes_read); while (bytes_read < num_to_read) { fragment = reader->Peek(&fragment_size); - size_t n = min(fragment_size, num_to_read - bytes_read); + size_t n = std::min(fragment_size, num_to_read - bytes_read); memcpy(scratch + bytes_read, fragment, n); bytes_read += n; reader->Skip(n); @@ -971,20 +1043,17 @@ size_t Compress(Source* reader, Sink* writer) { uint16* table = wmem.GetHashTable(num_to_read, &table_size); // Compress input_fragment and append to dest - const size_t max_output = MaxCompressedLength(num_to_read); + const int max_output = MaxCompressedLength(num_to_read); // Need a scratch buffer for the output, in case the byte sink doesn't // have room for us directly. - if (scratch_output == NULL) { - scratch_output = new char[max_output]; - } else { - // Since we encode kBlockSize regions followed by a region - // which is <= kBlockSize in length, a previously allocated - // scratch_output[] region is big enough for this iteration. - } - char* dest = writer->GetAppendBuffer(max_output, scratch_output); - char* end = internal::CompressFragment(fragment, fragment_size, - dest, table, table_size); + + // Since we encode kBlockSize regions followed by a region + // which is <= kBlockSize in length, a previously allocated + // scratch_output[] region is big enough for this iteration. + char* dest = writer->GetAppendBuffer(max_output, wmem.GetScratchOutput()); + char* end = internal::CompressFragment(fragment, fragment_size, dest, table, + table_size); writer->Append(dest, end - dest); written += (end - dest); @@ -992,8 +1061,7 @@ size_t Compress(Source* reader, Sink* writer) { reader->Skip(pending_advance); } - delete[] scratch; - delete[] scratch_output; + Report("snappy_compress", written, uncompressed_size); return written; } @@ -1007,14 +1075,22 @@ size_t Compress(Source* reader, Sink* writer) { // Writer template argument to SnappyDecompressor::DecompressAllTags(). class SnappyIOVecWriter { private: + // output_iov_end_ is set to iov + count and used to determine when + // the end of the iovs is reached. + const struct iovec* output_iov_end_; + +#if !defined(NDEBUG) const struct iovec* output_iov_; - const size_t output_iov_count_; +#endif // !defined(NDEBUG) - // We are currently writing into output_iov_[curr_iov_index_]. - int curr_iov_index_; + // Current iov that is being written into. + const struct iovec* curr_iov_; - // Bytes written to output_iov_[curr_iov_index_] so far. - size_t curr_iov_written_; + // Pointer to current iov's write location. + char* curr_iov_output_; + + // Remaining bytes to write into curr_iov_output. + size_t curr_iov_remaining_; // Total bytes decompressed into output_iov_ so far. size_t total_written_; @@ -1022,22 +1098,24 @@ class SnappyIOVecWriter { // Maximum number of bytes that will be decompressed into output_iov_. size_t output_limit_; - inline char* GetIOVecPointer(int index, size_t offset) { - return reinterpret_cast(output_iov_[index].iov_base) + - offset; + static inline char* GetIOVecPointer(const struct iovec* iov, size_t offset) { + return reinterpret_cast(iov->iov_base) + offset; } public: // Does not take ownership of iov. iov must be valid during the // entire lifetime of the SnappyIOVecWriter. inline SnappyIOVecWriter(const struct iovec* iov, size_t iov_count) - : output_iov_(iov), - output_iov_count_(iov_count), - curr_iov_index_(0), - curr_iov_written_(0), + : output_iov_end_(iov + iov_count), +#if !defined(NDEBUG) + output_iov_(iov), +#endif // !defined(NDEBUG) + curr_iov_(iov), + curr_iov_output_(iov_count ? reinterpret_cast(iov->iov_base) + : nullptr), + curr_iov_remaining_(iov_count ? iov->iov_len : 0), total_written_(0), - output_limit_(-1) { - } + output_limit_(-1) {} inline void SetExpectedLength(size_t len) { output_limit_ = len; @@ -1052,23 +1130,25 @@ class SnappyIOVecWriter { return false; } + return AppendNoCheck(ip, len); + } + + inline bool AppendNoCheck(const char* ip, size_t len) { while (len > 0) { - assert(curr_iov_written_ <= output_iov_[curr_iov_index_].iov_len); - if (curr_iov_written_ >= output_iov_[curr_iov_index_].iov_len) { + if (curr_iov_remaining_ == 0) { // This iovec is full. Go to the next one. - if (static_cast(curr_iov_index_) + 1 >= output_iov_count_) { + if (curr_iov_ + 1 >= output_iov_end_) { return false; } - curr_iov_written_ = 0; - ++curr_iov_index_; + ++curr_iov_; + curr_iov_output_ = reinterpret_cast(curr_iov_->iov_base); + curr_iov_remaining_ = curr_iov_->iov_len; } - const size_t to_write = std::min( - len, output_iov_[curr_iov_index_].iov_len - curr_iov_written_); - memcpy(GetIOVecPointer(curr_iov_index_, curr_iov_written_), - ip, - to_write); - curr_iov_written_ += to_write; + const size_t to_write = std::min(len, curr_iov_remaining_); + memcpy(curr_iov_output_, ip, to_write); + curr_iov_output_ += to_write; + curr_iov_remaining_ -= to_write; total_written_ += to_write; ip += to_write; len -= to_write; @@ -1080,12 +1160,11 @@ class SnappyIOVecWriter { inline bool TryFastAppend(const char* ip, size_t available, size_t len) { const size_t space_left = output_limit_ - total_written_; if (len <= 16 && available >= 16 + kMaximumTagLength && space_left >= 16 && - output_iov_[curr_iov_index_].iov_len - curr_iov_written_ >= 16) { + curr_iov_remaining_ >= 16) { // Fast path, used for the majority (about 95%) of invocations. - char* ptr = GetIOVecPointer(curr_iov_index_, curr_iov_written_); - UnalignedCopy64(ip, ptr); - UnalignedCopy64(ip + 8, ptr + 8); - curr_iov_written_ += len; + UnalignedCopy128(ip, curr_iov_output_); + curr_iov_output_ += len; + curr_iov_remaining_ -= len; total_written_ += len; return true; } @@ -1094,7 +1173,9 @@ class SnappyIOVecWriter { } inline bool AppendFromSelf(size_t offset, size_t len) { - if (offset > total_written_ || offset == 0) { + // See SnappyArrayWriter::AppendFromSelf for an explanation of + // the "offset - 1u" trick. + if (offset - 1u >= total_written_) { return false; } const size_t space_left = output_limit_ - total_written_; @@ -1103,8 +1184,8 @@ class SnappyIOVecWriter { } // Locate the iovec from which we need to start the copy. - int from_iov_index = curr_iov_index_; - size_t from_iov_offset = curr_iov_written_; + const iovec* from_iov = curr_iov_; + size_t from_iov_offset = curr_iov_->iov_len - curr_iov_remaining_; while (offset > 0) { if (from_iov_offset >= offset) { from_iov_offset -= offset; @@ -1112,46 +1193,47 @@ class SnappyIOVecWriter { } offset -= from_iov_offset; - --from_iov_index; - assert(from_iov_index >= 0); - from_iov_offset = output_iov_[from_iov_index].iov_len; + --from_iov; +#if !defined(NDEBUG) + assert(from_iov >= output_iov_); +#endif // !defined(NDEBUG) + from_iov_offset = from_iov->iov_len; } // Copy bytes starting from the iovec pointed to by from_iov_index to // the current iovec. while (len > 0) { - assert(from_iov_index <= curr_iov_index_); - if (from_iov_index != curr_iov_index_) { - const size_t to_copy = std::min( - output_iov_[from_iov_index].iov_len - from_iov_offset, - len); - Append(GetIOVecPointer(from_iov_index, from_iov_offset), to_copy); + assert(from_iov <= curr_iov_); + if (from_iov != curr_iov_) { + const size_t to_copy = + std::min(from_iov->iov_len - from_iov_offset, len); + AppendNoCheck(GetIOVecPointer(from_iov, from_iov_offset), to_copy); len -= to_copy; if (len > 0) { - ++from_iov_index; + ++from_iov; from_iov_offset = 0; } } else { - assert(curr_iov_written_ <= output_iov_[curr_iov_index_].iov_len); - size_t to_copy = std::min(output_iov_[curr_iov_index_].iov_len - - curr_iov_written_, - len); + size_t to_copy = curr_iov_remaining_; if (to_copy == 0) { // This iovec is full. Go to the next one. - if (static_cast(curr_iov_index_) + 1 >= output_iov_count_) { + if (curr_iov_ + 1 >= output_iov_end_) { return false; } - ++curr_iov_index_; - curr_iov_written_ = 0; + ++curr_iov_; + curr_iov_output_ = reinterpret_cast(curr_iov_->iov_base); + curr_iov_remaining_ = curr_iov_->iov_len; continue; } if (to_copy > len) { to_copy = len; } - IncrementalCopy(GetIOVecPointer(from_iov_index, from_iov_offset), - GetIOVecPointer(curr_iov_index_, curr_iov_written_), - to_copy); - curr_iov_written_ += to_copy; + + IncrementalCopy(GetIOVecPointer(from_iov, from_iov_offset), + curr_iov_output_, curr_iov_output_ + to_copy, + curr_iov_output_ + curr_iov_remaining_); + curr_iov_output_ += to_copy; + curr_iov_remaining_ -= to_copy; from_iov_offset += to_copy; total_written_ += to_copy; len -= to_copy; @@ -1161,20 +1243,21 @@ class SnappyIOVecWriter { return true; } + inline void Flush() {} }; -bool RawUncompressToIOVec(Source* compressed, const struct iovec* iov, - size_t iov_cnt) { - SnappyIOVecWriter output(iov, iov_cnt); - return InternalUncompress(compressed, &output); -} - bool RawUncompressToIOVec(const char* compressed, size_t compressed_length, const struct iovec* iov, size_t iov_cnt) { ByteArraySource reader(compressed, compressed_length); return RawUncompressToIOVec(&reader, iov, iov_cnt); } +bool RawUncompressToIOVec(Source* compressed, const struct iovec* iov, + size_t iov_cnt) { + SnappyIOVecWriter output(iov, iov_cnt); + return InternalUncompress(compressed, &output); +} + // ----------------------------------------------------------------------- // Flat array interfaces // ----------------------------------------------------------------------- @@ -1191,7 +1274,8 @@ class SnappyArrayWriter { public: inline explicit SnappyArrayWriter(char* dst) : base_(dst), - op_(dst) { + op_(dst), + op_limit_(dst) { } inline void SetExpectedLength(size_t len) { @@ -1218,8 +1302,7 @@ class SnappyArrayWriter { const size_t space_left = op_limit_ - op; if (len <= 16 && available >= 16 + kMaximumTagLength && space_left >= 16) { // Fast path, used for the majority (about 95%) of invocations. - UnalignedCopy64(ip, op); - UnalignedCopy64(ip + 8, op + 8); + UnalignedCopy128(ip, op); op_ = op + len; return true; } else { @@ -1228,8 +1311,7 @@ class SnappyArrayWriter { } inline bool AppendFromSelf(size_t offset, size_t len) { - char* op = op_; - const size_t space_left = op_limit_ - op; + char* const op_end = op_ + len; // Check if we try to append from before the start of the buffer. // Normally this would just be a check for "produced < offset", @@ -1238,29 +1320,16 @@ class SnappyArrayWriter { // to a very big number. This is convenient, as offset==0 is another // invalid case that we also want to catch, so that we do not go // into an infinite loop. - assert(op >= base_); - size_t produced = op - base_; - if (produced <= offset - 1u) { - return false; - } - if (len <= 16 && offset >= 8 && space_left >= 16) { - // Fast path, used for the majority (70-80%) of dynamic invocations. - UnalignedCopy64(op - offset, op); - UnalignedCopy64(op - offset + 8, op + 8); - } else { - if (space_left >= len + kMaxIncrementCopyOverflow) { - IncrementalCopyFastPath(op - offset, op, len); - } else { - if (space_left < len) { - return false; - } - IncrementalCopy(op - offset, op, len); - } - } + if (Produced() <= offset - 1u || op_end > op_limit_) return false; + op_ = IncrementalCopy(op_ - offset, op_, op_end, op_limit_); - op_ = op + len; return true; } + inline size_t Produced() const { + assert(op_ >= base_); + return op_ - base_; + } + inline void Flush() {} }; bool RawUncompress(const char* compressed, size_t n, char* uncompressed) { @@ -1273,7 +1342,7 @@ bool RawUncompress(Source* compressed, char* uncompressed) { return InternalUncompress(compressed, &output); } -bool Uncompress(const char* compressed, size_t n, string* uncompressed) { +bool Uncompress(const char* compressed, size_t n, std::string* uncompressed) { size_t ulength; if (!GetUncompressedLength(compressed, n, &ulength)) { return false; @@ -1287,7 +1356,6 @@ bool Uncompress(const char* compressed, size_t n, string* uncompressed) { return RawUncompress(compressed, n, string_as_array(uncompressed)); } - // A Writer that drops everything on the floor and just does validation class SnappyDecompressionValidator { private: @@ -1295,7 +1363,7 @@ class SnappyDecompressionValidator { size_t produced_; public: - inline SnappyDecompressionValidator() : produced_(0) { } + inline SnappyDecompressionValidator() : expected_(0), produced_(0) { } inline void SetExpectedLength(size_t len) { expected_ = len; } @@ -1316,6 +1384,7 @@ class SnappyDecompressionValidator { produced_ += len; return produced_ <= expected_; } + inline void Flush() {} }; bool IsValidCompressedBuffer(const char* compressed, size_t n) { @@ -1324,6 +1393,11 @@ bool IsValidCompressedBuffer(const char* compressed, size_t n) { return InternalUncompress(&reader, &writer); } +bool IsValidCompressed(Source* compressed) { + SnappyDecompressionValidator writer; + return InternalUncompress(compressed, &writer); +} + void RawCompress(const char* input, size_t input_length, char* compressed, @@ -1336,9 +1410,10 @@ void RawCompress(const char* input, *compressed_length = (writer.CurrentDestination() - compressed); } -size_t Compress(const char* input, size_t input_length, string* compressed) { +size_t Compress(const char* input, size_t input_length, + std::string* compressed) { // Pre-grow the buffer to the max length of the compressed output - compressed->resize(MaxCompressedLength(input_length)); + STLStringResizeUninitialized(compressed, MaxCompressedLength(input_length)); size_t compressed_length; RawCompress(input, input_length, string_as_array(compressed), @@ -1347,6 +1422,240 @@ size_t Compress(const char* input, size_t input_length, string* compressed) { return compressed_length; } +// ----------------------------------------------------------------------- +// Sink interface +// ----------------------------------------------------------------------- -} // end namespace snappy +// A type that decompresses into a Sink. The template parameter +// Allocator must export one method "char* Allocate(int size);", which +// allocates a buffer of "size" and appends that to the destination. +template +class SnappyScatteredWriter { + Allocator allocator_; + // We need random access into the data generated so far. Therefore + // we keep track of all of the generated data as an array of blocks. + // All of the blocks except the last have length kBlockSize. + std::vector blocks_; + size_t expected_; + + // Total size of all fully generated blocks so far + size_t full_size_; + + // Pointer into current output block + char* op_base_; // Base of output block + char* op_ptr_; // Pointer to next unfilled byte in block + char* op_limit_; // Pointer just past block + + inline size_t Size() const { + return full_size_ + (op_ptr_ - op_base_); + } + + bool SlowAppend(const char* ip, size_t len); + bool SlowAppendFromSelf(size_t offset, size_t len); + + public: + inline explicit SnappyScatteredWriter(const Allocator& allocator) + : allocator_(allocator), + full_size_(0), + op_base_(NULL), + op_ptr_(NULL), + op_limit_(NULL) { + } + + inline void SetExpectedLength(size_t len) { + assert(blocks_.empty()); + expected_ = len; + } + + inline bool CheckLength() const { + return Size() == expected_; + } + + // Return the number of bytes actually uncompressed so far + inline size_t Produced() const { + return Size(); + } + + inline bool Append(const char* ip, size_t len) { + size_t avail = op_limit_ - op_ptr_; + if (len <= avail) { + // Fast path + memcpy(op_ptr_, ip, len); + op_ptr_ += len; + return true; + } else { + return SlowAppend(ip, len); + } + } + + inline bool TryFastAppend(const char* ip, size_t available, size_t length) { + char* op = op_ptr_; + const int space_left = op_limit_ - op; + if (length <= 16 && available >= 16 + kMaximumTagLength && + space_left >= 16) { + // Fast path, used for the majority (about 95%) of invocations. + UnalignedCopy128(ip, op); + op_ptr_ = op + length; + return true; + } else { + return false; + } + } + + inline bool AppendFromSelf(size_t offset, size_t len) { + char* const op_end = op_ptr_ + len; + // See SnappyArrayWriter::AppendFromSelf for an explanation of + // the "offset - 1u" trick. + if (SNAPPY_PREDICT_TRUE(offset - 1u < op_ptr_ - op_base_ && + op_end <= op_limit_)) { + // Fast path: src and dst in current block. + op_ptr_ = IncrementalCopy(op_ptr_ - offset, op_ptr_, op_end, op_limit_); + return true; + } + return SlowAppendFromSelf(offset, len); + } + + // Called at the end of the decompress. We ask the allocator + // write all blocks to the sink. + inline void Flush() { allocator_.Flush(Produced()); } +}; + +template +bool SnappyScatteredWriter::SlowAppend(const char* ip, size_t len) { + size_t avail = op_limit_ - op_ptr_; + while (len > avail) { + // Completely fill this block + memcpy(op_ptr_, ip, avail); + op_ptr_ += avail; + assert(op_limit_ - op_ptr_ == 0); + full_size_ += (op_ptr_ - op_base_); + len -= avail; + ip += avail; + + // Bounds check + if (full_size_ + len > expected_) { + return false; + } + + // Make new block + size_t bsize = std::min(kBlockSize, expected_ - full_size_); + op_base_ = allocator_.Allocate(bsize); + op_ptr_ = op_base_; + op_limit_ = op_base_ + bsize; + blocks_.push_back(op_base_); + avail = bsize; + } + + memcpy(op_ptr_, ip, len); + op_ptr_ += len; + return true; +} + +template +bool SnappyScatteredWriter::SlowAppendFromSelf(size_t offset, + size_t len) { + // Overflow check + // See SnappyArrayWriter::AppendFromSelf for an explanation of + // the "offset - 1u" trick. + const size_t cur = Size(); + if (offset - 1u >= cur) return false; + if (expected_ - cur < len) return false; + + // Currently we shouldn't ever hit this path because Compress() chops the + // input into blocks and does not create cross-block copies. However, it is + // nice if we do not rely on that, since we can get better compression if we + // allow cross-block copies and thus might want to change the compressor in + // the future. + size_t src = cur - offset; + while (len-- > 0) { + char c = blocks_[src >> kBlockLog][src & (kBlockSize-1)]; + Append(&c, 1); + src++; + } + return true; +} + +class SnappySinkAllocator { + public: + explicit SnappySinkAllocator(Sink* dest): dest_(dest) {} + ~SnappySinkAllocator() {} + + char* Allocate(int size) { + Datablock block(new char[size], size); + blocks_.push_back(block); + return block.data; + } + + // We flush only at the end, because the writer wants + // random access to the blocks and once we hand the + // block over to the sink, we can't access it anymore. + // Also we don't write more than has been actually written + // to the blocks. + void Flush(size_t size) { + size_t size_written = 0; + size_t block_size; + for (int i = 0; i < blocks_.size(); ++i) { + block_size = std::min(blocks_[i].size, size - size_written); + dest_->AppendAndTakeOwnership(blocks_[i].data, block_size, + &SnappySinkAllocator::Deleter, NULL); + size_written += block_size; + } + blocks_.clear(); + } + + private: + struct Datablock { + char* data; + size_t size; + Datablock(char* p, size_t s) : data(p), size(s) {} + }; + + static void Deleter(void* arg, const char* bytes, size_t size) { + delete[] bytes; + } + + Sink* dest_; + std::vector blocks_; + + // Note: copying this object is allowed +}; + +size_t UncompressAsMuchAsPossible(Source* compressed, Sink* uncompressed) { + SnappySinkAllocator allocator(uncompressed); + SnappyScatteredWriter writer(allocator); + InternalUncompress(compressed, &writer); + return writer.Produced(); +} + +bool Uncompress(Source* compressed, Sink* uncompressed) { + // Read the uncompressed length from the front of the compressed input + SnappyDecompressor decompressor(compressed); + uint32 uncompressed_len = 0; + if (!decompressor.ReadUncompressedLength(&uncompressed_len)) { + return false; + } + + char c; + size_t allocated_size; + char* buf = uncompressed->GetAppendBufferVariable( + 1, uncompressed_len, &c, 1, &allocated_size); + + const size_t compressed_len = compressed->Available(); + // If we can get a flat buffer, then use it, otherwise do block by block + // uncompression + if (allocated_size >= uncompressed_len) { + SnappyArrayWriter writer(buf); + bool result = InternalUncompressAllTags(&decompressor, &writer, + compressed_len, uncompressed_len); + uncompressed->Append(buf, writer.Produced()); + return result; + } else { + SnappySinkAllocator allocator(uncompressed); + SnappyScatteredWriter writer(allocator); + return InternalUncompressAllTags(&decompressor, &writer, compressed_len, + uncompressed_len); + } +} + +} // namespace snappy diff --git a/ext/snappy/snappy.h b/ext/snappy/snappy.h index d15ffbf0a8..e9805bfb7d 100644 --- a/ext/snappy/snappy.h +++ b/ext/snappy/snappy.h @@ -36,10 +36,10 @@ // using BMDiff and then compressing the output of BMDiff with // Snappy. -#ifndef UTIL_SNAPPY_SNAPPY_H__ -#define UTIL_SNAPPY_SNAPPY_H__ +#ifndef THIRD_PARTY_SNAPPY_SNAPPY_H__ +#define THIRD_PARTY_SNAPPY_SNAPPY_H__ -#include +#include #include #include "snappy-stubs-public.h" @@ -69,11 +69,12 @@ namespace snappy { // Higher-level string based routines (should be sufficient for most users) // ------------------------------------------------------------------------ - // Sets "*output" to the compressed version of "input[0,input_length-1]". - // Original contents of *output are lost. + // Sets "*compressed" to the compressed version of "input[0,input_length-1]". + // Original contents of *compressed are lost. // - // REQUIRES: "input[]" is not an alias of "*output". - size_t Compress(const char* input, size_t input_length, string* output); + // REQUIRES: "input[]" is not an alias of "*compressed". + size_t Compress(const char* input, size_t input_length, + std::string* compressed); // Decompresses "compressed[0,compressed_length-1]" to "*uncompressed". // Original contents of "*uncompressed" are lost. @@ -82,8 +83,20 @@ namespace snappy { // // returns false if the message is corrupted and could not be decompressed bool Uncompress(const char* compressed, size_t compressed_length, - string* uncompressed); + std::string* uncompressed); + // Decompresses "compressed" to "*uncompressed". + // + // returns false if the message is corrupted and could not be decompressed + bool Uncompress(Source* compressed, Sink* uncompressed); + + // This routine uncompresses as much of the "compressed" as possible + // into sink. It returns the number of valid bytes added to sink + // (extra invalid bytes may have been added due to errors; the caller + // should ignore those). The emitted data typically has length + // GetUncompressedLength(), but may be shorter if an error is + // encountered. + size_t UncompressAsMuchAsPossible(Source* compressed, Sink* uncompressed); // ------------------------------------------------------------------------ // Lower-level character array based routines. May be useful for @@ -124,6 +137,28 @@ namespace snappy { // returns false if the message is corrupted and could not be decrypted bool RawUncompress(Source* compressed, char* uncompressed); + // Given data in "compressed[0..compressed_length-1]" generated by + // calling the Snappy::Compress routine, this routine + // stores the uncompressed data to the iovec "iov". The number of physical + // buffers in "iov" is given by iov_cnt and their cumulative size + // must be at least GetUncompressedLength(compressed). The individual buffers + // in "iov" must not overlap with each other. + // + // returns false if the message is corrupted and could not be decrypted + bool RawUncompressToIOVec(const char* compressed, size_t compressed_length, + const struct iovec* iov, size_t iov_cnt); + + // Given data from the byte source 'compressed' generated by calling + // the Snappy::Compress routine, this routine stores the uncompressed + // data to the iovec "iov". The number of physical + // buffers in "iov" is given by iov_cnt and their cumulative size + // must be at least GetUncompressedLength(compressed). The individual buffers + // in "iov" must not overlap with each other. + // + // returns false if the message is corrupted and could not be decrypted + bool RawUncompressToIOVec(Source* compressed, const struct iovec* iov, + size_t iov_cnt); + // Returns the maximal size of the compressed representation of // input data that is "source_bytes" bytes in length; size_t MaxCompressedLength(size_t source_bytes); @@ -142,21 +177,31 @@ namespace snappy { bool IsValidCompressedBuffer(const char* compressed, size_t compressed_length); - // *** DO NOT CHANGE THE VALUE OF kBlockSize *** + // Returns true iff the contents of "compressed" can be uncompressed + // successfully. Does not return the uncompressed data. Takes + // time proportional to *compressed length, but is usually at least + // a factor of four faster than actual decompression. + // On success, consumes all of *compressed. On failure, consumes an + // unspecified prefix of *compressed. + bool IsValidCompressed(Source* compressed); + + // The size of a compression block. Note that many parts of the compression + // code assumes that kBlockSize <= 65536; in particular, the hash table + // can only store 16-bit offsets, and EmitCopy() also assumes the offset + // is 65535 bytes or less. Note also that if you change this, it will + // affect the framing format (see framing_format.txt). // - // New Compression code chops up the input into blocks of at most - // the following size. This ensures that back-references in the - // output never cross kBlockSize block boundaries. This can be - // helpful in implementing blocked decompression. However the - // decompression code should not rely on this guarantee since older - // compression code may not obey it. - static const int kBlockLog = 15; - static const size_t kBlockSize = 1 << kBlockLog; + // Note that there might be older data around that is compressed with larger + // block sizes, so the decompression code should not rely on the + // non-existence of long backreferences. + static constexpr int kBlockLog = 16; + static constexpr size_t kBlockSize = 1 << kBlockLog; - static const int kMaxHashTableBits = 14; - static const size_t kMaxHashTableSize = 1 << kMaxHashTableBits; + static constexpr int kMinHashTableBits = 8; + static constexpr size_t kMinHashTableSize = 1 << kMinHashTableBits; + static constexpr int kMaxHashTableBits = 14; + static constexpr size_t kMaxHashTableSize = 1 << kMaxHashTableBits; } // end namespace snappy - -#endif // UTIL_SNAPPY_SNAPPY_H__ +#endif // THIRD_PARTY_SNAPPY_SNAPPY_H__ diff --git a/ext/vulkan/vk_platform.h b/ext/vulkan/vk_platform.h index 7289299240..dbb011285c 100644 --- a/ext/vulkan/vk_platform.h +++ b/ext/vulkan/vk_platform.h @@ -2,7 +2,7 @@ // File: vk_platform.h // /* -** Copyright (c) 2014-2017 The Khronos Group Inc. +** Copyright (c) 2014-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan.h b/ext/vulkan/vulkan.h index 5f853f9fc8..20ecd1016e 100644 --- a/ext/vulkan/vulkan.h +++ b/ext/vulkan/vulkan.h @@ -2,7 +2,7 @@ #define VULKAN_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -83,4 +83,9 @@ #include "vulkan_ggp.h" #endif + +#ifdef VK_ENABLE_BETA_EXTENSIONS +#include "vulkan_beta.h" +#endif + #endif // VULKAN_H_ diff --git a/ext/vulkan/vulkan_android.h b/ext/vulkan/vulkan_android.h index 9b8d3e276f..4f27750cd8 100644 --- a/ext/vulkan/vulkan_android.h +++ b/ext/vulkan/vulkan_android.h @@ -2,7 +2,7 @@ #define VULKAN_ANDROID_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_beta.h b/ext/vulkan/vulkan_beta.h new file mode 100644 index 0000000000..7380e39fe1 --- /dev/null +++ b/ext/vulkan/vulkan_beta.h @@ -0,0 +1,438 @@ +#ifndef VULKAN_BETA_H_ +#define VULKAN_BETA_H_ 1 + +/* +** Copyright (c) 2015-2020 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define VK_KHR_deferred_host_operations 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 2 +#define VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME "VK_KHR_deferred_host_operations" +typedef struct VkDeferredOperationInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeferredOperationKHR operationHandle; +} VkDeferredOperationInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDeferredOperationKHR)(VkDevice device, const VkAllocationCallbacks* pAllocator, VkDeferredOperationKHR* pDeferredOperation); +typedef void (VKAPI_PTR *PFN_vkDestroyDeferredOperationKHR)(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks* pAllocator); +typedef uint32_t (VKAPI_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeferredOperationResultKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkDeferredOperationJoinKHR)(VkDevice device, VkDeferredOperationKHR operation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDeferredOperationKHR( + VkDevice device, + const VkAllocationCallbacks* pAllocator, + VkDeferredOperationKHR* pDeferredOperation); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDeferredOperationKHR( + VkDevice device, + VkDeferredOperationKHR operation, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR uint32_t VKAPI_CALL vkGetDeferredOperationMaxConcurrencyKHR( + VkDevice device, + VkDeferredOperationKHR operation); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeferredOperationResultKHR( + VkDevice device, + VkDeferredOperationKHR operation); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeferredOperationJoinKHR( + VkDevice device, + VkDeferredOperationKHR operation); +#endif + + +#define VK_KHR_pipeline_library 1 +#define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME "VK_KHR_pipeline_library" +typedef struct VkPipelineLibraryCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t libraryCount; + const VkPipeline* pLibraries; +} VkPipelineLibraryCreateInfoKHR; + + + +#define VK_KHR_ray_tracing 1 +#define VK_KHR_RAY_TRACING_SPEC_VERSION 8 +#define VK_KHR_RAY_TRACING_EXTENSION_NAME "VK_KHR_ray_tracing" + +typedef enum VkAccelerationStructureBuildTypeKHR { + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR = 0, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR = 1, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureBuildTypeKHR; +typedef union VkDeviceOrHostAddressKHR { + VkDeviceAddress deviceAddress; + void* hostAddress; +} VkDeviceOrHostAddressKHR; + +typedef union VkDeviceOrHostAddressConstKHR { + VkDeviceAddress deviceAddress; + const void* hostAddress; +} VkDeviceOrHostAddressConstKHR; + +typedef struct VkAccelerationStructureBuildOffsetInfoKHR { + uint32_t primitiveCount; + uint32_t primitiveOffset; + uint32_t firstVertex; + uint32_t transformOffset; +} VkAccelerationStructureBuildOffsetInfoKHR; + +typedef struct VkRayTracingShaderGroupCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; + const void* pShaderGroupCaptureReplayHandle; +} VkRayTracingShaderGroupCreateInfoKHR; + +typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxPayloadSize; + uint32_t maxAttributeSize; + uint32_t maxCallableSize; +} VkRayTracingPipelineInterfaceCreateInfoKHR; + +typedef struct VkRayTracingPipelineCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoKHR* pGroups; + uint32_t maxRecursionDepth; + VkPipelineLibraryCreateInfoKHR libraries; + const VkRayTracingPipelineInterfaceCreateInfoKHR* pLibraryInterface; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoKHR; + +typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { + VkStructureType sType; + const void* pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceOrHostAddressConstKHR transformData; +} VkAccelerationStructureGeometryTrianglesDataKHR; + +typedef struct VkAccelerationStructureGeometryAabbsDataKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR data; + VkDeviceSize stride; +} VkAccelerationStructureGeometryAabbsDataKHR; + +typedef struct VkAccelerationStructureGeometryInstancesDataKHR { + VkStructureType sType; + const void* pNext; + VkBool32 arrayOfPointers; + VkDeviceOrHostAddressConstKHR data; +} VkAccelerationStructureGeometryInstancesDataKHR; + +typedef union VkAccelerationStructureGeometryDataKHR { + VkAccelerationStructureGeometryTrianglesDataKHR triangles; + VkAccelerationStructureGeometryAabbsDataKHR aabbs; + VkAccelerationStructureGeometryInstancesDataKHR instances; +} VkAccelerationStructureGeometryDataKHR; + +typedef struct VkAccelerationStructureGeometryKHR { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkAccelerationStructureGeometryDataKHR geometry; + VkGeometryFlagsKHR flags; +} VkAccelerationStructureGeometryKHR; + +typedef struct VkAccelerationStructureBuildGeometryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeKHR type; + VkBuildAccelerationStructureFlagsKHR flags; + VkBool32 update; + VkAccelerationStructureKHR srcAccelerationStructure; + VkAccelerationStructureKHR dstAccelerationStructure; + VkBool32 geometryArrayOfPointers; + uint32_t geometryCount; + const VkAccelerationStructureGeometryKHR* const* ppGeometries; + VkDeviceOrHostAddressKHR scratchData; +} VkAccelerationStructureBuildGeometryInfoKHR; + +typedef struct VkAccelerationStructureCreateGeometryTypeInfoKHR { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + uint32_t maxPrimitiveCount; + VkIndexType indexType; + uint32_t maxVertexCount; + VkFormat vertexFormat; + VkBool32 allowsTransforms; +} VkAccelerationStructureCreateGeometryTypeInfoKHR; + +typedef struct VkAccelerationStructureCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureTypeKHR type; + VkBuildAccelerationStructureFlagsKHR flags; + uint32_t maxGeometryCount; + const VkAccelerationStructureCreateGeometryTypeInfoKHR* pGeometryInfos; + VkDeviceAddress deviceAddress; +} VkAccelerationStructureCreateInfoKHR; + +typedef struct VkAccelerationStructureMemoryRequirementsInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureMemoryRequirementsTypeKHR type; + VkAccelerationStructureBuildTypeKHR buildType; + VkAccelerationStructureKHR accelerationStructure; +} VkAccelerationStructureMemoryRequirementsInfoKHR; + +typedef struct VkPhysicalDeviceRayTracingFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracing; + VkBool32 rayTracingShaderGroupHandleCaptureReplay; + VkBool32 rayTracingShaderGroupHandleCaptureReplayMixed; + VkBool32 rayTracingAccelerationStructureCaptureReplay; + VkBool32 rayTracingIndirectTraceRays; + VkBool32 rayTracingIndirectAccelerationStructureBuild; + VkBool32 rayTracingHostAccelerationStructureCommands; + VkBool32 rayQuery; + VkBool32 rayTracingPrimitiveCulling; +} VkPhysicalDeviceRayTracingFeaturesKHR; + +typedef struct VkPhysicalDeviceRayTracingPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxPrimitiveCount; + uint32_t maxDescriptorSetAccelerationStructures; + uint32_t shaderGroupHandleCaptureReplaySize; +} VkPhysicalDeviceRayTracingPropertiesKHR; + +typedef struct VkAccelerationStructureDeviceAddressInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR accelerationStructure; +} VkAccelerationStructureDeviceAddressInfoKHR; + +typedef struct VkAccelerationStructureVersionKHR { + VkStructureType sType; + const void* pNext; + const uint8_t* versionData; +} VkAccelerationStructureVersionKHR; + +typedef struct VkStridedBufferRegionKHR { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize stride; + VkDeviceSize size; +} VkStridedBufferRegionKHR; + +typedef struct VkTraceRaysIndirectCommandKHR { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommandKHR; + +typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkDeviceOrHostAddressKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureToMemoryInfoKHR; + +typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyMemoryToAccelerationStructureInfoKHR; + +typedef struct VkCopyAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureKHR)(VkDevice device, const VkAccelerationStructureCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureKHR* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsKHR)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoKHR* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureIndirectKHR)(VkCommandBuffer commandBuffer, const VkAccelerationStructureBuildGeometryInfoKHR* pInfo, VkBuffer indirectBuffer, VkDeviceSize indirectOffset, uint32_t indirectStride); +typedef VkResult (VKAPI_PTR *PFN_vkBuildAccelerationStructureKHR)(VkDevice device, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, size_t dataSize, void* pData, size_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedBufferRegionKHR* pRaygenShaderBindingTable, const VkStridedBufferRegionKHR* pMissShaderBindingTable, const VkStridedBufferRegionKHR* pHitShaderBindingTable, const VkStridedBufferRegionKHR* pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedBufferRegionKHR* pRaygenShaderBindingTable, const VkStridedBufferRegionKHR* pMissShaderBindingTable, const VkStridedBufferRegionKHR* pHitShaderBindingTable, const VkStridedBufferRegionKHR* pCallableShaderBindingTable, VkBuffer buffer, VkDeviceSize offset); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionKHR* version); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureKHR( + VkDevice device, + const VkAccelerationStructureCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureKHR* pAccelerationStructure); + +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsKHR( + VkDevice device, + const VkAccelerationStructureMemoryRequirementsInfoKHR* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureIndirectKHR( + VkCommandBuffer commandBuffer, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfo, + VkBuffer indirectBuffer, + VkDeviceSize indirectOffset, + uint32_t indirectStride); + +VKAPI_ATTR VkResult VKAPI_CALL vkBuildAccelerationStructureKHR( + VkDevice device, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureKHR( + VkDevice device, + const VkCopyAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureToMemoryKHR( + VkDevice device, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToAccelerationStructureKHR( + VkDevice device, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkWriteAccelerationStructuresPropertiesKHR( + VkDevice device, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + size_t dataSize, + void* pData, + size_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureToMemoryKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysKHR( + VkCommandBuffer commandBuffer, + const VkStridedBufferRegionKHR* pRaygenShaderBindingTable, + const VkStridedBufferRegionKHR* pMissShaderBindingTable, + const VkStridedBufferRegionKHR* pHitShaderBindingTable, + const VkStridedBufferRegionKHR* pCallableShaderBindingTable, + uint32_t width, + uint32_t height, + uint32_t depth); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesKHR( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetAccelerationStructureDeviceAddressKHR( + VkDevice device, + const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysIndirectKHR( + VkCommandBuffer commandBuffer, + const VkStridedBufferRegionKHR* pRaygenShaderBindingTable, + const VkStridedBufferRegionKHR* pMissShaderBindingTable, + const VkStridedBufferRegionKHR* pHitShaderBindingTable, + const VkStridedBufferRegionKHR* pCallableShaderBindingTable, + VkBuffer buffer, + VkDeviceSize offset); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceAccelerationStructureCompatibilityKHR( + VkDevice device, + const VkAccelerationStructureVersionKHR* version); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/vulkan/vulkan_core.h b/ext/vulkan/vulkan_core.h index 01da6ede32..db2e5561ba 100644 --- a/ext/vulkan/vulkan_core.h +++ b/ext/vulkan/vulkan_core.h @@ -2,7 +2,7 @@ #define VULKAN_CORE_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -44,7 +44,10 @@ extern "C" { #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) // Version of this file -#define VK_HEADER_VERSION 123 +#define VK_HEADER_VERSION 141 + +// Complete version of this file +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_VERSION(1, 2, VK_HEADER_VERSION) #define VK_NULL_HANDLE 0 @@ -108,9 +111,6 @@ VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) typedef enum VkPipelineCacheHeaderVersion { VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, - VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1), VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF } VkPipelineCacheHeaderVersion; @@ -133,8 +133,11 @@ typedef enum VkResult { VK_ERROR_TOO_MANY_OBJECTS = -10, VK_ERROR_FORMAT_NOT_SUPPORTED = -11, VK_ERROR_FRAGMENTED_POOL = -12, + VK_ERROR_UNKNOWN = -13, VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, + VK_ERROR_FRAGMENTATION = -1000161000, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, VK_ERROR_SURFACE_LOST_KHR = -1000000000, VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, VK_SUBOPTIMAL_KHR = 1000001003, @@ -142,16 +145,21 @@ typedef enum VkResult { VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_ERROR_INCOMPATIBLE_VERSION_KHR = -1000150000, VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, - VK_ERROR_FRAGMENTATION_EXT = -1000161000, VK_ERROR_NOT_PERMITTED_EXT = -1000174001, - VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = -1000244000, VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, + VK_THREAD_IDLE_KHR = 1000268000, + VK_THREAD_DONE_KHR = 1000268001, + VK_OPERATION_DEFERRED_KHR = 1000268002, + VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, + VK_PIPELINE_COMPILE_REQUIRED_EXT = 1000297000, VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, - VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL, - VK_RESULT_END_RANGE = VK_INCOMPLETE, - VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1), + VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, + VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED_EXT, VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; @@ -270,6 +278,56 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2 = 1000109000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2 = 1000109001, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2 = 1000109002, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2 = 1000109003, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2 = 1000109004, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO = 1000109005, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO = 1000109006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO = 1000207002, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO = 1000207004, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO = 1000207005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO = 1000244001, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, @@ -298,6 +356,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, @@ -329,14 +388,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = 1000082000, VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, - VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, - VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, - VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002, - VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000, VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, @@ -353,23 +405,19 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = 1000108000, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = 1000108001, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = 1000108002, - VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = 1000108003, - VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = 1000109000, - VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = 1000109001, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = 1000109002, - VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = 1000109003, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = 1000109004, - VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = 1000109005, - VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = 1000109006, VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR = 1000116000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR = 1000116001, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR = 1000116002, + VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR = 1000116003, + VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR = 1000116005, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, @@ -391,8 +439,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000, - VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, @@ -402,11 +448,30 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000165007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR = 1000150001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR = 1000150008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_KHR = 1000150009, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR = 1000150013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, @@ -418,11 +483,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = 1000161001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = 1000161002, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = 1000161003, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = 1000161004, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, @@ -432,8 +492,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, @@ -443,12 +501,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = 1000175000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = 1000177000, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, @@ -458,10 +514,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000192000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = 1000197000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = 1000199000, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = 1000199001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, @@ -472,13 +524,12 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL = 1000209000, - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = 1000210000, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL = 1000210000, VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL = 1000210002, VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, @@ -487,7 +538,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = 1000225000, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = 1000225001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = 1000225002, @@ -499,9 +549,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR = 1000239000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, - VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = 1000244001, VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, - VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = 1000245000, VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, @@ -511,7 +560,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = 1000253000, VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, @@ -519,8 +567,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = 1000261000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, + VK_STRUCTURE_TYPE_DEFERRED_OPERATION_INFO_KHR = 1000268000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, @@ -528,8 +576,30 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, + VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV = 1000277003, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV = 1000277004, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV = 1000277005, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, + VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, + VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, + VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = 1000295000, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = 1000295001, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = 1000295002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = 1000297000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, + VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, @@ -565,10 +635,22 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, @@ -576,15 +658,18 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, @@ -593,12 +678,44 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, - VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, - VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, - VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; @@ -608,17 +725,11 @@ typedef enum VkSystemAllocationScope { VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, - VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, - VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, - VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1), VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF } VkSystemAllocationScope; typedef enum VkInternalAllocationType { VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, - VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1), VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF } VkInternalAllocationType; @@ -898,9 +1009,6 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, - VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, - VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, - VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), VK_FORMAT_MAX_ENUM = 0x7FFFFFFF } VkFormat; @@ -908,9 +1016,6 @@ typedef enum VkImageType { VK_IMAGE_TYPE_1D = 0, VK_IMAGE_TYPE_2D = 1, VK_IMAGE_TYPE_3D = 2, - VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D, - VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D, - VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1), VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageType; @@ -918,9 +1023,6 @@ typedef enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0, VK_IMAGE_TILING_LINEAR = 1, VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, - VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, - VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF } VkImageTiling; @@ -930,9 +1032,6 @@ typedef enum VkPhysicalDeviceType { VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, VK_PHYSICAL_DEVICE_TYPE_CPU = 4, - VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER, - VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU, - VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1), VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkPhysicalDeviceType; @@ -941,20 +1040,17 @@ typedef enum VkQueryType { VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, VK_QUERY_TYPE_TIMESTAMP = 2, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, + VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR = 1000116000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000165000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150000, VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, - VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, - VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, - VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF } VkQueryType; typedef enum VkSharingMode { VK_SHARING_MODE_EXCLUSIVE = 0, VK_SHARING_MODE_CONCURRENT = 1, - VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE, - VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT, - VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1), VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF } VkSharingMode; @@ -970,15 +1066,20 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_PREINITIALIZED = 8, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL = 1000241000, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, - VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF } VkImageLayout; @@ -990,9 +1091,6 @@ typedef enum VkImageViewType { VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, - VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D, - VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, - VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1), VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageViewType; @@ -1004,18 +1102,12 @@ typedef enum VkComponentSwizzle { VK_COMPONENT_SWIZZLE_G = 4, VK_COMPONENT_SWIZZLE_B = 5, VK_COMPONENT_SWIZZLE_A = 6, - VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A, - VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1), VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF } VkComponentSwizzle; typedef enum VkVertexInputRate { VK_VERTEX_INPUT_RATE_VERTEX = 0, VK_VERTEX_INPUT_RATE_INSTANCE = 1, - VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX, - VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE, - VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1), VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF } VkVertexInputRate; @@ -1031,9 +1123,6 @@ typedef enum VkPrimitiveTopology { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, - VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, - VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1), VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF } VkPrimitiveTopology; @@ -1042,18 +1131,12 @@ typedef enum VkPolygonMode { VK_POLYGON_MODE_LINE = 1, VK_POLYGON_MODE_POINT = 2, VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, - VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL, - VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT, - VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1), VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF } VkPolygonMode; typedef enum VkFrontFace { VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, VK_FRONT_FACE_CLOCKWISE = 1, - VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE, - VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE, - VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1), VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF } VkFrontFace; @@ -1066,9 +1149,6 @@ typedef enum VkCompareOp { VK_COMPARE_OP_NOT_EQUAL = 5, VK_COMPARE_OP_GREATER_OR_EQUAL = 6, VK_COMPARE_OP_ALWAYS = 7, - VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER, - VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS, - VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1), VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF } VkCompareOp; @@ -1081,9 +1161,6 @@ typedef enum VkStencilOp { VK_STENCIL_OP_INVERT = 5, VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, - VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP, - VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP, - VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1), VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF } VkStencilOp; @@ -1104,9 +1181,6 @@ typedef enum VkLogicOp { VK_LOGIC_OP_OR_INVERTED = 13, VK_LOGIC_OP_NAND = 14, VK_LOGIC_OP_SET = 15, - VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR, - VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET, - VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1), VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF } VkLogicOp; @@ -1130,9 +1204,6 @@ typedef enum VkBlendFactor { VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, VK_BLEND_FACTOR_SRC1_ALPHA = 17, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, - VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, - VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1), VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF } VkBlendFactor; @@ -1188,9 +1259,6 @@ typedef enum VkBlendOp { VK_BLEND_OP_RED_EXT = 1000148043, VK_BLEND_OP_GREEN_EXT = 1000148044, VK_BLEND_OP_BLUE_EXT = 1000148045, - VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD, - VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX, - VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1), VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF } VkBlendOp; @@ -1211,9 +1279,6 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, - VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF } VkDynamicState; @@ -1222,18 +1287,12 @@ typedef enum VkFilter { VK_FILTER_LINEAR = 1, VK_FILTER_CUBIC_IMG = 1000015000, VK_FILTER_CUBIC_EXT = VK_FILTER_CUBIC_IMG, - VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, - VK_FILTER_END_RANGE = VK_FILTER_LINEAR, - VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), VK_FILTER_MAX_ENUM = 0x7FFFFFFF } VkFilter; typedef enum VkSamplerMipmapMode { VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, - VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST, - VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR, - VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1), VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerMipmapMode; @@ -1244,9 +1303,6 @@ typedef enum VkSamplerAddressMode { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, - VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, - VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerAddressMode; @@ -1257,9 +1313,8 @@ typedef enum VkBorderColor { VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, - VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, - VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE, - VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1), + VK_BORDER_COLOR_FLOAT_CUSTOM_EXT = 1000287003, + VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004, VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF } VkBorderColor; @@ -1276,10 +1331,8 @@ typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, - VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, - VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000165000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorType; @@ -1287,57 +1340,42 @@ typedef enum VkAttachmentLoadOp { VK_ATTACHMENT_LOAD_OP_LOAD = 0, VK_ATTACHMENT_LOAD_OP_CLEAR = 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, - VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1), VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentLoadOp; typedef enum VkAttachmentStoreOp { VK_ATTACHMENT_STORE_OP_STORE = 0, VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1), + VK_ATTACHMENT_STORE_OP_NONE_QCOM = 1000301000, VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentStoreOp; typedef enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0, VK_PIPELINE_BIND_POINT_COMPUTE = 1, - VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000, - VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, - VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, - VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), + VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR = 1000165000, + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF } VkPipelineBindPoint; typedef enum VkCommandBufferLevel { VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, - VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY, - VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1), VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferLevel; typedef enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0, VK_INDEX_TYPE_UINT32 = 1, - VK_INDEX_TYPE_NONE_NV = 1000165000, + VK_INDEX_TYPE_NONE_KHR = 1000165000, VK_INDEX_TYPE_UINT8_EXT = 1000265000, - VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, - VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, - VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), + VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF } VkIndexType; typedef enum VkSubpassContents { VK_SUBPASS_CONTENTS_INLINE = 0, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, - VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE, - VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, - VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1), VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF } VkSubpassContents; @@ -1375,17 +1413,16 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, - VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000, - VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001, VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000165000, VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, + VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, + VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = 1000295000, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, - VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN, - VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL, - VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1), + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR, VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } VkObjectType; @@ -1393,9 +1430,8 @@ typedef enum VkVendorId { VK_VENDOR_ID_VIV = 0x10001, VK_VENDOR_ID_VSI = 0x10002, VK_VENDOR_ID_KAZAN = 0x10003, - VK_VENDOR_ID_BEGIN_RANGE = VK_VENDOR_ID_VIV, - VK_VENDOR_ID_END_RANGE = VK_VENDOR_ID_KAZAN, - VK_VENDOR_ID_RANGE_SIZE = (VK_VENDOR_ID_KAZAN - VK_VENDOR_ID_VIV + 1), + VK_VENDOR_ID_CODEPLAY = 0x10004, + VK_VENDOR_ID_MESA = 0x10005, VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF } VkVendorId; typedef VkFlags VkInstanceCreateFlags; @@ -1423,11 +1459,13 @@ typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000, + VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000, VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT, VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, @@ -1551,13 +1589,15 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, - VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 0x00200000, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000, VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000, - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000, VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 0x00020000, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; typedef VkFlags VkPipelineStageFlags; @@ -1635,7 +1675,9 @@ typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, - VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 0x00000010, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000010, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferCreateFlagBits; typedef VkFlags VkBufferCreateFlags; @@ -1650,11 +1692,14 @@ typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT = 0x00020000, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, - VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = 0x00020000, + VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR = 0x00000400, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferUsageFlagBits; typedef VkFlags VkBufferUsageFlags; @@ -1670,6 +1715,11 @@ typedef enum VkShaderModuleCreateFlagBits { VK_SHADER_MODULE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkShaderModuleCreateFlagBits; typedef VkFlags VkShaderModuleCreateFlags; + +typedef enum VkPipelineCacheCreateFlagBits { + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = 0x00000001, + VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheCreateFlagBits; typedef VkFlags VkPipelineCacheCreateFlags; typedef enum VkPipelineCreateFlagBits { @@ -1677,10 +1727,21 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, + VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 0x00000010, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 0x00020000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 0x00001000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR = 0x00002000, VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR = 0x00000040, VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080, + VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00040000, + VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 0x00000800, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = 0x00000100, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = 0x00000200, + VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -1703,14 +1764,20 @@ typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, VK_SHADER_STAGE_ALL = 0x7FFFFFFF, - VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100, - VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400, - VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800, - VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000, - VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000, + VK_SHADER_STAGE_RAYGEN_BIT_KHR = 0x00000100, + VK_SHADER_STAGE_ANY_HIT_BIT_KHR = 0x00000200, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR = 0x00000400, + VK_SHADER_STAGE_MISS_BIT_KHR = 0x00000800, + VK_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000, + VK_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000, VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040, VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080, + VK_SHADER_STAGE_RAYGEN_BIT_NV = VK_SHADER_STAGE_RAYGEN_BIT_KHR, + VK_SHADER_STAGE_ANY_HIT_BIT_NV = VK_SHADER_STAGE_ANY_HIT_BIT_KHR, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, + VK_SHADER_STAGE_MISS_BIT_NV = VK_SHADER_STAGE_MISS_BIT_KHR, + VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR, + VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR, VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkShaderStageFlagBits; typedef VkFlags VkPipelineVertexInputStateCreateFlags; @@ -1751,27 +1818,31 @@ typedef enum VkSamplerCreateFlagBits { typedef VkFlags VkSamplerCreateFlags; typedef enum VkDescriptorSetLayoutCreateFlagBits { + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 0x00000002, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = 0x00000002, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorSetLayoutCreateFlagBits; typedef VkFlags VkDescriptorSetLayoutCreateFlags; typedef enum VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = 0x00000002, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorPoolCreateFlagBits; typedef VkFlags VkDescriptorPoolCreateFlags; typedef VkFlags VkDescriptorPoolResetFlags; typedef enum VkFramebufferCreateFlagBits { - VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = 0x00000001, + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 0x00000001, + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFramebufferCreateFlagBits; typedef VkFlags VkFramebufferCreateFlags; typedef enum VkRenderPassCreateFlagBits { + VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 0x00000002, VK_RENDER_PASS_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkRenderPassCreateFlagBits; typedef VkFlags VkRenderPassCreateFlags; @@ -1785,6 +1856,8 @@ typedef VkFlags VkAttachmentDescriptionFlags; typedef enum VkSubpassDescriptionFlagBits { VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001, VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, + VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 0x00000004, + VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 0x00000008, VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubpassDescriptionFlagBits; typedef VkFlags VkSubpassDescriptionFlags; @@ -1811,13 +1884,15 @@ typedef enum VkAccessFlagBits { VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, - VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, - VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000, VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000, - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000, - VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000, VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, + VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000, + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; typedef VkFlags VkAccessFlags; @@ -3942,9 +4017,6 @@ typedef enum VkPointClippingBehavior { VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, - VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_END_RANGE = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, - VK_POINT_CLIPPING_BEHAVIOR_RANGE_SIZE = (VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES + 1), VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF } VkPointClippingBehavior; @@ -3953,9 +4025,6 @@ typedef enum VkTessellationDomainOrigin { VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_BEGIN_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_END_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_RANGE_SIZE = (VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT + 1), VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF } VkTessellationDomainOrigin; @@ -3970,9 +4039,6 @@ typedef enum VkSamplerYcbcrModelConversion { VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_BEGIN_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_END_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RANGE_SIZE = (VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY + 1), VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF } VkSamplerYcbcrModelConversion; @@ -3981,9 +4047,6 @@ typedef enum VkSamplerYcbcrRange { VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, - VK_SAMPLER_YCBCR_RANGE_BEGIN_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_END_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, - VK_SAMPLER_YCBCR_RANGE_RANGE_SIZE = (VK_SAMPLER_YCBCR_RANGE_ITU_NARROW - VK_SAMPLER_YCBCR_RANGE_ITU_FULL + 1), VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF } VkSamplerYcbcrRange; @@ -3992,9 +4055,6 @@ typedef enum VkChromaLocation { VK_CHROMA_LOCATION_MIDPOINT = 1, VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, - VK_CHROMA_LOCATION_BEGIN_RANGE = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_END_RANGE = VK_CHROMA_LOCATION_MIDPOINT, - VK_CHROMA_LOCATION_RANGE_SIZE = (VK_CHROMA_LOCATION_MIDPOINT - VK_CHROMA_LOCATION_COSITED_EVEN + 1), VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF } VkChromaLocation; @@ -4002,9 +4062,6 @@ typedef enum VkDescriptorUpdateTemplateType { VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + 1), VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorUpdateTemplateType; @@ -4037,7 +4094,11 @@ typedef VkFlags VkPeerMemoryFeatureFlags; typedef enum VkMemoryAllocateFlagBits { VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT = 0x00000002, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000004, VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryAllocateFlagBits; typedef VkFlags VkMemoryAllocateFlags; @@ -4804,11 +4865,764 @@ VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport( #endif +#define VK_VERSION_1_2 1 +// Vulkan 1.2 version number +#define VK_API_VERSION_1_2 VK_MAKE_VERSION(1, 2, 0)// Patch version should always be set to 0 + +typedef uint64_t VkDeviceAddress; +#define VK_MAX_DRIVER_NAME_SIZE 256 +#define VK_MAX_DRIVER_INFO_SIZE 256 + +typedef enum VkDriverId { + VK_DRIVER_ID_AMD_PROPRIETARY = 1, + VK_DRIVER_ID_AMD_OPEN_SOURCE = 2, + VK_DRIVER_ID_MESA_RADV = 3, + VK_DRIVER_ID_NVIDIA_PROPRIETARY = 4, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS = 5, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA = 6, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY = 7, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY = 8, + VK_DRIVER_ID_ARM_PROPRIETARY = 9, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER = 10, + VK_DRIVER_ID_GGP_PROPRIETARY = 11, + VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12, + VK_DRIVER_ID_MESA_LLVMPIPE = 13, + VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, + VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, + VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, + VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = VK_DRIVER_ID_NVIDIA_PROPRIETARY, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = VK_DRIVER_ID_IMAGINATION_PROPRIETARY, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = VK_DRIVER_ID_QUALCOMM_PROPRIETARY, + VK_DRIVER_ID_ARM_PROPRIETARY_KHR = VK_DRIVER_ID_ARM_PROPRIETARY, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = VK_DRIVER_ID_GOOGLE_SWIFTSHADER, + VK_DRIVER_ID_GGP_PROPRIETARY_KHR = VK_DRIVER_ID_GGP_PROPRIETARY, + VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY, + VK_DRIVER_ID_MAX_ENUM = 0x7FFFFFFF +} VkDriverId; + +typedef enum VkShaderFloatControlsIndependence { + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY = 0, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL = 1, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7FFFFFFF +} VkShaderFloatControlsIndependence; + +typedef enum VkSamplerReductionMode { + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE = 0, + VK_SAMPLER_REDUCTION_MODE_MIN = 1, + VK_SAMPLER_REDUCTION_MODE_MAX = 2, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, + VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, + VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, + VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerReductionMode; + +typedef enum VkSemaphoreType { + VK_SEMAPHORE_TYPE_BINARY = 0, + VK_SEMAPHORE_TYPE_TIMELINE = 1, + VK_SEMAPHORE_TYPE_BINARY_KHR = VK_SEMAPHORE_TYPE_BINARY, + VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE, + VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreType; + +typedef enum VkResolveModeFlagBits { + VK_RESOLVE_MODE_NONE = 0, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 0x00000001, + VK_RESOLVE_MODE_AVERAGE_BIT = 0x00000002, + VK_RESOLVE_MODE_MIN_BIT = 0x00000004, + VK_RESOLVE_MODE_MAX_BIT = 0x00000008, + VK_RESOLVE_MODE_NONE_KHR = VK_RESOLVE_MODE_NONE, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, + VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, + VK_RESOLVE_MODE_MIN_BIT_KHR = VK_RESOLVE_MODE_MIN_BIT, + VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT, + VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkResolveModeFlagBits; +typedef VkFlags VkResolveModeFlags; + +typedef enum VkDescriptorBindingFlagBits { + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 0x00000001, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 0x00000002, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 0x00000004, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 0x00000008, + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, + VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorBindingFlagBits; +typedef VkFlags VkDescriptorBindingFlags; + +typedef enum VkSemaphoreWaitFlagBits { + VK_SEMAPHORE_WAIT_ANY_BIT = 0x00000001, + VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT, + VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreWaitFlagBits; +typedef VkFlags VkSemaphoreWaitFlags; +typedef struct VkPhysicalDeviceVulkan11Features { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; + VkBool32 protectedMemory; + VkBool32 samplerYcbcrConversion; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceVulkan11Features; + +typedef struct VkPhysicalDeviceVulkan11Properties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; + uint32_t subgroupSize; + VkShaderStageFlags subgroupSupportedStages; + VkSubgroupFeatureFlags subgroupSupportedOperations; + VkBool32 subgroupQuadOperationsInAllStages; + VkPointClippingBehavior pointClippingBehavior; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; + VkBool32 protectedNoFault; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceVulkan11Properties; + +typedef struct VkPhysicalDeviceVulkan12Features { + VkStructureType sType; + void* pNext; + VkBool32 samplerMirrorClampToEdge; + VkBool32 drawIndirectCount; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; + VkBool32 descriptorIndexing; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; + VkBool32 samplerFilterMinmax; + VkBool32 scalarBlockLayout; + VkBool32 imagelessFramebuffer; + VkBool32 uniformBufferStandardLayout; + VkBool32 shaderSubgroupExtendedTypes; + VkBool32 separateDepthStencilLayouts; + VkBool32 hostQueryReset; + VkBool32 timelineSemaphore; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; + VkBool32 shaderOutputViewportIndex; + VkBool32 shaderOutputLayer; + VkBool32 subgroupBroadcastDynamicId; +} VkPhysicalDeviceVulkan12Features; + +typedef struct VkConformanceVersion { + uint8_t major; + uint8_t minor; + uint8_t subminor; + uint8_t patch; +} VkConformanceVersion; + +typedef struct VkPhysicalDeviceVulkan12Properties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; + uint64_t maxTimelineSemaphoreValueDifference; + VkSampleCountFlags framebufferIntegerColorSampleCounts; +} VkPhysicalDeviceVulkan12Properties; + +typedef struct VkImageFormatListCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkImageFormatListCreateInfo; + +typedef struct VkAttachmentDescription2 { + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2; + +typedef struct VkAttachmentReference2 { + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2; + +typedef struct VkSubpassDescription2 { + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2* pColorAttachments; + const VkAttachmentReference2* pResolveAttachments; + const VkAttachmentReference2* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2; + +typedef struct VkSubpassDependency2 { + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2; + +typedef struct VkRenderPassCreateInfo2 { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2; + +typedef struct VkSubpassBeginInfo { + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfo; + +typedef struct VkSubpassEndInfo { + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfo; + +typedef struct VkPhysicalDevice8BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeatures; + +typedef struct VkPhysicalDeviceDriverProperties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; +} VkPhysicalDeviceDriverProperties; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; +} VkPhysicalDeviceShaderAtomicInt64Features; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceShaderFloat16Int8Features; + +typedef struct VkPhysicalDeviceFloatControlsProperties { + VkStructureType sType; + void* pNext; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; +} VkPhysicalDeviceFloatControlsProperties; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t bindingCount; + const VkDescriptorBindingFlags* pBindingFlags; +} VkDescriptorSetLayoutBindingFlagsCreateInfo; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; +} VkPhysicalDeviceDescriptorIndexingFeatures; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties { + VkStructureType sType; + void* pNext; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; +} VkPhysicalDeviceDescriptorIndexingProperties; + +typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo { + VkStructureType sType; + const void* pNext; + uint32_t descriptorSetCount; + const uint32_t* pDescriptorCounts; +} VkDescriptorSetVariableDescriptorCountAllocateInfo; + +typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport { + VkStructureType sType; + void* pNext; + uint32_t maxVariableDescriptorCount; +} VkDescriptorSetVariableDescriptorCountLayoutSupport; + +typedef struct VkSubpassDescriptionDepthStencilResolve { + VkStructureType sType; + const void* pNext; + VkResolveModeFlagBits depthResolveMode; + VkResolveModeFlagBits stencilResolveMode; + const VkAttachmentReference2* pDepthStencilResolveAttachment; +} VkSubpassDescriptionDepthStencilResolve; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties { + VkStructureType sType; + void* pNext; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; +} VkPhysicalDeviceDepthStencilResolveProperties; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeatures; + +typedef struct VkImageStencilUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfo; + +typedef struct VkSamplerReductionModeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerReductionMode reductionMode; +} VkSamplerReductionModeCreateInfo; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { + VkStructureType sType; + void* pNext; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; +} VkPhysicalDeviceSamplerFilterMinmaxProperties; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { + VkStructureType sType; + void* pNext; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; +} VkPhysicalDeviceVulkanMemoryModelFeatures; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { + VkStructureType sType; + void* pNext; + VkBool32 imagelessFramebuffer; +} VkPhysicalDeviceImagelessFramebufferFeatures; + +typedef struct VkFramebufferAttachmentImageInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageUsageFlags usage; + uint32_t width; + uint32_t height; + uint32_t layerCount; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkFramebufferAttachmentImageInfo; + +typedef struct VkFramebufferAttachmentsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentImageInfoCount; + const VkFramebufferAttachmentImageInfo* pAttachmentImageInfos; +} VkFramebufferAttachmentsCreateInfo; + +typedef struct VkRenderPassAttachmentBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentCount; + const VkImageView* pAttachments; +} VkRenderPassAttachmentBeginInfo; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 uniformBufferStandardLayout; +} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupExtendedTypes; +} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { + VkStructureType sType; + void* pNext; + VkBool32 separateDepthStencilLayouts; +} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; + +typedef struct VkAttachmentReferenceStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilLayout; +} VkAttachmentReferenceStencilLayout; + +typedef struct VkAttachmentDescriptionStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilInitialLayout; + VkImageLayout stencilFinalLayout; +} VkAttachmentDescriptionStencilLayout; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures { + VkStructureType sType; + void* pNext; + VkBool32 hostQueryReset; +} VkPhysicalDeviceHostQueryResetFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { + VkStructureType sType; + void* pNext; + VkBool32 timelineSemaphore; +} VkPhysicalDeviceTimelineSemaphoreFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreProperties { + VkStructureType sType; + void* pNext; + uint64_t maxTimelineSemaphoreValueDifference; +} VkPhysicalDeviceTimelineSemaphoreProperties; + +typedef struct VkSemaphoreTypeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreType semaphoreType; + uint64_t initialValue; +} VkSemaphoreTypeCreateInfo; + +typedef struct VkTimelineSemaphoreSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreValueCount; + const uint64_t* pWaitSemaphoreValues; + uint32_t signalSemaphoreValueCount; + const uint64_t* pSignalSemaphoreValues; +} VkTimelineSemaphoreSubmitInfo; + +typedef struct VkSemaphoreWaitInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreWaitFlags flags; + uint32_t semaphoreCount; + const VkSemaphore* pSemaphores; + const uint64_t* pValues; +} VkSemaphoreWaitInfo; + +typedef struct VkSemaphoreSignalInfo { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; +} VkSemaphoreSignalInfo; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeatures; + +typedef struct VkBufferDeviceAddressInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfo; + +typedef struct VkBufferOpaqueCaptureAddressCreateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfo; + +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfo; + +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfo; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkResetQueryPool)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphores)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2( + VkDevice device, + const VkRenderPassCreateInfo2* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfo* pSubpassBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkResetQueryPool( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValue( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphores( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphore( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddress( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +#endif + + #define VK_KHR_surface 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) #define VK_KHR_SURFACE_SPEC_VERSION 25 #define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" +typedef enum VkPresentModeKHR { + VK_PRESENT_MODE_IMMEDIATE_KHR = 0, + VK_PRESENT_MODE_MAILBOX_KHR = 1, + VK_PRESENT_MODE_FIFO_KHR = 2, + VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, + VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentModeKHR; + typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, @@ -4828,25 +5642,9 @@ typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, - VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF } VkColorSpaceKHR; -typedef enum VkPresentModeKHR { - VK_PRESENT_MODE_IMMEDIATE_KHR = 0, - VK_PRESENT_MODE_MAILBOX_KHR = 1, - VK_PRESENT_MODE_FIFO_KHR = 2, - VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, - VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, - VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), - VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkPresentModeKHR; - typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, @@ -4859,7 +5657,6 @@ typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSurfaceTransformFlagBitsKHR; -typedef VkFlags VkSurfaceTransformFlagsKHR; typedef enum VkCompositeAlphaFlagBitsKHR { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, @@ -4868,6 +5665,7 @@ typedef enum VkCompositeAlphaFlagBitsKHR { VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkCompositeAlphaFlagBitsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; typedef VkFlags VkCompositeAlphaFlagsKHR; typedef struct VkSurfaceCapabilitiesKHR { uint32_t minImageCount; @@ -5591,14 +6389,9 @@ VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( #define VK_KHR_shader_float16_int8 1 #define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 #define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" -typedef struct VkPhysicalDeviceShaderFloat16Int8FeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; -} VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; -typedef VkPhysicalDeviceShaderFloat16Int8FeaturesKHR VkPhysicalDeviceFloat16Int8FeaturesKHR; +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; @@ -5672,144 +6465,58 @@ VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( #define VK_KHR_imageless_framebuffer 1 #define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 #define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" -typedef struct VkPhysicalDeviceImagelessFramebufferFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 imagelessFramebuffer; -} VkPhysicalDeviceImagelessFramebufferFeaturesKHR; +typedef VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; -typedef struct VkFramebufferAttachmentImageInfoKHR { - VkStructureType sType; - const void* pNext; - VkImageCreateFlags flags; - VkImageUsageFlags usage; - uint32_t width; - uint32_t height; - uint32_t layerCount; - uint32_t viewFormatCount; - const VkFormat* pViewFormats; -} VkFramebufferAttachmentImageInfoKHR; +typedef VkFramebufferAttachmentsCreateInfo VkFramebufferAttachmentsCreateInfoKHR; -typedef struct VkFramebufferAttachmentsCreateInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t attachmentImageInfoCount; - const VkFramebufferAttachmentImageInfoKHR* pAttachmentImageInfos; -} VkFramebufferAttachmentsCreateInfoKHR; +typedef VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; -typedef struct VkRenderPassAttachmentBeginInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t attachmentCount; - const VkImageView* pAttachments; -} VkRenderPassAttachmentBeginInfoKHR; +typedef VkRenderPassAttachmentBeginInfo VkRenderPassAttachmentBeginInfoKHR; #define VK_KHR_create_renderpass2 1 #define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 #define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" -typedef struct VkAttachmentDescription2KHR { - VkStructureType sType; - const void* pNext; - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription2KHR; +typedef VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; -typedef struct VkAttachmentReference2KHR { - VkStructureType sType; - const void* pNext; - uint32_t attachment; - VkImageLayout layout; - VkImageAspectFlags aspectMask; -} VkAttachmentReference2KHR; +typedef VkAttachmentDescription2 VkAttachmentDescription2KHR; -typedef struct VkSubpassDescription2KHR { - VkStructureType sType; - const void* pNext; - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t viewMask; - uint32_t inputAttachmentCount; - const VkAttachmentReference2KHR* pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference2KHR* pColorAttachments; - const VkAttachmentReference2KHR* pResolveAttachments; - const VkAttachmentReference2KHR* pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t* pPreserveAttachments; -} VkSubpassDescription2KHR; +typedef VkAttachmentReference2 VkAttachmentReference2KHR; -typedef struct VkSubpassDependency2KHR { - VkStructureType sType; - const void* pNext; - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; - int32_t viewOffset; -} VkSubpassDependency2KHR; +typedef VkSubpassDescription2 VkSubpassDescription2KHR; -typedef struct VkRenderPassCreateInfo2KHR { - VkStructureType sType; - const void* pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription2KHR* pAttachments; - uint32_t subpassCount; - const VkSubpassDescription2KHR* pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency2KHR* pDependencies; - uint32_t correlatedViewMaskCount; - const uint32_t* pCorrelatedViewMasks; -} VkRenderPassCreateInfo2KHR; +typedef VkSubpassDependency2 VkSubpassDependency2KHR; -typedef struct VkSubpassBeginInfoKHR { - VkStructureType sType; - const void* pNext; - VkSubpassContents contents; -} VkSubpassBeginInfoKHR; +typedef VkSubpassBeginInfo VkSubpassBeginInfoKHR; -typedef struct VkSubpassEndInfoKHR { - VkStructureType sType; - const void* pNext; -} VkSubpassEndInfoKHR; +typedef VkSubpassEndInfo VkSubpassEndInfoKHR; -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR( VkDevice device, - const VkRenderPassCreateInfo2KHR* pCreateInfo, + const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2KHR( VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, - const VkSubpassBeginInfoKHR* pSubpassBeginInfo); + const VkSubpassBeginInfo* pSubpassBeginInfo); VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2KHR( VkCommandBuffer commandBuffer, - const VkSubpassBeginInfoKHR* pSubpassBeginInfo, - const VkSubpassEndInfoKHR* pSubpassEndInfo); + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2KHR( VkCommandBuffer commandBuffer, - const VkSubpassEndInfoKHR* pSubpassEndInfo); + const VkSubpassEndInfo* pSubpassEndInfo); #endif @@ -5901,6 +6608,144 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR( #endif +#define VK_KHR_performance_query 1 +#define VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION 1 +#define VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME "VK_KHR_performance_query" + +typedef enum VkPerformanceCounterUnitKHR { + VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0, + VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR = 1, + VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR = 2, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR = 3, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR = 4, + VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR = 5, + VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR = 6, + VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR = 7, + VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR = 8, + VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR = 9, + VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10, + VK_PERFORMANCE_COUNTER_UNIT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterUnitKHR; + +typedef enum VkPerformanceCounterScopeKHR { + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR = 0, + VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR = 1, + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2, + VK_QUERY_SCOPE_COMMAND_BUFFER_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR, + VK_QUERY_SCOPE_RENDER_PASS_KHR = VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR, + VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR, + VK_PERFORMANCE_COUNTER_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterScopeKHR; + +typedef enum VkPerformanceCounterStorageKHR { + VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR = 0, + VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR = 1, + VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR = 2, + VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR = 3, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR = 4, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5, + VK_PERFORMANCE_COUNTER_STORAGE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterStorageKHR; + +typedef enum VkPerformanceCounterDescriptionFlagBitsKHR { + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = 0x00000001, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = 0x00000002, + VK_PERFORMANCE_COUNTER_DESCRIPTION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterDescriptionFlagBitsKHR; +typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; + +typedef enum VkAcquireProfilingLockFlagBitsKHR { + VK_ACQUIRE_PROFILING_LOCK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAcquireProfilingLockFlagBitsKHR; +typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 performanceCounterQueryPools; + VkBool32 performanceCounterMultipleQueryPools; +} VkPhysicalDevicePerformanceQueryFeaturesKHR; + +typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 allowCommandBufferQueryCopies; +} VkPhysicalDevicePerformanceQueryPropertiesKHR; + +typedef struct VkPerformanceCounterKHR { + VkStructureType sType; + const void* pNext; + VkPerformanceCounterUnitKHR unit; + VkPerformanceCounterScopeKHR scope; + VkPerformanceCounterStorageKHR storage; + uint8_t uuid[VK_UUID_SIZE]; +} VkPerformanceCounterKHR; + +typedef struct VkPerformanceCounterDescriptionKHR { + VkStructureType sType; + const void* pNext; + VkPerformanceCounterDescriptionFlagsKHR flags; + char name[VK_MAX_DESCRIPTION_SIZE]; + char category[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkPerformanceCounterDescriptionKHR; + +typedef struct VkQueryPoolPerformanceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t queueFamilyIndex; + uint32_t counterIndexCount; + const uint32_t* pCounterIndices; +} VkQueryPoolPerformanceCreateInfoKHR; + +typedef union VkPerformanceCounterResultKHR { + int32_t int32; + int64_t int64; + uint32_t uint32; + uint64_t uint64; + float float32; + double float64; +} VkPerformanceCounterResultKHR; + +typedef struct VkAcquireProfilingLockInfoKHR { + VkStructureType sType; + const void* pNext; + VkAcquireProfilingLockFlagsKHR flags; + uint64_t timeout; +} VkAcquireProfilingLockInfoKHR; + +typedef struct VkPerformanceQuerySubmitInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t counterPassIndex; +} VkPerformanceQuerySubmitInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t* pCounterCount, VkPerformanceCounterKHR* pCounters, VkPerformanceCounterDescriptionKHR* pCounterDescriptions); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)(VkPhysicalDevice physicalDevice, const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, uint32_t* pNumPasses); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireProfilingLockKHR)(VkDevice device, const VkAcquireProfilingLockInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkReleaseProfilingLockKHR)(VkDevice device); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + uint32_t* pCounterCount, + VkPerformanceCounterKHR* pCounters, + VkPerformanceCounterDescriptionKHR* pCounterDescriptions); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR( + VkPhysicalDevice physicalDevice, + const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, + uint32_t* pNumPasses); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireProfilingLockKHR( + VkDevice device, + const VkAcquireProfilingLockInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkReleaseProfilingLockKHR( + VkDevice device); +#endif + + #define VK_KHR_maintenance2 1 #define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 #define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" @@ -6086,12 +6931,7 @@ VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR( #define VK_KHR_image_format_list 1 #define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 #define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" -typedef struct VkImageFormatListCreateInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t viewFormatCount; - const VkFormat* pViewFormats; -} VkImageFormatListCreateInfoKHR; +typedef VkImageFormatListCreateInfo VkImageFormatListCreateInfoKHR; @@ -6205,147 +7045,68 @@ VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountKHR( #define VK_KHR_shader_subgroup_extended_types 1 #define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION 1 #define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME "VK_KHR_shader_subgroup_extended_types" -typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 shaderSubgroupExtendedTypes; -} VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; +typedef VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; #define VK_KHR_8bit_storage 1 #define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 #define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" -typedef struct VkPhysicalDevice8BitStorageFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; -} VkPhysicalDevice8BitStorageFeaturesKHR; +typedef VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; #define VK_KHR_shader_atomic_int64 1 #define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 #define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" -typedef struct VkPhysicalDeviceShaderAtomicInt64FeaturesKHR { +typedef VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + + + +#define VK_KHR_shader_clock 1 +#define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1 +#define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock" +typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { VkStructureType sType; void* pNext; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; -} VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + VkBool32 shaderSubgroupClock; + VkBool32 shaderDeviceClock; +} VkPhysicalDeviceShaderClockFeaturesKHR; #define VK_KHR_driver_properties 1 -#define VK_MAX_DRIVER_NAME_SIZE_KHR 256 -#define VK_MAX_DRIVER_INFO_SIZE_KHR 256 #define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 #define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" +#define VK_MAX_DRIVER_NAME_SIZE_KHR VK_MAX_DRIVER_NAME_SIZE +#define VK_MAX_DRIVER_INFO_SIZE_KHR VK_MAX_DRIVER_INFO_SIZE +typedef VkDriverId VkDriverIdKHR; -typedef enum VkDriverIdKHR { - VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1, - VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2, - VK_DRIVER_ID_MESA_RADV_KHR = 3, - VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4, - VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5, - VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6, - VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7, - VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8, - VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9, - VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = 10, - VK_DRIVER_ID_GGP_PROPRIETARY_KHR = 11, - VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = 12, - VK_DRIVER_ID_BEGIN_RANGE_KHR = VK_DRIVER_ID_AMD_PROPRIETARY_KHR, - VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR, - VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1), - VK_DRIVER_ID_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDriverIdKHR; -typedef struct VkConformanceVersionKHR { - uint8_t major; - uint8_t minor; - uint8_t subminor; - uint8_t patch; -} VkConformanceVersionKHR; +typedef VkConformanceVersion VkConformanceVersionKHR; -typedef struct VkPhysicalDeviceDriverPropertiesKHR { - VkStructureType sType; - void* pNext; - VkDriverIdKHR driverID; - char driverName[VK_MAX_DRIVER_NAME_SIZE_KHR]; - char driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR]; - VkConformanceVersionKHR conformanceVersion; -} VkPhysicalDeviceDriverPropertiesKHR; +typedef VkPhysicalDeviceDriverProperties VkPhysicalDeviceDriverPropertiesKHR; #define VK_KHR_shader_float_controls 1 #define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 4 #define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" +typedef VkShaderFloatControlsIndependence VkShaderFloatControlsIndependenceKHR; -typedef enum VkShaderFloatControlsIndependenceKHR { - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = 0, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = 1, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = 2, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_BEGIN_RANGE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_END_RANGE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_RANGE_SIZE_KHR = (VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR + 1), - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkShaderFloatControlsIndependenceKHR; -typedef struct VkPhysicalDeviceFloatControlsPropertiesKHR { - VkStructureType sType; - void* pNext; - VkShaderFloatControlsIndependenceKHR denormBehaviorIndependence; - VkShaderFloatControlsIndependenceKHR roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; -} VkPhysicalDeviceFloatControlsPropertiesKHR; +typedef VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; #define VK_KHR_depth_stencil_resolve 1 #define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 #define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" +typedef VkResolveModeFlagBits VkResolveModeFlagBitsKHR; -typedef enum VkResolveModeFlagBitsKHR { - VK_RESOLVE_MODE_NONE_KHR = 0, - VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = 0x00000001, - VK_RESOLVE_MODE_AVERAGE_BIT_KHR = 0x00000002, - VK_RESOLVE_MODE_MIN_BIT_KHR = 0x00000004, - VK_RESOLVE_MODE_MAX_BIT_KHR = 0x00000008, - VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkResolveModeFlagBitsKHR; -typedef VkFlags VkResolveModeFlagsKHR; -typedef struct VkSubpassDescriptionDepthStencilResolveKHR { - VkStructureType sType; - const void* pNext; - VkResolveModeFlagBitsKHR depthResolveMode; - VkResolveModeFlagBitsKHR stencilResolveMode; - const VkAttachmentReference2KHR* pDepthStencilResolveAttachment; -} VkSubpassDescriptionDepthStencilResolveKHR; +typedef VkResolveModeFlags VkResolveModeFlagsKHR; -typedef struct VkPhysicalDeviceDepthStencilResolvePropertiesKHR { - VkStructureType sType; - void* pNext; - VkResolveModeFlagsKHR supportedDepthResolveModes; - VkResolveModeFlagsKHR supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; -} VkPhysicalDeviceDepthStencilResolvePropertiesKHR; +typedef VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; + +typedef VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; @@ -6354,19 +7115,60 @@ typedef struct VkPhysicalDeviceDepthStencilResolvePropertiesKHR { #define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" +#define VK_KHR_timeline_semaphore 1 +#define VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION 2 +#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME "VK_KHR_timeline_semaphore" +typedef VkSemaphoreType VkSemaphoreTypeKHR; + +typedef VkSemaphoreWaitFlagBits VkSemaphoreWaitFlagBitsKHR; + +typedef VkSemaphoreWaitFlags VkSemaphoreWaitFlagsKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreProperties VkPhysicalDeviceTimelineSemaphorePropertiesKHR; + +typedef VkSemaphoreTypeCreateInfo VkSemaphoreTypeCreateInfoKHR; + +typedef VkTimelineSemaphoreSubmitInfo VkTimelineSemaphoreSubmitInfoKHR; + +typedef VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; + +typedef VkSemaphoreSignalInfo VkSemaphoreSignalInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValueKHR)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValueKHR( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphoresKHR( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphoreKHR( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); +#endif + + #define VK_KHR_vulkan_memory_model 1 #define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 #define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" -typedef struct VkPhysicalDeviceVulkanMemoryModelFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; -} VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; +typedef VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; +#define VK_KHR_spirv_1_4 1 +#define VK_KHR_SPIRV_1_4_SPEC_VERSION 1 +#define VK_KHR_SPIRV_1_4_EXTENSION_NAME "VK_KHR_spirv_1_4" + + #define VK_KHR_surface_protected_capabilities 1 #define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION 1 #define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME "VK_KHR_surface_protected_capabilities" @@ -6378,17 +7180,56 @@ typedef struct VkSurfaceProtectedCapabilitiesKHR { +#define VK_KHR_separate_depth_stencil_layouts 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME "VK_KHR_separate_depth_stencil_layouts" +typedef VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; + +typedef VkAttachmentReferenceStencilLayout VkAttachmentReferenceStencilLayoutKHR; + +typedef VkAttachmentDescriptionStencilLayout VkAttachmentDescriptionStencilLayoutKHR; + + + #define VK_KHR_uniform_buffer_standard_layout 1 #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 uniformBufferStandardLayout; -} VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; +typedef VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; +#define VK_KHR_buffer_device_address 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_KHR_buffer_device_address" +typedef VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; + +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoKHR; + +typedef VkBufferOpaqueCaptureAddressCreateInfo VkBufferOpaqueCaptureAddressCreateInfoKHR; + +typedef VkMemoryOpaqueCaptureAddressAllocateInfo VkMemoryOpaqueCaptureAddressAllocateInfoKHR; + +typedef VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR; + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddressKHR( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +#endif + + #define VK_KHR_pipeline_executable_properties 1 #define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION 1 #define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME "VK_KHR_pipeline_executable_properties" @@ -6398,9 +7239,6 @@ typedef enum VkPipelineExecutableStatisticFormatKHR { VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR = 1, VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR = 2, VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BEGIN_RANGE_KHR = VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_END_RANGE_KHR = VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_RANGE_SIZE_KHR = (VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR + 1), VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_MAX_ENUM_KHR = 0x7FFFFFFF } VkPipelineExecutableStatisticFormatKHR; typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { @@ -6482,6 +7320,11 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableInternalRepresentationsKHR #endif +#define VK_KHR_shader_non_semantic_info 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME "VK_KHR_shader_non_semantic_info" + + #define VK_EXT_debug_report 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) #define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 @@ -6519,19 +7362,15 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, - VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, - VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000165000, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportObjectTypeEXT; @@ -6612,9 +7451,6 @@ VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( typedef enum VkRasterizationOrderAMD { VK_RASTERIZATION_ORDER_STRICT_AMD = 0, VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, - VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD, - VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD, - VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1), VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF } VkRasterizationOrderAMD; typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { @@ -6808,7 +7644,7 @@ VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT( #define VK_NVX_image_view_handle 1 -#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 1 +#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 2 #define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" typedef struct VkImageViewHandleInfoNVX { VkStructureType sType; @@ -6818,12 +7654,25 @@ typedef struct VkImageViewHandleInfoNVX { VkSampler sampler; } VkImageViewHandleInfoNVX; +typedef struct VkImageViewAddressPropertiesNVX { + VkStructureType sType; + void* pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; +} VkImageViewAddressPropertiesNVX; + typedef uint32_t (VKAPI_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewAddressNVX)(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX* pProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR uint32_t VKAPI_CALL vkGetImageViewHandleNVX( VkDevice device, const VkImageViewHandleInfoNVX* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageViewAddressNVX( + VkDevice device, + VkImageView imageView, + VkImageViewAddressPropertiesNVX* pProperties); #endif @@ -6888,9 +7737,6 @@ typedef enum VkShaderInfoTypeAMD { VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, VK_SHADER_INFO_TYPE_BINARY_AMD = 1, VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, - VK_SHADER_INFO_TYPE_BEGIN_RANGE_AMD = VK_SHADER_INFO_TYPE_STATISTICS_AMD, - VK_SHADER_INFO_TYPE_END_RANGE_AMD = VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, - VK_SHADER_INFO_TYPE_RANGE_SIZE_AMD = (VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD - VK_SHADER_INFO_TYPE_STATISTICS_AMD + 1), VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF } VkShaderInfoTypeAMD; typedef struct VkShaderResourceUsageAMD { @@ -7011,9 +7857,6 @@ typedef struct VkExportMemoryAllocateInfoNV { typedef enum VkValidationCheckEXT { VK_VALIDATION_CHECK_ALL_EXT = 0, VK_VALIDATION_CHECK_SHADERS_EXT = 1, - VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT, - VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_SHADERS_EXT, - VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_SHADERS_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1), VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationCheckEXT; typedef struct VkValidationFlagsEXT { @@ -7040,7 +7883,7 @@ typedef struct VkValidationFlagsEXT { #define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT { VkStructureType sType; - const void* pNext; + void* pNext; VkBool32 textureCompressionASTC_HDR; } VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; @@ -7106,229 +7949,6 @@ VKAPI_ATTR void VKAPI_CALL vkCmdEndConditionalRenderingEXT( #endif -#define VK_NVX_device_generated_commands 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) -#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 -#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands" - -typedef enum VkIndirectCommandsTokenTypeNVX { - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX + 1), - VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsTokenTypeNVX; - -typedef enum VkObjectEntryTypeNVX { - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0, - VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1, - VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2, - VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3, - VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4, - VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX, - VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX, - VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX + 1), - VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryTypeNVX; - -typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX { - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsLayoutUsageFlagBitsNVX; -typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX; - -typedef enum VkObjectEntryUsageFlagBitsNVX { - VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001, - VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002, - VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryUsageFlagBitsNVX; -typedef VkFlags VkObjectEntryUsageFlagsNVX; -typedef struct VkDeviceGeneratedCommandsFeaturesNVX { - VkStructureType sType; - const void* pNext; - VkBool32 computeBindingPointSupport; -} VkDeviceGeneratedCommandsFeaturesNVX; - -typedef struct VkDeviceGeneratedCommandsLimitsNVX { - VkStructureType sType; - const void* pNext; - uint32_t maxIndirectCommandsLayoutTokenCount; - uint32_t maxObjectEntryCounts; - uint32_t minSequenceCountBufferOffsetAlignment; - uint32_t minSequenceIndexBufferOffsetAlignment; - uint32_t minCommandsTokenBufferOffsetAlignment; -} VkDeviceGeneratedCommandsLimitsNVX; - -typedef struct VkIndirectCommandsTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - VkBuffer buffer; - VkDeviceSize offset; -} VkIndirectCommandsTokenNVX; - -typedef struct VkIndirectCommandsLayoutTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - uint32_t bindingUnit; - uint32_t dynamicCount; - uint32_t divisor; -} VkIndirectCommandsLayoutTokenNVX; - -typedef struct VkIndirectCommandsLayoutCreateInfoNVX { - VkStructureType sType; - const void* pNext; - VkPipelineBindPoint pipelineBindPoint; - VkIndirectCommandsLayoutUsageFlagsNVX flags; - uint32_t tokenCount; - const VkIndirectCommandsLayoutTokenNVX* pTokens; -} VkIndirectCommandsLayoutCreateInfoNVX; - -typedef struct VkCmdProcessCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t indirectCommandsTokenCount; - const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens; - uint32_t maxSequencesCount; - VkCommandBuffer targetCommandBuffer; - VkBuffer sequencesCountBuffer; - VkDeviceSize sequencesCountOffset; - VkBuffer sequencesIndexBuffer; - VkDeviceSize sequencesIndexOffset; -} VkCmdProcessCommandsInfoNVX; - -typedef struct VkCmdReserveSpaceForCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t maxSequencesCount; -} VkCmdReserveSpaceForCommandsInfoNVX; - -typedef struct VkObjectTableCreateInfoNVX { - VkStructureType sType; - const void* pNext; - uint32_t objectCount; - const VkObjectEntryTypeNVX* pObjectEntryTypes; - const uint32_t* pObjectEntryCounts; - const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags; - uint32_t maxUniformBuffersPerDescriptor; - uint32_t maxStorageBuffersPerDescriptor; - uint32_t maxStorageImagesPerDescriptor; - uint32_t maxSampledImagesPerDescriptor; - uint32_t maxPipelineLayouts; -} VkObjectTableCreateInfoNVX; - -typedef struct VkObjectTableEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; -} VkObjectTableEntryNVX; - -typedef struct VkObjectTablePipelineEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipeline pipeline; -} VkObjectTablePipelineEntryNVX; - -typedef struct VkObjectTableDescriptorSetEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; -} VkObjectTableDescriptorSetEntryNVX; - -typedef struct VkObjectTableVertexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; -} VkObjectTableVertexBufferEntryNVX; - -typedef struct VkObjectTableIndexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; - VkIndexType indexType; -} VkObjectTableIndexBufferEntryNVX; - -typedef struct VkObjectTablePushConstantEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkShaderStageFlags stageFlags; -} VkObjectTablePushConstantEntryNVX; - -typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); -typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable); -typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices); -typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX( - VkDevice device, - const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX( - VkDevice device, - VkIndirectCommandsLayoutNVX indirectCommandsLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX( - VkDevice device, - const VkObjectTableCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkObjectTableNVX* pObjectTable); - -VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX( - VkDevice device, - VkObjectTableNVX objectTable, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectTableEntryNVX* const* ppObjectTableEntries, - const uint32_t* pObjectIndices); - -VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectEntryTypeNVX* pObjectEntryTypes, - const uint32_t* pObjectIndices); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( - VkPhysicalDevice physicalDevice, - VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, - VkDeviceGeneratedCommandsLimitsNVX* pLimits); -#endif - - #define VK_NV_clip_space_w_scaling 1 #define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 #define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" @@ -7411,25 +8031,16 @@ typedef enum VkDisplayPowerStateEXT { VK_DISPLAY_POWER_STATE_OFF_EXT = 0, VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, VK_DISPLAY_POWER_STATE_ON_EXT = 2, - VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT, - VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT, - VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1), VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDisplayPowerStateEXT; typedef enum VkDeviceEventTypeEXT { VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, - VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1), VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDeviceEventTypeEXT; typedef enum VkDisplayEventTypeEXT { VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, - VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1), VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDisplayEventTypeEXT; typedef struct VkDisplayPowerInfoEXT { @@ -7571,9 +8182,6 @@ typedef enum VkViewportCoordinateSwizzleNV { VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, - VK_VIEWPORT_COORDINATE_SWIZZLE_BEGIN_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, - VK_VIEWPORT_COORDINATE_SWIZZLE_END_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV, - VK_VIEWPORT_COORDINATE_SWIZZLE_RANGE_SIZE_NV = (VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV + 1), VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF } VkViewportCoordinateSwizzleNV; typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; @@ -7601,9 +8209,6 @@ typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { typedef enum VkDiscardRectangleModeEXT { VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, - VK_DISCARD_RECTANGLE_MODE_BEGIN_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT, - VK_DISCARD_RECTANGLE_MODE_END_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT, - VK_DISCARD_RECTANGLE_MODE_RANGE_SIZE_EXT = (VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT + 1), VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDiscardRectangleModeEXT; typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; @@ -7641,9 +8246,6 @@ typedef enum VkConservativeRasterizationModeEXT { VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, - VK_CONSERVATIVE_RASTERIZATION_MODE_BEGIN_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT, - VK_CONSERVATIVE_RASTERIZATION_MODE_END_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT, - VK_CONSERVATIVE_RASTERIZATION_MODE_RANGE_SIZE_EXT = (VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT + 1), VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF } VkConservativeRasterizationModeEXT; typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; @@ -7740,10 +8342,9 @@ VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT( #define VK_EXT_debug_utils 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) -#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 1 +#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 2 #define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; -typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, @@ -7752,7 +8353,6 @@ typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugUtilsMessageSeverityFlagBitsEXT; -typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, @@ -7761,6 +8361,15 @@ typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugUtilsMessageTypeFlagBitsEXT; typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +typedef struct VkDebugUtilsLabelEXT { + VkStructureType sType; + const void* pNext; + const char* pLabelName; + float color[4]; +} VkDebugUtilsLabelEXT; + typedef struct VkDebugUtilsObjectNameInfoEXT { VkStructureType sType; const void* pNext; @@ -7769,23 +8378,6 @@ typedef struct VkDebugUtilsObjectNameInfoEXT { const char* pObjectName; } VkDebugUtilsObjectNameInfoEXT; -typedef struct VkDebugUtilsObjectTagInfoEXT { - VkStructureType sType; - const void* pNext; - VkObjectType objectType; - uint64_t objectHandle; - uint64_t tagName; - size_t tagSize; - const void* pTag; -} VkDebugUtilsObjectTagInfoEXT; - -typedef struct VkDebugUtilsLabelEXT { - VkStructureType sType; - const void* pNext; - const char* pLabelName; - float color[4]; -} VkDebugUtilsLabelEXT; - typedef struct VkDebugUtilsMessengerCallbackDataEXT { VkStructureType sType; const void* pNext; @@ -7807,6 +8399,16 @@ typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); +typedef struct VkDebugUtilsObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkObjectType objectType; + uint64_t objectHandle; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugUtilsObjectTagInfoEXT; + typedef struct VkDebugUtilsMessengerCreateInfoEXT { VkStructureType sType; const void* pNext; @@ -7882,28 +8484,11 @@ VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT( #define VK_EXT_sampler_filter_minmax 1 #define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 2 #define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" +typedef VkSamplerReductionMode VkSamplerReductionModeEXT; -typedef enum VkSamplerReductionModeEXT { - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0, - VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1, - VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2, - VK_SAMPLER_REDUCTION_MODE_BEGIN_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT, - VK_SAMPLER_REDUCTION_MODE_END_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_MAX_EXT, - VK_SAMPLER_REDUCTION_MODE_RANGE_SIZE_EXT = (VK_SAMPLER_REDUCTION_MODE_MAX_EXT - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT + 1), - VK_SAMPLER_REDUCTION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkSamplerReductionModeEXT; -typedef struct VkSamplerReductionModeCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkSamplerReductionModeEXT reductionMode; -} VkSamplerReductionModeCreateInfoEXT; +typedef VkSamplerReductionModeCreateInfo VkSamplerReductionModeCreateInfoEXT; -typedef struct VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT { - VkStructureType sType; - void* pNext; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; -} VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; +typedef VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; @@ -8044,9 +8629,6 @@ typedef enum VkBlendOverlapEXT { VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, VK_BLEND_OVERLAP_DISJOINT_EXT = 1, VK_BLEND_OVERLAP_CONJOINT_EXT = 2, - VK_BLEND_OVERLAP_BEGIN_RANGE_EXT = VK_BLEND_OVERLAP_UNCORRELATED_EXT, - VK_BLEND_OVERLAP_END_RANGE_EXT = VK_BLEND_OVERLAP_CONJOINT_EXT, - VK_BLEND_OVERLAP_RANGE_SIZE_EXT = (VK_BLEND_OVERLAP_CONJOINT_EXT - VK_BLEND_OVERLAP_UNCORRELATED_EXT + 1), VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF } VkBlendOverlapEXT; typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { @@ -8099,9 +8681,6 @@ typedef enum VkCoverageModulationModeNV { VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, - VK_COVERAGE_MODULATION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_MODULATION_MODE_NONE_NV, - VK_COVERAGE_MODULATION_MODE_END_RANGE_NV = VK_COVERAGE_MODULATION_MODE_RGBA_NV, - VK_COVERAGE_MODULATION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_MODULATION_MODE_RGBA_NV - VK_COVERAGE_MODULATION_MODE_NONE_NV + 1), VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoverageModulationModeNV; typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; @@ -8208,9 +8787,6 @@ VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) typedef enum VkValidationCacheHeaderVersionEXT { VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, - VK_VALIDATION_CACHE_HEADER_VERSION_BEGIN_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT, - VK_VALIDATION_CACHE_HEADER_VERSION_END_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT, - VK_VALIDATION_CACHE_HEADER_VERSION_RANGE_SIZE_EXT = (VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT + 1), VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationCacheHeaderVersionEXT; typedef VkFlags VkValidationCacheCreateFlagsEXT; @@ -8262,87 +8838,19 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT( #define VK_EXT_descriptor_indexing 1 #define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 #define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" +typedef VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT; -typedef enum VkDescriptorBindingFlagBitsEXT { - VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = 0x00000001, - VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = 0x00000002, - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = 0x00000004, - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = 0x00000008, - VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDescriptorBindingFlagBitsEXT; -typedef VkFlags VkDescriptorBindingFlagsEXT; -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t bindingCount; - const VkDescriptorBindingFlagsEXT* pBindingFlags; -} VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; +typedef VkDescriptorBindingFlags VkDescriptorBindingFlagsEXT; -typedef struct VkPhysicalDeviceDescriptorIndexingFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; -} VkPhysicalDeviceDescriptorIndexingFeaturesEXT; +typedef VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; -typedef struct VkPhysicalDeviceDescriptorIndexingPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; -} VkPhysicalDeviceDescriptorIndexingPropertiesEXT; +typedef VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; -typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t descriptorSetCount; - const uint32_t* pDescriptorCounts; -} VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; +typedef VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; -typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupportEXT { - VkStructureType sType; - void* pNext; - uint32_t maxVariableDescriptorCount; -} VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; +typedef VkDescriptorSetVariableDescriptorCountAllocateInfo VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; + +typedef VkDescriptorSetVariableDescriptorCountLayoutSupport VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; @@ -8368,9 +8876,6 @@ typedef enum VkShadingRatePaletteEntryNV { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, - VK_SHADING_RATE_PALETTE_ENTRY_BEGIN_RANGE_NV = VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV, - VK_SHADING_RATE_PALETTE_ENTRY_END_RANGE_NV = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, - VK_SHADING_RATE_PALETTE_ENTRY_RANGE_SIZE_NV = (VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV - VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV + 1), VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF } VkShadingRatePaletteEntryNV; @@ -8379,9 +8884,6 @@ typedef enum VkCoarseSampleOrderTypeNV { VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, - VK_COARSE_SAMPLE_ORDER_TYPE_BEGIN_RANGE_NV = VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV, - VK_COARSE_SAMPLE_ORDER_TYPE_END_RANGE_NV = VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV, - VK_COARSE_SAMPLE_ORDER_TYPE_RANGE_SIZE_NV = (VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV - VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV + 1), VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoarseSampleOrderTypeNV; typedef struct VkShadingRatePaletteNV { @@ -8458,91 +8960,127 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetCoarseSampleOrderNV( #define VK_NV_ray_tracing 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) +typedef VkAccelerationStructureKHR VkAccelerationStructureNV; + #define VK_NV_RAY_TRACING_SPEC_VERSION 3 #define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" -#define VK_SHADER_UNUSED_NV (~0U) +#define VK_SHADER_UNUSED_KHR (~0U) +#define VK_SHADER_UNUSED_NV VK_SHADER_UNUSED_KHR -typedef enum VkAccelerationStructureTypeNV { - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1, - VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV, - VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV, - VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1), - VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkAccelerationStructureTypeNV; +typedef enum VkRayTracingShaderGroupTypeKHR { + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR = 0, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR = 1, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR = 2, + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkRayTracingShaderGroupTypeKHR; +typedef VkRayTracingShaderGroupTypeKHR VkRayTracingShaderGroupTypeNV; -typedef enum VkRayTracingShaderGroupTypeNV { - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0, - VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1, - VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2, - VK_RAY_TRACING_SHADER_GROUP_TYPE_BEGIN_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV, - VK_RAY_TRACING_SHADER_GROUP_TYPE_END_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV, - VK_RAY_TRACING_SHADER_GROUP_TYPE_RANGE_SIZE_NV = (VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV + 1), - VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkRayTracingShaderGroupTypeNV; -typedef enum VkGeometryTypeNV { - VK_GEOMETRY_TYPE_TRIANGLES_NV = 0, - VK_GEOMETRY_TYPE_AABBS_NV = 1, - VK_GEOMETRY_TYPE_BEGIN_RANGE_NV = VK_GEOMETRY_TYPE_TRIANGLES_NV, - VK_GEOMETRY_TYPE_END_RANGE_NV = VK_GEOMETRY_TYPE_AABBS_NV, - VK_GEOMETRY_TYPE_RANGE_SIZE_NV = (VK_GEOMETRY_TYPE_AABBS_NV - VK_GEOMETRY_TYPE_TRIANGLES_NV + 1), - VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkGeometryTypeNV; +typedef enum VkGeometryTypeKHR { + VK_GEOMETRY_TYPE_TRIANGLES_KHR = 0, + VK_GEOMETRY_TYPE_AABBS_KHR = 1, + VK_GEOMETRY_TYPE_INSTANCES_KHR = 1000150000, + VK_GEOMETRY_TYPE_TRIANGLES_NV = VK_GEOMETRY_TYPE_TRIANGLES_KHR, + VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR, + VK_GEOMETRY_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryTypeKHR; +typedef VkGeometryTypeKHR VkGeometryTypeNV; -typedef enum VkCopyAccelerationStructureModeNV { - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1, - VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV, - VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV, - VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NV = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV + 1), - VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NV = 0x7FFFFFFF -} VkCopyAccelerationStructureModeNV; -typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV + 1), - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkAccelerationStructureMemoryRequirementsTypeNV; +typedef enum VkAccelerationStructureTypeKHR { + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR = 0, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR = 1, + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureTypeKHR; +typedef VkAccelerationStructureTypeKHR VkAccelerationStructureTypeNV; -typedef enum VkGeometryFlagBitsNV { - VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002, - VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkGeometryFlagBitsNV; -typedef VkFlags VkGeometryFlagsNV; -typedef enum VkGeometryInstanceFlagBitsNV { - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001, - VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002, - VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008, - VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkGeometryInstanceFlagBitsNV; -typedef VkFlags VkGeometryInstanceFlagsNV; +typedef enum VkCopyAccelerationStructureModeKHR { + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR = 0, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR = 1, + VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR = 2, + VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR = 3, + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCopyAccelerationStructureModeKHR; +typedef VkCopyAccelerationStructureModeKHR VkCopyAccelerationStructureModeNV; + + +typedef enum VkAccelerationStructureMemoryRequirementsTypeKHR { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeKHR; +typedef VkAccelerationStructureMemoryRequirementsTypeKHR VkAccelerationStructureMemoryRequirementsTypeNV; + + +typedef enum VkGeometryFlagBitsKHR { + VK_GEOMETRY_OPAQUE_BIT_KHR = 0x00000001, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR = 0x00000002, + VK_GEOMETRY_OPAQUE_BIT_NV = VK_GEOMETRY_OPAQUE_BIT_KHR, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryFlagBitsKHR; +typedef VkFlags VkGeometryFlagsKHR; +typedef VkGeometryFlagsKHR VkGeometryFlagsNV; + +typedef VkGeometryFlagBitsKHR VkGeometryFlagBitsNV; + + +typedef enum VkGeometryInstanceFlagBitsKHR { + VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR = 0x00000001, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = 0x00000002, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR = 0x00000004, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR = 0x00000008, + VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryInstanceFlagBitsKHR; +typedef VkFlags VkGeometryInstanceFlagsKHR; +typedef VkGeometryInstanceFlagsKHR VkGeometryInstanceFlagsNV; + +typedef VkGeometryInstanceFlagBitsKHR VkGeometryInstanceFlagBitsNV; + + +typedef enum VkBuildAccelerationStructureFlagBitsKHR { + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR = 0x00000001, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR = 0x00000002, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR = 0x00000004, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR = 0x00000008, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR = 0x00000010, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureFlagBitsKHR; +typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +typedef VkBuildAccelerationStructureFlagsKHR VkBuildAccelerationStructureFlagsNV; + +typedef VkBuildAccelerationStructureFlagBitsKHR VkBuildAccelerationStructureFlagBitsNV; -typedef enum VkBuildAccelerationStructureFlagBitsNV { - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010, - VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkBuildAccelerationStructureFlagBitsNV; -typedef VkFlags VkBuildAccelerationStructureFlagsNV; typedef struct VkRayTracingShaderGroupCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkRayTracingShaderGroupTypeNV type; - uint32_t generalShader; - uint32_t closestHitShader; - uint32_t anyHitShader; - uint32_t intersectionShader; + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; } VkRayTracingShaderGroupCreateInfoNV; typedef struct VkRayTracingPipelineCreateInfoNV { @@ -8590,11 +9128,11 @@ typedef struct VkGeometryDataNV { } VkGeometryDataNV; typedef struct VkGeometryNV { - VkStructureType sType; - const void* pNext; - VkGeometryTypeNV geometryType; - VkGeometryDataNV geometry; - VkGeometryFlagsNV flags; + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsKHR flags; } VkGeometryNV; typedef struct VkAccelerationStructureInfoNV { @@ -8614,22 +9152,26 @@ typedef struct VkAccelerationStructureCreateInfoNV { VkAccelerationStructureInfoNV info; } VkAccelerationStructureCreateInfoNV; -typedef struct VkBindAccelerationStructureMemoryInfoNV { - VkStructureType sType; - const void* pNext; - VkAccelerationStructureNV accelerationStructure; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - uint32_t deviceIndexCount; - const uint32_t* pDeviceIndices; -} VkBindAccelerationStructureMemoryInfoNV; +typedef struct VkBindAccelerationStructureMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoKHR; -typedef struct VkWriteDescriptorSetAccelerationStructureNV { - VkStructureType sType; - const void* pNext; - uint32_t accelerationStructureCount; - const VkAccelerationStructureNV* pAccelerationStructures; -} VkWriteDescriptorSetAccelerationStructureNV; +typedef VkBindAccelerationStructureMemoryInfoKHR VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkWriteDescriptorSetAccelerationStructureKHR { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureKHR* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureKHR; + +typedef VkWriteDescriptorSetAccelerationStructureKHR VkWriteDescriptorSetAccelerationStructureNV; typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { VkStructureType sType; @@ -8651,17 +9193,49 @@ typedef struct VkPhysicalDeviceRayTracingPropertiesNV { uint32_t maxDescriptorSetAccelerationStructures; } VkPhysicalDeviceRayTracingPropertiesNV; +typedef struct VkTransformMatrixKHR { + float matrix[3][4]; +} VkTransformMatrixKHR; + +typedef VkTransformMatrixKHR VkTransformMatrixNV; + +typedef struct VkAabbPositionsKHR { + float minX; + float minY; + float minZ; + float maxX; + float maxY; + float maxZ; +} VkAabbPositionsKHR; + +typedef VkAabbPositionsKHR VkAabbPositionsNV; + +typedef struct VkAccelerationStructureInstanceKHR { + VkTransformMatrixKHR transform; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureInstanceKHR; + +typedef VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; + typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); -typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks* pAllocator); typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); -typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); -typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); -typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode); +typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryKHR)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoKHR* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoKHR* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureKHR dst, VkAccelerationStructureKHR src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureKHR dst, VkAccelerationStructureKHR src, VkCopyAccelerationStructureModeKHR mode); typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); -typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); #ifndef VK_NO_PROTOTYPES @@ -8671,9 +9245,14 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV( const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureKHR( + VkDevice device, + VkAccelerationStructureKHR accelerationStructure, + const VkAllocationCallbacks* pAllocator); + VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV( VkDevice device, - VkAccelerationStructureNV accelerationStructure, + VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( @@ -8681,10 +9260,15 @@ VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); +VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryKHR( + VkDevice device, + uint32_t bindInfoCount, + const VkBindAccelerationStructureMemoryInfoKHR* pBindInfos); + VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV( VkDevice device, uint32_t bindInfoCount, - const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); + const VkBindAccelerationStructureMemoryInfoKHR* pBindInfos); VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( VkCommandBuffer commandBuffer, @@ -8692,16 +9276,16 @@ VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, - VkAccelerationStructureNV dst, - VkAccelerationStructureNV src, + VkAccelerationStructureKHR dst, + VkAccelerationStructureKHR src, VkBuffer scratch, VkDeviceSize scratchOffset); VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV( VkCommandBuffer commandBuffer, - VkAccelerationStructureNV dst, - VkAccelerationStructureNV src, - VkCopyAccelerationStructureModeNV mode); + VkAccelerationStructureKHR dst, + VkAccelerationStructureKHR src, + VkCopyAccelerationStructureModeKHR mode); VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV( VkCommandBuffer commandBuffer, @@ -8728,6 +9312,14 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV( const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( VkDevice device, VkPipeline pipeline, @@ -8738,14 +9330,22 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV( VkDevice device, - VkAccelerationStructureNV accelerationStructure, + VkAccelerationStructureKHR accelerationStructure, size_t dataSize, void* pData); +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesKHR( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); + VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV( VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, - const VkAccelerationStructureNV* pAccelerationStructures, + const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); @@ -8775,7 +9375,7 @@ typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { #define VK_EXT_filter_cubic 1 -#define VK_EXT_FILTER_CUBIC_SPEC_VERSION 2 +#define VK_EXT_FILTER_CUBIC_SPEC_VERSION 3 #define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" typedef struct VkPhysicalDeviceImageViewImageFormatInfoEXT { VkStructureType sType; @@ -8787,11 +9387,16 @@ typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { VkStructureType sType; void* pNext; VkBool32 filterCubic; - VkBool32 filterCubicMinmax ; + VkBool32 filterCubicMinmax; } VkFilterCubicImageViewImageFormatPropertiesEXT; +#define VK_QCOM_render_pass_shader_resolve 1 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION 4 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME "VK_QCOM_render_pass_shader_resolve" + + #define VK_EXT_global_priority 1 #define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 #define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" @@ -8801,9 +9406,6 @@ typedef enum VkQueueGlobalPriorityEXT { VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024, - VK_QUEUE_GLOBAL_PRIORITY_BEGIN_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT, - VK_QUEUE_GLOBAL_PRIORITY_END_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT, - VK_QUEUE_GLOBAL_PRIORITY_RANGE_SIZE_EXT = (VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT + 1), VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_EXT = 0x7FFFFFFF } VkQueueGlobalPriorityEXT; typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT { @@ -8887,9 +9489,6 @@ typedef enum VkTimeDomainEXT { VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, - VK_TIME_DOMAIN_BEGIN_RANGE_EXT = VK_TIME_DOMAIN_DEVICE_EXT, - VK_TIME_DOMAIN_END_RANGE_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT, - VK_TIME_DOMAIN_RANGE_SIZE_EXT = (VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT - VK_TIME_DOMAIN_DEVICE_EXT + 1), VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF } VkTimeDomainEXT; typedef struct VkCalibratedTimestampInfoEXT { @@ -8948,9 +9547,6 @@ typedef enum VkMemoryOverallocationBehaviorAMD { VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_BEGIN_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_END_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_RANGE_SIZE_AMD = (VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD + 1), VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF } VkMemoryOverallocationBehaviorAMD; typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { @@ -9188,40 +9784,28 @@ typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { #define VK_INTEL_performance_query 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) -#define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 1 +#define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 2 #define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" typedef enum VkPerformanceConfigurationTypeINTEL { VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, - VK_PERFORMANCE_CONFIGURATION_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL, - VK_PERFORMANCE_CONFIGURATION_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL, - VK_PERFORMANCE_CONFIGURATION_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL - VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL + 1), VK_PERFORMANCE_CONFIGURATION_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceConfigurationTypeINTEL; typedef enum VkQueryPoolSamplingModeINTEL { VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, - VK_QUERY_POOL_SAMPLING_MODE_BEGIN_RANGE_INTEL = VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL, - VK_QUERY_POOL_SAMPLING_MODE_END_RANGE_INTEL = VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL, - VK_QUERY_POOL_SAMPLING_MODE_RANGE_SIZE_INTEL = (VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL - VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL + 1), VK_QUERY_POOL_SAMPLING_MODE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkQueryPoolSamplingModeINTEL; typedef enum VkPerformanceOverrideTypeINTEL { VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, - VK_PERFORMANCE_OVERRIDE_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL, - VK_PERFORMANCE_OVERRIDE_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL, - VK_PERFORMANCE_OVERRIDE_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL - VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL + 1), VK_PERFORMANCE_OVERRIDE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceOverrideTypeINTEL; typedef enum VkPerformanceParameterTypeINTEL { VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, - VK_PERFORMANCE_PARAMETER_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL, - VK_PERFORMANCE_PARAMETER_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL, - VK_PERFORMANCE_PARAMETER_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL - VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL + 1), VK_PERFORMANCE_PARAMETER_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceParameterTypeINTEL; @@ -9231,9 +9815,6 @@ typedef enum VkPerformanceValueTypeINTEL { VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, - VK_PERFORMANCE_VALUE_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL, - VK_PERFORMANCE_VALUE_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL, - VK_PERFORMANCE_VALUE_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL - VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL + 1), VK_PERFORMANCE_VALUE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceValueTypeINTEL; typedef union VkPerformanceValueDataINTEL { @@ -9255,11 +9836,13 @@ typedef struct VkInitializePerformanceApiInfoINTEL { void* pUserData; } VkInitializePerformanceApiInfoINTEL; -typedef struct VkQueryPoolCreateInfoINTEL { +typedef struct VkQueryPoolPerformanceQueryCreateInfoINTEL { VkStructureType sType; const void* pNext; VkQueryPoolSamplingModeINTEL performanceCountersSampling; -} VkQueryPoolCreateInfoINTEL; +} VkQueryPoolPerformanceQueryCreateInfoINTEL; + +typedef VkQueryPoolPerformanceQueryCreateInfoINTEL VkQueryPoolCreateInfoINTEL; typedef struct VkPerformanceMarkerInfoINTEL { VkStructureType sType; @@ -9406,11 +9989,7 @@ typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { #define VK_EXT_scalar_block_layout 1 #define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 #define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" -typedef struct VkPhysicalDeviceScalarBlockLayoutFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 scalarBlockLayout; -} VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; +typedef VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; @@ -9520,7 +10099,6 @@ typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { #define VK_EXT_buffer_device_address 1 -typedef uint64_t VkDeviceAddress; #define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 #define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { @@ -9533,11 +10111,7 @@ typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { typedef VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; -typedef struct VkBufferDeviceAddressInfoEXT { - VkStructureType sType; - const void* pNext; - VkBuffer buffer; -} VkBufferDeviceAddressInfoEXT; +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoEXT; typedef struct VkBufferDeviceAddressCreateInfoEXT { VkStructureType sType; @@ -9545,37 +10119,66 @@ typedef struct VkBufferDeviceAddressCreateInfoEXT { VkDeviceAddress deviceAddress; } VkBufferDeviceAddressCreateInfoEXT; -typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT( VkDevice device, - const VkBufferDeviceAddressInfoEXT* pInfo); + const VkBufferDeviceAddressInfo* pInfo); +#endif + + +#define VK_EXT_tooling_info 1 +#define VK_EXT_TOOLING_INFO_SPEC_VERSION 1 +#define VK_EXT_TOOLING_INFO_EXTENSION_NAME "VK_EXT_tooling_info" + +typedef enum VkToolPurposeFlagBitsEXT { + VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = 0x00000001, + VK_TOOL_PURPOSE_PROFILING_BIT_EXT = 0x00000002, + VK_TOOL_PURPOSE_TRACING_BIT_EXT = 0x00000004, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = 0x00000008, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = 0x00000010, + VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 0x00000020, + VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 0x00000040, + VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkToolPurposeFlagBitsEXT; +typedef VkFlags VkToolPurposeFlagsEXT; +typedef struct VkPhysicalDeviceToolPropertiesEXT { + VkStructureType sType; + void* pNext; + char name[VK_MAX_EXTENSION_NAME_SIZE]; + char version[VK_MAX_EXTENSION_NAME_SIZE]; + VkToolPurposeFlagsEXT purposes; + char description[VK_MAX_DESCRIPTION_SIZE]; + char layer[VK_MAX_EXTENSION_NAME_SIZE]; +} VkPhysicalDeviceToolPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolPropertiesEXT* pToolProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolPropertiesEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pToolCount, + VkPhysicalDeviceToolPropertiesEXT* pToolProperties); #endif #define VK_EXT_separate_stencil_usage 1 #define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 #define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" -typedef struct VkImageStencilUsageCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkImageUsageFlags stencilUsage; -} VkImageStencilUsageCreateInfoEXT; +typedef VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; #define VK_EXT_validation_features 1 -#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 2 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 3 #define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" typedef enum VkValidationFeatureEnableEXT { VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2, - VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, - VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, - VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), + VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3, VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationFeatureEnableEXT; @@ -9587,9 +10190,6 @@ typedef enum VkValidationFeatureDisableEXT { VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, - VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, - VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, - VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationFeatureDisableEXT; typedef struct VkValidationFeaturesEXT { @@ -9619,9 +10219,6 @@ typedef enum VkComponentTypeNV { VK_COMPONENT_TYPE_UINT16_NV = 8, VK_COMPONENT_TYPE_UINT32_NV = 9, VK_COMPONENT_TYPE_UINT64_NV = 10, - VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, - VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, - VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF } VkComponentTypeNV; @@ -9630,9 +10227,6 @@ typedef enum VkScopeNV { VK_SCOPE_WORKGROUP_NV = 2, VK_SCOPE_SUBGROUP_NV = 3, VK_SCOPE_QUEUE_FAMILY_NV = 5, - VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, - VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, - VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF } VkScopeNV; typedef struct VkCooperativeMatrixPropertiesNV { @@ -9678,9 +10272,6 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesNV( typedef enum VkCoverageReductionModeNV { VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, - VK_COVERAGE_REDUCTION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_REDUCTION_MODE_MERGE_NV, - VK_COVERAGE_REDUCTION_MODE_END_RANGE_NV = VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV, - VK_COVERAGE_REDUCTION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV - VK_COVERAGE_REDUCTION_MODE_MERGE_NV + 1), VK_COVERAGE_REDUCTION_MODE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoverageReductionModeNV; typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; @@ -9770,9 +10361,6 @@ typedef enum VkLineRasterizationModeEXT { VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = 1, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = 2, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = 3, - VK_LINE_RASTERIZATION_MODE_BEGIN_RANGE_EXT = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, - VK_LINE_RASTERIZATION_MODE_END_RANGE_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, - VK_LINE_RASTERIZATION_MODE_RANGE_SIZE_EXT = (VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT - VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT + 1), VK_LINE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF } VkLineRasterizationModeEXT; typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT { @@ -9814,11 +10402,7 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleEXT( #define VK_EXT_host_query_reset 1 #define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 #define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" -typedef struct VkPhysicalDeviceHostQueryResetFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 hostQueryReset; -} VkPhysicalDeviceHostQueryResetFeaturesEXT; +typedef VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; typedef void (VKAPI_PTR *PFN_vkResetQueryPoolEXT)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); @@ -9853,6 +10437,196 @@ typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT { +#define VK_NV_device_generated_commands 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) +#define VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 +#define VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NV_device_generated_commands" + +typedef enum VkIndirectCommandsTokenTypeNV { + VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV = 2, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV = 3, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeNV; + +typedef enum VkIndirectStateFlagBitsNV { + VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 0x00000001, + VK_INDIRECT_STATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectStateFlagBitsNV; +typedef VkFlags VkIndirectStateFlagsNV; + +typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 0x00000001, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 0x00000002, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 0x00000004, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsNV; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxGraphicsShaderGroupCount; + uint32_t maxIndirectSequenceCount; + uint32_t maxIndirectCommandsTokenCount; + uint32_t maxIndirectCommandsStreamCount; + uint32_t maxIndirectCommandsTokenOffset; + uint32_t maxIndirectCommandsStreamStride; + uint32_t minSequencesCountBufferOffsetAlignment; + uint32_t minSequencesIndexBufferOffsetAlignment; + uint32_t minIndirectCommandsBufferOffsetAlignment; +} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV; + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 deviceGeneratedCommands; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; + +typedef struct VkGraphicsShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; +} VkGraphicsShaderGroupCreateInfoNV; + +typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t groupCount; + const VkGraphicsShaderGroupCreateInfoNV* pGroups; + uint32_t pipelineCount; + const VkPipeline* pPipelines; +} VkGraphicsPipelineShaderGroupsCreateInfoNV; + +typedef struct VkBindShaderGroupIndirectCommandNV { + uint32_t groupIndex; +} VkBindShaderGroupIndirectCommandNV; + +typedef struct VkBindIndexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandNV; + +typedef struct VkBindVertexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandNV; + +typedef struct VkSetStateFlagsIndirectCommandNV { + uint32_t data; +} VkSetStateFlagsIndirectCommandNV; + +typedef struct VkIndirectCommandsStreamNV { + VkBuffer buffer; + VkDeviceSize offset; +} VkIndirectCommandsStreamNV; + +typedef struct VkIndirectCommandsLayoutTokenNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsTokenTypeNV tokenType; + uint32_t stream; + uint32_t offset; + uint32_t vertexBindingUnit; + VkBool32 vertexDynamicStride; + VkPipelineLayout pushconstantPipelineLayout; + VkShaderStageFlags pushconstantShaderStageFlags; + uint32_t pushconstantOffset; + uint32_t pushconstantSize; + VkIndirectStateFlagsNV indirectStateFlags; + uint32_t indexTypeCount; + const VkIndexType* pIndexTypes; + const uint32_t* pIndexTypeValues; +} VkIndirectCommandsLayoutTokenNV; + +typedef struct VkIndirectCommandsLayoutCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsLayoutUsageFlagsNV flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenNV* pTokens; + uint32_t streamCount; + const uint32_t* pStreamStrides; +} VkIndirectCommandsLayoutCreateInfoNV; + +typedef struct VkGeneratedCommandsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t streamCount; + const VkIndirectCommandsStreamNV* pStreams; + uint32_t sequencesCount; + VkBuffer preprocessBuffer; + VkDeviceSize preprocessOffset; + VkDeviceSize preprocessSize; + VkBuffer sequencesCountBuffer; + VkDeviceSize sequencesCountOffset; + VkBuffer sequencesIndexBuffer; + VkDeviceSize sequencesIndexOffset; +} VkGeneratedCommandsInfoNV; + +typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t maxSequencesCount; +} VkGeneratedCommandsMemoryRequirementsInfoNV; + +typedef void (VKAPI_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex); +typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNV)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNV)(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetGeneratedCommandsMemoryRequirementsNV( + VkDevice device, + const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkCmdPreprocessGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + VkBool32 isPreprocessed, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipelineShaderGroupNV( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline, + uint32_t groupIndex); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNV( + VkDevice device, + const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNV( + VkDevice device, + VkIndirectCommandsLayoutNV indirectCommandsLayout, + const VkAllocationCallbacks* pAllocator); +#endif + + #define VK_EXT_texel_buffer_alignment 1 #define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 #define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" @@ -9873,10 +10647,174 @@ typedef struct VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT { +#define VK_QCOM_render_pass_transform 1 +#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 1 +#define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" +typedef struct VkRenderPassTransformBeginInfoQCOM { + VkStructureType sType; + void* pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkRenderPassTransformBeginInfoQCOM; + +typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { + VkStructureType sType; + void* pNext; + VkSurfaceTransformFlagBitsKHR transform; + VkRect2D renderArea; +} VkCommandBufferInheritanceRenderPassTransformInfoQCOM; + + + +#define VK_EXT_robustness2 1 +#define VK_EXT_ROBUSTNESS_2_SPEC_VERSION 1 +#define VK_EXT_ROBUSTNESS_2_EXTENSION_NAME "VK_EXT_robustness2" +typedef struct VkPhysicalDeviceRobustness2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 robustBufferAccess2; + VkBool32 robustImageAccess2; + VkBool32 nullDescriptor; +} VkPhysicalDeviceRobustness2FeaturesEXT; + +typedef struct VkPhysicalDeviceRobustness2PropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize robustStorageBufferAccessSizeAlignment; + VkDeviceSize robustUniformBufferAccessSizeAlignment; +} VkPhysicalDeviceRobustness2PropertiesEXT; + + + +#define VK_EXT_custom_border_color 1 +#define VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION 12 +#define VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME "VK_EXT_custom_border_color" +typedef struct VkSamplerCustomBorderColorCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkClearColorValue customBorderColor; + VkFormat format; +} VkSamplerCustomBorderColorCreateInfoEXT; + +typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxCustomBorderColorSamplers; +} VkPhysicalDeviceCustomBorderColorPropertiesEXT; + +typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 customBorderColors; + VkBool32 customBorderColorWithoutFormat; +} VkPhysicalDeviceCustomBorderColorFeaturesEXT; + + + #define VK_GOOGLE_user_type 1 #define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1 #define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type" + +#define VK_EXT_private_data 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlotEXT) +#define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 +#define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" + +typedef enum VkPrivateDataSlotCreateFlagBitsEXT { + VK_PRIVATE_DATA_SLOT_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPrivateDataSlotCreateFlagBitsEXT; +typedef VkFlags VkPrivateDataSlotCreateFlagsEXT; +typedef struct VkPhysicalDevicePrivateDataFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 privateData; +} VkPhysicalDevicePrivateDataFeaturesEXT; + +typedef struct VkDevicePrivateDataCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t privateDataSlotRequestCount; +} VkDevicePrivateDataCreateInfoEXT; + +typedef struct VkPrivateDataSlotCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPrivateDataSlotCreateFlagsEXT flags; +} VkPrivateDataSlotCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlotEXT* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlotEXT privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlotEXT( + VkDevice device, + const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlotEXT* pPrivateDataSlot); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlotEXT( + VkDevice device, + VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t data); + +VKAPI_ATTR void VKAPI_CALL vkGetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t* pData); +#endif + + +#define VK_EXT_pipeline_creation_cache_control 1 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelineCreationCacheControl; +} VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; + + + +#define VK_NV_device_diagnostics_config 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config" + +typedef enum VkDeviceDiagnosticsConfigFlagBitsNV { + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 0x00000001, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 0x00000002, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 0x00000004, + VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkDeviceDiagnosticsConfigFlagBitsNV; +typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 diagnosticsConfig; +} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; + +typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceDiagnosticsConfigFlagsNV flags; +} VkDeviceDiagnosticsConfigCreateInfoNV; + + + +#define VK_QCOM_render_pass_store_ops 1 +#define VK_QCOM_render_pass_store_ops_SPEC_VERSION 2 +#define VK_QCOM_render_pass_store_ops_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" + #ifdef __cplusplus } #endif diff --git a/ext/vulkan/vulkan_fuchsia.h b/ext/vulkan/vulkan_fuchsia.h index 81ebe55d31..e97901480a 100644 --- a/ext/vulkan/vulkan_fuchsia.h +++ b/ext/vulkan/vulkan_fuchsia.h @@ -2,7 +2,7 @@ #define VULKAN_FUCHSIA_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_ggp.h b/ext/vulkan/vulkan_ggp.h index fd306131c3..09b337e6dd 100644 --- a/ext/vulkan/vulkan_ggp.h +++ b/ext/vulkan/vulkan_ggp.h @@ -2,7 +2,7 @@ #define VULKAN_GGP_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_ios.h b/ext/vulkan/vulkan_ios.h index 72ef1a8a82..9f81999381 100644 --- a/ext/vulkan/vulkan_ios.h +++ b/ext/vulkan/vulkan_ios.h @@ -2,7 +2,7 @@ #define VULKAN_IOS_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_macos.h b/ext/vulkan/vulkan_macos.h index e6e5deaa36..8c9684778b 100644 --- a/ext/vulkan/vulkan_macos.h +++ b/ext/vulkan/vulkan_macos.h @@ -2,7 +2,7 @@ #define VULKAN_MACOS_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_metal.h b/ext/vulkan/vulkan_metal.h index 3dec68c771..c85d24387f 100644 --- a/ext/vulkan/vulkan_metal.h +++ b/ext/vulkan/vulkan_metal.h @@ -2,7 +2,7 @@ #define VULKAN_METAL_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_vi.h b/ext/vulkan/vulkan_vi.h index 6fb66f9dd2..ee877d9b94 100644 --- a/ext/vulkan/vulkan_vi.h +++ b/ext/vulkan/vulkan_vi.h @@ -2,7 +2,7 @@ #define VULKAN_VI_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_wayland.h b/ext/vulkan/vulkan_wayland.h index 599d05b24a..5278c188b5 100644 --- a/ext/vulkan/vulkan_wayland.h +++ b/ext/vulkan/vulkan_wayland.h @@ -2,7 +2,7 @@ #define VULKAN_WAYLAND_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_win32.h b/ext/vulkan/vulkan_win32.h index 20a1dc0e58..4408d26de4 100644 --- a/ext/vulkan/vulkan_win32.h +++ b/ext/vulkan/vulkan_win32.h @@ -2,7 +2,7 @@ #define VULKAN_WIN32_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -272,9 +272,6 @@ typedef enum VkFullScreenExclusiveEXT { VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1, VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2, VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3, - VK_FULL_SCREEN_EXCLUSIVE_BEGIN_RANGE_EXT = VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT, - VK_FULL_SCREEN_EXCLUSIVE_END_RANGE_EXT = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT, - VK_FULL_SCREEN_EXCLUSIVE_RANGE_SIZE_EXT = (VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT - VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT + 1), VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF } VkFullScreenExclusiveEXT; typedef struct VkSurfaceFullScreenExclusiveInfoEXT { diff --git a/ext/vulkan/vulkan_xcb.h b/ext/vulkan/vulkan_xcb.h index 4cc0bc0cec..43d1407a86 100644 --- a/ext/vulkan/vulkan_xcb.h +++ b/ext/vulkan/vulkan_xcb.h @@ -2,7 +2,7 @@ #define VULKAN_XCB_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_xlib.h b/ext/vulkan/vulkan_xlib.h index ee2b48accb..7beada9257 100644 --- a/ext/vulkan/vulkan_xlib.h +++ b/ext/vulkan/vulkan_xlib.h @@ -2,7 +2,7 @@ #define VULKAN_XLIB_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_xlib_xrandr.h b/ext/vulkan/vulkan_xlib_xrandr.h index 08c4fd729c..8e9e150d84 100644 --- a/ext/vulkan/vulkan_xlib_xrandr.h +++ b/ext/vulkan/vulkan_xlib_xrandr.h @@ -2,7 +2,7 @@ #define VULKAN_XLIB_XRANDR_H_ 1 /* -** Copyright (c) 2015-2019 The Khronos Group Inc. +** Copyright (c) 2015-2020 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/xxhash.c b/ext/xxhash.c index 5149945e44..7807719256 100644 --- a/ext/xxhash.c +++ b/ext/xxhash.c @@ -1,944 +1,43 @@ /* -xxHash - Fast Hash algorithm -Copyright (C) 2012-2014, Yann Collet. -BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -You can contact the author at : -- xxHash source repository : http://code.google.com/p/xxhash/ -- public discussion board : https://groups.google.com/forum/#!forum/lz4c -*/ + * xxHash - Extremely Fast Hash algorithm + * Copyright (C) 2012-2020 Yann Collet + * + * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at: + * - xxHash homepage: https://www.xxhash.com + * - xxHash source repository: https://github.com/Cyan4973/xxHash + */ -//************************************** -// Tuning parameters -//************************************** -// Unaligned memory access is automatically enabled for "common" CPU, such as x86. -// For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected. -// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance. -// You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32). + /* + * xxhash.c instantiates functions defined in xxhash.h + */ -#include "ppsspp_config.h" +#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ +#define XXH_IMPLEMENTATION /* access definitions */ -// ector NOTE: For whatever reason ARM is unhappy about this on Android. -#if !defined(IOS) && !defined(ANDROID) && (defined(ARM) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)) -# define XXH_USE_UNALIGNED_ACCESS 1 -#endif - -// XXH_ACCEPT_NULL_INPUT_POINTER : -// If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer. -// When this option is enabled, xxHash output for null input pointers will be the same as a null-length input. -// This option has a very small performance cost (only measurable on small inputs). -// By default, this option is disabled. To enable it, uncomment below define : -//#define XXH_ACCEPT_NULL_INPUT_POINTER 1 - -// XXH_FORCE_NATIVE_FORMAT : -// By default, xxHash library provides endian-independant Hash values, based on little-endian convention. -// Results are therefore identical for little-endian and big-endian CPU. -// This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. -// Should endian-independance be of no importance for your application, you may set the #define below to 1. -// It will improve speed for Big-endian CPU. -// This option has no impact on Little_Endian CPU. -#define XXH_FORCE_NATIVE_FORMAT 1 - - -//************************************** -// Compiler Specific Options -//************************************** -// Disable some Visual warning messages -#ifdef _MSC_VER // Visual Studio -# pragma warning(disable : 4127) // disable: C4127: conditional expression is constant -#endif - -#ifdef _MSC_VER // Visual Studio -# define FORCE_INLINE static __forceinline -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -#endif - -//************************************** -// Includes & Memory related functions -//************************************** #include "xxhash.h" -// Modify the local functions below should you wish to use some other memory routines -// for malloc(), free() -#include -FORCE_INLINE void* XXH_malloc(size_t s) -{ - return malloc(s); -} -FORCE_INLINE void XXH_free (void* p) -{ - free(p); -} -// for memcpy() -#include -FORCE_INLINE void* XXH_memcpy(void* dest, const void* src, size_t size) -{ - return memcpy(dest,src,size); -} - - -//************************************** -// Basic Types -//************************************** -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99 -# include -typedef uint8_t BYTE; -typedef uint16_t U16; -typedef uint32_t U32; -typedef int32_t S32; -typedef uint64_t U64; -#else -typedef unsigned char BYTE; -typedef unsigned short U16; -typedef unsigned int U32; -typedef signed int S32; -typedef unsigned long long U64; -#endif - -#if defined(__GNUC__) && !defined(XXH_USE_UNALIGNED_ACCESS) -# define _PACKED __attribute__ ((packed)) -#else -# define _PACKED -#endif - -#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__) -# ifdef __IBMC__ -# pragma pack(1) -# else -# pragma pack(push, 1) -# endif -#endif - -typedef struct _U32_S -{ - U32 v; -} _PACKED U32_S; -typedef struct _U64_S -{ - U64 v; -} _PACKED U64_S; - -#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__) -# pragma pack(pop) -#endif - -#define A32(x) (((U32_S *)(x))->v) -#define A64(x) (((U64_S *)(x))->v) - - -//*************************************** -// Compiler-specific Functions and Macros -//*************************************** -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) - -// Note : although _rotl exists for minGW (GCC under windows), performance seems poor -#if defined(_MSC_VER) -# define XXH_rotl32(x,r) _rotl(x,r) -# define XXH_rotl64(x,r) _rotl64(x,r) -#else -# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) -# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) -#endif - -#if defined(_MSC_VER) // Visual Studio -# define XXH_swap32 _byteswap_ulong -# define XXH_swap64 _byteswap_uint64 -#elif GCC_VERSION >= 403 -# define XXH_swap32 __builtin_bswap32 -# define XXH_swap64 __builtin_bswap64 -#else -static inline U32 XXH_swap32 (U32 x) -{ - return ((x << 24) & 0xff000000 ) | - ((x << 8) & 0x00ff0000 ) | - ((x >> 8) & 0x0000ff00 ) | - ((x >> 24) & 0x000000ff ); -} -static inline U64 XXH_swap64 (U64 x) -{ - return ((x << 56) & 0xff00000000000000ULL) | - ((x << 40) & 0x00ff000000000000ULL) | - ((x << 24) & 0x0000ff0000000000ULL) | - ((x << 8) & 0x000000ff00000000ULL) | - ((x >> 8) & 0x00000000ff000000ULL) | - ((x >> 24) & 0x0000000000ff0000ULL) | - ((x >> 40) & 0x000000000000ff00ULL) | - ((x >> 56) & 0x00000000000000ffULL); -} -#endif - - -//************************************** -// Constants -//************************************** -#define PRIME32_1 2654435761U -#define PRIME32_2 2246822519U -#define PRIME32_3 3266489917U -#define PRIME32_4 668265263U -#define PRIME32_5 374761393U - -#define PRIME64_1 11400714785074694791ULL -#define PRIME64_2 14029467366897019727ULL -#define PRIME64_3 1609587929392839161ULL -#define PRIME64_4 9650029242287828579ULL -#define PRIME64_5 2870177450012600261ULL - -//************************************** -// Architecture Macros -//************************************** -typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; -#ifndef XXH_CPU_LITTLE_ENDIAN // It is possible to define XXH_CPU_LITTLE_ENDIAN externally, for example using a compiler switch -static const int one = 1; -# define XXH_CPU_LITTLE_ENDIAN (*(char*)(&one)) -#endif - - -//************************************** -// Macros -//************************************** -#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } // use only *after* variable declarations - - -//**************************** -// Memory reads -//**************************** -typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; - -FORCE_INLINE U32 XXH_readLE32_align(const U32* ptr, XXH_endianess endian, XXH_alignment align) -{ - if (align==XXH_unaligned) - return endian==XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr)); - else - return endian==XXH_littleEndian ? *ptr : XXH_swap32(*ptr); -} - -FORCE_INLINE U32 XXH_readLE32(const U32* ptr, XXH_endianess endian) -{ - return XXH_readLE32_align(ptr, endian, XXH_unaligned); -} - -FORCE_INLINE U64 XXH_readLE64_align(const U64* ptr, XXH_endianess endian, XXH_alignment align) -{ - if (align==XXH_unaligned) - return endian==XXH_littleEndian ? A64(ptr) : XXH_swap64(A64(ptr)); - else - return endian==XXH_littleEndian ? *ptr : XXH_swap64(*ptr); -} - -FORCE_INLINE U64 XXH_readLE64(const U64* ptr, XXH_endianess endian) -{ - return XXH_readLE64_align(ptr, endian, XXH_unaligned); -} - - -//**************************** -// Simple Hash Functions -//**************************** -FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) -{ - const BYTE* p = (const BYTE*)input; - const BYTE* bEnd = p + len; - U32 h32; -#define XXH_get32bits(p) XXH_readLE32_align((const U32*)p, endian, align) - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (p==NULL) - { - len=0; - bEnd=p=(const BYTE*)(size_t)16; - } -#endif - - if (len>=16) - { - const BYTE* const limit = bEnd - 16; - U32 v1 = seed + PRIME32_1 + PRIME32_2; - U32 v2 = seed + PRIME32_2; - U32 v3 = seed + 0; - U32 v4 = seed - PRIME32_1; - - do - { -#if defined(ARM) && defined(__GNUC__) - __builtin_prefetch(p + 0xc0, 0, 0); -#endif - v1 += XXH_get32bits(p) * PRIME32_2; - v1 = XXH_rotl32(v1, 13); - v1 *= PRIME32_1; - p+=4; - v2 += XXH_get32bits(p) * PRIME32_2; - v2 = XXH_rotl32(v2, 13); - v2 *= PRIME32_1; - p+=4; - v3 += XXH_get32bits(p) * PRIME32_2; - v3 = XXH_rotl32(v3, 13); - v3 *= PRIME32_1; - p+=4; - v4 += XXH_get32bits(p) * PRIME32_2; - v4 = XXH_rotl32(v4, 13); - v4 *= PRIME32_1; - p+=4; - } - while (p<=limit); - - h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); - } - else - { - h32 = seed + PRIME32_5; - } - - h32 += (U32) len; - - while (p+4<=bEnd) - { - h32 += XXH_get32bits(p) * PRIME32_3; - h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; - p+=4; - } - - while (p> 15; - h32 *= PRIME32_2; - h32 ^= h32 >> 13; - h32 *= PRIME32_3; - h32 ^= h32 >> 16; - - return h32; -} - - -unsigned int XXH32 (const void* input, size_t len, unsigned seed) -{ -#if 0 - // Simple version, good for code maintenance, but unfortunately slow for small inputs - XXH32_state_t state; - XXH32_reset(&state, seed); - XXH32_update(&state, input, len); - return XXH32_digest(&state); -#else - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - -# if !defined(XXH_USE_UNALIGNED_ACCESS) - if ((((size_t)input) & 3) == 0) // Input is aligned, let's leverage the speed advantage - { - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); - else - return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); - } -# endif - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); - else - return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); -#endif -} - -FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) -{ - const BYTE* p = (const BYTE*)input; - const BYTE* bEnd = p + len; - U64 h64; -#define XXH_get64bits(p) XXH_readLE64_align((const U64*)p, endian, align) - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (p==NULL) - { - len=0; - bEnd=p=(const BYTE*)(size_t)32; - } -#endif - - if (len>=32) - { - const BYTE* const limit = bEnd - 32; - U64 v1 = seed + PRIME64_1 + PRIME64_2; - U64 v2 = seed + PRIME64_2; - U64 v3 = seed + 0; - U64 v4 = seed - PRIME64_1; - - do - { -#if defined(ARM) && defined(__GNUC__) - // TODO: Validate that this helps as it does with XXH32. - __builtin_prefetch(p + 0xc0, 0, 0); -#endif - v1 += XXH_get64bits(p) * PRIME64_2; - p+=8; - v1 = XXH_rotl64(v1, 31); - v1 *= PRIME64_1; - v2 += XXH_get64bits(p) * PRIME64_2; - p+=8; - v2 = XXH_rotl64(v2, 31); - v2 *= PRIME64_1; - v3 += XXH_get64bits(p) * PRIME64_2; - p+=8; - v3 = XXH_rotl64(v3, 31); - v3 *= PRIME64_1; - v4 += XXH_get64bits(p) * PRIME64_2; - p+=8; - v4 = XXH_rotl64(v4, 31); - v4 *= PRIME64_1; - } - while (p<=limit); - - h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); - - v1 *= PRIME64_2; - v1 = XXH_rotl64(v1, 31); - v1 *= PRIME64_1; - h64 ^= v1; - h64 = h64 * PRIME64_1 + PRIME64_4; - - v2 *= PRIME64_2; - v2 = XXH_rotl64(v2, 31); - v2 *= PRIME64_1; - h64 ^= v2; - h64 = h64 * PRIME64_1 + PRIME64_4; - - v3 *= PRIME64_2; - v3 = XXH_rotl64(v3, 31); - v3 *= PRIME64_1; - h64 ^= v3; - h64 = h64 * PRIME64_1 + PRIME64_4; - - v4 *= PRIME64_2; - v4 = XXH_rotl64(v4, 31); - v4 *= PRIME64_1; - h64 ^= v4; - h64 = h64 * PRIME64_1 + PRIME64_4; - } - else - { - h64 = seed + PRIME64_5; - } - - h64 += (U64) len; - - while (p+8<=bEnd) - { - U64 k1 = XXH_get64bits(p); - k1 *= PRIME64_2; - k1 = XXH_rotl64(k1,31); - k1 *= PRIME64_1; - h64 ^= k1; - h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; - p+=8; - } - - if (p+4<=bEnd) - { - h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; - h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; - p+=4; - } - - while (p> 33; - h64 *= PRIME64_2; - h64 ^= h64 >> 29; - h64 *= PRIME64_3; - h64 ^= h64 >> 32; - - return h64; -} - - -unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed) -{ -#if 0 - // Simple version, good for code maintenance, but unfortunately slow for small inputs - XXH64_state_t state; - XXH64_reset(&state, seed); - XXH64_update(&state, input, len); - return XXH64_digest(&state); -#else - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - -# if !defined(XXH_USE_UNALIGNED_ACCESS) - if ((((size_t)input) & 7)==0) // Input is aligned, let's leverage the speed advantage - { - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); - else - return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); - } -# endif - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); - else - return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); -#endif -} - -/**************************************************** - * Advanced Hash Functions -****************************************************/ - -/*** Allocation ***/ -typedef struct -{ - U64 total_len; - U32 seed; - U32 v1; - U32 v2; - U32 v3; - U32 v4; - U32 memsize; - char memory[16]; -} XXH_istate32_t; - -typedef struct -{ - U64 total_len; - U64 seed; - U64 v1; - U64 v2; - U64 v3; - U64 v4; - U32 memsize; - char memory[32]; -} XXH_istate64_t; - - -XXH32_state_t* XXH32_createState(void) -{ - XXH_STATIC_ASSERT(sizeof(XXH32_state_t) >= sizeof(XXH_istate32_t)); // A compilation error here means XXH32_state_t is not large enough - return (XXH32_state_t*)malloc(sizeof(XXH32_state_t)); -} -XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) -{ - free(statePtr); - return XXH_OK; -}; - -XXH64_state_t* XXH64_createState(void) -{ - XXH_STATIC_ASSERT(sizeof(XXH64_state_t) >= sizeof(XXH_istate64_t)); // A compilation error here means XXH64_state_t is not large enough - return (XXH64_state_t*)malloc(sizeof(XXH64_state_t)); -} -XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) -{ - free(statePtr); - return XXH_OK; -}; - - -/*** Hash feed ***/ - -XXH_errorcode XXH32_reset(XXH32_state_t* state_in, U32 seed) -{ - XXH_istate32_t* state = (XXH_istate32_t*) state_in; - state->seed = seed; - state->v1 = seed + PRIME32_1 + PRIME32_2; - state->v2 = seed + PRIME32_2; - state->v3 = seed + 0; - state->v4 = seed - PRIME32_1; - state->total_len = 0; - state->memsize = 0; - return XXH_OK; -} - -XXH_errorcode XXH64_reset(XXH64_state_t* state_in, unsigned long long seed) -{ - XXH_istate64_t* state = (XXH_istate64_t*) state_in; - state->seed = seed; - state->v1 = seed + PRIME64_1 + PRIME64_2; - state->v2 = seed + PRIME64_2; - state->v3 = seed + 0; - state->v4 = seed - PRIME64_1; - state->total_len = 0; - state->memsize = 0; - return XXH_OK; -} - - -FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state_in, const void* input, size_t len, XXH_endianess endian) -{ - XXH_istate32_t* state = (XXH_istate32_t *) state_in; - const BYTE* p = (const BYTE*)input; - const BYTE* const bEnd = p + len; - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (input==NULL) return XXH_ERROR; -#endif - - state->total_len += len; - - if (state->memsize + len < 16) // fill in tmp buffer - { - XXH_memcpy(state->memory + state->memsize, input, len); - state->memsize += (U32)len; - return XXH_OK; - } - - if (state->memsize) // some data left from previous update - { - XXH_memcpy(state->memory + state->memsize, input, 16-state->memsize); - { - const U32* p32 = (const U32*)state->memory; - state->v1 += XXH_readLE32(p32, endian) * PRIME32_2; - state->v1 = XXH_rotl32(state->v1, 13); - state->v1 *= PRIME32_1; - p32++; - state->v2 += XXH_readLE32(p32, endian) * PRIME32_2; - state->v2 = XXH_rotl32(state->v2, 13); - state->v2 *= PRIME32_1; - p32++; - state->v3 += XXH_readLE32(p32, endian) * PRIME32_2; - state->v3 = XXH_rotl32(state->v3, 13); - state->v3 *= PRIME32_1; - p32++; - state->v4 += XXH_readLE32(p32, endian) * PRIME32_2; - state->v4 = XXH_rotl32(state->v4, 13); - state->v4 *= PRIME32_1; - p32++; - } - p += 16-state->memsize; - state->memsize = 0; - } - - if (p <= bEnd-16) - { - const BYTE* const limit = bEnd - 16; - U32 v1 = state->v1; - U32 v2 = state->v2; - U32 v3 = state->v3; - U32 v4 = state->v4; - - do - { - v1 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; - v1 = XXH_rotl32(v1, 13); - v1 *= PRIME32_1; - p+=4; - v2 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; - v2 = XXH_rotl32(v2, 13); - v2 *= PRIME32_1; - p+=4; - v3 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; - v3 = XXH_rotl32(v3, 13); - v3 *= PRIME32_1; - p+=4; - v4 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; - v4 = XXH_rotl32(v4, 13); - v4 *= PRIME32_1; - p+=4; - } - while (p<=limit); - - state->v1 = v1; - state->v2 = v2; - state->v3 = v3; - state->v4 = v4; - } - - if (p < bEnd) - { - XXH_memcpy(state->memory, p, bEnd-p); - state->memsize = (int)(bEnd-p); - } - - return XXH_OK; -} - -XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_update_endian(state_in, input, len, XXH_littleEndian); - else - return XXH32_update_endian(state_in, input, len, XXH_bigEndian); -} - - - -FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state_in, XXH_endianess endian) -{ - XXH_istate32_t* state = (XXH_istate32_t*) state_in; - const BYTE * p = (const BYTE*)state->memory; - BYTE* bEnd = (BYTE*)state->memory + state->memsize; - U32 h32; - - if (state->total_len >= 16) - { - h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18); - } - else - { - h32 = state->seed + PRIME32_5; - } - - h32 += (U32) state->total_len; - - while (p+4<=bEnd) - { - h32 += XXH_readLE32((const U32*)p, endian) * PRIME32_3; - h32 = XXH_rotl32(h32, 17) * PRIME32_4; - p+=4; - } - - while (p> 15; - h32 *= PRIME32_2; - h32 ^= h32 >> 13; - h32 *= PRIME32_3; - h32 ^= h32 >> 16; - - return h32; -} - - -U32 XXH32_digest (const XXH32_state_t* state_in) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_digest_endian(state_in, XXH_littleEndian); - else - return XXH32_digest_endian(state_in, XXH_bigEndian); -} - - -FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state_in, const void* input, size_t len, XXH_endianess endian) -{ - XXH_istate64_t * state = (XXH_istate64_t *) state_in; - const BYTE* p = (const BYTE*)input; - const BYTE* const bEnd = p + len; - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (input==NULL) return XXH_ERROR; -#endif - - state->total_len += len; - - if (state->memsize + len < 32) // fill in tmp buffer - { - XXH_memcpy(state->memory + state->memsize, input, len); - state->memsize += (U32)len; - return XXH_OK; - } - - if (state->memsize) // some data left from previous update - { - XXH_memcpy(state->memory + state->memsize, input, 32-state->memsize); - { - const U64* p64 = (const U64*)state->memory; - state->v1 += XXH_readLE64(p64, endian) * PRIME64_2; - state->v1 = XXH_rotl64(state->v1, 31); - state->v1 *= PRIME64_1; - p64++; - state->v2 += XXH_readLE64(p64, endian) * PRIME64_2; - state->v2 = XXH_rotl64(state->v2, 31); - state->v2 *= PRIME64_1; - p64++; - state->v3 += XXH_readLE64(p64, endian) * PRIME64_2; - state->v3 = XXH_rotl64(state->v3, 31); - state->v3 *= PRIME64_1; - p64++; - state->v4 += XXH_readLE64(p64, endian) * PRIME64_2; - state->v4 = XXH_rotl64(state->v4, 31); - state->v4 *= PRIME64_1; - p64++; - } - p += 32-state->memsize; - state->memsize = 0; - } - - if (p+32 <= bEnd) - { - const BYTE* const limit = bEnd - 32; - U64 v1 = state->v1; - U64 v2 = state->v2; - U64 v3 = state->v3; - U64 v4 = state->v4; - - do - { - v1 += XXH_readLE64((const U64*)p, endian) * PRIME64_2; - v1 = XXH_rotl64(v1, 31); - v1 *= PRIME64_1; - p+=8; - v2 += XXH_readLE64((const U64*)p, endian) * PRIME64_2; - v2 = XXH_rotl64(v2, 31); - v2 *= PRIME64_1; - p+=8; - v3 += XXH_readLE64((const U64*)p, endian) * PRIME64_2; - v3 = XXH_rotl64(v3, 31); - v3 *= PRIME64_1; - p+=8; - v4 += XXH_readLE64((const U64*)p, endian) * PRIME64_2; - v4 = XXH_rotl64(v4, 31); - v4 *= PRIME64_1; - p+=8; - } - while (p<=limit); - - state->v1 = v1; - state->v2 = v2; - state->v3 = v3; - state->v4 = v4; - } - - if (p < bEnd) - { - XXH_memcpy(state->memory, p, bEnd-p); - state->memsize = (int)(bEnd-p); - } - - return XXH_OK; -} - -XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_update_endian(state_in, input, len, XXH_littleEndian); - else - return XXH64_update_endian(state_in, input, len, XXH_bigEndian); -} - - - -FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state_in, XXH_endianess endian) -{ - XXH_istate64_t * state = (XXH_istate64_t *) state_in; - const BYTE * p = (const BYTE*)state->memory; - BYTE* bEnd = (BYTE*)state->memory + state->memsize; - U64 h64; - - if (state->total_len >= 32) - { - U64 v1 = state->v1; - U64 v2 = state->v2; - U64 v3 = state->v3; - U64 v4 = state->v4; - - h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); - - v1 *= PRIME64_2; - v1 = XXH_rotl64(v1, 31); - v1 *= PRIME64_1; - h64 ^= v1; - h64 = h64*PRIME64_1 + PRIME64_4; - - v2 *= PRIME64_2; - v2 = XXH_rotl64(v2, 31); - v2 *= PRIME64_1; - h64 ^= v2; - h64 = h64*PRIME64_1 + PRIME64_4; - - v3 *= PRIME64_2; - v3 = XXH_rotl64(v3, 31); - v3 *= PRIME64_1; - h64 ^= v3; - h64 = h64*PRIME64_1 + PRIME64_4; - - v4 *= PRIME64_2; - v4 = XXH_rotl64(v4, 31); - v4 *= PRIME64_1; - h64 ^= v4; - h64 = h64*PRIME64_1 + PRIME64_4; - } - else - { - h64 = state->seed + PRIME64_5; - } - - h64 += (U64) state->total_len; - - while (p+8<=bEnd) - { - U64 k1 = XXH_readLE64((const U64*)p, endian); - k1 *= PRIME64_2; - k1 = XXH_rotl64(k1,31); - k1 *= PRIME64_1; - h64 ^= k1; - h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; - p+=8; - } - - if (p+4<=bEnd) - { - h64 ^= (U64)(XXH_readLE32((const U32*)p, endian)) * PRIME64_1; - h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; - p+=4; - } - - while (p> 33; - h64 *= PRIME64_2; - h64 ^= h64 >> 29; - h64 *= PRIME64_3; - h64 ^= h64 >> 32; - - return h64; -} - - -unsigned long long XXH64_digest (const XXH64_state_t* state_in) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_digest_endian(state_in, XXH_littleEndian); - else - return XXH64_digest_endian(state_in, XXH_bigEndian); -} diff --git a/ext/xxhash.h b/ext/xxhash.h index 55b45015a4..7fe59d9a3e 100644 --- a/ext/xxhash.h +++ b/ext/xxhash.h @@ -1,39 +1,42 @@ /* - xxHash - Extremely Fast Hash algorithm - Header File - Copyright (C) 2012-2014, Yann Collet. - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * xxHash - Extremely Fast Hash algorithm + * Header File + * Copyright (C) 2012-2020 Yann Collet + * + * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at: + * - xxHash homepage: https://www.xxhash.com + * - xxHash source repository: https://github.com/Cyan4973/xxHash + */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: +/* TODO: update */ +/* Notice extracted from xxHash homepage: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - xxHash source repository : http://code.google.com/p/xxhash/ -*/ - -/* Notice extracted from xxHash homepage : - -xxHash is an extremely fast Hash algorithm, running at RAM speed limits. +xxHash is an extremely fast hash algorithm, running at RAM speed limits. It also successfully passes all tests from the SMHasher suite. Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) @@ -55,100 +58,4705 @@ SHA1-32 0.28 GB/s 10 Q.Score is a measure of quality of the hash function. It depends on successfully passing SMHasher test set. 10 is a perfect score. -*/ -#pragma once +Note: SMHasher's CRC32 implementation is not the fastest one. +Other speed-oriented implementations can be faster, +especially in combination with PCLMUL instruction: +https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735 + +A 64-bit version, named XXH64, is available since r35. +It offers much better speed, but for 64-bit applications only. +Name Speed on 64 bits Speed on 32 bits +XXH64 13.8 GB/s 1.9 GB/s +XXH32 6.8 GB/s 6.0 GB/s +*/ #if defined (__cplusplus) extern "C" { #endif +/* **************************** + * INLINE mode + ******************************/ +/*! + * XXH_INLINE_ALL (and XXH_PRIVATE_API) + * Use these build macros to inline xxhash into the target unit. + * Inlining improves performance on small inputs, especially when the length is + * expressed as a compile-time constant: + * + * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html + * + * It also keeps xxHash symbols private to the unit, so they are not exported. + * + * Usage: + * #define XXH_INLINE_ALL + * #include "xxhash.h" + * + * Do not compile and link xxhash.o as a separate object, as it is not useful. + */ +#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ + && !defined(XXH_INLINE_ALL_31684351384) + /* this section should be traversed only once */ +# define XXH_INLINE_ALL_31684351384 + /* give access to the advanced API, required to compile implementations */ +# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ +# define XXH_STATIC_LINKING_ONLY + /* make all functions private */ +# undef XXH_PUBLIC_API +# if defined(__GNUC__) +# define XXH_PUBLIC_API static __inline __attribute__((unused)) +# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define XXH_PUBLIC_API static inline +# elif defined(_MSC_VER) +# define XXH_PUBLIC_API static __inline +# else + /* note: this version may generate warnings for unused static functions */ +# define XXH_PUBLIC_API static +# endif -/***************************** - Includes -*****************************/ + /* + * This part deals with the special case where a unit wants to inline xxHash, + * but "xxhash.h" has previously been included without XXH_INLINE_ALL, such + * as part of some previously included *.h header file. + * Without further action, the new include would just be ignored, + * and functions would effectively _not_ be inlined (silent failure). + * The following macros solve this situation by prefixing all inlined names, + * avoiding naming collision with previous inclusions. + */ +# ifdef XXH_NAMESPACE +# error "XXH_INLINE_ALL with XXH_NAMESPACE is not supported" + /* + * Note: Alternative: #undef all symbols (it's a pretty large list). + * Without #error: it compiles, but functions are actually not inlined. + */ +# endif +# define XXH_NAMESPACE XXH_INLINE_ + /* + * Some identifiers (enums, type names) are not symbols, but they must + * still be renamed to avoid redeclaration. + * Alternative solution: do not redeclare them. + * However, this requires some #ifdefs, and is a more dispersed action. + * Meanwhile, renaming can be achieved in a single block + */ +# define XXH_IPREF(Id) XXH_INLINE_ ## Id +# define XXH_OK XXH_IPREF(XXH_OK) +# define XXH_ERROR XXH_IPREF(XXH_ERROR) +# define XXH_errorcode XXH_IPREF(XXH_errorcode) +# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) +# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) +# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) +# define XXH32_state_s XXH_IPREF(XXH32_state_s) +# define XXH32_state_t XXH_IPREF(XXH32_state_t) +# define XXH64_state_s XXH_IPREF(XXH64_state_s) +# define XXH64_state_t XXH_IPREF(XXH64_state_t) +# define XXH3_state_s XXH_IPREF(XXH3_state_s) +# define XXH3_state_t XXH_IPREF(XXH3_state_t) +# define XXH128_hash_t XXH_IPREF(XXH128_hash_t) + /* Ensure the header is parsed again, even if it was previously included */ +# undef XXHASH_H_5627135585666179 +# undef XXHASH_H_STATIC_13879238742 +#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ + + + +/* **************************************************************** + * Stable API + *****************************************************************/ +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + +/* specific declaration modes for Windows */ +#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) +# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif +#endif + +/*! + * XXH_NAMESPACE, aka Namespace Emulation: + * + * If you want to include _and expose_ xxHash functions from within your own + * library, but also want to avoid symbol collisions with other libraries which + * may also include xxHash, you can use XXH_NAMESPACE to automatically prefix + * any public symbol from xxhash library with the value of XXH_NAMESPACE + * (therefore, avoid empty or numeric values). + * + * Note that no change is required within the calling program as long as it + * includes `xxhash.h`: Regular symbol names will be automatically translated + * by this header. + */ +#ifdef XXH_NAMESPACE +# define XXH_CAT(A,B) A##B +# define XXH_NAME2(A,B) XXH_CAT(A,B) +# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +/* XXH32 */ +# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) +# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) +# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) +# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) +# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) +# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) +# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) +# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) +# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) +/* XXH64 */ +# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) +# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) +# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) +/* XXH3_64bits */ +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) +/* XXH3_128bits */ +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) +#endif + + +/* ************************************* +* Version +***************************************/ +#define XXH_VERSION_MAJOR 0 +#define XXH_VERSION_MINOR 8 +#define XXH_VERSION_RELEASE 0 +#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) +XXH_PUBLIC_API unsigned XXH_versionNumber (void); + + +/* **************************** +* Definitions +******************************/ #include /* size_t */ - - -/***************************** - Type -*****************************/ typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; +/*-********************************************************************** +* 32-bit hash +************************************************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint32_t XXH32_hash_t; +#else +# include +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# else +# if ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform: need a 32-bit type" +# endif +# endif +#endif -/***************************** - Simple Hash Functions +/*! + * XXH32(): + * Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input". + * The memory between input & input+length must be valid (allocated and read-accessible). + * "seed" can be used to alter the result predictably. + * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s + * + * Note: XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. It provides a superior level of + * dispersion, and greatly reduces the risks of collisions. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); + +/******* Streaming *******/ + +/* + * Streaming functions generate the xxHash value from an incrememtal input. + * This method is slower than single-call functions, due to state management. + * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. + * + * An XXH state must first be allocated using `XXH*_createState()`. + * + * Start a new hash by initializing the state with a seed using `XXH*_reset()`. + * + * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. + * + * The function returns an error code, with 0 meaning OK, and any other value + * meaning there is an error. + * + * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. + * This function returns the nn-bits hash as an int or long long. + * + * It's still possible to continue inserting input into the hash state after a + * digest, and generate new hash values later on by invoking `XXH*_digest()`. + * + * When done, release the state using `XXH*_freeState()`. + */ + +typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); + +/******* Canonical representation *******/ + +/* + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * This the simplest and fastest format for further post-processing. + * + * However, this leaves open the question of what is the order on the byte level, + * since little and big endian conventions will store the same number differently. + * + * The canonical representation settles this issue by mandating big-endian + * convention, the same convention as human-readable numbers (large digits first). + * + * When writing hash values to storage, sending them over a network, or printing + * them, it's highly recommended to use the canonical representation to ensure + * portability across a wider range of systems, present and future. + * + * The following functions allow transformation of hash values to and from + * canonical format. + */ + +typedef struct { unsigned char digest[4]; } XXH32_canonical_t; +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); + + +#ifndef XXH_NO_LONG_LONG +/*-********************************************************************** +* 64-bit hash +************************************************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint64_t XXH64_hash_t; +#else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +#endif + +/*! + * XXH64(): + * Returns the 64-bit hash of sequence of length @length stored at memory + * address @input. + * @seed can be used to alter the result predictably. + * + * This function usually runs faster on 64-bit systems, but slower on 32-bit + * systems (see benchmark). + * + * Note: XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. It provides a superior level of + * dispersion, and greatly reduces the risks of collisions. + */ +XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, XXH64_hash_t seed); + +/******* Streaming *******/ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); + + +/*-********************************************************************** +* XXH3 64-bit variant +************************************************************************/ + +/* ************************************************************************ + * XXH3 is a new hash algorithm featuring: + * - Improved speed for both small and large inputs + * - True 64-bit and 128-bit outputs + * - SIMD acceleration + * - Improved 32-bit viability + * + * Speed analysis methodology is explained here: + * + * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * + * In general, expect XXH3 to run about ~2x faster on large inputs and >3x + * faster on small ones compared to XXH64, though exact differences depend on + * the platform. + * + * The algorithm is portable: Like XXH32 and XXH64, it generates the same hash + * on all platforms. + * + * It benefits greatly from SIMD and 64-bit arithmetic, but does not require it. + * + * Almost all 32-bit and 64-bit targets that can run XXH32 smoothly can run + * XXH3 at competitive speeds, even if XXH64 runs slowly. Further details are + * explained in the implementation. + * + * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8, + * ZVector and scalar targets. This can be controlled with the XXH_VECTOR macro. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * When only 64 bits are needed, prefer calling the _64bits variant, as it + * reduces the amount of mixing, resulting in faster speed on small inputs. + * + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The 128-bit version adds additional strength, but it is slightly slower. + * + * Return values of XXH3 and XXH128 are officially finalized starting + * with v0.8.0 and will no longer change in future versions. + * Avoid storing values from before that release in long-term storage. + * + * Results produced by v0.7.x are not comparable with results from v0.7.y. + * However, the API is completely stable, and it can safely be used for + * ephemeral data (local sessions). + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + */ + +/* XXH3_64bits(): + * default 64-bit variant, using default secret and default seed of 0. + * It's the fastest variant. */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); + +/* + * XXH3_64bits_withSeed(): + * This variant generates a custom secret on the fly + * based on default secret altered using the `seed` value. + * While this operation is decently fast, note that it's not completely free. + * Note: seed==0 produces the same results as XXH3_64bits(). + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); + +/* + * XXH3_64bits_withSecret(): + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). + * However, the quality of produced hash values depends on secret's entropy. + * Technically, the secret must look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever unsure about the "randomness" of the blob of bytes, + * consider relabelling it as a "custom seed" instead, + * and employ "XXH3_generateSecret()" (see below) + * to generate a high entropy secret derived from the custom seed. + */ +#define XXH3_SECRET_SIZE_MIN 136 +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + */ +typedef struct XXH3_state_s XXH3_state_t; +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); +XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state); + +/* + * XXH3_64bits_reset(): + * Initialize with default parameters. + * digest will be equivalent to `XXH3_64bits()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr); +/* + * XXH3_64bits_reset_withSeed(): + * Generate a custom secret from `seed`, and store it into `statePtr`. + * digest will be equivalent to `XXH3_64bits_withSeed()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +/* + * XXH3_64bits_reset_withSecret(): + * `secret` is referenced, it _must outlive_ the hash streaming session. + * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* statePtr); + +/* note : canonical representation of XXH3 is the same as XXH64 + * since they both produce XXH64_hash_t values */ + + +/*-********************************************************************** +* XXH3 128-bit variant +************************************************************************/ + +typedef struct { + XXH64_hash_t low64; + XXH64_hash_t high64; +} XXH128_hash_t; + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + * + * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). + * Use already declared XXH3_createState() and XXH3_freeState(). + * + * All reset and streaming functions have same meaning as their 64-bit counterpart. + */ + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr); + +/* Following helper functions make it possible to compare XXH128_hast_t values. + * Since XXH128_hash_t is a structure, this capability is not offered by the language. + * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ + +/*! + * XXH128_isEqual(): + * Return: 1 if `h1` and `h2` are equal, 0 if they are not. + */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); + +/*! + * XXH128_cmp(): + * + * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. + * + * return: >0 if *h128_1 > *h128_2 + * =0 if *h128_1 == *h128_2 + * <0 if *h128_1 < *h128_2 + */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); + + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); + + +#endif /* XXH_NO_LONG_LONG */ + +#endif /* XXHASH_H_5627135585666179 */ + + + +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) +#define XXHASH_H_STATIC_13879238742 +/* **************************************************************************** + * This section contains declarations which are not guaranteed to remain stable. + * They may change in future versions, becoming incompatible with a different + * version of the library. + * These declarations should only be used with static linking. + * Never use them in association with dynamic linking! + ***************************************************************************** */ + +/* + * These definitions are only present to allow static allocation + * of XXH states, on stack or in a struct, for example. + * Never **ever** access their members directly. + */ + +struct XXH32_state_s { + XXH32_hash_t total_len_32; + XXH32_hash_t large_len; + XXH32_hash_t v1; + XXH32_hash_t v2; + XXH32_hash_t v3; + XXH32_hash_t v4; + XXH32_hash_t mem32[4]; + XXH32_hash_t memsize; + XXH32_hash_t reserved; /* never read nor write, might be removed in a future version */ +}; /* typedef'd to XXH32_state_t */ + + +#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ + +struct XXH64_state_s { + XXH64_hash_t total_len; + XXH64_hash_t v1; + XXH64_hash_t v2; + XXH64_hash_t v3; + XXH64_hash_t v4; + XXH64_hash_t mem64[4]; + XXH32_hash_t memsize; + XXH32_hash_t reserved32; /* required for padding anyway */ + XXH64_hash_t reserved64; /* never read nor write, might be removed in a future version */ +}; /* typedef'd to XXH64_state_t */ + +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11+ */ +# include +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +/* Old GCC versions only accept the attribute after the type in structures. */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ + && defined(__GNUC__) +# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) +#else +# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type +#endif + +#define XXH3_INTERNALBUFFER_SIZE 256 +#define XXH3_SECRET_DEFAULT_SIZE 192 +struct XXH3_state_s { + XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); + /* used to store a custom secret generated from a seed */ + XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); + XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); + XXH32_hash_t bufferedSize; + XXH32_hash_t reserved32; + size_t nbStripesSoFar; + XXH64_hash_t totalLen; + size_t nbStripesPerBlock; + size_t secretLimit; + XXH64_hash_t seed; + XXH64_hash_t reserved64; + const unsigned char* extSecret; /* reference to external secret; + * if == NULL, use .customSecret instead */ + /* note: there may be some padding at the end due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +#undef XXH_ALIGN_MEMBER + +/* When the XXH3_state_t structure is merely emplaced on stack, + * it should be initialized with XXH3_INITSTATE() or a memset() + * in case its first reset uses XXH3_NNbits_reset_withSeed(). + * This init can be omitted if the first reset uses default or _withSecret mode. + * This operation isn't necessary when the state is created with XXH3_createState(). + * Note that this doesn't prepare the state for a streaming operation, + * it's still necessary to use XXH3_NNbits_reset*() afterwards. + */ +#define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; } + + +/* === Experimental API === */ +/* Symbols defined below must be considered tied to a specific library version. */ + +/* + * XXH3_generateSecret(): + * + * Derive a high-entropy secret from any user-defined content, named customSeed. + * The generated secret can be used in combination with `*_withSecret()` functions. + * The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed, + * as it becomes much more difficult for an external actor to guess how to impact the calculation logic. + * + * The function accepts as input a custom seed of any length and any content, + * and derives from it a high-entropy secret of length XXH3_SECRET_DEFAULT_SIZE + * into an already allocated buffer secretBuffer. + * The generated secret is _always_ XXH_SECRET_DEFAULT_SIZE bytes long. + * + * The generated secret can then be used with any `*_withSecret()` variant. + * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`, + * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()` + * are part of this list. They all accept a `secret` parameter + * which must be very long for implementation reasons (>= XXH3_SECRET_SIZE_MIN) + * _and_ feature very high entropy (consist of random-looking bytes). + * These conditions can be a high bar to meet, so + * this function can be used to generate a secret of proper quality. + * + * customSeed can be anything. It can have any size, even small ones, + * and its content can be anything, even stupidly "low entropy" source such as a bunch of zeroes. + * The resulting `secret` will nonetheless provide all expected qualities. + * + * Supplying NULL as the customSeed copies the default secret into `secretBuffer`. + * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior. + */ +XXH_PUBLIC_API void XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize); + + +/* simple short-cut to pre-selected XXH3_128bits variant */ +XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); + + +#endif /* XXH_NO_LONG_LONG */ + + +#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) +# define XXH_IMPLEMENTATION +#endif + +#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ + + +/* ======================================================================== */ +/* ======================================================================== */ +/* ======================================================================== */ + + +/*-********************************************************************** + * xxHash implementation + *-********************************************************************** + * xxHash's implementation used to be hosted inside xxhash.c. + * + * However, inlining requires implementation to be visible to the compiler, + * hence be included alongside the header. + * Previously, implementation was hosted inside xxhash.c, + * which was then #included when inlining was activated. + * This construction created issues with a few build and install systems, + * as it required xxhash.c to be stored in /include directory. + * + * xxHash implementation is now directly integrated within xxhash.h. + * As a consequence, xxhash.c is no longer needed in /include. + * + * xxhash.c is still available and is still useful. + * In a "normal" setup, when xxhash is not inlined, + * xxhash.h only exposes the prototypes and public symbols, + * while xxhash.c can be built into an object file xxhash.o + * which can then be linked into the final binary. + ************************************************************************/ + +#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ + || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) +# define XXH_IMPLEM_13a8737387 + +/* ************************************* +* Tuning parameters +***************************************/ +/*! + * XXH_FORCE_MEMORY_ACCESS: + * By default, access to unaligned memory is controlled by `memcpy()`, which is + * safe and portable. + * + * Unfortunately, on some target/compiler combinations, the generated assembly + * is sub-optimal. + * + * The below switch allow selection of a different access method + * in the search for improved performance. + * Method 0 (default): + * Use `memcpy()`. Safe and portable. Default. + * Method 1: + * `__attribute__((packed))` statement. It depends on compiler extensions + * and is therefore not portable. + * This method is safe if your compiler supports it, and *generally* as + * fast or faster than `memcpy`. + * Method 2: + * Direct access via cast. This method doesn't depend on the compiler but + * violates the C standard. + * It can generate buggy code on targets which do not support unaligned + * memory accesses. + * But in some circumstances, it's the only known way to get the most + * performance (example: GCC + ARMv6) + * Method 3: + * Byteshift. This can generate the best code on old compilers which don't + * inline small `memcpy()` calls, and it might also be faster on big-endian + * systems which lack a native byteswap instruction. + * See https://stackoverflow.com/a/32095106/646947 for details. + * Prefer these methods in priority order (0 > 1 > 2 > 3) + */ +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if !defined(__clang__) && defined(__GNUC__) && defined(__ARM_FEATURE_UNALIGNED) && defined(__ARM_ARCH) && (__ARM_ARCH == 6) +# define XXH_FORCE_MEMORY_ACCESS 2 +# elif !defined(__clang__) && ((defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ + (defined(__GNUC__) && (defined(__ARM_ARCH) && __ARM_ARCH >= 7))) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +/*! + * XXH_ACCEPT_NULL_INPUT_POINTER: + * If the input pointer is NULL, xxHash's default behavior is to dereference it, + * triggering a segfault. + * When this macro is enabled, xxHash actively checks the input for a null pointer. + * If it is, the result for null input pointers is the same as a zero-length input. + */ +#ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */ +# define XXH_ACCEPT_NULL_INPUT_POINTER 0 +#endif + +/*! + * XXH_FORCE_ALIGN_CHECK: + * This is an important performance trick + * for architectures without decent unaligned memory access performance. + * It checks for input alignment, and when conditions are met, + * uses a "fast path" employing direct 32-bit/64-bit read, + * resulting in _dramatically faster_ read speed. + * + * The check costs one initial branch per hash, which is generally negligible, but not zero. + * Moreover, it's not useful to generate binary for an additional code path + * if memory access uses same instruction for both aligned and unaligned adresses. + * + * In these cases, the alignment check can be removed by setting this macro to 0. + * Then the code will always use unaligned memory access. + * Align check is automatically disabled on x86, x64 & arm64, + * which are platforms known to offer good unaligned memory accesses performance. + * + * This option does not affect XXH3 (only XXH32 and XXH64). + */ +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ +# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ + || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + +/*! + * XXH_NO_INLINE_HINTS: + * + * By default, xxHash tries to force the compiler to inline almost all internal + * functions. + * + * This can usually improve performance due to reduced jumping and improved + * constant folding, but significantly increases the size of the binary which + * might not be favorable. + * + * Additionally, sometimes the forced inlining can be detrimental to performance, + * depending on the architecture. + * + * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the + * compiler full control on whether to inline or not. + * + * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using + * -fno-inline with GCC or Clang, this will automatically be defined. + */ +#ifndef XXH_NO_INLINE_HINTS +# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ + || defined(__NO_INLINE__) /* -O0, -fno-inline */ +# define XXH_NO_INLINE_HINTS 1 +# else +# define XXH_NO_INLINE_HINTS 0 +# endif +#endif + +/*! + * XXH_REROLL: + * Whether to reroll XXH32_finalize, and XXH64_finalize, + * instead of using an unrolled jump table/if statement loop. + * + * This is automatically defined on -Os/-Oz on GCC and Clang. + */ +#ifndef XXH_REROLL +# if defined(__OPTIMIZE_SIZE__) +# define XXH_REROLL 1 +# else +# define XXH_REROLL 0 +# endif +#endif + + +/* ************************************* +* Includes & Memory related functions +***************************************/ +/*! + * Modify the local functions below should you wish to use + * different memory routines for malloc() and free() + */ +#include + +static void* XXH_malloc(size_t s) { return malloc(s); } +static void XXH_free(void* p) { free(p); } + +/*! and for memcpy() */ +#include +static void* XXH_memcpy(void* dest, const void* src, size_t size) +{ + return memcpy(dest,src,size); +} + +#include /* ULLONG_MAX */ + + +/* ************************************* +* Compiler Specific Options +***************************************/ +#ifdef _MSC_VER /* Visual Studio warning fix */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +#if XXH_NO_INLINE_HINTS /* disable inlining hints */ +# if defined(__GNUC__) +# define XXH_FORCE_INLINE static __attribute__((unused)) +# else +# define XXH_FORCE_INLINE static +# endif +# define XXH_NO_INLINE static +/* enable inlining hints */ +#elif defined(_MSC_VER) /* Visual Studio */ +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) +#elif defined(__GNUC__) +# define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) +# define XXH_NO_INLINE static __attribute__((noinline)) +#elif defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static +#else +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static +#endif + + + +/* ************************************* +* Debug +***************************************/ +/* + * XXH_DEBUGLEVEL is expected to be defined externally, typically via the + * compiler's command line options. The value must be a number. + */ +#ifndef XXH_DEBUGLEVEL +# ifdef DEBUGLEVEL /* backwards compat */ +# define XXH_DEBUGLEVEL DEBUGLEVEL +# else +# define XXH_DEBUGLEVEL 0 +# endif +#endif + +#if (XXH_DEBUGLEVEL>=1) +# include /* note: can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# define XXH_ASSERT(c) ((void)0) +#endif + +/* note: use after variable declarations */ +#define XXH_STATIC_ASSERT(c) do { enum { XXH_sa = 1/(int)(!!(c)) }; } while (0) + + +/* ************************************* +* Basic Types +***************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; +#endif +typedef XXH32_hash_t xxh_u32; + +#ifdef XXH_OLD_NAMES +# define BYTE xxh_u8 +# define U8 xxh_u8 +# define U32 xxh_u32 +#endif + +/* *** Memory access *** */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE32 and XXH_readBE32. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* + * Force direct memory access. Only works on CPU which support unaligned memory + * access in hardware. + */ +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; +#endif +static xxh_u32 XXH_read32(const void* ptr) +{ + typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; + return ((const xxh_unalign*)ptr)->u32; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: https://stackoverflow.com/a/32095106/646947 + */ +static xxh_u32 XXH_read32(const void* memPtr) +{ + xxh_u32 val; + memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* *** Endianess *** */ +typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; + +/*! + * XXH_CPU_LITTLE_ENDIAN: + * Defined to 1 if the target is little endian, or 0 if it is big endian. + * It can be defined externally, for example on the compiler command line. + * + * If it is not defined, a runtime check (which is usually constant folded) + * is used instead. + */ +#ifndef XXH_CPU_LITTLE_ENDIAN +/* + * Try to detect endianness automatically, to avoid the nonstandard behavior + * in `XXH_isLittleEndian()` + */ +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +/* + * runtime test, presumed to simplify to a constant by compiler + */ +static int XXH_isLittleEndian(void) +{ + /* + * Portable and well-defined behavior. + * Don't use static: it is detrimental to performance. + */ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#ifdef __has_builtin +# define XXH_HAS_BUILTIN(x) __has_builtin(x) +#else +# define XXH_HAS_BUILTIN(x) 0 +#endif + +#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ + && XXH_HAS_BUILTIN(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 +/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ +#elif defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#endif + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +#else +static xxh_u32 XXH_swap32 (xxh_u32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +#endif + + +/* *************************** +* Memory reads *****************************/ - -unsigned int XXH32 (const void* input, size_t length, unsigned seed); -unsigned long long XXH64 (const void* input, size_t length, unsigned long long seed); +typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; /* -XXH32() : - Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input". - The memory between input & input+length must be valid (allocated and read-accessible). - "seed" can be used to alter the result predictably. - This function successfully passes all SMHasher tests. - Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s -XXH64() : - Calculate the 64-bits hash of sequence of length "len" stored at memory address "input". -*/ + * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. + * + * This is ideal for older compilers which don't inline memcpy. + */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u32)bytePtr[1] << 8) + | ((xxh_u32)bytePtr[2] << 16) + | ((xxh_u32)bytePtr[3] << 24); +} + +XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[3] + | ((xxh_u32)bytePtr[2] << 8) + | ((xxh_u32)bytePtr[1] << 16) + | ((xxh_u32)bytePtr[0] << 24); +} + +#else +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); +} + +static xxh_u32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } +} + + +/* ************************************* +* Misc +***************************************/ +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ******************************************************************* +* 32-bit hash functions +*********************************************************************/ +static const xxh_u32 XXH_PRIME32_1 = 0x9E3779B1U; /* 0b10011110001101110111100110110001 */ +static const xxh_u32 XXH_PRIME32_2 = 0x85EBCA77U; /* 0b10000101111010111100101001110111 */ +static const xxh_u32 XXH_PRIME32_3 = 0xC2B2AE3DU; /* 0b11000010101100101010111000111101 */ +static const xxh_u32 XXH_PRIME32_4 = 0x27D4EB2FU; /* 0b00100111110101001110101100101111 */ +static const xxh_u32 XXH_PRIME32_5 = 0x165667B1U; /* 0b00010110010101100110011110110001 */ + +#ifdef XXH_OLD_NAMES +# define PRIME32_1 XXH_PRIME32_1 +# define PRIME32_2 XXH_PRIME32_2 +# define PRIME32_3 XXH_PRIME32_3 +# define PRIME32_4 XXH_PRIME32_4 +# define PRIME32_5 XXH_PRIME32_5 +#endif + +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) +{ + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; +#if defined(__GNUC__) && defined(__SSE4_1__) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * UGLY HACK: + * This inline assembly hack forces acc into a normal register. This is the + * only thing that prevents GCC and Clang from autovectorizing the XXH32 + * loop (pragmas and attributes don't work for some resason) without globally + * disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on + * newer chips!) making it slightly slower to multiply four integers at + * once compared to four integers independently. Even when pmulld was + * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE + * just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because + * the SIMD actually serializes this operation: While v1 is rotating, v2 + * can load data, while v3 can multiply. SSE forces them to operate + * together. + * + * How this hack works: + * __asm__("" // Declare an assembly block but don't declare any instructions + * : // However, as an Input/Output Operand, + * "+r" // constrain a read/write operand (+) as a general purpose register (r). + * (acc) // and set acc as the operand + * ); + * + * Because of the 'r', the compiler has promised that seed will be in a + * general purpose register and the '+' says that it will be 'read/write', + * so it has to assume it has changed. It is like volatile without all the + * loads and stores. + * + * Since the argument has to be in a normal register (not an SSE register), + * each time XXH32_round is called, it is impossible to vectorize. + */ + __asm__("" : "+r" (acc)); +#endif + return acc; +} + +/* mix all bits */ +static xxh_u32 XXH32_avalanche(xxh_u32 h32) +{ + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + return(h32); +} + +#define XXH_get32bits(p) XXH_readLE32_align(p, align) + +static xxh_u32 +XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1 do { \ + h32 += (*ptr++) * XXH_PRIME32_5; \ + h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \ +} while (0) + +#define XXH_PROCESS4 do { \ + h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \ + ptr += 4; \ + h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \ +} while (0) + + /* Compact rerolled version */ + if (XXH_REROLL) { + len &= 15; + while (len >= 4) { + XXH_PROCESS4; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1; + --len; + } + return XXH32_avalanche(h32); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: XXH_PROCESS4; + /* fallthrough */ + case 8: XXH_PROCESS4; + /* fallthrough */ + case 4: XXH_PROCESS4; + return XXH32_avalanche(h32); + + case 13: XXH_PROCESS4; + /* fallthrough */ + case 9: XXH_PROCESS4; + /* fallthrough */ + case 5: XXH_PROCESS4; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 14: XXH_PROCESS4; + /* fallthrough */ + case 10: XXH_PROCESS4; + /* fallthrough */ + case 6: XXH_PROCESS4; + XXH_PROCESS1; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 15: XXH_PROCESS4; + /* fallthrough */ + case 11: XXH_PROCESS4; + /* fallthrough */ + case 7: XXH_PROCESS4; + /* fallthrough */ + case 3: XXH_PROCESS1; + /* fallthrough */ + case 2: XXH_PROCESS1; + /* fallthrough */ + case 1: XXH_PROCESS1; + /* fallthrough */ + case 0: return XXH32_avalanche(h32); + } + XXH_ASSERT(0); + return h32; /* reaching this point is deemed impossible */ + } +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1 XXH_PROCESS1 +# define PROCESS4 XXH_PROCESS4 +#else +# undef XXH_PROCESS1 +# undef XXH_PROCESS4 +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) +{ + const xxh_u8* bEnd = input + len; + xxh_u32 h32; + +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + if (input==NULL) { + len=0; + bEnd=input=(const xxh_u8*)(size_t)16; + } +#endif + + if (len>=16) { + const xxh_u8* const limit = bEnd - 15; + xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + xxh_u32 v2 = seed + XXH_PRIME32_2; + xxh_u32 v3 = seed + 0; + xxh_u32 v4 = seed - XXH_PRIME32_1; + + do { +#if defined(ARM) && defined(__GNUC__) + __builtin_prefetch(input + 0xc0, 0, 0); +#endif + v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; + v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; + v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; + v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; + } while (input < limit); + + h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); + } else { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (xxh_u32)len; + + return XXH32_finalize(h32, input, len&15, align); +} + + +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_state_t state; + XXH32_reset(&state, seed); + XXH32_update(&state, (const xxh_u8*)input, len); + return XXH32_digest(&state); + +#else + + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); +#endif +} -/***************************** - Advanced Hash Functions -*****************************/ -typedef struct { long long ll[ 6]; } XXH32_state_t; -typedef struct { long long ll[11]; } XXH64_state_t; +/******* Hash streaming *******/ + +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) +{ + return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); +} +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) +{ + memcpy(dstState, srcState, sizeof(*dstState)); +} + +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) +{ + XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ + memset(&state, 0, sizeof(state)); + state.v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + state.v2 = seed + XXH_PRIME32_2; + state.v3 = seed + 0; + state.v4 = seed - XXH_PRIME32_1; + /* do not write into reserved, planned to be removed in a future version */ + memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved)); + return XXH_OK; +} + + +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) +{ + if (input==NULL) +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + return XXH_OK; +#else + return XXH_ERROR; +#endif + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); + + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); + state->memsize += (XXH32_hash_t)len; + return XXH_OK; + } + + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const xxh_u32* p32 = state->mem32; + state->v1 = XXH32_round(state->v1, XXH_readLE32(p32)); p32++; + state->v2 = XXH32_round(state->v2, XXH_readLE32(p32)); p32++; + state->v3 = XXH32_round(state->v3, XXH_readLE32(p32)); p32++; + state->v4 = XXH32_round(state->v4, XXH_readLE32(p32)); + } + p += 16-state->memsize; + state->memsize = 0; + } + + if (p <= bEnd-16) { + const xxh_u8* const limit = bEnd - 16; + xxh_u32 v1 = state->v1; + xxh_u32 v2 = state->v2; + xxh_u32 v3 = state->v3; + xxh_u32 v4 = state->v4; + + do { + v1 = XXH32_round(v1, XXH_readLE32(p)); p+=4; + v2 = XXH32_round(v2, XXH_readLE32(p)); p+=4; + v3 = XXH32_round(v3, XXH_readLE32(p)); p+=4; + v4 = XXH32_round(v4, XXH_readLE32(p)); p+=4; + } while (p<=limit); + + state->v1 = v1; + state->v2 = v2; + state->v3 = v3; + state->v4 = v4; + } + + if (p < bEnd) { + XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* state) +{ + xxh_u32 h32; + + if (state->large_len) { + h32 = XXH_rotl32(state->v1, 1) + + XXH_rotl32(state->v2, 7) + + XXH_rotl32(state->v3, 12) + + XXH_rotl32(state->v4, 18); + } else { + h32 = state->v3 /* == seed */ + XXH_PRIME32_5; + } + + h32 += state->total_len_32; + + return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); +} + + +/******* Canonical representation *******/ /* -These structures allow static allocation of XXH states. -States must then be initialized using XXHnn_reset() before first use. + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * + * The canonical representation uses big endian convention, the same convention + * as human-readable numbers (large digits first). + * + * This way, hash values can be written into a file or buffer, remaining + * comparable across different systems. + * + * The following functions allow transformation of hash values to and from their + * canonical format. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); + memcpy(dst, &hash, sizeof(*dst)); +} -If you prefer dynamic allocation, please refer to functions below. -*/ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} -XXH32_state_t* XXH32_createState(void); -XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); -XXH64_state_t* XXH64_createState(void); -XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); +#ifndef XXH_NO_LONG_LONG + +/* ******************************************************************* +* 64-bit hash functions +*********************************************************************/ + +/******* Memory access *******/ + +typedef XXH64_hash_t xxh_u64; + +#ifdef XXH_OLD_NAMES +# define U64 xxh_u64 +#endif + +/*! + * XXH_REROLL_XXH64: + * Whether to reroll the XXH64_finalize() loop. + * + * Just like XXH32, we can unroll the XXH64_finalize() loop. This can be a + * performance gain on 64-bit hosts, as only one jump is required. + * + * However, on 32-bit hosts, because arithmetic needs to be done with two 32-bit + * registers, and 64-bit arithmetic needs to be simulated, it isn't beneficial + * to unroll. The code becomes ridiculously large (the largest function in the + * binary on i386!), and rerolling it saves anywhere from 3kB to 20kB. It is + * also slightly faster because it fits into cache better and is more likely + * to be inlined by the compiler. + * + * If XXH_REROLL is defined, this is ignored and the loop is always rerolled. + */ +#ifndef XXH_REROLL_XXH64 +# if (defined(__ILP32__) || defined(_ILP32)) /* ILP32 is often defined on 32-bit GCC family */ \ + || !(defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) /* x86-64 */ \ + || defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__) /* aarch64 */ \ + || defined(__PPC64__) || defined(__PPC64LE__) || defined(__ppc64__) || defined(__powerpc64__) /* ppc64 */ \ + || defined(__mips64__) || defined(__mips64)) /* mips64 */ \ + || (!defined(SIZE_MAX) || SIZE_MAX < ULLONG_MAX) /* check limits */ +# define XXH_REROLL_XXH64 1 +# else +# define XXH_REROLL_XXH64 0 +# endif +#endif /* !defined(XXH_REROLL_XXH64) */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE64 and XXH_readBE64. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ +static xxh_u64 XXH_read64(const void* memPtr) { return *(const xxh_u64*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* -These functions create and release memory for XXH state. -States must then be initialized using XXHnn_reset() before first use. -*/ + * __pack instructions are safer, but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; +#endif +static xxh_u64 XXH_read64(const void* ptr) +{ + typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; + return ((const xxh_unalign64*)ptr)->u64; +} - -XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned seed); -XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); -unsigned int XXH32_digest (const XXH32_state_t* statePtr); - -XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed); -XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); -unsigned long long XXH64_digest (const XXH64_state_t* statePtr); +#else /* -These functions calculate the xxHash of an input provided in multiple smaller packets, -as opposed to an input provided as a single block. + * Portable and safe solution. Generally efficient. + * see: https://stackoverflow.com/a/32095106/646947 + */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + xxh_u64 val; + memcpy(&val, memPtr, sizeof(val)); + return val; +} -XXH state space must first be allocated, using either static or dynamic method provided above. +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ -Start a new hash by initializing state with a seed, using XXHnn_reset(). +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap64 _byteswap_uint64 +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap64 __builtin_bswap64 +#else +static xxh_u64 XXH_swap64 (xxh_u64 x) +{ + return ((x << 56) & 0xff00000000000000ULL) | + ((x << 40) & 0x00ff000000000000ULL) | + ((x << 24) & 0x0000ff0000000000ULL) | + ((x << 8) & 0x000000ff00000000ULL) | + ((x >> 8) & 0x00000000ff000000ULL) | + ((x >> 24) & 0x0000000000ff0000ULL) | + ((x >> 40) & 0x000000000000ff00ULL) | + ((x >> 56) & 0x00000000000000ffULL); +} +#endif -Then, feed the hash state by calling XXHnn_update() as many times as necessary. -Obviously, input must be valid, meaning allocated and read accessible. -The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. -Finally, you can produce a hash anytime, by using XXHnn_digest(). -This function returns the final nn-bits hash. -You can nonetheless continue feeding the hash state with more input, -and therefore get some new hashes, by calling again XXHnn_digest(). +/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) -When you are done, don't forget to free XXH state space, using typically XXHnn_freeState(). -*/ +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u64)bytePtr[1] << 8) + | ((xxh_u64)bytePtr[2] << 16) + | ((xxh_u64)bytePtr[3] << 24) + | ((xxh_u64)bytePtr[4] << 32) + | ((xxh_u64)bytePtr[5] << 40) + | ((xxh_u64)bytePtr[6] << 48) + | ((xxh_u64)bytePtr[7] << 56); +} + +XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[7] + | ((xxh_u64)bytePtr[6] << 8) + | ((xxh_u64)bytePtr[5] << 16) + | ((xxh_u64)bytePtr[4] << 24) + | ((xxh_u64)bytePtr[3] << 32) + | ((xxh_u64)bytePtr[2] << 40) + | ((xxh_u64)bytePtr[1] << 48) + | ((xxh_u64)bytePtr[0] << 56); +} + +#else +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); +} + +static xxh_u64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); +} + + +/******* xxh64 *******/ + +static const xxh_u64 XXH_PRIME64_1 = 0x9E3779B185EBCA87ULL; /* 0b1001111000110111011110011011000110000101111010111100101010000111 */ +static const xxh_u64 XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4FULL; /* 0b1100001010110010101011100011110100100111110101001110101101001111 */ +static const xxh_u64 XXH_PRIME64_3 = 0x165667B19E3779F9ULL; /* 0b0001011001010110011001111011000110011110001101110111100111111001 */ +static const xxh_u64 XXH_PRIME64_4 = 0x85EBCA77C2B2AE63ULL; /* 0b1000010111101011110010100111011111000010101100101010111001100011 */ +static const xxh_u64 XXH_PRIME64_5 = 0x27D4EB2F165667C5ULL; /* 0b0010011111010100111010110010111100010110010101100110011111000101 */ + +#ifdef XXH_OLD_NAMES +# define PRIME64_1 XXH_PRIME64_1 +# define PRIME64_2 XXH_PRIME64_2 +# define PRIME64_3 XXH_PRIME64_3 +# define PRIME64_4 XXH_PRIME64_4 +# define PRIME64_5 XXH_PRIME64_5 +#endif + +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) +{ + acc += input * XXH_PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= XXH_PRIME64_1; + return acc; +} + +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; + return acc; +} + +static xxh_u64 XXH64_avalanche(xxh_u64 h64) +{ + h64 ^= h64 >> 33; + h64 *= XXH_PRIME64_2; + h64 ^= h64 >> 29; + h64 *= XXH_PRIME64_3; + h64 ^= h64 >> 32; + return h64; +} + + +#define XXH_get64bits(p) XXH_readLE64_align(p, align) + +static xxh_u64 +XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1_64 do { \ + h64 ^= (*ptr++) * XXH_PRIME64_5; \ + h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; \ +} while (0) + +#define XXH_PROCESS4_64 do { \ + h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; \ + ptr += 4; \ + h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; \ +} while (0) + +#define XXH_PROCESS8_64 do { \ + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); \ + ptr += 8; \ + h64 ^= k1; \ + h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; \ +} while (0) + + /* Rerolled version for 32-bit targets is faster and much smaller. */ + if (XXH_REROLL || XXH_REROLL_XXH64) { + len &= 31; + while (len >= 8) { + XXH_PROCESS8_64; + len -= 8; + } + if (len >= 4) { + XXH_PROCESS4_64; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1_64; + --len; + } + return XXH64_avalanche(h64); + } else { + switch(len & 31) { + case 24: XXH_PROCESS8_64; + /* fallthrough */ + case 16: XXH_PROCESS8_64; + /* fallthrough */ + case 8: XXH_PROCESS8_64; + return XXH64_avalanche(h64); + + case 28: XXH_PROCESS8_64; + /* fallthrough */ + case 20: XXH_PROCESS8_64; + /* fallthrough */ + case 12: XXH_PROCESS8_64; + /* fallthrough */ + case 4: XXH_PROCESS4_64; + return XXH64_avalanche(h64); + + case 25: XXH_PROCESS8_64; + /* fallthrough */ + case 17: XXH_PROCESS8_64; + /* fallthrough */ + case 9: XXH_PROCESS8_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 29: XXH_PROCESS8_64; + /* fallthrough */ + case 21: XXH_PROCESS8_64; + /* fallthrough */ + case 13: XXH_PROCESS8_64; + /* fallthrough */ + case 5: XXH_PROCESS4_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 26: XXH_PROCESS8_64; + /* fallthrough */ + case 18: XXH_PROCESS8_64; + /* fallthrough */ + case 10: XXH_PROCESS8_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 30: XXH_PROCESS8_64; + /* fallthrough */ + case 22: XXH_PROCESS8_64; + /* fallthrough */ + case 14: XXH_PROCESS8_64; + /* fallthrough */ + case 6: XXH_PROCESS4_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 27: XXH_PROCESS8_64; + /* fallthrough */ + case 19: XXH_PROCESS8_64; + /* fallthrough */ + case 11: XXH_PROCESS8_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 31: XXH_PROCESS8_64; + /* fallthrough */ + case 23: XXH_PROCESS8_64; + /* fallthrough */ + case 15: XXH_PROCESS8_64; + /* fallthrough */ + case 7: XXH_PROCESS4_64; + /* fallthrough */ + case 3: XXH_PROCESS1_64; + /* fallthrough */ + case 2: XXH_PROCESS1_64; + /* fallthrough */ + case 1: XXH_PROCESS1_64; + /* fallthrough */ + case 0: return XXH64_avalanche(h64); + } + } + /* impossible to reach */ + XXH_ASSERT(0); + return 0; /* unreachable, but some compilers complain without it */ +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1_64 XXH_PROCESS1_64 +# define PROCESS4_64 XXH_PROCESS4_64 +# define PROCESS8_64 XXH_PROCESS8_64 +#else +# undef XXH_PROCESS1_64 +# undef XXH_PROCESS4_64 +# undef XXH_PROCESS8_64 +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) +{ + const xxh_u8* bEnd = input + len; + xxh_u64 h64; + +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + if (input==NULL) { + len=0; + bEnd=input=(const xxh_u8*)(size_t)32; + } +#endif + + if (len>=32) { + const xxh_u8* const limit = bEnd - 32; + xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + xxh_u64 v2 = seed + XXH_PRIME64_2; + xxh_u64 v3 = seed + 0; + xxh_u64 v4 = seed - XXH_PRIME64_1; + + do { + v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; + v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; + v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; + v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; + } while (input<=limit); + + h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); + h64 = XXH64_mergeRound(h64, v1); + h64 = XXH64_mergeRound(h64, v2); + h64 = XXH64_mergeRound(h64, v3); + h64 = XXH64_mergeRound(h64, v4); + + } else { + h64 = seed + XXH_PRIME64_5; + } + + h64 += (xxh_u64) len; + + return XXH64_finalize(h64, input, len, align); +} + + +XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t len, XXH64_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH64_state_t state; + XXH64_reset(&state, seed); + XXH64_update(&state, (const xxh_u8*)input, len); + return XXH64_digest(&state); + +#else + + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); + +#endif +} + +/******* Hash Streaming *******/ + +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) +{ + return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); +} +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState) +{ + memcpy(dstState, srcState, sizeof(*dstState)); +} + +XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t seed) +{ + XXH64_state_t state; /* use a local state to memcpy() in order to avoid strict-aliasing warnings */ + memset(&state, 0, sizeof(state)); + state.v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + state.v2 = seed + XXH_PRIME64_2; + state.v3 = seed + 0; + state.v4 = seed - XXH_PRIME64_1; + /* do not write into reserved64, might be removed in a future version */ + memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved64)); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH64_state_t* state, const void* input, size_t len) +{ + if (input==NULL) +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + return XXH_OK; +#else + return XXH_ERROR; +#endif + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); + state->memsize += (xxh_u32)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0)); + state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1)); + state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2)); + state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3)); + p += 32-state->memsize; + state->memsize = 0; + } + + if (p+32 <= bEnd) { + const xxh_u8* const limit = bEnd - 32; + xxh_u64 v1 = state->v1; + xxh_u64 v2 = state->v2; + xxh_u64 v3 = state->v3; + xxh_u64 v4 = state->v4; + + do { + v1 = XXH64_round(v1, XXH_readLE64(p)); p+=8; + v2 = XXH64_round(v2, XXH_readLE64(p)); p+=8; + v3 = XXH64_round(v3, XXH_readLE64(p)); p+=8; + v4 = XXH64_round(v4, XXH_readLE64(p)); p+=8; + } while (p<=limit); + + state->v1 = v1; + state->v2 = v2; + state->v3 = v3; + state->v4 = v4; + } + + if (p < bEnd) { + XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* state) +{ + xxh_u64 h64; + + if (state->total_len >= 32) { + xxh_u64 const v1 = state->v1; + xxh_u64 const v2 = state->v2; + xxh_u64 const v3 = state->v3; + xxh_u64 const v4 = state->v4; + + h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); + h64 = XXH64_mergeRound(h64, v1); + h64 = XXH64_mergeRound(h64, v2); + h64 = XXH64_mergeRound(h64, v3); + h64 = XXH64_mergeRound(h64, v4); + } else { + h64 = state->v3 /*seed*/ + XXH_PRIME64_5; + } + + h64 += (xxh_u64) state->total_len; + + return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); +} + + +/******* Canonical representation *******/ + +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); + memcpy(dst, &hash, sizeof(*dst)); +} + +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} + + + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ + +/* === Compiler specifics === */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#else +/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */ +# define XXH_RESTRICT /* disable */ +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) \ + || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ + || defined(__clang__) +# define XXH_likely(x) __builtin_expect(x, 1) +# define XXH_unlikely(x) __builtin_expect(x, 0) +#else +# define XXH_likely(x) (x) +# define XXH_unlikely(x) (x) +#endif + +#if defined(__GNUC__) +# if defined(__AVX2__) +# include +# elif defined(__SSE2__) +# include +# elif defined(__ARM_NEON__) || defined(__ARM_NEON) +# define inline __inline__ /* circumvent a clang bug */ +# include +# undef inline +# endif +#elif defined(_MSC_VER) +# include +#endif + +/* + * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while + * remaining a true 64-bit/128-bit hash function. + * + * This is done by prioritizing a subset of 64-bit operations that can be + * emulated without too many steps on the average 32-bit machine. + * + * For example, these two lines seem similar, and run equally fast on 64-bit: + * + * xxh_u64 x; + * x ^= (x >> 47); // good + * x ^= (x >> 13); // bad + * + * However, to a 32-bit machine, there is a major difference. + * + * x ^= (x >> 47) looks like this: + * + * x.lo ^= (x.hi >> (47 - 32)); + * + * while x ^= (x >> 13) looks like this: + * + * // note: funnel shifts are not usually cheap. + * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); + * x.hi ^= (x.hi >> 13); + * + * The first one is significantly faster than the second, simply because the + * shift is larger than 32. This means: + * - All the bits we need are in the upper 32 bits, so we can ignore the lower + * 32 bits in the shift. + * - The shift result will always fit in the lower 32 bits, and therefore, + * we can ignore the upper 32 bits in the xor. + * + * Thanks to this optimization, XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * - For the 128-bit variant, a decent byteswap helps short inputs. + * + * The first two are already required by XXH32, and almost all 32-bit and 64-bit + * platforms which can run XXH32 can run XXH3 efficiently. + * + * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one + * notable exception. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand allowing free + * shifts is helpful, too. + * + * Therefore, we do a quick sanity check. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we will + * emit a warning, as it is not a "sane" platform to compile for. + * + * Usually, if this happens, it is because of an accident and you probably need + * to specify -march, as you likely meant to compile for a newer architecture. + * + * Credit: large sections of the vectorial and asm source code paths + * have been contributed by @easyaspi314 + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ +#define XXH_SCALAR 0 /* Portable scalar version */ +#define XXH_SSE2 1 /* SSE2 for Pentium 4 and all x86_64 */ +#define XXH_AVX2 2 /* AVX2 for Haswell and Bulldozer */ +#define XXH_AVX512 3 /* AVX512 for Skylake and Icelake */ +#define XXH_NEON 4 /* NEON for most ARMv7-A and all AArch64 */ +#define XXH_VSX 5 /* VSX and ZVector for POWER8/z13 */ + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if defined(__AVX512F__) +# define XXH_VECTOR XXH_AVX512 +# elif defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif defined(__GNUC__) /* msvc support maybe later */ \ + && (defined(__ARM_NEON__) || defined(__ARM_NEON)) \ + && (defined(__LITTLE_ENDIAN__) /* We only support little endian NEON */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +# define XXH_VECTOR XXH_NEON +# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ + || (defined(__s390x__) && defined(__VEC__)) \ + && defined(__GNUC__) /* TODO: IBM XL */ +# define XXH_VECTOR XXH_VSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* + * Controls the alignment of the accumulator, + * for compatibility with aligned vector loads, which are usually faster. + */ +#ifndef XXH_ACC_ALIGN +# if defined(XXH_X86DISPATCH) +# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ +# elif XXH_VECTOR == XXH_SCALAR /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == XXH_SSE2 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == XXH_NEON /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_VSX /* vsx */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ +# define XXH_ACC_ALIGN 64 +# endif +#endif + +#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ + || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#else +# define XXH_SEC_ALIGN 8 +#endif + +/* + * UGLY HACK: + * GCC usually generates the best code with -O3 for xxHash. + * + * However, when targeting AVX2, it is overzealous in its unrolling resulting + * in code roughly 3/4 the speed of Clang. + * + * There are other issues, such as GCC splitting _mm256_loadu_si256 into + * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which + * only applies to Sandy and Ivy Bridge... which don't even support AVX2. + * + * That is why when compiling the AVX2 version, it is recommended to use either + * -O2 -mavx2 -march=haswell + * or + * -O2 -mavx2 -mno-avx256-split-unaligned-load + * for decent performance, or to use Clang instead. + * + * Fortunately, we can control the first one with a pragma that forces GCC into + * -O2, but the other one we can't control without "failed to inline always + * inline function due to target mismatch" warnings. + */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC push_options +# pragma GCC optimize("-O2") +#endif + + +#if XXH_VECTOR == XXH_NEON +/* + * NEON's setup for vmlal_u32 is a little more complicated than it is on + * SSE2, AVX2, and VSX. + * + * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast. + * + * To do the same operation, the 128-bit 'Q' register needs to be split into + * two 64-bit 'D' registers, performing this operation:: + * + * [ a | b ] + * | '---------. .--------' | + * | x | + * | .---------' '--------. | + * [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32 ] + * + * Due to significant changes in aarch64, the fastest method for aarch64 is + * completely different than the fastest method for ARMv7-A. + * + * ARMv7-A treats D registers as unions overlaying Q registers, so modifying + * D11 will modify the high half of Q5. This is similar to how modifying AH + * will only affect bits 8-15 of AX on x86. + * + * VZIP takes two registers, and puts even lanes in one register and odd lanes + * in the other. + * + * On ARMv7-A, this strangely modifies both parameters in place instead of + * taking the usual 3-operand form. + * + * Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the + * lower and upper halves of the Q register to end up with the high and low + * halves where we want - all in one instruction. + * + * vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] } + * + * Unfortunately we need inline assembly for this: Instructions modifying two + * registers at once is not possible in GCC or Clang's IR, and they have to + * create a copy. + * + * aarch64 requires a different approach. + * + * In order to make it easier to write a decent compiler for aarch64, many + * quirks were removed, such as conditional execution. + * + * NEON was also affected by this. + * + * aarch64 cannot access the high bits of a Q-form register, and writes to a + * D-form register zero the high bits, similar to how writes to W-form scalar + * registers (or DWORD registers on x86_64) work. + * + * The formerly free vget_high intrinsics now require a vext (with a few + * exceptions) + * + * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent + * of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one + * operand. + * + * The equivalent of the VZIP.32 on the lower and upper halves would be this + * mess: + * + * ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] } + * zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] } + * zip2 v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] } + * + * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN): + * + * shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32); + * xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF); + * + * This is available on ARMv7-A, but is less efficient than a single VZIP.32. + */ + +/* + * Function-like macro: + * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi) + * { + * outLo = (uint32x2_t)(in & 0xFFFFFFFF); + * outHi = (uint32x2_t)(in >> 32); + * in = UNDEFINED; + * } + */ +# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \ + && defined(__GNUC__) \ + && !defined(__aarch64__) && !defined(__arm64__) +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ + /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ + /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ + __asm__("vzip.32 %e0, %f0" : "+w" (in)); \ + (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ + (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ + } while (0) +# else +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + (outLo) = vmovn_u64 (in); \ + (outHi) = vshrn_n_u64 ((in), 32); \ + } while (0) +# endif +#endif /* XXH_VECTOR == XXH_NEON */ + +/* + * VSX and Z Vector helpers. + * + * This is very messy, and any pull requests to clean this up are welcome. + * + * There are a lot of problems with supporting VSX and s390x, due to + * inconsistent intrinsics, spotty coverage, and multiple endiannesses. + */ +#if XXH_VECTOR == XXH_VSX +# if defined(__s390x__) +# include +# else +/* gcc's altivec.h can have the unwanted consequence to unconditionally + * #define bool, vector, and pixel keywords, + * with bad consequences for programs already using these keywords for other purposes. + * The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined. + * __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler, + * but it seems that, in some cases, it isn't. + * Force the build macro to be defined, so that keywords are not altered. + */ +# if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__) +# define __APPLE_ALTIVEC__ +# endif +# include +# endif + +typedef __vector unsigned long long xxh_u64x2; +typedef __vector unsigned char xxh_u8x16; +typedef __vector unsigned xxh_u32x4; + +# ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +# endif /* !defined(XXH_VSX_BE) */ + +# if XXH_VSX_BE +/* A wrapper for POWER9's vec_revb. */ +# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) +# define XXH_vec_revb vec_revb +# else +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) +{ + xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif +# endif /* XXH_VSX_BE */ + +/* + * Performs an unaligned load and byte swaps it on big endian. + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) +{ + xxh_u64x2 ret; + memcpy(&ret, ptr, sizeof(xxh_u64x2)); +# if XXH_VSX_BE + ret = XXH_vec_revb(ret); +# endif + return ret; +} + +/* + * vec_mulo and vec_mule are very problematic intrinsics on PowerPC + * + * These intrinsics weren't added until GCC 8, despite existing for a while, + * and they are endian dependent. Also, their meaning swap depending on version. + * */ +# if defined(__s390x__) + /* s390x is always big endian, no issue on this platform */ +# define XXH_vec_mulo vec_mulo +# define XXH_vec_mule vec_mule +# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) +/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +# else +/* gcc needs inline assembly */ +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +# endif /* XXH_vec_mulo, XXH_vec_mule */ +#endif /* XXH_VECTOR == XXH_VSX */ + + +/* prefetch + * can be disabled, by declaring XXH_NO_PREFETCH build macro */ +#if defined(XXH_NO_PREFETCH) +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# else +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* XXH_NO_PREFETCH */ + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +/* Pseudorandom secret taken directly from FARSH */ +XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + + +#ifdef XXH_OLD_NAMES +# define kSecret XXH3_kSecret +#endif + +/* + * Calculates a 32-bit to 64-bit long multiply. + * + * Wraps __emulu on MSVC x86 because it tends to call __allmul when it doesn't + * need to (but it shouldn't need to anyways, it is about 7 instructions to do + * a 64x64 multiply...). Since we know that this will _always_ emit MULL, we + * use that instead of the normal method. + * + * If you are compiling for platforms like Thumb-1 and don't have a better option, + * you may also want to write your own long multiply routine here. + * + * XXH_FORCE_INLINE xxh_u64 XXH_mult32to64(xxh_u64 x, xxh_u64 y) + * { + * return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); + * } + */ +#if defined(_MSC_VER) && defined(_M_IX86) +# include +# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) +#else +/* + * Downcast + upcast is usually better than masking on older compilers like + * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. + * + * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands + * and perform a full 64x64 multiply -- entirely redundant on 32-bit. + */ +# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) +#endif + +/* + * Calculates a 64->128-bit long multiply. + * + * Uses __uint128_t and _umul128 if available, otherwise uses a scalar version. + */ +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this type + * despite not having the arithmetic for it. This results in a laggy + * compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if defined(__GNUC__) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t r128; + r128.low64 = (xxh_u64)(product); + r128.high64 = (xxh_u64)(product >> 64); + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif defined(_M_X64) || defined(_M_IA64) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t r128; + r128.low64 = product_low; + r128.high64 = product_high; + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown below + * with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 + * --------- + * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. + * This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARM's Digital Signal Processing extension + * in 32-bit ARMv6 and later, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, and + * allows this to be calculated in only 4 instructions at speeds + * comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be a couple + * of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128; + r128.low64 = lower; + r128.high64 = upper; + return r128; +#endif +} + +/* + * Does a 64-bit to 128-bit multiply, then XOR folds it. + * + * The reason for the separate function is to prevent passing too many structs + * around by value. This will hopefully inline the multiply, but we don't force it. + */ +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + +/* Seems to produce slightly better code on GCC for some reason. */ +XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) +{ + XXH_ASSERT(0 <= shift && shift < 64); + return v64 ^ (v64 >> shift); +} + +/* + * This is a fast avalanche stage, + * suitable when input bits are already partially mixed + */ +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 = XXH_xorshift64(h64, 37); + h64 *= 0x165667919E3779F9ULL; + h64 = XXH_xorshift64(h64, 32); + return h64; +} + +/* + * This is a stronger avalanche, + * inspired by Pelle Evensen's rrmxmx + * preferable when input has not been previously mixed + */ +static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) +{ + /* this mix is inspired by Pelle Evensen's rrmxmx */ + h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); + h64 *= 0x9FB21C651E98DF25ULL; + h64 ^= (h64 >> 35) + len ; + h64 *= 0x9FB21C651E98DF25ULL; + return XXH_xorshift64(h64, 28); +} + + +/* ========================================== + * Short keys + * ========================================== + * One of the shortcomings of XXH32 and XXH64 was that their performance was + * sub-optimal on short lengths. It used an iterative algorithm which strongly + * favored lengths that were a multiple of 4 or 8. + * + * Instead of iterating over individual inputs, we use a set of single shot + * functions which piece together a range of lengths and operate in constant time. + * + * Additionally, the number of multiplies has been significantly reduced. This + * reduces latency, especially when emulating 64-bit multiplies on 32-bit. + * + * Depending on the platform, this may or may not be faster than XXH32, but it + * is almost guaranteed to be faster than XXH64. + */ + +/* + * At very short lengths, there isn't enough input to fully hide secrets, or use + * the entire secret. + * + * There is also only a limited amount of mixing we can do before significantly + * impacting performance. + * + * Therefore, we use different sections of the secret and always mix two secret + * samples with an XOR. This should have no effect on performance on the + * seedless or withSeed variants because everything _should_ be constant folded + * by modern compilers. + * + * The XOR mixing hides individual parts of the secret and increases entropy. + * + * This adds an extra layer of strength for custom secrets. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combined = { input[0], 0x01, input[0], input[0] } + * len = 2: combined = { input[1], 0x02, input[0], input[1] } + * len = 3: combined = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; + return XXH64_avalanche(keyed); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len < 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input1 = XXH_readLE32(input); + xxh_u32 const input2 = XXH_readLE32(input + len - 4); + xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; + xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); + xxh_u64 const keyed = input64 ^ bitflip; + return XXH3_rrmxmx(keyed, len); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(8 <= len && len <= 16); + { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; + xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; + xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; + xxh_u64 const acc = len + + XXH_swap64(input_lo) + input_hi + + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); + if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); + } +} + +/* + * DISCLAIMER: There are known *seed-dependent* multicollisions here due to + * multiplication by zero, affecting hashes of lengths 17 to 240. + * + * However, they are very unlikely. + * + * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all + * unseeded non-cryptographic hashes, it does not attempt to defend itself + * against specially crafted inputs, only random inputs. + * + * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes + * cancelling out the secret is taken an arbitrary number of times (addressed + * in XXH3_accumulate_512), this collision is very unlikely with random inputs + * and/or proper seeding: + * + * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a + * function that is only called up to 16 times per hash with up to 240 bytes of + * input. + * + * This is not too bad for a non-cryptographic hash function, especially with + * only 64 bit outputs. + * + * The 128-bit variant (which trades some speed for strength) is NOT affected + * by this, although it is always a good idea to use a proper seed if you care + * about strength. + */ +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ +#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ + /* + * UGLY HACK: + * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in + * slower code. + * + * By forcing seed64 into a register, we disrupt the cost model and + * cause it to scalarize. See `XXH32_round()` + * + * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, + * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on + * GCC 9.2, despite both emitting scalar code. + * + * GCC generates much better scalar code than Clang for the rest of XXH3, + * which is why finding a more optimal codepath is an interest. + */ + __asm__ ("" : "+r" (seed64)); +#endif + { xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) + ); + } +} + +/* For mid range keys, XXH3 uses a Mum-hash variant. */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * XXH_PRIME64_1; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); + + return XXH3_avalanche(acc); + } +} + +#define XXH3_MIDSIZE_MAX 240 + +XXH_NO_INLINE XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * XXH_PRIME64_1; + int const nbRounds = (int)len / 16; + int i; + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + acc = XXH3_avalanche(acc); + XXH_ASSERT(nbRounds >= 8); +#if defined(__clang__) /* Clang */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. + * In everywhere else, it uses scalar code. + * + * For 64->128-bit multiplies, even if the NEON was 100% optimal, it + * would still be slower than UMAAL (see XXH_mult64to128). + * + * Unfortunately, Clang doesn't handle the long multiplies properly and + * converts them to the nonexistent "vmulq_u64" intrinsic, which is then + * scalarized into an ugly mess of VMOV.32 instructions. + * + * This mess is difficult to avoid without turning autovectorization + * off completely, but they are usually relatively minor and/or not + * worth it to fix. + * + * This loop is the easiest to fix, as unlike XXH32, this pragma + * _actually works_ because it is a loop vectorization instead of an + * SLP vectorization. + */ + #pragma clang loop vectorize(disable) +#endif + for (i=8 ; i < nbRounds; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + /* last bytes */ + acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + return XXH3_avalanche(acc); + } +} + + +/* ======= Long Keys ======= */ + +#define XXH_STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) + +#ifdef XXH_OLD_NAMES +# define STRIPE_LEN XXH_STRIPE_LEN +# define ACC_NB XXH_ACC_NB +#endif + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + memcpy(dst, &v64, sizeof(v64)); +} + +/* Several intrinsic functions below are supposed to accept __int64 as argument, + * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . + * However, several environments do not define __int64 type, + * requiring a workaround. + */ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) + typedef int64_t xxh_i64; +#else + /* the following type must have a width of 64-bit */ + typedef long long xxh_i64; +#endif + +/* + * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. + * + * It is a hardened version of UMAC, based off of FARSH's implementation. + * + * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD + * implementations, and it is ridiculously fast. + * + * We harden it by mixing the original input to the accumulators as well as the product. + * + * This means that in the (relatively likely) case of a multiply by zero, the + * original input is preserved. + * + * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve + * cross-pollination, as otherwise the upper and lower halves would be + * essentially independent. + * + * This doesn't matter on 64-bit hashes since they all get merged together in + * the end, so we skip the extra step. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +#if (XXH_VECTOR == XXH_AVX512) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_AVX512 +# define XXH_TARGET_AVX512 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ALIGN(64) __m512i* const xacc = (__m512i *) acc; + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + + { + /* data_vec = input[0]; */ + __m512i const data_vec = _mm512_loadu_si512 (input); + /* key_vec = secret[0]; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + /* data_key = data_vec ^ key_vec; */ + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); + /* xacc[0] += swap(data_vec); */ + __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); + __m512i const sum = _mm512_add_epi64(*xacc, data_swap); + /* xacc[0] += product; */ + *xacc = _mm512_add_epi64(product, sum); + } +} + +/* + * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. + * + * Multiplication isn't perfect, as explained by Google in HighwayHash: + * + * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + * // varying degrees. In descending order of goodness, bytes + * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + * // As expected, the upper and lower bytes are much worse. + * + * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 + * + * Since our algorithm uses a pseudorandom secret to add some variance into the + * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. + * + * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid + * extraction. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + { XXH_ALIGN(64) __m512i* const xacc = (__m512i*) acc; + const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); + + /* xacc[0] ^= (xacc[0] >> 47) */ + __m512i const acc_vec = *xacc; + __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); + __m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted); + /* xacc[0] ^= secret; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + + /* xacc[0] *= XXH_PRIME32_1; */ + __m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); + __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); + *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); + XXH_ASSERT(((size_t)customSecret & 63) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); + __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, -(xxh_i64)seed64); + + XXH_ALIGN(64) const __m512i* const src = (const __m512i*) XXH3_kSecret; + XXH_ALIGN(64) __m512i* const dest = ( __m512i*) customSecret; + int i; + for (i=0; i < nbRounds; ++i) { + /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', + * this will warn "discards โ€˜constโ€™ qualifier". */ + union { + XXH_ALIGN(64) const __m512i* cp; + XXH_ALIGN(64) void* p; + } remote_const_void; + remote_const_void.cp = src + i; + dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_AVX2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_AVX2 +# define XXH_TARGET_AVX2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { XXH_ALIGN(32) __m256i* const xacc = (__m256i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xinput = (const __m256i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm256_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { XXH_ALIGN(32) __m256i* const xacc = (__m256i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); + (void)(&XXH_writeLE64); + XXH_PREFETCH(customSecret); + { __m256i const seed = _mm256_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64, -(xxh_i64)seed64, (xxh_i64)seed64); + + XXH_ALIGN(64) const __m256i* const src = (const __m256i*) XXH3_kSecret; + XXH_ALIGN(64) __m256i* dest = ( __m256i*) customSecret; + +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + * The asm hack causes Clang to assume that XXH3_kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + __asm__("" : "+r" (dest)); +# endif + + /* GCC -O2 need unroll loop manually */ + dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); + dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); + dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); + dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); + dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); + dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed); + } +} + +#endif + +#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_SSE2 +# define XXH_TARGET_SSE2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* SSE2 is just a half-scale version of the AVX2 version. */ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { XXH_ALIGN(16) __m128i* const xacc = (__m128i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xinput = (const __m128i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { XXH_ALIGN(16) __m128i* const xacc = (__m128i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); + +# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 + // MSVC 32bit mode does not support _mm_set_epi64x before 2015 + XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, -(xxh_i64)seed64 }; + __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); +# else + __m128i const seed = _mm_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64); +# endif + int i; + + XXH_ALIGN(64) const float* const src = (float const*) XXH3_kSecret; + XXH_ALIGN(XXH_SEC_ALIGN) __m128i* dest = (__m128i*) customSecret; +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + __asm__("" : "+r" (dest)); +# endif + + for (i=0; i < nbRounds; ++i) { + dest[i] = _mm_add_epi64(_mm_castps_si128(_mm_load_ps(src+i*4)), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_NEON) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { + XXH_ALIGN(16) uint64x2_t* const xacc = (uint64x2_t *) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* const xinput = (const uint8_t *) input; + uint8_t const* const xsecret = (const uint8_t *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN / sizeof(uint64x2_t); i++) { + /* data_vec = xinput[i]; */ + uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key; + uint32x2_t data_key_lo, data_key_hi; + /* xacc[i] += swap(data_vec); */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped = vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + /* data_key = data_vec ^ key_vec; */ + data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); + /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (data_key >> 32); + * data_key = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ + xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); + + } + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { uint64x2_t* xacc = (uint64x2_t*) acc; + uint8_t const* xsecret = (uint8_t const*) secret; + uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(uint64x2_t); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + uint64x2_t acc_vec = xacc[i]; + uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); + uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); + + /* xacc[i] ^= xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key = veorq_u64(data_vec, vreinterpretq_u64_u8(key_vec)); + + /* xacc[i] *= XXH_PRIME32_1 */ + uint32x2_t data_key_lo, data_key_hi; + /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (xacc[i] >> 32); + * xacc[i] = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + { /* + * prod_hi = (data_key >> 32) * XXH_PRIME32_1; + * + * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will + * incorrectly "optimize" this: + * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b)); + * shifted = vshll_n_u32(tmp, 32); + * to this: + * tmp = "vmulq_u64"(a, b); // no such thing! + * shifted = vshlq_n_u64(tmp, 32); + * + * However, unlike SSE, Clang lacks a 64-bit multiply routine + * for NEON, and it scalarizes two 64-bit multiplies instead. + * + * vmull_u32 has the same timing as vmul_u32, and it avoids + * this bug completely. + * See https://bugs.llvm.org/show_bug.cgi?id=39967 + */ + uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime); + /* xacc[i] = prod_hi << 32; */ + xacc[i] = vshlq_n_u64(prod_hi, 32); + /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */ + xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime); + } + } } +} + +#endif + +#if (XXH_VECTOR == XXH_VSX) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + xxh_u64x2* const xacc = (xxh_u64x2*) acc; /* presumed aligned */ + xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ + xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ + xxh_u64x2 const v32 = { 32, 32 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* data_vec = xinput[i]; */ + xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i); + /* key_vec = xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + /* shuffled = (data_key << 32) | (data_key >> 32); */ + xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); + /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ + xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); + xacc[i] += product; + + /* swap high and low halves */ +#ifdef __s390x__ + xacc[i] += vec_permi(data_vec, data_vec, 2); +#else + xacc[i] += vec_xxpermdi(data_vec, data_vec, 2); +#endif + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_u64x2* const xacc = (xxh_u64x2*) acc; + const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; + /* constants */ + xxh_u64x2 const v32 = { 32, 32 }; + xxh_u64x2 const v47 = { 47, 47 }; + xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + xxh_u64x2 const acc_vec = xacc[i]; + xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + + /* xacc[i] ^= xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + + /* xacc[i] *= XXH_PRIME32_1 */ + /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ + xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); + /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ + xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } } +} + +#endif + +/* scalar variants - universal */ + +XXH_FORCE_INLINE void +XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xinput = (const xxh_u8*) input; /* no alignment restriction */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + size_t i; + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + for (i=0; i < XXH_ACC_NB; i++) { + xxh_u64 const data_val = XXH_readLE64(xinput + 8*i); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + i*8); + xacc[i ^ 1] += data_val; /* swap adjacent lanes */ + xacc[i] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + size_t i; + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + for (i=0; i < XXH_ACC_NB; i++) { + xxh_u64 const key64 = XXH_readLE64(xsecret + 8*i); + xxh_u64 acc64 = xacc[i]; + acc64 = XXH_xorshift64(acc64, 47); + acc64 ^= key64; + acc64 *= XXH_PRIME32_1; + xacc[i] = acc64; + } +} + +XXH_FORCE_INLINE void +XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + /* + * We need a separate pointer for the hack below, + * which requires a non-const pointer. + * Any decent compiler will optimize this out otherwise. + */ + const xxh_u8* kSecretPtr = XXH3_kSecret; + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + +#if defined(__clang__) && defined(__aarch64__) + /* + * UGLY HACK: + * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are + * placed sequentially, in order, at the top of the unrolled loop. + * + * While MOVK is great for generating constants (2 cycles for a 64-bit + * constant compared to 4 cycles for LDR), long MOVK chains stall the + * integer pipelines: + * I L S + * MOVK + * MOVK + * MOVK + * MOVK + * ADD + * SUB STR + * STR + * By forcing loads from memory (as the asm line causes Clang to assume + * that XXH3_kSecretPtr has been changed), the pipelines are used more + * efficiently: + * I L S + * LDR + * ADD LDR + * SUB STR + * STR + * XXH3_64bits_withSeed, len == 256, Snapdragon 835 + * without hack: 2654.4 MB/s + * with hack: 3202.9 MB/s + */ + __asm__("" : "+r" (kSecretPtr)); +#endif + /* + * Note: in debug mode, this overrides the asm optimization + * and Clang will emit MOVK chains again. + */ + XXH_ASSERT(kSecretPtr == XXH3_kSecret); + + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + for (i=0; i < nbRounds; i++) { + /* + * The asm hack causes Clang to assume that kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; + xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; + XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); + XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); + } } +} + + +typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*); +typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); +typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); + + +#if (XXH_VECTOR == XXH_AVX512) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 + +#elif (XXH_VECTOR == XXH_AVX2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 + +#elif (XXH_VECTOR == XXH_SSE2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 + +#elif (XXH_VECTOR == XXH_NEON) + +#define XXH3_accumulate_512 XXH3_accumulate_512_neon +#define XXH3_scrambleAcc XXH3_scrambleAcc_neon +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_VSX) + +#define XXH3_accumulate_512 XXH3_accumulate_512_vsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#else /* scalar */ + +#define XXH3_accumulate_512 XXH3_accumulate_512_scalar +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#endif + + + +#ifndef XXH_PREFETCH_DIST +# ifdef __clang__ +# define XXH_PREFETCH_DIST 320 +# else +# if (XXH_VECTOR == XXH_AVX512) +# define XXH_PREFETCH_DIST 512 +# else +# define XXH_PREFETCH_DIST 384 +# endif +# endif /* __clang__ */ +#endif /* XXH_PREFETCH_DIST */ + +/* + * XXH3_accumulate() + * Loops over XXH3_accumulate_512(). + * Assumption: nbStripes will not overflow the secret size + */ +XXH_FORCE_INLINE void +XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes, + XXH3_f_accumulate_512 f_acc512) +{ + size_t n; + for (n = 0; n < nbStripes; n++ ) { + const xxh_u8* const in = input + n*XXH_STRIPE_LEN; + XXH_PREFETCH(in + XXH_PREFETCH_DIST); + f_acc512(acc, + in, + secret + n*XXH_SECRET_CONSUME_RATE); + } +} + +XXH_FORCE_INLINE void +XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; + size_t const nb_blocks = (len - 1) / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > XXH_STRIPE_LEN); + { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512); + + /* last stripe */ + { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ + f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + size_t i = 0; + + for (i = 0; i < 4; i++) { + result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); +#if defined(__clang__) /* Clang */ \ + && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Prevent autovectorization on Clang ARMv7-a. Exact same problem as + * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. + * XXH3_64bits, len == 256, Snapdragon 835: + * without hack: 2063.7 MB/s + * with hack: 2560.7 MB/s + */ + __asm__("" : "+r" (result64)); +#endif + } + + return XXH3_avalanche(result64); +} + +#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ + XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, + const void* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + /* do not align on 8, so that the secret is different from the accumulator */ +#define XXH_SECRET_MERGEACCS_START 11 + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + * Since the function is not inlined, the compiler may not be able to understand that, + * in some scenarios, its `secret` argument is actually a compile time constant. + * This variant enforces that the compiler can detect that, + * and uses this opportunity to streamline the generated code for better performance. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * XXH3_hashLong_64b_withSeed(): + * Generate a custom key based on alteration of default XXH3_kSecret with the seed, + * and then use this key for long mode hashing. + * + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + * + * It's important for performance that XXH3_hashLong is not inlined. Not sure + * why (uop cache maybe?), but the difference is large and easily measurable. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, + XXH64_hash_t seed, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed == 0) + return XXH3_hashLong_64b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed); + return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed(const void* input, size_t len, + XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_64b_withSeed_internal(input, len, seed, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + + +typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong64_f f_hashLong) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secretLen` condition is not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + * Also, note that function signature doesn't offer room to return an error. + */ + if (len <= 16) + return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); +} + + +/* === Public entry point === */ + +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) +{ + return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); +} + + +/* === XXH3 streaming === */ + +/* + * Malloc's a pointer that is always aligned to align. + * + * This must be freed with `XXH_alignedFree()`. + * + * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte + * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 + * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. + * + * This underalignment previously caused a rather obvious crash which went + * completely unnoticed due to XXH3_createState() not actually being tested. + * Credit to RedSpah for noticing this bug. + * + * The alignment is done manually: Functions like posix_memalign or _mm_malloc + * are avoided: To maintain portability, we would have to write a fallback + * like this anyways, and besides, testing for the existence of library + * functions without relying on external build tools is impossible. + * + * The method is simple: Overallocate, manually align, and store the offset + * to the original behind the returned pointer. + * + * Align must be a power of 2 and 8 <= align <= 128. + */ +static void* XXH_alignedMalloc(size_t s, size_t align) +{ + XXH_ASSERT(align <= 128 && align >= 8); /* range check */ + XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ + XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ + { /* Overallocate to make room for manual realignment and an offset byte */ + xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); + if (base != NULL) { + /* + * Get the offset needed to align this pointer. + * + * Even if the returned pointer is aligned, there will always be + * at least one byte to store the offset to the original pointer. + */ + size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ + /* Add the offset for the now-aligned pointer */ + xxh_u8* ptr = base + offset; + + XXH_ASSERT((size_t)ptr % align == 0); + + /* Store the offset immediately before the returned pointer. */ + ptr[-1] = (xxh_u8)offset; + return ptr; + } + return NULL; + } +} +/* + * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass + * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. + */ +static void XXH_alignedFree(void* p) +{ + if (p != NULL) { + xxh_u8* ptr = (xxh_u8*)p; + /* Get the offset byte we added in XXH_malloc. */ + xxh_u8 offset = ptr[-1]; + /* Free the original malloc'd pointer */ + xxh_u8* base = ptr - offset; + XXH_free(base); + } +} +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); + if (state==NULL) return NULL; + XXH3_INITSTATE(state); + return state; +} + +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_alignedFree(statePtr); + return XXH_OK; +} + +XXH_PUBLIC_API void +XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) +{ + memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_64bits_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + size_t const initStart = offsetof(XXH3_state_t, bufferedSize); + size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; + XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); + XXH_ASSERT(statePtr != NULL); + /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ + memset((char*)statePtr + initStart, 0, initLength); + statePtr->acc[0] = XXH_PRIME32_3; + statePtr->acc[1] = XXH_PRIME64_1; + statePtr->acc[2] = XXH_PRIME64_2; + statePtr->acc[3] = XXH_PRIME64_3; + statePtr->acc[4] = XXH_PRIME64_4; + statePtr->acc[5] = XXH_PRIME32_2; + statePtr->acc[6] = XXH_PRIME64_5; + statePtr->acc[7] = XXH_PRIME32_1; + statePtr->seed = seed; + statePtr->extSecret = (const unsigned char*)secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_64bits_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_64bits_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_64bits_reset(statePtr); + if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_64bits_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/* Note : when XXH3_consumeStripes() is invoked, + * there must be a guarantee that at least one more byte must be consumed from input + * so that the function can blindly consume all stripes using the "normal" secret segment */ +XXH_FORCE_INLINE void +XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, + size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, + const xxh_u8* XXH_RESTRICT input, size_t nbStripes, + const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ + XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); + if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { + /* need a scrambling operation */ + size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; + size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); + f_scramble(acc, secret + secretLimit); + XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); + *nbStripesSoFarPtr = nbStripesAfterBlock; + } else { + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); + *nbStripesSoFarPtr += nbStripes; + } +} + +/* + * Both XXH3_64bits_update and XXH3_128bits_update use this routine. + */ +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* state, + const xxh_u8* input, size_t len, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + if (input==NULL) +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + return XXH_OK; +#else + return XXH_ERROR; +#endif + + { const xxh_u8* const bEnd = input + len; + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + + state->totalLen += len; + + if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { /* fill in tmp buffer */ + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + /* total input is now > XXH3_INTERNALBUFFER_SIZE */ + + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ + + /* + * Internal buffer is partially filled (always, except at beginning) + * Complete it, then consume it. + */ + if (state->bufferedSize) { + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(state->acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + state->bufferedSize = 0; + } + XXH_ASSERT(input < bEnd); + + /* Consume input by a multiple of internal buffer size */ + if (input+XXH3_INTERNALBUFFER_SIZE < bEnd) { + const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; + do { + XXH3_consumeStripes(state->acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + input += XXH3_INTERNALBUFFER_SIZE; + } while (inputbuffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + } + XXH_ASSERT(input < bEnd); + + /* Some remaining input (always) : buffer it */ + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); + } + + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, + const XXH3_state_t* state, + const unsigned char* secret) +{ + /* + * Digest on a local copy. This way, the state remains unaltered, and it can + * continue ingesting more input afterwards. + */ + memcpy(acc, state->acc, sizeof(state->acc)); + if (state->bufferedSize >= XXH_STRIPE_LEN) { + size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; + size_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, nbStripes, + secret, state->secretLimit, + XXH3_accumulate_512, XXH3_scrambleAcc); + /* last stripe */ + XXH3_accumulate_512(acc, + state->buffer + state->bufferedSize - XXH_STRIPE_LEN, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } else { /* bufferedSize < XXH_STRIPE_LEN */ + xxh_u8 lastStripe[XXH_STRIPE_LEN]; + size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; + XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ + memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + XXH3_accumulate_512(acc, + lastStripe, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } +} + +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + return XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + } + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if (state->seed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + + +#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +XXH_PUBLIC_API void +XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize) +{ + XXH_ASSERT(secretBuffer != NULL); + if (customSeedSize == 0) { + memcpy(secretBuffer, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return; + } + XXH_ASSERT(customSeed != NULL); + + { size_t const segmentSize = sizeof(XXH128_hash_t); + size_t const nbSegments = XXH_SECRET_DEFAULT_SIZE / segmentSize; + XXH128_canonical_t scrambler; + XXH64_hash_t seeds[12]; + size_t segnb; + XXH_ASSERT(nbSegments == 12); + XXH_ASSERT(segmentSize * nbSegments == XXH_SECRET_DEFAULT_SIZE); /* exact multiple */ + XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); + + /* + * Copy customSeed to seeds[], truncating or repeating as necessary. + */ + { size_t toFill = XXH_MIN(customSeedSize, sizeof(seeds)); + size_t filled = toFill; + memcpy(seeds, customSeed, toFill); + while (filled < sizeof(seeds)) { + toFill = XXH_MIN(filled, sizeof(seeds) - filled); + memcpy((char*)seeds + filled, seeds, toFill); + filled += toFill; + } } + + /* generate secret */ + memcpy(secretBuffer, &scrambler, sizeof(scrambler)); + for (segnb=1; segnb < nbSegments; segnb++) { + size_t const segmentStart = segnb * segmentSize; + XXH128_canonical_t segment; + XXH128_canonicalFromHash(&segment, + XXH128(&scrambler, sizeof(scrambler), XXH_readLE64(seeds + segnb) + segnb) ); + memcpy((char*)secretBuffer + segmentStart, &segment, sizeof(segment)); + } } +} + + +/* ========================================== + * XXH3 128 bits (a.k.a XXH128) + * ========================================== + * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, + * even without counting the significantly larger output size. + * + * For example, extra steps are taken to avoid the seed-dependent collisions + * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). + * + * This strength naturally comes at the cost of some speed, especially on short + * lengths. Note that longer hashes are about as fast as the 64-bit version + * due to it using only a slight modification of the 64-bit loop. + * + * XXH128 is also more oriented towards 64-bit machines. It is still extremely + * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). + */ + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + /* A doubled version of 1to3_64b with different constants. */ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } + * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } + * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); + xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; + XXH128_hash_t h128; + h128.low64 = XXH64_avalanche(keyed_lo); + h128.high64 = XXH64_avalanche(keyed_hi); + return h128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; + xxh_u64 const keyed = input_64 ^ bitflip; + + /* Shift len to the left to ensure it is even, this avoids even multiplies. */ + XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); + + m128.high64 += (m128.low64 << 1); + m128.low64 ^= (m128.high64 >> 3); + + m128.low64 = XXH_xorshift64(m128.low64, 35); + m128.low64 *= 0x9FB21C651E98DF25ULL; + m128.low64 = XXH_xorshift64(m128.low64, 28); + m128.high64 = XXH3_avalanche(m128.high64); + return m128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; + xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 input_hi = XXH_readLE64(input + len - 8); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); + /* + * Put len in the middle of m128 to ensure that the length gets mixed to + * both the low and high bits in the 128x64 multiply below. + */ + m128.low64 += (xxh_u64)(len - 1) << 54; + input_hi ^= bitfliph; + /* + * Add the high 32 bits of input_hi to the high 32 bits of m128, then + * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to + * the high 64 bits of m128. + * + * The best approach to this operation is different on 32-bit and 64-bit. + */ + if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ + /* + * 32-bit optimized version, which is more readable. + * + * On 32-bit, it removes an ADC and delays a dependency between the two + * halves of m128.high64, but it generates an extra mask on 64-bit. + */ + m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); + } else { + /* + * 64-bit optimized (albeit more confusing) version. + * + * Uses some properties of addition and multiplication to remove the mask: + * + * Let: + * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) + * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) + * c = XXH_PRIME32_2 + * + * a + (b * c) + * Inverse Property: x + y - x == y + * a + (b * (1 + c - 1)) + * Distributive Property: x * (y + z) == (x * y) + (x * z) + * a + (b * 1) + (b * (c - 1)) + * Identity Property: x * 1 == x + * a + b + (b * (c - 1)) + * + * Substitute a, b, and c: + * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + * + * Since input_hi.hi + input_hi.lo == input_hi, we get this: + * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + */ + m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); + } + /* m128 ^= XXH_swap64(m128 >> 64); */ + m128.low64 ^= XXH_swap64(m128.high64); + + { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ + XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); + h128.high64 += m128.high64 * XXH_PRIME64_2; + + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* + * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t h128; + xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); + xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); + h128.low64 = XXH64_avalanche(seed ^ bitflipl); + h128.high64 = XXH64_avalanche( seed ^ bitfliph); + return h128; + } } +} + +/* + * A bit slower than XXH3_mix16B, but handles multiply by zero better. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, + const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_NO_INLINE XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + int const nbRounds = (int)len / 32; + int i; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + for (i=0; i<4; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + (32 * i), + seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + XXH_ASSERT(nbRounds >= 4); + for (i=4 ; i < nbRounds; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), + seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, + input + len - 16, + input + len - 32, + secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, + 0ULL - seed); + + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)len * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + secretSize + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)len * XXH_PRIME64_2)); + return h128; + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed64 == 0) + return XXH3_hashLong_128b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed64); + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + +typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const void* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_128bits_internal(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong128_f f_hl128) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secret` conditions are not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + */ + if (len <= 16) + return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hl128(input, len, seed64, secret, secretLen); +} + + +/* === Public XXH128 API === */ + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) +{ + return XXH3_128bits_internal(input, len, 0, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_default); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_128bits_internal(input, len, 0, + (const xxh_u8*)secret, secretSize, + XXH3_hashLong_128b_withSecret); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_internal(input, len, seed, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_withSeed); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH128(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ + +/* + * All the functions are actually the same as for 64-bit streaming variant. + * The only difference is the finalizatiom routine. + */ + +static void +XXH3_128bits_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + XXH3_64bits_reset_internal(statePtr, seed, secret, secretSize); +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_128bits_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_128bits_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_128bits_reset(statePtr); + if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_128bits_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + state->secretLimit + XXH_STRIPE_LEN + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); + return h128; + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + +/* 128-bit utility functions */ + +#include /* memcmp, memcpy */ + +/* return : 1 is equal, 0 if different */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + memcpy(dst, &hash.high64, sizeof(hash.high64)); + memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + +/* Pop our optimization override from above */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC pop_options +#endif + +#endif /* XXH_NO_LONG_LONG */ + + +#endif /* XXH_IMPLEMENTATION */ #if defined (__cplusplus) diff --git a/ext/zlib/gzguts.h b/ext/zlib/gzguts.h index d87659d031..cbd680da48 100644 --- a/ext/zlib/gzguts.h +++ b/ext/zlib/gzguts.h @@ -27,6 +27,10 @@ #endif #include +#ifdef __APPLE__ +#include +#endif + #ifdef _WIN32 # include #endif diff --git a/ffmpeg b/ffmpeg index 55147e5f33..d3e695286c 160000 --- a/ffmpeg +++ b/ffmpeg @@ -1 +1 @@ -Subproject commit 55147e5f33f5ae4904f75ec082af809267122b94 +Subproject commit d3e695286cce346274192c214c00f021c00cd575 diff --git a/git-version.cmake b/git-version.cmake index 97a9de9710..efd4983b8c 100644 --- a/git-version.cmake +++ b/git-version.cmake @@ -23,13 +23,6 @@ if(EXISTS ${GIT_VERSION_FILE}) if(NOT ${match} EQUAL "") set(GIT_VERSION_UPDATE "0") endif() - - # Don't update if it's already the same. - file(STRINGS ${GIT_VERSION_FILE} match - REGEX "${GIT_VERSION}") - if(NOT ${match} EQUAL "") - set(GIT_VERSION_UPDATE "0") - endif() endif() set(code_string "// This is a generated file.\n\n" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2f632ddb58..3967b35ba1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Feb 25 00:57:06 CET 2020 +#Thu May 28 22:53:27 CEST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/headless/Compare.cpp b/headless/Compare.cpp index ba35b93c90..8036090001 100644 --- a/headless/Compare.cpp +++ b/headless/Compare.cpp @@ -16,10 +16,9 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "headless/Compare.h" -#include "file/file_util.h" #include "Common/ColorConv.h" -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" #include "Core/Host.h" #include "GPU/GPUState.h" diff --git a/headless/Headless.cpp b/headless/Headless.cpp index d59b2a82f3..20b845ba2e 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -9,10 +9,15 @@ #include #endif -#include "file/zip_read.h" -#include "profiler/profiler.h" -#include "Common/FileUtil.h" +#include "Common/Profiler/Profiler.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" + +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" +#include "Common/File/FileUtil.h" #include "Common/GraphicsContext.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Core.h" @@ -21,11 +26,9 @@ #include "Core/HLE/sceUtility.h" #include "Core/Host.h" #include "Core/SaveState.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "Log.h" #include "LogManager.h" -#include "base/NativeApp.h" -#include "base/timeutil.h" #include "Compare.h" #include "StubHost.h" @@ -169,12 +172,11 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool if (autoCompare) headlessHost->SetComparisonScreenshot(ExpectedScreenshotFromFilename(coreParameter.fileToStart)); - time_update(); bool passed = true; // TODO: We must have some kind of stack overflow or we're not following the ABI right. // This gets trashed if it's not static. static double deadline; - deadline = time_now() + timeout; + deadline = time_now_d() + timeout; Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops); @@ -193,7 +195,6 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool coreState = CORE_RUNNING; headlessHost->SwapBuffers(); } - time_update(); if (time_now_d() > deadline) { // Don't compare, print the output at least up to this point, and bail. printf("%s", output.c_str()); @@ -327,15 +328,7 @@ int main(int argc, const char* argv[]) if (testFilenames.empty()) return printUsage(argv[0], argc <= 1 ? NULL : "No executables specified"); - HeadlessHost *headlessHost = getHost(gpuCore); - headlessHost->SetGraphicsCore(gpuCore); - host = headlessHost; - - std::string error_string; - GraphicsContext *graphicsContext = nullptr; - bool glWorking = host->InitGraphics(&error_string, &graphicsContext); - - LogManager::Init(); + LogManager::Init(&g_Config.bEnableLogging); LogManager *logman = LogManager::GetInstance(); PrintfLogger *printfLogger = new PrintfLogger(); @@ -347,6 +340,14 @@ int main(int argc, const char* argv[]) } logman->AddListener(printfLogger); + HeadlessHost *headlessHost = getHost(gpuCore); + headlessHost->SetGraphicsCore(gpuCore); + host = headlessHost; + + std::string error_string; + GraphicsContext *graphicsContext = nullptr; + bool glWorking = host->InitGraphics(&error_string, &graphicsContext); + CoreParameter coreParameter; coreParameter.cpuCore = cpuCore; coreParameter.gpuCore = glWorking ? gpuCore : GPUCORE_NULL; @@ -382,7 +383,7 @@ int main(int argc, const char* argv[]) g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS; g_Config.iLockParentalLevel = 9; g_Config.iInternalResolution = 1; - g_Config.bFrameSkipUnthrottle = false; + g_Config.iUnthrottleMode = (int)UnthrottleMode::CONTINUOUS; g_Config.bEnableLogging = fullLog; g_Config.iNumWorkerThreads = 1; g_Config.bSoftwareSkinning = true; @@ -407,9 +408,10 @@ int main(int argc, const char* argv[]) #endif // Try to find the flash0 directory. Often this is from a subdirectory. - for (int i = 0; i < 3; ++i) - { - if (!File::Exists(g_Config.flash0Directory)) + for (int i = 0; i < 4 && !File::Exists(g_Config.flash0Directory); ++i) { + if (File::Exists(g_Config.flash0Directory + "../assets/flash0/")) + g_Config.flash0Directory += "../assets/flash0/"; + else g_Config.flash0Directory += "../../flash0/"; } // Or else, maybe in the executable's dir. diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index 7ad31e3578..29d26051d5 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -176,7 +176,7 @@ NotUsing Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS - ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native + ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew EnableFastChecks StreamingSIMDExtensions2 Precise @@ -198,7 +198,7 @@ ../ffmpeg/Windows/x86/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -209,7 +209,7 @@ NotUsing Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native + ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew NotSet Precise false @@ -231,7 +231,7 @@ ../ffmpeg/Windows/x86_64/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -242,8 +242,7 @@ NotUsing Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native - NotSet + ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew Precise false true @@ -261,7 +260,7 @@ ../ffmpeg/Windows/aarch64/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -272,8 +271,7 @@ NotUsing Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native - NotSet + ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew Precise false true @@ -292,7 +290,7 @@ ../ffmpeg/Windows/arm/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -305,7 +303,7 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS - ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native + ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew false StreamingSIMDExtensions2 Precise @@ -328,7 +326,7 @@ ../ffmpeg/Windows/x86/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -341,7 +339,7 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native + ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew false NotSet Precise @@ -366,7 +364,7 @@ ../ffmpeg/Windows/x86_64/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -379,9 +377,8 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native + ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew false - NotSet Precise Speed false @@ -401,7 +398,7 @@ ../ffmpeg/Windows/aarch64/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -414,9 +411,8 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native + ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew false - NotSet Precise Speed false @@ -436,7 +432,7 @@ ../ffmpeg/Windows/arm/lib - ../Windows/git-version-gen.cmd + ../Windows/git-version-gen.cmd Headless Updating git-version.cpp @@ -504,9 +500,6 @@ {457f45d2-556f-47bc-a31d-aff0d15beaed} - - {C4DF647E-80EA-4111-A0A8-218B1B711E18} - {f761046e-6c38-4428-a5f1-38391a37bb34} @@ -520,4 +513,4 @@ - \ No newline at end of file + diff --git a/headless/SDLHeadlessHost.cpp b/headless/SDLHeadlessHost.cpp index d0e5757fff..b57d02a5cd 100644 --- a/headless/SDLHeadlessHost.cpp +++ b/headless/SDLHeadlessHost.cpp @@ -17,14 +17,21 @@ #ifdef SDL -#include +#include #include -#include #include "headless/SDLHeadlessHost.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" -#include "Common/FileUtil.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" +#include "Common/Log.h" +#include "Common/File/FileUtil.h" #include "Common/GraphicsContext.h" +#include "Common/TimeUtil.h" #include "Core/CoreParameter.h" #include "Core/ConfigValues.h" @@ -32,15 +39,6 @@ #include "GPU/Common/GPUDebugInterface.h" #include "GPU/GPUState.h" -#include "base/logging.h" -#include "base/timeutil.h" -#include "gfx/gl_common.h" -#include "gfx_es2/gpu_features.h" -#include "file/vfs.h" -#include "file/zip_read.h" -#include "thin3d/thin3d_create.h" -#include "thin3d/GLRenderManager.h" - const bool WINDOW_VISIBLE = false; const int WINDOW_WIDTH = 480; const int WINDOW_HEIGHT = 272; @@ -53,7 +51,7 @@ SDL_Window *CreateHiddenWindow() { return SDL_CreateWindow("PPSSPPHeadless", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, flags); } -class GLDummyGraphicsContext : public DummyGraphicsContext { +class GLDummyGraphicsContext : public GraphicsContext { public: GLDummyGraphicsContext() { } @@ -92,6 +90,11 @@ public: renderManager_->StopThread(); } + void Shutdown() override {} + void Resize() override {} + void SwapInterval(int interval) override {} + void SwapBuffers() override {} + private: Draw::DrawContext *draw_; GLRenderManager *renderManager_ = nullptr; @@ -124,7 +127,7 @@ bool GLDummyGraphicsContext::InitFromRenderThread(std::string *errorMessage) { glContext_ = SDL_GL_CreateContext(screen_); // Ensure that the swap interval is set after context creation (needed for kmsdrm) - SDL_GL_SetSwapInterval(1); + SDL_GL_SetSwapInterval(0); #ifndef USING_GLES2 // Some core profile drivers elide certain extensions from GL_EXTENSIONS/etc. @@ -153,7 +156,7 @@ bool GLDummyGraphicsContext::InitFromRenderThread(std::string *errorMessage) { renderManager_->SetInflightFrames(g_Config.iInflightFrames); SetGPUBackend(GPUBackend::OPENGL); bool success = draw_->CreatePresets(); - assert(success); + _assert_(success); renderManager_->SetSwapFunction([&]() { SDL_GL_SwapWindow(screen_); }); diff --git a/headless/StubHost.cpp b/headless/StubHost.cpp index 6569cc3b1a..1219d42365 100644 --- a/headless/StubHost.cpp +++ b/headless/StubHost.cpp @@ -15,7 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/FileUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/Log.h" #include "Core/CoreParameter.h" #include "Core/System.h" #include "GPU/Common/GPUDebugInterface.h" diff --git a/headless/StubHost.h b/headless/StubHost.h index d6498e2b0f..8ac54ddff8 100644 --- a/headless/StubHost.h +++ b/headless/StubHost.h @@ -44,6 +44,7 @@ public: bool IsDebuggingEnabled() override { return false; } bool AttemptLoadSymbolMap() override { g_symbolMap->Clear(); return false; } + void NotifySymbolMapUpdated() override {} bool ShouldSkipUI() override { return true; } diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index dba04b79ad..af5548bf84 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -15,12 +15,19 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include +#include #include "headless/WindowsHeadlessHost.h" -#include "Common/FileUtil.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/OpenGL/GLFeatures.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" + #include "Common/CommonWindows.h" +#include "Common/Log.h" +#include "Common/File/FileUtil.h" +#include "Common/TimeUtil.h" #include "Core/CoreParameter.h" #include "Core/System.h" @@ -33,13 +40,6 @@ #include "Windows/GPU/D3D11Context.h" #include "Windows/GPU/WindowsVulkanContext.h" -#include "base/logging.h" -#include "base/timeutil.h" -#include "gfx/gl_common.h" -#include "gfx_es2/gpu_features.h" -#include "file/vfs.h" -#include "file/zip_read.h" - const bool WINDOW_VISIBLE = false; const int WINDOW_WIDTH = 480; const int WINDOW_HEIGHT = 272; @@ -56,13 +56,13 @@ HWND CreateHiddenWindow() { LoadCursor(NULL, IDC_ARROW), (HBRUSH) GetStockObject(BLACK_BRUSH), NULL, - _T("PPSSPPHeadless"), + L"PPSSPPHeadless", NULL, }; RegisterClassEx(&wndClass); DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP; - return CreateWindowEx(0, _T("PPSSPPHeadless"), _T("PPSSPPHeadless"), style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL); + return CreateWindowEx(0, L"PPSSPPHeadless", L"PPSSPPHeadless", style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL); } void WindowsHeadlessHost::LoadNativeAssets() diff --git a/history.md b/history.md index 38af1adf76..c6f48dca3f 100644 --- a/history.md +++ b/history.md @@ -1,6 +1,51 @@ This is history moved out from README.md, which was getting a bit long. +What's new in 1.6.3 +------------------- +* Crashfixes, task switching and one in Phantasy Star Portable +* Improve graphics in PoP on some devices + +What's new in 1.6.1, 1.6.2 +-------------------------- +* Crashfixes +* Fix broken graphics in flOw. + +What's new in 1.6.0 +------------------- +* OpenGL backend now properly multithreaded, giving a good speed boost. +* Various Vulkan performance improvements (like [#10911][]) and memory allocation fixes. +* GPU command interpreter performance improvements ([#10658][]) +* Various fixes for app switching and widgets ([#10855][]) on Android +* Bugfixes and some performance improvements in the ARM64 JIT compiler and IR interpreter +* Shader cache enabled for Vulkan +* Multiple iOS fixes, including JIT ([#10465][]) and file browser ([#10921][]). +* Improved compatibility on Mac ([#10113][]) +* Texture replacement ID bugfix (note: some textures from 1.5.4 may become incompatible) +* Adhoc multiplayer fixes ([#8975][]) +* Vulkan support on Linux/SDL ([#10413][]) +* Retroarch support + +What's new in 1.5.4 +------------------- +* Bugfixes and crashfixes! + +What's new in 1.5.0 +------------------- +* Full Vulkan support, also for Android now. Very fast on supported devices. ([#10033][], [#10049][]) +* Smarter graphics state management, reduced CPU consumption on all backends ([#9899][]) +* Android: Support for Arabic and other scripts we couldn't support before +* Fix Android widgets, screen scaling ([#10145][]) +* Fixes to video dumping +* Geometry problems fixed in Medal of Honor +* Implement immediate draws, fixing Thrillville ([#7459][]) +* Software rendering improvements, speed and accuracy +* Hardware tesselation of PSP Beziers and Splines (used by a few games) +* Partial sceUsbGps and sceUsbCam support (Android) +* Android "Sustained performance mode" to avoid thermal throttling ([#9901][]) +* Linux controller mapping fixes ([#9997][]) +* Assorted bugfixes and compatibility improvements + What's new in 1.4.2 ------------------- * Fixed longstanding bug causing games to crash on ARM64 @@ -10,15 +55,15 @@ What's new in 1.4.2 What's new in 1.4.1 ------------------- -* Fixes for some common hangs and crashes (#9698, ...) -* Vertex decoder optimizations (#9674) -* Corrections to mipmap bias and selection function (#9633) -* Major improvements and fixes to software renderer, including mipmap support (#9635, ...) +* Fixes for some common hangs and crashes ([#9698][], ...) +* Vertex decoder optimizations ([#9674][]) +* Corrections to mipmap bias and selection function ([#9633][]) +* Major improvements and fixes to software renderer, including mipmap support ([#9635][], ...) * UI background image support * Basic mouse input support on Windows -* Windows desktop touch fixes (#9560) +* Windows desktop touch fixes ([#9560][]) * D3D11 "depal" color fixes, fixing Sonic Rivals -* Fix crash in framebuffer blits affecting Persona 3 (#9566) +* Fix crash in framebuffer blits affecting Persona 3 ([#9566][]) What's new in 1.4-2 ------------------- @@ -27,12 +72,12 @@ What's new in 1.4-2 What's new in 1.4 ----------------- * Support D3D11 (performs better than OpenGL or D3D9 on most hardware) -* Audio quality improvement (linear interpolation) (#8950) +* Audio quality improvement (linear interpolation) ([#8950][]) * Hardware spline/bezier tesselation in OpenGL, D3D11 and Vulkan (...) * Post-processing shaders in D3D11 -* Prescale UV setting removed, now the default (improves perf) (#9176) +* Prescale UV setting removed, now the default (improves perf) ([#9176][]) * High DPI display fixes -* Various fixes for UMD switching for multi-UMD games (#9245, #9256) +* Various fixes for UMD switching for multi-UMD games ([#9245][], [#9256][]) * New audio setting to improve compatibility with Bluetooth headsets * Various desktop gamepad compatibility fixes * Workaround for mipmap issue, fixing fonts in Tactics Ogre Japanese @@ -42,25 +87,25 @@ Support for Symbian, Maemo and Blackberry has been removed. What's new in 1.3.0 ------------------- -* Fix JIT problems on Galaxy S7 and iOS 9+ devices. (#8965, #8937) -* Fix Android TV support and use latest FFmpeg. (#8651, #8870) -* Texture replacement support - for custom textures and upscaling. (#8715, #8821) -* Initial game recording / TAS features. (#8939, #8945) -* Correctly map memory on Raspberry Pi 3, much better performance. (#8801) +* Fix JIT problems on Galaxy S7 and iOS 9+ devices. ([#8965][], [#8937][]) +* Fix Android TV support and use latest FFmpeg. ([#8651][], [#8870][]) +* Texture replacement support - for custom textures and upscaling. ([#8715][], [#8821][]) +* Initial game recording / TAS features. ([#8939][], [#8945][]) +* Correctly map memory on Raspberry Pi 3, much better performance. ([#8801][]) * Workaround rendering issues on Tegra K1/X1. (8294a54) -* Disc streaming to play quickly from tablet/phone on wifi. (#8845) -* Initial Vulkan support - not full featured yet. (#8601, etc.) -* Experimental new CPU backend and CPU fixes. (#8725) -* Allow insert/eject of memstick - required by some games. (#8889) -* Better support for ps3 controller mapping. (#8949) -* Better UI handling for settings with long names in some languages. (#8900, #8898) -* Screenshots in compatibility reporting, better website. (#8812) -* Fix type D cheat codes, allow for homebrew. (#8818) -* Graphic glitch fixes in several games. (#8686, #8757, #8804) -* Fix video playback glitches in several games. (#8793, #8803, #8867, #8914) -* Various performance and compatibility improvements. (#8868, #8884, #8932, #8934, #8813, #8701, #8960) -* Various debugger and GE debugger improvements. (#8882, #8762) -* Fix some problems when switching away from and back to the app (#8968) +* Disc streaming to play quickly from tablet/phone on wifi. ([#8845][]) +* Initial Vulkan support - not full featured yet. ([#8601][], etc.) +* Experimental new CPU backend and CPU fixes. ([#8725][]) +* Allow insert/eject of memstick - required by some games. ([#8889][]) +* Better support for ps3 controller mapping. ([#8949][]) +* Better UI handling for settings with long names in some languages. ([#8900][], [#8898][]) +* Screenshots in compatibility reporting, better website. ([#8812][]) +* Fix type D cheat codes, allow for homebrew. ([#8818][]) +* Graphic glitch fixes in several games. ([#8686][], [#8757][], [#8804][]) +* Fix video playback glitches in several games. ([#8793][], [#8803][], [#8867][], [#8914][]) +* Various performance and compatibility improvements. ([#8868][], [#8884][], [#8932][], [#8934][], [#8813][], [#8701][], [#8960][]) +* Various debugger and GE debugger improvements. ([#8882][], [#8762][]) +* Fix some problems when switching away from and back to the app ([#8968][]) What's new in 1.2.2 ------------------- @@ -274,3 +319,64 @@ Update (Kyhel) : go to see there http://forums.ppsspp.org/showthread.php?tid=3595&pid=59241#pid59241 * Got it tested windows <-> mac osx <-> psp, it works * Monster Hunter 3rd HD works too, as well as God Eater Burst. + +[#10911]: https://github.com/hrydgard/ppsspp/issues/10911 "Vulkan: Depalettize in shaders" +[#10658]: https://github.com/hrydgard/ppsspp/issues/10658 "Execute_Prim: Add a smaller \"inner interpreter\" to speed long up sequences of PRIM commands" +[#10855]: https://github.com/hrydgard/ppsspp/issues/10855 "PPSSPP 1.5.4 on Android. Shortcuts do not work the first time." +[#10465]: https://github.com/hrydgard/ppsspp/issues/10465 "Allow arm64 jit when memory base is not nicely aligned" +[#10921]: https://github.com/hrydgard/ppsspp/issues/10921 "Add support for File app (file browser) on iOS 11" +[#10113]: https://github.com/hrydgard/ppsspp/issues/10113 "Request a core profile in OpenGL (after 1.5.0)" +[#8975]: https://github.com/hrydgard/ppsspp/issues/8975 "Ad hoc: Band-aid fix for clear peer list. Should fix #7331" +[#10413]: https://github.com/hrydgard/ppsspp/issues/10413 "SDL/X11 Vulkan init" +[#10033]: https://github.com/hrydgard/ppsspp/issues/10033 "VulkanRenderManager - big refactoring of the Vulkan code" +[#10049]: https://github.com/hrydgard/ppsspp/issues/10049 "Vulkan threading tweaks and minor" +[#9899]: https://github.com/hrydgard/ppsspp/issues/9899 "Vulkan state optimizations" +[#10145]: https://github.com/hrydgard/ppsspp/issues/10145 "Android: When creating shortcuts, put the file path in data, not in extras." +[#7459]: https://github.com/hrydgard/ppsspp/issues/7459 "Thrillville Off The Rails Graphics' issues" +[#9901]: https://github.com/hrydgard/ppsspp/issues/9901 "Initial work on supporting sustained perf mode" +[#9997]: https://github.com/hrydgard/ppsspp/issues/9997 "Create default mapping for unknown control pads in SDL's controller database" +[#9698]: https://github.com/hrydgard/ppsspp/issues/9698 "General crash and hang fixes" +[#9674]: https://github.com/hrydgard/ppsspp/issues/9674 "Implement a few x86 vertexjit optimizations" +[#9633]: https://github.com/hrydgard/ppsspp/issues/9633 "Improve support for mipmaps and related headless fixes" +[#9635]: https://github.com/hrydgard/ppsspp/issues/9635 "SoftGPU: Rasterize triangles in chunks of 4 pixels" +[#9560]: https://github.com/hrydgard/ppsspp/issues/9560 "Allow using any touchId to scroll. Should help #9554." +[#9566]: https://github.com/hrydgard/ppsspp/issues/9566 "Fix out-of-bounds framebuffer blit on color bind" +[#8950]: https://github.com/hrydgard/ppsspp/issues/8950 "SasAudio: Implement linear interpolation" +[#9176]: https://github.com/hrydgard/ppsspp/issues/9176 "Always prescale uv (\"texcoord speedhack\")" +[#9245]: https://github.com/hrydgard/ppsspp/issues/9245 "Fix \"Akaya Akashiya Ayakashi\" umd switch" +[#9256]: https://github.com/hrydgard/ppsspp/issues/9256 "Fix Dies irae Amantes amentes umd switch" +[#8965]: https://github.com/hrydgard/ppsspp/issues/8965 "Port over the Exynos cacheline size fix from Dolphin." +[#8937]: https://github.com/hrydgard/ppsspp/issues/8937 "Implement W^X-compatible JIT. Hopefully makes JIT work on iOS again" +[#8651]: https://github.com/hrydgard/ppsspp/issues/8651 "Switch Android build to using clang (needs buildbot update)" +[#8870]: https://github.com/hrydgard/ppsspp/issues/8870 "Update to target Android SDK platform 24 (N)" +[#8715]: https://github.com/hrydgard/ppsspp/issues/8715 "Initial texture replacement support" +[#8821]: https://github.com/hrydgard/ppsspp/issues/8821 "Add basic TextureReplacement UI options." +[#8939]: https://github.com/hrydgard/ppsspp/issues/8939 "Add Frame Advance" +[#8945]: https://github.com/hrydgard/ppsspp/issues/8945 "Add Display Recording and Audio Dumping to Desktop" +[#8801]: https://github.com/hrydgard/ppsspp/issues/8801 "Improve performance on Raspberry Pi (and maybe other Linux)" +[#8845]: https://github.com/hrydgard/ppsspp/issues/8845 "Add UI for wifi remote disc streaming" +[#8601]: https://github.com/hrydgard/ppsspp/issues/8601 "Vulkan rendering backend. Early Work-In-Progress" +[#8725]: https://github.com/hrydgard/ppsspp/issues/8725 "IR Interpreter" +[#8889]: https://github.com/hrydgard/ppsspp/issues/8889 "Initial support for memstick insert/remove" +[#8949]: https://github.com/hrydgard/ppsspp/issues/8949 "Adds --PS3 comand line option for PS3 controller support on SDL." +[#8900]: https://github.com/hrydgard/ppsspp/issues/8900 "Wrap text in many places where it makes sense" +[#8898]: https://github.com/hrydgard/ppsspp/issues/8898 "UI: Scale option text down when there's no space" +[#8812]: https://github.com/hrydgard/ppsspp/issues/8812 "Include screenshots in compatibility reports" +[#8818]: https://github.com/hrydgard/ppsspp/issues/8818 "CWC improvements/fixes" +[#8686]: https://github.com/hrydgard/ppsspp/issues/8686 "Interpolate bezier patch colors/UVs using bernstein" +[#8757]: https://github.com/hrydgard/ppsspp/issues/8757 "Save FBOs on decimate when a safe size is known" +[#8804]: https://github.com/hrydgard/ppsspp/issues/8804 "Download single-use renders right away" +[#8793]: https://github.com/hrydgard/ppsspp/issues/8793 "Correct some scePsmf info retrieval funcs and error handling" +[#8803]: https://github.com/hrydgard/ppsspp/issues/8803 "Reject invalid MPEG puts for certain lib versions" +[#8867]: https://github.com/hrydgard/ppsspp/issues/8867 "Improve mpeg parsing / corruption issues" +[#8914]: https://github.com/hrydgard/ppsspp/issues/8914 "Psmf: Ignore stream size with old PsmfPlayer libs" +[#8868]: https://github.com/hrydgard/ppsspp/issues/8868 "Return error when trying to close files with pending operations" +[#8884]: https://github.com/hrydgard/ppsspp/issues/8884 "Better support zh_gb.pgf" +[#8932]: https://github.com/hrydgard/ppsspp/issues/8932 "Font: Draw nothing for chars before first glyph" +[#8934]: https://github.com/hrydgard/ppsspp/issues/8934 "Io: Do not delay on file seek" +[#8813]: https://github.com/hrydgard/ppsspp/issues/8813 "Enable extra ram for The Elder Scrolls Travels Oblivion USA Beta and Melodie alpha" +[#8701]: https://github.com/hrydgard/ppsspp/issues/8701 "Correct dependency handling when loading modules" +[#8960]: https://github.com/hrydgard/ppsspp/issues/8960 "Fix scePowerSetClockFrequency timing" +[#8882]: https://github.com/hrydgard/ppsspp/issues/8882 "Add custom log expressions to the debugger" +[#8762]: https://github.com/hrydgard/ppsspp/issues/8762 "Add more GE debugger features" +[#8968]: https://github.com/hrydgard/ppsspp/issues/8968 "Android: Add both a lost and restore phase" diff --git a/ios/AppDelegate.mm b/ios/AppDelegate.mm index ab79d0be07..ba8d4ff6d9 100644 --- a/ios/AppDelegate.mm +++ b/ios/AppDelegate.mm @@ -1,6 +1,7 @@ #import "AppDelegate.h" #import "ViewController.h" -#import "base/NativeApp.h" +#import "Common/System/System.h" +#import "Common/System/NativeApp.h" #import "Core/System.h" #import "Core/Config.h" #import "Common/Log.h" diff --git a/ios/DisplayManager.mm b/ios/DisplayManager.mm index 495353a6df..19f828d380 100644 --- a/ios/DisplayManager.mm +++ b/ios/DisplayManager.mm @@ -8,8 +8,9 @@ #import "DisplayManager.h" #import "ViewController.h" #import "AppDelegate.h" -#include "base/display.h" -#include "base/NativeApp.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" #include "Core/System.h" #import diff --git a/ios/PPSSPPUIApplication.mm b/ios/PPSSPPUIApplication.mm index d07e7a26e0..2166da2406 100644 --- a/ios/PPSSPPUIApplication.mm +++ b/ios/PPSSPPUIApplication.mm @@ -12,15 +12,18 @@ #import #import -#include "base/display.h" -#include "base/timeutil.h" -#include "file/zip_read.h" -#include "input/input_state.h" -#include "net/resolve.h" -#include "ui/screen.h" -#include "thin3d/thin3d.h" -#include "input/keycodes.h" -#include "gfx_es2/gpu_features.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Common/TimeUtil.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" +#include "Common/Input/InputState.h" +#include "Common/Net/Resolve.h" +#include "Common/UI/Screen.h" +#include "Common/GPU/thin3d.h" +#include "Common/Input/KeyCodes.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #import "ios/AppDelegate.h" #include "ios/SmartKeyboardMap.hpp" diff --git a/ios/SmartKeyboardMap.cpp b/ios/SmartKeyboardMap.cpp index 785e8fafad..43d8e5b46e 100644 --- a/ios/SmartKeyboardMap.cpp +++ b/ios/SmartKeyboardMap.cpp @@ -7,7 +7,7 @@ // #include "SmartKeyboardMap.hpp" -#include "input/keycodes.h" +#include "Common/Input/KeyCodes.h" int getSmartKeyboardMap(int keycode) { switch(keycode) { diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 73fd05c7fd..02b18a5ec5 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -12,24 +12,28 @@ #import #include -#include "base/display.h" -#include "base/timeutil.h" -#include "file/zip_read.h" -#include "input/input_state.h" -#include "net/resolve.h" -#include "ui/screen.h" -#include "thin3d/thin3d.h" -#include "thin3d/thin3d_create.h" -#include "thin3d/GLRenderManager.h" -#include "input/keycodes.h" -#include "gfx_es2/gpu_features.h" +#include "Common/Net/Resolve.h" +#include "Common/UI/Screen.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLFeatures.h" + +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Common/File/VFS/VFS.h" +#include "Common/Log.h" +#include "Common/TimeUtil.h" +#include "Common/Input/InputState.h" +#include "Common/Input/KeyCodes.h" +#include "Common/GraphicsContext.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" #include "Core/HLE/sceUsbCam.h" #include "Core/HLE/sceUsbGps.h" -#include "Common/GraphicsContext.h" #include #include @@ -38,7 +42,7 @@ #define IS_IPAD() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) #define IS_IPHONE() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) -class IOSGraphicsContext : public DummyGraphicsContext { +class IOSGraphicsContext : public GraphicsContext { public: IOSGraphicsContext() { CheckGLExtensions(); @@ -47,7 +51,7 @@ public: renderManager_->SetInflightFrames(g_Config.iInflightFrames); SetGPUBackend(GPUBackend::OPENGL); bool success = draw_->CreatePresets(); - _assert_msg_(G3D, success, "Failed to compile preset shaders"); + _assert_msg_(success, "Failed to compile preset shaders"); } ~IOSGraphicsContext() { delete draw_; @@ -55,6 +59,12 @@ public: Draw::DrawContext *GetDrawContext() override { return draw_; } + + void SwapInterval(int interval) override {} + void SwapBuffers() override {} + void Resize() override {} + void Shutdown() override {} + void ThreadStart() override { renderManager_->ThreadStart(draw_); } @@ -71,6 +81,7 @@ public: renderManager_->WaitUntilQueueIdle(); renderManager_->StopThread(); } + private: Draw::DrawContext *draw_; GLRenderManager *renderManager_; @@ -237,19 +248,18 @@ static LocationHelper *locationHelper; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NativeInitGraphics(graphicsContext); - ILOG("Emulation thread starting\n"); + INFO_LOG(SYSTEM, "Emulation thread starting\n"); while (threadEnabled) { NativeUpdate(); NativeRender(graphicsContext); - time_update(); } - ILOG("Emulation thread shutting down\n"); + INFO_LOG(SYSTEM, "Emulation thread shutting down\n"); NativeShutdownGraphics(); // Also ask the main thread to stop, so it doesn't hang waiting for a new frame. - ILOG("Emulation thread stopping\n"); + INFO_LOG(SYSTEM, "Emulation thread stopping\n"); graphicsContext->StopThread(); threadStopped = true; diff --git a/ios/main.mm b/ios/main.mm index 4c9f004c5f..5daecb3e79 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -14,8 +14,9 @@ #import "PPSSPPUIApplication.h" #import "ViewController.h" -#include "base/NativeApp.h" -#include "profiler/profiler.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Profiler/Profiler.h" #define CS_OPS_STATUS 0 /* return status */ #define CS_DEBUGGED 0x10000000 /* process is currently or has previously been debugged and allowed to run with invalid pages */ diff --git a/libretro/.gitignore b/libretro/.gitignore index b791c99ede..de1b540422 100644 --- a/libretro/.gitignore +++ b/libretro/.gitignore @@ -2,3 +2,4 @@ *.so *.dll *.dylib +*.manifest diff --git a/libretro/CMakeLists.txt b/libretro/CMakeLists.txt index b590cc25df..69efea8980 100644 --- a/libretro/CMakeLists.txt +++ b/libretro/CMakeLists.txt @@ -3,6 +3,7 @@ set(LIBRETRO_SRCS libretro.cpp LibretroGraphicsContext.cpp LibretroGLContext.cpp + LibretroGLCoreContext.cpp LibretroVulkanContext.cpp libretro_vulkan.cpp) diff --git a/libretro/LibretroD3D11Context.cpp b/libretro/LibretroD3D11Context.cpp index cd46e66858..216876a409 100644 --- a/libretro/LibretroD3D11Context.cpp +++ b/libretro/LibretroD3D11Context.cpp @@ -1,7 +1,8 @@ - +#include "Common/Log.h" #include "Core/ConfigValues.h" #include "libretro/LibretroD3D11Context.h" -#include "thin3d/d3d11_loader.h" +#include "Common/GPU/D3D11/D3D11Loader.h" + #include #ifdef __MINGW32__ diff --git a/libretro/LibretroGLContext.cpp b/libretro/LibretroGLContext.cpp index c8260650cb..c8f3bcd0a7 100644 --- a/libretro/LibretroGLContext.cpp +++ b/libretro/LibretroGLContext.cpp @@ -3,7 +3,7 @@ #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" -#include "gfx_es2/gpu_features.h" +#include "Common/GPU/OpenGL/GLFeatures.h" #include "libretro/LibretroGLContext.h" diff --git a/libretro/LibretroGLContext.h b/libretro/LibretroGLContext.h index b85c8affb0..5c6ded1d6e 100644 --- a/libretro/LibretroGLContext.h +++ b/libretro/LibretroGLContext.h @@ -1,16 +1,14 @@ #pragma once -#include "gfx/gl_common.h" +#include "Common/GPU/OpenGL/GLCommon.h" #include "libretro/LibretroGraphicsContext.h" -#include "thin3d/GLRenderManager.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" class LibretroGLContext : public LibretroHWRenderContext { public: LibretroGLContext() #ifdef USING_GLES2 : LibretroHWRenderContext(RETRO_HW_CONTEXT_OPENGLES2) -#elif defined(HAVE_OPENGL_CORE) - : LibretroHWRenderContext(RETRO_HW_CONTEXT_OPENGL_CORE, 3, 1) #else : LibretroHWRenderContext(RETRO_HW_CONTEXT_OPENGL) #endif diff --git a/libretro/LibretroGLCoreContext.cpp b/libretro/LibretroGLCoreContext.cpp new file mode 100644 index 0000000000..7b571bdaf0 --- /dev/null +++ b/libretro/LibretroGLCoreContext.cpp @@ -0,0 +1,36 @@ + +#include "Common/Log.h" +#include "Core/Config.h" +#include "Core/ConfigValues.h" +#include "Core/System.h" +#include "Common/GPU/OpenGL/GLFeatures.h" + +#include "libretro/LibretroGLCoreContext.h" + +bool LibretroGLCoreContext::Init() { + if (!LibretroHWRenderContext::Init(true)) + return false; + + g_Config.iGPUBackend = (int)GPUBackend::OPENGL; + return true; +} + +void LibretroGLCoreContext::CreateDrawContext() { + if (!glewInitDone) { +#if !defined(IOS) && !defined(USING_GLES2) + if (glewInit() != GLEW_OK) { + ERROR_LOG(G3D, "glewInit() failed.\n"); + return; + } +#endif + glewInitDone = true; + CheckGLExtensions(); + } + draw_ = Draw::T3DCreateGLContext(); + renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); +} + +void LibretroGLCoreContext::DestroyDrawContext() { + LibretroHWRenderContext::DestroyDrawContext(); + renderManager_ = nullptr; +} diff --git a/libretro/LibretroGLCoreContext.h b/libretro/LibretroGLCoreContext.h new file mode 100644 index 0000000000..bb8d5e460f --- /dev/null +++ b/libretro/LibretroGLCoreContext.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Common/GPU/OpenGL/GLCommon.h" +#include "libretro/LibretroGraphicsContext.h" +#include "Common/GPU/OpenGL/GLRenderManager.h" + +class LibretroGLCoreContext : public LibretroHWRenderContext { +public: + LibretroGLCoreContext() + : LibretroHWRenderContext(RETRO_HW_CONTEXT_OPENGL_CORE, 3, 1) + { + hw_render_.bottom_left_origin = true; + } + + bool Init() override; + void CreateDrawContext() override; + void DestroyDrawContext() override; + void SetRenderTarget() override { + extern GLuint g_defaultFBO; + g_defaultFBO = hw_render_.get_current_framebuffer(); + } + + void ThreadStart() override { renderManager_->ThreadStart(draw_); } + bool ThreadFrame() override { return renderManager_->ThreadFrame(); } + void ThreadEnd() override { renderManager_->ThreadEnd(); } + void StopThread() override { + renderManager_->WaitUntilQueueIdle(); + renderManager_->StopThread(); + } + + GPUCore GetGPUCore() override { return GPUCORE_GLES; } + const char *Ident() override { return "OpenGL Core"; } + +private: + GLRenderManager *renderManager_ = nullptr; + bool glewInitDone = false; +}; diff --git a/libretro/LibretroGraphicsContext.cpp b/libretro/LibretroGraphicsContext.cpp index 508353f6bb..01ce61068d 100644 --- a/libretro/LibretroGraphicsContext.cpp +++ b/libretro/LibretroGraphicsContext.cpp @@ -1,6 +1,7 @@ #include "libretro/LibretroGraphicsContext.h" #include "libretro/LibretroGLContext.h" +#include "libretro/LibretroGLCoreContext.h" #include "libretro/libretro.h" #include "libretro/LibretroVulkanContext.h" #ifdef _WIN32 @@ -14,13 +15,20 @@ retro_video_refresh_t LibretroGraphicsContext::video_cb; +extern "C" { + retro_hw_get_proc_address_t libretro_get_proc_address; +}; + void retro_set_video_refresh(retro_video_refresh_t cb) { LibretroGraphicsContext::video_cb = cb; } static void context_reset() { ((LibretroHWRenderContext *)Libretro::ctx)->ContextReset(); } static void context_destroy() { ((LibretroHWRenderContext *)Libretro::ctx)->ContextDestroy(); } bool LibretroHWRenderContext::Init(bool cache_context) { hw_render_.cache_context = cache_context; - return Libretro::environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render_); + if (!Libretro::environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render_)) + return false; + libretro_get_proc_address = hw_render_.get_proc_address; + return true; } LibretroHWRenderContext::LibretroHWRenderContext(retro_hw_context_type context_type, unsigned version_major, unsigned version_minor) { @@ -44,7 +52,7 @@ void LibretroHWRenderContext::ContextReset() { if (!draw_) { CreateDrawContext(); bool success = draw_->CreatePresets(); - assert(success); + _assert_(success); } GotBackbuffer(); @@ -81,34 +89,55 @@ void LibretroGraphicsContext::LostBackbuffer() { draw_->HandleEvent(Draw::Event: LibretroGraphicsContext *LibretroGraphicsContext::CreateGraphicsContext() { LibretroGraphicsContext *ctx; - ctx = new LibretroGLContext(); + retro_hw_context_type preferred; + if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER, &preferred)) + preferred = RETRO_HW_CONTEXT_DUMMY; - if (ctx->Init()) { - return ctx; +#ifndef USING_GLES2 + if (preferred == RETRO_HW_CONTEXT_DUMMY || preferred == RETRO_HW_CONTEXT_OPENGL_CORE) { + ctx = new LibretroGLCoreContext(); + + if (ctx->Init()) { + return ctx; + } + delete ctx; } - delete ctx; +#endif - ctx = new LibretroVulkanContext(); + if (preferred == RETRO_HW_CONTEXT_DUMMY || preferred == RETRO_HW_CONTEXT_OPENGL) { + ctx = new LibretroGLContext(); - if (ctx->Init()) { - return ctx; + if (ctx->Init()) { + return ctx; + } + delete ctx; + } + + if (preferred == RETRO_HW_CONTEXT_DUMMY || preferred == RETRO_HW_CONTEXT_VULKAN) { + ctx = new LibretroVulkanContext(); + + if (ctx->Init()) { + return ctx; + } + delete ctx; } - delete ctx; #ifdef _WIN32 - ctx = new LibretroD3D11Context(); + if (preferred == RETRO_HW_CONTEXT_DUMMY || preferred == RETRO_HW_CONTEXT_DIRECT3D) { + ctx = new LibretroD3D11Context(); - if (ctx->Init()) { - return ctx; + if (ctx->Init()) { + return ctx; + } + delete ctx; + + ctx = new LibretroD3D9Context(); + + if (ctx->Init()) { + return ctx; + } + delete ctx; } - delete ctx; - - ctx = new LibretroD3D9Context(); - - if (ctx->Init()) { - return ctx; - } - delete ctx; #endif #if 1 diff --git a/libretro/LibretroGraphicsContext.h b/libretro/LibretroGraphicsContext.h index 65b92d2a6a..97890c3013 100644 --- a/libretro/LibretroGraphicsContext.h +++ b/libretro/LibretroGraphicsContext.h @@ -3,7 +3,7 @@ #include "libretro/libretro.h" #include "Common/GraphicsContext.h" -#include "thin3d/thin3d_create.h" +#include "Common/GPU/thin3d_create.h" #include "Core/System.h" #include "GPU/GPUState.h" diff --git a/libretro/LibretroVulkanContext.cpp b/libretro/LibretroVulkanContext.cpp index ed5615b500..5d62a54b45 100644 --- a/libretro/LibretroVulkanContext.cpp +++ b/libretro/LibretroVulkanContext.cpp @@ -1,13 +1,13 @@ -#include "Common/Vulkan/VulkanLoader.h" -#include "Common/Vulkan/VulkanContext.h" -#include "Common/Vulkan/VulkanDebug.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanDebug.h" #include "Common/Log.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" #include "GPU/GPUInterface.h" -#include "util/text/parsers.h" +#include "Common/Data/Text/Parsers.h" #include "libretro/LibretroVulkanContext.h" #include "libretro/libretro_vulkan.h" @@ -69,7 +69,7 @@ static bool create_device(retro_vulkan_context *context, VkInstance instance, Vk vk->InitSurface(WINDOWSYSTEM_WAYLAND, nullptr, nullptr); #endif - if (!vk->InitQueue()) { + if (!vk->InitSwapchain()) { return false; } @@ -116,7 +116,8 @@ void LibretroVulkanContext::Shutdown() { vk->WaitUntilQueueIdle(); - vk->DestroyObjects(); + vk->DestroySwapchain(); + vk->DestroySurface(); vk->DestroyDevice(); vk->DestroyInstance(); delete vk; diff --git a/libretro/Makefile b/libretro/Makefile index 28d145afed..8b2d15fa49 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -275,7 +275,7 @@ else ifneq (,$(findstring windows_msvc2017,$(platform))) PlatformSuffix = $(subst windows_msvc2017_,,$(platform)) ifneq (,$(findstring desktop,$(PlatformSuffix))) WinPartition = desktop - MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 + MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 LDFLAGS += -MANIFEST -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib else ifneq (,$(findstring uwp,$(PlatformSuffix))) @@ -374,7 +374,114 @@ else ifneq (,$(findstring windows_msvc2017,$(platform))) FFMPEGLIBDIR := $(FFMPEGDIR)/Windows/$(TARGET_ARCH)/lib FFMPEGLDFLAGS += -LIBPATH:$(FFMPEGLIBDIR) GL_LIB := opengl32.lib - LDFLAGS += ws2_32.lib user32.lib shell32.lib avcodec.lib avutil.lib swresample.lib swscale.lib avformat.lib advapi32.lib winmm.lib gdi32.lib d3d9.lib d3dx9.lib + LDFLAGS += ws2_32.lib user32.lib shell32.lib avcodec.lib avutil.lib swresample.lib swscale.lib avformat.lib advapi32.lib winmm.lib gdi32.lib d3d9.lib d3dx9.lib Iphlpapi.lib + +# Windows MSVC 2019 all architectures +else ifneq (,$(findstring windows_msvc2019,$(platform))) + + PlatformSuffix = $(subst windows_msvc2019_,,$(platform)) + ifneq (,$(findstring desktop,$(PlatformSuffix))) + WinPartition = desktop + MSVC2019CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 + LDFLAGS += -MANIFEST -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 + LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib + else ifneq (,$(findstring uwp,$(PlatformSuffix))) + WinPartition = uwp + MSVC2019CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB + LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO + LIBS += WindowsApp.lib + endif + + CFLAGS += $(MSVC2019CompileFlags) -nologo + CXXFLAGS += $(MSVC2019CompileFlags) -nologo -EHsc + + TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) + + CC = cl.exe + CXX = cl.exe + + SPACE := + SPACE := $(SPACE) $(SPACE) + BACKSLASH := + BACKSLASH := \$(BACKSLASH) + filter_out1 = $(filter-out $(firstword $1),$1) + filter_out2 = $(call filter_out1,$(call filter_out1,$1)) + + reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>nul))) + fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) + + b1 := ( + b2 := ) + ProgramFiles86w := $(ProgramFiles$(b1)x86$(b2)) + ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") + + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir := $(WindowsSdkDir) + + WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) + WindowsSDKVersion := $(WindowsSDKVersion) + + VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2019/BuildTools + VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2019/Enterprise + VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2019/Professional + VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2019/Community + + VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) + ifeq ($(VsInstallRoot), ) + VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) + endif + ifeq ($(VsInstallRoot), ) + VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) + endif + ifeq ($(VsInstallRoot), ) + VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) + endif + VsInstallRoot := $(VsInstallRoot) + + VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') + VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) + VcCompilerLibDir := $(VcCompilerToolsDir)/lib/$(TargetArchMoniker) + + WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared") + WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt") + WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um") + WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)") + WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)") + + LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerLibDir)") + INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include") + + # For some reason the HostX86 compiler doesn't like compiling for x64 + # ("no such file" opening a shared library), and vice-versa. + # Work around it for now by using the strictly x86 compiler for x86, and x64 for x64. + # NOTE: What about ARM? + ifneq (,$(findstring x64,$(TargetArchMoniker))) + override TARGET_ARCH = x86_64 + VCCompilerToolsBinDir := $(VcCompilerToolsDir)/bin/HostX64/$(TargetArchMoniker) + LIB := $(LIB);$(CORE_DIR)/dx9sdk/Lib/x64 + else + override TARGET_ARCH = x86 + VCCompilerToolsBinDir := $(VcCompilerToolsDir)/bin/HostX86/$(TargetArchMoniker) + LIB := $(LIB);$(CORE_DIR)/dx9sdk/Lib/x86 + endif + + PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)"):$(PATH) + PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE") + + export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir) + export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir);$(FFMPEGDIR)/Windows/$(TARGET_ARCH)/lib + TARGET := $(TARGET_NAME)_libretro.dll + PSS_STYLE :=2 + LDFLAGS += -DLL + PLATFORM_EXT := win32 + FFMPEGINCFLAGS += -I$(FFMPEGDIR)/Windows/$(TARGET_ARCH)/include + FFMPEGLIBDIR := $(FFMPEGDIR)/Windows/$(TARGET_ARCH)/lib + FFMPEGLDFLAGS += -LIBPATH:$(FFMPEGLIBDIR) + GL_LIB := opengl32.lib + LDFLAGS += ws2_32.lib user32.lib shell32.lib avcodec.lib avutil.lib swresample.lib swscale.lib avformat.lib advapi32.lib winmm.lib gdi32.lib d3d9.lib d3dx9.lib Iphlpapi.lib # Windows else ifneq (,$(findstring win,$(platform))) @@ -405,7 +512,7 @@ else GLFLAGS += -DHAVE_OPENGL endif -COREFLAGS += -D__LIBRETRO__ -DPPSSPP -DUSE_FFMPEG -DGLEW_STATIC -DGLEW_NO_GLU +COREFLAGS += -D__LIBRETRO__ -DPPSSPP -DUSE_FFMPEG -DGLEW_STATIC -DGLEW_NO_GLU -DMINIUPNP_STATICLIB ifeq ($(DEBUG), 1) ifneq (,$(findstring msvc,$(platform))) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index ef28c58eca..950b6a864a 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -7,6 +7,10 @@ GPUDIR = $(CORE_DIR)/GPU EXTDIR = $(CORE_DIR)/ext NATIVEDIR = $(EXTDIR)/native +SOURCES_CXX := +SOURCES_C := +SOURCES_ASM := + INCFLAGS += \ -I$(CORE_DIR) \ -I$(COMMONDIR) \ @@ -19,79 +23,78 @@ INCFLAGS += \ $(FFMPEGINCFLAGS) \ -I$(EXTDIR)/cityhash \ -I$(EXTDIR)/armips \ - -I$(NATIVEDIR)/ext \ + -I$(EXTDIR) \ -I$(NATIVEDIR) \ - -I$(NATIVEDIR)/ext/libpng17 \ + -I$(EXTDIR)/libpng17 \ -I$(EXTDIR)/libkirk \ -I$(EXTDIR)/xbrz \ -I$(EXTDIR)/xxhash \ -I$(EXTDIR)/glew ifeq ($(PLATFORM_EXT), android) - INCFLAGS += -I$(NATIVEDIR)/ext/libzip + INCFLAGS += -I$(EXTDIR)/libzip SOURCES_C += \ - $(NATIVEDIR)/ext/libzip/mkstemp.c \ - $(NATIVEDIR)/ext/libzip/zip_add.c \ - $(NATIVEDIR)/ext/libzip/zip_add_dir.c \ - $(NATIVEDIR)/ext/libzip/zip_close.c \ - $(NATIVEDIR)/ext/libzip/zip_delete.c \ - $(NATIVEDIR)/ext/libzip/zip_dirent.c \ - $(NATIVEDIR)/ext/libzip/zip_entry_free.c \ - $(NATIVEDIR)/ext/libzip/zip_entry_new.c \ - $(NATIVEDIR)/ext/libzip/zip_err_str.c \ - $(NATIVEDIR)/ext/libzip/zip_error.c \ - $(NATIVEDIR)/ext/libzip/zip_error_clear.c \ - $(NATIVEDIR)/ext/libzip/zip_error_get.c \ - $(NATIVEDIR)/ext/libzip/zip_error_get_sys_type.c \ - $(NATIVEDIR)/ext/libzip/zip_error_strerror.c \ - $(NATIVEDIR)/ext/libzip/zip_error_to_str.c \ - $(NATIVEDIR)/ext/libzip/zip_fclose.c \ - $(NATIVEDIR)/ext/libzip/zip_file_error_clear.c \ - $(NATIVEDIR)/ext/libzip/zip_file_error_get.c \ - $(NATIVEDIR)/ext/libzip/zip_file_get_offset.c \ - $(NATIVEDIR)/ext/libzip/zip_file_strerror.c \ - $(NATIVEDIR)/ext/libzip/zip_filerange_crc.c \ - $(NATIVEDIR)/ext/libzip/zip_fopen.c \ - $(NATIVEDIR)/ext/libzip/zip_fopen_index.c \ - $(NATIVEDIR)/ext/libzip/zip_fread.c \ - $(NATIVEDIR)/ext/libzip/zip_free.c \ - $(NATIVEDIR)/ext/libzip/zip_get_archive_comment.c \ - $(NATIVEDIR)/ext/libzip/zip_get_archive_flag.c \ - $(NATIVEDIR)/ext/libzip/zip_get_file_comment.c \ - $(NATIVEDIR)/ext/libzip/zip_get_name.c \ - $(NATIVEDIR)/ext/libzip/zip_get_num_files.c \ - $(NATIVEDIR)/ext/libzip/zip_memdup.c \ - $(NATIVEDIR)/ext/libzip/zip_name_locate.c \ - $(NATIVEDIR)/ext/libzip/zip_new.c \ - $(NATIVEDIR)/ext/libzip/zip_open.c \ - $(NATIVEDIR)/ext/libzip/zip_rename.c \ - $(NATIVEDIR)/ext/libzip/zip_replace.c \ - $(NATIVEDIR)/ext/libzip/zip_set_archive_comment.c \ - $(NATIVEDIR)/ext/libzip/zip_set_archive_flag.c \ - $(NATIVEDIR)/ext/libzip/zip_set_file_comment.c \ - $(NATIVEDIR)/ext/libzip/zip_set_name.c \ - $(NATIVEDIR)/ext/libzip/zip_source_buffer.c \ - $(NATIVEDIR)/ext/libzip/zip_source_file.c \ - $(NATIVEDIR)/ext/libzip/zip_source_filep.c \ - $(NATIVEDIR)/ext/libzip/zip_source_free.c \ - $(NATIVEDIR)/ext/libzip/zip_source_function.c \ - $(NATIVEDIR)/ext/libzip/zip_source_zip.c \ - $(NATIVEDIR)/ext/libzip/zip_stat.c \ - $(NATIVEDIR)/ext/libzip/zip_stat_index.c \ - $(NATIVEDIR)/ext/libzip/zip_stat_init.c \ - $(NATIVEDIR)/ext/libzip/zip_strerror.c \ - $(NATIVEDIR)/ext/libzip/zip_unchange.c \ - $(NATIVEDIR)/ext/libzip/zip_unchange_all.c \ - $(NATIVEDIR)/ext/libzip/zip_unchange_archive.c \ - $(NATIVEDIR)/ext/libzip/zip_unchange_data.c + $(EXTDIR)/libzip/mkstemp.c \ + $(EXTDIR)/libzip/zip_add.c \ + $(EXTDIR)/libzip/zip_add_dir.c \ + $(EXTDIR)/libzip/zip_close.c \ + $(EXTDIR)/libzip/zip_delete.c \ + $(EXTDIR)/libzip/zip_dirent.c \ + $(EXTDIR)/libzip/zip_entry_free.c \ + $(EXTDIR)/libzip/zip_entry_new.c \ + $(EXTDIR)/libzip/zip_err_str.c \ + $(EXTDIR)/libzip/zip_error.c \ + $(EXTDIR)/libzip/zip_error_clear.c \ + $(EXTDIR)/libzip/zip_error_get.c \ + $(EXTDIR)/libzip/zip_error_get_sys_type.c \ + $(EXTDIR)/libzip/zip_error_strerror.c \ + $(EXTDIR)/libzip/zip_error_to_str.c \ + $(EXTDIR)/libzip/zip_fclose.c \ + $(EXTDIR)/libzip/zip_file_error_clear.c \ + $(EXTDIR)/libzip/zip_file_error_get.c \ + $(EXTDIR)/libzip/zip_file_get_offset.c \ + $(EXTDIR)/libzip/zip_file_strerror.c \ + $(EXTDIR)/libzip/zip_filerange_crc.c \ + $(EXTDIR)/libzip/zip_fopen.c \ + $(EXTDIR)/libzip/zip_fopen_index.c \ + $(EXTDIR)/libzip/zip_fread.c \ + $(EXTDIR)/libzip/zip_free.c \ + $(EXTDIR)/libzip/zip_get_archive_comment.c \ + $(EXTDIR)/libzip/zip_get_archive_flag.c \ + $(EXTDIR)/libzip/zip_get_file_comment.c \ + $(EXTDIR)/libzip/zip_get_name.c \ + $(EXTDIR)/libzip/zip_get_num_files.c \ + $(EXTDIR)/libzip/zip_memdup.c \ + $(EXTDIR)/libzip/zip_name_locate.c \ + $(EXTDIR)/libzip/zip_new.c \ + $(EXTDIR)/libzip/zip_open.c \ + $(EXTDIR)/libzip/zip_rename.c \ + $(EXTDIR)/libzip/zip_replace.c \ + $(EXTDIR)/libzip/zip_set_archive_comment.c \ + $(EXTDIR)/libzip/zip_set_archive_flag.c \ + $(EXTDIR)/libzip/zip_set_file_comment.c \ + $(EXTDIR)/libzip/zip_set_name.c \ + $(EXTDIR)/libzip/zip_source_buffer.c \ + $(EXTDIR)/libzip/zip_source_file.c \ + $(EXTDIR)/libzip/zip_source_filep.c \ + $(EXTDIR)/libzip/zip_source_free.c \ + $(EXTDIR)/libzip/zip_source_function.c \ + $(EXTDIR)/libzip/zip_source_zip.c \ + $(EXTDIR)/libzip/zip_stat.c \ + $(EXTDIR)/libzip/zip_stat_index.c \ + $(EXTDIR)/libzip/zip_stat_init.c \ + $(EXTDIR)/libzip/zip_strerror.c \ + $(EXTDIR)/libzip/zip_unchange.c \ + $(EXTDIR)/libzip/zip_unchange_all.c \ + $(EXTDIR)/libzip/zip_unchange_archive.c \ + $(EXTDIR)/libzip/zip_unchange_data.c SOURCES_C +=\ - $(NATIVEDIR)/gfx_es2/gl3stub.c \ - $(NATIVEDIR)/math/fast/fast_math.c \ - $(NATIVEDIR)/math/fast/fast_matrix.c + $(COMMONDIR)/Math/fast/fast_math.c \ + $(COMMONDIR)/Math/fast/fast_matrix.c endif -SOURCES_C += $(EXTDIR)/glew/glew.c +SOURCES_C += $(LIBRETRODIR)/ext/glew/glew.c SOURCES_C += \ $(EXTDIR)/libkirk/AES.c \ @@ -102,34 +105,36 @@ SOURCES_C += \ $(EXTDIR)/libkirk/kirk_engine.c SOURCES_C += \ - $(NATIVEDIR)/ext/libpng17/png.c \ - $(NATIVEDIR)/ext/libpng17/pngerror.c \ - $(NATIVEDIR)/ext/libpng17/pngget.c \ - $(NATIVEDIR)/ext/libpng17/pngmem.c \ - $(NATIVEDIR)/ext/libpng17/pngread.c \ - $(NATIVEDIR)/ext/libpng17/pngrio.c \ - $(NATIVEDIR)/ext/libpng17/pngrtran.c \ - $(NATIVEDIR)/ext/libpng17/pngrutil.c \ - $(NATIVEDIR)/ext/libpng17/pngset.c \ - $(NATIVEDIR)/ext/libpng17/pngtrans.c \ - $(NATIVEDIR)/ext/libpng17/pngwio.c \ - $(NATIVEDIR)/ext/libpng17/pngwrite.c \ - $(NATIVEDIR)/ext/libpng17/pngwtran.c \ - $(NATIVEDIR)/ext/libpng17/pngwutil.c + $(EXTDIR)/libpng17/png.c \ + $(EXTDIR)/libpng17/pngerror.c \ + $(EXTDIR)/libpng17/pngget.c \ + $(EXTDIR)/libpng17/pngmem.c \ + $(EXTDIR)/libpng17/pngread.c \ + $(EXTDIR)/libpng17/pngrio.c \ + $(EXTDIR)/libpng17/pngrtran.c \ + $(EXTDIR)/libpng17/pngrutil.c \ + $(EXTDIR)/libpng17/pngset.c \ + $(EXTDIR)/libpng17/pngtrans.c \ + $(EXTDIR)/libpng17/pngwio.c \ + $(EXTDIR)/libpng17/pngwrite.c \ + $(EXTDIR)/libpng17/pngwtran.c \ + $(EXTDIR)/libpng17/pngwutil.c SOURCES_C += $(EXTDIR)/sfmt19937/SFMT.c SOURCES_C += $(EXTDIR)/xxhash.c SOURCES_CXX += \ $(EXTDIR)/snappy/snappy-c.cpp \ + $(EXTDIR)/snappy/snappy-sinksource.cpp \ + $(EXTDIR)/snappy/snappy-stubs-internal.cpp \ $(EXTDIR)/snappy/snappy.cpp SOURCES_CXX += $(EXTDIR)/xbrz/xbrz.cpp SOURCES_CXX += \ - $(NATIVEDIR)/ext/gason/gason.cpp + $(EXTDIR)/gason/gason.cpp -SOURCES_CXX += $(NATIVEDIR)/ext/cityhash/city.cpp +SOURCES_CXX += $(EXTDIR)/cityhash/city.cpp SOURCES_CXX += \ $(COMMONDIR)/Crypto/md5.cpp \ @@ -137,27 +142,95 @@ SOURCES_CXX += \ $(COMMONDIR)/Crypto/sha256.cpp SOURCES_CXX += \ - $(COMMONDIR)/ChunkFile.cpp \ + $(COMMONDIR)/Data/Color/RGBAUtil.cpp \ + $(COMMONDIR)/Data/Convert/SmallDataConvert.cpp \ + $(COMMONDIR)/Data/Encoding/Base64.cpp \ + $(COMMONDIR)/Data/Encoding/Compression.cpp \ + $(COMMONDIR)/Data/Encoding/Utf8.cpp \ + $(COMMONDIR)/Data/Format/RIFF.cpp \ + $(COMMONDIR)/Data/Format/IniFile.cpp \ + $(COMMONDIR)/Data/Format/JSONReader.cpp \ + $(COMMONDIR)/Data/Format/JSONWriter.cpp \ + $(COMMONDIR)/Data/Format/PNGLoad.cpp \ + $(COMMONDIR)/Data/Format/ZIMLoad.cpp \ + $(COMMONDIR)/Data/Format/ZIMSave.cpp \ + $(COMMONDIR)/Data/Hash/Hash.cpp \ + $(COMMONDIR)/Data/Text/I18n.cpp \ + $(COMMONDIR)/Data/Text/Parsers.cpp \ + $(COMMONDIR)/Data/Text/WrapText.cpp \ + $(COMMONDIR)/File/VFS/VFS.cpp \ + $(COMMONDIR)/File/VFS/AssetReader.cpp \ + $(COMMONDIR)/File/DiskFree.cpp \ + $(COMMONDIR)/File/PathBrowser.cpp \ + $(COMMONDIR)/File/FileUtil.cpp \ + $(COMMONDIR)/File/FileDescriptor.cpp \ + $(COMMONDIR)/File/DirListing.cpp \ + $(COMMONDIR)/GPU/thin3d.cpp \ + $(COMMONDIR)/GPU/OpenGL/thin3d_gl.cpp \ + $(COMMONDIR)/GPU/OpenGL/GLDebugLog.cpp \ + $(COMMONDIR)/GPU/OpenGL/GLSLProgram.cpp \ + $(COMMONDIR)/GPU/OpenGL/GLFeatures.cpp \ + $(COMMONDIR)/GPU/OpenGL/GLRenderManager.cpp \ + $(COMMONDIR)/GPU/OpenGL/GLQueueRunner.cpp \ + $(COMMONDIR)/GPU/OpenGL/DataFormatGL.cpp \ + $(COMMONDIR)/GPU/Vulkan/thin3d_vulkan.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanQueueRunner.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanRenderManager.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanLoader.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanContext.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanDebug.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanImage.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanMemory.cpp \ + $(COMMONDIR)/Input/GestureDetector.cpp \ + $(COMMONDIR)/Input/InputState.cpp \ + $(COMMONDIR)/Math/curves.cpp \ + $(COMMONDIR)/Math/expression_parser.cpp \ + $(COMMONDIR)/Math/math_util.cpp \ + $(COMMONDIR)/Math/lin/vec3.cpp \ + $(COMMONDIR)/Math/lin/matrix4x4.cpp \ + $(COMMONDIR)/Net/HTTPClient.cpp \ + $(COMMONDIR)/Net/HTTPHeaders.cpp \ + $(COMMONDIR)/Net/HTTPServer.cpp \ + $(COMMONDIR)/Net/Resolve.cpp \ + $(COMMONDIR)/Net/Sinks.cpp \ + $(COMMONDIR)/Net/URL.cpp \ + $(COMMONDIR)/Net/WebsocketServer.cpp \ + $(COMMONDIR)/Render/DrawBuffer.cpp \ + $(COMMONDIR)/Render/TextureAtlas.cpp \ + $(COMMONDIR)/Serialize/Serializer.cpp \ + $(COMMONDIR)/Thread/Executor.cpp \ + $(COMMONDIR)/Thread/ThreadUtil.cpp \ + $(COMMONDIR)/Thread/ThreadPool.cpp \ + $(COMMONDIR)/Thread/PrioritizedWorkQueue.cpp \ + $(COMMONDIR)/UI/Root.cpp \ + $(COMMONDIR)/UI/Screen.cpp \ + $(COMMONDIR)/UI/UI.cpp \ + $(COMMONDIR)/UI/Context.cpp \ + $(COMMONDIR)/UI/UIScreen.cpp \ + $(COMMONDIR)/UI/Tween.cpp \ + $(COMMONDIR)/UI/View.cpp \ + $(COMMONDIR)/UI/ViewGroup.cpp \ + $(COMMONDIR)/System/Display.cpp \ + $(COMMONDIR)/Buffer.cpp \ $(COMMONDIR)/ConsoleListener.cpp \ - $(COMMONDIR)/FileUtil.cpp \ - $(COMMONDIR)/KeyMap.cpp \ + $(COMMONDIR)/ExceptionHandlerSetup.cpp \ + $(COMMONDIR)/Log.cpp \ $(COMMONDIR)/LogManager.cpp \ $(COMMONDIR)/OSVersion.cpp \ $(COMMONDIR)/MemoryUtil.cpp \ - $(COMMONDIR)/Misc.cpp \ - $(COMMONDIR)/MsgHandler.cpp \ + $(COMMONDIR)/SysError.cpp \ $(COMMONDIR)/StringUtils.cpp \ - $(COMMONDIR)/Timer.cpp \ - $(COMMONDIR)/ThreadPools.cpp - + $(COMMONDIR)/TimeUtil.cpp +SOURCES_C +=\ + $(COMMONDIR)/GPU/OpenGL/gl3stub.c SOURCES_CXX += \ $(GPUCOMMONDIR)/VertexDecoderCommon.cpp \ $(GPUCOMMONDIR)/GPUStateUtils.cpp \ $(GPUCOMMONDIR)/DrawEngineCommon.cpp \ $(GPUCOMMONDIR)/SplineCommon.cpp \ - $(GPUCOMMONDIR)/FramebufferCommon.cpp \ + $(GPUCOMMONDIR)/FramebufferManagerCommon.cpp \ $(GPUCOMMONDIR)/PresentationCommon.cpp \ $(GPUCOMMONDIR)/ShaderId.cpp \ $(GPUCOMMONDIR)/ShaderCommon.cpp \ @@ -182,6 +255,7 @@ SOURCES_CXX += \ $(GPUDIR)/Software/TransformUnit.cpp \ $(GPUDIR)/Software/SoftGpu.cpp \ $(GPUDIR)/Software/Sampler.cpp \ + $(GPUDIR)/GeConstants.cpp \ $(GPUDIR)/GeDisasm.cpp \ $(GPUDIR)/GPUCommon.cpp \ $(GPUDIR)/GPU.cpp \ @@ -205,15 +279,6 @@ SOURCES_CXX += \ $(GPUDIR)/GLES/ShaderManagerGLES.cpp \ $(GPUDIR)/GLES/StateMappingGLES.cpp \ $(GPUDIR)/GLES/StencilBufferGLES.cpp \ - $(EXTDIR)/native/base/backtrace.cpp \ - $(EXTDIR)/native/base/buffer.cpp \ - $(EXTDIR)/native/base/colorutil.cpp \ - $(EXTDIR)/native/base/display.cpp \ - $(EXTDIR)/native/base/logging.cpp \ - $(EXTDIR)/native/base/stringutil.cpp \ - $(EXTDIR)/native/base/timeutil.cpp \ - $(EXTDIR)/native/data/compression.cpp \ - $(EXTDIR)/native/json/json_reader.cpp \ $(EXTDIR)/glslang/OGLCompilersDLL/InitializeDll.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/CodeGen.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/Link.cpp \ @@ -260,73 +325,29 @@ SOURCES_CXX += \ ifeq ($(PLATFORM_EXT), win32) SOURCES_CXX += $(COMMONDIR)/MemArenaWin32.cpp \ $(EXTDIR)/glslang/glslang/OSDependent/Windows/ossource.cpp \ - $(NATIVEDIR)/gfx_es2/draw_text_win.cpp + $(COMMONDIR)/Render/Text/draw_text_win.cpp else ifeq ($(PLATFORM_EXT), darwin) SOURCES_CXX += $(COMMONDIR)/MemArenaDarwin.cpp \ $(EXTDIR)/glslang/glslang/OSDependent/Unix/ossource.cpp else ifeq ($(PLATFORM_EXT), android) SOURCES_CXX += $(COMMONDIR)/MemArenaAndroid.cpp \ $(EXTDIR)/glslang/glslang/OSDependent/Unix/ossource.cpp \ - $(NATIVEDIR)/gfx_es2/draw_text_android.cpp + $(COMMONDIR)/Render/Text/draw_text_android.cpp else SOURCES_CXX += $(COMMONDIR)/MemArenaPosix.cpp \ $(EXTDIR)/glslang/glslang/OSDependent/Unix/ossource.cpp endif -SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ - $(NATIVEDIR)/file/fd_util.cpp \ - $(NATIVEDIR)/file/file_util.cpp \ - $(NATIVEDIR)/file/ini_file.cpp \ - $(NATIVEDIR)/file/free.cpp \ - $(NATIVEDIR)/file/zip_read.cpp \ - $(NATIVEDIR)/gfx/gl_debug_log.cpp \ - $(NATIVEDIR)/gfx/texture_atlas.cpp \ - $(NATIVEDIR)/gfx/d3d9_shader.cpp \ - $(NATIVEDIR)/gfx/d3d9_state.cpp \ - $(NATIVEDIR)/gfx_es2/draw_buffer.cpp \ - $(NATIVEDIR)/gfx_es2/draw_text.cpp \ - $(NATIVEDIR)/gfx_es2/gpu_features.cpp \ - $(NATIVEDIR)/gfx_es2/glsl_program.cpp \ - $(NATIVEDIR)/i18n/i18n.cpp \ - $(NATIVEDIR)/image/zim_load.cpp \ - $(NATIVEDIR)/image/png_load.cpp \ - $(NATIVEDIR)/input/gesture_detector.cpp \ - $(NATIVEDIR)/input/input_state.cpp \ - $(NATIVEDIR)/math/curves.cpp \ - $(NATIVEDIR)/math/expression_parser.cpp \ - $(NATIVEDIR)/math/lin/matrix4x4.cpp \ - $(NATIVEDIR)/math/lin/plane.cpp \ - $(NATIVEDIR)/math/lin/quat.cpp \ - $(NATIVEDIR)/math/lin/vec3.cpp \ - $(NATIVEDIR)/net/http_client.cpp \ - $(NATIVEDIR)/net/resolve.cpp \ - $(NATIVEDIR)/net/url.cpp \ - $(NATIVEDIR)/thin3d/thin3d.cpp \ - $(NATIVEDIR)/thin3d/thin3d_gl.cpp \ - $(NATIVEDIR)/thin3d/GLRenderManager.cpp \ - $(NATIVEDIR)/thin3d/GLQueueRunner.cpp \ - $(NATIVEDIR)/thin3d/DataFormatGL.cpp \ - $(NATIVEDIR)/thread/threadutil.cpp \ - $(NATIVEDIR)/thread/threadpool.cpp \ - $(NATIVEDIR)/ui/root.cpp \ - $(NATIVEDIR)/ui/screen.cpp \ - $(NATIVEDIR)/ui/ui.cpp \ - $(NATIVEDIR)/ui/ui_context.cpp \ - $(NATIVEDIR)/ui/ui_screen.cpp \ - $(NATIVEDIR)/ui/ui_tween.cpp \ - $(NATIVEDIR)/ui/view.cpp \ - $(NATIVEDIR)/ui/viewgroup.cpp \ - $(NATIVEDIR)/util/hash/hash.cpp \ - $(NATIVEDIR)/util/text/utf8.cpp \ - $(NATIVEDIR)/util/text/parsers.cpp \ - $(NATIVEDIR)/util/text/wrap_text.cpp \ - $(NATIVEDIR)/ext/jpge/jpgd.cpp \ - $(NATIVEDIR)/ext/jpge/jpge.cpp \ +SOURCES_CXX += \ + $(COMMONDIR)/Render/Text/draw_text.cpp \ + $(EXTDIR)/jpge/jpgd.cpp \ + $(EXTDIR)/jpge/jpge.cpp \ $(COREDIR)/AVIDump.cpp \ $(COREDIR)/Config.cpp \ $(COREDIR)/TextureReplacer.cpp \ $(COREDIR)/Core.cpp \ $(COREDIR)/WaveFile.cpp \ + $(COREDIR)/KeyMap.cpp \ $(COREDIR)/FileLoaders/HTTPFileLoader.cpp \ $(COREDIR)/FileLoaders/CachingFileLoader.cpp \ $(COREDIR)/FileLoaders/DiskCachingFileLoader.cpp \ @@ -336,6 +357,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/CoreTiming.cpp \ $(COREDIR)/CwCheat.cpp \ $(COREDIR)/HDRemaster.cpp \ + $(COREDIR)/Instance.cpp \ $(COREDIR)/Debugger/Breakpoints.cpp \ $(COREDIR)/Debugger/SymbolMap.cpp \ $(COREDIR)/Dialog/PSPDialog.cpp \ @@ -361,6 +383,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/Font/PGF.cpp \ $(COREDIR)/HLE/HLE.cpp \ $(COREDIR)/HLE/KUBridge.cpp \ + $(COREDIR)/HLE/Plugins.cpp \ $(COREDIR)/HLE/sceSha256.cpp \ $(COREDIR)/HLE/sceG729.cpp \ $(COREDIR)/HLE/sceSfmt19937.cpp \ @@ -430,6 +453,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/HLE/sceNp.cpp \ $(COREDIR)/HLE/scePauth.cpp \ $(COREDIR)/HLE/sceUsbGps.cpp \ + $(COREDIR)/HW/BufferQueue.cpp \ $(COREDIR)/HW/Camera.cpp \ $(COREDIR)/HW/SimpleAudioDec.cpp \ $(COREDIR)/HW/AsyncIOManager.cpp \ @@ -466,6 +490,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/MIPS/MIPSIntVFPU.cpp \ $(COREDIR)/MIPS/MIPSTables.cpp \ $(COREDIR)/MIPS/MIPSVFPUUtils.cpp \ + $(COREDIR)/MemFault.cpp \ $(COREDIR)/MemMap.cpp \ $(COREDIR)/MemMapFunctions.cpp \ $(COREDIR)/PSPLoaders.cpp \ @@ -474,11 +499,13 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/SaveState.cpp \ $(COREDIR)/Screenshot.cpp \ $(COREDIR)/System.cpp \ + $(COREDIR)/ThreadPools.cpp \ $(COREDIR)/Util/BlockAllocator.cpp \ $(COREDIR)/Util/PPGeDraw.cpp \ $(COREDIR)/Util/AudioFormat.cpp \ - $(EXTDIR)/disarm.cpp \ - $(CORE_DIR)/UI/TextureUtil.cpp + $(COREDIR)/Util/PortManager.cpp \ + $(CORE_DIR)/UI/TextureUtil.cpp \ + $(CORE_DIR)/UI/GameInfoCache.cpp SOURCES_CXX += $(COREDIR)/HLE/__sceAudio.cpp @@ -499,6 +526,7 @@ ifeq ($(WITH_DYNAREC),1) $(COREDIR)/MIPS/ARM/ArmJit.cpp \ $(COREDIR)/MIPS/ARM/ArmRegCache.cpp \ $(COREDIR)/MIPS/ARM/ArmRegCacheFPU.cpp \ + $(EXTDIR)/disarm.cpp \ $(GPUCOMMONDIR)/VertexDecoderArm.cpp ifeq ($(HAVE_NEON),1) @@ -509,10 +537,10 @@ ifeq ($(WITH_DYNAREC),1) $(COMMONDIR)/ColorConvNEON.cpp \ $(GPUDIR)/Common/TextureDecoderNEON.cpp - SOURCES_C += $(NATIVEDIR)/ext/libpng17/arm/arm_init.c \ - $(NATIVEDIR)/ext/libpng17/arm/filter_neon_intrinsics.c - ASMFILES += $(NATIVEDIR)/math/fast/fast_matrix_neon.S \ - $(NATIVEDIR)/ext/libpng17/arm/filter_neon.S + SOURCES_C += $(EXTDIR)/libpng17/arm/arm_init.c \ + $(EXTDIR)/libpng17/arm/filter_neon_intrinsics.c + ASMFILES += $(COMMONDIR)/Math/fast/fast_matrix_neon.S \ + $(EXTDIR)/libpng17/arm/filter_neon.S endif else ifeq ($(TARGET_ARCH),arm64) DYNAFLAGS += -D_ARCH_64 @@ -535,13 +563,14 @@ ifeq ($(WITH_DYNAREC),1) SOURCES_CXX += \ $(COREDIR)/MIPS/ARM/ArmCompVFPUNEON.cpp \ $(COREDIR)/MIPS/ARM/ArmCompVFPUNEONUtil.cpp \ + $(COREDIR)/Util/AudioFormatNEON.cpp \ $(COMMONDIR)/ColorConvNEON.cpp \ $(GPUDIR)/Common/TextureDecoderNEON.cpp - SOURCES_C += $(NATIVEDIR)/ext/libpng17/arm/arm_init.c \ - $(NATIVEDIR)/ext/libpng17/arm/filter_neon_intrinsics.c + SOURCES_C += $(EXTDIR)/libpng17/arm/arm_init.c \ + $(EXTDIR)/libpng17/arm/filter_neon_intrinsics.c ASMFILES += $(NATIVEDIR)/math/fast/fast_matrix_neon.S \ - $(NATIVEDIR)/ext/libpng17/arm/filter_neon.S + $(EXTDIR)/libpng17/arm/filter_neon.S endif else ifneq (,$(findstring msvc,$(platform))) @@ -562,6 +591,7 @@ endif endif SOURCES_CXX += $(GPUDIR)/Software/SamplerX86.cpp SOURCES_CXX += $(COMMONDIR)/x64Emitter.cpp \ + $(COMMONDIR)/x64Analyzer.cpp \ $(COMMONDIR)/ABI.cpp \ $(COMMONDIR)/Thunk.cpp \ $(COMMONDIR)/CPUDetect.cpp \ @@ -577,14 +607,9 @@ endif $(COREDIR)/MIPS/x86/RegCache.cpp \ $(COREDIR)/MIPS/x86/RegCacheFPU.cpp \ $(GPUDIR)/Common/VertexDecoderX86.cpp - SOURCES_C += $(NATIVEDIR)/math/fast/fast_matrix_sse.c + SOURCES_C += $(COMMONDIR)/Math/fast/fast_matrix_sse.c endif endif -SOURCES_CXX += \ - $(COMMONDIR)/ArmEmitter.cpp \ - $(COMMONDIR)/Arm64Emitter.cpp \ - $(COREDIR)/Util/DisArm64.cpp - #UDIS86 # Compiled and linked even on ARM for now @@ -594,20 +619,28 @@ SOURCES_C += $(EXTDIR)/udis86/decode.c \ $(EXTDIR)/udis86/syn.c \ $(EXTDIR)/udis86/udis86.c +INCFLAGS += -I$(EXTDIR)/miniupnp-build +SOURCES_C += \ + $(EXTDIR)/miniupnp/miniupnpc/connecthostport.c \ + $(EXTDIR)/miniupnp/miniupnpc/igd_desc_parse.c \ + $(EXTDIR)/miniupnp/miniupnpc/minisoap.c \ + $(EXTDIR)/miniupnp/miniupnpc/minissdpc.c \ + $(EXTDIR)/miniupnp/miniupnpc/miniupnpc.c \ + $(EXTDIR)/miniupnp/miniupnpc/miniwget.c \ + $(EXTDIR)/miniupnp/miniupnpc/minixml.c \ + $(EXTDIR)/miniupnp/miniupnpc/minixmlvalid.c \ + $(EXTDIR)/miniupnp/miniupnpc/portlistingparse.c \ + $(EXTDIR)/miniupnp/miniupnpc/receivedata.c \ + $(EXTDIR)/miniupnp/miniupnpc/upnpcommands.c \ + $(EXTDIR)/miniupnp/miniupnpc/upnpdev.c \ + $(EXTDIR)/miniupnp/miniupnpc/upnperrors.c \ + $(EXTDIR)/miniupnp/miniupnpc/upnpreplyparse.c SOURCES_CXX += \ - $(COMMONDIR)/Vulkan/VulkanContext.cpp \ - $(COMMONDIR)/Vulkan/VulkanDebug.cpp \ - $(COMMONDIR)/Vulkan/VulkanImage.cpp \ - $(COMMONDIR)/Vulkan/VulkanLoader.cpp \ - $(COMMONDIR)/Vulkan/VulkanMemory.cpp \ - $(NATIVEDIR)/thin3d/thin3d_vulkan.cpp \ - $(NATIVEDIR)/thin3d/VulkanRenderManager.cpp \ - $(NATIVEDIR)/thin3d/VulkanQueueRunner.cpp \ $(GPUDIR)/Vulkan/DepalettizeShaderVulkan.cpp \ $(GPUDIR)/Vulkan/DrawEngineVulkan.cpp \ $(GPUDIR)/Vulkan/FragmentShaderGeneratorVulkan.cpp \ - $(GPUDIR)/Vulkan/FramebufferVulkan.cpp \ + $(GPUDIR)/Vulkan/FramebufferManagerVulkan.cpp \ $(GPUDIR)/Vulkan/GPU_Vulkan.cpp \ $(GPUDIR)/Vulkan/PipelineManagerVulkan.cpp \ $(GPUDIR)/Vulkan/ShaderManagerVulkan.cpp \ @@ -631,7 +664,7 @@ SOURCES_CXX += \ $(GPUDIR)/Directx9/DepalettizeShaderDX9.cpp \ $(GPUDIR)/Directx9/DrawEngineDX9.cpp \ $(GPUDIR)/Directx9/PixelShaderGeneratorDX9.cpp \ - $(GPUDIR)/Directx9/FramebufferDX9.cpp \ + $(GPUDIR)/Directx9/FramebufferManagerDX9.cpp \ $(GPUDIR)/Directx9/GPU_DX9.cpp \ $(GPUDIR)/Directx9/ShaderManagerDX9.cpp \ $(GPUDIR)/Directx9/StateMappingDX9.cpp \ @@ -656,12 +689,13 @@ SOURCES_CXX += \ $(LIBRETRODIR)/LibretroD3D11Context.cpp SOURCES_CXX += \ - $(NATIVEDIR)/thin3d/thin3d_d3d9.cpp \ - $(NATIVEDIR)/thin3d/thin3d_d3d11.cpp \ - $(NATIVEDIR)/thin3d/d3dx9_loader.cpp \ - $(NATIVEDIR)/thin3d/d3d11_loader.cpp \ - $(NATIVEDIR)/thin3d/d3d9_d3dcompiler_loader.cpp - + $(COMMONDIR)/GPU/D3D9/D3D9ShaderCompiler.cpp \ + $(COMMONDIR)/GPU/D3D9/D3D9StateCache.cpp \ + $(COMMONDIR)/GPU/D3D9/D3DCompilerLoader.cpp \ + $(COMMONDIR)/GPU/D3D9/thin3d_d3d9.cpp \ + $(COMMONDIR)/GPU/D3D11/D3D11Loader.cpp \ + $(COMMONDIR)/GPU/D3D11/thin3d_d3d11.cpp + INCFLAGS += -I$(CORE_DIR)/dx9sdk/Include -I$(CORE_DIR)/dx9sdk/Include/DX11 endif @@ -669,7 +703,8 @@ endif SOURCES_CXX += \ $(LIBRETRODIR)/libretro.cpp \ $(LIBRETRODIR)/LibretroGraphicsContext.cpp \ - $(LIBRETRODIR)/LibretroGLContext.cpp + $(LIBRETRODIR)/LibretroGLContext.cpp \ + $(LIBRETRODIR)/LibretroGLCoreContext.cpp ifneq ($(STATIC_LINKING), 1) SOURCES_C += \ @@ -697,11 +732,7 @@ ifneq (,$(findstring $(GIT_VERSION),$(shell grep -s char $(GIT_VERSION_SRC)))) endif ifneq ($(GIT_VERSION_NO_UPDATE),1) - $(shell echo '// This is a generated file.' > $(GIT_VERSION_SRC)) - $(shell echo >> $(GIT_VERSION_SRC)) $(shell echo 'const char *PPSSPP_GIT_VERSION = "${GIT_VERSION}";' >> $(GIT_VERSION_SRC)) - $(shell echo >> $(GIT_VERSION_SRC)) - $(shell echo "// If you don't want this file to update/recompile, change to 1." >> $(GIT_VERSION_SRC)) $(shell echo '#define PPSSPP_GIT_VERSION_NO_UPDATE 0' >> $(GIT_VERSION_SRC)) endif diff --git a/libretro/ext/glew/glew.c b/libretro/ext/glew/glew.c new file mode 100644 index 0000000000..b1da292894 --- /dev/null +++ b/libretro/ext/glew/glew.c @@ -0,0 +1,22979 @@ +/* +** The OpenGL Extension Wrangler Library +** Copyright (C) 2008-2017, Nigel Stewart +** Copyright (C) 2002-2008, Milan Ikits +** Copyright (C) 2002-2008, Marcelo E. Magallon +** Copyright (C) 2002, Lev Povalahev +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** * The name of the author may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +** THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include /* For size_t */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern retro_hw_get_proc_address_t libretro_get_proc_address; + +#ifdef __cplusplus +} +#endif + +/* + * Define GLboolean const cast. + */ +#define CONST_CAST(x) (*(GLboolean*)&x) + +/* + * Define glewGetProcAddress. + */ +#define glewGetProcAddress(name) libretro_get_proc_address((name)) + +/* + * GLEW, just like OpenGL or GLU, does not rely on the standard C library. + * These functions implement the functionality required in this file. + */ + +static GLuint _glewStrLen (const GLubyte* s) +{ + GLuint i=0; + if (s == NULL) return 0; + while (s[i] != '\0') i++; + return i; +} + +static GLuint _glewStrCLen (const GLubyte* s, GLubyte c) +{ + GLuint i=0; + if (s == NULL) return 0; + while (s[i] != '\0' && s[i] != c) i++; + return i; +} + +static GLuint _glewStrCopy(char *d, const char *s, char c) +{ + GLuint i=0; + if (s == NULL) return 0; + while (s[i] != '\0' && s[i] != c) { d[i] = s[i]; i++; } + d[i] = '\0'; + return i; +} + +#if !defined(GLEW_OSMESA) +#if !defined(__APPLE__) || defined(GLEW_APPLE_GLX) +static GLboolean _glewStrSame (const GLubyte* a, const GLubyte* b, GLuint n) +{ + GLuint i=0; + if(a == NULL || b == NULL) + return (a == NULL && b == NULL && n == 0) ? GL_TRUE : GL_FALSE; + while (i < n && a[i] != '\0' && b[i] != '\0' && a[i] == b[i]) i++; + return i == n ? GL_TRUE : GL_FALSE; +} +#endif +#endif + +static GLboolean _glewStrSame1 (const GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb) +{ + while (*na > 0 && (**a == ' ' || **a == '\n' || **a == '\r' || **a == '\t')) + { + (*a)++; + (*na)--; + } + if(*na >= nb) + { + GLuint i=0; + while (i < nb && (*a)+i != NULL && b+i != NULL && (*a)[i] == b[i]) i++; + if(i == nb) + { + *a = *a + nb; + *na = *na - nb; + return GL_TRUE; + } + } + return GL_FALSE; +} + +static GLboolean _glewStrSame2 (const GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb) +{ + if(*na >= nb) + { + GLuint i=0; + while (i < nb && (*a)+i != NULL && b+i != NULL && (*a)[i] == b[i]) i++; + if(i == nb) + { + *a = *a + nb; + *na = *na - nb; + return GL_TRUE; + } + } + return GL_FALSE; +} + +static GLboolean _glewStrSame3 (const GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb) +{ + if(*na >= nb) + { + GLuint i=0; + while (i < nb && (*a)+i != NULL && b+i != NULL && (*a)[i] == b[i]) i++; + if (i == nb && (*na == nb || (*a)[i] == ' ' || (*a)[i] == '\n' || (*a)[i] == '\r' || (*a)[i] == '\t')) + { + *a = *a + nb; + *na = *na - nb; + return GL_TRUE; + } + } + return GL_FALSE; +} + +/* + * Search for name in the extensions string. Use of strstr() + * is not sufficient because extension names can be prefixes of + * other extension names. Could use strtok() but the constant + * string returned by glGetString might be in read-only memory. + */ +#if !defined(GLEW_OSMESA) +#if !defined(__APPLE__) || defined(GLEW_APPLE_GLX) +static GLboolean _glewSearchExtension (const char* name, const GLubyte *start, const GLubyte *end) +{ + const GLubyte* p; + GLuint len = _glewStrLen((const GLubyte*)name); + p = start; + while (p < end) + { + GLuint n = _glewStrCLen(p, ' '); + if (len == n && _glewStrSame((const GLubyte*)name, p, n)) return GL_TRUE; + p += n+1; + } + return GL_FALSE; +} +#endif +#endif + +PFNGLCOPYTEXSUBIMAGE3DPROC __glewCopyTexSubImage3D = NULL; +PFNGLDRAWRANGEELEMENTSPROC __glewDrawRangeElements = NULL; +PFNGLTEXIMAGE3DPROC __glewTexImage3D = NULL; +PFNGLTEXSUBIMAGE3DPROC __glewTexSubImage3D = NULL; + +PFNGLACTIVETEXTUREPROC __glewActiveTexture = NULL; +PFNGLCLIENTACTIVETEXTUREPROC __glewClientActiveTexture = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DPROC __glewCompressedTexImage1D = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC __glewCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DPROC __glewCompressedTexImage3D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC __glewCompressedTexSubImage1D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC __glewCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC __glewCompressedTexSubImage3D = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEPROC __glewGetCompressedTexImage = NULL; +PFNGLLOADTRANSPOSEMATRIXDPROC __glewLoadTransposeMatrixd = NULL; +PFNGLLOADTRANSPOSEMATRIXFPROC __glewLoadTransposeMatrixf = NULL; +PFNGLMULTTRANSPOSEMATRIXDPROC __glewMultTransposeMatrixd = NULL; +PFNGLMULTTRANSPOSEMATRIXFPROC __glewMultTransposeMatrixf = NULL; +PFNGLMULTITEXCOORD1DPROC __glewMultiTexCoord1d = NULL; +PFNGLMULTITEXCOORD1DVPROC __glewMultiTexCoord1dv = NULL; +PFNGLMULTITEXCOORD1FPROC __glewMultiTexCoord1f = NULL; +PFNGLMULTITEXCOORD1FVPROC __glewMultiTexCoord1fv = NULL; +PFNGLMULTITEXCOORD1IPROC __glewMultiTexCoord1i = NULL; +PFNGLMULTITEXCOORD1IVPROC __glewMultiTexCoord1iv = NULL; +PFNGLMULTITEXCOORD1SPROC __glewMultiTexCoord1s = NULL; +PFNGLMULTITEXCOORD1SVPROC __glewMultiTexCoord1sv = NULL; +PFNGLMULTITEXCOORD2DPROC __glewMultiTexCoord2d = NULL; +PFNGLMULTITEXCOORD2DVPROC __glewMultiTexCoord2dv = NULL; +PFNGLMULTITEXCOORD2FPROC __glewMultiTexCoord2f = NULL; +PFNGLMULTITEXCOORD2FVPROC __glewMultiTexCoord2fv = NULL; +PFNGLMULTITEXCOORD2IPROC __glewMultiTexCoord2i = NULL; +PFNGLMULTITEXCOORD2IVPROC __glewMultiTexCoord2iv = NULL; +PFNGLMULTITEXCOORD2SPROC __glewMultiTexCoord2s = NULL; +PFNGLMULTITEXCOORD2SVPROC __glewMultiTexCoord2sv = NULL; +PFNGLMULTITEXCOORD3DPROC __glewMultiTexCoord3d = NULL; +PFNGLMULTITEXCOORD3DVPROC __glewMultiTexCoord3dv = NULL; +PFNGLMULTITEXCOORD3FPROC __glewMultiTexCoord3f = NULL; +PFNGLMULTITEXCOORD3FVPROC __glewMultiTexCoord3fv = NULL; +PFNGLMULTITEXCOORD3IPROC __glewMultiTexCoord3i = NULL; +PFNGLMULTITEXCOORD3IVPROC __glewMultiTexCoord3iv = NULL; +PFNGLMULTITEXCOORD3SPROC __glewMultiTexCoord3s = NULL; +PFNGLMULTITEXCOORD3SVPROC __glewMultiTexCoord3sv = NULL; +PFNGLMULTITEXCOORD4DPROC __glewMultiTexCoord4d = NULL; +PFNGLMULTITEXCOORD4DVPROC __glewMultiTexCoord4dv = NULL; +PFNGLMULTITEXCOORD4FPROC __glewMultiTexCoord4f = NULL; +PFNGLMULTITEXCOORD4FVPROC __glewMultiTexCoord4fv = NULL; +PFNGLMULTITEXCOORD4IPROC __glewMultiTexCoord4i = NULL; +PFNGLMULTITEXCOORD4IVPROC __glewMultiTexCoord4iv = NULL; +PFNGLMULTITEXCOORD4SPROC __glewMultiTexCoord4s = NULL; +PFNGLMULTITEXCOORD4SVPROC __glewMultiTexCoord4sv = NULL; +PFNGLSAMPLECOVERAGEPROC __glewSampleCoverage = NULL; + +PFNGLBLENDCOLORPROC __glewBlendColor = NULL; +PFNGLBLENDEQUATIONPROC __glewBlendEquation = NULL; +PFNGLBLENDFUNCSEPARATEPROC __glewBlendFuncSeparate = NULL; +PFNGLFOGCOORDPOINTERPROC __glewFogCoordPointer = NULL; +PFNGLFOGCOORDDPROC __glewFogCoordd = NULL; +PFNGLFOGCOORDDVPROC __glewFogCoorddv = NULL; +PFNGLFOGCOORDFPROC __glewFogCoordf = NULL; +PFNGLFOGCOORDFVPROC __glewFogCoordfv = NULL; +PFNGLMULTIDRAWARRAYSPROC __glewMultiDrawArrays = NULL; +PFNGLMULTIDRAWELEMENTSPROC __glewMultiDrawElements = NULL; +PFNGLPOINTPARAMETERFPROC __glewPointParameterf = NULL; +PFNGLPOINTPARAMETERFVPROC __glewPointParameterfv = NULL; +PFNGLPOINTPARAMETERIPROC __glewPointParameteri = NULL; +PFNGLPOINTPARAMETERIVPROC __glewPointParameteriv = NULL; +PFNGLSECONDARYCOLOR3BPROC __glewSecondaryColor3b = NULL; +PFNGLSECONDARYCOLOR3BVPROC __glewSecondaryColor3bv = NULL; +PFNGLSECONDARYCOLOR3DPROC __glewSecondaryColor3d = NULL; +PFNGLSECONDARYCOLOR3DVPROC __glewSecondaryColor3dv = NULL; +PFNGLSECONDARYCOLOR3FPROC __glewSecondaryColor3f = NULL; +PFNGLSECONDARYCOLOR3FVPROC __glewSecondaryColor3fv = NULL; +PFNGLSECONDARYCOLOR3IPROC __glewSecondaryColor3i = NULL; +PFNGLSECONDARYCOLOR3IVPROC __glewSecondaryColor3iv = NULL; +PFNGLSECONDARYCOLOR3SPROC __glewSecondaryColor3s = NULL; +PFNGLSECONDARYCOLOR3SVPROC __glewSecondaryColor3sv = NULL; +PFNGLSECONDARYCOLOR3UBPROC __glewSecondaryColor3ub = NULL; +PFNGLSECONDARYCOLOR3UBVPROC __glewSecondaryColor3ubv = NULL; +PFNGLSECONDARYCOLOR3UIPROC __glewSecondaryColor3ui = NULL; +PFNGLSECONDARYCOLOR3UIVPROC __glewSecondaryColor3uiv = NULL; +PFNGLSECONDARYCOLOR3USPROC __glewSecondaryColor3us = NULL; +PFNGLSECONDARYCOLOR3USVPROC __glewSecondaryColor3usv = NULL; +PFNGLSECONDARYCOLORPOINTERPROC __glewSecondaryColorPointer = NULL; +PFNGLWINDOWPOS2DPROC __glewWindowPos2d = NULL; +PFNGLWINDOWPOS2DVPROC __glewWindowPos2dv = NULL; +PFNGLWINDOWPOS2FPROC __glewWindowPos2f = NULL; +PFNGLWINDOWPOS2FVPROC __glewWindowPos2fv = NULL; +PFNGLWINDOWPOS2IPROC __glewWindowPos2i = NULL; +PFNGLWINDOWPOS2IVPROC __glewWindowPos2iv = NULL; +PFNGLWINDOWPOS2SPROC __glewWindowPos2s = NULL; +PFNGLWINDOWPOS2SVPROC __glewWindowPos2sv = NULL; +PFNGLWINDOWPOS3DPROC __glewWindowPos3d = NULL; +PFNGLWINDOWPOS3DVPROC __glewWindowPos3dv = NULL; +PFNGLWINDOWPOS3FPROC __glewWindowPos3f = NULL; +PFNGLWINDOWPOS3FVPROC __glewWindowPos3fv = NULL; +PFNGLWINDOWPOS3IPROC __glewWindowPos3i = NULL; +PFNGLWINDOWPOS3IVPROC __glewWindowPos3iv = NULL; +PFNGLWINDOWPOS3SPROC __glewWindowPos3s = NULL; +PFNGLWINDOWPOS3SVPROC __glewWindowPos3sv = NULL; + +PFNGLBEGINQUERYPROC __glewBeginQuery = NULL; +PFNGLBINDBUFFERPROC __glewBindBuffer = NULL; +PFNGLBUFFERDATAPROC __glewBufferData = NULL; +PFNGLBUFFERSUBDATAPROC __glewBufferSubData = NULL; +PFNGLDELETEBUFFERSPROC __glewDeleteBuffers = NULL; +PFNGLDELETEQUERIESPROC __glewDeleteQueries = NULL; +PFNGLENDQUERYPROC __glewEndQuery = NULL; +PFNGLGENBUFFERSPROC __glewGenBuffers = NULL; +PFNGLGENQUERIESPROC __glewGenQueries = NULL; +PFNGLGETBUFFERPARAMETERIVPROC __glewGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVPROC __glewGetBufferPointerv = NULL; +PFNGLGETBUFFERSUBDATAPROC __glewGetBufferSubData = NULL; +PFNGLGETQUERYOBJECTIVPROC __glewGetQueryObjectiv = NULL; +PFNGLGETQUERYOBJECTUIVPROC __glewGetQueryObjectuiv = NULL; +PFNGLGETQUERYIVPROC __glewGetQueryiv = NULL; +PFNGLISBUFFERPROC __glewIsBuffer = NULL; +PFNGLISQUERYPROC __glewIsQuery = NULL; +PFNGLMAPBUFFERPROC __glewMapBuffer = NULL; +PFNGLUNMAPBUFFERPROC __glewUnmapBuffer = NULL; + +PFNGLATTACHSHADERPROC __glewAttachShader = NULL; +PFNGLBINDATTRIBLOCATIONPROC __glewBindAttribLocation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC __glewBlendEquationSeparate = NULL; +PFNGLCOMPILESHADERPROC __glewCompileShader = NULL; +PFNGLCREATEPROGRAMPROC __glewCreateProgram = NULL; +PFNGLCREATESHADERPROC __glewCreateShader = NULL; +PFNGLDELETEPROGRAMPROC __glewDeleteProgram = NULL; +PFNGLDELETESHADERPROC __glewDeleteShader = NULL; +PFNGLDETACHSHADERPROC __glewDetachShader = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC __glewDisableVertexAttribArray = NULL; +PFNGLDRAWBUFFERSPROC __glewDrawBuffers = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC __glewEnableVertexAttribArray = NULL; +PFNGLGETACTIVEATTRIBPROC __glewGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC __glewGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC __glewGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC __glewGetAttribLocation = NULL; +PFNGLGETPROGRAMINFOLOGPROC __glewGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC __glewGetProgramiv = NULL; +PFNGLGETSHADERINFOLOGPROC __glewGetShaderInfoLog = NULL; +PFNGLGETSHADERSOURCEPROC __glewGetShaderSource = NULL; +PFNGLGETSHADERIVPROC __glewGetShaderiv = NULL; +PFNGLGETUNIFORMLOCATIONPROC __glewGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC __glewGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC __glewGetUniformiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC __glewGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBDVPROC __glewGetVertexAttribdv = NULL; +PFNGLGETVERTEXATTRIBFVPROC __glewGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC __glewGetVertexAttribiv = NULL; +PFNGLISPROGRAMPROC __glewIsProgram = NULL; +PFNGLISSHADERPROC __glewIsShader = NULL; +PFNGLLINKPROGRAMPROC __glewLinkProgram = NULL; +PFNGLSHADERSOURCEPROC __glewShaderSource = NULL; +PFNGLSTENCILFUNCSEPARATEPROC __glewStencilFuncSeparate = NULL; +PFNGLSTENCILMASKSEPARATEPROC __glewStencilMaskSeparate = NULL; +PFNGLSTENCILOPSEPARATEPROC __glewStencilOpSeparate = NULL; +PFNGLUNIFORM1FPROC __glewUniform1f = NULL; +PFNGLUNIFORM1FVPROC __glewUniform1fv = NULL; +PFNGLUNIFORM1IPROC __glewUniform1i = NULL; +PFNGLUNIFORM1IVPROC __glewUniform1iv = NULL; +PFNGLUNIFORM2FPROC __glewUniform2f = NULL; +PFNGLUNIFORM2FVPROC __glewUniform2fv = NULL; +PFNGLUNIFORM2IPROC __glewUniform2i = NULL; +PFNGLUNIFORM2IVPROC __glewUniform2iv = NULL; +PFNGLUNIFORM3FPROC __glewUniform3f = NULL; +PFNGLUNIFORM3FVPROC __glewUniform3fv = NULL; +PFNGLUNIFORM3IPROC __glewUniform3i = NULL; +PFNGLUNIFORM3IVPROC __glewUniform3iv = NULL; +PFNGLUNIFORM4FPROC __glewUniform4f = NULL; +PFNGLUNIFORM4FVPROC __glewUniform4fv = NULL; +PFNGLUNIFORM4IPROC __glewUniform4i = NULL; +PFNGLUNIFORM4IVPROC __glewUniform4iv = NULL; +PFNGLUNIFORMMATRIX2FVPROC __glewUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC __glewUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC __glewUniformMatrix4fv = NULL; +PFNGLUSEPROGRAMPROC __glewUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC __glewValidateProgram = NULL; +PFNGLVERTEXATTRIB1DPROC __glewVertexAttrib1d = NULL; +PFNGLVERTEXATTRIB1DVPROC __glewVertexAttrib1dv = NULL; +PFNGLVERTEXATTRIB1FPROC __glewVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC __glewVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB1SPROC __glewVertexAttrib1s = NULL; +PFNGLVERTEXATTRIB1SVPROC __glewVertexAttrib1sv = NULL; +PFNGLVERTEXATTRIB2DPROC __glewVertexAttrib2d = NULL; +PFNGLVERTEXATTRIB2DVPROC __glewVertexAttrib2dv = NULL; +PFNGLVERTEXATTRIB2FPROC __glewVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC __glewVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB2SPROC __glewVertexAttrib2s = NULL; +PFNGLVERTEXATTRIB2SVPROC __glewVertexAttrib2sv = NULL; +PFNGLVERTEXATTRIB3DPROC __glewVertexAttrib3d = NULL; +PFNGLVERTEXATTRIB3DVPROC __glewVertexAttrib3dv = NULL; +PFNGLVERTEXATTRIB3FPROC __glewVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC __glewVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB3SPROC __glewVertexAttrib3s = NULL; +PFNGLVERTEXATTRIB3SVPROC __glewVertexAttrib3sv = NULL; +PFNGLVERTEXATTRIB4NBVPROC __glewVertexAttrib4Nbv = NULL; +PFNGLVERTEXATTRIB4NIVPROC __glewVertexAttrib4Niv = NULL; +PFNGLVERTEXATTRIB4NSVPROC __glewVertexAttrib4Nsv = NULL; +PFNGLVERTEXATTRIB4NUBPROC __glewVertexAttrib4Nub = NULL; +PFNGLVERTEXATTRIB4NUBVPROC __glewVertexAttrib4Nubv = NULL; +PFNGLVERTEXATTRIB4NUIVPROC __glewVertexAttrib4Nuiv = NULL; +PFNGLVERTEXATTRIB4NUSVPROC __glewVertexAttrib4Nusv = NULL; +PFNGLVERTEXATTRIB4BVPROC __glewVertexAttrib4bv = NULL; +PFNGLVERTEXATTRIB4DPROC __glewVertexAttrib4d = NULL; +PFNGLVERTEXATTRIB4DVPROC __glewVertexAttrib4dv = NULL; +PFNGLVERTEXATTRIB4FPROC __glewVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC __glewVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIB4IVPROC __glewVertexAttrib4iv = NULL; +PFNGLVERTEXATTRIB4SPROC __glewVertexAttrib4s = NULL; +PFNGLVERTEXATTRIB4SVPROC __glewVertexAttrib4sv = NULL; +PFNGLVERTEXATTRIB4UBVPROC __glewVertexAttrib4ubv = NULL; +PFNGLVERTEXATTRIB4UIVPROC __glewVertexAttrib4uiv = NULL; +PFNGLVERTEXATTRIB4USVPROC __glewVertexAttrib4usv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC __glewVertexAttribPointer = NULL; + +PFNGLUNIFORMMATRIX2X3FVPROC __glewUniformMatrix2x3fv = NULL; +PFNGLUNIFORMMATRIX2X4FVPROC __glewUniformMatrix2x4fv = NULL; +PFNGLUNIFORMMATRIX3X2FVPROC __glewUniformMatrix3x2fv = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC __glewUniformMatrix3x4fv = NULL; +PFNGLUNIFORMMATRIX4X2FVPROC __glewUniformMatrix4x2fv = NULL; +PFNGLUNIFORMMATRIX4X3FVPROC __glewUniformMatrix4x3fv = NULL; + +PFNGLBEGINCONDITIONALRENDERPROC __glewBeginConditionalRender = NULL; +PFNGLBEGINTRANSFORMFEEDBACKPROC __glewBeginTransformFeedback = NULL; +PFNGLBINDFRAGDATALOCATIONPROC __glewBindFragDataLocation = NULL; +PFNGLCLAMPCOLORPROC __glewClampColor = NULL; +PFNGLCLEARBUFFERFIPROC __glewClearBufferfi = NULL; +PFNGLCLEARBUFFERFVPROC __glewClearBufferfv = NULL; +PFNGLCLEARBUFFERIVPROC __glewClearBufferiv = NULL; +PFNGLCLEARBUFFERUIVPROC __glewClearBufferuiv = NULL; +PFNGLCOLORMASKIPROC __glewColorMaski = NULL; +PFNGLDISABLEIPROC __glewDisablei = NULL; +PFNGLENABLEIPROC __glewEnablei = NULL; +PFNGLENDCONDITIONALRENDERPROC __glewEndConditionalRender = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC __glewEndTransformFeedback = NULL; +PFNGLGETBOOLEANI_VPROC __glewGetBooleani_v = NULL; +PFNGLGETFRAGDATALOCATIONPROC __glewGetFragDataLocation = NULL; +PFNGLGETSTRINGIPROC __glewGetStringi = NULL; +PFNGLGETTEXPARAMETERIIVPROC __glewGetTexParameterIiv = NULL; +PFNGLGETTEXPARAMETERIUIVPROC __glewGetTexParameterIuiv = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC __glewGetTransformFeedbackVarying = NULL; +PFNGLGETUNIFORMUIVPROC __glewGetUniformuiv = NULL; +PFNGLGETVERTEXATTRIBIIVPROC __glewGetVertexAttribIiv = NULL; +PFNGLGETVERTEXATTRIBIUIVPROC __glewGetVertexAttribIuiv = NULL; +PFNGLISENABLEDIPROC __glewIsEnabledi = NULL; +PFNGLTEXPARAMETERIIVPROC __glewTexParameterIiv = NULL; +PFNGLTEXPARAMETERIUIVPROC __glewTexParameterIuiv = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC __glewTransformFeedbackVaryings = NULL; +PFNGLUNIFORM1UIPROC __glewUniform1ui = NULL; +PFNGLUNIFORM1UIVPROC __glewUniform1uiv = NULL; +PFNGLUNIFORM2UIPROC __glewUniform2ui = NULL; +PFNGLUNIFORM2UIVPROC __glewUniform2uiv = NULL; +PFNGLUNIFORM3UIPROC __glewUniform3ui = NULL; +PFNGLUNIFORM3UIVPROC __glewUniform3uiv = NULL; +PFNGLUNIFORM4UIPROC __glewUniform4ui = NULL; +PFNGLUNIFORM4UIVPROC __glewUniform4uiv = NULL; +PFNGLVERTEXATTRIBI1IPROC __glewVertexAttribI1i = NULL; +PFNGLVERTEXATTRIBI1IVPROC __glewVertexAttribI1iv = NULL; +PFNGLVERTEXATTRIBI1UIPROC __glewVertexAttribI1ui = NULL; +PFNGLVERTEXATTRIBI1UIVPROC __glewVertexAttribI1uiv = NULL; +PFNGLVERTEXATTRIBI2IPROC __glewVertexAttribI2i = NULL; +PFNGLVERTEXATTRIBI2IVPROC __glewVertexAttribI2iv = NULL; +PFNGLVERTEXATTRIBI2UIPROC __glewVertexAttribI2ui = NULL; +PFNGLVERTEXATTRIBI2UIVPROC __glewVertexAttribI2uiv = NULL; +PFNGLVERTEXATTRIBI3IPROC __glewVertexAttribI3i = NULL; +PFNGLVERTEXATTRIBI3IVPROC __glewVertexAttribI3iv = NULL; +PFNGLVERTEXATTRIBI3UIPROC __glewVertexAttribI3ui = NULL; +PFNGLVERTEXATTRIBI3UIVPROC __glewVertexAttribI3uiv = NULL; +PFNGLVERTEXATTRIBI4BVPROC __glewVertexAttribI4bv = NULL; +PFNGLVERTEXATTRIBI4IPROC __glewVertexAttribI4i = NULL; +PFNGLVERTEXATTRIBI4IVPROC __glewVertexAttribI4iv = NULL; +PFNGLVERTEXATTRIBI4SVPROC __glewVertexAttribI4sv = NULL; +PFNGLVERTEXATTRIBI4UBVPROC __glewVertexAttribI4ubv = NULL; +PFNGLVERTEXATTRIBI4UIPROC __glewVertexAttribI4ui = NULL; +PFNGLVERTEXATTRIBI4UIVPROC __glewVertexAttribI4uiv = NULL; +PFNGLVERTEXATTRIBI4USVPROC __glewVertexAttribI4usv = NULL; +PFNGLVERTEXATTRIBIPOINTERPROC __glewVertexAttribIPointer = NULL; + +PFNGLDRAWARRAYSINSTANCEDPROC __glewDrawArraysInstanced = NULL; +PFNGLDRAWELEMENTSINSTANCEDPROC __glewDrawElementsInstanced = NULL; +PFNGLPRIMITIVERESTARTINDEXPROC __glewPrimitiveRestartIndex = NULL; +PFNGLTEXBUFFERPROC __glewTexBuffer = NULL; + +PFNGLFRAMEBUFFERTEXTUREPROC __glewFramebufferTexture = NULL; +PFNGLGETBUFFERPARAMETERI64VPROC __glewGetBufferParameteri64v = NULL; +PFNGLGETINTEGER64I_VPROC __glewGetInteger64i_v = NULL; + +PFNGLVERTEXATTRIBDIVISORPROC __glewVertexAttribDivisor = NULL; + +PFNGLBLENDEQUATIONSEPARATEIPROC __glewBlendEquationSeparatei = NULL; +PFNGLBLENDEQUATIONIPROC __glewBlendEquationi = NULL; +PFNGLBLENDFUNCSEPARATEIPROC __glewBlendFuncSeparatei = NULL; +PFNGLBLENDFUNCIPROC __glewBlendFunci = NULL; +PFNGLMINSAMPLESHADINGPROC __glewMinSampleShading = NULL; + +PFNGLGETGRAPHICSRESETSTATUSPROC __glewGetGraphicsResetStatus = NULL; +PFNGLGETNCOMPRESSEDTEXIMAGEPROC __glewGetnCompressedTexImage = NULL; +PFNGLGETNTEXIMAGEPROC __glewGetnTexImage = NULL; +PFNGLGETNUNIFORMDVPROC __glewGetnUniformdv = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC __glewMultiDrawArraysIndirectCount = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC __glewMultiDrawElementsIndirectCount = NULL; +PFNGLSPECIALIZESHADERPROC __glewSpecializeShader = NULL; + +PFNGLTBUFFERMASK3DFXPROC __glewTbufferMask3DFX = NULL; + +PFNGLDEBUGMESSAGECALLBACKAMDPROC __glewDebugMessageCallbackAMD = NULL; +PFNGLDEBUGMESSAGEENABLEAMDPROC __glewDebugMessageEnableAMD = NULL; +PFNGLDEBUGMESSAGEINSERTAMDPROC __glewDebugMessageInsertAMD = NULL; +PFNGLGETDEBUGMESSAGELOGAMDPROC __glewGetDebugMessageLogAMD = NULL; + +PFNGLBLENDEQUATIONINDEXEDAMDPROC __glewBlendEquationIndexedAMD = NULL; +PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC __glewBlendEquationSeparateIndexedAMD = NULL; +PFNGLBLENDFUNCINDEXEDAMDPROC __glewBlendFuncIndexedAMD = NULL; +PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC __glewBlendFuncSeparateIndexedAMD = NULL; + +PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC __glewFramebufferSamplePositionsfvAMD = NULL; +PFNGLGETFRAMEBUFFERPARAMETERFVAMDPROC __glewGetFramebufferParameterfvAMD = NULL; +PFNGLGETNAMEDFRAMEBUFFERPARAMETERFVAMDPROC __glewGetNamedFramebufferParameterfvAMD = NULL; +PFNGLNAMEDFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC __glewNamedFramebufferSamplePositionsfvAMD = NULL; + +PFNGLVERTEXATTRIBPARAMETERIAMDPROC __glewVertexAttribParameteriAMD = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC __glewMultiDrawArraysIndirectAMD = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC __glewMultiDrawElementsIndirectAMD = NULL; + +PFNGLDELETENAMESAMDPROC __glewDeleteNamesAMD = NULL; +PFNGLGENNAMESAMDPROC __glewGenNamesAMD = NULL; +PFNGLISNAMEAMDPROC __glewIsNameAMD = NULL; + +PFNGLQUERYOBJECTPARAMETERUIAMDPROC __glewQueryObjectParameteruiAMD = NULL; + +PFNGLBEGINPERFMONITORAMDPROC __glewBeginPerfMonitorAMD = NULL; +PFNGLDELETEPERFMONITORSAMDPROC __glewDeletePerfMonitorsAMD = NULL; +PFNGLENDPERFMONITORAMDPROC __glewEndPerfMonitorAMD = NULL; +PFNGLGENPERFMONITORSAMDPROC __glewGenPerfMonitorsAMD = NULL; +PFNGLGETPERFMONITORCOUNTERDATAAMDPROC __glewGetPerfMonitorCounterDataAMD = NULL; +PFNGLGETPERFMONITORCOUNTERINFOAMDPROC __glewGetPerfMonitorCounterInfoAMD = NULL; +PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC __glewGetPerfMonitorCounterStringAMD = NULL; +PFNGLGETPERFMONITORCOUNTERSAMDPROC __glewGetPerfMonitorCountersAMD = NULL; +PFNGLGETPERFMONITORGROUPSTRINGAMDPROC __glewGetPerfMonitorGroupStringAMD = NULL; +PFNGLGETPERFMONITORGROUPSAMDPROC __glewGetPerfMonitorGroupsAMD = NULL; +PFNGLSELECTPERFMONITORCOUNTERSAMDPROC __glewSelectPerfMonitorCountersAMD = NULL; + +PFNGLSETMULTISAMPLEFVAMDPROC __glewSetMultisamplefvAMD = NULL; + +PFNGLTEXSTORAGESPARSEAMDPROC __glewTexStorageSparseAMD = NULL; +PFNGLTEXTURESTORAGESPARSEAMDPROC __glewTextureStorageSparseAMD = NULL; + +PFNGLSTENCILOPVALUEAMDPROC __glewStencilOpValueAMD = NULL; + +PFNGLTESSELLATIONFACTORAMDPROC __glewTessellationFactorAMD = NULL; +PFNGLTESSELLATIONMODEAMDPROC __glewTessellationModeAMD = NULL; + +PFNGLBLITFRAMEBUFFERANGLEPROC __glewBlitFramebufferANGLE = NULL; + +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC __glewRenderbufferStorageMultisampleANGLE = NULL; + +PFNGLDRAWARRAYSINSTANCEDANGLEPROC __glewDrawArraysInstancedANGLE = NULL; +PFNGLDRAWELEMENTSINSTANCEDANGLEPROC __glewDrawElementsInstancedANGLE = NULL; +PFNGLVERTEXATTRIBDIVISORANGLEPROC __glewVertexAttribDivisorANGLE = NULL; + +PFNGLBEGINQUERYANGLEPROC __glewBeginQueryANGLE = NULL; +PFNGLDELETEQUERIESANGLEPROC __glewDeleteQueriesANGLE = NULL; +PFNGLENDQUERYANGLEPROC __glewEndQueryANGLE = NULL; +PFNGLGENQUERIESANGLEPROC __glewGenQueriesANGLE = NULL; +PFNGLGETQUERYOBJECTI64VANGLEPROC __glewGetQueryObjecti64vANGLE = NULL; +PFNGLGETQUERYOBJECTIVANGLEPROC __glewGetQueryObjectivANGLE = NULL; +PFNGLGETQUERYOBJECTUI64VANGLEPROC __glewGetQueryObjectui64vANGLE = NULL; +PFNGLGETQUERYOBJECTUIVANGLEPROC __glewGetQueryObjectuivANGLE = NULL; +PFNGLGETQUERYIVANGLEPROC __glewGetQueryivANGLE = NULL; +PFNGLISQUERYANGLEPROC __glewIsQueryANGLE = NULL; +PFNGLQUERYCOUNTERANGLEPROC __glewQueryCounterANGLE = NULL; + +PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC __glewGetTranslatedShaderSourceANGLE = NULL; + +PFNGLCOPYTEXTURELEVELSAPPLEPROC __glewCopyTextureLevelsAPPLE = NULL; + +PFNGLDRAWELEMENTARRAYAPPLEPROC __glewDrawElementArrayAPPLE = NULL; +PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC __glewDrawRangeElementArrayAPPLE = NULL; +PFNGLELEMENTPOINTERAPPLEPROC __glewElementPointerAPPLE = NULL; +PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC __glewMultiDrawElementArrayAPPLE = NULL; +PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC __glewMultiDrawRangeElementArrayAPPLE = NULL; + +PFNGLDELETEFENCESAPPLEPROC __glewDeleteFencesAPPLE = NULL; +PFNGLFINISHFENCEAPPLEPROC __glewFinishFenceAPPLE = NULL; +PFNGLFINISHOBJECTAPPLEPROC __glewFinishObjectAPPLE = NULL; +PFNGLGENFENCESAPPLEPROC __glewGenFencesAPPLE = NULL; +PFNGLISFENCEAPPLEPROC __glewIsFenceAPPLE = NULL; +PFNGLSETFENCEAPPLEPROC __glewSetFenceAPPLE = NULL; +PFNGLTESTFENCEAPPLEPROC __glewTestFenceAPPLE = NULL; +PFNGLTESTOBJECTAPPLEPROC __glewTestObjectAPPLE = NULL; + +PFNGLBUFFERPARAMETERIAPPLEPROC __glewBufferParameteriAPPLE = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC __glewFlushMappedBufferRangeAPPLE = NULL; + +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC __glewRenderbufferStorageMultisampleAPPLE = NULL; +PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC __glewResolveMultisampleFramebufferAPPLE = NULL; + +PFNGLGETOBJECTPARAMETERIVAPPLEPROC __glewGetObjectParameterivAPPLE = NULL; +PFNGLOBJECTPURGEABLEAPPLEPROC __glewObjectPurgeableAPPLE = NULL; +PFNGLOBJECTUNPURGEABLEAPPLEPROC __glewObjectUnpurgeableAPPLE = NULL; + +PFNGLCLIENTWAITSYNCAPPLEPROC __glewClientWaitSyncAPPLE = NULL; +PFNGLDELETESYNCAPPLEPROC __glewDeleteSyncAPPLE = NULL; +PFNGLFENCESYNCAPPLEPROC __glewFenceSyncAPPLE = NULL; +PFNGLGETINTEGER64VAPPLEPROC __glewGetInteger64vAPPLE = NULL; +PFNGLGETSYNCIVAPPLEPROC __glewGetSyncivAPPLE = NULL; +PFNGLISSYNCAPPLEPROC __glewIsSyncAPPLE = NULL; +PFNGLWAITSYNCAPPLEPROC __glewWaitSyncAPPLE = NULL; + +PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC __glewGetTexParameterPointervAPPLE = NULL; +PFNGLTEXTURERANGEAPPLEPROC __glewTextureRangeAPPLE = NULL; + +PFNGLBINDVERTEXARRAYAPPLEPROC __glewBindVertexArrayAPPLE = NULL; +PFNGLDELETEVERTEXARRAYSAPPLEPROC __glewDeleteVertexArraysAPPLE = NULL; +PFNGLGENVERTEXARRAYSAPPLEPROC __glewGenVertexArraysAPPLE = NULL; +PFNGLISVERTEXARRAYAPPLEPROC __glewIsVertexArrayAPPLE = NULL; + +PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC __glewFlushVertexArrayRangeAPPLE = NULL; +PFNGLVERTEXARRAYPARAMETERIAPPLEPROC __glewVertexArrayParameteriAPPLE = NULL; +PFNGLVERTEXARRAYRANGEAPPLEPROC __glewVertexArrayRangeAPPLE = NULL; + +PFNGLDISABLEVERTEXATTRIBAPPLEPROC __glewDisableVertexAttribAPPLE = NULL; +PFNGLENABLEVERTEXATTRIBAPPLEPROC __glewEnableVertexAttribAPPLE = NULL; +PFNGLISVERTEXATTRIBENABLEDAPPLEPROC __glewIsVertexAttribEnabledAPPLE = NULL; +PFNGLMAPVERTEXATTRIB1DAPPLEPROC __glewMapVertexAttrib1dAPPLE = NULL; +PFNGLMAPVERTEXATTRIB1FAPPLEPROC __glewMapVertexAttrib1fAPPLE = NULL; +PFNGLMAPVERTEXATTRIB2DAPPLEPROC __glewMapVertexAttrib2dAPPLE = NULL; +PFNGLMAPVERTEXATTRIB2FAPPLEPROC __glewMapVertexAttrib2fAPPLE = NULL; + +PFNGLCLEARDEPTHFPROC __glewClearDepthf = NULL; +PFNGLDEPTHRANGEFPROC __glewDepthRangef = NULL; +PFNGLGETSHADERPRECISIONFORMATPROC __glewGetShaderPrecisionFormat = NULL; +PFNGLRELEASESHADERCOMPILERPROC __glewReleaseShaderCompiler = NULL; +PFNGLSHADERBINARYPROC __glewShaderBinary = NULL; + +PFNGLMEMORYBARRIERBYREGIONPROC __glewMemoryBarrierByRegion = NULL; + +PFNGLPRIMITIVEBOUNDINGBOXARBPROC __glewPrimitiveBoundingBoxARB = NULL; + +PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __glewDrawArraysInstancedBaseInstance = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __glewDrawElementsInstancedBaseInstance = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __glewDrawElementsInstancedBaseVertexBaseInstance = NULL; + +PFNGLGETIMAGEHANDLEARBPROC __glewGetImageHandleARB = NULL; +PFNGLGETTEXTUREHANDLEARBPROC __glewGetTextureHandleARB = NULL; +PFNGLGETTEXTURESAMPLERHANDLEARBPROC __glewGetTextureSamplerHandleARB = NULL; +PFNGLGETVERTEXATTRIBLUI64VARBPROC __glewGetVertexAttribLui64vARB = NULL; +PFNGLISIMAGEHANDLERESIDENTARBPROC __glewIsImageHandleResidentARB = NULL; +PFNGLISTEXTUREHANDLERESIDENTARBPROC __glewIsTextureHandleResidentARB = NULL; +PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC __glewMakeImageHandleNonResidentARB = NULL; +PFNGLMAKEIMAGEHANDLERESIDENTARBPROC __glewMakeImageHandleResidentARB = NULL; +PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC __glewMakeTextureHandleNonResidentARB = NULL; +PFNGLMAKETEXTUREHANDLERESIDENTARBPROC __glewMakeTextureHandleResidentARB = NULL; +PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC __glewProgramUniformHandleui64ARB = NULL; +PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC __glewProgramUniformHandleui64vARB = NULL; +PFNGLUNIFORMHANDLEUI64ARBPROC __glewUniformHandleui64ARB = NULL; +PFNGLUNIFORMHANDLEUI64VARBPROC __glewUniformHandleui64vARB = NULL; +PFNGLVERTEXATTRIBL1UI64ARBPROC __glewVertexAttribL1ui64ARB = NULL; +PFNGLVERTEXATTRIBL1UI64VARBPROC __glewVertexAttribL1ui64vARB = NULL; + +PFNGLBINDFRAGDATALOCATIONINDEXEDPROC __glewBindFragDataLocationIndexed = NULL; +PFNGLGETFRAGDATAINDEXPROC __glewGetFragDataIndex = NULL; + +PFNGLBUFFERSTORAGEPROC __glewBufferStorage = NULL; + +PFNGLCREATESYNCFROMCLEVENTARBPROC __glewCreateSyncFromCLeventARB = NULL; + +PFNGLCLEARBUFFERDATAPROC __glewClearBufferData = NULL; +PFNGLCLEARBUFFERSUBDATAPROC __glewClearBufferSubData = NULL; +PFNGLCLEARNAMEDBUFFERDATAEXTPROC __glewClearNamedBufferDataEXT = NULL; +PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC __glewClearNamedBufferSubDataEXT = NULL; + +PFNGLCLEARTEXIMAGEPROC __glewClearTexImage = NULL; +PFNGLCLEARTEXSUBIMAGEPROC __glewClearTexSubImage = NULL; + +PFNGLCLIPCONTROLPROC __glewClipControl = NULL; + +PFNGLCLAMPCOLORARBPROC __glewClampColorARB = NULL; + +PFNGLDISPATCHCOMPUTEPROC __glewDispatchCompute = NULL; +PFNGLDISPATCHCOMPUTEINDIRECTPROC __glewDispatchComputeIndirect = NULL; + +PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC __glewDispatchComputeGroupSizeARB = NULL; + +PFNGLCOPYBUFFERSUBDATAPROC __glewCopyBufferSubData = NULL; + +PFNGLCOPYIMAGESUBDATAPROC __glewCopyImageSubData = NULL; + +PFNGLDEBUGMESSAGECALLBACKARBPROC __glewDebugMessageCallbackARB = NULL; +PFNGLDEBUGMESSAGECONTROLARBPROC __glewDebugMessageControlARB = NULL; +PFNGLDEBUGMESSAGEINSERTARBPROC __glewDebugMessageInsertARB = NULL; +PFNGLGETDEBUGMESSAGELOGARBPROC __glewGetDebugMessageLogARB = NULL; + +PFNGLBINDTEXTUREUNITPROC __glewBindTextureUnit = NULL; +PFNGLBLITNAMEDFRAMEBUFFERPROC __glewBlitNamedFramebuffer = NULL; +PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC __glewCheckNamedFramebufferStatus = NULL; +PFNGLCLEARNAMEDBUFFERDATAPROC __glewClearNamedBufferData = NULL; +PFNGLCLEARNAMEDBUFFERSUBDATAPROC __glewClearNamedBufferSubData = NULL; +PFNGLCLEARNAMEDFRAMEBUFFERFIPROC __glewClearNamedFramebufferfi = NULL; +PFNGLCLEARNAMEDFRAMEBUFFERFVPROC __glewClearNamedFramebufferfv = NULL; +PFNGLCLEARNAMEDFRAMEBUFFERIVPROC __glewClearNamedFramebufferiv = NULL; +PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC __glewClearNamedFramebufferuiv = NULL; +PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC __glewCompressedTextureSubImage1D = NULL; +PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC __glewCompressedTextureSubImage2D = NULL; +PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC __glewCompressedTextureSubImage3D = NULL; +PFNGLCOPYNAMEDBUFFERSUBDATAPROC __glewCopyNamedBufferSubData = NULL; +PFNGLCOPYTEXTURESUBIMAGE1DPROC __glewCopyTextureSubImage1D = NULL; +PFNGLCOPYTEXTURESUBIMAGE2DPROC __glewCopyTextureSubImage2D = NULL; +PFNGLCOPYTEXTURESUBIMAGE3DPROC __glewCopyTextureSubImage3D = NULL; +PFNGLCREATEBUFFERSPROC __glewCreateBuffers = NULL; +PFNGLCREATEFRAMEBUFFERSPROC __glewCreateFramebuffers = NULL; +PFNGLCREATEPROGRAMPIPELINESPROC __glewCreateProgramPipelines = NULL; +PFNGLCREATEQUERIESPROC __glewCreateQueries = NULL; +PFNGLCREATERENDERBUFFERSPROC __glewCreateRenderbuffers = NULL; +PFNGLCREATESAMPLERSPROC __glewCreateSamplers = NULL; +PFNGLCREATETEXTURESPROC __glewCreateTextures = NULL; +PFNGLCREATETRANSFORMFEEDBACKSPROC __glewCreateTransformFeedbacks = NULL; +PFNGLCREATEVERTEXARRAYSPROC __glewCreateVertexArrays = NULL; +PFNGLDISABLEVERTEXARRAYATTRIBPROC __glewDisableVertexArrayAttrib = NULL; +PFNGLENABLEVERTEXARRAYATTRIBPROC __glewEnableVertexArrayAttrib = NULL; +PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC __glewFlushMappedNamedBufferRange = NULL; +PFNGLGENERATETEXTUREMIPMAPPROC __glewGenerateTextureMipmap = NULL; +PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC __glewGetCompressedTextureImage = NULL; +PFNGLGETNAMEDBUFFERPARAMETERI64VPROC __glewGetNamedBufferParameteri64v = NULL; +PFNGLGETNAMEDBUFFERPARAMETERIVPROC __glewGetNamedBufferParameteriv = NULL; +PFNGLGETNAMEDBUFFERPOINTERVPROC __glewGetNamedBufferPointerv = NULL; +PFNGLGETNAMEDBUFFERSUBDATAPROC __glewGetNamedBufferSubData = NULL; +PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC __glewGetNamedFramebufferAttachmentParameteriv = NULL; +PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC __glewGetNamedFramebufferParameteriv = NULL; +PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC __glewGetNamedRenderbufferParameteriv = NULL; +PFNGLGETQUERYBUFFEROBJECTI64VPROC __glewGetQueryBufferObjecti64v = NULL; +PFNGLGETQUERYBUFFEROBJECTIVPROC __glewGetQueryBufferObjectiv = NULL; +PFNGLGETQUERYBUFFEROBJECTUI64VPROC __glewGetQueryBufferObjectui64v = NULL; +PFNGLGETQUERYBUFFEROBJECTUIVPROC __glewGetQueryBufferObjectuiv = NULL; +PFNGLGETTEXTUREIMAGEPROC __glewGetTextureImage = NULL; +PFNGLGETTEXTURELEVELPARAMETERFVPROC __glewGetTextureLevelParameterfv = NULL; +PFNGLGETTEXTURELEVELPARAMETERIVPROC __glewGetTextureLevelParameteriv = NULL; +PFNGLGETTEXTUREPARAMETERIIVPROC __glewGetTextureParameterIiv = NULL; +PFNGLGETTEXTUREPARAMETERIUIVPROC __glewGetTextureParameterIuiv = NULL; +PFNGLGETTEXTUREPARAMETERFVPROC __glewGetTextureParameterfv = NULL; +PFNGLGETTEXTUREPARAMETERIVPROC __glewGetTextureParameteriv = NULL; +PFNGLGETTRANSFORMFEEDBACKI64_VPROC __glewGetTransformFeedbacki64_v = NULL; +PFNGLGETTRANSFORMFEEDBACKI_VPROC __glewGetTransformFeedbacki_v = NULL; +PFNGLGETTRANSFORMFEEDBACKIVPROC __glewGetTransformFeedbackiv = NULL; +PFNGLGETVERTEXARRAYINDEXED64IVPROC __glewGetVertexArrayIndexed64iv = NULL; +PFNGLGETVERTEXARRAYINDEXEDIVPROC __glewGetVertexArrayIndexediv = NULL; +PFNGLGETVERTEXARRAYIVPROC __glewGetVertexArrayiv = NULL; +PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC __glewInvalidateNamedFramebufferData = NULL; +PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC __glewInvalidateNamedFramebufferSubData = NULL; +PFNGLMAPNAMEDBUFFERPROC __glewMapNamedBuffer = NULL; +PFNGLMAPNAMEDBUFFERRANGEPROC __glewMapNamedBufferRange = NULL; +PFNGLNAMEDBUFFERDATAPROC __glewNamedBufferData = NULL; +PFNGLNAMEDBUFFERSTORAGEPROC __glewNamedBufferStorage = NULL; +PFNGLNAMEDBUFFERSUBDATAPROC __glewNamedBufferSubData = NULL; +PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC __glewNamedFramebufferDrawBuffer = NULL; +PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC __glewNamedFramebufferDrawBuffers = NULL; +PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC __glewNamedFramebufferParameteri = NULL; +PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC __glewNamedFramebufferReadBuffer = NULL; +PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC __glewNamedFramebufferRenderbuffer = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTUREPROC __glewNamedFramebufferTexture = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC __glewNamedFramebufferTextureLayer = NULL; +PFNGLNAMEDRENDERBUFFERSTORAGEPROC __glewNamedRenderbufferStorage = NULL; +PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC __glewNamedRenderbufferStorageMultisample = NULL; +PFNGLTEXTUREBUFFERPROC __glewTextureBuffer = NULL; +PFNGLTEXTUREBUFFERRANGEPROC __glewTextureBufferRange = NULL; +PFNGLTEXTUREPARAMETERIIVPROC __glewTextureParameterIiv = NULL; +PFNGLTEXTUREPARAMETERIUIVPROC __glewTextureParameterIuiv = NULL; +PFNGLTEXTUREPARAMETERFPROC __glewTextureParameterf = NULL; +PFNGLTEXTUREPARAMETERFVPROC __glewTextureParameterfv = NULL; +PFNGLTEXTUREPARAMETERIPROC __glewTextureParameteri = NULL; +PFNGLTEXTUREPARAMETERIVPROC __glewTextureParameteriv = NULL; +PFNGLTEXTURESTORAGE1DPROC __glewTextureStorage1D = NULL; +PFNGLTEXTURESTORAGE2DPROC __glewTextureStorage2D = NULL; +PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC __glewTextureStorage2DMultisample = NULL; +PFNGLTEXTURESTORAGE3DPROC __glewTextureStorage3D = NULL; +PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC __glewTextureStorage3DMultisample = NULL; +PFNGLTEXTURESUBIMAGE1DPROC __glewTextureSubImage1D = NULL; +PFNGLTEXTURESUBIMAGE2DPROC __glewTextureSubImage2D = NULL; +PFNGLTEXTURESUBIMAGE3DPROC __glewTextureSubImage3D = NULL; +PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC __glewTransformFeedbackBufferBase = NULL; +PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC __glewTransformFeedbackBufferRange = NULL; +PFNGLUNMAPNAMEDBUFFERPROC __glewUnmapNamedBuffer = NULL; +PFNGLVERTEXARRAYATTRIBBINDINGPROC __glewVertexArrayAttribBinding = NULL; +PFNGLVERTEXARRAYATTRIBFORMATPROC __glewVertexArrayAttribFormat = NULL; +PFNGLVERTEXARRAYATTRIBIFORMATPROC __glewVertexArrayAttribIFormat = NULL; +PFNGLVERTEXARRAYATTRIBLFORMATPROC __glewVertexArrayAttribLFormat = NULL; +PFNGLVERTEXARRAYBINDINGDIVISORPROC __glewVertexArrayBindingDivisor = NULL; +PFNGLVERTEXARRAYELEMENTBUFFERPROC __glewVertexArrayElementBuffer = NULL; +PFNGLVERTEXARRAYVERTEXBUFFERPROC __glewVertexArrayVertexBuffer = NULL; +PFNGLVERTEXARRAYVERTEXBUFFERSPROC __glewVertexArrayVertexBuffers = NULL; + +PFNGLDRAWBUFFERSARBPROC __glewDrawBuffersARB = NULL; + +PFNGLBLENDEQUATIONSEPARATEIARBPROC __glewBlendEquationSeparateiARB = NULL; +PFNGLBLENDEQUATIONIARBPROC __glewBlendEquationiARB = NULL; +PFNGLBLENDFUNCSEPARATEIARBPROC __glewBlendFuncSeparateiARB = NULL; +PFNGLBLENDFUNCIARBPROC __glewBlendFunciARB = NULL; + +PFNGLDRAWELEMENTSBASEVERTEXPROC __glewDrawElementsBaseVertex = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __glewDrawElementsInstancedBaseVertex = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC __glewDrawRangeElementsBaseVertex = NULL; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC __glewMultiDrawElementsBaseVertex = NULL; + +PFNGLDRAWARRAYSINDIRECTPROC __glewDrawArraysIndirect = NULL; +PFNGLDRAWELEMENTSINDIRECTPROC __glewDrawElementsIndirect = NULL; + +PFNGLFRAMEBUFFERPARAMETERIPROC __glewFramebufferParameteri = NULL; +PFNGLGETFRAMEBUFFERPARAMETERIVPROC __glewGetFramebufferParameteriv = NULL; +PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC __glewGetNamedFramebufferParameterivEXT = NULL; +PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC __glewNamedFramebufferParameteriEXT = NULL; + +PFNGLBINDFRAMEBUFFERPROC __glewBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC __glewBindRenderbuffer = NULL; +PFNGLBLITFRAMEBUFFERPROC __glewBlitFramebuffer = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC __glewCheckFramebufferStatus = NULL; +PFNGLDELETEFRAMEBUFFERSPROC __glewDeleteFramebuffers = NULL; +PFNGLDELETERENDERBUFFERSPROC __glewDeleteRenderbuffers = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC __glewFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTURE1DPROC __glewFramebufferTexture1D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC __glewFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE3DPROC __glewFramebufferTexture3D = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERPROC __glewFramebufferTextureLayer = NULL; +PFNGLGENFRAMEBUFFERSPROC __glewGenFramebuffers = NULL; +PFNGLGENRENDERBUFFERSPROC __glewGenRenderbuffers = NULL; +PFNGLGENERATEMIPMAPPROC __glewGenerateMipmap = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __glewGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC __glewGetRenderbufferParameteriv = NULL; +PFNGLISFRAMEBUFFERPROC __glewIsFramebuffer = NULL; +PFNGLISRENDERBUFFERPROC __glewIsRenderbuffer = NULL; +PFNGLRENDERBUFFERSTORAGEPROC __glewRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __glewRenderbufferStorageMultisample = NULL; + +PFNGLFRAMEBUFFERTEXTUREARBPROC __glewFramebufferTextureARB = NULL; +PFNGLFRAMEBUFFERTEXTUREFACEARBPROC __glewFramebufferTextureFaceARB = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERARBPROC __glewFramebufferTextureLayerARB = NULL; +PFNGLPROGRAMPARAMETERIARBPROC __glewProgramParameteriARB = NULL; + +PFNGLGETPROGRAMBINARYPROC __glewGetProgramBinary = NULL; +PFNGLPROGRAMBINARYPROC __glewProgramBinary = NULL; +PFNGLPROGRAMPARAMETERIPROC __glewProgramParameteri = NULL; + +PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC __glewGetCompressedTextureSubImage = NULL; +PFNGLGETTEXTURESUBIMAGEPROC __glewGetTextureSubImage = NULL; + +PFNGLSPECIALIZESHADERARBPROC __glewSpecializeShaderARB = NULL; + +PFNGLGETUNIFORMDVPROC __glewGetUniformdv = NULL; +PFNGLUNIFORM1DPROC __glewUniform1d = NULL; +PFNGLUNIFORM1DVPROC __glewUniform1dv = NULL; +PFNGLUNIFORM2DPROC __glewUniform2d = NULL; +PFNGLUNIFORM2DVPROC __glewUniform2dv = NULL; +PFNGLUNIFORM3DPROC __glewUniform3d = NULL; +PFNGLUNIFORM3DVPROC __glewUniform3dv = NULL; +PFNGLUNIFORM4DPROC __glewUniform4d = NULL; +PFNGLUNIFORM4DVPROC __glewUniform4dv = NULL; +PFNGLUNIFORMMATRIX2DVPROC __glewUniformMatrix2dv = NULL; +PFNGLUNIFORMMATRIX2X3DVPROC __glewUniformMatrix2x3dv = NULL; +PFNGLUNIFORMMATRIX2X4DVPROC __glewUniformMatrix2x4dv = NULL; +PFNGLUNIFORMMATRIX3DVPROC __glewUniformMatrix3dv = NULL; +PFNGLUNIFORMMATRIX3X2DVPROC __glewUniformMatrix3x2dv = NULL; +PFNGLUNIFORMMATRIX3X4DVPROC __glewUniformMatrix3x4dv = NULL; +PFNGLUNIFORMMATRIX4DVPROC __glewUniformMatrix4dv = NULL; +PFNGLUNIFORMMATRIX4X2DVPROC __glewUniformMatrix4x2dv = NULL; +PFNGLUNIFORMMATRIX4X3DVPROC __glewUniformMatrix4x3dv = NULL; + +PFNGLGETUNIFORMI64VARBPROC __glewGetUniformi64vARB = NULL; +PFNGLGETUNIFORMUI64VARBPROC __glewGetUniformui64vARB = NULL; +PFNGLGETNUNIFORMI64VARBPROC __glewGetnUniformi64vARB = NULL; +PFNGLGETNUNIFORMUI64VARBPROC __glewGetnUniformui64vARB = NULL; +PFNGLPROGRAMUNIFORM1I64ARBPROC __glewProgramUniform1i64ARB = NULL; +PFNGLPROGRAMUNIFORM1I64VARBPROC __glewProgramUniform1i64vARB = NULL; +PFNGLPROGRAMUNIFORM1UI64ARBPROC __glewProgramUniform1ui64ARB = NULL; +PFNGLPROGRAMUNIFORM1UI64VARBPROC __glewProgramUniform1ui64vARB = NULL; +PFNGLPROGRAMUNIFORM2I64ARBPROC __glewProgramUniform2i64ARB = NULL; +PFNGLPROGRAMUNIFORM2I64VARBPROC __glewProgramUniform2i64vARB = NULL; +PFNGLPROGRAMUNIFORM2UI64ARBPROC __glewProgramUniform2ui64ARB = NULL; +PFNGLPROGRAMUNIFORM2UI64VARBPROC __glewProgramUniform2ui64vARB = NULL; +PFNGLPROGRAMUNIFORM3I64ARBPROC __glewProgramUniform3i64ARB = NULL; +PFNGLPROGRAMUNIFORM3I64VARBPROC __glewProgramUniform3i64vARB = NULL; +PFNGLPROGRAMUNIFORM3UI64ARBPROC __glewProgramUniform3ui64ARB = NULL; +PFNGLPROGRAMUNIFORM3UI64VARBPROC __glewProgramUniform3ui64vARB = NULL; +PFNGLPROGRAMUNIFORM4I64ARBPROC __glewProgramUniform4i64ARB = NULL; +PFNGLPROGRAMUNIFORM4I64VARBPROC __glewProgramUniform4i64vARB = NULL; +PFNGLPROGRAMUNIFORM4UI64ARBPROC __glewProgramUniform4ui64ARB = NULL; +PFNGLPROGRAMUNIFORM4UI64VARBPROC __glewProgramUniform4ui64vARB = NULL; +PFNGLUNIFORM1I64ARBPROC __glewUniform1i64ARB = NULL; +PFNGLUNIFORM1I64VARBPROC __glewUniform1i64vARB = NULL; +PFNGLUNIFORM1UI64ARBPROC __glewUniform1ui64ARB = NULL; +PFNGLUNIFORM1UI64VARBPROC __glewUniform1ui64vARB = NULL; +PFNGLUNIFORM2I64ARBPROC __glewUniform2i64ARB = NULL; +PFNGLUNIFORM2I64VARBPROC __glewUniform2i64vARB = NULL; +PFNGLUNIFORM2UI64ARBPROC __glewUniform2ui64ARB = NULL; +PFNGLUNIFORM2UI64VARBPROC __glewUniform2ui64vARB = NULL; +PFNGLUNIFORM3I64ARBPROC __glewUniform3i64ARB = NULL; +PFNGLUNIFORM3I64VARBPROC __glewUniform3i64vARB = NULL; +PFNGLUNIFORM3UI64ARBPROC __glewUniform3ui64ARB = NULL; +PFNGLUNIFORM3UI64VARBPROC __glewUniform3ui64vARB = NULL; +PFNGLUNIFORM4I64ARBPROC __glewUniform4i64ARB = NULL; +PFNGLUNIFORM4I64VARBPROC __glewUniform4i64vARB = NULL; +PFNGLUNIFORM4UI64ARBPROC __glewUniform4ui64ARB = NULL; +PFNGLUNIFORM4UI64VARBPROC __glewUniform4ui64vARB = NULL; + +PFNGLCOLORSUBTABLEPROC __glewColorSubTable = NULL; +PFNGLCOLORTABLEPROC __glewColorTable = NULL; +PFNGLCOLORTABLEPARAMETERFVPROC __glewColorTableParameterfv = NULL; +PFNGLCOLORTABLEPARAMETERIVPROC __glewColorTableParameteriv = NULL; +PFNGLCONVOLUTIONFILTER1DPROC __glewConvolutionFilter1D = NULL; +PFNGLCONVOLUTIONFILTER2DPROC __glewConvolutionFilter2D = NULL; +PFNGLCONVOLUTIONPARAMETERFPROC __glewConvolutionParameterf = NULL; +PFNGLCONVOLUTIONPARAMETERFVPROC __glewConvolutionParameterfv = NULL; +PFNGLCONVOLUTIONPARAMETERIPROC __glewConvolutionParameteri = NULL; +PFNGLCONVOLUTIONPARAMETERIVPROC __glewConvolutionParameteriv = NULL; +PFNGLCOPYCOLORSUBTABLEPROC __glewCopyColorSubTable = NULL; +PFNGLCOPYCOLORTABLEPROC __glewCopyColorTable = NULL; +PFNGLCOPYCONVOLUTIONFILTER1DPROC __glewCopyConvolutionFilter1D = NULL; +PFNGLCOPYCONVOLUTIONFILTER2DPROC __glewCopyConvolutionFilter2D = NULL; +PFNGLGETCOLORTABLEPROC __glewGetColorTable = NULL; +PFNGLGETCOLORTABLEPARAMETERFVPROC __glewGetColorTableParameterfv = NULL; +PFNGLGETCOLORTABLEPARAMETERIVPROC __glewGetColorTableParameteriv = NULL; +PFNGLGETCONVOLUTIONFILTERPROC __glewGetConvolutionFilter = NULL; +PFNGLGETCONVOLUTIONPARAMETERFVPROC __glewGetConvolutionParameterfv = NULL; +PFNGLGETCONVOLUTIONPARAMETERIVPROC __glewGetConvolutionParameteriv = NULL; +PFNGLGETHISTOGRAMPROC __glewGetHistogram = NULL; +PFNGLGETHISTOGRAMPARAMETERFVPROC __glewGetHistogramParameterfv = NULL; +PFNGLGETHISTOGRAMPARAMETERIVPROC __glewGetHistogramParameteriv = NULL; +PFNGLGETMINMAXPROC __glewGetMinmax = NULL; +PFNGLGETMINMAXPARAMETERFVPROC __glewGetMinmaxParameterfv = NULL; +PFNGLGETMINMAXPARAMETERIVPROC __glewGetMinmaxParameteriv = NULL; +PFNGLGETSEPARABLEFILTERPROC __glewGetSeparableFilter = NULL; +PFNGLHISTOGRAMPROC __glewHistogram = NULL; +PFNGLMINMAXPROC __glewMinmax = NULL; +PFNGLRESETHISTOGRAMPROC __glewResetHistogram = NULL; +PFNGLRESETMINMAXPROC __glewResetMinmax = NULL; +PFNGLSEPARABLEFILTER2DPROC __glewSeparableFilter2D = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __glewMultiDrawArraysIndirectCountARB = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __glewMultiDrawElementsIndirectCountARB = NULL; + +PFNGLDRAWARRAYSINSTANCEDARBPROC __glewDrawArraysInstancedARB = NULL; +PFNGLDRAWELEMENTSINSTANCEDARBPROC __glewDrawElementsInstancedARB = NULL; +PFNGLVERTEXATTRIBDIVISORARBPROC __glewVertexAttribDivisorARB = NULL; + +PFNGLGETINTERNALFORMATIVPROC __glewGetInternalformativ = NULL; + +PFNGLGETINTERNALFORMATI64VPROC __glewGetInternalformati64v = NULL; + +PFNGLINVALIDATEBUFFERDATAPROC __glewInvalidateBufferData = NULL; +PFNGLINVALIDATEBUFFERSUBDATAPROC __glewInvalidateBufferSubData = NULL; +PFNGLINVALIDATEFRAMEBUFFERPROC __glewInvalidateFramebuffer = NULL; +PFNGLINVALIDATESUBFRAMEBUFFERPROC __glewInvalidateSubFramebuffer = NULL; +PFNGLINVALIDATETEXIMAGEPROC __glewInvalidateTexImage = NULL; +PFNGLINVALIDATETEXSUBIMAGEPROC __glewInvalidateTexSubImage = NULL; + +PFNGLFLUSHMAPPEDBUFFERRANGEPROC __glewFlushMappedBufferRange = NULL; +PFNGLMAPBUFFERRANGEPROC __glewMapBufferRange = NULL; + +PFNGLCURRENTPALETTEMATRIXARBPROC __glewCurrentPaletteMatrixARB = NULL; +PFNGLMATRIXINDEXPOINTERARBPROC __glewMatrixIndexPointerARB = NULL; +PFNGLMATRIXINDEXUBVARBPROC __glewMatrixIndexubvARB = NULL; +PFNGLMATRIXINDEXUIVARBPROC __glewMatrixIndexuivARB = NULL; +PFNGLMATRIXINDEXUSVARBPROC __glewMatrixIndexusvARB = NULL; + +PFNGLBINDBUFFERSBASEPROC __glewBindBuffersBase = NULL; +PFNGLBINDBUFFERSRANGEPROC __glewBindBuffersRange = NULL; +PFNGLBINDIMAGETEXTURESPROC __glewBindImageTextures = NULL; +PFNGLBINDSAMPLERSPROC __glewBindSamplers = NULL; +PFNGLBINDTEXTURESPROC __glewBindTextures = NULL; +PFNGLBINDVERTEXBUFFERSPROC __glewBindVertexBuffers = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTPROC __glewMultiDrawArraysIndirect = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTPROC __glewMultiDrawElementsIndirect = NULL; + +PFNGLSAMPLECOVERAGEARBPROC __glewSampleCoverageARB = NULL; + +PFNGLACTIVETEXTUREARBPROC __glewActiveTextureARB = NULL; +PFNGLCLIENTACTIVETEXTUREARBPROC __glewClientActiveTextureARB = NULL; +PFNGLMULTITEXCOORD1DARBPROC __glewMultiTexCoord1dARB = NULL; +PFNGLMULTITEXCOORD1DVARBPROC __glewMultiTexCoord1dvARB = NULL; +PFNGLMULTITEXCOORD1FARBPROC __glewMultiTexCoord1fARB = NULL; +PFNGLMULTITEXCOORD1FVARBPROC __glewMultiTexCoord1fvARB = NULL; +PFNGLMULTITEXCOORD1IARBPROC __glewMultiTexCoord1iARB = NULL; +PFNGLMULTITEXCOORD1IVARBPROC __glewMultiTexCoord1ivARB = NULL; +PFNGLMULTITEXCOORD1SARBPROC __glewMultiTexCoord1sARB = NULL; +PFNGLMULTITEXCOORD1SVARBPROC __glewMultiTexCoord1svARB = NULL; +PFNGLMULTITEXCOORD2DARBPROC __glewMultiTexCoord2dARB = NULL; +PFNGLMULTITEXCOORD2DVARBPROC __glewMultiTexCoord2dvARB = NULL; +PFNGLMULTITEXCOORD2FARBPROC __glewMultiTexCoord2fARB = NULL; +PFNGLMULTITEXCOORD2FVARBPROC __glewMultiTexCoord2fvARB = NULL; +PFNGLMULTITEXCOORD2IARBPROC __glewMultiTexCoord2iARB = NULL; +PFNGLMULTITEXCOORD2IVARBPROC __glewMultiTexCoord2ivARB = NULL; +PFNGLMULTITEXCOORD2SARBPROC __glewMultiTexCoord2sARB = NULL; +PFNGLMULTITEXCOORD2SVARBPROC __glewMultiTexCoord2svARB = NULL; +PFNGLMULTITEXCOORD3DARBPROC __glewMultiTexCoord3dARB = NULL; +PFNGLMULTITEXCOORD3DVARBPROC __glewMultiTexCoord3dvARB = NULL; +PFNGLMULTITEXCOORD3FARBPROC __glewMultiTexCoord3fARB = NULL; +PFNGLMULTITEXCOORD3FVARBPROC __glewMultiTexCoord3fvARB = NULL; +PFNGLMULTITEXCOORD3IARBPROC __glewMultiTexCoord3iARB = NULL; +PFNGLMULTITEXCOORD3IVARBPROC __glewMultiTexCoord3ivARB = NULL; +PFNGLMULTITEXCOORD3SARBPROC __glewMultiTexCoord3sARB = NULL; +PFNGLMULTITEXCOORD3SVARBPROC __glewMultiTexCoord3svARB = NULL; +PFNGLMULTITEXCOORD4DARBPROC __glewMultiTexCoord4dARB = NULL; +PFNGLMULTITEXCOORD4DVARBPROC __glewMultiTexCoord4dvARB = NULL; +PFNGLMULTITEXCOORD4FARBPROC __glewMultiTexCoord4fARB = NULL; +PFNGLMULTITEXCOORD4FVARBPROC __glewMultiTexCoord4fvARB = NULL; +PFNGLMULTITEXCOORD4IARBPROC __glewMultiTexCoord4iARB = NULL; +PFNGLMULTITEXCOORD4IVARBPROC __glewMultiTexCoord4ivARB = NULL; +PFNGLMULTITEXCOORD4SARBPROC __glewMultiTexCoord4sARB = NULL; +PFNGLMULTITEXCOORD4SVARBPROC __glewMultiTexCoord4svARB = NULL; + +PFNGLBEGINQUERYARBPROC __glewBeginQueryARB = NULL; +PFNGLDELETEQUERIESARBPROC __glewDeleteQueriesARB = NULL; +PFNGLENDQUERYARBPROC __glewEndQueryARB = NULL; +PFNGLGENQUERIESARBPROC __glewGenQueriesARB = NULL; +PFNGLGETQUERYOBJECTIVARBPROC __glewGetQueryObjectivARB = NULL; +PFNGLGETQUERYOBJECTUIVARBPROC __glewGetQueryObjectuivARB = NULL; +PFNGLGETQUERYIVARBPROC __glewGetQueryivARB = NULL; +PFNGLISQUERYARBPROC __glewIsQueryARB = NULL; + +PFNGLMAXSHADERCOMPILERTHREADSARBPROC __glewMaxShaderCompilerThreadsARB = NULL; + +PFNGLPOINTPARAMETERFARBPROC __glewPointParameterfARB = NULL; +PFNGLPOINTPARAMETERFVARBPROC __glewPointParameterfvARB = NULL; + +PFNGLPOLYGONOFFSETCLAMPPROC __glewPolygonOffsetClamp = NULL; + +PFNGLGETPROGRAMINTERFACEIVPROC __glewGetProgramInterfaceiv = NULL; +PFNGLGETPROGRAMRESOURCEINDEXPROC __glewGetProgramResourceIndex = NULL; +PFNGLGETPROGRAMRESOURCELOCATIONPROC __glewGetProgramResourceLocation = NULL; +PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC __glewGetProgramResourceLocationIndex = NULL; +PFNGLGETPROGRAMRESOURCENAMEPROC __glewGetProgramResourceName = NULL; +PFNGLGETPROGRAMRESOURCEIVPROC __glewGetProgramResourceiv = NULL; + +PFNGLPROVOKINGVERTEXPROC __glewProvokingVertex = NULL; + +PFNGLGETGRAPHICSRESETSTATUSARBPROC __glewGetGraphicsResetStatusARB = NULL; +PFNGLGETNCOLORTABLEARBPROC __glewGetnColorTableARB = NULL; +PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC __glewGetnCompressedTexImageARB = NULL; +PFNGLGETNCONVOLUTIONFILTERARBPROC __glewGetnConvolutionFilterARB = NULL; +PFNGLGETNHISTOGRAMARBPROC __glewGetnHistogramARB = NULL; +PFNGLGETNMAPDVARBPROC __glewGetnMapdvARB = NULL; +PFNGLGETNMAPFVARBPROC __glewGetnMapfvARB = NULL; +PFNGLGETNMAPIVARBPROC __glewGetnMapivARB = NULL; +PFNGLGETNMINMAXARBPROC __glewGetnMinmaxARB = NULL; +PFNGLGETNPIXELMAPFVARBPROC __glewGetnPixelMapfvARB = NULL; +PFNGLGETNPIXELMAPUIVARBPROC __glewGetnPixelMapuivARB = NULL; +PFNGLGETNPIXELMAPUSVARBPROC __glewGetnPixelMapusvARB = NULL; +PFNGLGETNPOLYGONSTIPPLEARBPROC __glewGetnPolygonStippleARB = NULL; +PFNGLGETNSEPARABLEFILTERARBPROC __glewGetnSeparableFilterARB = NULL; +PFNGLGETNTEXIMAGEARBPROC __glewGetnTexImageARB = NULL; +PFNGLGETNUNIFORMDVARBPROC __glewGetnUniformdvARB = NULL; +PFNGLGETNUNIFORMFVARBPROC __glewGetnUniformfvARB = NULL; +PFNGLGETNUNIFORMIVARBPROC __glewGetnUniformivARB = NULL; +PFNGLGETNUNIFORMUIVARBPROC __glewGetnUniformuivARB = NULL; +PFNGLREADNPIXELSARBPROC __glewReadnPixelsARB = NULL; + +PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC __glewFramebufferSampleLocationsfvARB = NULL; +PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC __glewNamedFramebufferSampleLocationsfvARB = NULL; + +PFNGLMINSAMPLESHADINGARBPROC __glewMinSampleShadingARB = NULL; + +PFNGLBINDSAMPLERPROC __glewBindSampler = NULL; +PFNGLDELETESAMPLERSPROC __glewDeleteSamplers = NULL; +PFNGLGENSAMPLERSPROC __glewGenSamplers = NULL; +PFNGLGETSAMPLERPARAMETERIIVPROC __glewGetSamplerParameterIiv = NULL; +PFNGLGETSAMPLERPARAMETERIUIVPROC __glewGetSamplerParameterIuiv = NULL; +PFNGLGETSAMPLERPARAMETERFVPROC __glewGetSamplerParameterfv = NULL; +PFNGLGETSAMPLERPARAMETERIVPROC __glewGetSamplerParameteriv = NULL; +PFNGLISSAMPLERPROC __glewIsSampler = NULL; +PFNGLSAMPLERPARAMETERIIVPROC __glewSamplerParameterIiv = NULL; +PFNGLSAMPLERPARAMETERIUIVPROC __glewSamplerParameterIuiv = NULL; +PFNGLSAMPLERPARAMETERFPROC __glewSamplerParameterf = NULL; +PFNGLSAMPLERPARAMETERFVPROC __glewSamplerParameterfv = NULL; +PFNGLSAMPLERPARAMETERIPROC __glewSamplerParameteri = NULL; +PFNGLSAMPLERPARAMETERIVPROC __glewSamplerParameteriv = NULL; + +PFNGLACTIVESHADERPROGRAMPROC __glewActiveShaderProgram = NULL; +PFNGLBINDPROGRAMPIPELINEPROC __glewBindProgramPipeline = NULL; +PFNGLCREATESHADERPROGRAMVPROC __glewCreateShaderProgramv = NULL; +PFNGLDELETEPROGRAMPIPELINESPROC __glewDeleteProgramPipelines = NULL; +PFNGLGENPROGRAMPIPELINESPROC __glewGenProgramPipelines = NULL; +PFNGLGETPROGRAMPIPELINEINFOLOGPROC __glewGetProgramPipelineInfoLog = NULL; +PFNGLGETPROGRAMPIPELINEIVPROC __glewGetProgramPipelineiv = NULL; +PFNGLISPROGRAMPIPELINEPROC __glewIsProgramPipeline = NULL; +PFNGLPROGRAMUNIFORM1DPROC __glewProgramUniform1d = NULL; +PFNGLPROGRAMUNIFORM1DVPROC __glewProgramUniform1dv = NULL; +PFNGLPROGRAMUNIFORM1FPROC __glewProgramUniform1f = NULL; +PFNGLPROGRAMUNIFORM1FVPROC __glewProgramUniform1fv = NULL; +PFNGLPROGRAMUNIFORM1IPROC __glewProgramUniform1i = NULL; +PFNGLPROGRAMUNIFORM1IVPROC __glewProgramUniform1iv = NULL; +PFNGLPROGRAMUNIFORM1UIPROC __glewProgramUniform1ui = NULL; +PFNGLPROGRAMUNIFORM1UIVPROC __glewProgramUniform1uiv = NULL; +PFNGLPROGRAMUNIFORM2DPROC __glewProgramUniform2d = NULL; +PFNGLPROGRAMUNIFORM2DVPROC __glewProgramUniform2dv = NULL; +PFNGLPROGRAMUNIFORM2FPROC __glewProgramUniform2f = NULL; +PFNGLPROGRAMUNIFORM2FVPROC __glewProgramUniform2fv = NULL; +PFNGLPROGRAMUNIFORM2IPROC __glewProgramUniform2i = NULL; +PFNGLPROGRAMUNIFORM2IVPROC __glewProgramUniform2iv = NULL; +PFNGLPROGRAMUNIFORM2UIPROC __glewProgramUniform2ui = NULL; +PFNGLPROGRAMUNIFORM2UIVPROC __glewProgramUniform2uiv = NULL; +PFNGLPROGRAMUNIFORM3DPROC __glewProgramUniform3d = NULL; +PFNGLPROGRAMUNIFORM3DVPROC __glewProgramUniform3dv = NULL; +PFNGLPROGRAMUNIFORM3FPROC __glewProgramUniform3f = NULL; +PFNGLPROGRAMUNIFORM3FVPROC __glewProgramUniform3fv = NULL; +PFNGLPROGRAMUNIFORM3IPROC __glewProgramUniform3i = NULL; +PFNGLPROGRAMUNIFORM3IVPROC __glewProgramUniform3iv = NULL; +PFNGLPROGRAMUNIFORM3UIPROC __glewProgramUniform3ui = NULL; +PFNGLPROGRAMUNIFORM3UIVPROC __glewProgramUniform3uiv = NULL; +PFNGLPROGRAMUNIFORM4DPROC __glewProgramUniform4d = NULL; +PFNGLPROGRAMUNIFORM4DVPROC __glewProgramUniform4dv = NULL; +PFNGLPROGRAMUNIFORM4FPROC __glewProgramUniform4f = NULL; +PFNGLPROGRAMUNIFORM4FVPROC __glewProgramUniform4fv = NULL; +PFNGLPROGRAMUNIFORM4IPROC __glewProgramUniform4i = NULL; +PFNGLPROGRAMUNIFORM4IVPROC __glewProgramUniform4iv = NULL; +PFNGLPROGRAMUNIFORM4UIPROC __glewProgramUniform4ui = NULL; +PFNGLPROGRAMUNIFORM4UIVPROC __glewProgramUniform4uiv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2DVPROC __glewProgramUniformMatrix2dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2FVPROC __glewProgramUniformMatrix2fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC __glewProgramUniformMatrix2x3dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC __glewProgramUniformMatrix2x3fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC __glewProgramUniformMatrix2x4dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC __glewProgramUniformMatrix2x4fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3DVPROC __glewProgramUniformMatrix3dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3FVPROC __glewProgramUniformMatrix3fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC __glewProgramUniformMatrix3x2dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC __glewProgramUniformMatrix3x2fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC __glewProgramUniformMatrix3x4dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC __glewProgramUniformMatrix3x4fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4DVPROC __glewProgramUniformMatrix4dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4FVPROC __glewProgramUniformMatrix4fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC __glewProgramUniformMatrix4x2dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC __glewProgramUniformMatrix4x2fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC __glewProgramUniformMatrix4x3dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC __glewProgramUniformMatrix4x3fv = NULL; +PFNGLUSEPROGRAMSTAGESPROC __glewUseProgramStages = NULL; +PFNGLVALIDATEPROGRAMPIPELINEPROC __glewValidateProgramPipeline = NULL; + +PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __glewGetActiveAtomicCounterBufferiv = NULL; + +PFNGLBINDIMAGETEXTUREPROC __glewBindImageTexture = NULL; +PFNGLMEMORYBARRIERPROC __glewMemoryBarrier = NULL; + +PFNGLATTACHOBJECTARBPROC __glewAttachObjectARB = NULL; +PFNGLCOMPILESHADERARBPROC __glewCompileShaderARB = NULL; +PFNGLCREATEPROGRAMOBJECTARBPROC __glewCreateProgramObjectARB = NULL; +PFNGLCREATESHADEROBJECTARBPROC __glewCreateShaderObjectARB = NULL; +PFNGLDELETEOBJECTARBPROC __glewDeleteObjectARB = NULL; +PFNGLDETACHOBJECTARBPROC __glewDetachObjectARB = NULL; +PFNGLGETACTIVEUNIFORMARBPROC __glewGetActiveUniformARB = NULL; +PFNGLGETATTACHEDOBJECTSARBPROC __glewGetAttachedObjectsARB = NULL; +PFNGLGETHANDLEARBPROC __glewGetHandleARB = NULL; +PFNGLGETINFOLOGARBPROC __glewGetInfoLogARB = NULL; +PFNGLGETOBJECTPARAMETERFVARBPROC __glewGetObjectParameterfvARB = NULL; +PFNGLGETOBJECTPARAMETERIVARBPROC __glewGetObjectParameterivARB = NULL; +PFNGLGETSHADERSOURCEARBPROC __glewGetShaderSourceARB = NULL; +PFNGLGETUNIFORMLOCATIONARBPROC __glewGetUniformLocationARB = NULL; +PFNGLGETUNIFORMFVARBPROC __glewGetUniformfvARB = NULL; +PFNGLGETUNIFORMIVARBPROC __glewGetUniformivARB = NULL; +PFNGLLINKPROGRAMARBPROC __glewLinkProgramARB = NULL; +PFNGLSHADERSOURCEARBPROC __glewShaderSourceARB = NULL; +PFNGLUNIFORM1FARBPROC __glewUniform1fARB = NULL; +PFNGLUNIFORM1FVARBPROC __glewUniform1fvARB = NULL; +PFNGLUNIFORM1IARBPROC __glewUniform1iARB = NULL; +PFNGLUNIFORM1IVARBPROC __glewUniform1ivARB = NULL; +PFNGLUNIFORM2FARBPROC __glewUniform2fARB = NULL; +PFNGLUNIFORM2FVARBPROC __glewUniform2fvARB = NULL; +PFNGLUNIFORM2IARBPROC __glewUniform2iARB = NULL; +PFNGLUNIFORM2IVARBPROC __glewUniform2ivARB = NULL; +PFNGLUNIFORM3FARBPROC __glewUniform3fARB = NULL; +PFNGLUNIFORM3FVARBPROC __glewUniform3fvARB = NULL; +PFNGLUNIFORM3IARBPROC __glewUniform3iARB = NULL; +PFNGLUNIFORM3IVARBPROC __glewUniform3ivARB = NULL; +PFNGLUNIFORM4FARBPROC __glewUniform4fARB = NULL; +PFNGLUNIFORM4FVARBPROC __glewUniform4fvARB = NULL; +PFNGLUNIFORM4IARBPROC __glewUniform4iARB = NULL; +PFNGLUNIFORM4IVARBPROC __glewUniform4ivARB = NULL; +PFNGLUNIFORMMATRIX2FVARBPROC __glewUniformMatrix2fvARB = NULL; +PFNGLUNIFORMMATRIX3FVARBPROC __glewUniformMatrix3fvARB = NULL; +PFNGLUNIFORMMATRIX4FVARBPROC __glewUniformMatrix4fvARB = NULL; +PFNGLUSEPROGRAMOBJECTARBPROC __glewUseProgramObjectARB = NULL; +PFNGLVALIDATEPROGRAMARBPROC __glewValidateProgramARB = NULL; + +PFNGLSHADERSTORAGEBLOCKBINDINGPROC __glewShaderStorageBlockBinding = NULL; + +PFNGLGETACTIVESUBROUTINENAMEPROC __glewGetActiveSubroutineName = NULL; +PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __glewGetActiveSubroutineUniformName = NULL; +PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC __glewGetActiveSubroutineUniformiv = NULL; +PFNGLGETPROGRAMSTAGEIVPROC __glewGetProgramStageiv = NULL; +PFNGLGETSUBROUTINEINDEXPROC __glewGetSubroutineIndex = NULL; +PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC __glewGetSubroutineUniformLocation = NULL; +PFNGLGETUNIFORMSUBROUTINEUIVPROC __glewGetUniformSubroutineuiv = NULL; +PFNGLUNIFORMSUBROUTINESUIVPROC __glewUniformSubroutinesuiv = NULL; + +PFNGLCOMPILESHADERINCLUDEARBPROC __glewCompileShaderIncludeARB = NULL; +PFNGLDELETENAMEDSTRINGARBPROC __glewDeleteNamedStringARB = NULL; +PFNGLGETNAMEDSTRINGARBPROC __glewGetNamedStringARB = NULL; +PFNGLGETNAMEDSTRINGIVARBPROC __glewGetNamedStringivARB = NULL; +PFNGLISNAMEDSTRINGARBPROC __glewIsNamedStringARB = NULL; +PFNGLNAMEDSTRINGARBPROC __glewNamedStringARB = NULL; + +PFNGLBUFFERPAGECOMMITMENTARBPROC __glewBufferPageCommitmentARB = NULL; + +PFNGLTEXPAGECOMMITMENTARBPROC __glewTexPageCommitmentARB = NULL; + +PFNGLCLIENTWAITSYNCPROC __glewClientWaitSync = NULL; +PFNGLDELETESYNCPROC __glewDeleteSync = NULL; +PFNGLFENCESYNCPROC __glewFenceSync = NULL; +PFNGLGETINTEGER64VPROC __glewGetInteger64v = NULL; +PFNGLGETSYNCIVPROC __glewGetSynciv = NULL; +PFNGLISSYNCPROC __glewIsSync = NULL; +PFNGLWAITSYNCPROC __glewWaitSync = NULL; + +PFNGLPATCHPARAMETERFVPROC __glewPatchParameterfv = NULL; +PFNGLPATCHPARAMETERIPROC __glewPatchParameteri = NULL; + +PFNGLTEXTUREBARRIERPROC __glewTextureBarrier = NULL; + +PFNGLTEXBUFFERARBPROC __glewTexBufferARB = NULL; + +PFNGLTEXBUFFERRANGEPROC __glewTexBufferRange = NULL; +PFNGLTEXTUREBUFFERRANGEEXTPROC __glewTextureBufferRangeEXT = NULL; + +PFNGLCOMPRESSEDTEXIMAGE1DARBPROC __glewCompressedTexImage1DARB = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DARBPROC __glewCompressedTexImage2DARB = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DARBPROC __glewCompressedTexImage3DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __glewCompressedTexSubImage1DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __glewCompressedTexSubImage2DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __glewCompressedTexSubImage3DARB = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEARBPROC __glewGetCompressedTexImageARB = NULL; + +PFNGLGETMULTISAMPLEFVPROC __glewGetMultisamplefv = NULL; +PFNGLSAMPLEMASKIPROC __glewSampleMaski = NULL; +PFNGLTEXIMAGE2DMULTISAMPLEPROC __glewTexImage2DMultisample = NULL; +PFNGLTEXIMAGE3DMULTISAMPLEPROC __glewTexImage3DMultisample = NULL; + +PFNGLTEXSTORAGE1DPROC __glewTexStorage1D = NULL; +PFNGLTEXSTORAGE2DPROC __glewTexStorage2D = NULL; +PFNGLTEXSTORAGE3DPROC __glewTexStorage3D = NULL; + +PFNGLTEXSTORAGE2DMULTISAMPLEPROC __glewTexStorage2DMultisample = NULL; +PFNGLTEXSTORAGE3DMULTISAMPLEPROC __glewTexStorage3DMultisample = NULL; +PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC __glewTextureStorage2DMultisampleEXT = NULL; +PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC __glewTextureStorage3DMultisampleEXT = NULL; + +PFNGLTEXTUREVIEWPROC __glewTextureView = NULL; + +PFNGLGETQUERYOBJECTI64VPROC __glewGetQueryObjecti64v = NULL; +PFNGLGETQUERYOBJECTUI64VPROC __glewGetQueryObjectui64v = NULL; +PFNGLQUERYCOUNTERPROC __glewQueryCounter = NULL; + +PFNGLBINDTRANSFORMFEEDBACKPROC __glewBindTransformFeedback = NULL; +PFNGLDELETETRANSFORMFEEDBACKSPROC __glewDeleteTransformFeedbacks = NULL; +PFNGLDRAWTRANSFORMFEEDBACKPROC __glewDrawTransformFeedback = NULL; +PFNGLGENTRANSFORMFEEDBACKSPROC __glewGenTransformFeedbacks = NULL; +PFNGLISTRANSFORMFEEDBACKPROC __glewIsTransformFeedback = NULL; +PFNGLPAUSETRANSFORMFEEDBACKPROC __glewPauseTransformFeedback = NULL; +PFNGLRESUMETRANSFORMFEEDBACKPROC __glewResumeTransformFeedback = NULL; + +PFNGLBEGINQUERYINDEXEDPROC __glewBeginQueryIndexed = NULL; +PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC __glewDrawTransformFeedbackStream = NULL; +PFNGLENDQUERYINDEXEDPROC __glewEndQueryIndexed = NULL; +PFNGLGETQUERYINDEXEDIVPROC __glewGetQueryIndexediv = NULL; + +PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __glewDrawTransformFeedbackInstanced = NULL; +PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __glewDrawTransformFeedbackStreamInstanced = NULL; + +PFNGLLOADTRANSPOSEMATRIXDARBPROC __glewLoadTransposeMatrixdARB = NULL; +PFNGLLOADTRANSPOSEMATRIXFARBPROC __glewLoadTransposeMatrixfARB = NULL; +PFNGLMULTTRANSPOSEMATRIXDARBPROC __glewMultTransposeMatrixdARB = NULL; +PFNGLMULTTRANSPOSEMATRIXFARBPROC __glewMultTransposeMatrixfARB = NULL; + +PFNGLBINDBUFFERBASEPROC __glewBindBufferBase = NULL; +PFNGLBINDBUFFERRANGEPROC __glewBindBufferRange = NULL; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC __glewGetActiveUniformBlockName = NULL; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC __glewGetActiveUniformBlockiv = NULL; +PFNGLGETACTIVEUNIFORMNAMEPROC __glewGetActiveUniformName = NULL; +PFNGLGETACTIVEUNIFORMSIVPROC __glewGetActiveUniformsiv = NULL; +PFNGLGETINTEGERI_VPROC __glewGetIntegeri_v = NULL; +PFNGLGETUNIFORMBLOCKINDEXPROC __glewGetUniformBlockIndex = NULL; +PFNGLGETUNIFORMINDICESPROC __glewGetUniformIndices = NULL; +PFNGLUNIFORMBLOCKBINDINGPROC __glewUniformBlockBinding = NULL; + +PFNGLBINDVERTEXARRAYPROC __glewBindVertexArray = NULL; +PFNGLDELETEVERTEXARRAYSPROC __glewDeleteVertexArrays = NULL; +PFNGLGENVERTEXARRAYSPROC __glewGenVertexArrays = NULL; +PFNGLISVERTEXARRAYPROC __glewIsVertexArray = NULL; + +PFNGLGETVERTEXATTRIBLDVPROC __glewGetVertexAttribLdv = NULL; +PFNGLVERTEXATTRIBL1DPROC __glewVertexAttribL1d = NULL; +PFNGLVERTEXATTRIBL1DVPROC __glewVertexAttribL1dv = NULL; +PFNGLVERTEXATTRIBL2DPROC __glewVertexAttribL2d = NULL; +PFNGLVERTEXATTRIBL2DVPROC __glewVertexAttribL2dv = NULL; +PFNGLVERTEXATTRIBL3DPROC __glewVertexAttribL3d = NULL; +PFNGLVERTEXATTRIBL3DVPROC __glewVertexAttribL3dv = NULL; +PFNGLVERTEXATTRIBL4DPROC __glewVertexAttribL4d = NULL; +PFNGLVERTEXATTRIBL4DVPROC __glewVertexAttribL4dv = NULL; +PFNGLVERTEXATTRIBLPOINTERPROC __glewVertexAttribLPointer = NULL; + +PFNGLBINDVERTEXBUFFERPROC __glewBindVertexBuffer = NULL; +PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC __glewVertexArrayBindVertexBufferEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC __glewVertexArrayVertexAttribBindingEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC __glewVertexArrayVertexAttribFormatEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC __glewVertexArrayVertexAttribIFormatEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC __glewVertexArrayVertexAttribLFormatEXT = NULL; +PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC __glewVertexArrayVertexBindingDivisorEXT = NULL; +PFNGLVERTEXATTRIBBINDINGPROC __glewVertexAttribBinding = NULL; +PFNGLVERTEXATTRIBFORMATPROC __glewVertexAttribFormat = NULL; +PFNGLVERTEXATTRIBIFORMATPROC __glewVertexAttribIFormat = NULL; +PFNGLVERTEXATTRIBLFORMATPROC __glewVertexAttribLFormat = NULL; +PFNGLVERTEXBINDINGDIVISORPROC __glewVertexBindingDivisor = NULL; + +PFNGLVERTEXBLENDARBPROC __glewVertexBlendARB = NULL; +PFNGLWEIGHTPOINTERARBPROC __glewWeightPointerARB = NULL; +PFNGLWEIGHTBVARBPROC __glewWeightbvARB = NULL; +PFNGLWEIGHTDVARBPROC __glewWeightdvARB = NULL; +PFNGLWEIGHTFVARBPROC __glewWeightfvARB = NULL; +PFNGLWEIGHTIVARBPROC __glewWeightivARB = NULL; +PFNGLWEIGHTSVARBPROC __glewWeightsvARB = NULL; +PFNGLWEIGHTUBVARBPROC __glewWeightubvARB = NULL; +PFNGLWEIGHTUIVARBPROC __glewWeightuivARB = NULL; +PFNGLWEIGHTUSVARBPROC __glewWeightusvARB = NULL; + +PFNGLBINDBUFFERARBPROC __glewBindBufferARB = NULL; +PFNGLBUFFERDATAARBPROC __glewBufferDataARB = NULL; +PFNGLBUFFERSUBDATAARBPROC __glewBufferSubDataARB = NULL; +PFNGLDELETEBUFFERSARBPROC __glewDeleteBuffersARB = NULL; +PFNGLGENBUFFERSARBPROC __glewGenBuffersARB = NULL; +PFNGLGETBUFFERPARAMETERIVARBPROC __glewGetBufferParameterivARB = NULL; +PFNGLGETBUFFERPOINTERVARBPROC __glewGetBufferPointervARB = NULL; +PFNGLGETBUFFERSUBDATAARBPROC __glewGetBufferSubDataARB = NULL; +PFNGLISBUFFERARBPROC __glewIsBufferARB = NULL; +PFNGLMAPBUFFERARBPROC __glewMapBufferARB = NULL; +PFNGLUNMAPBUFFERARBPROC __glewUnmapBufferARB = NULL; + +PFNGLBINDPROGRAMARBPROC __glewBindProgramARB = NULL; +PFNGLDELETEPROGRAMSARBPROC __glewDeleteProgramsARB = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYARBPROC __glewDisableVertexAttribArrayARB = NULL; +PFNGLENABLEVERTEXATTRIBARRAYARBPROC __glewEnableVertexAttribArrayARB = NULL; +PFNGLGENPROGRAMSARBPROC __glewGenProgramsARB = NULL; +PFNGLGETPROGRAMENVPARAMETERDVARBPROC __glewGetProgramEnvParameterdvARB = NULL; +PFNGLGETPROGRAMENVPARAMETERFVARBPROC __glewGetProgramEnvParameterfvARB = NULL; +PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC __glewGetProgramLocalParameterdvARB = NULL; +PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC __glewGetProgramLocalParameterfvARB = NULL; +PFNGLGETPROGRAMSTRINGARBPROC __glewGetProgramStringARB = NULL; +PFNGLGETPROGRAMIVARBPROC __glewGetProgramivARB = NULL; +PFNGLGETVERTEXATTRIBPOINTERVARBPROC __glewGetVertexAttribPointervARB = NULL; +PFNGLGETVERTEXATTRIBDVARBPROC __glewGetVertexAttribdvARB = NULL; +PFNGLGETVERTEXATTRIBFVARBPROC __glewGetVertexAttribfvARB = NULL; +PFNGLGETVERTEXATTRIBIVARBPROC __glewGetVertexAttribivARB = NULL; +PFNGLISPROGRAMARBPROC __glewIsProgramARB = NULL; +PFNGLPROGRAMENVPARAMETER4DARBPROC __glewProgramEnvParameter4dARB = NULL; +PFNGLPROGRAMENVPARAMETER4DVARBPROC __glewProgramEnvParameter4dvARB = NULL; +PFNGLPROGRAMENVPARAMETER4FARBPROC __glewProgramEnvParameter4fARB = NULL; +PFNGLPROGRAMENVPARAMETER4FVARBPROC __glewProgramEnvParameter4fvARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4DARBPROC __glewProgramLocalParameter4dARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4DVARBPROC __glewProgramLocalParameter4dvARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4FARBPROC __glewProgramLocalParameter4fARB = NULL; +PFNGLPROGRAMLOCALPARAMETER4FVARBPROC __glewProgramLocalParameter4fvARB = NULL; +PFNGLPROGRAMSTRINGARBPROC __glewProgramStringARB = NULL; +PFNGLVERTEXATTRIB1DARBPROC __glewVertexAttrib1dARB = NULL; +PFNGLVERTEXATTRIB1DVARBPROC __glewVertexAttrib1dvARB = NULL; +PFNGLVERTEXATTRIB1FARBPROC __glewVertexAttrib1fARB = NULL; +PFNGLVERTEXATTRIB1FVARBPROC __glewVertexAttrib1fvARB = NULL; +PFNGLVERTEXATTRIB1SARBPROC __glewVertexAttrib1sARB = NULL; +PFNGLVERTEXATTRIB1SVARBPROC __glewVertexAttrib1svARB = NULL; +PFNGLVERTEXATTRIB2DARBPROC __glewVertexAttrib2dARB = NULL; +PFNGLVERTEXATTRIB2DVARBPROC __glewVertexAttrib2dvARB = NULL; +PFNGLVERTEXATTRIB2FARBPROC __glewVertexAttrib2fARB = NULL; +PFNGLVERTEXATTRIB2FVARBPROC __glewVertexAttrib2fvARB = NULL; +PFNGLVERTEXATTRIB2SARBPROC __glewVertexAttrib2sARB = NULL; +PFNGLVERTEXATTRIB2SVARBPROC __glewVertexAttrib2svARB = NULL; +PFNGLVERTEXATTRIB3DARBPROC __glewVertexAttrib3dARB = NULL; +PFNGLVERTEXATTRIB3DVARBPROC __glewVertexAttrib3dvARB = NULL; +PFNGLVERTEXATTRIB3FARBPROC __glewVertexAttrib3fARB = NULL; +PFNGLVERTEXATTRIB3FVARBPROC __glewVertexAttrib3fvARB = NULL; +PFNGLVERTEXATTRIB3SARBPROC __glewVertexAttrib3sARB = NULL; +PFNGLVERTEXATTRIB3SVARBPROC __glewVertexAttrib3svARB = NULL; +PFNGLVERTEXATTRIB4NBVARBPROC __glewVertexAttrib4NbvARB = NULL; +PFNGLVERTEXATTRIB4NIVARBPROC __glewVertexAttrib4NivARB = NULL; +PFNGLVERTEXATTRIB4NSVARBPROC __glewVertexAttrib4NsvARB = NULL; +PFNGLVERTEXATTRIB4NUBARBPROC __glewVertexAttrib4NubARB = NULL; +PFNGLVERTEXATTRIB4NUBVARBPROC __glewVertexAttrib4NubvARB = NULL; +PFNGLVERTEXATTRIB4NUIVARBPROC __glewVertexAttrib4NuivARB = NULL; +PFNGLVERTEXATTRIB4NUSVARBPROC __glewVertexAttrib4NusvARB = NULL; +PFNGLVERTEXATTRIB4BVARBPROC __glewVertexAttrib4bvARB = NULL; +PFNGLVERTEXATTRIB4DARBPROC __glewVertexAttrib4dARB = NULL; +PFNGLVERTEXATTRIB4DVARBPROC __glewVertexAttrib4dvARB = NULL; +PFNGLVERTEXATTRIB4FARBPROC __glewVertexAttrib4fARB = NULL; +PFNGLVERTEXATTRIB4FVARBPROC __glewVertexAttrib4fvARB = NULL; +PFNGLVERTEXATTRIB4IVARBPROC __glewVertexAttrib4ivARB = NULL; +PFNGLVERTEXATTRIB4SARBPROC __glewVertexAttrib4sARB = NULL; +PFNGLVERTEXATTRIB4SVARBPROC __glewVertexAttrib4svARB = NULL; +PFNGLVERTEXATTRIB4UBVARBPROC __glewVertexAttrib4ubvARB = NULL; +PFNGLVERTEXATTRIB4UIVARBPROC __glewVertexAttrib4uivARB = NULL; +PFNGLVERTEXATTRIB4USVARBPROC __glewVertexAttrib4usvARB = NULL; +PFNGLVERTEXATTRIBPOINTERARBPROC __glewVertexAttribPointerARB = NULL; + +PFNGLBINDATTRIBLOCATIONARBPROC __glewBindAttribLocationARB = NULL; +PFNGLGETACTIVEATTRIBARBPROC __glewGetActiveAttribARB = NULL; +PFNGLGETATTRIBLOCATIONARBPROC __glewGetAttribLocationARB = NULL; + +PFNGLCOLORP3UIPROC __glewColorP3ui = NULL; +PFNGLCOLORP3UIVPROC __glewColorP3uiv = NULL; +PFNGLCOLORP4UIPROC __glewColorP4ui = NULL; +PFNGLCOLORP4UIVPROC __glewColorP4uiv = NULL; +PFNGLMULTITEXCOORDP1UIPROC __glewMultiTexCoordP1ui = NULL; +PFNGLMULTITEXCOORDP1UIVPROC __glewMultiTexCoordP1uiv = NULL; +PFNGLMULTITEXCOORDP2UIPROC __glewMultiTexCoordP2ui = NULL; +PFNGLMULTITEXCOORDP2UIVPROC __glewMultiTexCoordP2uiv = NULL; +PFNGLMULTITEXCOORDP3UIPROC __glewMultiTexCoordP3ui = NULL; +PFNGLMULTITEXCOORDP3UIVPROC __glewMultiTexCoordP3uiv = NULL; +PFNGLMULTITEXCOORDP4UIPROC __glewMultiTexCoordP4ui = NULL; +PFNGLMULTITEXCOORDP4UIVPROC __glewMultiTexCoordP4uiv = NULL; +PFNGLNORMALP3UIPROC __glewNormalP3ui = NULL; +PFNGLNORMALP3UIVPROC __glewNormalP3uiv = NULL; +PFNGLSECONDARYCOLORP3UIPROC __glewSecondaryColorP3ui = NULL; +PFNGLSECONDARYCOLORP3UIVPROC __glewSecondaryColorP3uiv = NULL; +PFNGLTEXCOORDP1UIPROC __glewTexCoordP1ui = NULL; +PFNGLTEXCOORDP1UIVPROC __glewTexCoordP1uiv = NULL; +PFNGLTEXCOORDP2UIPROC __glewTexCoordP2ui = NULL; +PFNGLTEXCOORDP2UIVPROC __glewTexCoordP2uiv = NULL; +PFNGLTEXCOORDP3UIPROC __glewTexCoordP3ui = NULL; +PFNGLTEXCOORDP3UIVPROC __glewTexCoordP3uiv = NULL; +PFNGLTEXCOORDP4UIPROC __glewTexCoordP4ui = NULL; +PFNGLTEXCOORDP4UIVPROC __glewTexCoordP4uiv = NULL; +PFNGLVERTEXATTRIBP1UIPROC __glewVertexAttribP1ui = NULL; +PFNGLVERTEXATTRIBP1UIVPROC __glewVertexAttribP1uiv = NULL; +PFNGLVERTEXATTRIBP2UIPROC __glewVertexAttribP2ui = NULL; +PFNGLVERTEXATTRIBP2UIVPROC __glewVertexAttribP2uiv = NULL; +PFNGLVERTEXATTRIBP3UIPROC __glewVertexAttribP3ui = NULL; +PFNGLVERTEXATTRIBP3UIVPROC __glewVertexAttribP3uiv = NULL; +PFNGLVERTEXATTRIBP4UIPROC __glewVertexAttribP4ui = NULL; +PFNGLVERTEXATTRIBP4UIVPROC __glewVertexAttribP4uiv = NULL; +PFNGLVERTEXP2UIPROC __glewVertexP2ui = NULL; +PFNGLVERTEXP2UIVPROC __glewVertexP2uiv = NULL; +PFNGLVERTEXP3UIPROC __glewVertexP3ui = NULL; +PFNGLVERTEXP3UIVPROC __glewVertexP3uiv = NULL; +PFNGLVERTEXP4UIPROC __glewVertexP4ui = NULL; +PFNGLVERTEXP4UIVPROC __glewVertexP4uiv = NULL; + +PFNGLDEPTHRANGEARRAYVPROC __glewDepthRangeArrayv = NULL; +PFNGLDEPTHRANGEINDEXEDPROC __glewDepthRangeIndexed = NULL; +PFNGLGETDOUBLEI_VPROC __glewGetDoublei_v = NULL; +PFNGLGETFLOATI_VPROC __glewGetFloati_v = NULL; +PFNGLSCISSORARRAYVPROC __glewScissorArrayv = NULL; +PFNGLSCISSORINDEXEDPROC __glewScissorIndexed = NULL; +PFNGLSCISSORINDEXEDVPROC __glewScissorIndexedv = NULL; +PFNGLVIEWPORTARRAYVPROC __glewViewportArrayv = NULL; +PFNGLVIEWPORTINDEXEDFPROC __glewViewportIndexedf = NULL; +PFNGLVIEWPORTINDEXEDFVPROC __glewViewportIndexedfv = NULL; + +PFNGLWINDOWPOS2DARBPROC __glewWindowPos2dARB = NULL; +PFNGLWINDOWPOS2DVARBPROC __glewWindowPos2dvARB = NULL; +PFNGLWINDOWPOS2FARBPROC __glewWindowPos2fARB = NULL; +PFNGLWINDOWPOS2FVARBPROC __glewWindowPos2fvARB = NULL; +PFNGLWINDOWPOS2IARBPROC __glewWindowPos2iARB = NULL; +PFNGLWINDOWPOS2IVARBPROC __glewWindowPos2ivARB = NULL; +PFNGLWINDOWPOS2SARBPROC __glewWindowPos2sARB = NULL; +PFNGLWINDOWPOS2SVARBPROC __glewWindowPos2svARB = NULL; +PFNGLWINDOWPOS3DARBPROC __glewWindowPos3dARB = NULL; +PFNGLWINDOWPOS3DVARBPROC __glewWindowPos3dvARB = NULL; +PFNGLWINDOWPOS3FARBPROC __glewWindowPos3fARB = NULL; +PFNGLWINDOWPOS3FVARBPROC __glewWindowPos3fvARB = NULL; +PFNGLWINDOWPOS3IARBPROC __glewWindowPos3iARB = NULL; +PFNGLWINDOWPOS3IVARBPROC __glewWindowPos3ivARB = NULL; +PFNGLWINDOWPOS3SARBPROC __glewWindowPos3sARB = NULL; +PFNGLWINDOWPOS3SVARBPROC __glewWindowPos3svARB = NULL; + +PFNGLDRAWBUFFERSATIPROC __glewDrawBuffersATI = NULL; + +PFNGLDRAWELEMENTARRAYATIPROC __glewDrawElementArrayATI = NULL; +PFNGLDRAWRANGEELEMENTARRAYATIPROC __glewDrawRangeElementArrayATI = NULL; +PFNGLELEMENTPOINTERATIPROC __glewElementPointerATI = NULL; + +PFNGLGETTEXBUMPPARAMETERFVATIPROC __glewGetTexBumpParameterfvATI = NULL; +PFNGLGETTEXBUMPPARAMETERIVATIPROC __glewGetTexBumpParameterivATI = NULL; +PFNGLTEXBUMPPARAMETERFVATIPROC __glewTexBumpParameterfvATI = NULL; +PFNGLTEXBUMPPARAMETERIVATIPROC __glewTexBumpParameterivATI = NULL; + +PFNGLALPHAFRAGMENTOP1ATIPROC __glewAlphaFragmentOp1ATI = NULL; +PFNGLALPHAFRAGMENTOP2ATIPROC __glewAlphaFragmentOp2ATI = NULL; +PFNGLALPHAFRAGMENTOP3ATIPROC __glewAlphaFragmentOp3ATI = NULL; +PFNGLBEGINFRAGMENTSHADERATIPROC __glewBeginFragmentShaderATI = NULL; +PFNGLBINDFRAGMENTSHADERATIPROC __glewBindFragmentShaderATI = NULL; +PFNGLCOLORFRAGMENTOP1ATIPROC __glewColorFragmentOp1ATI = NULL; +PFNGLCOLORFRAGMENTOP2ATIPROC __glewColorFragmentOp2ATI = NULL; +PFNGLCOLORFRAGMENTOP3ATIPROC __glewColorFragmentOp3ATI = NULL; +PFNGLDELETEFRAGMENTSHADERATIPROC __glewDeleteFragmentShaderATI = NULL; +PFNGLENDFRAGMENTSHADERATIPROC __glewEndFragmentShaderATI = NULL; +PFNGLGENFRAGMENTSHADERSATIPROC __glewGenFragmentShadersATI = NULL; +PFNGLPASSTEXCOORDATIPROC __glewPassTexCoordATI = NULL; +PFNGLSAMPLEMAPATIPROC __glewSampleMapATI = NULL; +PFNGLSETFRAGMENTSHADERCONSTANTATIPROC __glewSetFragmentShaderConstantATI = NULL; + +PFNGLMAPOBJECTBUFFERATIPROC __glewMapObjectBufferATI = NULL; +PFNGLUNMAPOBJECTBUFFERATIPROC __glewUnmapObjectBufferATI = NULL; + +PFNGLPNTRIANGLESFATIPROC __glewPNTrianglesfATI = NULL; +PFNGLPNTRIANGLESIATIPROC __glewPNTrianglesiATI = NULL; + +PFNGLSTENCILFUNCSEPARATEATIPROC __glewStencilFuncSeparateATI = NULL; +PFNGLSTENCILOPSEPARATEATIPROC __glewStencilOpSeparateATI = NULL; + +PFNGLARRAYOBJECTATIPROC __glewArrayObjectATI = NULL; +PFNGLFREEOBJECTBUFFERATIPROC __glewFreeObjectBufferATI = NULL; +PFNGLGETARRAYOBJECTFVATIPROC __glewGetArrayObjectfvATI = NULL; +PFNGLGETARRAYOBJECTIVATIPROC __glewGetArrayObjectivATI = NULL; +PFNGLGETOBJECTBUFFERFVATIPROC __glewGetObjectBufferfvATI = NULL; +PFNGLGETOBJECTBUFFERIVATIPROC __glewGetObjectBufferivATI = NULL; +PFNGLGETVARIANTARRAYOBJECTFVATIPROC __glewGetVariantArrayObjectfvATI = NULL; +PFNGLGETVARIANTARRAYOBJECTIVATIPROC __glewGetVariantArrayObjectivATI = NULL; +PFNGLISOBJECTBUFFERATIPROC __glewIsObjectBufferATI = NULL; +PFNGLNEWOBJECTBUFFERATIPROC __glewNewObjectBufferATI = NULL; +PFNGLUPDATEOBJECTBUFFERATIPROC __glewUpdateObjectBufferATI = NULL; +PFNGLVARIANTARRAYOBJECTATIPROC __glewVariantArrayObjectATI = NULL; + +PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC __glewGetVertexAttribArrayObjectfvATI = NULL; +PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC __glewGetVertexAttribArrayObjectivATI = NULL; +PFNGLVERTEXATTRIBARRAYOBJECTATIPROC __glewVertexAttribArrayObjectATI = NULL; + +PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC __glewClientActiveVertexStreamATI = NULL; +PFNGLNORMALSTREAM3BATIPROC __glewNormalStream3bATI = NULL; +PFNGLNORMALSTREAM3BVATIPROC __glewNormalStream3bvATI = NULL; +PFNGLNORMALSTREAM3DATIPROC __glewNormalStream3dATI = NULL; +PFNGLNORMALSTREAM3DVATIPROC __glewNormalStream3dvATI = NULL; +PFNGLNORMALSTREAM3FATIPROC __glewNormalStream3fATI = NULL; +PFNGLNORMALSTREAM3FVATIPROC __glewNormalStream3fvATI = NULL; +PFNGLNORMALSTREAM3IATIPROC __glewNormalStream3iATI = NULL; +PFNGLNORMALSTREAM3IVATIPROC __glewNormalStream3ivATI = NULL; +PFNGLNORMALSTREAM3SATIPROC __glewNormalStream3sATI = NULL; +PFNGLNORMALSTREAM3SVATIPROC __glewNormalStream3svATI = NULL; +PFNGLVERTEXBLENDENVFATIPROC __glewVertexBlendEnvfATI = NULL; +PFNGLVERTEXBLENDENVIATIPROC __glewVertexBlendEnviATI = NULL; +PFNGLVERTEXSTREAM1DATIPROC __glewVertexStream1dATI = NULL; +PFNGLVERTEXSTREAM1DVATIPROC __glewVertexStream1dvATI = NULL; +PFNGLVERTEXSTREAM1FATIPROC __glewVertexStream1fATI = NULL; +PFNGLVERTEXSTREAM1FVATIPROC __glewVertexStream1fvATI = NULL; +PFNGLVERTEXSTREAM1IATIPROC __glewVertexStream1iATI = NULL; +PFNGLVERTEXSTREAM1IVATIPROC __glewVertexStream1ivATI = NULL; +PFNGLVERTEXSTREAM1SATIPROC __glewVertexStream1sATI = NULL; +PFNGLVERTEXSTREAM1SVATIPROC __glewVertexStream1svATI = NULL; +PFNGLVERTEXSTREAM2DATIPROC __glewVertexStream2dATI = NULL; +PFNGLVERTEXSTREAM2DVATIPROC __glewVertexStream2dvATI = NULL; +PFNGLVERTEXSTREAM2FATIPROC __glewVertexStream2fATI = NULL; +PFNGLVERTEXSTREAM2FVATIPROC __glewVertexStream2fvATI = NULL; +PFNGLVERTEXSTREAM2IATIPROC __glewVertexStream2iATI = NULL; +PFNGLVERTEXSTREAM2IVATIPROC __glewVertexStream2ivATI = NULL; +PFNGLVERTEXSTREAM2SATIPROC __glewVertexStream2sATI = NULL; +PFNGLVERTEXSTREAM2SVATIPROC __glewVertexStream2svATI = NULL; +PFNGLVERTEXSTREAM3DATIPROC __glewVertexStream3dATI = NULL; +PFNGLVERTEXSTREAM3DVATIPROC __glewVertexStream3dvATI = NULL; +PFNGLVERTEXSTREAM3FATIPROC __glewVertexStream3fATI = NULL; +PFNGLVERTEXSTREAM3FVATIPROC __glewVertexStream3fvATI = NULL; +PFNGLVERTEXSTREAM3IATIPROC __glewVertexStream3iATI = NULL; +PFNGLVERTEXSTREAM3IVATIPROC __glewVertexStream3ivATI = NULL; +PFNGLVERTEXSTREAM3SATIPROC __glewVertexStream3sATI = NULL; +PFNGLVERTEXSTREAM3SVATIPROC __glewVertexStream3svATI = NULL; +PFNGLVERTEXSTREAM4DATIPROC __glewVertexStream4dATI = NULL; +PFNGLVERTEXSTREAM4DVATIPROC __glewVertexStream4dvATI = NULL; +PFNGLVERTEXSTREAM4FATIPROC __glewVertexStream4fATI = NULL; +PFNGLVERTEXSTREAM4FVATIPROC __glewVertexStream4fvATI = NULL; +PFNGLVERTEXSTREAM4IATIPROC __glewVertexStream4iATI = NULL; +PFNGLVERTEXSTREAM4IVATIPROC __glewVertexStream4ivATI = NULL; +PFNGLVERTEXSTREAM4SATIPROC __glewVertexStream4sATI = NULL; +PFNGLVERTEXSTREAM4SVATIPROC __glewVertexStream4svATI = NULL; + +PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __glewDrawArraysInstancedBaseInstanceEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __glewDrawElementsInstancedBaseInstanceEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __glewDrawElementsInstancedBaseVertexBaseInstanceEXT = NULL; + +PFNGLGETUNIFORMBUFFERSIZEEXTPROC __glewGetUniformBufferSizeEXT = NULL; +PFNGLGETUNIFORMOFFSETEXTPROC __glewGetUniformOffsetEXT = NULL; +PFNGLUNIFORMBUFFEREXTPROC __glewUniformBufferEXT = NULL; + +PFNGLBLENDCOLOREXTPROC __glewBlendColorEXT = NULL; + +PFNGLBLENDEQUATIONSEPARATEEXTPROC __glewBlendEquationSeparateEXT = NULL; + +PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __glewBindFragDataLocationIndexedEXT = NULL; +PFNGLGETFRAGDATAINDEXEXTPROC __glewGetFragDataIndexEXT = NULL; +PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __glewGetProgramResourceLocationIndexEXT = NULL; + +PFNGLBLENDFUNCSEPARATEEXTPROC __glewBlendFuncSeparateEXT = NULL; + +PFNGLBLENDEQUATIONEXTPROC __glewBlendEquationEXT = NULL; + +PFNGLBUFFERSTORAGEEXTPROC __glewBufferStorageEXT = NULL; +PFNGLNAMEDBUFFERSTORAGEEXTPROC __glewNamedBufferStorageEXT = NULL; + +PFNGLCLEARTEXIMAGEEXTPROC __glewClearTexImageEXT = NULL; +PFNGLCLEARTEXSUBIMAGEEXTPROC __glewClearTexSubImageEXT = NULL; + +PFNGLCOLORSUBTABLEEXTPROC __glewColorSubTableEXT = NULL; +PFNGLCOPYCOLORSUBTABLEEXTPROC __glewCopyColorSubTableEXT = NULL; + +PFNGLLOCKARRAYSEXTPROC __glewLockArraysEXT = NULL; +PFNGLUNLOCKARRAYSEXTPROC __glewUnlockArraysEXT = NULL; + +PFNGLCONVOLUTIONFILTER1DEXTPROC __glewConvolutionFilter1DEXT = NULL; +PFNGLCONVOLUTIONFILTER2DEXTPROC __glewConvolutionFilter2DEXT = NULL; +PFNGLCONVOLUTIONPARAMETERFEXTPROC __glewConvolutionParameterfEXT = NULL; +PFNGLCONVOLUTIONPARAMETERFVEXTPROC __glewConvolutionParameterfvEXT = NULL; +PFNGLCONVOLUTIONPARAMETERIEXTPROC __glewConvolutionParameteriEXT = NULL; +PFNGLCONVOLUTIONPARAMETERIVEXTPROC __glewConvolutionParameterivEXT = NULL; +PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC __glewCopyConvolutionFilter1DEXT = NULL; +PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC __glewCopyConvolutionFilter2DEXT = NULL; +PFNGLGETCONVOLUTIONFILTEREXTPROC __glewGetConvolutionFilterEXT = NULL; +PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC __glewGetConvolutionParameterfvEXT = NULL; +PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC __glewGetConvolutionParameterivEXT = NULL; +PFNGLGETSEPARABLEFILTEREXTPROC __glewGetSeparableFilterEXT = NULL; +PFNGLSEPARABLEFILTER2DEXTPROC __glewSeparableFilter2DEXT = NULL; + +PFNGLBINORMALPOINTEREXTPROC __glewBinormalPointerEXT = NULL; +PFNGLTANGENTPOINTEREXTPROC __glewTangentPointerEXT = NULL; + +PFNGLCOPYIMAGESUBDATAEXTPROC __glewCopyImageSubDataEXT = NULL; + +PFNGLCOPYTEXIMAGE1DEXTPROC __glewCopyTexImage1DEXT = NULL; +PFNGLCOPYTEXIMAGE2DEXTPROC __glewCopyTexImage2DEXT = NULL; +PFNGLCOPYTEXSUBIMAGE1DEXTPROC __glewCopyTexSubImage1DEXT = NULL; +PFNGLCOPYTEXSUBIMAGE2DEXTPROC __glewCopyTexSubImage2DEXT = NULL; +PFNGLCOPYTEXSUBIMAGE3DEXTPROC __glewCopyTexSubImage3DEXT = NULL; + +PFNGLCULLPARAMETERDVEXTPROC __glewCullParameterdvEXT = NULL; +PFNGLCULLPARAMETERFVEXTPROC __glewCullParameterfvEXT = NULL; + +PFNGLGETOBJECTLABELEXTPROC __glewGetObjectLabelEXT = NULL; +PFNGLLABELOBJECTEXTPROC __glewLabelObjectEXT = NULL; + +PFNGLINSERTEVENTMARKEREXTPROC __glewInsertEventMarkerEXT = NULL; +PFNGLPOPGROUPMARKEREXTPROC __glewPopGroupMarkerEXT = NULL; +PFNGLPUSHGROUPMARKEREXTPROC __glewPushGroupMarkerEXT = NULL; + +PFNGLDEPTHBOUNDSEXTPROC __glewDepthBoundsEXT = NULL; + +PFNGLBINDMULTITEXTUREEXTPROC __glewBindMultiTextureEXT = NULL; +PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC __glewCheckNamedFramebufferStatusEXT = NULL; +PFNGLCLIENTATTRIBDEFAULTEXTPROC __glewClientAttribDefaultEXT = NULL; +PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC __glewCompressedMultiTexImage1DEXT = NULL; +PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC __glewCompressedMultiTexImage2DEXT = NULL; +PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC __glewCompressedMultiTexImage3DEXT = NULL; +PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC __glewCompressedMultiTexSubImage1DEXT = NULL; +PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC __glewCompressedMultiTexSubImage2DEXT = NULL; +PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC __glewCompressedMultiTexSubImage3DEXT = NULL; +PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC __glewCompressedTextureImage1DEXT = NULL; +PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC __glewCompressedTextureImage2DEXT = NULL; +PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC __glewCompressedTextureImage3DEXT = NULL; +PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC __glewCompressedTextureSubImage1DEXT = NULL; +PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC __glewCompressedTextureSubImage2DEXT = NULL; +PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC __glewCompressedTextureSubImage3DEXT = NULL; +PFNGLCOPYMULTITEXIMAGE1DEXTPROC __glewCopyMultiTexImage1DEXT = NULL; +PFNGLCOPYMULTITEXIMAGE2DEXTPROC __glewCopyMultiTexImage2DEXT = NULL; +PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC __glewCopyMultiTexSubImage1DEXT = NULL; +PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC __glewCopyMultiTexSubImage2DEXT = NULL; +PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC __glewCopyMultiTexSubImage3DEXT = NULL; +PFNGLCOPYTEXTUREIMAGE1DEXTPROC __glewCopyTextureImage1DEXT = NULL; +PFNGLCOPYTEXTUREIMAGE2DEXTPROC __glewCopyTextureImage2DEXT = NULL; +PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC __glewCopyTextureSubImage1DEXT = NULL; +PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC __glewCopyTextureSubImage2DEXT = NULL; +PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC __glewCopyTextureSubImage3DEXT = NULL; +PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC __glewDisableClientStateIndexedEXT = NULL; +PFNGLDISABLECLIENTSTATEIEXTPROC __glewDisableClientStateiEXT = NULL; +PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC __glewDisableVertexArrayAttribEXT = NULL; +PFNGLDISABLEVERTEXARRAYEXTPROC __glewDisableVertexArrayEXT = NULL; +PFNGLENABLECLIENTSTATEINDEXEDEXTPROC __glewEnableClientStateIndexedEXT = NULL; +PFNGLENABLECLIENTSTATEIEXTPROC __glewEnableClientStateiEXT = NULL; +PFNGLENABLEVERTEXARRAYATTRIBEXTPROC __glewEnableVertexArrayAttribEXT = NULL; +PFNGLENABLEVERTEXARRAYEXTPROC __glewEnableVertexArrayEXT = NULL; +PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC __glewFlushMappedNamedBufferRangeEXT = NULL; +PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC __glewFramebufferDrawBufferEXT = NULL; +PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC __glewFramebufferDrawBuffersEXT = NULL; +PFNGLFRAMEBUFFERREADBUFFEREXTPROC __glewFramebufferReadBufferEXT = NULL; +PFNGLGENERATEMULTITEXMIPMAPEXTPROC __glewGenerateMultiTexMipmapEXT = NULL; +PFNGLGENERATETEXTUREMIPMAPEXTPROC __glewGenerateTextureMipmapEXT = NULL; +PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC __glewGetCompressedMultiTexImageEXT = NULL; +PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC __glewGetCompressedTextureImageEXT = NULL; +PFNGLGETDOUBLEINDEXEDVEXTPROC __glewGetDoubleIndexedvEXT = NULL; +PFNGLGETDOUBLEI_VEXTPROC __glewGetDoublei_vEXT = NULL; +PFNGLGETFLOATINDEXEDVEXTPROC __glewGetFloatIndexedvEXT = NULL; +PFNGLGETFLOATI_VEXTPROC __glewGetFloati_vEXT = NULL; +PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC __glewGetFramebufferParameterivEXT = NULL; +PFNGLGETMULTITEXENVFVEXTPROC __glewGetMultiTexEnvfvEXT = NULL; +PFNGLGETMULTITEXENVIVEXTPROC __glewGetMultiTexEnvivEXT = NULL; +PFNGLGETMULTITEXGENDVEXTPROC __glewGetMultiTexGendvEXT = NULL; +PFNGLGETMULTITEXGENFVEXTPROC __glewGetMultiTexGenfvEXT = NULL; +PFNGLGETMULTITEXGENIVEXTPROC __glewGetMultiTexGenivEXT = NULL; +PFNGLGETMULTITEXIMAGEEXTPROC __glewGetMultiTexImageEXT = NULL; +PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC __glewGetMultiTexLevelParameterfvEXT = NULL; +PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC __glewGetMultiTexLevelParameterivEXT = NULL; +PFNGLGETMULTITEXPARAMETERIIVEXTPROC __glewGetMultiTexParameterIivEXT = NULL; +PFNGLGETMULTITEXPARAMETERIUIVEXTPROC __glewGetMultiTexParameterIuivEXT = NULL; +PFNGLGETMULTITEXPARAMETERFVEXTPROC __glewGetMultiTexParameterfvEXT = NULL; +PFNGLGETMULTITEXPARAMETERIVEXTPROC __glewGetMultiTexParameterivEXT = NULL; +PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC __glewGetNamedBufferParameterivEXT = NULL; +PFNGLGETNAMEDBUFFERPOINTERVEXTPROC __glewGetNamedBufferPointervEXT = NULL; +PFNGLGETNAMEDBUFFERSUBDATAEXTPROC __glewGetNamedBufferSubDataEXT = NULL; +PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC __glewGetNamedFramebufferAttachmentParameterivEXT = NULL; +PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC __glewGetNamedProgramLocalParameterIivEXT = NULL; +PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC __glewGetNamedProgramLocalParameterIuivEXT = NULL; +PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC __glewGetNamedProgramLocalParameterdvEXT = NULL; +PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC __glewGetNamedProgramLocalParameterfvEXT = NULL; +PFNGLGETNAMEDPROGRAMSTRINGEXTPROC __glewGetNamedProgramStringEXT = NULL; +PFNGLGETNAMEDPROGRAMIVEXTPROC __glewGetNamedProgramivEXT = NULL; +PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC __glewGetNamedRenderbufferParameterivEXT = NULL; +PFNGLGETPOINTERINDEXEDVEXTPROC __glewGetPointerIndexedvEXT = NULL; +PFNGLGETPOINTERI_VEXTPROC __glewGetPointeri_vEXT = NULL; +PFNGLGETTEXTUREIMAGEEXTPROC __glewGetTextureImageEXT = NULL; +PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC __glewGetTextureLevelParameterfvEXT = NULL; +PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC __glewGetTextureLevelParameterivEXT = NULL; +PFNGLGETTEXTUREPARAMETERIIVEXTPROC __glewGetTextureParameterIivEXT = NULL; +PFNGLGETTEXTUREPARAMETERIUIVEXTPROC __glewGetTextureParameterIuivEXT = NULL; +PFNGLGETTEXTUREPARAMETERFVEXTPROC __glewGetTextureParameterfvEXT = NULL; +PFNGLGETTEXTUREPARAMETERIVEXTPROC __glewGetTextureParameterivEXT = NULL; +PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC __glewGetVertexArrayIntegeri_vEXT = NULL; +PFNGLGETVERTEXARRAYINTEGERVEXTPROC __glewGetVertexArrayIntegervEXT = NULL; +PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC __glewGetVertexArrayPointeri_vEXT = NULL; +PFNGLGETVERTEXARRAYPOINTERVEXTPROC __glewGetVertexArrayPointervEXT = NULL; +PFNGLMAPNAMEDBUFFEREXTPROC __glewMapNamedBufferEXT = NULL; +PFNGLMAPNAMEDBUFFERRANGEEXTPROC __glewMapNamedBufferRangeEXT = NULL; +PFNGLMATRIXFRUSTUMEXTPROC __glewMatrixFrustumEXT = NULL; +PFNGLMATRIXLOADIDENTITYEXTPROC __glewMatrixLoadIdentityEXT = NULL; +PFNGLMATRIXLOADTRANSPOSEDEXTPROC __glewMatrixLoadTransposedEXT = NULL; +PFNGLMATRIXLOADTRANSPOSEFEXTPROC __glewMatrixLoadTransposefEXT = NULL; +PFNGLMATRIXLOADDEXTPROC __glewMatrixLoaddEXT = NULL; +PFNGLMATRIXLOADFEXTPROC __glewMatrixLoadfEXT = NULL; +PFNGLMATRIXMULTTRANSPOSEDEXTPROC __glewMatrixMultTransposedEXT = NULL; +PFNGLMATRIXMULTTRANSPOSEFEXTPROC __glewMatrixMultTransposefEXT = NULL; +PFNGLMATRIXMULTDEXTPROC __glewMatrixMultdEXT = NULL; +PFNGLMATRIXMULTFEXTPROC __glewMatrixMultfEXT = NULL; +PFNGLMATRIXORTHOEXTPROC __glewMatrixOrthoEXT = NULL; +PFNGLMATRIXPOPEXTPROC __glewMatrixPopEXT = NULL; +PFNGLMATRIXPUSHEXTPROC __glewMatrixPushEXT = NULL; +PFNGLMATRIXROTATEDEXTPROC __glewMatrixRotatedEXT = NULL; +PFNGLMATRIXROTATEFEXTPROC __glewMatrixRotatefEXT = NULL; +PFNGLMATRIXSCALEDEXTPROC __glewMatrixScaledEXT = NULL; +PFNGLMATRIXSCALEFEXTPROC __glewMatrixScalefEXT = NULL; +PFNGLMATRIXTRANSLATEDEXTPROC __glewMatrixTranslatedEXT = NULL; +PFNGLMATRIXTRANSLATEFEXTPROC __glewMatrixTranslatefEXT = NULL; +PFNGLMULTITEXBUFFEREXTPROC __glewMultiTexBufferEXT = NULL; +PFNGLMULTITEXCOORDPOINTEREXTPROC __glewMultiTexCoordPointerEXT = NULL; +PFNGLMULTITEXENVFEXTPROC __glewMultiTexEnvfEXT = NULL; +PFNGLMULTITEXENVFVEXTPROC __glewMultiTexEnvfvEXT = NULL; +PFNGLMULTITEXENVIEXTPROC __glewMultiTexEnviEXT = NULL; +PFNGLMULTITEXENVIVEXTPROC __glewMultiTexEnvivEXT = NULL; +PFNGLMULTITEXGENDEXTPROC __glewMultiTexGendEXT = NULL; +PFNGLMULTITEXGENDVEXTPROC __glewMultiTexGendvEXT = NULL; +PFNGLMULTITEXGENFEXTPROC __glewMultiTexGenfEXT = NULL; +PFNGLMULTITEXGENFVEXTPROC __glewMultiTexGenfvEXT = NULL; +PFNGLMULTITEXGENIEXTPROC __glewMultiTexGeniEXT = NULL; +PFNGLMULTITEXGENIVEXTPROC __glewMultiTexGenivEXT = NULL; +PFNGLMULTITEXIMAGE1DEXTPROC __glewMultiTexImage1DEXT = NULL; +PFNGLMULTITEXIMAGE2DEXTPROC __glewMultiTexImage2DEXT = NULL; +PFNGLMULTITEXIMAGE3DEXTPROC __glewMultiTexImage3DEXT = NULL; +PFNGLMULTITEXPARAMETERIIVEXTPROC __glewMultiTexParameterIivEXT = NULL; +PFNGLMULTITEXPARAMETERIUIVEXTPROC __glewMultiTexParameterIuivEXT = NULL; +PFNGLMULTITEXPARAMETERFEXTPROC __glewMultiTexParameterfEXT = NULL; +PFNGLMULTITEXPARAMETERFVEXTPROC __glewMultiTexParameterfvEXT = NULL; +PFNGLMULTITEXPARAMETERIEXTPROC __glewMultiTexParameteriEXT = NULL; +PFNGLMULTITEXPARAMETERIVEXTPROC __glewMultiTexParameterivEXT = NULL; +PFNGLMULTITEXRENDERBUFFEREXTPROC __glewMultiTexRenderbufferEXT = NULL; +PFNGLMULTITEXSUBIMAGE1DEXTPROC __glewMultiTexSubImage1DEXT = NULL; +PFNGLMULTITEXSUBIMAGE2DEXTPROC __glewMultiTexSubImage2DEXT = NULL; +PFNGLMULTITEXSUBIMAGE3DEXTPROC __glewMultiTexSubImage3DEXT = NULL; +PFNGLNAMEDBUFFERDATAEXTPROC __glewNamedBufferDataEXT = NULL; +PFNGLNAMEDBUFFERSUBDATAEXTPROC __glewNamedBufferSubDataEXT = NULL; +PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC __glewNamedCopyBufferSubDataEXT = NULL; +PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC __glewNamedFramebufferRenderbufferEXT = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC __glewNamedFramebufferTexture1DEXT = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC __glewNamedFramebufferTexture2DEXT = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC __glewNamedFramebufferTexture3DEXT = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC __glewNamedFramebufferTextureEXT = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC __glewNamedFramebufferTextureFaceEXT = NULL; +PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC __glewNamedFramebufferTextureLayerEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC __glewNamedProgramLocalParameter4dEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC __glewNamedProgramLocalParameter4dvEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC __glewNamedProgramLocalParameter4fEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC __glewNamedProgramLocalParameter4fvEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC __glewNamedProgramLocalParameterI4iEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC __glewNamedProgramLocalParameterI4ivEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC __glewNamedProgramLocalParameterI4uiEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC __glewNamedProgramLocalParameterI4uivEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC __glewNamedProgramLocalParameters4fvEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC __glewNamedProgramLocalParametersI4ivEXT = NULL; +PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC __glewNamedProgramLocalParametersI4uivEXT = NULL; +PFNGLNAMEDPROGRAMSTRINGEXTPROC __glewNamedProgramStringEXT = NULL; +PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC __glewNamedRenderbufferStorageEXT = NULL; +PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC __glewNamedRenderbufferStorageMultisampleCoverageEXT = NULL; +PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __glewNamedRenderbufferStorageMultisampleEXT = NULL; +PFNGLPROGRAMUNIFORM1FEXTPROC __glewProgramUniform1fEXT = NULL; +PFNGLPROGRAMUNIFORM1FVEXTPROC __glewProgramUniform1fvEXT = NULL; +PFNGLPROGRAMUNIFORM1IEXTPROC __glewProgramUniform1iEXT = NULL; +PFNGLPROGRAMUNIFORM1IVEXTPROC __glewProgramUniform1ivEXT = NULL; +PFNGLPROGRAMUNIFORM1UIEXTPROC __glewProgramUniform1uiEXT = NULL; +PFNGLPROGRAMUNIFORM1UIVEXTPROC __glewProgramUniform1uivEXT = NULL; +PFNGLPROGRAMUNIFORM2FEXTPROC __glewProgramUniform2fEXT = NULL; +PFNGLPROGRAMUNIFORM2FVEXTPROC __glewProgramUniform2fvEXT = NULL; +PFNGLPROGRAMUNIFORM2IEXTPROC __glewProgramUniform2iEXT = NULL; +PFNGLPROGRAMUNIFORM2IVEXTPROC __glewProgramUniform2ivEXT = NULL; +PFNGLPROGRAMUNIFORM2UIEXTPROC __glewProgramUniform2uiEXT = NULL; +PFNGLPROGRAMUNIFORM2UIVEXTPROC __glewProgramUniform2uivEXT = NULL; +PFNGLPROGRAMUNIFORM3FEXTPROC __glewProgramUniform3fEXT = NULL; +PFNGLPROGRAMUNIFORM3FVEXTPROC __glewProgramUniform3fvEXT = NULL; +PFNGLPROGRAMUNIFORM3IEXTPROC __glewProgramUniform3iEXT = NULL; +PFNGLPROGRAMUNIFORM3IVEXTPROC __glewProgramUniform3ivEXT = NULL; +PFNGLPROGRAMUNIFORM3UIEXTPROC __glewProgramUniform3uiEXT = NULL; +PFNGLPROGRAMUNIFORM3UIVEXTPROC __glewProgramUniform3uivEXT = NULL; +PFNGLPROGRAMUNIFORM4FEXTPROC __glewProgramUniform4fEXT = NULL; +PFNGLPROGRAMUNIFORM4FVEXTPROC __glewProgramUniform4fvEXT = NULL; +PFNGLPROGRAMUNIFORM4IEXTPROC __glewProgramUniform4iEXT = NULL; +PFNGLPROGRAMUNIFORM4IVEXTPROC __glewProgramUniform4ivEXT = NULL; +PFNGLPROGRAMUNIFORM4UIEXTPROC __glewProgramUniform4uiEXT = NULL; +PFNGLPROGRAMUNIFORM4UIVEXTPROC __glewProgramUniform4uivEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC __glewProgramUniformMatrix2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __glewProgramUniformMatrix2x3fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __glewProgramUniformMatrix2x4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC __glewProgramUniformMatrix3fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __glewProgramUniformMatrix3x2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __glewProgramUniformMatrix3x4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC __glewProgramUniformMatrix4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __glewProgramUniformMatrix4x2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __glewProgramUniformMatrix4x3fvEXT = NULL; +PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC __glewPushClientAttribDefaultEXT = NULL; +PFNGLTEXTUREBUFFEREXTPROC __glewTextureBufferEXT = NULL; +PFNGLTEXTUREIMAGE1DEXTPROC __glewTextureImage1DEXT = NULL; +PFNGLTEXTUREIMAGE2DEXTPROC __glewTextureImage2DEXT = NULL; +PFNGLTEXTUREIMAGE3DEXTPROC __glewTextureImage3DEXT = NULL; +PFNGLTEXTUREPARAMETERIIVEXTPROC __glewTextureParameterIivEXT = NULL; +PFNGLTEXTUREPARAMETERIUIVEXTPROC __glewTextureParameterIuivEXT = NULL; +PFNGLTEXTUREPARAMETERFEXTPROC __glewTextureParameterfEXT = NULL; +PFNGLTEXTUREPARAMETERFVEXTPROC __glewTextureParameterfvEXT = NULL; +PFNGLTEXTUREPARAMETERIEXTPROC __glewTextureParameteriEXT = NULL; +PFNGLTEXTUREPARAMETERIVEXTPROC __glewTextureParameterivEXT = NULL; +PFNGLTEXTURERENDERBUFFEREXTPROC __glewTextureRenderbufferEXT = NULL; +PFNGLTEXTURESUBIMAGE1DEXTPROC __glewTextureSubImage1DEXT = NULL; +PFNGLTEXTURESUBIMAGE2DEXTPROC __glewTextureSubImage2DEXT = NULL; +PFNGLTEXTURESUBIMAGE3DEXTPROC __glewTextureSubImage3DEXT = NULL; +PFNGLUNMAPNAMEDBUFFEREXTPROC __glewUnmapNamedBufferEXT = NULL; +PFNGLVERTEXARRAYCOLOROFFSETEXTPROC __glewVertexArrayColorOffsetEXT = NULL; +PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC __glewVertexArrayEdgeFlagOffsetEXT = NULL; +PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC __glewVertexArrayFogCoordOffsetEXT = NULL; +PFNGLVERTEXARRAYINDEXOFFSETEXTPROC __glewVertexArrayIndexOffsetEXT = NULL; +PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC __glewVertexArrayMultiTexCoordOffsetEXT = NULL; +PFNGLVERTEXARRAYNORMALOFFSETEXTPROC __glewVertexArrayNormalOffsetEXT = NULL; +PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC __glewVertexArraySecondaryColorOffsetEXT = NULL; +PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC __glewVertexArrayTexCoordOffsetEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC __glewVertexArrayVertexAttribDivisorEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC __glewVertexArrayVertexAttribIOffsetEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC __glewVertexArrayVertexAttribOffsetEXT = NULL; +PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC __glewVertexArrayVertexOffsetEXT = NULL; + +PFNGLDISCARDFRAMEBUFFEREXTPROC __glewDiscardFramebufferEXT = NULL; + +PFNGLDRAWBUFFERSEXTPROC __glewDrawBuffersEXT = NULL; + +PFNGLCOLORMASKINDEXEDEXTPROC __glewColorMaskIndexedEXT = NULL; +PFNGLDISABLEINDEXEDEXTPROC __glewDisableIndexedEXT = NULL; +PFNGLENABLEINDEXEDEXTPROC __glewEnableIndexedEXT = NULL; +PFNGLGETBOOLEANINDEXEDVEXTPROC __glewGetBooleanIndexedvEXT = NULL; +PFNGLGETINTEGERINDEXEDVEXTPROC __glewGetIntegerIndexedvEXT = NULL; +PFNGLISENABLEDINDEXEDEXTPROC __glewIsEnabledIndexedEXT = NULL; + +PFNGLBLENDEQUATIONSEPARATEIEXTPROC __glewBlendEquationSeparateiEXT = NULL; +PFNGLBLENDEQUATIONIEXTPROC __glewBlendEquationiEXT = NULL; +PFNGLBLENDFUNCSEPARATEIEXTPROC __glewBlendFuncSeparateiEXT = NULL; +PFNGLBLENDFUNCIEXTPROC __glewBlendFunciEXT = NULL; +PFNGLCOLORMASKIEXTPROC __glewColorMaskiEXT = NULL; +PFNGLDISABLEIEXTPROC __glewDisableiEXT = NULL; +PFNGLENABLEIEXTPROC __glewEnableiEXT = NULL; +PFNGLISENABLEDIEXTPROC __glewIsEnablediEXT = NULL; + +PFNGLDRAWELEMENTSBASEVERTEXEXTPROC __glewDrawElementsBaseVertexEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __glewDrawElementsInstancedBaseVertexEXT = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __glewDrawRangeElementsBaseVertexEXT = NULL; +PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __glewMultiDrawElementsBaseVertexEXT = NULL; + +PFNGLDRAWARRAYSINSTANCEDEXTPROC __glewDrawArraysInstancedEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDEXTPROC __glewDrawElementsInstancedEXT = NULL; + +PFNGLDRAWRANGEELEMENTSEXTPROC __glewDrawRangeElementsEXT = NULL; + +PFNGLBUFFERSTORAGEEXTERNALEXTPROC __glewBufferStorageExternalEXT = NULL; +PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC __glewNamedBufferStorageExternalEXT = NULL; + +PFNGLFOGCOORDPOINTEREXTPROC __glewFogCoordPointerEXT = NULL; +PFNGLFOGCOORDDEXTPROC __glewFogCoorddEXT = NULL; +PFNGLFOGCOORDDVEXTPROC __glewFogCoorddvEXT = NULL; +PFNGLFOGCOORDFEXTPROC __glewFogCoordfEXT = NULL; +PFNGLFOGCOORDFVEXTPROC __glewFogCoordfvEXT = NULL; + +PFNGLFRAGMENTCOLORMATERIALEXTPROC __glewFragmentColorMaterialEXT = NULL; +PFNGLFRAGMENTLIGHTMODELFEXTPROC __glewFragmentLightModelfEXT = NULL; +PFNGLFRAGMENTLIGHTMODELFVEXTPROC __glewFragmentLightModelfvEXT = NULL; +PFNGLFRAGMENTLIGHTMODELIEXTPROC __glewFragmentLightModeliEXT = NULL; +PFNGLFRAGMENTLIGHTMODELIVEXTPROC __glewFragmentLightModelivEXT = NULL; +PFNGLFRAGMENTLIGHTFEXTPROC __glewFragmentLightfEXT = NULL; +PFNGLFRAGMENTLIGHTFVEXTPROC __glewFragmentLightfvEXT = NULL; +PFNGLFRAGMENTLIGHTIEXTPROC __glewFragmentLightiEXT = NULL; +PFNGLFRAGMENTLIGHTIVEXTPROC __glewFragmentLightivEXT = NULL; +PFNGLFRAGMENTMATERIALFEXTPROC __glewFragmentMaterialfEXT = NULL; +PFNGLFRAGMENTMATERIALFVEXTPROC __glewFragmentMaterialfvEXT = NULL; +PFNGLFRAGMENTMATERIALIEXTPROC __glewFragmentMaterialiEXT = NULL; +PFNGLFRAGMENTMATERIALIVEXTPROC __glewFragmentMaterialivEXT = NULL; +PFNGLGETFRAGMENTLIGHTFVEXTPROC __glewGetFragmentLightfvEXT = NULL; +PFNGLGETFRAGMENTLIGHTIVEXTPROC __glewGetFragmentLightivEXT = NULL; +PFNGLGETFRAGMENTMATERIALFVEXTPROC __glewGetFragmentMaterialfvEXT = NULL; +PFNGLGETFRAGMENTMATERIALIVEXTPROC __glewGetFragmentMaterialivEXT = NULL; +PFNGLLIGHTENVIEXTPROC __glewLightEnviEXT = NULL; + +PFNGLBLITFRAMEBUFFEREXTPROC __glewBlitFramebufferEXT = NULL; + +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __glewRenderbufferStorageMultisampleEXT = NULL; + +PFNGLBINDFRAMEBUFFEREXTPROC __glewBindFramebufferEXT = NULL; +PFNGLBINDRENDERBUFFEREXTPROC __glewBindRenderbufferEXT = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC __glewCheckFramebufferStatusEXT = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC __glewDeleteFramebuffersEXT = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC __glewDeleteRenderbuffersEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC __glewFramebufferRenderbufferEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC __glewFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC __glewFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC __glewFramebufferTexture3DEXT = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC __glewGenFramebuffersEXT = NULL; +PFNGLGENRENDERBUFFERSEXTPROC __glewGenRenderbuffersEXT = NULL; +PFNGLGENERATEMIPMAPEXTPROC __glewGenerateMipmapEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC __glewGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC __glewGetRenderbufferParameterivEXT = NULL; +PFNGLISFRAMEBUFFEREXTPROC __glewIsFramebufferEXT = NULL; +PFNGLISRENDERBUFFEREXTPROC __glewIsRenderbufferEXT = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC __glewRenderbufferStorageEXT = NULL; + +PFNGLFRAMEBUFFERTEXTUREEXTPROC __glewFramebufferTextureEXT = NULL; +PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC __glewFramebufferTextureFaceEXT = NULL; +PFNGLPROGRAMPARAMETERIEXTPROC __glewProgramParameteriEXT = NULL; + +PFNGLPROGRAMENVPARAMETERS4FVEXTPROC __glewProgramEnvParameters4fvEXT = NULL; +PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC __glewProgramLocalParameters4fvEXT = NULL; + +PFNGLBINDFRAGDATALOCATIONEXTPROC __glewBindFragDataLocationEXT = NULL; +PFNGLGETFRAGDATALOCATIONEXTPROC __glewGetFragDataLocationEXT = NULL; +PFNGLGETUNIFORMUIVEXTPROC __glewGetUniformuivEXT = NULL; +PFNGLGETVERTEXATTRIBIIVEXTPROC __glewGetVertexAttribIivEXT = NULL; +PFNGLGETVERTEXATTRIBIUIVEXTPROC __glewGetVertexAttribIuivEXT = NULL; +PFNGLUNIFORM1UIEXTPROC __glewUniform1uiEXT = NULL; +PFNGLUNIFORM1UIVEXTPROC __glewUniform1uivEXT = NULL; +PFNGLUNIFORM2UIEXTPROC __glewUniform2uiEXT = NULL; +PFNGLUNIFORM2UIVEXTPROC __glewUniform2uivEXT = NULL; +PFNGLUNIFORM3UIEXTPROC __glewUniform3uiEXT = NULL; +PFNGLUNIFORM3UIVEXTPROC __glewUniform3uivEXT = NULL; +PFNGLUNIFORM4UIEXTPROC __glewUniform4uiEXT = NULL; +PFNGLUNIFORM4UIVEXTPROC __glewUniform4uivEXT = NULL; +PFNGLVERTEXATTRIBI1IEXTPROC __glewVertexAttribI1iEXT = NULL; +PFNGLVERTEXATTRIBI1IVEXTPROC __glewVertexAttribI1ivEXT = NULL; +PFNGLVERTEXATTRIBI1UIEXTPROC __glewVertexAttribI1uiEXT = NULL; +PFNGLVERTEXATTRIBI1UIVEXTPROC __glewVertexAttribI1uivEXT = NULL; +PFNGLVERTEXATTRIBI2IEXTPROC __glewVertexAttribI2iEXT = NULL; +PFNGLVERTEXATTRIBI2IVEXTPROC __glewVertexAttribI2ivEXT = NULL; +PFNGLVERTEXATTRIBI2UIEXTPROC __glewVertexAttribI2uiEXT = NULL; +PFNGLVERTEXATTRIBI2UIVEXTPROC __glewVertexAttribI2uivEXT = NULL; +PFNGLVERTEXATTRIBI3IEXTPROC __glewVertexAttribI3iEXT = NULL; +PFNGLVERTEXATTRIBI3IVEXTPROC __glewVertexAttribI3ivEXT = NULL; +PFNGLVERTEXATTRIBI3UIEXTPROC __glewVertexAttribI3uiEXT = NULL; +PFNGLVERTEXATTRIBI3UIVEXTPROC __glewVertexAttribI3uivEXT = NULL; +PFNGLVERTEXATTRIBI4BVEXTPROC __glewVertexAttribI4bvEXT = NULL; +PFNGLVERTEXATTRIBI4IEXTPROC __glewVertexAttribI4iEXT = NULL; +PFNGLVERTEXATTRIBI4IVEXTPROC __glewVertexAttribI4ivEXT = NULL; +PFNGLVERTEXATTRIBI4SVEXTPROC __glewVertexAttribI4svEXT = NULL; +PFNGLVERTEXATTRIBI4UBVEXTPROC __glewVertexAttribI4ubvEXT = NULL; +PFNGLVERTEXATTRIBI4UIEXTPROC __glewVertexAttribI4uiEXT = NULL; +PFNGLVERTEXATTRIBI4UIVEXTPROC __glewVertexAttribI4uivEXT = NULL; +PFNGLVERTEXATTRIBI4USVEXTPROC __glewVertexAttribI4usvEXT = NULL; +PFNGLVERTEXATTRIBIPOINTEREXTPROC __glewVertexAttribIPointerEXT = NULL; + +PFNGLGETHISTOGRAMEXTPROC __glewGetHistogramEXT = NULL; +PFNGLGETHISTOGRAMPARAMETERFVEXTPROC __glewGetHistogramParameterfvEXT = NULL; +PFNGLGETHISTOGRAMPARAMETERIVEXTPROC __glewGetHistogramParameterivEXT = NULL; +PFNGLGETMINMAXEXTPROC __glewGetMinmaxEXT = NULL; +PFNGLGETMINMAXPARAMETERFVEXTPROC __glewGetMinmaxParameterfvEXT = NULL; +PFNGLGETMINMAXPARAMETERIVEXTPROC __glewGetMinmaxParameterivEXT = NULL; +PFNGLHISTOGRAMEXTPROC __glewHistogramEXT = NULL; +PFNGLMINMAXEXTPROC __glewMinmaxEXT = NULL; +PFNGLRESETHISTOGRAMEXTPROC __glewResetHistogramEXT = NULL; +PFNGLRESETMINMAXEXTPROC __glewResetMinmaxEXT = NULL; + +PFNGLINDEXFUNCEXTPROC __glewIndexFuncEXT = NULL; + +PFNGLINDEXMATERIALEXTPROC __glewIndexMaterialEXT = NULL; + +PFNGLVERTEXATTRIBDIVISOREXTPROC __glewVertexAttribDivisorEXT = NULL; + +PFNGLAPPLYTEXTUREEXTPROC __glewApplyTextureEXT = NULL; +PFNGLTEXTURELIGHTEXTPROC __glewTextureLightEXT = NULL; +PFNGLTEXTUREMATERIALEXTPROC __glewTextureMaterialEXT = NULL; + +PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC __glewFlushMappedBufferRangeEXT = NULL; +PFNGLMAPBUFFERRANGEEXTPROC __glewMapBufferRangeEXT = NULL; + +PFNGLBUFFERSTORAGEMEMEXTPROC __glewBufferStorageMemEXT = NULL; +PFNGLCREATEMEMORYOBJECTSEXTPROC __glewCreateMemoryObjectsEXT = NULL; +PFNGLDELETEMEMORYOBJECTSEXTPROC __glewDeleteMemoryObjectsEXT = NULL; +PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC __glewGetMemoryObjectParameterivEXT = NULL; +PFNGLGETUNSIGNEDBYTEI_VEXTPROC __glewGetUnsignedBytei_vEXT = NULL; +PFNGLGETUNSIGNEDBYTEVEXTPROC __glewGetUnsignedBytevEXT = NULL; +PFNGLISMEMORYOBJECTEXTPROC __glewIsMemoryObjectEXT = NULL; +PFNGLMEMORYOBJECTPARAMETERIVEXTPROC __glewMemoryObjectParameterivEXT = NULL; +PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC __glewNamedBufferStorageMemEXT = NULL; +PFNGLTEXSTORAGEMEM1DEXTPROC __glewTexStorageMem1DEXT = NULL; +PFNGLTEXSTORAGEMEM2DEXTPROC __glewTexStorageMem2DEXT = NULL; +PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC __glewTexStorageMem2DMultisampleEXT = NULL; +PFNGLTEXSTORAGEMEM3DEXTPROC __glewTexStorageMem3DEXT = NULL; +PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC __glewTexStorageMem3DMultisampleEXT = NULL; +PFNGLTEXTURESTORAGEMEM1DEXTPROC __glewTextureStorageMem1DEXT = NULL; +PFNGLTEXTURESTORAGEMEM2DEXTPROC __glewTextureStorageMem2DEXT = NULL; +PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC __glewTextureStorageMem2DMultisampleEXT = NULL; +PFNGLTEXTURESTORAGEMEM3DEXTPROC __glewTextureStorageMem3DEXT = NULL; +PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC __glewTextureStorageMem3DMultisampleEXT = NULL; + +PFNGLIMPORTMEMORYFDEXTPROC __glewImportMemoryFdEXT = NULL; + +PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC __glewImportMemoryWin32HandleEXT = NULL; +PFNGLIMPORTMEMORYWIN32NAMEEXTPROC __glewImportMemoryWin32NameEXT = NULL; + +PFNGLMULTIDRAWARRAYSEXTPROC __glewMultiDrawArraysEXT = NULL; +PFNGLMULTIDRAWELEMENTSEXTPROC __glewMultiDrawElementsEXT = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC __glewMultiDrawArraysIndirectEXT = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC __glewMultiDrawElementsIndirectEXT = NULL; + +PFNGLSAMPLEMASKEXTPROC __glewSampleMaskEXT = NULL; +PFNGLSAMPLEPATTERNEXTPROC __glewSamplePatternEXT = NULL; + +PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __glewFramebufferTexture2DMultisampleEXT = NULL; + +PFNGLDRAWBUFFERSINDEXEDEXTPROC __glewDrawBuffersIndexedEXT = NULL; +PFNGLGETINTEGERI_VEXTPROC __glewGetIntegeri_vEXT = NULL; +PFNGLREADBUFFERINDEXEDEXTPROC __glewReadBufferIndexedEXT = NULL; + +PFNGLCOLORTABLEEXTPROC __glewColorTableEXT = NULL; +PFNGLGETCOLORTABLEEXTPROC __glewGetColorTableEXT = NULL; +PFNGLGETCOLORTABLEPARAMETERFVEXTPROC __glewGetColorTableParameterfvEXT = NULL; +PFNGLGETCOLORTABLEPARAMETERIVEXTPROC __glewGetColorTableParameterivEXT = NULL; + +PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC __glewGetPixelTransformParameterfvEXT = NULL; +PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC __glewGetPixelTransformParameterivEXT = NULL; +PFNGLPIXELTRANSFORMPARAMETERFEXTPROC __glewPixelTransformParameterfEXT = NULL; +PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC __glewPixelTransformParameterfvEXT = NULL; +PFNGLPIXELTRANSFORMPARAMETERIEXTPROC __glewPixelTransformParameteriEXT = NULL; +PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC __glewPixelTransformParameterivEXT = NULL; + +PFNGLPOINTPARAMETERFEXTPROC __glewPointParameterfEXT = NULL; +PFNGLPOINTPARAMETERFVEXTPROC __glewPointParameterfvEXT = NULL; + +PFNGLPOLYGONOFFSETEXTPROC __glewPolygonOffsetEXT = NULL; + +PFNGLPOLYGONOFFSETCLAMPEXTPROC __glewPolygonOffsetClampEXT = NULL; + +PFNGLPROVOKINGVERTEXEXTPROC __glewProvokingVertexEXT = NULL; + +PFNGLCOVERAGEMODULATIONNVPROC __glewCoverageModulationNV = NULL; +PFNGLCOVERAGEMODULATIONTABLENVPROC __glewCoverageModulationTableNV = NULL; +PFNGLGETCOVERAGEMODULATIONTABLENVPROC __glewGetCoverageModulationTableNV = NULL; +PFNGLRASTERSAMPLESEXTPROC __glewRasterSamplesEXT = NULL; + +PFNGLBEGINSCENEEXTPROC __glewBeginSceneEXT = NULL; +PFNGLENDSCENEEXTPROC __glewEndSceneEXT = NULL; + +PFNGLSECONDARYCOLOR3BEXTPROC __glewSecondaryColor3bEXT = NULL; +PFNGLSECONDARYCOLOR3BVEXTPROC __glewSecondaryColor3bvEXT = NULL; +PFNGLSECONDARYCOLOR3DEXTPROC __glewSecondaryColor3dEXT = NULL; +PFNGLSECONDARYCOLOR3DVEXTPROC __glewSecondaryColor3dvEXT = NULL; +PFNGLSECONDARYCOLOR3FEXTPROC __glewSecondaryColor3fEXT = NULL; +PFNGLSECONDARYCOLOR3FVEXTPROC __glewSecondaryColor3fvEXT = NULL; +PFNGLSECONDARYCOLOR3IEXTPROC __glewSecondaryColor3iEXT = NULL; +PFNGLSECONDARYCOLOR3IVEXTPROC __glewSecondaryColor3ivEXT = NULL; +PFNGLSECONDARYCOLOR3SEXTPROC __glewSecondaryColor3sEXT = NULL; +PFNGLSECONDARYCOLOR3SVEXTPROC __glewSecondaryColor3svEXT = NULL; +PFNGLSECONDARYCOLOR3UBEXTPROC __glewSecondaryColor3ubEXT = NULL; +PFNGLSECONDARYCOLOR3UBVEXTPROC __glewSecondaryColor3ubvEXT = NULL; +PFNGLSECONDARYCOLOR3UIEXTPROC __glewSecondaryColor3uiEXT = NULL; +PFNGLSECONDARYCOLOR3UIVEXTPROC __glewSecondaryColor3uivEXT = NULL; +PFNGLSECONDARYCOLOR3USEXTPROC __glewSecondaryColor3usEXT = NULL; +PFNGLSECONDARYCOLOR3USVEXTPROC __glewSecondaryColor3usvEXT = NULL; +PFNGLSECONDARYCOLORPOINTEREXTPROC __glewSecondaryColorPointerEXT = NULL; + +PFNGLDELETESEMAPHORESEXTPROC __glewDeleteSemaphoresEXT = NULL; +PFNGLGENSEMAPHORESEXTPROC __glewGenSemaphoresEXT = NULL; +PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC __glewGetSemaphoreParameterui64vEXT = NULL; +PFNGLISSEMAPHOREEXTPROC __glewIsSemaphoreEXT = NULL; +PFNGLSEMAPHOREPARAMETERUI64VEXTPROC __glewSemaphoreParameterui64vEXT = NULL; +PFNGLSIGNALSEMAPHOREEXTPROC __glewSignalSemaphoreEXT = NULL; +PFNGLWAITSEMAPHOREEXTPROC __glewWaitSemaphoreEXT = NULL; + +PFNGLIMPORTSEMAPHOREFDEXTPROC __glewImportSemaphoreFdEXT = NULL; + +PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC __glewImportSemaphoreWin32HandleEXT = NULL; +PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC __glewImportSemaphoreWin32NameEXT = NULL; + +PFNGLACTIVEPROGRAMEXTPROC __glewActiveProgramEXT = NULL; +PFNGLCREATESHADERPROGRAMEXTPROC __glewCreateShaderProgramEXT = NULL; +PFNGLUSESHADERPROGRAMEXTPROC __glewUseShaderProgramEXT = NULL; + +PFNGLBINDIMAGETEXTUREEXTPROC __glewBindImageTextureEXT = NULL; +PFNGLMEMORYBARRIEREXTPROC __glewMemoryBarrierEXT = NULL; + +PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC __glewClearPixelLocalStorageuiEXT = NULL; +PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __glewFramebufferPixelLocalStorageSizeEXT = NULL; +PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __glewGetFramebufferPixelLocalStorageSizeEXT = NULL; + +PFNGLTEXPAGECOMMITMENTEXTPROC __glewTexPageCommitmentEXT = NULL; +PFNGLTEXTUREPAGECOMMITMENTEXTPROC __glewTexturePageCommitmentEXT = NULL; + +PFNGLACTIVESTENCILFACEEXTPROC __glewActiveStencilFaceEXT = NULL; + +PFNGLTEXSUBIMAGE1DEXTPROC __glewTexSubImage1DEXT = NULL; +PFNGLTEXSUBIMAGE2DEXTPROC __glewTexSubImage2DEXT = NULL; +PFNGLTEXSUBIMAGE3DEXTPROC __glewTexSubImage3DEXT = NULL; + +PFNGLTEXIMAGE3DEXTPROC __glewTexImage3DEXT = NULL; + +PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC __glewFramebufferTextureLayerEXT = NULL; + +PFNGLTEXBUFFEREXTPROC __glewTexBufferEXT = NULL; + +PFNGLCLEARCOLORIIEXTPROC __glewClearColorIiEXT = NULL; +PFNGLCLEARCOLORIUIEXTPROC __glewClearColorIuiEXT = NULL; +PFNGLGETTEXPARAMETERIIVEXTPROC __glewGetTexParameterIivEXT = NULL; +PFNGLGETTEXPARAMETERIUIVEXTPROC __glewGetTexParameterIuivEXT = NULL; +PFNGLTEXPARAMETERIIVEXTPROC __glewTexParameterIivEXT = NULL; +PFNGLTEXPARAMETERIUIVEXTPROC __glewTexParameterIuivEXT = NULL; + +PFNGLARETEXTURESRESIDENTEXTPROC __glewAreTexturesResidentEXT = NULL; +PFNGLBINDTEXTUREEXTPROC __glewBindTextureEXT = NULL; +PFNGLDELETETEXTURESEXTPROC __glewDeleteTexturesEXT = NULL; +PFNGLGENTEXTURESEXTPROC __glewGenTexturesEXT = NULL; +PFNGLISTEXTUREEXTPROC __glewIsTextureEXT = NULL; +PFNGLPRIORITIZETEXTURESEXTPROC __glewPrioritizeTexturesEXT = NULL; + +PFNGLTEXTURENORMALEXTPROC __glewTextureNormalEXT = NULL; + +PFNGLTEXSTORAGE1DEXTPROC __glewTexStorage1DEXT = NULL; +PFNGLTEXSTORAGE2DEXTPROC __glewTexStorage2DEXT = NULL; +PFNGLTEXSTORAGE3DEXTPROC __glewTexStorage3DEXT = NULL; +PFNGLTEXTURESTORAGE1DEXTPROC __glewTextureStorage1DEXT = NULL; +PFNGLTEXTURESTORAGE2DEXTPROC __glewTextureStorage2DEXT = NULL; +PFNGLTEXTURESTORAGE3DEXTPROC __glewTextureStorage3DEXT = NULL; + +PFNGLTEXTUREVIEWEXTPROC __glewTextureViewEXT = NULL; + +PFNGLGETQUERYOBJECTI64VEXTPROC __glewGetQueryObjecti64vEXT = NULL; +PFNGLGETQUERYOBJECTUI64VEXTPROC __glewGetQueryObjectui64vEXT = NULL; + +PFNGLBEGINTRANSFORMFEEDBACKEXTPROC __glewBeginTransformFeedbackEXT = NULL; +PFNGLBINDBUFFERBASEEXTPROC __glewBindBufferBaseEXT = NULL; +PFNGLBINDBUFFEROFFSETEXTPROC __glewBindBufferOffsetEXT = NULL; +PFNGLBINDBUFFERRANGEEXTPROC __glewBindBufferRangeEXT = NULL; +PFNGLENDTRANSFORMFEEDBACKEXTPROC __glewEndTransformFeedbackEXT = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC __glewGetTransformFeedbackVaryingEXT = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC __glewTransformFeedbackVaryingsEXT = NULL; + +PFNGLARRAYELEMENTEXTPROC __glewArrayElementEXT = NULL; +PFNGLCOLORPOINTEREXTPROC __glewColorPointerEXT = NULL; +PFNGLDRAWARRAYSEXTPROC __glewDrawArraysEXT = NULL; +PFNGLEDGEFLAGPOINTEREXTPROC __glewEdgeFlagPointerEXT = NULL; +PFNGLINDEXPOINTEREXTPROC __glewIndexPointerEXT = NULL; +PFNGLNORMALPOINTEREXTPROC __glewNormalPointerEXT = NULL; +PFNGLTEXCOORDPOINTEREXTPROC __glewTexCoordPointerEXT = NULL; +PFNGLVERTEXPOINTEREXTPROC __glewVertexPointerEXT = NULL; + +PFNGLBINDARRAYSETEXTPROC __glewBindArraySetEXT = NULL; +PFNGLCREATEARRAYSETEXTPROC __glewCreateArraySetExt = NULL; +PFNGLDELETEARRAYSETSEXTPROC __glewDeleteArraySetsEXT = NULL; + +PFNGLGETVERTEXATTRIBLDVEXTPROC __glewGetVertexAttribLdvEXT = NULL; +PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC __glewVertexArrayVertexAttribLOffsetEXT = NULL; +PFNGLVERTEXATTRIBL1DEXTPROC __glewVertexAttribL1dEXT = NULL; +PFNGLVERTEXATTRIBL1DVEXTPROC __glewVertexAttribL1dvEXT = NULL; +PFNGLVERTEXATTRIBL2DEXTPROC __glewVertexAttribL2dEXT = NULL; +PFNGLVERTEXATTRIBL2DVEXTPROC __glewVertexAttribL2dvEXT = NULL; +PFNGLVERTEXATTRIBL3DEXTPROC __glewVertexAttribL3dEXT = NULL; +PFNGLVERTEXATTRIBL3DVEXTPROC __glewVertexAttribL3dvEXT = NULL; +PFNGLVERTEXATTRIBL4DEXTPROC __glewVertexAttribL4dEXT = NULL; +PFNGLVERTEXATTRIBL4DVEXTPROC __glewVertexAttribL4dvEXT = NULL; +PFNGLVERTEXATTRIBLPOINTEREXTPROC __glewVertexAttribLPointerEXT = NULL; + +PFNGLBEGINVERTEXSHADEREXTPROC __glewBeginVertexShaderEXT = NULL; +PFNGLBINDLIGHTPARAMETEREXTPROC __glewBindLightParameterEXT = NULL; +PFNGLBINDMATERIALPARAMETEREXTPROC __glewBindMaterialParameterEXT = NULL; +PFNGLBINDPARAMETEREXTPROC __glewBindParameterEXT = NULL; +PFNGLBINDTEXGENPARAMETEREXTPROC __glewBindTexGenParameterEXT = NULL; +PFNGLBINDTEXTUREUNITPARAMETEREXTPROC __glewBindTextureUnitParameterEXT = NULL; +PFNGLBINDVERTEXSHADEREXTPROC __glewBindVertexShaderEXT = NULL; +PFNGLDELETEVERTEXSHADEREXTPROC __glewDeleteVertexShaderEXT = NULL; +PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC __glewDisableVariantClientStateEXT = NULL; +PFNGLENABLEVARIANTCLIENTSTATEEXTPROC __glewEnableVariantClientStateEXT = NULL; +PFNGLENDVERTEXSHADEREXTPROC __glewEndVertexShaderEXT = NULL; +PFNGLEXTRACTCOMPONENTEXTPROC __glewExtractComponentEXT = NULL; +PFNGLGENSYMBOLSEXTPROC __glewGenSymbolsEXT = NULL; +PFNGLGENVERTEXSHADERSEXTPROC __glewGenVertexShadersEXT = NULL; +PFNGLGETINVARIANTBOOLEANVEXTPROC __glewGetInvariantBooleanvEXT = NULL; +PFNGLGETINVARIANTFLOATVEXTPROC __glewGetInvariantFloatvEXT = NULL; +PFNGLGETINVARIANTINTEGERVEXTPROC __glewGetInvariantIntegervEXT = NULL; +PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC __glewGetLocalConstantBooleanvEXT = NULL; +PFNGLGETLOCALCONSTANTFLOATVEXTPROC __glewGetLocalConstantFloatvEXT = NULL; +PFNGLGETLOCALCONSTANTINTEGERVEXTPROC __glewGetLocalConstantIntegervEXT = NULL; +PFNGLGETVARIANTBOOLEANVEXTPROC __glewGetVariantBooleanvEXT = NULL; +PFNGLGETVARIANTFLOATVEXTPROC __glewGetVariantFloatvEXT = NULL; +PFNGLGETVARIANTINTEGERVEXTPROC __glewGetVariantIntegervEXT = NULL; +PFNGLGETVARIANTPOINTERVEXTPROC __glewGetVariantPointervEXT = NULL; +PFNGLINSERTCOMPONENTEXTPROC __glewInsertComponentEXT = NULL; +PFNGLISVARIANTENABLEDEXTPROC __glewIsVariantEnabledEXT = NULL; +PFNGLSETINVARIANTEXTPROC __glewSetInvariantEXT = NULL; +PFNGLSETLOCALCONSTANTEXTPROC __glewSetLocalConstantEXT = NULL; +PFNGLSHADEROP1EXTPROC __glewShaderOp1EXT = NULL; +PFNGLSHADEROP2EXTPROC __glewShaderOp2EXT = NULL; +PFNGLSHADEROP3EXTPROC __glewShaderOp3EXT = NULL; +PFNGLSWIZZLEEXTPROC __glewSwizzleEXT = NULL; +PFNGLVARIANTPOINTEREXTPROC __glewVariantPointerEXT = NULL; +PFNGLVARIANTBVEXTPROC __glewVariantbvEXT = NULL; +PFNGLVARIANTDVEXTPROC __glewVariantdvEXT = NULL; +PFNGLVARIANTFVEXTPROC __glewVariantfvEXT = NULL; +PFNGLVARIANTIVEXTPROC __glewVariantivEXT = NULL; +PFNGLVARIANTSVEXTPROC __glewVariantsvEXT = NULL; +PFNGLVARIANTUBVEXTPROC __glewVariantubvEXT = NULL; +PFNGLVARIANTUIVEXTPROC __glewVariantuivEXT = NULL; +PFNGLVARIANTUSVEXTPROC __glewVariantusvEXT = NULL; +PFNGLWRITEMASKEXTPROC __glewWriteMaskEXT = NULL; + +PFNGLVERTEXWEIGHTPOINTEREXTPROC __glewVertexWeightPointerEXT = NULL; +PFNGLVERTEXWEIGHTFEXTPROC __glewVertexWeightfEXT = NULL; +PFNGLVERTEXWEIGHTFVEXTPROC __glewVertexWeightfvEXT = NULL; + +PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC __glewAcquireKeyedMutexWin32EXT = NULL; +PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC __glewReleaseKeyedMutexWin32EXT = NULL; + +PFNGLWINDOWRECTANGLESEXTPROC __glewWindowRectanglesEXT = NULL; + +PFNGLIMPORTSYNCEXTPROC __glewImportSyncEXT = NULL; + +PFNGLFRAMETERMINATORGREMEDYPROC __glewFrameTerminatorGREMEDY = NULL; + +PFNGLSTRINGMARKERGREMEDYPROC __glewStringMarkerGREMEDY = NULL; + +PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC __glewGetImageTransformParameterfvHP = NULL; +PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC __glewGetImageTransformParameterivHP = NULL; +PFNGLIMAGETRANSFORMPARAMETERFHPPROC __glewImageTransformParameterfHP = NULL; +PFNGLIMAGETRANSFORMPARAMETERFVHPPROC __glewImageTransformParameterfvHP = NULL; +PFNGLIMAGETRANSFORMPARAMETERIHPPROC __glewImageTransformParameteriHP = NULL; +PFNGLIMAGETRANSFORMPARAMETERIVHPPROC __glewImageTransformParameterivHP = NULL; + +PFNGLMULTIMODEDRAWARRAYSIBMPROC __glewMultiModeDrawArraysIBM = NULL; +PFNGLMULTIMODEDRAWELEMENTSIBMPROC __glewMultiModeDrawElementsIBM = NULL; + +PFNGLCOLORPOINTERLISTIBMPROC __glewColorPointerListIBM = NULL; +PFNGLEDGEFLAGPOINTERLISTIBMPROC __glewEdgeFlagPointerListIBM = NULL; +PFNGLFOGCOORDPOINTERLISTIBMPROC __glewFogCoordPointerListIBM = NULL; +PFNGLINDEXPOINTERLISTIBMPROC __glewIndexPointerListIBM = NULL; +PFNGLNORMALPOINTERLISTIBMPROC __glewNormalPointerListIBM = NULL; +PFNGLSECONDARYCOLORPOINTERLISTIBMPROC __glewSecondaryColorPointerListIBM = NULL; +PFNGLTEXCOORDPOINTERLISTIBMPROC __glewTexCoordPointerListIBM = NULL; +PFNGLVERTEXPOINTERLISTIBMPROC __glewVertexPointerListIBM = NULL; + +PFNGLMAPTEXTURE2DINTELPROC __glewMapTexture2DINTEL = NULL; +PFNGLSYNCTEXTUREINTELPROC __glewSyncTextureINTEL = NULL; +PFNGLUNMAPTEXTURE2DINTELPROC __glewUnmapTexture2DINTEL = NULL; + +PFNGLCOLORPOINTERVINTELPROC __glewColorPointervINTEL = NULL; +PFNGLNORMALPOINTERVINTELPROC __glewNormalPointervINTEL = NULL; +PFNGLTEXCOORDPOINTERVINTELPROC __glewTexCoordPointervINTEL = NULL; +PFNGLVERTEXPOINTERVINTELPROC __glewVertexPointervINTEL = NULL; + +PFNGLBEGINPERFQUERYINTELPROC __glewBeginPerfQueryINTEL = NULL; +PFNGLCREATEPERFQUERYINTELPROC __glewCreatePerfQueryINTEL = NULL; +PFNGLDELETEPERFQUERYINTELPROC __glewDeletePerfQueryINTEL = NULL; +PFNGLENDPERFQUERYINTELPROC __glewEndPerfQueryINTEL = NULL; +PFNGLGETFIRSTPERFQUERYIDINTELPROC __glewGetFirstPerfQueryIdINTEL = NULL; +PFNGLGETNEXTPERFQUERYIDINTELPROC __glewGetNextPerfQueryIdINTEL = NULL; +PFNGLGETPERFCOUNTERINFOINTELPROC __glewGetPerfCounterInfoINTEL = NULL; +PFNGLGETPERFQUERYDATAINTELPROC __glewGetPerfQueryDataINTEL = NULL; +PFNGLGETPERFQUERYIDBYNAMEINTELPROC __glewGetPerfQueryIdByNameINTEL = NULL; +PFNGLGETPERFQUERYINFOINTELPROC __glewGetPerfQueryInfoINTEL = NULL; + +PFNGLTEXSCISSORFUNCINTELPROC __glewTexScissorFuncINTEL = NULL; +PFNGLTEXSCISSORINTELPROC __glewTexScissorINTEL = NULL; + +PFNGLBLENDBARRIERKHRPROC __glewBlendBarrierKHR = NULL; + +PFNGLDEBUGMESSAGECALLBACKPROC __glewDebugMessageCallback = NULL; +PFNGLDEBUGMESSAGECONTROLPROC __glewDebugMessageControl = NULL; +PFNGLDEBUGMESSAGEINSERTPROC __glewDebugMessageInsert = NULL; +PFNGLGETDEBUGMESSAGELOGPROC __glewGetDebugMessageLog = NULL; +PFNGLGETOBJECTLABELPROC __glewGetObjectLabel = NULL; +PFNGLGETOBJECTPTRLABELPROC __glewGetObjectPtrLabel = NULL; +PFNGLOBJECTLABELPROC __glewObjectLabel = NULL; +PFNGLOBJECTPTRLABELPROC __glewObjectPtrLabel = NULL; +PFNGLPOPDEBUGGROUPPROC __glewPopDebugGroup = NULL; +PFNGLPUSHDEBUGGROUPPROC __glewPushDebugGroup = NULL; + +PFNGLMAXSHADERCOMPILERTHREADSKHRPROC __glewMaxShaderCompilerThreadsKHR = NULL; + +PFNGLGETNUNIFORMFVPROC __glewGetnUniformfv = NULL; +PFNGLGETNUNIFORMIVPROC __glewGetnUniformiv = NULL; +PFNGLGETNUNIFORMUIVPROC __glewGetnUniformuiv = NULL; +PFNGLREADNPIXELSPROC __glewReadnPixels = NULL; + +PFNGLBUFFERREGIONENABLEDPROC __glewBufferRegionEnabled = NULL; +PFNGLDELETEBUFFERREGIONPROC __glewDeleteBufferRegion = NULL; +PFNGLDRAWBUFFERREGIONPROC __glewDrawBufferRegion = NULL; +PFNGLNEWBUFFERREGIONPROC __glewNewBufferRegion = NULL; +PFNGLREADBUFFERREGIONPROC __glewReadBufferRegion = NULL; + +PFNGLRESIZEBUFFERSMESAPROC __glewResizeBuffersMESA = NULL; + +PFNGLWINDOWPOS2DMESAPROC __glewWindowPos2dMESA = NULL; +PFNGLWINDOWPOS2DVMESAPROC __glewWindowPos2dvMESA = NULL; +PFNGLWINDOWPOS2FMESAPROC __glewWindowPos2fMESA = NULL; +PFNGLWINDOWPOS2FVMESAPROC __glewWindowPos2fvMESA = NULL; +PFNGLWINDOWPOS2IMESAPROC __glewWindowPos2iMESA = NULL; +PFNGLWINDOWPOS2IVMESAPROC __glewWindowPos2ivMESA = NULL; +PFNGLWINDOWPOS2SMESAPROC __glewWindowPos2sMESA = NULL; +PFNGLWINDOWPOS2SVMESAPROC __glewWindowPos2svMESA = NULL; +PFNGLWINDOWPOS3DMESAPROC __glewWindowPos3dMESA = NULL; +PFNGLWINDOWPOS3DVMESAPROC __glewWindowPos3dvMESA = NULL; +PFNGLWINDOWPOS3FMESAPROC __glewWindowPos3fMESA = NULL; +PFNGLWINDOWPOS3FVMESAPROC __glewWindowPos3fvMESA = NULL; +PFNGLWINDOWPOS3IMESAPROC __glewWindowPos3iMESA = NULL; +PFNGLWINDOWPOS3IVMESAPROC __glewWindowPos3ivMESA = NULL; +PFNGLWINDOWPOS3SMESAPROC __glewWindowPos3sMESA = NULL; +PFNGLWINDOWPOS3SVMESAPROC __glewWindowPos3svMESA = NULL; +PFNGLWINDOWPOS4DMESAPROC __glewWindowPos4dMESA = NULL; +PFNGLWINDOWPOS4DVMESAPROC __glewWindowPos4dvMESA = NULL; +PFNGLWINDOWPOS4FMESAPROC __glewWindowPos4fMESA = NULL; +PFNGLWINDOWPOS4FVMESAPROC __glewWindowPos4fvMESA = NULL; +PFNGLWINDOWPOS4IMESAPROC __glewWindowPos4iMESA = NULL; +PFNGLWINDOWPOS4IVMESAPROC __glewWindowPos4ivMESA = NULL; +PFNGLWINDOWPOS4SMESAPROC __glewWindowPos4sMESA = NULL; +PFNGLWINDOWPOS4SVMESAPROC __glewWindowPos4svMESA = NULL; + +PFNGLBEGINCONDITIONALRENDERNVXPROC __glewBeginConditionalRenderNVX = NULL; +PFNGLENDCONDITIONALRENDERNVXPROC __glewEndConditionalRenderNVX = NULL; + +PFNGLLGPUCOPYIMAGESUBDATANVXPROC __glewLGPUCopyImageSubDataNVX = NULL; +PFNGLLGPUINTERLOCKNVXPROC __glewLGPUInterlockNVX = NULL; +PFNGLLGPUNAMEDBUFFERSUBDATANVXPROC __glewLGPUNamedBufferSubDataNVX = NULL; + +PFNGLSTEREOPARAMETERFNVPROC __glewStereoParameterfNV = NULL; +PFNGLSTEREOPARAMETERINVPROC __glewStereoParameteriNV = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC __glewMultiDrawArraysIndirectBindlessNV = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC __glewMultiDrawElementsIndirectBindlessNV = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC __glewMultiDrawArraysIndirectBindlessCountNV = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC __glewMultiDrawElementsIndirectBindlessCountNV = NULL; + +PFNGLGETIMAGEHANDLENVPROC __glewGetImageHandleNV = NULL; +PFNGLGETTEXTUREHANDLENVPROC __glewGetTextureHandleNV = NULL; +PFNGLGETTEXTURESAMPLERHANDLENVPROC __glewGetTextureSamplerHandleNV = NULL; +PFNGLISIMAGEHANDLERESIDENTNVPROC __glewIsImageHandleResidentNV = NULL; +PFNGLISTEXTUREHANDLERESIDENTNVPROC __glewIsTextureHandleResidentNV = NULL; +PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC __glewMakeImageHandleNonResidentNV = NULL; +PFNGLMAKEIMAGEHANDLERESIDENTNVPROC __glewMakeImageHandleResidentNV = NULL; +PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC __glewMakeTextureHandleNonResidentNV = NULL; +PFNGLMAKETEXTUREHANDLERESIDENTNVPROC __glewMakeTextureHandleResidentNV = NULL; +PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC __glewProgramUniformHandleui64NV = NULL; +PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC __glewProgramUniformHandleui64vNV = NULL; +PFNGLUNIFORMHANDLEUI64NVPROC __glewUniformHandleui64NV = NULL; +PFNGLUNIFORMHANDLEUI64VNVPROC __glewUniformHandleui64vNV = NULL; + +PFNGLBLENDBARRIERNVPROC __glewBlendBarrierNV = NULL; +PFNGLBLENDPARAMETERINVPROC __glewBlendParameteriNV = NULL; + +PFNGLVIEWPORTPOSITIONWSCALENVPROC __glewViewportPositionWScaleNV = NULL; + +PFNGLCALLCOMMANDLISTNVPROC __glewCallCommandListNV = NULL; +PFNGLCOMMANDLISTSEGMENTSNVPROC __glewCommandListSegmentsNV = NULL; +PFNGLCOMPILECOMMANDLISTNVPROC __glewCompileCommandListNV = NULL; +PFNGLCREATECOMMANDLISTSNVPROC __glewCreateCommandListsNV = NULL; +PFNGLCREATESTATESNVPROC __glewCreateStatesNV = NULL; +PFNGLDELETECOMMANDLISTSNVPROC __glewDeleteCommandListsNV = NULL; +PFNGLDELETESTATESNVPROC __glewDeleteStatesNV = NULL; +PFNGLDRAWCOMMANDSADDRESSNVPROC __glewDrawCommandsAddressNV = NULL; +PFNGLDRAWCOMMANDSNVPROC __glewDrawCommandsNV = NULL; +PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC __glewDrawCommandsStatesAddressNV = NULL; +PFNGLDRAWCOMMANDSSTATESNVPROC __glewDrawCommandsStatesNV = NULL; +PFNGLGETCOMMANDHEADERNVPROC __glewGetCommandHeaderNV = NULL; +PFNGLGETSTAGEINDEXNVPROC __glewGetStageIndexNV = NULL; +PFNGLISCOMMANDLISTNVPROC __glewIsCommandListNV = NULL; +PFNGLISSTATENVPROC __glewIsStateNV = NULL; +PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC __glewListDrawCommandsStatesClientNV = NULL; +PFNGLSTATECAPTURENVPROC __glewStateCaptureNV = NULL; + +PFNGLBEGINCONDITIONALRENDERNVPROC __glewBeginConditionalRenderNV = NULL; +PFNGLENDCONDITIONALRENDERNVPROC __glewEndConditionalRenderNV = NULL; + +PFNGLSUBPIXELPRECISIONBIASNVPROC __glewSubpixelPrecisionBiasNV = NULL; + +PFNGLCONSERVATIVERASTERPARAMETERFNVPROC __glewConservativeRasterParameterfNV = NULL; + +PFNGLCONSERVATIVERASTERPARAMETERINVPROC __glewConservativeRasterParameteriNV = NULL; + +PFNGLCOPYBUFFERSUBDATANVPROC __glewCopyBufferSubDataNV = NULL; + +PFNGLCOPYIMAGESUBDATANVPROC __glewCopyImageSubDataNV = NULL; + +PFNGLCLEARDEPTHDNVPROC __glewClearDepthdNV = NULL; +PFNGLDEPTHBOUNDSDNVPROC __glewDepthBoundsdNV = NULL; +PFNGLDEPTHRANGEDNVPROC __glewDepthRangedNV = NULL; + +PFNGLDRAWBUFFERSNVPROC __glewDrawBuffersNV = NULL; + +PFNGLDRAWARRAYSINSTANCEDNVPROC __glewDrawArraysInstancedNV = NULL; +PFNGLDRAWELEMENTSINSTANCEDNVPROC __glewDrawElementsInstancedNV = NULL; + +PFNGLDRAWTEXTURENVPROC __glewDrawTextureNV = NULL; + +PFNGLDRAWVKIMAGENVPROC __glewDrawVkImageNV = NULL; +PFNGLGETVKPROCADDRNVPROC __glewGetVkProcAddrNV = NULL; +PFNGLSIGNALVKFENCENVPROC __glewSignalVkFenceNV = NULL; +PFNGLSIGNALVKSEMAPHORENVPROC __glewSignalVkSemaphoreNV = NULL; +PFNGLWAITVKSEMAPHORENVPROC __glewWaitVkSemaphoreNV = NULL; + +PFNGLEVALMAPSNVPROC __glewEvalMapsNV = NULL; +PFNGLGETMAPATTRIBPARAMETERFVNVPROC __glewGetMapAttribParameterfvNV = NULL; +PFNGLGETMAPATTRIBPARAMETERIVNVPROC __glewGetMapAttribParameterivNV = NULL; +PFNGLGETMAPCONTROLPOINTSNVPROC __glewGetMapControlPointsNV = NULL; +PFNGLGETMAPPARAMETERFVNVPROC __glewGetMapParameterfvNV = NULL; +PFNGLGETMAPPARAMETERIVNVPROC __glewGetMapParameterivNV = NULL; +PFNGLMAPCONTROLPOINTSNVPROC __glewMapControlPointsNV = NULL; +PFNGLMAPPARAMETERFVNVPROC __glewMapParameterfvNV = NULL; +PFNGLMAPPARAMETERIVNVPROC __glewMapParameterivNV = NULL; + +PFNGLGETMULTISAMPLEFVNVPROC __glewGetMultisamplefvNV = NULL; +PFNGLSAMPLEMASKINDEXEDNVPROC __glewSampleMaskIndexedNV = NULL; +PFNGLTEXRENDERBUFFERNVPROC __glewTexRenderbufferNV = NULL; + +PFNGLDELETEFENCESNVPROC __glewDeleteFencesNV = NULL; +PFNGLFINISHFENCENVPROC __glewFinishFenceNV = NULL; +PFNGLGENFENCESNVPROC __glewGenFencesNV = NULL; +PFNGLGETFENCEIVNVPROC __glewGetFenceivNV = NULL; +PFNGLISFENCENVPROC __glewIsFenceNV = NULL; +PFNGLSETFENCENVPROC __glewSetFenceNV = NULL; +PFNGLTESTFENCENVPROC __glewTestFenceNV = NULL; + +PFNGLFRAGMENTCOVERAGECOLORNVPROC __glewFragmentCoverageColorNV = NULL; + +PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC __glewGetProgramNamedParameterdvNV = NULL; +PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC __glewGetProgramNamedParameterfvNV = NULL; +PFNGLPROGRAMNAMEDPARAMETER4DNVPROC __glewProgramNamedParameter4dNV = NULL; +PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC __glewProgramNamedParameter4dvNV = NULL; +PFNGLPROGRAMNAMEDPARAMETER4FNVPROC __glewProgramNamedParameter4fNV = NULL; +PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC __glewProgramNamedParameter4fvNV = NULL; + +PFNGLBLITFRAMEBUFFERNVPROC __glewBlitFramebufferNV = NULL; + +PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC __glewRenderbufferStorageMultisampleNV = NULL; + +PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC __glewRenderbufferStorageMultisampleCoverageNV = NULL; + +PFNGLPROGRAMVERTEXLIMITNVPROC __glewProgramVertexLimitNV = NULL; + +PFNGLMULTICASTBARRIERNVPROC __glewMulticastBarrierNV = NULL; +PFNGLMULTICASTBLITFRAMEBUFFERNVPROC __glewMulticastBlitFramebufferNV = NULL; +PFNGLMULTICASTBUFFERSUBDATANVPROC __glewMulticastBufferSubDataNV = NULL; +PFNGLMULTICASTCOPYBUFFERSUBDATANVPROC __glewMulticastCopyBufferSubDataNV = NULL; +PFNGLMULTICASTCOPYIMAGESUBDATANVPROC __glewMulticastCopyImageSubDataNV = NULL; +PFNGLMULTICASTFRAMEBUFFERSAMPLELOCATIONSFVNVPROC __glewMulticastFramebufferSampleLocationsfvNV = NULL; +PFNGLMULTICASTGETQUERYOBJECTI64VNVPROC __glewMulticastGetQueryObjecti64vNV = NULL; +PFNGLMULTICASTGETQUERYOBJECTIVNVPROC __glewMulticastGetQueryObjectivNV = NULL; +PFNGLMULTICASTGETQUERYOBJECTUI64VNVPROC __glewMulticastGetQueryObjectui64vNV = NULL; +PFNGLMULTICASTGETQUERYOBJECTUIVNVPROC __glewMulticastGetQueryObjectuivNV = NULL; +PFNGLMULTICASTWAITSYNCNVPROC __glewMulticastWaitSyncNV = NULL; +PFNGLRENDERGPUMASKNVPROC __glewRenderGpuMaskNV = NULL; + +PFNGLPROGRAMENVPARAMETERI4INVPROC __glewProgramEnvParameterI4iNV = NULL; +PFNGLPROGRAMENVPARAMETERI4IVNVPROC __glewProgramEnvParameterI4ivNV = NULL; +PFNGLPROGRAMENVPARAMETERI4UINVPROC __glewProgramEnvParameterI4uiNV = NULL; +PFNGLPROGRAMENVPARAMETERI4UIVNVPROC __glewProgramEnvParameterI4uivNV = NULL; +PFNGLPROGRAMENVPARAMETERSI4IVNVPROC __glewProgramEnvParametersI4ivNV = NULL; +PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC __glewProgramEnvParametersI4uivNV = NULL; +PFNGLPROGRAMLOCALPARAMETERI4INVPROC __glewProgramLocalParameterI4iNV = NULL; +PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC __glewProgramLocalParameterI4ivNV = NULL; +PFNGLPROGRAMLOCALPARAMETERI4UINVPROC __glewProgramLocalParameterI4uiNV = NULL; +PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC __glewProgramLocalParameterI4uivNV = NULL; +PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC __glewProgramLocalParametersI4ivNV = NULL; +PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC __glewProgramLocalParametersI4uivNV = NULL; + +PFNGLGETUNIFORMI64VNVPROC __glewGetUniformi64vNV = NULL; +PFNGLGETUNIFORMUI64VNVPROC __glewGetUniformui64vNV = NULL; +PFNGLPROGRAMUNIFORM1I64NVPROC __glewProgramUniform1i64NV = NULL; +PFNGLPROGRAMUNIFORM1I64VNVPROC __glewProgramUniform1i64vNV = NULL; +PFNGLPROGRAMUNIFORM1UI64NVPROC __glewProgramUniform1ui64NV = NULL; +PFNGLPROGRAMUNIFORM1UI64VNVPROC __glewProgramUniform1ui64vNV = NULL; +PFNGLPROGRAMUNIFORM2I64NVPROC __glewProgramUniform2i64NV = NULL; +PFNGLPROGRAMUNIFORM2I64VNVPROC __glewProgramUniform2i64vNV = NULL; +PFNGLPROGRAMUNIFORM2UI64NVPROC __glewProgramUniform2ui64NV = NULL; +PFNGLPROGRAMUNIFORM2UI64VNVPROC __glewProgramUniform2ui64vNV = NULL; +PFNGLPROGRAMUNIFORM3I64NVPROC __glewProgramUniform3i64NV = NULL; +PFNGLPROGRAMUNIFORM3I64VNVPROC __glewProgramUniform3i64vNV = NULL; +PFNGLPROGRAMUNIFORM3UI64NVPROC __glewProgramUniform3ui64NV = NULL; +PFNGLPROGRAMUNIFORM3UI64VNVPROC __glewProgramUniform3ui64vNV = NULL; +PFNGLPROGRAMUNIFORM4I64NVPROC __glewProgramUniform4i64NV = NULL; +PFNGLPROGRAMUNIFORM4I64VNVPROC __glewProgramUniform4i64vNV = NULL; +PFNGLPROGRAMUNIFORM4UI64NVPROC __glewProgramUniform4ui64NV = NULL; +PFNGLPROGRAMUNIFORM4UI64VNVPROC __glewProgramUniform4ui64vNV = NULL; +PFNGLUNIFORM1I64NVPROC __glewUniform1i64NV = NULL; +PFNGLUNIFORM1I64VNVPROC __glewUniform1i64vNV = NULL; +PFNGLUNIFORM1UI64NVPROC __glewUniform1ui64NV = NULL; +PFNGLUNIFORM1UI64VNVPROC __glewUniform1ui64vNV = NULL; +PFNGLUNIFORM2I64NVPROC __glewUniform2i64NV = NULL; +PFNGLUNIFORM2I64VNVPROC __glewUniform2i64vNV = NULL; +PFNGLUNIFORM2UI64NVPROC __glewUniform2ui64NV = NULL; +PFNGLUNIFORM2UI64VNVPROC __glewUniform2ui64vNV = NULL; +PFNGLUNIFORM3I64NVPROC __glewUniform3i64NV = NULL; +PFNGLUNIFORM3I64VNVPROC __glewUniform3i64vNV = NULL; +PFNGLUNIFORM3UI64NVPROC __glewUniform3ui64NV = NULL; +PFNGLUNIFORM3UI64VNVPROC __glewUniform3ui64vNV = NULL; +PFNGLUNIFORM4I64NVPROC __glewUniform4i64NV = NULL; +PFNGLUNIFORM4I64VNVPROC __glewUniform4i64vNV = NULL; +PFNGLUNIFORM4UI64NVPROC __glewUniform4ui64NV = NULL; +PFNGLUNIFORM4UI64VNVPROC __glewUniform4ui64vNV = NULL; + +PFNGLCOLOR3HNVPROC __glewColor3hNV = NULL; +PFNGLCOLOR3HVNVPROC __glewColor3hvNV = NULL; +PFNGLCOLOR4HNVPROC __glewColor4hNV = NULL; +PFNGLCOLOR4HVNVPROC __glewColor4hvNV = NULL; +PFNGLFOGCOORDHNVPROC __glewFogCoordhNV = NULL; +PFNGLFOGCOORDHVNVPROC __glewFogCoordhvNV = NULL; +PFNGLMULTITEXCOORD1HNVPROC __glewMultiTexCoord1hNV = NULL; +PFNGLMULTITEXCOORD1HVNVPROC __glewMultiTexCoord1hvNV = NULL; +PFNGLMULTITEXCOORD2HNVPROC __glewMultiTexCoord2hNV = NULL; +PFNGLMULTITEXCOORD2HVNVPROC __glewMultiTexCoord2hvNV = NULL; +PFNGLMULTITEXCOORD3HNVPROC __glewMultiTexCoord3hNV = NULL; +PFNGLMULTITEXCOORD3HVNVPROC __glewMultiTexCoord3hvNV = NULL; +PFNGLMULTITEXCOORD4HNVPROC __glewMultiTexCoord4hNV = NULL; +PFNGLMULTITEXCOORD4HVNVPROC __glewMultiTexCoord4hvNV = NULL; +PFNGLNORMAL3HNVPROC __glewNormal3hNV = NULL; +PFNGLNORMAL3HVNVPROC __glewNormal3hvNV = NULL; +PFNGLSECONDARYCOLOR3HNVPROC __glewSecondaryColor3hNV = NULL; +PFNGLSECONDARYCOLOR3HVNVPROC __glewSecondaryColor3hvNV = NULL; +PFNGLTEXCOORD1HNVPROC __glewTexCoord1hNV = NULL; +PFNGLTEXCOORD1HVNVPROC __glewTexCoord1hvNV = NULL; +PFNGLTEXCOORD2HNVPROC __glewTexCoord2hNV = NULL; +PFNGLTEXCOORD2HVNVPROC __glewTexCoord2hvNV = NULL; +PFNGLTEXCOORD3HNVPROC __glewTexCoord3hNV = NULL; +PFNGLTEXCOORD3HVNVPROC __glewTexCoord3hvNV = NULL; +PFNGLTEXCOORD4HNVPROC __glewTexCoord4hNV = NULL; +PFNGLTEXCOORD4HVNVPROC __glewTexCoord4hvNV = NULL; +PFNGLVERTEX2HNVPROC __glewVertex2hNV = NULL; +PFNGLVERTEX2HVNVPROC __glewVertex2hvNV = NULL; +PFNGLVERTEX3HNVPROC __glewVertex3hNV = NULL; +PFNGLVERTEX3HVNVPROC __glewVertex3hvNV = NULL; +PFNGLVERTEX4HNVPROC __glewVertex4hNV = NULL; +PFNGLVERTEX4HVNVPROC __glewVertex4hvNV = NULL; +PFNGLVERTEXATTRIB1HNVPROC __glewVertexAttrib1hNV = NULL; +PFNGLVERTEXATTRIB1HVNVPROC __glewVertexAttrib1hvNV = NULL; +PFNGLVERTEXATTRIB2HNVPROC __glewVertexAttrib2hNV = NULL; +PFNGLVERTEXATTRIB2HVNVPROC __glewVertexAttrib2hvNV = NULL; +PFNGLVERTEXATTRIB3HNVPROC __glewVertexAttrib3hNV = NULL; +PFNGLVERTEXATTRIB3HVNVPROC __glewVertexAttrib3hvNV = NULL; +PFNGLVERTEXATTRIB4HNVPROC __glewVertexAttrib4hNV = NULL; +PFNGLVERTEXATTRIB4HVNVPROC __glewVertexAttrib4hvNV = NULL; +PFNGLVERTEXATTRIBS1HVNVPROC __glewVertexAttribs1hvNV = NULL; +PFNGLVERTEXATTRIBS2HVNVPROC __glewVertexAttribs2hvNV = NULL; +PFNGLVERTEXATTRIBS3HVNVPROC __glewVertexAttribs3hvNV = NULL; +PFNGLVERTEXATTRIBS4HVNVPROC __glewVertexAttribs4hvNV = NULL; +PFNGLVERTEXWEIGHTHNVPROC __glewVertexWeighthNV = NULL; +PFNGLVERTEXWEIGHTHVNVPROC __glewVertexWeighthvNV = NULL; + +PFNGLVERTEXATTRIBDIVISORNVPROC __glewVertexAttribDivisorNV = NULL; + +PFNGLGETINTERNALFORMATSAMPLEIVNVPROC __glewGetInternalformatSampleivNV = NULL; + +PFNGLUNIFORMMATRIX2X3FVNVPROC __glewUniformMatrix2x3fvNV = NULL; +PFNGLUNIFORMMATRIX2X4FVNVPROC __glewUniformMatrix2x4fvNV = NULL; +PFNGLUNIFORMMATRIX3X2FVNVPROC __glewUniformMatrix3x2fvNV = NULL; +PFNGLUNIFORMMATRIX3X4FVNVPROC __glewUniformMatrix3x4fvNV = NULL; +PFNGLUNIFORMMATRIX4X2FVNVPROC __glewUniformMatrix4x2fvNV = NULL; +PFNGLUNIFORMMATRIX4X3FVNVPROC __glewUniformMatrix4x3fvNV = NULL; + +PFNGLBEGINOCCLUSIONQUERYNVPROC __glewBeginOcclusionQueryNV = NULL; +PFNGLDELETEOCCLUSIONQUERIESNVPROC __glewDeleteOcclusionQueriesNV = NULL; +PFNGLENDOCCLUSIONQUERYNVPROC __glewEndOcclusionQueryNV = NULL; +PFNGLGENOCCLUSIONQUERIESNVPROC __glewGenOcclusionQueriesNV = NULL; +PFNGLGETOCCLUSIONQUERYIVNVPROC __glewGetOcclusionQueryivNV = NULL; +PFNGLGETOCCLUSIONQUERYUIVNVPROC __glewGetOcclusionQueryuivNV = NULL; +PFNGLISOCCLUSIONQUERYNVPROC __glewIsOcclusionQueryNV = NULL; + +PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC __glewProgramBufferParametersIivNV = NULL; +PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC __glewProgramBufferParametersIuivNV = NULL; +PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC __glewProgramBufferParametersfvNV = NULL; + +PFNGLCOPYPATHNVPROC __glewCopyPathNV = NULL; +PFNGLCOVERFILLPATHINSTANCEDNVPROC __glewCoverFillPathInstancedNV = NULL; +PFNGLCOVERFILLPATHNVPROC __glewCoverFillPathNV = NULL; +PFNGLCOVERSTROKEPATHINSTANCEDNVPROC __glewCoverStrokePathInstancedNV = NULL; +PFNGLCOVERSTROKEPATHNVPROC __glewCoverStrokePathNV = NULL; +PFNGLDELETEPATHSNVPROC __glewDeletePathsNV = NULL; +PFNGLGENPATHSNVPROC __glewGenPathsNV = NULL; +PFNGLGETPATHCOLORGENFVNVPROC __glewGetPathColorGenfvNV = NULL; +PFNGLGETPATHCOLORGENIVNVPROC __glewGetPathColorGenivNV = NULL; +PFNGLGETPATHCOMMANDSNVPROC __glewGetPathCommandsNV = NULL; +PFNGLGETPATHCOORDSNVPROC __glewGetPathCoordsNV = NULL; +PFNGLGETPATHDASHARRAYNVPROC __glewGetPathDashArrayNV = NULL; +PFNGLGETPATHLENGTHNVPROC __glewGetPathLengthNV = NULL; +PFNGLGETPATHMETRICRANGENVPROC __glewGetPathMetricRangeNV = NULL; +PFNGLGETPATHMETRICSNVPROC __glewGetPathMetricsNV = NULL; +PFNGLGETPATHPARAMETERFVNVPROC __glewGetPathParameterfvNV = NULL; +PFNGLGETPATHPARAMETERIVNVPROC __glewGetPathParameterivNV = NULL; +PFNGLGETPATHSPACINGNVPROC __glewGetPathSpacingNV = NULL; +PFNGLGETPATHTEXGENFVNVPROC __glewGetPathTexGenfvNV = NULL; +PFNGLGETPATHTEXGENIVNVPROC __glewGetPathTexGenivNV = NULL; +PFNGLGETPROGRAMRESOURCEFVNVPROC __glewGetProgramResourcefvNV = NULL; +PFNGLINTERPOLATEPATHSNVPROC __glewInterpolatePathsNV = NULL; +PFNGLISPATHNVPROC __glewIsPathNV = NULL; +PFNGLISPOINTINFILLPATHNVPROC __glewIsPointInFillPathNV = NULL; +PFNGLISPOINTINSTROKEPATHNVPROC __glewIsPointInStrokePathNV = NULL; +PFNGLMATRIXLOAD3X2FNVPROC __glewMatrixLoad3x2fNV = NULL; +PFNGLMATRIXLOAD3X3FNVPROC __glewMatrixLoad3x3fNV = NULL; +PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC __glewMatrixLoadTranspose3x3fNV = NULL; +PFNGLMATRIXMULT3X2FNVPROC __glewMatrixMult3x2fNV = NULL; +PFNGLMATRIXMULT3X3FNVPROC __glewMatrixMult3x3fNV = NULL; +PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC __glewMatrixMultTranspose3x3fNV = NULL; +PFNGLPATHCOLORGENNVPROC __glewPathColorGenNV = NULL; +PFNGLPATHCOMMANDSNVPROC __glewPathCommandsNV = NULL; +PFNGLPATHCOORDSNVPROC __glewPathCoordsNV = NULL; +PFNGLPATHCOVERDEPTHFUNCNVPROC __glewPathCoverDepthFuncNV = NULL; +PFNGLPATHDASHARRAYNVPROC __glewPathDashArrayNV = NULL; +PFNGLPATHFOGGENNVPROC __glewPathFogGenNV = NULL; +PFNGLPATHGLYPHINDEXARRAYNVPROC __glewPathGlyphIndexArrayNV = NULL; +PFNGLPATHGLYPHINDEXRANGENVPROC __glewPathGlyphIndexRangeNV = NULL; +PFNGLPATHGLYPHRANGENVPROC __glewPathGlyphRangeNV = NULL; +PFNGLPATHGLYPHSNVPROC __glewPathGlyphsNV = NULL; +PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC __glewPathMemoryGlyphIndexArrayNV = NULL; +PFNGLPATHPARAMETERFNVPROC __glewPathParameterfNV = NULL; +PFNGLPATHPARAMETERFVNVPROC __glewPathParameterfvNV = NULL; +PFNGLPATHPARAMETERINVPROC __glewPathParameteriNV = NULL; +PFNGLPATHPARAMETERIVNVPROC __glewPathParameterivNV = NULL; +PFNGLPATHSTENCILDEPTHOFFSETNVPROC __glewPathStencilDepthOffsetNV = NULL; +PFNGLPATHSTENCILFUNCNVPROC __glewPathStencilFuncNV = NULL; +PFNGLPATHSTRINGNVPROC __glewPathStringNV = NULL; +PFNGLPATHSUBCOMMANDSNVPROC __glewPathSubCommandsNV = NULL; +PFNGLPATHSUBCOORDSNVPROC __glewPathSubCoordsNV = NULL; +PFNGLPATHTEXGENNVPROC __glewPathTexGenNV = NULL; +PFNGLPOINTALONGPATHNVPROC __glewPointAlongPathNV = NULL; +PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC __glewProgramPathFragmentInputGenNV = NULL; +PFNGLSTENCILFILLPATHINSTANCEDNVPROC __glewStencilFillPathInstancedNV = NULL; +PFNGLSTENCILFILLPATHNVPROC __glewStencilFillPathNV = NULL; +PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC __glewStencilStrokePathInstancedNV = NULL; +PFNGLSTENCILSTROKEPATHNVPROC __glewStencilStrokePathNV = NULL; +PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC __glewStencilThenCoverFillPathInstancedNV = NULL; +PFNGLSTENCILTHENCOVERFILLPATHNVPROC __glewStencilThenCoverFillPathNV = NULL; +PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC __glewStencilThenCoverStrokePathInstancedNV = NULL; +PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC __glewStencilThenCoverStrokePathNV = NULL; +PFNGLTRANSFORMPATHNVPROC __glewTransformPathNV = NULL; +PFNGLWEIGHTPATHSNVPROC __glewWeightPathsNV = NULL; + +PFNGLFLUSHPIXELDATARANGENVPROC __glewFlushPixelDataRangeNV = NULL; +PFNGLPIXELDATARANGENVPROC __glewPixelDataRangeNV = NULL; + +PFNGLPOINTPARAMETERINVPROC __glewPointParameteriNV = NULL; +PFNGLPOINTPARAMETERIVNVPROC __glewPointParameterivNV = NULL; + +PFNGLPOLYGONMODENVPROC __glewPolygonModeNV = NULL; + +PFNGLGETVIDEOI64VNVPROC __glewGetVideoi64vNV = NULL; +PFNGLGETVIDEOIVNVPROC __glewGetVideoivNV = NULL; +PFNGLGETVIDEOUI64VNVPROC __glewGetVideoui64vNV = NULL; +PFNGLGETVIDEOUIVNVPROC __glewGetVideouivNV = NULL; +PFNGLPRESENTFRAMEDUALFILLNVPROC __glewPresentFrameDualFillNV = NULL; +PFNGLPRESENTFRAMEKEYEDNVPROC __glewPresentFrameKeyedNV = NULL; + +PFNGLPRIMITIVERESTARTINDEXNVPROC __glewPrimitiveRestartIndexNV = NULL; +PFNGLPRIMITIVERESTARTNVPROC __glewPrimitiveRestartNV = NULL; + +PFNGLCOMBINERINPUTNVPROC __glewCombinerInputNV = NULL; +PFNGLCOMBINEROUTPUTNVPROC __glewCombinerOutputNV = NULL; +PFNGLCOMBINERPARAMETERFNVPROC __glewCombinerParameterfNV = NULL; +PFNGLCOMBINERPARAMETERFVNVPROC __glewCombinerParameterfvNV = NULL; +PFNGLCOMBINERPARAMETERINVPROC __glewCombinerParameteriNV = NULL; +PFNGLCOMBINERPARAMETERIVNVPROC __glewCombinerParameterivNV = NULL; +PFNGLFINALCOMBINERINPUTNVPROC __glewFinalCombinerInputNV = NULL; +PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC __glewGetCombinerInputParameterfvNV = NULL; +PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC __glewGetCombinerInputParameterivNV = NULL; +PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC __glewGetCombinerOutputParameterfvNV = NULL; +PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC __glewGetCombinerOutputParameterivNV = NULL; +PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC __glewGetFinalCombinerInputParameterfvNV = NULL; +PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC __glewGetFinalCombinerInputParameterivNV = NULL; + +PFNGLCOMBINERSTAGEPARAMETERFVNVPROC __glewCombinerStageParameterfvNV = NULL; +PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC __glewGetCombinerStageParameterfvNV = NULL; + +PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC __glewFramebufferSampleLocationsfvNV = NULL; +PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC __glewNamedFramebufferSampleLocationsfvNV = NULL; + +PFNGLGETBUFFERPARAMETERUI64VNVPROC __glewGetBufferParameterui64vNV = NULL; +PFNGLGETINTEGERUI64VNVPROC __glewGetIntegerui64vNV = NULL; +PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC __glewGetNamedBufferParameterui64vNV = NULL; +PFNGLISBUFFERRESIDENTNVPROC __glewIsBufferResidentNV = NULL; +PFNGLISNAMEDBUFFERRESIDENTNVPROC __glewIsNamedBufferResidentNV = NULL; +PFNGLMAKEBUFFERNONRESIDENTNVPROC __glewMakeBufferNonResidentNV = NULL; +PFNGLMAKEBUFFERRESIDENTNVPROC __glewMakeBufferResidentNV = NULL; +PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC __glewMakeNamedBufferNonResidentNV = NULL; +PFNGLMAKENAMEDBUFFERRESIDENTNVPROC __glewMakeNamedBufferResidentNV = NULL; +PFNGLPROGRAMUNIFORMUI64NVPROC __glewProgramUniformui64NV = NULL; +PFNGLPROGRAMUNIFORMUI64VNVPROC __glewProgramUniformui64vNV = NULL; +PFNGLUNIFORMUI64NVPROC __glewUniformui64NV = NULL; +PFNGLUNIFORMUI64VNVPROC __glewUniformui64vNV = NULL; + +PFNGLCOMPRESSEDTEXIMAGE3DNVPROC __glewCompressedTexImage3DNV = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DNVPROC __glewCompressedTexSubImage3DNV = NULL; +PFNGLCOPYTEXSUBIMAGE3DNVPROC __glewCopyTexSubImage3DNV = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERNVPROC __glewFramebufferTextureLayerNV = NULL; +PFNGLTEXIMAGE3DNVPROC __glewTexImage3DNV = NULL; +PFNGLTEXSUBIMAGE3DNVPROC __glewTexSubImage3DNV = NULL; + +PFNGLTEXTUREBARRIERNVPROC __glewTextureBarrierNV = NULL; + +PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC __glewTexImage2DMultisampleCoverageNV = NULL; +PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC __glewTexImage3DMultisampleCoverageNV = NULL; +PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC __glewTextureImage2DMultisampleCoverageNV = NULL; +PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC __glewTextureImage2DMultisampleNV = NULL; +PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC __glewTextureImage3DMultisampleCoverageNV = NULL; +PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC __glewTextureImage3DMultisampleNV = NULL; + +PFNGLACTIVEVARYINGNVPROC __glewActiveVaryingNV = NULL; +PFNGLBEGINTRANSFORMFEEDBACKNVPROC __glewBeginTransformFeedbackNV = NULL; +PFNGLBINDBUFFERBASENVPROC __glewBindBufferBaseNV = NULL; +PFNGLBINDBUFFEROFFSETNVPROC __glewBindBufferOffsetNV = NULL; +PFNGLBINDBUFFERRANGENVPROC __glewBindBufferRangeNV = NULL; +PFNGLENDTRANSFORMFEEDBACKNVPROC __glewEndTransformFeedbackNV = NULL; +PFNGLGETACTIVEVARYINGNVPROC __glewGetActiveVaryingNV = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC __glewGetTransformFeedbackVaryingNV = NULL; +PFNGLGETVARYINGLOCATIONNVPROC __glewGetVaryingLocationNV = NULL; +PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC __glewTransformFeedbackAttribsNV = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC __glewTransformFeedbackVaryingsNV = NULL; + +PFNGLBINDTRANSFORMFEEDBACKNVPROC __glewBindTransformFeedbackNV = NULL; +PFNGLDELETETRANSFORMFEEDBACKSNVPROC __glewDeleteTransformFeedbacksNV = NULL; +PFNGLDRAWTRANSFORMFEEDBACKNVPROC __glewDrawTransformFeedbackNV = NULL; +PFNGLGENTRANSFORMFEEDBACKSNVPROC __glewGenTransformFeedbacksNV = NULL; +PFNGLISTRANSFORMFEEDBACKNVPROC __glewIsTransformFeedbackNV = NULL; +PFNGLPAUSETRANSFORMFEEDBACKNVPROC __glewPauseTransformFeedbackNV = NULL; +PFNGLRESUMETRANSFORMFEEDBACKNVPROC __glewResumeTransformFeedbackNV = NULL; + +PFNGLVDPAUFININVPROC __glewVDPAUFiniNV = NULL; +PFNGLVDPAUGETSURFACEIVNVPROC __glewVDPAUGetSurfaceivNV = NULL; +PFNGLVDPAUINITNVPROC __glewVDPAUInitNV = NULL; +PFNGLVDPAUISSURFACENVPROC __glewVDPAUIsSurfaceNV = NULL; +PFNGLVDPAUMAPSURFACESNVPROC __glewVDPAUMapSurfacesNV = NULL; +PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC __glewVDPAURegisterOutputSurfaceNV = NULL; +PFNGLVDPAUREGISTERVIDEOSURFACENVPROC __glewVDPAURegisterVideoSurfaceNV = NULL; +PFNGLVDPAUSURFACEACCESSNVPROC __glewVDPAUSurfaceAccessNV = NULL; +PFNGLVDPAUUNMAPSURFACESNVPROC __glewVDPAUUnmapSurfacesNV = NULL; +PFNGLVDPAUUNREGISTERSURFACENVPROC __glewVDPAUUnregisterSurfaceNV = NULL; + +PFNGLFLUSHVERTEXARRAYRANGENVPROC __glewFlushVertexArrayRangeNV = NULL; +PFNGLVERTEXARRAYRANGENVPROC __glewVertexArrayRangeNV = NULL; + +PFNGLGETVERTEXATTRIBLI64VNVPROC __glewGetVertexAttribLi64vNV = NULL; +PFNGLGETVERTEXATTRIBLUI64VNVPROC __glewGetVertexAttribLui64vNV = NULL; +PFNGLVERTEXATTRIBL1I64NVPROC __glewVertexAttribL1i64NV = NULL; +PFNGLVERTEXATTRIBL1I64VNVPROC __glewVertexAttribL1i64vNV = NULL; +PFNGLVERTEXATTRIBL1UI64NVPROC __glewVertexAttribL1ui64NV = NULL; +PFNGLVERTEXATTRIBL1UI64VNVPROC __glewVertexAttribL1ui64vNV = NULL; +PFNGLVERTEXATTRIBL2I64NVPROC __glewVertexAttribL2i64NV = NULL; +PFNGLVERTEXATTRIBL2I64VNVPROC __glewVertexAttribL2i64vNV = NULL; +PFNGLVERTEXATTRIBL2UI64NVPROC __glewVertexAttribL2ui64NV = NULL; +PFNGLVERTEXATTRIBL2UI64VNVPROC __glewVertexAttribL2ui64vNV = NULL; +PFNGLVERTEXATTRIBL3I64NVPROC __glewVertexAttribL3i64NV = NULL; +PFNGLVERTEXATTRIBL3I64VNVPROC __glewVertexAttribL3i64vNV = NULL; +PFNGLVERTEXATTRIBL3UI64NVPROC __glewVertexAttribL3ui64NV = NULL; +PFNGLVERTEXATTRIBL3UI64VNVPROC __glewVertexAttribL3ui64vNV = NULL; +PFNGLVERTEXATTRIBL4I64NVPROC __glewVertexAttribL4i64NV = NULL; +PFNGLVERTEXATTRIBL4I64VNVPROC __glewVertexAttribL4i64vNV = NULL; +PFNGLVERTEXATTRIBL4UI64NVPROC __glewVertexAttribL4ui64NV = NULL; +PFNGLVERTEXATTRIBL4UI64VNVPROC __glewVertexAttribL4ui64vNV = NULL; +PFNGLVERTEXATTRIBLFORMATNVPROC __glewVertexAttribLFormatNV = NULL; + +PFNGLBUFFERADDRESSRANGENVPROC __glewBufferAddressRangeNV = NULL; +PFNGLCOLORFORMATNVPROC __glewColorFormatNV = NULL; +PFNGLEDGEFLAGFORMATNVPROC __glewEdgeFlagFormatNV = NULL; +PFNGLFOGCOORDFORMATNVPROC __glewFogCoordFormatNV = NULL; +PFNGLGETINTEGERUI64I_VNVPROC __glewGetIntegerui64i_vNV = NULL; +PFNGLINDEXFORMATNVPROC __glewIndexFormatNV = NULL; +PFNGLNORMALFORMATNVPROC __glewNormalFormatNV = NULL; +PFNGLSECONDARYCOLORFORMATNVPROC __glewSecondaryColorFormatNV = NULL; +PFNGLTEXCOORDFORMATNVPROC __glewTexCoordFormatNV = NULL; +PFNGLVERTEXATTRIBFORMATNVPROC __glewVertexAttribFormatNV = NULL; +PFNGLVERTEXATTRIBIFORMATNVPROC __glewVertexAttribIFormatNV = NULL; +PFNGLVERTEXFORMATNVPROC __glewVertexFormatNV = NULL; + +PFNGLAREPROGRAMSRESIDENTNVPROC __glewAreProgramsResidentNV = NULL; +PFNGLBINDPROGRAMNVPROC __glewBindProgramNV = NULL; +PFNGLDELETEPROGRAMSNVPROC __glewDeleteProgramsNV = NULL; +PFNGLEXECUTEPROGRAMNVPROC __glewExecuteProgramNV = NULL; +PFNGLGENPROGRAMSNVPROC __glewGenProgramsNV = NULL; +PFNGLGETPROGRAMPARAMETERDVNVPROC __glewGetProgramParameterdvNV = NULL; +PFNGLGETPROGRAMPARAMETERFVNVPROC __glewGetProgramParameterfvNV = NULL; +PFNGLGETPROGRAMSTRINGNVPROC __glewGetProgramStringNV = NULL; +PFNGLGETPROGRAMIVNVPROC __glewGetProgramivNV = NULL; +PFNGLGETTRACKMATRIXIVNVPROC __glewGetTrackMatrixivNV = NULL; +PFNGLGETVERTEXATTRIBPOINTERVNVPROC __glewGetVertexAttribPointervNV = NULL; +PFNGLGETVERTEXATTRIBDVNVPROC __glewGetVertexAttribdvNV = NULL; +PFNGLGETVERTEXATTRIBFVNVPROC __glewGetVertexAttribfvNV = NULL; +PFNGLGETVERTEXATTRIBIVNVPROC __glewGetVertexAttribivNV = NULL; +PFNGLISPROGRAMNVPROC __glewIsProgramNV = NULL; +PFNGLLOADPROGRAMNVPROC __glewLoadProgramNV = NULL; +PFNGLPROGRAMPARAMETER4DNVPROC __glewProgramParameter4dNV = NULL; +PFNGLPROGRAMPARAMETER4DVNVPROC __glewProgramParameter4dvNV = NULL; +PFNGLPROGRAMPARAMETER4FNVPROC __glewProgramParameter4fNV = NULL; +PFNGLPROGRAMPARAMETER4FVNVPROC __glewProgramParameter4fvNV = NULL; +PFNGLPROGRAMPARAMETERS4DVNVPROC __glewProgramParameters4dvNV = NULL; +PFNGLPROGRAMPARAMETERS4FVNVPROC __glewProgramParameters4fvNV = NULL; +PFNGLREQUESTRESIDENTPROGRAMSNVPROC __glewRequestResidentProgramsNV = NULL; +PFNGLTRACKMATRIXNVPROC __glewTrackMatrixNV = NULL; +PFNGLVERTEXATTRIB1DNVPROC __glewVertexAttrib1dNV = NULL; +PFNGLVERTEXATTRIB1DVNVPROC __glewVertexAttrib1dvNV = NULL; +PFNGLVERTEXATTRIB1FNVPROC __glewVertexAttrib1fNV = NULL; +PFNGLVERTEXATTRIB1FVNVPROC __glewVertexAttrib1fvNV = NULL; +PFNGLVERTEXATTRIB1SNVPROC __glewVertexAttrib1sNV = NULL; +PFNGLVERTEXATTRIB1SVNVPROC __glewVertexAttrib1svNV = NULL; +PFNGLVERTEXATTRIB2DNVPROC __glewVertexAttrib2dNV = NULL; +PFNGLVERTEXATTRIB2DVNVPROC __glewVertexAttrib2dvNV = NULL; +PFNGLVERTEXATTRIB2FNVPROC __glewVertexAttrib2fNV = NULL; +PFNGLVERTEXATTRIB2FVNVPROC __glewVertexAttrib2fvNV = NULL; +PFNGLVERTEXATTRIB2SNVPROC __glewVertexAttrib2sNV = NULL; +PFNGLVERTEXATTRIB2SVNVPROC __glewVertexAttrib2svNV = NULL; +PFNGLVERTEXATTRIB3DNVPROC __glewVertexAttrib3dNV = NULL; +PFNGLVERTEXATTRIB3DVNVPROC __glewVertexAttrib3dvNV = NULL; +PFNGLVERTEXATTRIB3FNVPROC __glewVertexAttrib3fNV = NULL; +PFNGLVERTEXATTRIB3FVNVPROC __glewVertexAttrib3fvNV = NULL; +PFNGLVERTEXATTRIB3SNVPROC __glewVertexAttrib3sNV = NULL; +PFNGLVERTEXATTRIB3SVNVPROC __glewVertexAttrib3svNV = NULL; +PFNGLVERTEXATTRIB4DNVPROC __glewVertexAttrib4dNV = NULL; +PFNGLVERTEXATTRIB4DVNVPROC __glewVertexAttrib4dvNV = NULL; +PFNGLVERTEXATTRIB4FNVPROC __glewVertexAttrib4fNV = NULL; +PFNGLVERTEXATTRIB4FVNVPROC __glewVertexAttrib4fvNV = NULL; +PFNGLVERTEXATTRIB4SNVPROC __glewVertexAttrib4sNV = NULL; +PFNGLVERTEXATTRIB4SVNVPROC __glewVertexAttrib4svNV = NULL; +PFNGLVERTEXATTRIB4UBNVPROC __glewVertexAttrib4ubNV = NULL; +PFNGLVERTEXATTRIB4UBVNVPROC __glewVertexAttrib4ubvNV = NULL; +PFNGLVERTEXATTRIBPOINTERNVPROC __glewVertexAttribPointerNV = NULL; +PFNGLVERTEXATTRIBS1DVNVPROC __glewVertexAttribs1dvNV = NULL; +PFNGLVERTEXATTRIBS1FVNVPROC __glewVertexAttribs1fvNV = NULL; +PFNGLVERTEXATTRIBS1SVNVPROC __glewVertexAttribs1svNV = NULL; +PFNGLVERTEXATTRIBS2DVNVPROC __glewVertexAttribs2dvNV = NULL; +PFNGLVERTEXATTRIBS2FVNVPROC __glewVertexAttribs2fvNV = NULL; +PFNGLVERTEXATTRIBS2SVNVPROC __glewVertexAttribs2svNV = NULL; +PFNGLVERTEXATTRIBS3DVNVPROC __glewVertexAttribs3dvNV = NULL; +PFNGLVERTEXATTRIBS3FVNVPROC __glewVertexAttribs3fvNV = NULL; +PFNGLVERTEXATTRIBS3SVNVPROC __glewVertexAttribs3svNV = NULL; +PFNGLVERTEXATTRIBS4DVNVPROC __glewVertexAttribs4dvNV = NULL; +PFNGLVERTEXATTRIBS4FVNVPROC __glewVertexAttribs4fvNV = NULL; +PFNGLVERTEXATTRIBS4SVNVPROC __glewVertexAttribs4svNV = NULL; +PFNGLVERTEXATTRIBS4UBVNVPROC __glewVertexAttribs4ubvNV = NULL; + +PFNGLBEGINVIDEOCAPTURENVPROC __glewBeginVideoCaptureNV = NULL; +PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC __glewBindVideoCaptureStreamBufferNV = NULL; +PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC __glewBindVideoCaptureStreamTextureNV = NULL; +PFNGLENDVIDEOCAPTURENVPROC __glewEndVideoCaptureNV = NULL; +PFNGLGETVIDEOCAPTURESTREAMDVNVPROC __glewGetVideoCaptureStreamdvNV = NULL; +PFNGLGETVIDEOCAPTURESTREAMFVNVPROC __glewGetVideoCaptureStreamfvNV = NULL; +PFNGLGETVIDEOCAPTURESTREAMIVNVPROC __glewGetVideoCaptureStreamivNV = NULL; +PFNGLGETVIDEOCAPTUREIVNVPROC __glewGetVideoCaptureivNV = NULL; +PFNGLVIDEOCAPTURENVPROC __glewVideoCaptureNV = NULL; +PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC __glewVideoCaptureStreamParameterdvNV = NULL; +PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC __glewVideoCaptureStreamParameterfvNV = NULL; +PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC __glewVideoCaptureStreamParameterivNV = NULL; + +PFNGLDEPTHRANGEARRAYFVNVPROC __glewDepthRangeArrayfvNV = NULL; +PFNGLDEPTHRANGEINDEXEDFNVPROC __glewDepthRangeIndexedfNV = NULL; +PFNGLDISABLEINVPROC __glewDisableiNV = NULL; +PFNGLENABLEINVPROC __glewEnableiNV = NULL; +PFNGLGETFLOATI_VNVPROC __glewGetFloati_vNV = NULL; +PFNGLISENABLEDINVPROC __glewIsEnablediNV = NULL; +PFNGLSCISSORARRAYVNVPROC __glewScissorArrayvNV = NULL; +PFNGLSCISSORINDEXEDNVPROC __glewScissorIndexedNV = NULL; +PFNGLSCISSORINDEXEDVNVPROC __glewScissorIndexedvNV = NULL; +PFNGLVIEWPORTARRAYVNVPROC __glewViewportArrayvNV = NULL; +PFNGLVIEWPORTINDEXEDFNVPROC __glewViewportIndexedfNV = NULL; +PFNGLVIEWPORTINDEXEDFVNVPROC __glewViewportIndexedfvNV = NULL; + +PFNGLVIEWPORTSWIZZLENVPROC __glewViewportSwizzleNV = NULL; + +PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __glewFramebufferTextureMultiviewOVR = NULL; + +PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __glewFramebufferTextureMultisampleMultiviewOVR = NULL; + +PFNGLALPHAFUNCQCOMPROC __glewAlphaFuncQCOM = NULL; + +PFNGLDISABLEDRIVERCONTROLQCOMPROC __glewDisableDriverControlQCOM = NULL; +PFNGLENABLEDRIVERCONTROLQCOMPROC __glewEnableDriverControlQCOM = NULL; +PFNGLGETDRIVERCONTROLSTRINGQCOMPROC __glewGetDriverControlStringQCOM = NULL; +PFNGLGETDRIVERCONTROLSQCOMPROC __glewGetDriverControlsQCOM = NULL; + +PFNGLEXTGETBUFFERPOINTERVQCOMPROC __glewExtGetBufferPointervQCOM = NULL; +PFNGLEXTGETBUFFERSQCOMPROC __glewExtGetBuffersQCOM = NULL; +PFNGLEXTGETFRAMEBUFFERSQCOMPROC __glewExtGetFramebuffersQCOM = NULL; +PFNGLEXTGETRENDERBUFFERSQCOMPROC __glewExtGetRenderbuffersQCOM = NULL; +PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC __glewExtGetTexLevelParameterivQCOM = NULL; +PFNGLEXTGETTEXSUBIMAGEQCOMPROC __glewExtGetTexSubImageQCOM = NULL; +PFNGLEXTGETTEXTURESQCOMPROC __glewExtGetTexturesQCOM = NULL; +PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC __glewExtTexObjectStateOverrideiQCOM = NULL; + +PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC __glewExtGetProgramBinarySourceQCOM = NULL; +PFNGLEXTGETPROGRAMSQCOMPROC __glewExtGetProgramsQCOM = NULL; +PFNGLEXTGETSHADERSQCOMPROC __glewExtGetShadersQCOM = NULL; +PFNGLEXTISPROGRAMBINARYQCOMPROC __glewExtIsProgramBinaryQCOM = NULL; + +PFNGLFRAMEBUFFERFOVEATIONCONFIGQCOMPROC __glewFramebufferFoveationConfigQCOM = NULL; +PFNGLFRAMEBUFFERFOVEATIONPARAMETERSQCOMPROC __glewFramebufferFoveationParametersQCOM = NULL; + +PFNGLFRAMEBUFFERFETCHBARRIERQCOMPROC __glewFramebufferFetchBarrierQCOM = NULL; + +PFNGLENDTILINGQCOMPROC __glewEndTilingQCOM = NULL; +PFNGLSTARTTILINGQCOMPROC __glewStartTilingQCOM = NULL; + +PFNGLALPHAFUNCXPROC __glewAlphaFuncx = NULL; +PFNGLCLEARCOLORXPROC __glewClearColorx = NULL; +PFNGLCLEARDEPTHXPROC __glewClearDepthx = NULL; +PFNGLCOLOR4XPROC __glewColor4x = NULL; +PFNGLDEPTHRANGEXPROC __glewDepthRangex = NULL; +PFNGLFOGXPROC __glewFogx = NULL; +PFNGLFOGXVPROC __glewFogxv = NULL; +PFNGLFRUSTUMFPROC __glewFrustumf = NULL; +PFNGLFRUSTUMXPROC __glewFrustumx = NULL; +PFNGLLIGHTMODELXPROC __glewLightModelx = NULL; +PFNGLLIGHTMODELXVPROC __glewLightModelxv = NULL; +PFNGLLIGHTXPROC __glewLightx = NULL; +PFNGLLIGHTXVPROC __glewLightxv = NULL; +PFNGLLINEWIDTHXPROC __glewLineWidthx = NULL; +PFNGLLOADMATRIXXPROC __glewLoadMatrixx = NULL; +PFNGLMATERIALXPROC __glewMaterialx = NULL; +PFNGLMATERIALXVPROC __glewMaterialxv = NULL; +PFNGLMULTMATRIXXPROC __glewMultMatrixx = NULL; +PFNGLMULTITEXCOORD4XPROC __glewMultiTexCoord4x = NULL; +PFNGLNORMAL3XPROC __glewNormal3x = NULL; +PFNGLORTHOFPROC __glewOrthof = NULL; +PFNGLORTHOXPROC __glewOrthox = NULL; +PFNGLPOINTSIZEXPROC __glewPointSizex = NULL; +PFNGLPOLYGONOFFSETXPROC __glewPolygonOffsetx = NULL; +PFNGLROTATEXPROC __glewRotatex = NULL; +PFNGLSAMPLECOVERAGEXPROC __glewSampleCoveragex = NULL; +PFNGLSCALEXPROC __glewScalex = NULL; +PFNGLTEXENVXPROC __glewTexEnvx = NULL; +PFNGLTEXENVXVPROC __glewTexEnvxv = NULL; +PFNGLTEXPARAMETERXPROC __glewTexParameterx = NULL; +PFNGLTRANSLATEXPROC __glewTranslatex = NULL; + +PFNGLCLIPPLANEFPROC __glewClipPlanef = NULL; +PFNGLCLIPPLANEXPROC __glewClipPlanex = NULL; +PFNGLGETCLIPPLANEFPROC __glewGetClipPlanef = NULL; +PFNGLGETCLIPPLANEXPROC __glewGetClipPlanex = NULL; +PFNGLGETFIXEDVPROC __glewGetFixedv = NULL; +PFNGLGETLIGHTXVPROC __glewGetLightxv = NULL; +PFNGLGETMATERIALXVPROC __glewGetMaterialxv = NULL; +PFNGLGETTEXENVXVPROC __glewGetTexEnvxv = NULL; +PFNGLGETTEXPARAMETERXVPROC __glewGetTexParameterxv = NULL; +PFNGLPOINTPARAMETERXPROC __glewPointParameterx = NULL; +PFNGLPOINTPARAMETERXVPROC __glewPointParameterxv = NULL; +PFNGLPOINTSIZEPOINTEROESPROC __glewPointSizePointerOES = NULL; +PFNGLTEXPARAMETERXVPROC __glewTexParameterxv = NULL; + +PFNGLERRORSTRINGREGALPROC __glewErrorStringREGAL = NULL; + +PFNGLGETEXTENSIONREGALPROC __glewGetExtensionREGAL = NULL; +PFNGLISSUPPORTEDREGALPROC __glewIsSupportedREGAL = NULL; + +PFNGLLOGMESSAGECALLBACKREGALPROC __glewLogMessageCallbackREGAL = NULL; + +PFNGLGETPROCADDRESSREGALPROC __glewGetProcAddressREGAL = NULL; + +PFNGLDETAILTEXFUNCSGISPROC __glewDetailTexFuncSGIS = NULL; +PFNGLGETDETAILTEXFUNCSGISPROC __glewGetDetailTexFuncSGIS = NULL; + +PFNGLFOGFUNCSGISPROC __glewFogFuncSGIS = NULL; +PFNGLGETFOGFUNCSGISPROC __glewGetFogFuncSGIS = NULL; + +PFNGLSAMPLEMASKSGISPROC __glewSampleMaskSGIS = NULL; +PFNGLSAMPLEPATTERNSGISPROC __glewSamplePatternSGIS = NULL; + +PFNGLINTERLEAVEDTEXTURECOORDSETSSGISPROC __glewInterleavedTextureCoordSetsSGIS = NULL; +PFNGLSELECTTEXTURECOORDSETSGISPROC __glewSelectTextureCoordSetSGIS = NULL; +PFNGLSELECTTEXTURESGISPROC __glewSelectTextureSGIS = NULL; +PFNGLSELECTTEXTURETRANSFORMSGISPROC __glewSelectTextureTransformSGIS = NULL; + +PFNGLMULTISAMPLESUBRECTPOSSGISPROC __glewMultisampleSubRectPosSGIS = NULL; + +PFNGLGETSHARPENTEXFUNCSGISPROC __glewGetSharpenTexFuncSGIS = NULL; +PFNGLSHARPENTEXFUNCSGISPROC __glewSharpenTexFuncSGIS = NULL; + +PFNGLTEXIMAGE4DSGISPROC __glewTexImage4DSGIS = NULL; +PFNGLTEXSUBIMAGE4DSGISPROC __glewTexSubImage4DSGIS = NULL; + +PFNGLGETTEXFILTERFUNCSGISPROC __glewGetTexFilterFuncSGIS = NULL; +PFNGLTEXFILTERFUNCSGISPROC __glewTexFilterFuncSGIS = NULL; + +PFNGLASYNCMARKERSGIXPROC __glewAsyncMarkerSGIX = NULL; +PFNGLDELETEASYNCMARKERSSGIXPROC __glewDeleteAsyncMarkersSGIX = NULL; +PFNGLFINISHASYNCSGIXPROC __glewFinishAsyncSGIX = NULL; +PFNGLGENASYNCMARKERSSGIXPROC __glewGenAsyncMarkersSGIX = NULL; +PFNGLISASYNCMARKERSGIXPROC __glewIsAsyncMarkerSGIX = NULL; +PFNGLPOLLASYNCSGIXPROC __glewPollAsyncSGIX = NULL; + +PFNGLADDRESSSPACEPROC __glewAddressSpace = NULL; +PFNGLDATAPIPEPROC __glewDataPipe = NULL; + +PFNGLFLUSHRASTERSGIXPROC __glewFlushRasterSGIX = NULL; + +PFNGLFOGLAYERSSGIXPROC __glewFogLayersSGIX = NULL; +PFNGLGETFOGLAYERSSGIXPROC __glewGetFogLayersSGIX = NULL; + +PFNGLTEXTUREFOGSGIXPROC __glewTextureFogSGIX = NULL; + +PFNGLFRAGMENTCOLORMATERIALSGIXPROC __glewFragmentColorMaterialSGIX = NULL; +PFNGLFRAGMENTLIGHTMODELFSGIXPROC __glewFragmentLightModelfSGIX = NULL; +PFNGLFRAGMENTLIGHTMODELFVSGIXPROC __glewFragmentLightModelfvSGIX = NULL; +PFNGLFRAGMENTLIGHTMODELISGIXPROC __glewFragmentLightModeliSGIX = NULL; +PFNGLFRAGMENTLIGHTMODELIVSGIXPROC __glewFragmentLightModelivSGIX = NULL; +PFNGLFRAGMENTLIGHTFSGIXPROC __glewFragmentLightfSGIX = NULL; +PFNGLFRAGMENTLIGHTFVSGIXPROC __glewFragmentLightfvSGIX = NULL; +PFNGLFRAGMENTLIGHTISGIXPROC __glewFragmentLightiSGIX = NULL; +PFNGLFRAGMENTLIGHTIVSGIXPROC __glewFragmentLightivSGIX = NULL; +PFNGLFRAGMENTMATERIALFSGIXPROC __glewFragmentMaterialfSGIX = NULL; +PFNGLFRAGMENTMATERIALFVSGIXPROC __glewFragmentMaterialfvSGIX = NULL; +PFNGLFRAGMENTMATERIALISGIXPROC __glewFragmentMaterialiSGIX = NULL; +PFNGLFRAGMENTMATERIALIVSGIXPROC __glewFragmentMaterialivSGIX = NULL; +PFNGLGETFRAGMENTLIGHTFVSGIXPROC __glewGetFragmentLightfvSGIX = NULL; +PFNGLGETFRAGMENTLIGHTIVSGIXPROC __glewGetFragmentLightivSGIX = NULL; +PFNGLGETFRAGMENTMATERIALFVSGIXPROC __glewGetFragmentMaterialfvSGIX = NULL; +PFNGLGETFRAGMENTMATERIALIVSGIXPROC __glewGetFragmentMaterialivSGIX = NULL; + +PFNGLFRAMEZOOMSGIXPROC __glewFrameZoomSGIX = NULL; + +PFNGLIGLOOINTERFACESGIXPROC __glewIglooInterfaceSGIX = NULL; + +PFNGLALLOCMPEGPREDICTORSSGIXPROC __glewAllocMPEGPredictorsSGIX = NULL; +PFNGLDELETEMPEGPREDICTORSSGIXPROC __glewDeleteMPEGPredictorsSGIX = NULL; +PFNGLGENMPEGPREDICTORSSGIXPROC __glewGenMPEGPredictorsSGIX = NULL; +PFNGLGETMPEGPARAMETERFVSGIXPROC __glewGetMPEGParameterfvSGIX = NULL; +PFNGLGETMPEGPARAMETERIVSGIXPROC __glewGetMPEGParameterivSGIX = NULL; +PFNGLGETMPEGPREDICTORSGIXPROC __glewGetMPEGPredictorSGIX = NULL; +PFNGLGETMPEGQUANTTABLEUBVPROC __glewGetMPEGQuantTableubv = NULL; +PFNGLISMPEGPREDICTORSGIXPROC __glewIsMPEGPredictorSGIX = NULL; +PFNGLMPEGPREDICTORSGIXPROC __glewMPEGPredictorSGIX = NULL; +PFNGLMPEGQUANTTABLEUBVPROC __glewMPEGQuantTableubv = NULL; +PFNGLSWAPMPEGPREDICTORSSGIXPROC __glewSwapMPEGPredictorsSGIX = NULL; + +PFNGLGETNONLINLIGHTFVSGIXPROC __glewGetNonlinLightfvSGIX = NULL; +PFNGLGETNONLINMATERIALFVSGIXPROC __glewGetNonlinMaterialfvSGIX = NULL; +PFNGLNONLINLIGHTFVSGIXPROC __glewNonlinLightfvSGIX = NULL; +PFNGLNONLINMATERIALFVSGIXPROC __glewNonlinMaterialfvSGIX = NULL; + +PFNGLPIXELTEXGENSGIXPROC __glewPixelTexGenSGIX = NULL; + +PFNGLDEFORMSGIXPROC __glewDeformSGIX = NULL; +PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC __glewLoadIdentityDeformationMapSGIX = NULL; + +PFNGLMESHBREADTHSGIXPROC __glewMeshBreadthSGIX = NULL; +PFNGLMESHSTRIDESGIXPROC __glewMeshStrideSGIX = NULL; + +PFNGLREFERENCEPLANESGIXPROC __glewReferencePlaneSGIX = NULL; + +PFNGLSPRITEPARAMETERFSGIXPROC __glewSpriteParameterfSGIX = NULL; +PFNGLSPRITEPARAMETERFVSGIXPROC __glewSpriteParameterfvSGIX = NULL; +PFNGLSPRITEPARAMETERISGIXPROC __glewSpriteParameteriSGIX = NULL; +PFNGLSPRITEPARAMETERIVSGIXPROC __glewSpriteParameterivSGIX = NULL; + +PFNGLTAGSAMPLEBUFFERSGIXPROC __glewTagSampleBufferSGIX = NULL; + +PFNGLGETVECTOROPERATIONSGIXPROC __glewGetVectorOperationSGIX = NULL; +PFNGLVECTOROPERATIONSGIXPROC __glewVectorOperationSGIX = NULL; + +PFNGLAREVERTEXARRAYSRESIDENTSGIXPROC __glewAreVertexArraysResidentSGIX = NULL; +PFNGLBINDVERTEXARRAYSGIXPROC __glewBindVertexArraySGIX = NULL; +PFNGLDELETEVERTEXARRAYSSGIXPROC __glewDeleteVertexArraysSGIX = NULL; +PFNGLGENVERTEXARRAYSSGIXPROC __glewGenVertexArraysSGIX = NULL; +PFNGLISVERTEXARRAYSGIXPROC __glewIsVertexArraySGIX = NULL; +PFNGLPRIORITIZEVERTEXARRAYSSGIXPROC __glewPrioritizeVertexArraysSGIX = NULL; + +PFNGLCOLORTABLEPARAMETERFVSGIPROC __glewColorTableParameterfvSGI = NULL; +PFNGLCOLORTABLEPARAMETERIVSGIPROC __glewColorTableParameterivSGI = NULL; +PFNGLCOLORTABLESGIPROC __glewColorTableSGI = NULL; +PFNGLCOPYCOLORTABLESGIPROC __glewCopyColorTableSGI = NULL; +PFNGLGETCOLORTABLEPARAMETERFVSGIPROC __glewGetColorTableParameterfvSGI = NULL; +PFNGLGETCOLORTABLEPARAMETERIVSGIPROC __glewGetColorTableParameterivSGI = NULL; +PFNGLGETCOLORTABLESGIPROC __glewGetColorTableSGI = NULL; + +PFNGLGETPIXELTRANSFORMPARAMETERFVSGIPROC __glewGetPixelTransformParameterfvSGI = NULL; +PFNGLGETPIXELTRANSFORMPARAMETERIVSGIPROC __glewGetPixelTransformParameterivSGI = NULL; +PFNGLPIXELTRANSFORMPARAMETERFSGIPROC __glewPixelTransformParameterfSGI = NULL; +PFNGLPIXELTRANSFORMPARAMETERFVSGIPROC __glewPixelTransformParameterfvSGI = NULL; +PFNGLPIXELTRANSFORMPARAMETERISGIPROC __glewPixelTransformParameteriSGI = NULL; +PFNGLPIXELTRANSFORMPARAMETERIVSGIPROC __glewPixelTransformParameterivSGI = NULL; +PFNGLPIXELTRANSFORMSGIPROC __glewPixelTransformSGI = NULL; + +PFNGLFINISHTEXTURESUNXPROC __glewFinishTextureSUNX = NULL; + +PFNGLGLOBALALPHAFACTORBSUNPROC __glewGlobalAlphaFactorbSUN = NULL; +PFNGLGLOBALALPHAFACTORDSUNPROC __glewGlobalAlphaFactordSUN = NULL; +PFNGLGLOBALALPHAFACTORFSUNPROC __glewGlobalAlphaFactorfSUN = NULL; +PFNGLGLOBALALPHAFACTORISUNPROC __glewGlobalAlphaFactoriSUN = NULL; +PFNGLGLOBALALPHAFACTORSSUNPROC __glewGlobalAlphaFactorsSUN = NULL; +PFNGLGLOBALALPHAFACTORUBSUNPROC __glewGlobalAlphaFactorubSUN = NULL; +PFNGLGLOBALALPHAFACTORUISUNPROC __glewGlobalAlphaFactoruiSUN = NULL; +PFNGLGLOBALALPHAFACTORUSSUNPROC __glewGlobalAlphaFactorusSUN = NULL; + +PFNGLREADVIDEOPIXELSSUNPROC __glewReadVideoPixelsSUN = NULL; + +PFNGLREPLACEMENTCODEPOINTERSUNPROC __glewReplacementCodePointerSUN = NULL; +PFNGLREPLACEMENTCODEUBSUNPROC __glewReplacementCodeubSUN = NULL; +PFNGLREPLACEMENTCODEUBVSUNPROC __glewReplacementCodeubvSUN = NULL; +PFNGLREPLACEMENTCODEUISUNPROC __glewReplacementCodeuiSUN = NULL; +PFNGLREPLACEMENTCODEUIVSUNPROC __glewReplacementCodeuivSUN = NULL; +PFNGLREPLACEMENTCODEUSSUNPROC __glewReplacementCodeusSUN = NULL; +PFNGLREPLACEMENTCODEUSVSUNPROC __glewReplacementCodeusvSUN = NULL; + +PFNGLCOLOR3FVERTEX3FSUNPROC __glewColor3fVertex3fSUN = NULL; +PFNGLCOLOR3FVERTEX3FVSUNPROC __glewColor3fVertex3fvSUN = NULL; +PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC __glewColor4fNormal3fVertex3fSUN = NULL; +PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC __glewColor4fNormal3fVertex3fvSUN = NULL; +PFNGLCOLOR4UBVERTEX2FSUNPROC __glewColor4ubVertex2fSUN = NULL; +PFNGLCOLOR4UBVERTEX2FVSUNPROC __glewColor4ubVertex2fvSUN = NULL; +PFNGLCOLOR4UBVERTEX3FSUNPROC __glewColor4ubVertex3fSUN = NULL; +PFNGLCOLOR4UBVERTEX3FVSUNPROC __glewColor4ubVertex3fvSUN = NULL; +PFNGLNORMAL3FVERTEX3FSUNPROC __glewNormal3fVertex3fSUN = NULL; +PFNGLNORMAL3FVERTEX3FVSUNPROC __glewNormal3fVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC __glewReplacementCodeuiColor3fVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC __glewReplacementCodeuiColor3fVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC __glewReplacementCodeuiColor4fNormal3fVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC __glewReplacementCodeuiColor4fNormal3fVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC __glewReplacementCodeuiColor4ubVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC __glewReplacementCodeuiColor4ubVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC __glewReplacementCodeuiNormal3fVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC __glewReplacementCodeuiNormal3fVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC __glewReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC __glewReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC __glewReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC __glewReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC __glewReplacementCodeuiTexCoord2fVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC __glewReplacementCodeuiTexCoord2fVertex3fvSUN = NULL; +PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC __glewReplacementCodeuiVertex3fSUN = NULL; +PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC __glewReplacementCodeuiVertex3fvSUN = NULL; +PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC __glewTexCoord2fColor3fVertex3fSUN = NULL; +PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC __glewTexCoord2fColor3fVertex3fvSUN = NULL; +PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC __glewTexCoord2fColor4fNormal3fVertex3fSUN = NULL; +PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC __glewTexCoord2fColor4fNormal3fVertex3fvSUN = NULL; +PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC __glewTexCoord2fColor4ubVertex3fSUN = NULL; +PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC __glewTexCoord2fColor4ubVertex3fvSUN = NULL; +PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC __glewTexCoord2fNormal3fVertex3fSUN = NULL; +PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC __glewTexCoord2fNormal3fVertex3fvSUN = NULL; +PFNGLTEXCOORD2FVERTEX3FSUNPROC __glewTexCoord2fVertex3fSUN = NULL; +PFNGLTEXCOORD2FVERTEX3FVSUNPROC __glewTexCoord2fVertex3fvSUN = NULL; +PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC __glewTexCoord4fColor4fNormal3fVertex4fSUN = NULL; +PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC __glewTexCoord4fColor4fNormal3fVertex4fvSUN = NULL; +PFNGLTEXCOORD4FVERTEX4FSUNPROC __glewTexCoord4fVertex4fSUN = NULL; +PFNGLTEXCOORD4FVERTEX4FVSUNPROC __glewTexCoord4fVertex4fvSUN = NULL; + +PFNGLADDSWAPHINTRECTWINPROC __glewAddSwapHintRectWIN = NULL; + +GLboolean __GLEW_VERSION_1_1 = GL_FALSE; +GLboolean __GLEW_VERSION_1_2 = GL_FALSE; +GLboolean __GLEW_VERSION_1_2_1 = GL_FALSE; +GLboolean __GLEW_VERSION_1_3 = GL_FALSE; +GLboolean __GLEW_VERSION_1_4 = GL_FALSE; +GLboolean __GLEW_VERSION_1_5 = GL_FALSE; +GLboolean __GLEW_VERSION_2_0 = GL_FALSE; +GLboolean __GLEW_VERSION_2_1 = GL_FALSE; +GLboolean __GLEW_VERSION_3_0 = GL_FALSE; +GLboolean __GLEW_VERSION_3_1 = GL_FALSE; +GLboolean __GLEW_VERSION_3_2 = GL_FALSE; +GLboolean __GLEW_VERSION_3_3 = GL_FALSE; +GLboolean __GLEW_VERSION_4_0 = GL_FALSE; +GLboolean __GLEW_VERSION_4_1 = GL_FALSE; +GLboolean __GLEW_VERSION_4_2 = GL_FALSE; +GLboolean __GLEW_VERSION_4_3 = GL_FALSE; +GLboolean __GLEW_VERSION_4_4 = GL_FALSE; +GLboolean __GLEW_VERSION_4_5 = GL_FALSE; +GLboolean __GLEW_VERSION_4_6 = GL_FALSE; +GLboolean __GLEW_3DFX_multisample = GL_FALSE; +GLboolean __GLEW_3DFX_tbuffer = GL_FALSE; +GLboolean __GLEW_3DFX_texture_compression_FXT1 = GL_FALSE; +GLboolean __GLEW_AMD_blend_minmax_factor = GL_FALSE; +GLboolean __GLEW_AMD_compressed_3DC_texture = GL_FALSE; +GLboolean __GLEW_AMD_compressed_ATC_texture = GL_FALSE; +GLboolean __GLEW_AMD_conservative_depth = GL_FALSE; +GLboolean __GLEW_AMD_debug_output = GL_FALSE; +GLboolean __GLEW_AMD_depth_clamp_separate = GL_FALSE; +GLboolean __GLEW_AMD_draw_buffers_blend = GL_FALSE; +GLboolean __GLEW_AMD_framebuffer_sample_positions = GL_FALSE; +GLboolean __GLEW_AMD_gcn_shader = GL_FALSE; +GLboolean __GLEW_AMD_gpu_shader_half_float = GL_FALSE; +GLboolean __GLEW_AMD_gpu_shader_int16 = GL_FALSE; +GLboolean __GLEW_AMD_gpu_shader_int64 = GL_FALSE; +GLboolean __GLEW_AMD_interleaved_elements = GL_FALSE; +GLboolean __GLEW_AMD_multi_draw_indirect = GL_FALSE; +GLboolean __GLEW_AMD_name_gen_delete = GL_FALSE; +GLboolean __GLEW_AMD_occlusion_query_event = GL_FALSE; +GLboolean __GLEW_AMD_performance_monitor = GL_FALSE; +GLboolean __GLEW_AMD_pinned_memory = GL_FALSE; +GLboolean __GLEW_AMD_program_binary_Z400 = GL_FALSE; +GLboolean __GLEW_AMD_query_buffer_object = GL_FALSE; +GLboolean __GLEW_AMD_sample_positions = GL_FALSE; +GLboolean __GLEW_AMD_seamless_cubemap_per_texture = GL_FALSE; +GLboolean __GLEW_AMD_shader_atomic_counter_ops = GL_FALSE; +GLboolean __GLEW_AMD_shader_ballot = GL_FALSE; +GLboolean __GLEW_AMD_shader_explicit_vertex_parameter = GL_FALSE; +GLboolean __GLEW_AMD_shader_stencil_export = GL_FALSE; +GLboolean __GLEW_AMD_shader_stencil_value_export = GL_FALSE; +GLboolean __GLEW_AMD_shader_trinary_minmax = GL_FALSE; +GLboolean __GLEW_AMD_sparse_texture = GL_FALSE; +GLboolean __GLEW_AMD_stencil_operation_extended = GL_FALSE; +GLboolean __GLEW_AMD_texture_gather_bias_lod = GL_FALSE; +GLboolean __GLEW_AMD_texture_texture4 = GL_FALSE; +GLboolean __GLEW_AMD_transform_feedback3_lines_triangles = GL_FALSE; +GLboolean __GLEW_AMD_transform_feedback4 = GL_FALSE; +GLboolean __GLEW_AMD_vertex_shader_layer = GL_FALSE; +GLboolean __GLEW_AMD_vertex_shader_tessellator = GL_FALSE; +GLboolean __GLEW_AMD_vertex_shader_viewport_index = GL_FALSE; +GLboolean __GLEW_ANDROID_extension_pack_es31a = GL_FALSE; +GLboolean __GLEW_ANGLE_depth_texture = GL_FALSE; +GLboolean __GLEW_ANGLE_framebuffer_blit = GL_FALSE; +GLboolean __GLEW_ANGLE_framebuffer_multisample = GL_FALSE; +GLboolean __GLEW_ANGLE_instanced_arrays = GL_FALSE; +GLboolean __GLEW_ANGLE_pack_reverse_row_order = GL_FALSE; +GLboolean __GLEW_ANGLE_program_binary = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_compression_dxt1 = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_compression_dxt3 = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_compression_dxt5 = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_usage = GL_FALSE; +GLboolean __GLEW_ANGLE_timer_query = GL_FALSE; +GLboolean __GLEW_ANGLE_translated_shader_source = GL_FALSE; +GLboolean __GLEW_APPLE_aux_depth_stencil = GL_FALSE; +GLboolean __GLEW_APPLE_client_storage = GL_FALSE; +GLboolean __GLEW_APPLE_clip_distance = GL_FALSE; +GLboolean __GLEW_APPLE_color_buffer_packed_float = GL_FALSE; +GLboolean __GLEW_APPLE_copy_texture_levels = GL_FALSE; +GLboolean __GLEW_APPLE_element_array = GL_FALSE; +GLboolean __GLEW_APPLE_fence = GL_FALSE; +GLboolean __GLEW_APPLE_float_pixels = GL_FALSE; +GLboolean __GLEW_APPLE_flush_buffer_range = GL_FALSE; +GLboolean __GLEW_APPLE_framebuffer_multisample = GL_FALSE; +GLboolean __GLEW_APPLE_object_purgeable = GL_FALSE; +GLboolean __GLEW_APPLE_pixel_buffer = GL_FALSE; +GLboolean __GLEW_APPLE_rgb_422 = GL_FALSE; +GLboolean __GLEW_APPLE_row_bytes = GL_FALSE; +GLboolean __GLEW_APPLE_specular_vector = GL_FALSE; +GLboolean __GLEW_APPLE_sync = GL_FALSE; +GLboolean __GLEW_APPLE_texture_2D_limited_npot = GL_FALSE; +GLboolean __GLEW_APPLE_texture_format_BGRA8888 = GL_FALSE; +GLboolean __GLEW_APPLE_texture_max_level = GL_FALSE; +GLboolean __GLEW_APPLE_texture_packed_float = GL_FALSE; +GLboolean __GLEW_APPLE_texture_range = GL_FALSE; +GLboolean __GLEW_APPLE_transform_hint = GL_FALSE; +GLboolean __GLEW_APPLE_vertex_array_object = GL_FALSE; +GLboolean __GLEW_APPLE_vertex_array_range = GL_FALSE; +GLboolean __GLEW_APPLE_vertex_program_evaluators = GL_FALSE; +GLboolean __GLEW_APPLE_ycbcr_422 = GL_FALSE; +GLboolean __GLEW_ARB_ES2_compatibility = GL_FALSE; +GLboolean __GLEW_ARB_ES3_1_compatibility = GL_FALSE; +GLboolean __GLEW_ARB_ES3_2_compatibility = GL_FALSE; +GLboolean __GLEW_ARB_ES3_compatibility = GL_FALSE; +GLboolean __GLEW_ARB_arrays_of_arrays = GL_FALSE; +GLboolean __GLEW_ARB_base_instance = GL_FALSE; +GLboolean __GLEW_ARB_bindless_texture = GL_FALSE; +GLboolean __GLEW_ARB_blend_func_extended = GL_FALSE; +GLboolean __GLEW_ARB_buffer_storage = GL_FALSE; +GLboolean __GLEW_ARB_cl_event = GL_FALSE; +GLboolean __GLEW_ARB_clear_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_clear_texture = GL_FALSE; +GLboolean __GLEW_ARB_clip_control = GL_FALSE; +GLboolean __GLEW_ARB_color_buffer_float = GL_FALSE; +GLboolean __GLEW_ARB_compatibility = GL_FALSE; +GLboolean __GLEW_ARB_compressed_texture_pixel_storage = GL_FALSE; +GLboolean __GLEW_ARB_compute_shader = GL_FALSE; +GLboolean __GLEW_ARB_compute_variable_group_size = GL_FALSE; +GLboolean __GLEW_ARB_conditional_render_inverted = GL_FALSE; +GLboolean __GLEW_ARB_conservative_depth = GL_FALSE; +GLboolean __GLEW_ARB_copy_buffer = GL_FALSE; +GLboolean __GLEW_ARB_copy_image = GL_FALSE; +GLboolean __GLEW_ARB_cull_distance = GL_FALSE; +GLboolean __GLEW_ARB_debug_output = GL_FALSE; +GLboolean __GLEW_ARB_depth_buffer_float = GL_FALSE; +GLboolean __GLEW_ARB_depth_clamp = GL_FALSE; +GLboolean __GLEW_ARB_depth_texture = GL_FALSE; +GLboolean __GLEW_ARB_derivative_control = GL_FALSE; +GLboolean __GLEW_ARB_direct_state_access = GL_FALSE; +GLboolean __GLEW_ARB_draw_buffers = GL_FALSE; +GLboolean __GLEW_ARB_draw_buffers_blend = GL_FALSE; +GLboolean __GLEW_ARB_draw_elements_base_vertex = GL_FALSE; +GLboolean __GLEW_ARB_draw_indirect = GL_FALSE; +GLboolean __GLEW_ARB_draw_instanced = GL_FALSE; +GLboolean __GLEW_ARB_enhanced_layouts = GL_FALSE; +GLboolean __GLEW_ARB_explicit_attrib_location = GL_FALSE; +GLboolean __GLEW_ARB_explicit_uniform_location = GL_FALSE; +GLboolean __GLEW_ARB_fragment_coord_conventions = GL_FALSE; +GLboolean __GLEW_ARB_fragment_layer_viewport = GL_FALSE; +GLboolean __GLEW_ARB_fragment_program = GL_FALSE; +GLboolean __GLEW_ARB_fragment_program_shadow = GL_FALSE; +GLboolean __GLEW_ARB_fragment_shader = GL_FALSE; +GLboolean __GLEW_ARB_fragment_shader_interlock = GL_FALSE; +GLboolean __GLEW_ARB_framebuffer_no_attachments = GL_FALSE; +GLboolean __GLEW_ARB_framebuffer_object = GL_FALSE; +GLboolean __GLEW_ARB_framebuffer_sRGB = GL_FALSE; +GLboolean __GLEW_ARB_geometry_shader4 = GL_FALSE; +GLboolean __GLEW_ARB_get_program_binary = GL_FALSE; +GLboolean __GLEW_ARB_get_texture_sub_image = GL_FALSE; +GLboolean __GLEW_ARB_gl_spirv = GL_FALSE; +GLboolean __GLEW_ARB_gpu_shader5 = GL_FALSE; +GLboolean __GLEW_ARB_gpu_shader_fp64 = GL_FALSE; +GLboolean __GLEW_ARB_gpu_shader_int64 = GL_FALSE; +GLboolean __GLEW_ARB_half_float_pixel = GL_FALSE; +GLboolean __GLEW_ARB_half_float_vertex = GL_FALSE; +GLboolean __GLEW_ARB_imaging = GL_FALSE; +GLboolean __GLEW_ARB_indirect_parameters = GL_FALSE; +GLboolean __GLEW_ARB_instanced_arrays = GL_FALSE; +GLboolean __GLEW_ARB_internalformat_query = GL_FALSE; +GLboolean __GLEW_ARB_internalformat_query2 = GL_FALSE; +GLboolean __GLEW_ARB_invalidate_subdata = GL_FALSE; +GLboolean __GLEW_ARB_map_buffer_alignment = GL_FALSE; +GLboolean __GLEW_ARB_map_buffer_range = GL_FALSE; +GLboolean __GLEW_ARB_matrix_palette = GL_FALSE; +GLboolean __GLEW_ARB_multi_bind = GL_FALSE; +GLboolean __GLEW_ARB_multi_draw_indirect = GL_FALSE; +GLboolean __GLEW_ARB_multisample = GL_FALSE; +GLboolean __GLEW_ARB_multitexture = GL_FALSE; +GLboolean __GLEW_ARB_occlusion_query = GL_FALSE; +GLboolean __GLEW_ARB_occlusion_query2 = GL_FALSE; +GLboolean __GLEW_ARB_parallel_shader_compile = GL_FALSE; +GLboolean __GLEW_ARB_pipeline_statistics_query = GL_FALSE; +GLboolean __GLEW_ARB_pixel_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_point_parameters = GL_FALSE; +GLboolean __GLEW_ARB_point_sprite = GL_FALSE; +GLboolean __GLEW_ARB_polygon_offset_clamp = GL_FALSE; +GLboolean __GLEW_ARB_post_depth_coverage = GL_FALSE; +GLboolean __GLEW_ARB_program_interface_query = GL_FALSE; +GLboolean __GLEW_ARB_provoking_vertex = GL_FALSE; +GLboolean __GLEW_ARB_query_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_robust_buffer_access_behavior = GL_FALSE; +GLboolean __GLEW_ARB_robustness = GL_FALSE; +GLboolean __GLEW_ARB_robustness_application_isolation = GL_FALSE; +GLboolean __GLEW_ARB_robustness_share_group_isolation = GL_FALSE; +GLboolean __GLEW_ARB_sample_locations = GL_FALSE; +GLboolean __GLEW_ARB_sample_shading = GL_FALSE; +GLboolean __GLEW_ARB_sampler_objects = GL_FALSE; +GLboolean __GLEW_ARB_seamless_cube_map = GL_FALSE; +GLboolean __GLEW_ARB_seamless_cubemap_per_texture = GL_FALSE; +GLboolean __GLEW_ARB_separate_shader_objects = GL_FALSE; +GLboolean __GLEW_ARB_shader_atomic_counter_ops = GL_FALSE; +GLboolean __GLEW_ARB_shader_atomic_counters = GL_FALSE; +GLboolean __GLEW_ARB_shader_ballot = GL_FALSE; +GLboolean __GLEW_ARB_shader_bit_encoding = GL_FALSE; +GLboolean __GLEW_ARB_shader_clock = GL_FALSE; +GLboolean __GLEW_ARB_shader_draw_parameters = GL_FALSE; +GLboolean __GLEW_ARB_shader_group_vote = GL_FALSE; +GLboolean __GLEW_ARB_shader_image_load_store = GL_FALSE; +GLboolean __GLEW_ARB_shader_image_size = GL_FALSE; +GLboolean __GLEW_ARB_shader_objects = GL_FALSE; +GLboolean __GLEW_ARB_shader_precision = GL_FALSE; +GLboolean __GLEW_ARB_shader_stencil_export = GL_FALSE; +GLboolean __GLEW_ARB_shader_storage_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_shader_subroutine = GL_FALSE; +GLboolean __GLEW_ARB_shader_texture_image_samples = GL_FALSE; +GLboolean __GLEW_ARB_shader_texture_lod = GL_FALSE; +GLboolean __GLEW_ARB_shader_viewport_layer_array = GL_FALSE; +GLboolean __GLEW_ARB_shading_language_100 = GL_FALSE; +GLboolean __GLEW_ARB_shading_language_420pack = GL_FALSE; +GLboolean __GLEW_ARB_shading_language_include = GL_FALSE; +GLboolean __GLEW_ARB_shading_language_packing = GL_FALSE; +GLboolean __GLEW_ARB_shadow = GL_FALSE; +GLboolean __GLEW_ARB_shadow_ambient = GL_FALSE; +GLboolean __GLEW_ARB_sparse_buffer = GL_FALSE; +GLboolean __GLEW_ARB_sparse_texture = GL_FALSE; +GLboolean __GLEW_ARB_sparse_texture2 = GL_FALSE; +GLboolean __GLEW_ARB_sparse_texture_clamp = GL_FALSE; +GLboolean __GLEW_ARB_spirv_extensions = GL_FALSE; +GLboolean __GLEW_ARB_stencil_texturing = GL_FALSE; +GLboolean __GLEW_ARB_sync = GL_FALSE; +GLboolean __GLEW_ARB_tessellation_shader = GL_FALSE; +GLboolean __GLEW_ARB_texture_barrier = GL_FALSE; +GLboolean __GLEW_ARB_texture_border_clamp = GL_FALSE; +GLboolean __GLEW_ARB_texture_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_texture_buffer_object_rgb32 = GL_FALSE; +GLboolean __GLEW_ARB_texture_buffer_range = GL_FALSE; +GLboolean __GLEW_ARB_texture_compression = GL_FALSE; +GLboolean __GLEW_ARB_texture_compression_bptc = GL_FALSE; +GLboolean __GLEW_ARB_texture_compression_rgtc = GL_FALSE; +GLboolean __GLEW_ARB_texture_cube_map = GL_FALSE; +GLboolean __GLEW_ARB_texture_cube_map_array = GL_FALSE; +GLboolean __GLEW_ARB_texture_env_add = GL_FALSE; +GLboolean __GLEW_ARB_texture_env_combine = GL_FALSE; +GLboolean __GLEW_ARB_texture_env_crossbar = GL_FALSE; +GLboolean __GLEW_ARB_texture_env_dot3 = GL_FALSE; +GLboolean __GLEW_ARB_texture_filter_anisotropic = GL_FALSE; +GLboolean __GLEW_ARB_texture_filter_minmax = GL_FALSE; +GLboolean __GLEW_ARB_texture_float = GL_FALSE; +GLboolean __GLEW_ARB_texture_gather = GL_FALSE; +GLboolean __GLEW_ARB_texture_mirror_clamp_to_edge = GL_FALSE; +GLboolean __GLEW_ARB_texture_mirrored_repeat = GL_FALSE; +GLboolean __GLEW_ARB_texture_multisample = GL_FALSE; +GLboolean __GLEW_ARB_texture_non_power_of_two = GL_FALSE; +GLboolean __GLEW_ARB_texture_query_levels = GL_FALSE; +GLboolean __GLEW_ARB_texture_query_lod = GL_FALSE; +GLboolean __GLEW_ARB_texture_rectangle = GL_FALSE; +GLboolean __GLEW_ARB_texture_rg = GL_FALSE; +GLboolean __GLEW_ARB_texture_rgb10_a2ui = GL_FALSE; +GLboolean __GLEW_ARB_texture_stencil8 = GL_FALSE; +GLboolean __GLEW_ARB_texture_storage = GL_FALSE; +GLboolean __GLEW_ARB_texture_storage_multisample = GL_FALSE; +GLboolean __GLEW_ARB_texture_swizzle = GL_FALSE; +GLboolean __GLEW_ARB_texture_view = GL_FALSE; +GLboolean __GLEW_ARB_timer_query = GL_FALSE; +GLboolean __GLEW_ARB_transform_feedback2 = GL_FALSE; +GLboolean __GLEW_ARB_transform_feedback3 = GL_FALSE; +GLboolean __GLEW_ARB_transform_feedback_instanced = GL_FALSE; +GLboolean __GLEW_ARB_transform_feedback_overflow_query = GL_FALSE; +GLboolean __GLEW_ARB_transpose_matrix = GL_FALSE; +GLboolean __GLEW_ARB_uniform_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_vertex_array_bgra = GL_FALSE; +GLboolean __GLEW_ARB_vertex_array_object = GL_FALSE; +GLboolean __GLEW_ARB_vertex_attrib_64bit = GL_FALSE; +GLboolean __GLEW_ARB_vertex_attrib_binding = GL_FALSE; +GLboolean __GLEW_ARB_vertex_blend = GL_FALSE; +GLboolean __GLEW_ARB_vertex_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_vertex_program = GL_FALSE; +GLboolean __GLEW_ARB_vertex_shader = GL_FALSE; +GLboolean __GLEW_ARB_vertex_type_10f_11f_11f_rev = GL_FALSE; +GLboolean __GLEW_ARB_vertex_type_2_10_10_10_rev = GL_FALSE; +GLboolean __GLEW_ARB_viewport_array = GL_FALSE; +GLboolean __GLEW_ARB_window_pos = GL_FALSE; +GLboolean __GLEW_ARM_mali_program_binary = GL_FALSE; +GLboolean __GLEW_ARM_mali_shader_binary = GL_FALSE; +GLboolean __GLEW_ARM_rgba8 = GL_FALSE; +GLboolean __GLEW_ARM_shader_framebuffer_fetch = GL_FALSE; +GLboolean __GLEW_ARM_shader_framebuffer_fetch_depth_stencil = GL_FALSE; +GLboolean __GLEW_ATIX_point_sprites = GL_FALSE; +GLboolean __GLEW_ATIX_texture_env_combine3 = GL_FALSE; +GLboolean __GLEW_ATIX_texture_env_route = GL_FALSE; +GLboolean __GLEW_ATIX_vertex_shader_output_point_size = GL_FALSE; +GLboolean __GLEW_ATI_draw_buffers = GL_FALSE; +GLboolean __GLEW_ATI_element_array = GL_FALSE; +GLboolean __GLEW_ATI_envmap_bumpmap = GL_FALSE; +GLboolean __GLEW_ATI_fragment_shader = GL_FALSE; +GLboolean __GLEW_ATI_map_object_buffer = GL_FALSE; +GLboolean __GLEW_ATI_meminfo = GL_FALSE; +GLboolean __GLEW_ATI_pn_triangles = GL_FALSE; +GLboolean __GLEW_ATI_separate_stencil = GL_FALSE; +GLboolean __GLEW_ATI_shader_texture_lod = GL_FALSE; +GLboolean __GLEW_ATI_text_fragment_shader = GL_FALSE; +GLboolean __GLEW_ATI_texture_compression_3dc = GL_FALSE; +GLboolean __GLEW_ATI_texture_env_combine3 = GL_FALSE; +GLboolean __GLEW_ATI_texture_float = GL_FALSE; +GLboolean __GLEW_ATI_texture_mirror_once = GL_FALSE; +GLboolean __GLEW_ATI_vertex_array_object = GL_FALSE; +GLboolean __GLEW_ATI_vertex_attrib_array_object = GL_FALSE; +GLboolean __GLEW_ATI_vertex_streams = GL_FALSE; +GLboolean __GLEW_EGL_KHR_context_flush_control = GL_FALSE; +GLboolean __GLEW_EGL_NV_robustness_video_memory_purge = GL_FALSE; +GLboolean __GLEW_EXT_422_pixels = GL_FALSE; +GLboolean __GLEW_EXT_Cg_shader = GL_FALSE; +GLboolean __GLEW_EXT_EGL_image_array = GL_FALSE; +GLboolean __GLEW_EXT_YUV_target = GL_FALSE; +GLboolean __GLEW_EXT_abgr = GL_FALSE; +GLboolean __GLEW_EXT_base_instance = GL_FALSE; +GLboolean __GLEW_EXT_bgra = GL_FALSE; +GLboolean __GLEW_EXT_bindable_uniform = GL_FALSE; +GLboolean __GLEW_EXT_blend_color = GL_FALSE; +GLboolean __GLEW_EXT_blend_equation_separate = GL_FALSE; +GLboolean __GLEW_EXT_blend_func_extended = GL_FALSE; +GLboolean __GLEW_EXT_blend_func_separate = GL_FALSE; +GLboolean __GLEW_EXT_blend_logic_op = GL_FALSE; +GLboolean __GLEW_EXT_blend_minmax = GL_FALSE; +GLboolean __GLEW_EXT_blend_subtract = GL_FALSE; +GLboolean __GLEW_EXT_buffer_storage = GL_FALSE; +GLboolean __GLEW_EXT_clear_texture = GL_FALSE; +GLboolean __GLEW_EXT_clip_cull_distance = GL_FALSE; +GLboolean __GLEW_EXT_clip_volume_hint = GL_FALSE; +GLboolean __GLEW_EXT_cmyka = GL_FALSE; +GLboolean __GLEW_EXT_color_buffer_float = GL_FALSE; +GLboolean __GLEW_EXT_color_buffer_half_float = GL_FALSE; +GLboolean __GLEW_EXT_color_subtable = GL_FALSE; +GLboolean __GLEW_EXT_compiled_vertex_array = GL_FALSE; +GLboolean __GLEW_EXT_compressed_ETC1_RGB8_sub_texture = GL_FALSE; +GLboolean __GLEW_EXT_conservative_depth = GL_FALSE; +GLboolean __GLEW_EXT_convolution = GL_FALSE; +GLboolean __GLEW_EXT_coordinate_frame = GL_FALSE; +GLboolean __GLEW_EXT_copy_image = GL_FALSE; +GLboolean __GLEW_EXT_copy_texture = GL_FALSE; +GLboolean __GLEW_EXT_cull_vertex = GL_FALSE; +GLboolean __GLEW_EXT_debug_label = GL_FALSE; +GLboolean __GLEW_EXT_debug_marker = GL_FALSE; +GLboolean __GLEW_EXT_depth_bounds_test = GL_FALSE; +GLboolean __GLEW_EXT_direct_state_access = GL_FALSE; +GLboolean __GLEW_EXT_discard_framebuffer = GL_FALSE; +GLboolean __GLEW_EXT_draw_buffers = GL_FALSE; +GLboolean __GLEW_EXT_draw_buffers2 = GL_FALSE; +GLboolean __GLEW_EXT_draw_buffers_indexed = GL_FALSE; +GLboolean __GLEW_EXT_draw_elements_base_vertex = GL_FALSE; +GLboolean __GLEW_EXT_draw_instanced = GL_FALSE; +GLboolean __GLEW_EXT_draw_range_elements = GL_FALSE; +GLboolean __GLEW_EXT_external_buffer = GL_FALSE; +GLboolean __GLEW_EXT_float_blend = GL_FALSE; +GLboolean __GLEW_EXT_fog_coord = GL_FALSE; +GLboolean __GLEW_EXT_frag_depth = GL_FALSE; +GLboolean __GLEW_EXT_fragment_lighting = GL_FALSE; +GLboolean __GLEW_EXT_framebuffer_blit = GL_FALSE; +GLboolean __GLEW_EXT_framebuffer_multisample = GL_FALSE; +GLboolean __GLEW_EXT_framebuffer_multisample_blit_scaled = GL_FALSE; +GLboolean __GLEW_EXT_framebuffer_object = GL_FALSE; +GLboolean __GLEW_EXT_framebuffer_sRGB = GL_FALSE; +GLboolean __GLEW_EXT_geometry_point_size = GL_FALSE; +GLboolean __GLEW_EXT_geometry_shader = GL_FALSE; +GLboolean __GLEW_EXT_geometry_shader4 = GL_FALSE; +GLboolean __GLEW_EXT_gpu_program_parameters = GL_FALSE; +GLboolean __GLEW_EXT_gpu_shader4 = GL_FALSE; +GLboolean __GLEW_EXT_gpu_shader5 = GL_FALSE; +GLboolean __GLEW_EXT_histogram = GL_FALSE; +GLboolean __GLEW_EXT_index_array_formats = GL_FALSE; +GLboolean __GLEW_EXT_index_func = GL_FALSE; +GLboolean __GLEW_EXT_index_material = GL_FALSE; +GLboolean __GLEW_EXT_index_texture = GL_FALSE; +GLboolean __GLEW_EXT_instanced_arrays = GL_FALSE; +GLboolean __GLEW_EXT_light_texture = GL_FALSE; +GLboolean __GLEW_EXT_map_buffer_range = GL_FALSE; +GLboolean __GLEW_EXT_memory_object = GL_FALSE; +GLboolean __GLEW_EXT_memory_object_fd = GL_FALSE; +GLboolean __GLEW_EXT_memory_object_win32 = GL_FALSE; +GLboolean __GLEW_EXT_misc_attribute = GL_FALSE; +GLboolean __GLEW_EXT_multi_draw_arrays = GL_FALSE; +GLboolean __GLEW_EXT_multi_draw_indirect = GL_FALSE; +GLboolean __GLEW_EXT_multiple_textures = GL_FALSE; +GLboolean __GLEW_EXT_multisample = GL_FALSE; +GLboolean __GLEW_EXT_multisample_compatibility = GL_FALSE; +GLboolean __GLEW_EXT_multisampled_render_to_texture = GL_FALSE; +GLboolean __GLEW_EXT_multisampled_render_to_texture2 = GL_FALSE; +GLboolean __GLEW_EXT_multiview_draw_buffers = GL_FALSE; +GLboolean __GLEW_EXT_packed_depth_stencil = GL_FALSE; +GLboolean __GLEW_EXT_packed_float = GL_FALSE; +GLboolean __GLEW_EXT_packed_pixels = GL_FALSE; +GLboolean __GLEW_EXT_paletted_texture = GL_FALSE; +GLboolean __GLEW_EXT_pixel_buffer_object = GL_FALSE; +GLboolean __GLEW_EXT_pixel_transform = GL_FALSE; +GLboolean __GLEW_EXT_pixel_transform_color_table = GL_FALSE; +GLboolean __GLEW_EXT_point_parameters = GL_FALSE; +GLboolean __GLEW_EXT_polygon_offset = GL_FALSE; +GLboolean __GLEW_EXT_polygon_offset_clamp = GL_FALSE; +GLboolean __GLEW_EXT_post_depth_coverage = GL_FALSE; +GLboolean __GLEW_EXT_provoking_vertex = GL_FALSE; +GLboolean __GLEW_EXT_pvrtc_sRGB = GL_FALSE; +GLboolean __GLEW_EXT_raster_multisample = GL_FALSE; +GLboolean __GLEW_EXT_read_format_bgra = GL_FALSE; +GLboolean __GLEW_EXT_render_snorm = GL_FALSE; +GLboolean __GLEW_EXT_rescale_normal = GL_FALSE; +GLboolean __GLEW_EXT_sRGB = GL_FALSE; +GLboolean __GLEW_EXT_sRGB_write_control = GL_FALSE; +GLboolean __GLEW_EXT_scene_marker = GL_FALSE; +GLboolean __GLEW_EXT_secondary_color = GL_FALSE; +GLboolean __GLEW_EXT_semaphore = GL_FALSE; +GLboolean __GLEW_EXT_semaphore_fd = GL_FALSE; +GLboolean __GLEW_EXT_semaphore_win32 = GL_FALSE; +GLboolean __GLEW_EXT_separate_shader_objects = GL_FALSE; +GLboolean __GLEW_EXT_separate_specular_color = GL_FALSE; +GLboolean __GLEW_EXT_shader_framebuffer_fetch = GL_FALSE; +GLboolean __GLEW_EXT_shader_group_vote = GL_FALSE; +GLboolean __GLEW_EXT_shader_image_load_formatted = GL_FALSE; +GLboolean __GLEW_EXT_shader_image_load_store = GL_FALSE; +GLboolean __GLEW_EXT_shader_implicit_conversions = GL_FALSE; +GLboolean __GLEW_EXT_shader_integer_mix = GL_FALSE; +GLboolean __GLEW_EXT_shader_io_blocks = GL_FALSE; +GLboolean __GLEW_EXT_shader_non_constant_global_initializers = GL_FALSE; +GLboolean __GLEW_EXT_shader_pixel_local_storage = GL_FALSE; +GLboolean __GLEW_EXT_shader_pixel_local_storage2 = GL_FALSE; +GLboolean __GLEW_EXT_shader_texture_lod = GL_FALSE; +GLboolean __GLEW_EXT_shadow_funcs = GL_FALSE; +GLboolean __GLEW_EXT_shadow_samplers = GL_FALSE; +GLboolean __GLEW_EXT_shared_texture_palette = GL_FALSE; +GLboolean __GLEW_EXT_sparse_texture = GL_FALSE; +GLboolean __GLEW_EXT_sparse_texture2 = GL_FALSE; +GLboolean __GLEW_EXT_stencil_clear_tag = GL_FALSE; +GLboolean __GLEW_EXT_stencil_two_side = GL_FALSE; +GLboolean __GLEW_EXT_stencil_wrap = GL_FALSE; +GLboolean __GLEW_EXT_subtexture = GL_FALSE; +GLboolean __GLEW_EXT_texture = GL_FALSE; +GLboolean __GLEW_EXT_texture3D = GL_FALSE; +GLboolean __GLEW_EXT_texture_array = GL_FALSE; +GLboolean __GLEW_EXT_texture_buffer_object = GL_FALSE; +GLboolean __GLEW_EXT_texture_compression_astc_decode_mode = GL_FALSE; +GLboolean __GLEW_EXT_texture_compression_astc_decode_mode_rgb9e5 = GL_FALSE; +GLboolean __GLEW_EXT_texture_compression_bptc = GL_FALSE; +GLboolean __GLEW_EXT_texture_compression_dxt1 = GL_FALSE; +GLboolean __GLEW_EXT_texture_compression_latc = GL_FALSE; +GLboolean __GLEW_EXT_texture_compression_rgtc = GL_FALSE; +GLboolean __GLEW_EXT_texture_compression_s3tc = GL_FALSE; +GLboolean __GLEW_EXT_texture_cube_map = GL_FALSE; +GLboolean __GLEW_EXT_texture_cube_map_array = GL_FALSE; +GLboolean __GLEW_EXT_texture_edge_clamp = GL_FALSE; +GLboolean __GLEW_EXT_texture_env = GL_FALSE; +GLboolean __GLEW_EXT_texture_env_add = GL_FALSE; +GLboolean __GLEW_EXT_texture_env_combine = GL_FALSE; +GLboolean __GLEW_EXT_texture_env_dot3 = GL_FALSE; +GLboolean __GLEW_EXT_texture_filter_anisotropic = GL_FALSE; +GLboolean __GLEW_EXT_texture_filter_minmax = GL_FALSE; +GLboolean __GLEW_EXT_texture_format_BGRA8888 = GL_FALSE; +GLboolean __GLEW_EXT_texture_integer = GL_FALSE; +GLboolean __GLEW_EXT_texture_lod_bias = GL_FALSE; +GLboolean __GLEW_EXT_texture_mirror_clamp = GL_FALSE; +GLboolean __GLEW_EXT_texture_norm16 = GL_FALSE; +GLboolean __GLEW_EXT_texture_object = GL_FALSE; +GLboolean __GLEW_EXT_texture_perturb_normal = GL_FALSE; +GLboolean __GLEW_EXT_texture_rectangle = GL_FALSE; +GLboolean __GLEW_EXT_texture_rg = GL_FALSE; +GLboolean __GLEW_EXT_texture_sRGB = GL_FALSE; +GLboolean __GLEW_EXT_texture_sRGB_R8 = GL_FALSE; +GLboolean __GLEW_EXT_texture_sRGB_RG8 = GL_FALSE; +GLboolean __GLEW_EXT_texture_sRGB_decode = GL_FALSE; +GLboolean __GLEW_EXT_texture_shared_exponent = GL_FALSE; +GLboolean __GLEW_EXT_texture_snorm = GL_FALSE; +GLboolean __GLEW_EXT_texture_storage = GL_FALSE; +GLboolean __GLEW_EXT_texture_swizzle = GL_FALSE; +GLboolean __GLEW_EXT_texture_type_2_10_10_10_REV = GL_FALSE; +GLboolean __GLEW_EXT_texture_view = GL_FALSE; +GLboolean __GLEW_EXT_timer_query = GL_FALSE; +GLboolean __GLEW_EXT_transform_feedback = GL_FALSE; +GLboolean __GLEW_EXT_unpack_subimage = GL_FALSE; +GLboolean __GLEW_EXT_vertex_array = GL_FALSE; +GLboolean __GLEW_EXT_vertex_array_bgra = GL_FALSE; +GLboolean __GLEW_EXT_vertex_array_setXXX = GL_FALSE; +GLboolean __GLEW_EXT_vertex_attrib_64bit = GL_FALSE; +GLboolean __GLEW_EXT_vertex_shader = GL_FALSE; +GLboolean __GLEW_EXT_vertex_weighting = GL_FALSE; +GLboolean __GLEW_EXT_win32_keyed_mutex = GL_FALSE; +GLboolean __GLEW_EXT_window_rectangles = GL_FALSE; +GLboolean __GLEW_EXT_x11_sync_object = GL_FALSE; +GLboolean __GLEW_GREMEDY_frame_terminator = GL_FALSE; +GLboolean __GLEW_GREMEDY_string_marker = GL_FALSE; +GLboolean __GLEW_HP_convolution_border_modes = GL_FALSE; +GLboolean __GLEW_HP_image_transform = GL_FALSE; +GLboolean __GLEW_HP_occlusion_test = GL_FALSE; +GLboolean __GLEW_HP_texture_lighting = GL_FALSE; +GLboolean __GLEW_IBM_cull_vertex = GL_FALSE; +GLboolean __GLEW_IBM_multimode_draw_arrays = GL_FALSE; +GLboolean __GLEW_IBM_rasterpos_clip = GL_FALSE; +GLboolean __GLEW_IBM_static_data = GL_FALSE; +GLboolean __GLEW_IBM_texture_mirrored_repeat = GL_FALSE; +GLboolean __GLEW_IBM_vertex_array_lists = GL_FALSE; +GLboolean __GLEW_INGR_color_clamp = GL_FALSE; +GLboolean __GLEW_INGR_interlace_read = GL_FALSE; +GLboolean __GLEW_INTEL_conservative_rasterization = GL_FALSE; +GLboolean __GLEW_INTEL_fragment_shader_ordering = GL_FALSE; +GLboolean __GLEW_INTEL_framebuffer_CMAA = GL_FALSE; +GLboolean __GLEW_INTEL_map_texture = GL_FALSE; +GLboolean __GLEW_INTEL_parallel_arrays = GL_FALSE; +GLboolean __GLEW_INTEL_performance_query = GL_FALSE; +GLboolean __GLEW_INTEL_texture_scissor = GL_FALSE; +GLboolean __GLEW_KHR_blend_equation_advanced = GL_FALSE; +GLboolean __GLEW_KHR_blend_equation_advanced_coherent = GL_FALSE; +GLboolean __GLEW_KHR_context_flush_control = GL_FALSE; +GLboolean __GLEW_KHR_debug = GL_FALSE; +GLboolean __GLEW_KHR_no_error = GL_FALSE; +GLboolean __GLEW_KHR_parallel_shader_compile = GL_FALSE; +GLboolean __GLEW_KHR_robust_buffer_access_behavior = GL_FALSE; +GLboolean __GLEW_KHR_robustness = GL_FALSE; +GLboolean __GLEW_KHR_texture_compression_astc_hdr = GL_FALSE; +GLboolean __GLEW_KHR_texture_compression_astc_ldr = GL_FALSE; +GLboolean __GLEW_KHR_texture_compression_astc_sliced_3d = GL_FALSE; +GLboolean __GLEW_KTX_buffer_region = GL_FALSE; +GLboolean __GLEW_MESAX_texture_stack = GL_FALSE; +GLboolean __GLEW_MESA_pack_invert = GL_FALSE; +GLboolean __GLEW_MESA_resize_buffers = GL_FALSE; +GLboolean __GLEW_MESA_shader_integer_functions = GL_FALSE; +GLboolean __GLEW_MESA_window_pos = GL_FALSE; +GLboolean __GLEW_MESA_ycbcr_texture = GL_FALSE; +GLboolean __GLEW_NVX_blend_equation_advanced_multi_draw_buffers = GL_FALSE; +GLboolean __GLEW_NVX_conditional_render = GL_FALSE; +GLboolean __GLEW_NVX_gpu_memory_info = GL_FALSE; +GLboolean __GLEW_NVX_linked_gpu_multicast = GL_FALSE; +GLboolean __GLEW_NV_3dvision_settings = GL_FALSE; +GLboolean __GLEW_NV_EGL_stream_consumer_external = GL_FALSE; +GLboolean __GLEW_NV_alpha_to_coverage_dither_control = GL_FALSE; +GLboolean __GLEW_NV_bgr = GL_FALSE; +GLboolean __GLEW_NV_bindless_multi_draw_indirect = GL_FALSE; +GLboolean __GLEW_NV_bindless_multi_draw_indirect_count = GL_FALSE; +GLboolean __GLEW_NV_bindless_texture = GL_FALSE; +GLboolean __GLEW_NV_blend_equation_advanced = GL_FALSE; +GLboolean __GLEW_NV_blend_equation_advanced_coherent = GL_FALSE; +GLboolean __GLEW_NV_blend_minmax_factor = GL_FALSE; +GLboolean __GLEW_NV_blend_square = GL_FALSE; +GLboolean __GLEW_NV_clip_space_w_scaling = GL_FALSE; +GLboolean __GLEW_NV_command_list = GL_FALSE; +GLboolean __GLEW_NV_compute_program5 = GL_FALSE; +GLboolean __GLEW_NV_conditional_render = GL_FALSE; +GLboolean __GLEW_NV_conservative_raster = GL_FALSE; +GLboolean __GLEW_NV_conservative_raster_dilate = GL_FALSE; +GLboolean __GLEW_NV_conservative_raster_pre_snap_triangles = GL_FALSE; +GLboolean __GLEW_NV_copy_buffer = GL_FALSE; +GLboolean __GLEW_NV_copy_depth_to_color = GL_FALSE; +GLboolean __GLEW_NV_copy_image = GL_FALSE; +GLboolean __GLEW_NV_deep_texture3D = GL_FALSE; +GLboolean __GLEW_NV_depth_buffer_float = GL_FALSE; +GLboolean __GLEW_NV_depth_clamp = GL_FALSE; +GLboolean __GLEW_NV_depth_range_unclamped = GL_FALSE; +GLboolean __GLEW_NV_draw_buffers = GL_FALSE; +GLboolean __GLEW_NV_draw_instanced = GL_FALSE; +GLboolean __GLEW_NV_draw_texture = GL_FALSE; +GLboolean __GLEW_NV_draw_vulkan_image = GL_FALSE; +GLboolean __GLEW_NV_evaluators = GL_FALSE; +GLboolean __GLEW_NV_explicit_attrib_location = GL_FALSE; +GLboolean __GLEW_NV_explicit_multisample = GL_FALSE; +GLboolean __GLEW_NV_fbo_color_attachments = GL_FALSE; +GLboolean __GLEW_NV_fence = GL_FALSE; +GLboolean __GLEW_NV_fill_rectangle = GL_FALSE; +GLboolean __GLEW_NV_float_buffer = GL_FALSE; +GLboolean __GLEW_NV_fog_distance = GL_FALSE; +GLboolean __GLEW_NV_fragment_coverage_to_color = GL_FALSE; +GLboolean __GLEW_NV_fragment_program = GL_FALSE; +GLboolean __GLEW_NV_fragment_program2 = GL_FALSE; +GLboolean __GLEW_NV_fragment_program4 = GL_FALSE; +GLboolean __GLEW_NV_fragment_program_option = GL_FALSE; +GLboolean __GLEW_NV_fragment_shader_interlock = GL_FALSE; +GLboolean __GLEW_NV_framebuffer_blit = GL_FALSE; +GLboolean __GLEW_NV_framebuffer_mixed_samples = GL_FALSE; +GLboolean __GLEW_NV_framebuffer_multisample = GL_FALSE; +GLboolean __GLEW_NV_framebuffer_multisample_coverage = GL_FALSE; +GLboolean __GLEW_NV_generate_mipmap_sRGB = GL_FALSE; +GLboolean __GLEW_NV_geometry_program4 = GL_FALSE; +GLboolean __GLEW_NV_geometry_shader4 = GL_FALSE; +GLboolean __GLEW_NV_geometry_shader_passthrough = GL_FALSE; +GLboolean __GLEW_NV_gpu_multicast = GL_FALSE; +GLboolean __GLEW_NV_gpu_program4 = GL_FALSE; +GLboolean __GLEW_NV_gpu_program5 = GL_FALSE; +GLboolean __GLEW_NV_gpu_program5_mem_extended = GL_FALSE; +GLboolean __GLEW_NV_gpu_program_fp64 = GL_FALSE; +GLboolean __GLEW_NV_gpu_shader5 = GL_FALSE; +GLboolean __GLEW_NV_half_float = GL_FALSE; +GLboolean __GLEW_NV_image_formats = GL_FALSE; +GLboolean __GLEW_NV_instanced_arrays = GL_FALSE; +GLboolean __GLEW_NV_internalformat_sample_query = GL_FALSE; +GLboolean __GLEW_NV_light_max_exponent = GL_FALSE; +GLboolean __GLEW_NV_multisample_coverage = GL_FALSE; +GLboolean __GLEW_NV_multisample_filter_hint = GL_FALSE; +GLboolean __GLEW_NV_non_square_matrices = GL_FALSE; +GLboolean __GLEW_NV_occlusion_query = GL_FALSE; +GLboolean __GLEW_NV_pack_subimage = GL_FALSE; +GLboolean __GLEW_NV_packed_depth_stencil = GL_FALSE; +GLboolean __GLEW_NV_packed_float = GL_FALSE; +GLboolean __GLEW_NV_packed_float_linear = GL_FALSE; +GLboolean __GLEW_NV_parameter_buffer_object = GL_FALSE; +GLboolean __GLEW_NV_parameter_buffer_object2 = GL_FALSE; +GLboolean __GLEW_NV_path_rendering = GL_FALSE; +GLboolean __GLEW_NV_path_rendering_shared_edge = GL_FALSE; +GLboolean __GLEW_NV_pixel_buffer_object = GL_FALSE; +GLboolean __GLEW_NV_pixel_data_range = GL_FALSE; +GLboolean __GLEW_NV_platform_binary = GL_FALSE; +GLboolean __GLEW_NV_point_sprite = GL_FALSE; +GLboolean __GLEW_NV_polygon_mode = GL_FALSE; +GLboolean __GLEW_NV_present_video = GL_FALSE; +GLboolean __GLEW_NV_primitive_restart = GL_FALSE; +GLboolean __GLEW_NV_read_depth = GL_FALSE; +GLboolean __GLEW_NV_read_depth_stencil = GL_FALSE; +GLboolean __GLEW_NV_read_stencil = GL_FALSE; +GLboolean __GLEW_NV_register_combiners = GL_FALSE; +GLboolean __GLEW_NV_register_combiners2 = GL_FALSE; +GLboolean __GLEW_NV_robustness_video_memory_purge = GL_FALSE; +GLboolean __GLEW_NV_sRGB_formats = GL_FALSE; +GLboolean __GLEW_NV_sample_locations = GL_FALSE; +GLboolean __GLEW_NV_sample_mask_override_coverage = GL_FALSE; +GLboolean __GLEW_NV_shader_atomic_counters = GL_FALSE; +GLboolean __GLEW_NV_shader_atomic_float = GL_FALSE; +GLboolean __GLEW_NV_shader_atomic_float64 = GL_FALSE; +GLboolean __GLEW_NV_shader_atomic_fp16_vector = GL_FALSE; +GLboolean __GLEW_NV_shader_atomic_int64 = GL_FALSE; +GLboolean __GLEW_NV_shader_buffer_load = GL_FALSE; +GLboolean __GLEW_NV_shader_noperspective_interpolation = GL_FALSE; +GLboolean __GLEW_NV_shader_storage_buffer_object = GL_FALSE; +GLboolean __GLEW_NV_shader_thread_group = GL_FALSE; +GLboolean __GLEW_NV_shader_thread_shuffle = GL_FALSE; +GLboolean __GLEW_NV_shadow_samplers_array = GL_FALSE; +GLboolean __GLEW_NV_shadow_samplers_cube = GL_FALSE; +GLboolean __GLEW_NV_stereo_view_rendering = GL_FALSE; +GLboolean __GLEW_NV_tessellation_program5 = GL_FALSE; +GLboolean __GLEW_NV_texgen_emboss = GL_FALSE; +GLboolean __GLEW_NV_texgen_reflection = GL_FALSE; +GLboolean __GLEW_NV_texture_array = GL_FALSE; +GLboolean __GLEW_NV_texture_barrier = GL_FALSE; +GLboolean __GLEW_NV_texture_border_clamp = GL_FALSE; +GLboolean __GLEW_NV_texture_compression_latc = GL_FALSE; +GLboolean __GLEW_NV_texture_compression_s3tc = GL_FALSE; +GLboolean __GLEW_NV_texture_compression_s3tc_update = GL_FALSE; +GLboolean __GLEW_NV_texture_compression_vtc = GL_FALSE; +GLboolean __GLEW_NV_texture_env_combine4 = GL_FALSE; +GLboolean __GLEW_NV_texture_expand_normal = GL_FALSE; +GLboolean __GLEW_NV_texture_multisample = GL_FALSE; +GLboolean __GLEW_NV_texture_npot_2D_mipmap = GL_FALSE; +GLboolean __GLEW_NV_texture_rectangle = GL_FALSE; +GLboolean __GLEW_NV_texture_rectangle_compressed = GL_FALSE; +GLboolean __GLEW_NV_texture_shader = GL_FALSE; +GLboolean __GLEW_NV_texture_shader2 = GL_FALSE; +GLboolean __GLEW_NV_texture_shader3 = GL_FALSE; +GLboolean __GLEW_NV_transform_feedback = GL_FALSE; +GLboolean __GLEW_NV_transform_feedback2 = GL_FALSE; +GLboolean __GLEW_NV_uniform_buffer_unified_memory = GL_FALSE; +GLboolean __GLEW_NV_vdpau_interop = GL_FALSE; +GLboolean __GLEW_NV_vertex_array_range = GL_FALSE; +GLboolean __GLEW_NV_vertex_array_range2 = GL_FALSE; +GLboolean __GLEW_NV_vertex_attrib_integer_64bit = GL_FALSE; +GLboolean __GLEW_NV_vertex_buffer_unified_memory = GL_FALSE; +GLboolean __GLEW_NV_vertex_program = GL_FALSE; +GLboolean __GLEW_NV_vertex_program1_1 = GL_FALSE; +GLboolean __GLEW_NV_vertex_program2 = GL_FALSE; +GLboolean __GLEW_NV_vertex_program2_option = GL_FALSE; +GLboolean __GLEW_NV_vertex_program3 = GL_FALSE; +GLboolean __GLEW_NV_vertex_program4 = GL_FALSE; +GLboolean __GLEW_NV_video_capture = GL_FALSE; +GLboolean __GLEW_NV_viewport_array = GL_FALSE; +GLboolean __GLEW_NV_viewport_array2 = GL_FALSE; +GLboolean __GLEW_NV_viewport_swizzle = GL_FALSE; +GLboolean __GLEW_OES_byte_coordinates = GL_FALSE; +GLboolean __GLEW_OML_interlace = GL_FALSE; +GLboolean __GLEW_OML_resample = GL_FALSE; +GLboolean __GLEW_OML_subsample = GL_FALSE; +GLboolean __GLEW_OVR_multiview = GL_FALSE; +GLboolean __GLEW_OVR_multiview2 = GL_FALSE; +GLboolean __GLEW_OVR_multiview_multisampled_render_to_texture = GL_FALSE; +GLboolean __GLEW_PGI_misc_hints = GL_FALSE; +GLboolean __GLEW_PGI_vertex_hints = GL_FALSE; +GLboolean __GLEW_QCOM_alpha_test = GL_FALSE; +GLboolean __GLEW_QCOM_binning_control = GL_FALSE; +GLboolean __GLEW_QCOM_driver_control = GL_FALSE; +GLboolean __GLEW_QCOM_extended_get = GL_FALSE; +GLboolean __GLEW_QCOM_extended_get2 = GL_FALSE; +GLboolean __GLEW_QCOM_framebuffer_foveated = GL_FALSE; +GLboolean __GLEW_QCOM_perfmon_global_mode = GL_FALSE; +GLboolean __GLEW_QCOM_shader_framebuffer_fetch_noncoherent = GL_FALSE; +GLboolean __GLEW_QCOM_tiled_rendering = GL_FALSE; +GLboolean __GLEW_QCOM_writeonly_rendering = GL_FALSE; +GLboolean __GLEW_REGAL_ES1_0_compatibility = GL_FALSE; +GLboolean __GLEW_REGAL_ES1_1_compatibility = GL_FALSE; +GLboolean __GLEW_REGAL_enable = GL_FALSE; +GLboolean __GLEW_REGAL_error_string = GL_FALSE; +GLboolean __GLEW_REGAL_extension_query = GL_FALSE; +GLboolean __GLEW_REGAL_log = GL_FALSE; +GLboolean __GLEW_REGAL_proc_address = GL_FALSE; +GLboolean __GLEW_REND_screen_coordinates = GL_FALSE; +GLboolean __GLEW_S3_s3tc = GL_FALSE; +GLboolean __GLEW_SGIS_clip_band_hint = GL_FALSE; +GLboolean __GLEW_SGIS_color_range = GL_FALSE; +GLboolean __GLEW_SGIS_detail_texture = GL_FALSE; +GLboolean __GLEW_SGIS_fog_function = GL_FALSE; +GLboolean __GLEW_SGIS_generate_mipmap = GL_FALSE; +GLboolean __GLEW_SGIS_line_texgen = GL_FALSE; +GLboolean __GLEW_SGIS_multisample = GL_FALSE; +GLboolean __GLEW_SGIS_multitexture = GL_FALSE; +GLboolean __GLEW_SGIS_pixel_texture = GL_FALSE; +GLboolean __GLEW_SGIS_point_line_texgen = GL_FALSE; +GLboolean __GLEW_SGIS_shared_multisample = GL_FALSE; +GLboolean __GLEW_SGIS_sharpen_texture = GL_FALSE; +GLboolean __GLEW_SGIS_texture4D = GL_FALSE; +GLboolean __GLEW_SGIS_texture_border_clamp = GL_FALSE; +GLboolean __GLEW_SGIS_texture_edge_clamp = GL_FALSE; +GLboolean __GLEW_SGIS_texture_filter4 = GL_FALSE; +GLboolean __GLEW_SGIS_texture_lod = GL_FALSE; +GLboolean __GLEW_SGIS_texture_select = GL_FALSE; +GLboolean __GLEW_SGIX_async = GL_FALSE; +GLboolean __GLEW_SGIX_async_histogram = GL_FALSE; +GLboolean __GLEW_SGIX_async_pixel = GL_FALSE; +GLboolean __GLEW_SGIX_bali_g_instruments = GL_FALSE; +GLboolean __GLEW_SGIX_bali_r_instruments = GL_FALSE; +GLboolean __GLEW_SGIX_bali_timer_instruments = GL_FALSE; +GLboolean __GLEW_SGIX_blend_alpha_minmax = GL_FALSE; +GLboolean __GLEW_SGIX_blend_cadd = GL_FALSE; +GLboolean __GLEW_SGIX_blend_cmultiply = GL_FALSE; +GLboolean __GLEW_SGIX_calligraphic_fragment = GL_FALSE; +GLboolean __GLEW_SGIX_clipmap = GL_FALSE; +GLboolean __GLEW_SGIX_color_matrix_accuracy = GL_FALSE; +GLboolean __GLEW_SGIX_color_table_index_mode = GL_FALSE; +GLboolean __GLEW_SGIX_complex_polar = GL_FALSE; +GLboolean __GLEW_SGIX_convolution_accuracy = GL_FALSE; +GLboolean __GLEW_SGIX_cube_map = GL_FALSE; +GLboolean __GLEW_SGIX_cylinder_texgen = GL_FALSE; +GLboolean __GLEW_SGIX_datapipe = GL_FALSE; +GLboolean __GLEW_SGIX_decimation = GL_FALSE; +GLboolean __GLEW_SGIX_depth_pass_instrument = GL_FALSE; +GLboolean __GLEW_SGIX_depth_texture = GL_FALSE; +GLboolean __GLEW_SGIX_dvc = GL_FALSE; +GLboolean __GLEW_SGIX_flush_raster = GL_FALSE; +GLboolean __GLEW_SGIX_fog_blend = GL_FALSE; +GLboolean __GLEW_SGIX_fog_factor_to_alpha = GL_FALSE; +GLboolean __GLEW_SGIX_fog_layers = GL_FALSE; +GLboolean __GLEW_SGIX_fog_offset = GL_FALSE; +GLboolean __GLEW_SGIX_fog_patchy = GL_FALSE; +GLboolean __GLEW_SGIX_fog_scale = GL_FALSE; +GLboolean __GLEW_SGIX_fog_texture = GL_FALSE; +GLboolean __GLEW_SGIX_fragment_lighting_space = GL_FALSE; +GLboolean __GLEW_SGIX_fragment_specular_lighting = GL_FALSE; +GLboolean __GLEW_SGIX_fragments_instrument = GL_FALSE; +GLboolean __GLEW_SGIX_framezoom = GL_FALSE; +GLboolean __GLEW_SGIX_icc_texture = GL_FALSE; +GLboolean __GLEW_SGIX_igloo_interface = GL_FALSE; +GLboolean __GLEW_SGIX_image_compression = GL_FALSE; +GLboolean __GLEW_SGIX_impact_pixel_texture = GL_FALSE; +GLboolean __GLEW_SGIX_instrument_error = GL_FALSE; +GLboolean __GLEW_SGIX_interlace = GL_FALSE; +GLboolean __GLEW_SGIX_ir_instrument1 = GL_FALSE; +GLboolean __GLEW_SGIX_line_quality_hint = GL_FALSE; +GLboolean __GLEW_SGIX_list_priority = GL_FALSE; +GLboolean __GLEW_SGIX_mpeg1 = GL_FALSE; +GLboolean __GLEW_SGIX_mpeg2 = GL_FALSE; +GLboolean __GLEW_SGIX_nonlinear_lighting_pervertex = GL_FALSE; +GLboolean __GLEW_SGIX_nurbs_eval = GL_FALSE; +GLboolean __GLEW_SGIX_occlusion_instrument = GL_FALSE; +GLboolean __GLEW_SGIX_packed_6bytes = GL_FALSE; +GLboolean __GLEW_SGIX_pixel_texture = GL_FALSE; +GLboolean __GLEW_SGIX_pixel_texture_bits = GL_FALSE; +GLboolean __GLEW_SGIX_pixel_texture_lod = GL_FALSE; +GLboolean __GLEW_SGIX_pixel_tiles = GL_FALSE; +GLboolean __GLEW_SGIX_polynomial_ffd = GL_FALSE; +GLboolean __GLEW_SGIX_quad_mesh = GL_FALSE; +GLboolean __GLEW_SGIX_reference_plane = GL_FALSE; +GLboolean __GLEW_SGIX_resample = GL_FALSE; +GLboolean __GLEW_SGIX_scalebias_hint = GL_FALSE; +GLboolean __GLEW_SGIX_shadow = GL_FALSE; +GLboolean __GLEW_SGIX_shadow_ambient = GL_FALSE; +GLboolean __GLEW_SGIX_slim = GL_FALSE; +GLboolean __GLEW_SGIX_spotlight_cutoff = GL_FALSE; +GLboolean __GLEW_SGIX_sprite = GL_FALSE; +GLboolean __GLEW_SGIX_subdiv_patch = GL_FALSE; +GLboolean __GLEW_SGIX_subsample = GL_FALSE; +GLboolean __GLEW_SGIX_tag_sample_buffer = GL_FALSE; +GLboolean __GLEW_SGIX_texture_add_env = GL_FALSE; +GLboolean __GLEW_SGIX_texture_coordinate_clamp = GL_FALSE; +GLboolean __GLEW_SGIX_texture_lod_bias = GL_FALSE; +GLboolean __GLEW_SGIX_texture_mipmap_anisotropic = GL_FALSE; +GLboolean __GLEW_SGIX_texture_multi_buffer = GL_FALSE; +GLboolean __GLEW_SGIX_texture_phase = GL_FALSE; +GLboolean __GLEW_SGIX_texture_range = GL_FALSE; +GLboolean __GLEW_SGIX_texture_scale_bias = GL_FALSE; +GLboolean __GLEW_SGIX_texture_supersample = GL_FALSE; +GLboolean __GLEW_SGIX_vector_ops = GL_FALSE; +GLboolean __GLEW_SGIX_vertex_array_object = GL_FALSE; +GLboolean __GLEW_SGIX_vertex_preclip = GL_FALSE; +GLboolean __GLEW_SGIX_vertex_preclip_hint = GL_FALSE; +GLboolean __GLEW_SGIX_ycrcb = GL_FALSE; +GLboolean __GLEW_SGIX_ycrcb_subsample = GL_FALSE; +GLboolean __GLEW_SGIX_ycrcba = GL_FALSE; +GLboolean __GLEW_SGI_color_matrix = GL_FALSE; +GLboolean __GLEW_SGI_color_table = GL_FALSE; +GLboolean __GLEW_SGI_complex = GL_FALSE; +GLboolean __GLEW_SGI_complex_type = GL_FALSE; +GLboolean __GLEW_SGI_fft = GL_FALSE; +GLboolean __GLEW_SGI_texture_color_table = GL_FALSE; +GLboolean __GLEW_SUNX_constant_data = GL_FALSE; +GLboolean __GLEW_SUN_convolution_border_modes = GL_FALSE; +GLboolean __GLEW_SUN_global_alpha = GL_FALSE; +GLboolean __GLEW_SUN_mesh_array = GL_FALSE; +GLboolean __GLEW_SUN_read_video_pixels = GL_FALSE; +GLboolean __GLEW_SUN_slice_accum = GL_FALSE; +GLboolean __GLEW_SUN_triangle_list = GL_FALSE; +GLboolean __GLEW_SUN_vertex = GL_FALSE; +GLboolean __GLEW_WIN_phong_shading = GL_FALSE; +GLboolean __GLEW_WIN_scene_markerXXX = GL_FALSE; +GLboolean __GLEW_WIN_specular_fog = GL_FALSE; +GLboolean __GLEW_WIN_swap_hint = GL_FALSE; + +static const char * _glewExtensionLookup[] = { +#ifdef GL_VERSION_1_2 + "GL_VERSION_1_2", +#endif +#ifdef GL_VERSION_1_2_1 + "GL_VERSION_1_2_1", +#endif +#ifdef GL_VERSION_1_3 + "GL_VERSION_1_3", +#endif +#ifdef GL_VERSION_1_4 + "GL_VERSION_1_4", +#endif +#ifdef GL_VERSION_1_5 + "GL_VERSION_1_5", +#endif +#ifdef GL_VERSION_2_0 + "GL_VERSION_2_0", +#endif +#ifdef GL_VERSION_2_1 + "GL_VERSION_2_1", +#endif +#ifdef GL_VERSION_3_0 + "GL_VERSION_3_0", +#endif +#ifdef GL_VERSION_3_1 + "GL_VERSION_3_1", +#endif +#ifdef GL_VERSION_3_2 + "GL_VERSION_3_2", +#endif +#ifdef GL_VERSION_3_3 + "GL_VERSION_3_3", +#endif +#ifdef GL_VERSION_4_0 + "GL_VERSION_4_0", +#endif +#ifdef GL_VERSION_4_1 + "GL_VERSION_4_1", +#endif +#ifdef GL_VERSION_4_2 + "GL_VERSION_4_2", +#endif +#ifdef GL_VERSION_4_3 + "GL_VERSION_4_3", +#endif +#ifdef GL_VERSION_4_4 + "GL_VERSION_4_4", +#endif +#ifdef GL_VERSION_4_5 + "GL_VERSION_4_5", +#endif +#ifdef GL_VERSION_4_6 + "GL_VERSION_4_6", +#endif +#ifdef GL_3DFX_multisample + "GL_3DFX_multisample", +#endif +#ifdef GL_3DFX_tbuffer + "GL_3DFX_tbuffer", +#endif +#ifdef GL_3DFX_texture_compression_FXT1 + "GL_3DFX_texture_compression_FXT1", +#endif +#ifdef GL_AMD_blend_minmax_factor + "GL_AMD_blend_minmax_factor", +#endif +#ifdef GL_AMD_compressed_3DC_texture + "GL_AMD_compressed_3DC_texture", +#endif +#ifdef GL_AMD_compressed_ATC_texture + "GL_AMD_compressed_ATC_texture", +#endif +#ifdef GL_AMD_conservative_depth + "GL_AMD_conservative_depth", +#endif +#ifdef GL_AMD_debug_output + "GL_AMD_debug_output", +#endif +#ifdef GL_AMD_depth_clamp_separate + "GL_AMD_depth_clamp_separate", +#endif +#ifdef GL_AMD_draw_buffers_blend + "GL_AMD_draw_buffers_blend", +#endif +#ifdef GL_AMD_framebuffer_sample_positions + "GL_AMD_framebuffer_sample_positions", +#endif +#ifdef GL_AMD_gcn_shader + "GL_AMD_gcn_shader", +#endif +#ifdef GL_AMD_gpu_shader_half_float + "GL_AMD_gpu_shader_half_float", +#endif +#ifdef GL_AMD_gpu_shader_int16 + "GL_AMD_gpu_shader_int16", +#endif +#ifdef GL_AMD_gpu_shader_int64 + "GL_AMD_gpu_shader_int64", +#endif +#ifdef GL_AMD_interleaved_elements + "GL_AMD_interleaved_elements", +#endif +#ifdef GL_AMD_multi_draw_indirect + "GL_AMD_multi_draw_indirect", +#endif +#ifdef GL_AMD_name_gen_delete + "GL_AMD_name_gen_delete", +#endif +#ifdef GL_AMD_occlusion_query_event + "GL_AMD_occlusion_query_event", +#endif +#ifdef GL_AMD_performance_monitor + "GL_AMD_performance_monitor", +#endif +#ifdef GL_AMD_pinned_memory + "GL_AMD_pinned_memory", +#endif +#ifdef GL_AMD_program_binary_Z400 + "GL_AMD_program_binary_Z400", +#endif +#ifdef GL_AMD_query_buffer_object + "GL_AMD_query_buffer_object", +#endif +#ifdef GL_AMD_sample_positions + "GL_AMD_sample_positions", +#endif +#ifdef GL_AMD_seamless_cubemap_per_texture + "GL_AMD_seamless_cubemap_per_texture", +#endif +#ifdef GL_AMD_shader_atomic_counter_ops + "GL_AMD_shader_atomic_counter_ops", +#endif +#ifdef GL_AMD_shader_ballot + "GL_AMD_shader_ballot", +#endif +#ifdef GL_AMD_shader_explicit_vertex_parameter + "GL_AMD_shader_explicit_vertex_parameter", +#endif +#ifdef GL_AMD_shader_stencil_export + "GL_AMD_shader_stencil_export", +#endif +#ifdef GL_AMD_shader_stencil_value_export + "GL_AMD_shader_stencil_value_export", +#endif +#ifdef GL_AMD_shader_trinary_minmax + "GL_AMD_shader_trinary_minmax", +#endif +#ifdef GL_AMD_sparse_texture + "GL_AMD_sparse_texture", +#endif +#ifdef GL_AMD_stencil_operation_extended + "GL_AMD_stencil_operation_extended", +#endif +#ifdef GL_AMD_texture_gather_bias_lod + "GL_AMD_texture_gather_bias_lod", +#endif +#ifdef GL_AMD_texture_texture4 + "GL_AMD_texture_texture4", +#endif +#ifdef GL_AMD_transform_feedback3_lines_triangles + "GL_AMD_transform_feedback3_lines_triangles", +#endif +#ifdef GL_AMD_transform_feedback4 + "GL_AMD_transform_feedback4", +#endif +#ifdef GL_AMD_vertex_shader_layer + "GL_AMD_vertex_shader_layer", +#endif +#ifdef GL_AMD_vertex_shader_tessellator + "GL_AMD_vertex_shader_tessellator", +#endif +#ifdef GL_AMD_vertex_shader_viewport_index + "GL_AMD_vertex_shader_viewport_index", +#endif +#ifdef GL_ANDROID_extension_pack_es31a + "GL_ANDROID_extension_pack_es31a", +#endif +#ifdef GL_ANGLE_depth_texture + "GL_ANGLE_depth_texture", +#endif +#ifdef GL_ANGLE_framebuffer_blit + "GL_ANGLE_framebuffer_blit", +#endif +#ifdef GL_ANGLE_framebuffer_multisample + "GL_ANGLE_framebuffer_multisample", +#endif +#ifdef GL_ANGLE_instanced_arrays + "GL_ANGLE_instanced_arrays", +#endif +#ifdef GL_ANGLE_pack_reverse_row_order + "GL_ANGLE_pack_reverse_row_order", +#endif +#ifdef GL_ANGLE_program_binary + "GL_ANGLE_program_binary", +#endif +#ifdef GL_ANGLE_texture_compression_dxt1 + "GL_ANGLE_texture_compression_dxt1", +#endif +#ifdef GL_ANGLE_texture_compression_dxt3 + "GL_ANGLE_texture_compression_dxt3", +#endif +#ifdef GL_ANGLE_texture_compression_dxt5 + "GL_ANGLE_texture_compression_dxt5", +#endif +#ifdef GL_ANGLE_texture_usage + "GL_ANGLE_texture_usage", +#endif +#ifdef GL_ANGLE_timer_query + "GL_ANGLE_timer_query", +#endif +#ifdef GL_ANGLE_translated_shader_source + "GL_ANGLE_translated_shader_source", +#endif +#ifdef GL_APPLE_aux_depth_stencil + "GL_APPLE_aux_depth_stencil", +#endif +#ifdef GL_APPLE_client_storage + "GL_APPLE_client_storage", +#endif +#ifdef GL_APPLE_clip_distance + "GL_APPLE_clip_distance", +#endif +#ifdef GL_APPLE_color_buffer_packed_float + "GL_APPLE_color_buffer_packed_float", +#endif +#ifdef GL_APPLE_copy_texture_levels + "GL_APPLE_copy_texture_levels", +#endif +#ifdef GL_APPLE_element_array + "GL_APPLE_element_array", +#endif +#ifdef GL_APPLE_fence + "GL_APPLE_fence", +#endif +#ifdef GL_APPLE_float_pixels + "GL_APPLE_float_pixels", +#endif +#ifdef GL_APPLE_flush_buffer_range + "GL_APPLE_flush_buffer_range", +#endif +#ifdef GL_APPLE_framebuffer_multisample + "GL_APPLE_framebuffer_multisample", +#endif +#ifdef GL_APPLE_object_purgeable + "GL_APPLE_object_purgeable", +#endif +#ifdef GL_APPLE_pixel_buffer + "GL_APPLE_pixel_buffer", +#endif +#ifdef GL_APPLE_rgb_422 + "GL_APPLE_rgb_422", +#endif +#ifdef GL_APPLE_row_bytes + "GL_APPLE_row_bytes", +#endif +#ifdef GL_APPLE_specular_vector + "GL_APPLE_specular_vector", +#endif +#ifdef GL_APPLE_sync + "GL_APPLE_sync", +#endif +#ifdef GL_APPLE_texture_2D_limited_npot + "GL_APPLE_texture_2D_limited_npot", +#endif +#ifdef GL_APPLE_texture_format_BGRA8888 + "GL_APPLE_texture_format_BGRA8888", +#endif +#ifdef GL_APPLE_texture_max_level + "GL_APPLE_texture_max_level", +#endif +#ifdef GL_APPLE_texture_packed_float + "GL_APPLE_texture_packed_float", +#endif +#ifdef GL_APPLE_texture_range + "GL_APPLE_texture_range", +#endif +#ifdef GL_APPLE_transform_hint + "GL_APPLE_transform_hint", +#endif +#ifdef GL_APPLE_vertex_array_object + "GL_APPLE_vertex_array_object", +#endif +#ifdef GL_APPLE_vertex_array_range + "GL_APPLE_vertex_array_range", +#endif +#ifdef GL_APPLE_vertex_program_evaluators + "GL_APPLE_vertex_program_evaluators", +#endif +#ifdef GL_APPLE_ycbcr_422 + "GL_APPLE_ycbcr_422", +#endif +#ifdef GL_ARB_ES2_compatibility + "GL_ARB_ES2_compatibility", +#endif +#ifdef GL_ARB_ES3_1_compatibility + "GL_ARB_ES3_1_compatibility", +#endif +#ifdef GL_ARB_ES3_2_compatibility + "GL_ARB_ES3_2_compatibility", +#endif +#ifdef GL_ARB_ES3_compatibility + "GL_ARB_ES3_compatibility", +#endif +#ifdef GL_ARB_arrays_of_arrays + "GL_ARB_arrays_of_arrays", +#endif +#ifdef GL_ARB_base_instance + "GL_ARB_base_instance", +#endif +#ifdef GL_ARB_bindless_texture + "GL_ARB_bindless_texture", +#endif +#ifdef GL_ARB_blend_func_extended + "GL_ARB_blend_func_extended", +#endif +#ifdef GL_ARB_buffer_storage + "GL_ARB_buffer_storage", +#endif +#ifdef GL_ARB_cl_event + "GL_ARB_cl_event", +#endif +#ifdef GL_ARB_clear_buffer_object + "GL_ARB_clear_buffer_object", +#endif +#ifdef GL_ARB_clear_texture + "GL_ARB_clear_texture", +#endif +#ifdef GL_ARB_clip_control + "GL_ARB_clip_control", +#endif +#ifdef GL_ARB_color_buffer_float + "GL_ARB_color_buffer_float", +#endif +#ifdef GL_ARB_compatibility + "GL_ARB_compatibility", +#endif +#ifdef GL_ARB_compressed_texture_pixel_storage + "GL_ARB_compressed_texture_pixel_storage", +#endif +#ifdef GL_ARB_compute_shader + "GL_ARB_compute_shader", +#endif +#ifdef GL_ARB_compute_variable_group_size + "GL_ARB_compute_variable_group_size", +#endif +#ifdef GL_ARB_conditional_render_inverted + "GL_ARB_conditional_render_inverted", +#endif +#ifdef GL_ARB_conservative_depth + "GL_ARB_conservative_depth", +#endif +#ifdef GL_ARB_copy_buffer + "GL_ARB_copy_buffer", +#endif +#ifdef GL_ARB_copy_image + "GL_ARB_copy_image", +#endif +#ifdef GL_ARB_cull_distance + "GL_ARB_cull_distance", +#endif +#ifdef GL_ARB_debug_output + "GL_ARB_debug_output", +#endif +#ifdef GL_ARB_depth_buffer_float + "GL_ARB_depth_buffer_float", +#endif +#ifdef GL_ARB_depth_clamp + "GL_ARB_depth_clamp", +#endif +#ifdef GL_ARB_depth_texture + "GL_ARB_depth_texture", +#endif +#ifdef GL_ARB_derivative_control + "GL_ARB_derivative_control", +#endif +#ifdef GL_ARB_direct_state_access + "GL_ARB_direct_state_access", +#endif +#ifdef GL_ARB_draw_buffers + "GL_ARB_draw_buffers", +#endif +#ifdef GL_ARB_draw_buffers_blend + "GL_ARB_draw_buffers_blend", +#endif +#ifdef GL_ARB_draw_elements_base_vertex + "GL_ARB_draw_elements_base_vertex", +#endif +#ifdef GL_ARB_draw_indirect + "GL_ARB_draw_indirect", +#endif +#ifdef GL_ARB_draw_instanced + "GL_ARB_draw_instanced", +#endif +#ifdef GL_ARB_enhanced_layouts + "GL_ARB_enhanced_layouts", +#endif +#ifdef GL_ARB_explicit_attrib_location + "GL_ARB_explicit_attrib_location", +#endif +#ifdef GL_ARB_explicit_uniform_location + "GL_ARB_explicit_uniform_location", +#endif +#ifdef GL_ARB_fragment_coord_conventions + "GL_ARB_fragment_coord_conventions", +#endif +#ifdef GL_ARB_fragment_layer_viewport + "GL_ARB_fragment_layer_viewport", +#endif +#ifdef GL_ARB_fragment_program + "GL_ARB_fragment_program", +#endif +#ifdef GL_ARB_fragment_program_shadow + "GL_ARB_fragment_program_shadow", +#endif +#ifdef GL_ARB_fragment_shader + "GL_ARB_fragment_shader", +#endif +#ifdef GL_ARB_fragment_shader_interlock + "GL_ARB_fragment_shader_interlock", +#endif +#ifdef GL_ARB_framebuffer_no_attachments + "GL_ARB_framebuffer_no_attachments", +#endif +#ifdef GL_ARB_framebuffer_object + "GL_ARB_framebuffer_object", +#endif +#ifdef GL_ARB_framebuffer_sRGB + "GL_ARB_framebuffer_sRGB", +#endif +#ifdef GL_ARB_geometry_shader4 + "GL_ARB_geometry_shader4", +#endif +#ifdef GL_ARB_get_program_binary + "GL_ARB_get_program_binary", +#endif +#ifdef GL_ARB_get_texture_sub_image + "GL_ARB_get_texture_sub_image", +#endif +#ifdef GL_ARB_gl_spirv + "GL_ARB_gl_spirv", +#endif +#ifdef GL_ARB_gpu_shader5 + "GL_ARB_gpu_shader5", +#endif +#ifdef GL_ARB_gpu_shader_fp64 + "GL_ARB_gpu_shader_fp64", +#endif +#ifdef GL_ARB_gpu_shader_int64 + "GL_ARB_gpu_shader_int64", +#endif +#ifdef GL_ARB_half_float_pixel + "GL_ARB_half_float_pixel", +#endif +#ifdef GL_ARB_half_float_vertex + "GL_ARB_half_float_vertex", +#endif +#ifdef GL_ARB_imaging + "GL_ARB_imaging", +#endif +#ifdef GL_ARB_indirect_parameters + "GL_ARB_indirect_parameters", +#endif +#ifdef GL_ARB_instanced_arrays + "GL_ARB_instanced_arrays", +#endif +#ifdef GL_ARB_internalformat_query + "GL_ARB_internalformat_query", +#endif +#ifdef GL_ARB_internalformat_query2 + "GL_ARB_internalformat_query2", +#endif +#ifdef GL_ARB_invalidate_subdata + "GL_ARB_invalidate_subdata", +#endif +#ifdef GL_ARB_map_buffer_alignment + "GL_ARB_map_buffer_alignment", +#endif +#ifdef GL_ARB_map_buffer_range + "GL_ARB_map_buffer_range", +#endif +#ifdef GL_ARB_matrix_palette + "GL_ARB_matrix_palette", +#endif +#ifdef GL_ARB_multi_bind + "GL_ARB_multi_bind", +#endif +#ifdef GL_ARB_multi_draw_indirect + "GL_ARB_multi_draw_indirect", +#endif +#ifdef GL_ARB_multisample + "GL_ARB_multisample", +#endif +#ifdef GL_ARB_multitexture + "GL_ARB_multitexture", +#endif +#ifdef GL_ARB_occlusion_query + "GL_ARB_occlusion_query", +#endif +#ifdef GL_ARB_occlusion_query2 + "GL_ARB_occlusion_query2", +#endif +#ifdef GL_ARB_parallel_shader_compile + "GL_ARB_parallel_shader_compile", +#endif +#ifdef GL_ARB_pipeline_statistics_query + "GL_ARB_pipeline_statistics_query", +#endif +#ifdef GL_ARB_pixel_buffer_object + "GL_ARB_pixel_buffer_object", +#endif +#ifdef GL_ARB_point_parameters + "GL_ARB_point_parameters", +#endif +#ifdef GL_ARB_point_sprite + "GL_ARB_point_sprite", +#endif +#ifdef GL_ARB_polygon_offset_clamp + "GL_ARB_polygon_offset_clamp", +#endif +#ifdef GL_ARB_post_depth_coverage + "GL_ARB_post_depth_coverage", +#endif +#ifdef GL_ARB_program_interface_query + "GL_ARB_program_interface_query", +#endif +#ifdef GL_ARB_provoking_vertex + "GL_ARB_provoking_vertex", +#endif +#ifdef GL_ARB_query_buffer_object + "GL_ARB_query_buffer_object", +#endif +#ifdef GL_ARB_robust_buffer_access_behavior + "GL_ARB_robust_buffer_access_behavior", +#endif +#ifdef GL_ARB_robustness + "GL_ARB_robustness", +#endif +#ifdef GL_ARB_robustness_application_isolation + "GL_ARB_robustness_application_isolation", +#endif +#ifdef GL_ARB_robustness_share_group_isolation + "GL_ARB_robustness_share_group_isolation", +#endif +#ifdef GL_ARB_sample_locations + "GL_ARB_sample_locations", +#endif +#ifdef GL_ARB_sample_shading + "GL_ARB_sample_shading", +#endif +#ifdef GL_ARB_sampler_objects + "GL_ARB_sampler_objects", +#endif +#ifdef GL_ARB_seamless_cube_map + "GL_ARB_seamless_cube_map", +#endif +#ifdef GL_ARB_seamless_cubemap_per_texture + "GL_ARB_seamless_cubemap_per_texture", +#endif +#ifdef GL_ARB_separate_shader_objects + "GL_ARB_separate_shader_objects", +#endif +#ifdef GL_ARB_shader_atomic_counter_ops + "GL_ARB_shader_atomic_counter_ops", +#endif +#ifdef GL_ARB_shader_atomic_counters + "GL_ARB_shader_atomic_counters", +#endif +#ifdef GL_ARB_shader_ballot + "GL_ARB_shader_ballot", +#endif +#ifdef GL_ARB_shader_bit_encoding + "GL_ARB_shader_bit_encoding", +#endif +#ifdef GL_ARB_shader_clock + "GL_ARB_shader_clock", +#endif +#ifdef GL_ARB_shader_draw_parameters + "GL_ARB_shader_draw_parameters", +#endif +#ifdef GL_ARB_shader_group_vote + "GL_ARB_shader_group_vote", +#endif +#ifdef GL_ARB_shader_image_load_store + "GL_ARB_shader_image_load_store", +#endif +#ifdef GL_ARB_shader_image_size + "GL_ARB_shader_image_size", +#endif +#ifdef GL_ARB_shader_objects + "GL_ARB_shader_objects", +#endif +#ifdef GL_ARB_shader_precision + "GL_ARB_shader_precision", +#endif +#ifdef GL_ARB_shader_stencil_export + "GL_ARB_shader_stencil_export", +#endif +#ifdef GL_ARB_shader_storage_buffer_object + "GL_ARB_shader_storage_buffer_object", +#endif +#ifdef GL_ARB_shader_subroutine + "GL_ARB_shader_subroutine", +#endif +#ifdef GL_ARB_shader_texture_image_samples + "GL_ARB_shader_texture_image_samples", +#endif +#ifdef GL_ARB_shader_texture_lod + "GL_ARB_shader_texture_lod", +#endif +#ifdef GL_ARB_shader_viewport_layer_array + "GL_ARB_shader_viewport_layer_array", +#endif +#ifdef GL_ARB_shading_language_100 + "GL_ARB_shading_language_100", +#endif +#ifdef GL_ARB_shading_language_420pack + "GL_ARB_shading_language_420pack", +#endif +#ifdef GL_ARB_shading_language_include + "GL_ARB_shading_language_include", +#endif +#ifdef GL_ARB_shading_language_packing + "GL_ARB_shading_language_packing", +#endif +#ifdef GL_ARB_shadow + "GL_ARB_shadow", +#endif +#ifdef GL_ARB_shadow_ambient + "GL_ARB_shadow_ambient", +#endif +#ifdef GL_ARB_sparse_buffer + "GL_ARB_sparse_buffer", +#endif +#ifdef GL_ARB_sparse_texture + "GL_ARB_sparse_texture", +#endif +#ifdef GL_ARB_sparse_texture2 + "GL_ARB_sparse_texture2", +#endif +#ifdef GL_ARB_sparse_texture_clamp + "GL_ARB_sparse_texture_clamp", +#endif +#ifdef GL_ARB_spirv_extensions + "GL_ARB_spirv_extensions", +#endif +#ifdef GL_ARB_stencil_texturing + "GL_ARB_stencil_texturing", +#endif +#ifdef GL_ARB_sync + "GL_ARB_sync", +#endif +#ifdef GL_ARB_tessellation_shader + "GL_ARB_tessellation_shader", +#endif +#ifdef GL_ARB_texture_barrier + "GL_ARB_texture_barrier", +#endif +#ifdef GL_ARB_texture_border_clamp + "GL_ARB_texture_border_clamp", +#endif +#ifdef GL_ARB_texture_buffer_object + "GL_ARB_texture_buffer_object", +#endif +#ifdef GL_ARB_texture_buffer_object_rgb32 + "GL_ARB_texture_buffer_object_rgb32", +#endif +#ifdef GL_ARB_texture_buffer_range + "GL_ARB_texture_buffer_range", +#endif +#ifdef GL_ARB_texture_compression + "GL_ARB_texture_compression", +#endif +#ifdef GL_ARB_texture_compression_bptc + "GL_ARB_texture_compression_bptc", +#endif +#ifdef GL_ARB_texture_compression_rgtc + "GL_ARB_texture_compression_rgtc", +#endif +#ifdef GL_ARB_texture_cube_map + "GL_ARB_texture_cube_map", +#endif +#ifdef GL_ARB_texture_cube_map_array + "GL_ARB_texture_cube_map_array", +#endif +#ifdef GL_ARB_texture_env_add + "GL_ARB_texture_env_add", +#endif +#ifdef GL_ARB_texture_env_combine + "GL_ARB_texture_env_combine", +#endif +#ifdef GL_ARB_texture_env_crossbar + "GL_ARB_texture_env_crossbar", +#endif +#ifdef GL_ARB_texture_env_dot3 + "GL_ARB_texture_env_dot3", +#endif +#ifdef GL_ARB_texture_filter_anisotropic + "GL_ARB_texture_filter_anisotropic", +#endif +#ifdef GL_ARB_texture_filter_minmax + "GL_ARB_texture_filter_minmax", +#endif +#ifdef GL_ARB_texture_float + "GL_ARB_texture_float", +#endif +#ifdef GL_ARB_texture_gather + "GL_ARB_texture_gather", +#endif +#ifdef GL_ARB_texture_mirror_clamp_to_edge + "GL_ARB_texture_mirror_clamp_to_edge", +#endif +#ifdef GL_ARB_texture_mirrored_repeat + "GL_ARB_texture_mirrored_repeat", +#endif +#ifdef GL_ARB_texture_multisample + "GL_ARB_texture_multisample", +#endif +#ifdef GL_ARB_texture_non_power_of_two + "GL_ARB_texture_non_power_of_two", +#endif +#ifdef GL_ARB_texture_query_levels + "GL_ARB_texture_query_levels", +#endif +#ifdef GL_ARB_texture_query_lod + "GL_ARB_texture_query_lod", +#endif +#ifdef GL_ARB_texture_rectangle + "GL_ARB_texture_rectangle", +#endif +#ifdef GL_ARB_texture_rg + "GL_ARB_texture_rg", +#endif +#ifdef GL_ARB_texture_rgb10_a2ui + "GL_ARB_texture_rgb10_a2ui", +#endif +#ifdef GL_ARB_texture_stencil8 + "GL_ARB_texture_stencil8", +#endif +#ifdef GL_ARB_texture_storage + "GL_ARB_texture_storage", +#endif +#ifdef GL_ARB_texture_storage_multisample + "GL_ARB_texture_storage_multisample", +#endif +#ifdef GL_ARB_texture_swizzle + "GL_ARB_texture_swizzle", +#endif +#ifdef GL_ARB_texture_view + "GL_ARB_texture_view", +#endif +#ifdef GL_ARB_timer_query + "GL_ARB_timer_query", +#endif +#ifdef GL_ARB_transform_feedback2 + "GL_ARB_transform_feedback2", +#endif +#ifdef GL_ARB_transform_feedback3 + "GL_ARB_transform_feedback3", +#endif +#ifdef GL_ARB_transform_feedback_instanced + "GL_ARB_transform_feedback_instanced", +#endif +#ifdef GL_ARB_transform_feedback_overflow_query + "GL_ARB_transform_feedback_overflow_query", +#endif +#ifdef GL_ARB_transpose_matrix + "GL_ARB_transpose_matrix", +#endif +#ifdef GL_ARB_uniform_buffer_object + "GL_ARB_uniform_buffer_object", +#endif +#ifdef GL_ARB_vertex_array_bgra + "GL_ARB_vertex_array_bgra", +#endif +#ifdef GL_ARB_vertex_array_object + "GL_ARB_vertex_array_object", +#endif +#ifdef GL_ARB_vertex_attrib_64bit + "GL_ARB_vertex_attrib_64bit", +#endif +#ifdef GL_ARB_vertex_attrib_binding + "GL_ARB_vertex_attrib_binding", +#endif +#ifdef GL_ARB_vertex_blend + "GL_ARB_vertex_blend", +#endif +#ifdef GL_ARB_vertex_buffer_object + "GL_ARB_vertex_buffer_object", +#endif +#ifdef GL_ARB_vertex_program + "GL_ARB_vertex_program", +#endif +#ifdef GL_ARB_vertex_shader + "GL_ARB_vertex_shader", +#endif +#ifdef GL_ARB_vertex_type_10f_11f_11f_rev + "GL_ARB_vertex_type_10f_11f_11f_rev", +#endif +#ifdef GL_ARB_vertex_type_2_10_10_10_rev + "GL_ARB_vertex_type_2_10_10_10_rev", +#endif +#ifdef GL_ARB_viewport_array + "GL_ARB_viewport_array", +#endif +#ifdef GL_ARB_window_pos + "GL_ARB_window_pos", +#endif +#ifdef GL_ARM_mali_program_binary + "GL_ARM_mali_program_binary", +#endif +#ifdef GL_ARM_mali_shader_binary + "GL_ARM_mali_shader_binary", +#endif +#ifdef GL_ARM_rgba8 + "GL_ARM_rgba8", +#endif +#ifdef GL_ARM_shader_framebuffer_fetch + "GL_ARM_shader_framebuffer_fetch", +#endif +#ifdef GL_ARM_shader_framebuffer_fetch_depth_stencil + "GL_ARM_shader_framebuffer_fetch_depth_stencil", +#endif +#ifdef GL_ATIX_point_sprites + "GL_ATIX_point_sprites", +#endif +#ifdef GL_ATIX_texture_env_combine3 + "GL_ATIX_texture_env_combine3", +#endif +#ifdef GL_ATIX_texture_env_route + "GL_ATIX_texture_env_route", +#endif +#ifdef GL_ATIX_vertex_shader_output_point_size + "GL_ATIX_vertex_shader_output_point_size", +#endif +#ifdef GL_ATI_draw_buffers + "GL_ATI_draw_buffers", +#endif +#ifdef GL_ATI_element_array + "GL_ATI_element_array", +#endif +#ifdef GL_ATI_envmap_bumpmap + "GL_ATI_envmap_bumpmap", +#endif +#ifdef GL_ATI_fragment_shader + "GL_ATI_fragment_shader", +#endif +#ifdef GL_ATI_map_object_buffer + "GL_ATI_map_object_buffer", +#endif +#ifdef GL_ATI_meminfo + "GL_ATI_meminfo", +#endif +#ifdef GL_ATI_pn_triangles + "GL_ATI_pn_triangles", +#endif +#ifdef GL_ATI_separate_stencil + "GL_ATI_separate_stencil", +#endif +#ifdef GL_ATI_shader_texture_lod + "GL_ATI_shader_texture_lod", +#endif +#ifdef GL_ATI_text_fragment_shader + "GL_ATI_text_fragment_shader", +#endif +#ifdef GL_ATI_texture_compression_3dc + "GL_ATI_texture_compression_3dc", +#endif +#ifdef GL_ATI_texture_env_combine3 + "GL_ATI_texture_env_combine3", +#endif +#ifdef GL_ATI_texture_float + "GL_ATI_texture_float", +#endif +#ifdef GL_ATI_texture_mirror_once + "GL_ATI_texture_mirror_once", +#endif +#ifdef GL_ATI_vertex_array_object + "GL_ATI_vertex_array_object", +#endif +#ifdef GL_ATI_vertex_attrib_array_object + "GL_ATI_vertex_attrib_array_object", +#endif +#ifdef GL_ATI_vertex_streams + "GL_ATI_vertex_streams", +#endif +#ifdef GL_EGL_KHR_context_flush_control + "GL_EGL_KHR_context_flush_control", +#endif +#ifdef GL_EGL_NV_robustness_video_memory_purge + "GL_EGL_NV_robustness_video_memory_purge", +#endif +#ifdef GL_EXT_422_pixels + "GL_EXT_422_pixels", +#endif +#ifdef GL_EXT_Cg_shader + "GL_EXT_Cg_shader", +#endif +#ifdef GL_EXT_EGL_image_array + "GL_EXT_EGL_image_array", +#endif +#ifdef GL_EXT_YUV_target + "GL_EXT_YUV_target", +#endif +#ifdef GL_EXT_abgr + "GL_EXT_abgr", +#endif +#ifdef GL_EXT_base_instance + "GL_EXT_base_instance", +#endif +#ifdef GL_EXT_bgra + "GL_EXT_bgra", +#endif +#ifdef GL_EXT_bindable_uniform + "GL_EXT_bindable_uniform", +#endif +#ifdef GL_EXT_blend_color + "GL_EXT_blend_color", +#endif +#ifdef GL_EXT_blend_equation_separate + "GL_EXT_blend_equation_separate", +#endif +#ifdef GL_EXT_blend_func_extended + "GL_EXT_blend_func_extended", +#endif +#ifdef GL_EXT_blend_func_separate + "GL_EXT_blend_func_separate", +#endif +#ifdef GL_EXT_blend_logic_op + "GL_EXT_blend_logic_op", +#endif +#ifdef GL_EXT_blend_minmax + "GL_EXT_blend_minmax", +#endif +#ifdef GL_EXT_blend_subtract + "GL_EXT_blend_subtract", +#endif +#ifdef GL_EXT_buffer_storage + "GL_EXT_buffer_storage", +#endif +#ifdef GL_EXT_clear_texture + "GL_EXT_clear_texture", +#endif +#ifdef GL_EXT_clip_cull_distance + "GL_EXT_clip_cull_distance", +#endif +#ifdef GL_EXT_clip_volume_hint + "GL_EXT_clip_volume_hint", +#endif +#ifdef GL_EXT_cmyka + "GL_EXT_cmyka", +#endif +#ifdef GL_EXT_color_buffer_float + "GL_EXT_color_buffer_float", +#endif +#ifdef GL_EXT_color_buffer_half_float + "GL_EXT_color_buffer_half_float", +#endif +#ifdef GL_EXT_color_subtable + "GL_EXT_color_subtable", +#endif +#ifdef GL_EXT_compiled_vertex_array + "GL_EXT_compiled_vertex_array", +#endif +#ifdef GL_EXT_compressed_ETC1_RGB8_sub_texture + "GL_EXT_compressed_ETC1_RGB8_sub_texture", +#endif +#ifdef GL_EXT_conservative_depth + "GL_EXT_conservative_depth", +#endif +#ifdef GL_EXT_convolution + "GL_EXT_convolution", +#endif +#ifdef GL_EXT_coordinate_frame + "GL_EXT_coordinate_frame", +#endif +#ifdef GL_EXT_copy_image + "GL_EXT_copy_image", +#endif +#ifdef GL_EXT_copy_texture + "GL_EXT_copy_texture", +#endif +#ifdef GL_EXT_cull_vertex + "GL_EXT_cull_vertex", +#endif +#ifdef GL_EXT_debug_label + "GL_EXT_debug_label", +#endif +#ifdef GL_EXT_debug_marker + "GL_EXT_debug_marker", +#endif +#ifdef GL_EXT_depth_bounds_test + "GL_EXT_depth_bounds_test", +#endif +#ifdef GL_EXT_direct_state_access + "GL_EXT_direct_state_access", +#endif +#ifdef GL_EXT_discard_framebuffer + "GL_EXT_discard_framebuffer", +#endif +#ifdef GL_EXT_draw_buffers + "GL_EXT_draw_buffers", +#endif +#ifdef GL_EXT_draw_buffers2 + "GL_EXT_draw_buffers2", +#endif +#ifdef GL_EXT_draw_buffers_indexed + "GL_EXT_draw_buffers_indexed", +#endif +#ifdef GL_EXT_draw_elements_base_vertex + "GL_EXT_draw_elements_base_vertex", +#endif +#ifdef GL_EXT_draw_instanced + "GL_EXT_draw_instanced", +#endif +#ifdef GL_EXT_draw_range_elements + "GL_EXT_draw_range_elements", +#endif +#ifdef GL_EXT_external_buffer + "GL_EXT_external_buffer", +#endif +#ifdef GL_EXT_float_blend + "GL_EXT_float_blend", +#endif +#ifdef GL_EXT_fog_coord + "GL_EXT_fog_coord", +#endif +#ifdef GL_EXT_frag_depth + "GL_EXT_frag_depth", +#endif +#ifdef GL_EXT_fragment_lighting + "GL_EXT_fragment_lighting", +#endif +#ifdef GL_EXT_framebuffer_blit + "GL_EXT_framebuffer_blit", +#endif +#ifdef GL_EXT_framebuffer_multisample + "GL_EXT_framebuffer_multisample", +#endif +#ifdef GL_EXT_framebuffer_multisample_blit_scaled + "GL_EXT_framebuffer_multisample_blit_scaled", +#endif +#ifdef GL_EXT_framebuffer_object + "GL_EXT_framebuffer_object", +#endif +#ifdef GL_EXT_framebuffer_sRGB + "GL_EXT_framebuffer_sRGB", +#endif +#ifdef GL_EXT_geometry_point_size + "GL_EXT_geometry_point_size", +#endif +#ifdef GL_EXT_geometry_shader + "GL_EXT_geometry_shader", +#endif +#ifdef GL_EXT_geometry_shader4 + "GL_EXT_geometry_shader4", +#endif +#ifdef GL_EXT_gpu_program_parameters + "GL_EXT_gpu_program_parameters", +#endif +#ifdef GL_EXT_gpu_shader4 + "GL_EXT_gpu_shader4", +#endif +#ifdef GL_EXT_gpu_shader5 + "GL_EXT_gpu_shader5", +#endif +#ifdef GL_EXT_histogram + "GL_EXT_histogram", +#endif +#ifdef GL_EXT_index_array_formats + "GL_EXT_index_array_formats", +#endif +#ifdef GL_EXT_index_func + "GL_EXT_index_func", +#endif +#ifdef GL_EXT_index_material + "GL_EXT_index_material", +#endif +#ifdef GL_EXT_index_texture + "GL_EXT_index_texture", +#endif +#ifdef GL_EXT_instanced_arrays + "GL_EXT_instanced_arrays", +#endif +#ifdef GL_EXT_light_texture + "GL_EXT_light_texture", +#endif +#ifdef GL_EXT_map_buffer_range + "GL_EXT_map_buffer_range", +#endif +#ifdef GL_EXT_memory_object + "GL_EXT_memory_object", +#endif +#ifdef GL_EXT_memory_object_fd + "GL_EXT_memory_object_fd", +#endif +#ifdef GL_EXT_memory_object_win32 + "GL_EXT_memory_object_win32", +#endif +#ifdef GL_EXT_misc_attribute + "GL_EXT_misc_attribute", +#endif +#ifdef GL_EXT_multi_draw_arrays + "GL_EXT_multi_draw_arrays", +#endif +#ifdef GL_EXT_multi_draw_indirect + "GL_EXT_multi_draw_indirect", +#endif +#ifdef GL_EXT_multiple_textures + "GL_EXT_multiple_textures", +#endif +#ifdef GL_EXT_multisample + "GL_EXT_multisample", +#endif +#ifdef GL_EXT_multisample_compatibility + "GL_EXT_multisample_compatibility", +#endif +#ifdef GL_EXT_multisampled_render_to_texture + "GL_EXT_multisampled_render_to_texture", +#endif +#ifdef GL_EXT_multisampled_render_to_texture2 + "GL_EXT_multisampled_render_to_texture2", +#endif +#ifdef GL_EXT_multiview_draw_buffers + "GL_EXT_multiview_draw_buffers", +#endif +#ifdef GL_EXT_packed_depth_stencil + "GL_EXT_packed_depth_stencil", +#endif +#ifdef GL_EXT_packed_float + "GL_EXT_packed_float", +#endif +#ifdef GL_EXT_packed_pixels + "GL_EXT_packed_pixels", +#endif +#ifdef GL_EXT_paletted_texture + "GL_EXT_paletted_texture", +#endif +#ifdef GL_EXT_pixel_buffer_object + "GL_EXT_pixel_buffer_object", +#endif +#ifdef GL_EXT_pixel_transform + "GL_EXT_pixel_transform", +#endif +#ifdef GL_EXT_pixel_transform_color_table + "GL_EXT_pixel_transform_color_table", +#endif +#ifdef GL_EXT_point_parameters + "GL_EXT_point_parameters", +#endif +#ifdef GL_EXT_polygon_offset + "GL_EXT_polygon_offset", +#endif +#ifdef GL_EXT_polygon_offset_clamp + "GL_EXT_polygon_offset_clamp", +#endif +#ifdef GL_EXT_post_depth_coverage + "GL_EXT_post_depth_coverage", +#endif +#ifdef GL_EXT_provoking_vertex + "GL_EXT_provoking_vertex", +#endif +#ifdef GL_EXT_pvrtc_sRGB + "GL_EXT_pvrtc_sRGB", +#endif +#ifdef GL_EXT_raster_multisample + "GL_EXT_raster_multisample", +#endif +#ifdef GL_EXT_read_format_bgra + "GL_EXT_read_format_bgra", +#endif +#ifdef GL_EXT_render_snorm + "GL_EXT_render_snorm", +#endif +#ifdef GL_EXT_rescale_normal + "GL_EXT_rescale_normal", +#endif +#ifdef GL_EXT_sRGB + "GL_EXT_sRGB", +#endif +#ifdef GL_EXT_sRGB_write_control + "GL_EXT_sRGB_write_control", +#endif +#ifdef GL_EXT_scene_marker + "GL_EXT_scene_marker", +#endif +#ifdef GL_EXT_secondary_color + "GL_EXT_secondary_color", +#endif +#ifdef GL_EXT_semaphore + "GL_EXT_semaphore", +#endif +#ifdef GL_EXT_semaphore_fd + "GL_EXT_semaphore_fd", +#endif +#ifdef GL_EXT_semaphore_win32 + "GL_EXT_semaphore_win32", +#endif +#ifdef GL_EXT_separate_shader_objects + "GL_EXT_separate_shader_objects", +#endif +#ifdef GL_EXT_separate_specular_color + "GL_EXT_separate_specular_color", +#endif +#ifdef GL_EXT_shader_framebuffer_fetch + "GL_EXT_shader_framebuffer_fetch", +#endif +#ifdef GL_EXT_shader_group_vote + "GL_EXT_shader_group_vote", +#endif +#ifdef GL_EXT_shader_image_load_formatted + "GL_EXT_shader_image_load_formatted", +#endif +#ifdef GL_EXT_shader_image_load_store + "GL_EXT_shader_image_load_store", +#endif +#ifdef GL_EXT_shader_implicit_conversions + "GL_EXT_shader_implicit_conversions", +#endif +#ifdef GL_EXT_shader_integer_mix + "GL_EXT_shader_integer_mix", +#endif +#ifdef GL_EXT_shader_io_blocks + "GL_EXT_shader_io_blocks", +#endif +#ifdef GL_EXT_shader_non_constant_global_initializers + "GL_EXT_shader_non_constant_global_initializers", +#endif +#ifdef GL_EXT_shader_pixel_local_storage + "GL_EXT_shader_pixel_local_storage", +#endif +#ifdef GL_EXT_shader_pixel_local_storage2 + "GL_EXT_shader_pixel_local_storage2", +#endif +#ifdef GL_EXT_shader_texture_lod + "GL_EXT_shader_texture_lod", +#endif +#ifdef GL_EXT_shadow_funcs + "GL_EXT_shadow_funcs", +#endif +#ifdef GL_EXT_shadow_samplers + "GL_EXT_shadow_samplers", +#endif +#ifdef GL_EXT_shared_texture_palette + "GL_EXT_shared_texture_palette", +#endif +#ifdef GL_EXT_sparse_texture + "GL_EXT_sparse_texture", +#endif +#ifdef GL_EXT_sparse_texture2 + "GL_EXT_sparse_texture2", +#endif +#ifdef GL_EXT_stencil_clear_tag + "GL_EXT_stencil_clear_tag", +#endif +#ifdef GL_EXT_stencil_two_side + "GL_EXT_stencil_two_side", +#endif +#ifdef GL_EXT_stencil_wrap + "GL_EXT_stencil_wrap", +#endif +#ifdef GL_EXT_subtexture + "GL_EXT_subtexture", +#endif +#ifdef GL_EXT_texture + "GL_EXT_texture", +#endif +#ifdef GL_EXT_texture3D + "GL_EXT_texture3D", +#endif +#ifdef GL_EXT_texture_array + "GL_EXT_texture_array", +#endif +#ifdef GL_EXT_texture_buffer_object + "GL_EXT_texture_buffer_object", +#endif +#ifdef GL_EXT_texture_compression_astc_decode_mode + "GL_EXT_texture_compression_astc_decode_mode", +#endif +#ifdef GL_EXT_texture_compression_astc_decode_mode_rgb9e5 + "GL_EXT_texture_compression_astc_decode_mode_rgb9e5", +#endif +#ifdef GL_EXT_texture_compression_bptc + "GL_EXT_texture_compression_bptc", +#endif +#ifdef GL_EXT_texture_compression_dxt1 + "GL_EXT_texture_compression_dxt1", +#endif +#ifdef GL_EXT_texture_compression_latc + "GL_EXT_texture_compression_latc", +#endif +#ifdef GL_EXT_texture_compression_rgtc + "GL_EXT_texture_compression_rgtc", +#endif +#ifdef GL_EXT_texture_compression_s3tc + "GL_EXT_texture_compression_s3tc", +#endif +#ifdef GL_EXT_texture_cube_map + "GL_EXT_texture_cube_map", +#endif +#ifdef GL_EXT_texture_cube_map_array + "GL_EXT_texture_cube_map_array", +#endif +#ifdef GL_EXT_texture_edge_clamp + "GL_EXT_texture_edge_clamp", +#endif +#ifdef GL_EXT_texture_env + "GL_EXT_texture_env", +#endif +#ifdef GL_EXT_texture_env_add + "GL_EXT_texture_env_add", +#endif +#ifdef GL_EXT_texture_env_combine + "GL_EXT_texture_env_combine", +#endif +#ifdef GL_EXT_texture_env_dot3 + "GL_EXT_texture_env_dot3", +#endif +#ifdef GL_EXT_texture_filter_anisotropic + "GL_EXT_texture_filter_anisotropic", +#endif +#ifdef GL_EXT_texture_filter_minmax + "GL_EXT_texture_filter_minmax", +#endif +#ifdef GL_EXT_texture_format_BGRA8888 + "GL_EXT_texture_format_BGRA8888", +#endif +#ifdef GL_EXT_texture_integer + "GL_EXT_texture_integer", +#endif +#ifdef GL_EXT_texture_lod_bias + "GL_EXT_texture_lod_bias", +#endif +#ifdef GL_EXT_texture_mirror_clamp + "GL_EXT_texture_mirror_clamp", +#endif +#ifdef GL_EXT_texture_norm16 + "GL_EXT_texture_norm16", +#endif +#ifdef GL_EXT_texture_object + "GL_EXT_texture_object", +#endif +#ifdef GL_EXT_texture_perturb_normal + "GL_EXT_texture_perturb_normal", +#endif +#ifdef GL_EXT_texture_rectangle + "GL_EXT_texture_rectangle", +#endif +#ifdef GL_EXT_texture_rg + "GL_EXT_texture_rg", +#endif +#ifdef GL_EXT_texture_sRGB + "GL_EXT_texture_sRGB", +#endif +#ifdef GL_EXT_texture_sRGB_R8 + "GL_EXT_texture_sRGB_R8", +#endif +#ifdef GL_EXT_texture_sRGB_RG8 + "GL_EXT_texture_sRGB_RG8", +#endif +#ifdef GL_EXT_texture_sRGB_decode + "GL_EXT_texture_sRGB_decode", +#endif +#ifdef GL_EXT_texture_shared_exponent + "GL_EXT_texture_shared_exponent", +#endif +#ifdef GL_EXT_texture_snorm + "GL_EXT_texture_snorm", +#endif +#ifdef GL_EXT_texture_storage + "GL_EXT_texture_storage", +#endif +#ifdef GL_EXT_texture_swizzle + "GL_EXT_texture_swizzle", +#endif +#ifdef GL_EXT_texture_type_2_10_10_10_REV + "GL_EXT_texture_type_2_10_10_10_REV", +#endif +#ifdef GL_EXT_texture_view + "GL_EXT_texture_view", +#endif +#ifdef GL_EXT_timer_query + "GL_EXT_timer_query", +#endif +#ifdef GL_EXT_transform_feedback + "GL_EXT_transform_feedback", +#endif +#ifdef GL_EXT_unpack_subimage + "GL_EXT_unpack_subimage", +#endif +#ifdef GL_EXT_vertex_array + "GL_EXT_vertex_array", +#endif +#ifdef GL_EXT_vertex_array_bgra + "GL_EXT_vertex_array_bgra", +#endif +#ifdef GL_EXT_vertex_array_setXXX + "GL_EXT_vertex_array_setXXX", +#endif +#ifdef GL_EXT_vertex_attrib_64bit + "GL_EXT_vertex_attrib_64bit", +#endif +#ifdef GL_EXT_vertex_shader + "GL_EXT_vertex_shader", +#endif +#ifdef GL_EXT_vertex_weighting + "GL_EXT_vertex_weighting", +#endif +#ifdef GL_EXT_win32_keyed_mutex + "GL_EXT_win32_keyed_mutex", +#endif +#ifdef GL_EXT_window_rectangles + "GL_EXT_window_rectangles", +#endif +#ifdef GL_EXT_x11_sync_object + "GL_EXT_x11_sync_object", +#endif +#ifdef GL_GREMEDY_frame_terminator + "GL_GREMEDY_frame_terminator", +#endif +#ifdef GL_GREMEDY_string_marker + "GL_GREMEDY_string_marker", +#endif +#ifdef GL_HP_convolution_border_modes + "GL_HP_convolution_border_modes", +#endif +#ifdef GL_HP_image_transform + "GL_HP_image_transform", +#endif +#ifdef GL_HP_occlusion_test + "GL_HP_occlusion_test", +#endif +#ifdef GL_HP_texture_lighting + "GL_HP_texture_lighting", +#endif +#ifdef GL_IBM_cull_vertex + "GL_IBM_cull_vertex", +#endif +#ifdef GL_IBM_multimode_draw_arrays + "GL_IBM_multimode_draw_arrays", +#endif +#ifdef GL_IBM_rasterpos_clip + "GL_IBM_rasterpos_clip", +#endif +#ifdef GL_IBM_static_data + "GL_IBM_static_data", +#endif +#ifdef GL_IBM_texture_mirrored_repeat + "GL_IBM_texture_mirrored_repeat", +#endif +#ifdef GL_IBM_vertex_array_lists + "GL_IBM_vertex_array_lists", +#endif +#ifdef GL_INGR_color_clamp + "GL_INGR_color_clamp", +#endif +#ifdef GL_INGR_interlace_read + "GL_INGR_interlace_read", +#endif +#ifdef GL_INTEL_conservative_rasterization + "GL_INTEL_conservative_rasterization", +#endif +#ifdef GL_INTEL_fragment_shader_ordering + "GL_INTEL_fragment_shader_ordering", +#endif +#ifdef GL_INTEL_framebuffer_CMAA + "GL_INTEL_framebuffer_CMAA", +#endif +#ifdef GL_INTEL_map_texture + "GL_INTEL_map_texture", +#endif +#ifdef GL_INTEL_parallel_arrays + "GL_INTEL_parallel_arrays", +#endif +#ifdef GL_INTEL_performance_query + "GL_INTEL_performance_query", +#endif +#ifdef GL_INTEL_texture_scissor + "GL_INTEL_texture_scissor", +#endif +#ifdef GL_KHR_blend_equation_advanced + "GL_KHR_blend_equation_advanced", +#endif +#ifdef GL_KHR_blend_equation_advanced_coherent + "GL_KHR_blend_equation_advanced_coherent", +#endif +#ifdef GL_KHR_context_flush_control + "GL_KHR_context_flush_control", +#endif +#ifdef GL_KHR_debug + "GL_KHR_debug", +#endif +#ifdef GL_KHR_no_error + "GL_KHR_no_error", +#endif +#ifdef GL_KHR_parallel_shader_compile + "GL_KHR_parallel_shader_compile", +#endif +#ifdef GL_KHR_robust_buffer_access_behavior + "GL_KHR_robust_buffer_access_behavior", +#endif +#ifdef GL_KHR_robustness + "GL_KHR_robustness", +#endif +#ifdef GL_KHR_texture_compression_astc_hdr + "GL_KHR_texture_compression_astc_hdr", +#endif +#ifdef GL_KHR_texture_compression_astc_ldr + "GL_KHR_texture_compression_astc_ldr", +#endif +#ifdef GL_KHR_texture_compression_astc_sliced_3d + "GL_KHR_texture_compression_astc_sliced_3d", +#endif +#ifdef GL_KTX_buffer_region + "GL_KTX_buffer_region", +#endif +#ifdef GL_MESAX_texture_stack + "GL_MESAX_texture_stack", +#endif +#ifdef GL_MESA_pack_invert + "GL_MESA_pack_invert", +#endif +#ifdef GL_MESA_resize_buffers + "GL_MESA_resize_buffers", +#endif +#ifdef GL_MESA_shader_integer_functions + "GL_MESA_shader_integer_functions", +#endif +#ifdef GL_MESA_window_pos + "GL_MESA_window_pos", +#endif +#ifdef GL_MESA_ycbcr_texture + "GL_MESA_ycbcr_texture", +#endif +#ifdef GL_NVX_blend_equation_advanced_multi_draw_buffers + "GL_NVX_blend_equation_advanced_multi_draw_buffers", +#endif +#ifdef GL_NVX_conditional_render + "GL_NVX_conditional_render", +#endif +#ifdef GL_NVX_gpu_memory_info + "GL_NVX_gpu_memory_info", +#endif +#ifdef GL_NVX_linked_gpu_multicast + "GL_NVX_linked_gpu_multicast", +#endif +#ifdef GL_NV_3dvision_settings + "GL_NV_3dvision_settings", +#endif +#ifdef GL_NV_EGL_stream_consumer_external + "GL_NV_EGL_stream_consumer_external", +#endif +#ifdef GL_NV_alpha_to_coverage_dither_control + "GL_NV_alpha_to_coverage_dither_control", +#endif +#ifdef GL_NV_bgr + "GL_NV_bgr", +#endif +#ifdef GL_NV_bindless_multi_draw_indirect + "GL_NV_bindless_multi_draw_indirect", +#endif +#ifdef GL_NV_bindless_multi_draw_indirect_count + "GL_NV_bindless_multi_draw_indirect_count", +#endif +#ifdef GL_NV_bindless_texture + "GL_NV_bindless_texture", +#endif +#ifdef GL_NV_blend_equation_advanced + "GL_NV_blend_equation_advanced", +#endif +#ifdef GL_NV_blend_equation_advanced_coherent + "GL_NV_blend_equation_advanced_coherent", +#endif +#ifdef GL_NV_blend_minmax_factor + "GL_NV_blend_minmax_factor", +#endif +#ifdef GL_NV_blend_square + "GL_NV_blend_square", +#endif +#ifdef GL_NV_clip_space_w_scaling + "GL_NV_clip_space_w_scaling", +#endif +#ifdef GL_NV_command_list + "GL_NV_command_list", +#endif +#ifdef GL_NV_compute_program5 + "GL_NV_compute_program5", +#endif +#ifdef GL_NV_conditional_render + "GL_NV_conditional_render", +#endif +#ifdef GL_NV_conservative_raster + "GL_NV_conservative_raster", +#endif +#ifdef GL_NV_conservative_raster_dilate + "GL_NV_conservative_raster_dilate", +#endif +#ifdef GL_NV_conservative_raster_pre_snap_triangles + "GL_NV_conservative_raster_pre_snap_triangles", +#endif +#ifdef GL_NV_copy_buffer + "GL_NV_copy_buffer", +#endif +#ifdef GL_NV_copy_depth_to_color + "GL_NV_copy_depth_to_color", +#endif +#ifdef GL_NV_copy_image + "GL_NV_copy_image", +#endif +#ifdef GL_NV_deep_texture3D + "GL_NV_deep_texture3D", +#endif +#ifdef GL_NV_depth_buffer_float + "GL_NV_depth_buffer_float", +#endif +#ifdef GL_NV_depth_clamp + "GL_NV_depth_clamp", +#endif +#ifdef GL_NV_depth_range_unclamped + "GL_NV_depth_range_unclamped", +#endif +#ifdef GL_NV_draw_buffers + "GL_NV_draw_buffers", +#endif +#ifdef GL_NV_draw_instanced + "GL_NV_draw_instanced", +#endif +#ifdef GL_NV_draw_texture + "GL_NV_draw_texture", +#endif +#ifdef GL_NV_draw_vulkan_image + "GL_NV_draw_vulkan_image", +#endif +#ifdef GL_NV_evaluators + "GL_NV_evaluators", +#endif +#ifdef GL_NV_explicit_attrib_location + "GL_NV_explicit_attrib_location", +#endif +#ifdef GL_NV_explicit_multisample + "GL_NV_explicit_multisample", +#endif +#ifdef GL_NV_fbo_color_attachments + "GL_NV_fbo_color_attachments", +#endif +#ifdef GL_NV_fence + "GL_NV_fence", +#endif +#ifdef GL_NV_fill_rectangle + "GL_NV_fill_rectangle", +#endif +#ifdef GL_NV_float_buffer + "GL_NV_float_buffer", +#endif +#ifdef GL_NV_fog_distance + "GL_NV_fog_distance", +#endif +#ifdef GL_NV_fragment_coverage_to_color + "GL_NV_fragment_coverage_to_color", +#endif +#ifdef GL_NV_fragment_program + "GL_NV_fragment_program", +#endif +#ifdef GL_NV_fragment_program2 + "GL_NV_fragment_program2", +#endif +#ifdef GL_NV_fragment_program4 + "GL_NV_fragment_program4", +#endif +#ifdef GL_NV_fragment_program_option + "GL_NV_fragment_program_option", +#endif +#ifdef GL_NV_fragment_shader_interlock + "GL_NV_fragment_shader_interlock", +#endif +#ifdef GL_NV_framebuffer_blit + "GL_NV_framebuffer_blit", +#endif +#ifdef GL_NV_framebuffer_mixed_samples + "GL_NV_framebuffer_mixed_samples", +#endif +#ifdef GL_NV_framebuffer_multisample + "GL_NV_framebuffer_multisample", +#endif +#ifdef GL_NV_framebuffer_multisample_coverage + "GL_NV_framebuffer_multisample_coverage", +#endif +#ifdef GL_NV_generate_mipmap_sRGB + "GL_NV_generate_mipmap_sRGB", +#endif +#ifdef GL_NV_geometry_program4 + "GL_NV_geometry_program4", +#endif +#ifdef GL_NV_geometry_shader4 + "GL_NV_geometry_shader4", +#endif +#ifdef GL_NV_geometry_shader_passthrough + "GL_NV_geometry_shader_passthrough", +#endif +#ifdef GL_NV_gpu_multicast + "GL_NV_gpu_multicast", +#endif +#ifdef GL_NV_gpu_program4 + "GL_NV_gpu_program4", +#endif +#ifdef GL_NV_gpu_program5 + "GL_NV_gpu_program5", +#endif +#ifdef GL_NV_gpu_program5_mem_extended + "GL_NV_gpu_program5_mem_extended", +#endif +#ifdef GL_NV_gpu_program_fp64 + "GL_NV_gpu_program_fp64", +#endif +#ifdef GL_NV_gpu_shader5 + "GL_NV_gpu_shader5", +#endif +#ifdef GL_NV_half_float + "GL_NV_half_float", +#endif +#ifdef GL_NV_image_formats + "GL_NV_image_formats", +#endif +#ifdef GL_NV_instanced_arrays + "GL_NV_instanced_arrays", +#endif +#ifdef GL_NV_internalformat_sample_query + "GL_NV_internalformat_sample_query", +#endif +#ifdef GL_NV_light_max_exponent + "GL_NV_light_max_exponent", +#endif +#ifdef GL_NV_multisample_coverage + "GL_NV_multisample_coverage", +#endif +#ifdef GL_NV_multisample_filter_hint + "GL_NV_multisample_filter_hint", +#endif +#ifdef GL_NV_non_square_matrices + "GL_NV_non_square_matrices", +#endif +#ifdef GL_NV_occlusion_query + "GL_NV_occlusion_query", +#endif +#ifdef GL_NV_pack_subimage + "GL_NV_pack_subimage", +#endif +#ifdef GL_NV_packed_depth_stencil + "GL_NV_packed_depth_stencil", +#endif +#ifdef GL_NV_packed_float + "GL_NV_packed_float", +#endif +#ifdef GL_NV_packed_float_linear + "GL_NV_packed_float_linear", +#endif +#ifdef GL_NV_parameter_buffer_object + "GL_NV_parameter_buffer_object", +#endif +#ifdef GL_NV_parameter_buffer_object2 + "GL_NV_parameter_buffer_object2", +#endif +#ifdef GL_NV_path_rendering + "GL_NV_path_rendering", +#endif +#ifdef GL_NV_path_rendering_shared_edge + "GL_NV_path_rendering_shared_edge", +#endif +#ifdef GL_NV_pixel_buffer_object + "GL_NV_pixel_buffer_object", +#endif +#ifdef GL_NV_pixel_data_range + "GL_NV_pixel_data_range", +#endif +#ifdef GL_NV_platform_binary + "GL_NV_platform_binary", +#endif +#ifdef GL_NV_point_sprite + "GL_NV_point_sprite", +#endif +#ifdef GL_NV_polygon_mode + "GL_NV_polygon_mode", +#endif +#ifdef GL_NV_present_video + "GL_NV_present_video", +#endif +#ifdef GL_NV_primitive_restart + "GL_NV_primitive_restart", +#endif +#ifdef GL_NV_read_depth + "GL_NV_read_depth", +#endif +#ifdef GL_NV_read_depth_stencil + "GL_NV_read_depth_stencil", +#endif +#ifdef GL_NV_read_stencil + "GL_NV_read_stencil", +#endif +#ifdef GL_NV_register_combiners + "GL_NV_register_combiners", +#endif +#ifdef GL_NV_register_combiners2 + "GL_NV_register_combiners2", +#endif +#ifdef GL_NV_robustness_video_memory_purge + "GL_NV_robustness_video_memory_purge", +#endif +#ifdef GL_NV_sRGB_formats + "GL_NV_sRGB_formats", +#endif +#ifdef GL_NV_sample_locations + "GL_NV_sample_locations", +#endif +#ifdef GL_NV_sample_mask_override_coverage + "GL_NV_sample_mask_override_coverage", +#endif +#ifdef GL_NV_shader_atomic_counters + "GL_NV_shader_atomic_counters", +#endif +#ifdef GL_NV_shader_atomic_float + "GL_NV_shader_atomic_float", +#endif +#ifdef GL_NV_shader_atomic_float64 + "GL_NV_shader_atomic_float64", +#endif +#ifdef GL_NV_shader_atomic_fp16_vector + "GL_NV_shader_atomic_fp16_vector", +#endif +#ifdef GL_NV_shader_atomic_int64 + "GL_NV_shader_atomic_int64", +#endif +#ifdef GL_NV_shader_buffer_load + "GL_NV_shader_buffer_load", +#endif +#ifdef GL_NV_shader_noperspective_interpolation + "GL_NV_shader_noperspective_interpolation", +#endif +#ifdef GL_NV_shader_storage_buffer_object + "GL_NV_shader_storage_buffer_object", +#endif +#ifdef GL_NV_shader_thread_group + "GL_NV_shader_thread_group", +#endif +#ifdef GL_NV_shader_thread_shuffle + "GL_NV_shader_thread_shuffle", +#endif +#ifdef GL_NV_shadow_samplers_array + "GL_NV_shadow_samplers_array", +#endif +#ifdef GL_NV_shadow_samplers_cube + "GL_NV_shadow_samplers_cube", +#endif +#ifdef GL_NV_stereo_view_rendering + "GL_NV_stereo_view_rendering", +#endif +#ifdef GL_NV_tessellation_program5 + "GL_NV_tessellation_program5", +#endif +#ifdef GL_NV_texgen_emboss + "GL_NV_texgen_emboss", +#endif +#ifdef GL_NV_texgen_reflection + "GL_NV_texgen_reflection", +#endif +#ifdef GL_NV_texture_array + "GL_NV_texture_array", +#endif +#ifdef GL_NV_texture_barrier + "GL_NV_texture_barrier", +#endif +#ifdef GL_NV_texture_border_clamp + "GL_NV_texture_border_clamp", +#endif +#ifdef GL_NV_texture_compression_latc + "GL_NV_texture_compression_latc", +#endif +#ifdef GL_NV_texture_compression_s3tc + "GL_NV_texture_compression_s3tc", +#endif +#ifdef GL_NV_texture_compression_s3tc_update + "GL_NV_texture_compression_s3tc_update", +#endif +#ifdef GL_NV_texture_compression_vtc + "GL_NV_texture_compression_vtc", +#endif +#ifdef GL_NV_texture_env_combine4 + "GL_NV_texture_env_combine4", +#endif +#ifdef GL_NV_texture_expand_normal + "GL_NV_texture_expand_normal", +#endif +#ifdef GL_NV_texture_multisample + "GL_NV_texture_multisample", +#endif +#ifdef GL_NV_texture_npot_2D_mipmap + "GL_NV_texture_npot_2D_mipmap", +#endif +#ifdef GL_NV_texture_rectangle + "GL_NV_texture_rectangle", +#endif +#ifdef GL_NV_texture_rectangle_compressed + "GL_NV_texture_rectangle_compressed", +#endif +#ifdef GL_NV_texture_shader + "GL_NV_texture_shader", +#endif +#ifdef GL_NV_texture_shader2 + "GL_NV_texture_shader2", +#endif +#ifdef GL_NV_texture_shader3 + "GL_NV_texture_shader3", +#endif +#ifdef GL_NV_transform_feedback + "GL_NV_transform_feedback", +#endif +#ifdef GL_NV_transform_feedback2 + "GL_NV_transform_feedback2", +#endif +#ifdef GL_NV_uniform_buffer_unified_memory + "GL_NV_uniform_buffer_unified_memory", +#endif +#ifdef GL_NV_vdpau_interop + "GL_NV_vdpau_interop", +#endif +#ifdef GL_NV_vertex_array_range + "GL_NV_vertex_array_range", +#endif +#ifdef GL_NV_vertex_array_range2 + "GL_NV_vertex_array_range2", +#endif +#ifdef GL_NV_vertex_attrib_integer_64bit + "GL_NV_vertex_attrib_integer_64bit", +#endif +#ifdef GL_NV_vertex_buffer_unified_memory + "GL_NV_vertex_buffer_unified_memory", +#endif +#ifdef GL_NV_vertex_program + "GL_NV_vertex_program", +#endif +#ifdef GL_NV_vertex_program1_1 + "GL_NV_vertex_program1_1", +#endif +#ifdef GL_NV_vertex_program2 + "GL_NV_vertex_program2", +#endif +#ifdef GL_NV_vertex_program2_option + "GL_NV_vertex_program2_option", +#endif +#ifdef GL_NV_vertex_program3 + "GL_NV_vertex_program3", +#endif +#ifdef GL_NV_vertex_program4 + "GL_NV_vertex_program4", +#endif +#ifdef GL_NV_video_capture + "GL_NV_video_capture", +#endif +#ifdef GL_NV_viewport_array + "GL_NV_viewport_array", +#endif +#ifdef GL_NV_viewport_array2 + "GL_NV_viewport_array2", +#endif +#ifdef GL_NV_viewport_swizzle + "GL_NV_viewport_swizzle", +#endif +#ifdef GL_OES_byte_coordinates + "GL_OES_byte_coordinates", +#endif +#ifdef GL_OML_interlace + "GL_OML_interlace", +#endif +#ifdef GL_OML_resample + "GL_OML_resample", +#endif +#ifdef GL_OML_subsample + "GL_OML_subsample", +#endif +#ifdef GL_OVR_multiview + "GL_OVR_multiview", +#endif +#ifdef GL_OVR_multiview2 + "GL_OVR_multiview2", +#endif +#ifdef GL_OVR_multiview_multisampled_render_to_texture + "GL_OVR_multiview_multisampled_render_to_texture", +#endif +#ifdef GL_PGI_misc_hints + "GL_PGI_misc_hints", +#endif +#ifdef GL_PGI_vertex_hints + "GL_PGI_vertex_hints", +#endif +#ifdef GL_QCOM_alpha_test + "GL_QCOM_alpha_test", +#endif +#ifdef GL_QCOM_binning_control + "GL_QCOM_binning_control", +#endif +#ifdef GL_QCOM_driver_control + "GL_QCOM_driver_control", +#endif +#ifdef GL_QCOM_extended_get + "GL_QCOM_extended_get", +#endif +#ifdef GL_QCOM_extended_get2 + "GL_QCOM_extended_get2", +#endif +#ifdef GL_QCOM_framebuffer_foveated + "GL_QCOM_framebuffer_foveated", +#endif +#ifdef GL_QCOM_perfmon_global_mode + "GL_QCOM_perfmon_global_mode", +#endif +#ifdef GL_QCOM_shader_framebuffer_fetch_noncoherent + "GL_QCOM_shader_framebuffer_fetch_noncoherent", +#endif +#ifdef GL_QCOM_tiled_rendering + "GL_QCOM_tiled_rendering", +#endif +#ifdef GL_QCOM_writeonly_rendering + "GL_QCOM_writeonly_rendering", +#endif +#ifdef GL_REGAL_ES1_0_compatibility + "GL_REGAL_ES1_0_compatibility", +#endif +#ifdef GL_REGAL_ES1_1_compatibility + "GL_REGAL_ES1_1_compatibility", +#endif +#ifdef GL_REGAL_enable + "GL_REGAL_enable", +#endif +#ifdef GL_REGAL_error_string + "GL_REGAL_error_string", +#endif +#ifdef GL_REGAL_extension_query + "GL_REGAL_extension_query", +#endif +#ifdef GL_REGAL_log + "GL_REGAL_log", +#endif +#ifdef GL_REGAL_proc_address + "GL_REGAL_proc_address", +#endif +#ifdef GL_REND_screen_coordinates + "GL_REND_screen_coordinates", +#endif +#ifdef GL_S3_s3tc + "GL_S3_s3tc", +#endif +#ifdef GL_SGIS_clip_band_hint + "GL_SGIS_clip_band_hint", +#endif +#ifdef GL_SGIS_color_range + "GL_SGIS_color_range", +#endif +#ifdef GL_SGIS_detail_texture + "GL_SGIS_detail_texture", +#endif +#ifdef GL_SGIS_fog_function + "GL_SGIS_fog_function", +#endif +#ifdef GL_SGIS_generate_mipmap + "GL_SGIS_generate_mipmap", +#endif +#ifdef GL_SGIS_line_texgen + "GL_SGIS_line_texgen", +#endif +#ifdef GL_SGIS_multisample + "GL_SGIS_multisample", +#endif +#ifdef GL_SGIS_multitexture + "GL_SGIS_multitexture", +#endif +#ifdef GL_SGIS_pixel_texture + "GL_SGIS_pixel_texture", +#endif +#ifdef GL_SGIS_point_line_texgen + "GL_SGIS_point_line_texgen", +#endif +#ifdef GL_SGIS_shared_multisample + "GL_SGIS_shared_multisample", +#endif +#ifdef GL_SGIS_sharpen_texture + "GL_SGIS_sharpen_texture", +#endif +#ifdef GL_SGIS_texture4D + "GL_SGIS_texture4D", +#endif +#ifdef GL_SGIS_texture_border_clamp + "GL_SGIS_texture_border_clamp", +#endif +#ifdef GL_SGIS_texture_edge_clamp + "GL_SGIS_texture_edge_clamp", +#endif +#ifdef GL_SGIS_texture_filter4 + "GL_SGIS_texture_filter4", +#endif +#ifdef GL_SGIS_texture_lod + "GL_SGIS_texture_lod", +#endif +#ifdef GL_SGIS_texture_select + "GL_SGIS_texture_select", +#endif +#ifdef GL_SGIX_async + "GL_SGIX_async", +#endif +#ifdef GL_SGIX_async_histogram + "GL_SGIX_async_histogram", +#endif +#ifdef GL_SGIX_async_pixel + "GL_SGIX_async_pixel", +#endif +#ifdef GL_SGIX_bali_g_instruments + "GL_SGIX_bali_g_instruments", +#endif +#ifdef GL_SGIX_bali_r_instruments + "GL_SGIX_bali_r_instruments", +#endif +#ifdef GL_SGIX_bali_timer_instruments + "GL_SGIX_bali_timer_instruments", +#endif +#ifdef GL_SGIX_blend_alpha_minmax + "GL_SGIX_blend_alpha_minmax", +#endif +#ifdef GL_SGIX_blend_cadd + "GL_SGIX_blend_cadd", +#endif +#ifdef GL_SGIX_blend_cmultiply + "GL_SGIX_blend_cmultiply", +#endif +#ifdef GL_SGIX_calligraphic_fragment + "GL_SGIX_calligraphic_fragment", +#endif +#ifdef GL_SGIX_clipmap + "GL_SGIX_clipmap", +#endif +#ifdef GL_SGIX_color_matrix_accuracy + "GL_SGIX_color_matrix_accuracy", +#endif +#ifdef GL_SGIX_color_table_index_mode + "GL_SGIX_color_table_index_mode", +#endif +#ifdef GL_SGIX_complex_polar + "GL_SGIX_complex_polar", +#endif +#ifdef GL_SGIX_convolution_accuracy + "GL_SGIX_convolution_accuracy", +#endif +#ifdef GL_SGIX_cube_map + "GL_SGIX_cube_map", +#endif +#ifdef GL_SGIX_cylinder_texgen + "GL_SGIX_cylinder_texgen", +#endif +#ifdef GL_SGIX_datapipe + "GL_SGIX_datapipe", +#endif +#ifdef GL_SGIX_decimation + "GL_SGIX_decimation", +#endif +#ifdef GL_SGIX_depth_pass_instrument + "GL_SGIX_depth_pass_instrument", +#endif +#ifdef GL_SGIX_depth_texture + "GL_SGIX_depth_texture", +#endif +#ifdef GL_SGIX_dvc + "GL_SGIX_dvc", +#endif +#ifdef GL_SGIX_flush_raster + "GL_SGIX_flush_raster", +#endif +#ifdef GL_SGIX_fog_blend + "GL_SGIX_fog_blend", +#endif +#ifdef GL_SGIX_fog_factor_to_alpha + "GL_SGIX_fog_factor_to_alpha", +#endif +#ifdef GL_SGIX_fog_layers + "GL_SGIX_fog_layers", +#endif +#ifdef GL_SGIX_fog_offset + "GL_SGIX_fog_offset", +#endif +#ifdef GL_SGIX_fog_patchy + "GL_SGIX_fog_patchy", +#endif +#ifdef GL_SGIX_fog_scale + "GL_SGIX_fog_scale", +#endif +#ifdef GL_SGIX_fog_texture + "GL_SGIX_fog_texture", +#endif +#ifdef GL_SGIX_fragment_lighting_space + "GL_SGIX_fragment_lighting_space", +#endif +#ifdef GL_SGIX_fragment_specular_lighting + "GL_SGIX_fragment_specular_lighting", +#endif +#ifdef GL_SGIX_fragments_instrument + "GL_SGIX_fragments_instrument", +#endif +#ifdef GL_SGIX_framezoom + "GL_SGIX_framezoom", +#endif +#ifdef GL_SGIX_icc_texture + "GL_SGIX_icc_texture", +#endif +#ifdef GL_SGIX_igloo_interface + "GL_SGIX_igloo_interface", +#endif +#ifdef GL_SGIX_image_compression + "GL_SGIX_image_compression", +#endif +#ifdef GL_SGIX_impact_pixel_texture + "GL_SGIX_impact_pixel_texture", +#endif +#ifdef GL_SGIX_instrument_error + "GL_SGIX_instrument_error", +#endif +#ifdef GL_SGIX_interlace + "GL_SGIX_interlace", +#endif +#ifdef GL_SGIX_ir_instrument1 + "GL_SGIX_ir_instrument1", +#endif +#ifdef GL_SGIX_line_quality_hint + "GL_SGIX_line_quality_hint", +#endif +#ifdef GL_SGIX_list_priority + "GL_SGIX_list_priority", +#endif +#ifdef GL_SGIX_mpeg1 + "GL_SGIX_mpeg1", +#endif +#ifdef GL_SGIX_mpeg2 + "GL_SGIX_mpeg2", +#endif +#ifdef GL_SGIX_nonlinear_lighting_pervertex + "GL_SGIX_nonlinear_lighting_pervertex", +#endif +#ifdef GL_SGIX_nurbs_eval + "GL_SGIX_nurbs_eval", +#endif +#ifdef GL_SGIX_occlusion_instrument + "GL_SGIX_occlusion_instrument", +#endif +#ifdef GL_SGIX_packed_6bytes + "GL_SGIX_packed_6bytes", +#endif +#ifdef GL_SGIX_pixel_texture + "GL_SGIX_pixel_texture", +#endif +#ifdef GL_SGIX_pixel_texture_bits + "GL_SGIX_pixel_texture_bits", +#endif +#ifdef GL_SGIX_pixel_texture_lod + "GL_SGIX_pixel_texture_lod", +#endif +#ifdef GL_SGIX_pixel_tiles + "GL_SGIX_pixel_tiles", +#endif +#ifdef GL_SGIX_polynomial_ffd + "GL_SGIX_polynomial_ffd", +#endif +#ifdef GL_SGIX_quad_mesh + "GL_SGIX_quad_mesh", +#endif +#ifdef GL_SGIX_reference_plane + "GL_SGIX_reference_plane", +#endif +#ifdef GL_SGIX_resample + "GL_SGIX_resample", +#endif +#ifdef GL_SGIX_scalebias_hint + "GL_SGIX_scalebias_hint", +#endif +#ifdef GL_SGIX_shadow + "GL_SGIX_shadow", +#endif +#ifdef GL_SGIX_shadow_ambient + "GL_SGIX_shadow_ambient", +#endif +#ifdef GL_SGIX_slim + "GL_SGIX_slim", +#endif +#ifdef GL_SGIX_spotlight_cutoff + "GL_SGIX_spotlight_cutoff", +#endif +#ifdef GL_SGIX_sprite + "GL_SGIX_sprite", +#endif +#ifdef GL_SGIX_subdiv_patch + "GL_SGIX_subdiv_patch", +#endif +#ifdef GL_SGIX_subsample + "GL_SGIX_subsample", +#endif +#ifdef GL_SGIX_tag_sample_buffer + "GL_SGIX_tag_sample_buffer", +#endif +#ifdef GL_SGIX_texture_add_env + "GL_SGIX_texture_add_env", +#endif +#ifdef GL_SGIX_texture_coordinate_clamp + "GL_SGIX_texture_coordinate_clamp", +#endif +#ifdef GL_SGIX_texture_lod_bias + "GL_SGIX_texture_lod_bias", +#endif +#ifdef GL_SGIX_texture_mipmap_anisotropic + "GL_SGIX_texture_mipmap_anisotropic", +#endif +#ifdef GL_SGIX_texture_multi_buffer + "GL_SGIX_texture_multi_buffer", +#endif +#ifdef GL_SGIX_texture_phase + "GL_SGIX_texture_phase", +#endif +#ifdef GL_SGIX_texture_range + "GL_SGIX_texture_range", +#endif +#ifdef GL_SGIX_texture_scale_bias + "GL_SGIX_texture_scale_bias", +#endif +#ifdef GL_SGIX_texture_supersample + "GL_SGIX_texture_supersample", +#endif +#ifdef GL_SGIX_vector_ops + "GL_SGIX_vector_ops", +#endif +#ifdef GL_SGIX_vertex_array_object + "GL_SGIX_vertex_array_object", +#endif +#ifdef GL_SGIX_vertex_preclip + "GL_SGIX_vertex_preclip", +#endif +#ifdef GL_SGIX_vertex_preclip_hint + "GL_SGIX_vertex_preclip_hint", +#endif +#ifdef GL_SGIX_ycrcb + "GL_SGIX_ycrcb", +#endif +#ifdef GL_SGIX_ycrcb_subsample + "GL_SGIX_ycrcb_subsample", +#endif +#ifdef GL_SGIX_ycrcba + "GL_SGIX_ycrcba", +#endif +#ifdef GL_SGI_color_matrix + "GL_SGI_color_matrix", +#endif +#ifdef GL_SGI_color_table + "GL_SGI_color_table", +#endif +#ifdef GL_SGI_complex + "GL_SGI_complex", +#endif +#ifdef GL_SGI_complex_type + "GL_SGI_complex_type", +#endif +#ifdef GL_SGI_fft + "GL_SGI_fft", +#endif +#ifdef GL_SGI_texture_color_table + "GL_SGI_texture_color_table", +#endif +#ifdef GL_SUNX_constant_data + "GL_SUNX_constant_data", +#endif +#ifdef GL_SUN_convolution_border_modes + "GL_SUN_convolution_border_modes", +#endif +#ifdef GL_SUN_global_alpha + "GL_SUN_global_alpha", +#endif +#ifdef GL_SUN_mesh_array + "GL_SUN_mesh_array", +#endif +#ifdef GL_SUN_read_video_pixels + "GL_SUN_read_video_pixels", +#endif +#ifdef GL_SUN_slice_accum + "GL_SUN_slice_accum", +#endif +#ifdef GL_SUN_triangle_list + "GL_SUN_triangle_list", +#endif +#ifdef GL_SUN_vertex + "GL_SUN_vertex", +#endif +#ifdef GL_WIN_phong_shading + "GL_WIN_phong_shading", +#endif +#ifdef GL_WIN_scene_markerXXX + "GL_WIN_scene_markerXXX", +#endif +#ifdef GL_WIN_specular_fog + "GL_WIN_specular_fog", +#endif +#ifdef GL_WIN_swap_hint + "GL_WIN_swap_hint", +#endif + NULL +}; + +/* Detected in the extension string or strings */ +static GLboolean _glewExtensionString[801]; +/* Detected via extension string or experimental mode */ +static GLboolean* _glewExtensionEnabled[] = { +#ifdef GL_VERSION_1_2 + &__GLEW_VERSION_1_2, +#endif +#ifdef GL_VERSION_1_2_1 + &__GLEW_VERSION_1_2_1, +#endif +#ifdef GL_VERSION_1_3 + &__GLEW_VERSION_1_3, +#endif +#ifdef GL_VERSION_1_4 + &__GLEW_VERSION_1_4, +#endif +#ifdef GL_VERSION_1_5 + &__GLEW_VERSION_1_5, +#endif +#ifdef GL_VERSION_2_0 + &__GLEW_VERSION_2_0, +#endif +#ifdef GL_VERSION_2_1 + &__GLEW_VERSION_2_1, +#endif +#ifdef GL_VERSION_3_0 + &__GLEW_VERSION_3_0, +#endif +#ifdef GL_VERSION_3_1 + &__GLEW_VERSION_3_1, +#endif +#ifdef GL_VERSION_3_2 + &__GLEW_VERSION_3_2, +#endif +#ifdef GL_VERSION_3_3 + &__GLEW_VERSION_3_3, +#endif +#ifdef GL_VERSION_4_0 + &__GLEW_VERSION_4_0, +#endif +#ifdef GL_VERSION_4_1 + &__GLEW_VERSION_4_1, +#endif +#ifdef GL_VERSION_4_2 + &__GLEW_VERSION_4_2, +#endif +#ifdef GL_VERSION_4_3 + &__GLEW_VERSION_4_3, +#endif +#ifdef GL_VERSION_4_4 + &__GLEW_VERSION_4_4, +#endif +#ifdef GL_VERSION_4_5 + &__GLEW_VERSION_4_5, +#endif +#ifdef GL_VERSION_4_6 + &__GLEW_VERSION_4_6, +#endif +#ifdef GL_3DFX_multisample + &__GLEW_3DFX_multisample, +#endif +#ifdef GL_3DFX_tbuffer + &__GLEW_3DFX_tbuffer, +#endif +#ifdef GL_3DFX_texture_compression_FXT1 + &__GLEW_3DFX_texture_compression_FXT1, +#endif +#ifdef GL_AMD_blend_minmax_factor + &__GLEW_AMD_blend_minmax_factor, +#endif +#ifdef GL_AMD_compressed_3DC_texture + &__GLEW_AMD_compressed_3DC_texture, +#endif +#ifdef GL_AMD_compressed_ATC_texture + &__GLEW_AMD_compressed_ATC_texture, +#endif +#ifdef GL_AMD_conservative_depth + &__GLEW_AMD_conservative_depth, +#endif +#ifdef GL_AMD_debug_output + &__GLEW_AMD_debug_output, +#endif +#ifdef GL_AMD_depth_clamp_separate + &__GLEW_AMD_depth_clamp_separate, +#endif +#ifdef GL_AMD_draw_buffers_blend + &__GLEW_AMD_draw_buffers_blend, +#endif +#ifdef GL_AMD_framebuffer_sample_positions + &__GLEW_AMD_framebuffer_sample_positions, +#endif +#ifdef GL_AMD_gcn_shader + &__GLEW_AMD_gcn_shader, +#endif +#ifdef GL_AMD_gpu_shader_half_float + &__GLEW_AMD_gpu_shader_half_float, +#endif +#ifdef GL_AMD_gpu_shader_int16 + &__GLEW_AMD_gpu_shader_int16, +#endif +#ifdef GL_AMD_gpu_shader_int64 + &__GLEW_AMD_gpu_shader_int64, +#endif +#ifdef GL_AMD_interleaved_elements + &__GLEW_AMD_interleaved_elements, +#endif +#ifdef GL_AMD_multi_draw_indirect + &__GLEW_AMD_multi_draw_indirect, +#endif +#ifdef GL_AMD_name_gen_delete + &__GLEW_AMD_name_gen_delete, +#endif +#ifdef GL_AMD_occlusion_query_event + &__GLEW_AMD_occlusion_query_event, +#endif +#ifdef GL_AMD_performance_monitor + &__GLEW_AMD_performance_monitor, +#endif +#ifdef GL_AMD_pinned_memory + &__GLEW_AMD_pinned_memory, +#endif +#ifdef GL_AMD_program_binary_Z400 + &__GLEW_AMD_program_binary_Z400, +#endif +#ifdef GL_AMD_query_buffer_object + &__GLEW_AMD_query_buffer_object, +#endif +#ifdef GL_AMD_sample_positions + &__GLEW_AMD_sample_positions, +#endif +#ifdef GL_AMD_seamless_cubemap_per_texture + &__GLEW_AMD_seamless_cubemap_per_texture, +#endif +#ifdef GL_AMD_shader_atomic_counter_ops + &__GLEW_AMD_shader_atomic_counter_ops, +#endif +#ifdef GL_AMD_shader_ballot + &__GLEW_AMD_shader_ballot, +#endif +#ifdef GL_AMD_shader_explicit_vertex_parameter + &__GLEW_AMD_shader_explicit_vertex_parameter, +#endif +#ifdef GL_AMD_shader_stencil_export + &__GLEW_AMD_shader_stencil_export, +#endif +#ifdef GL_AMD_shader_stencil_value_export + &__GLEW_AMD_shader_stencil_value_export, +#endif +#ifdef GL_AMD_shader_trinary_minmax + &__GLEW_AMD_shader_trinary_minmax, +#endif +#ifdef GL_AMD_sparse_texture + &__GLEW_AMD_sparse_texture, +#endif +#ifdef GL_AMD_stencil_operation_extended + &__GLEW_AMD_stencil_operation_extended, +#endif +#ifdef GL_AMD_texture_gather_bias_lod + &__GLEW_AMD_texture_gather_bias_lod, +#endif +#ifdef GL_AMD_texture_texture4 + &__GLEW_AMD_texture_texture4, +#endif +#ifdef GL_AMD_transform_feedback3_lines_triangles + &__GLEW_AMD_transform_feedback3_lines_triangles, +#endif +#ifdef GL_AMD_transform_feedback4 + &__GLEW_AMD_transform_feedback4, +#endif +#ifdef GL_AMD_vertex_shader_layer + &__GLEW_AMD_vertex_shader_layer, +#endif +#ifdef GL_AMD_vertex_shader_tessellator + &__GLEW_AMD_vertex_shader_tessellator, +#endif +#ifdef GL_AMD_vertex_shader_viewport_index + &__GLEW_AMD_vertex_shader_viewport_index, +#endif +#ifdef GL_ANDROID_extension_pack_es31a + &__GLEW_ANDROID_extension_pack_es31a, +#endif +#ifdef GL_ANGLE_depth_texture + &__GLEW_ANGLE_depth_texture, +#endif +#ifdef GL_ANGLE_framebuffer_blit + &__GLEW_ANGLE_framebuffer_blit, +#endif +#ifdef GL_ANGLE_framebuffer_multisample + &__GLEW_ANGLE_framebuffer_multisample, +#endif +#ifdef GL_ANGLE_instanced_arrays + &__GLEW_ANGLE_instanced_arrays, +#endif +#ifdef GL_ANGLE_pack_reverse_row_order + &__GLEW_ANGLE_pack_reverse_row_order, +#endif +#ifdef GL_ANGLE_program_binary + &__GLEW_ANGLE_program_binary, +#endif +#ifdef GL_ANGLE_texture_compression_dxt1 + &__GLEW_ANGLE_texture_compression_dxt1, +#endif +#ifdef GL_ANGLE_texture_compression_dxt3 + &__GLEW_ANGLE_texture_compression_dxt3, +#endif +#ifdef GL_ANGLE_texture_compression_dxt5 + &__GLEW_ANGLE_texture_compression_dxt5, +#endif +#ifdef GL_ANGLE_texture_usage + &__GLEW_ANGLE_texture_usage, +#endif +#ifdef GL_ANGLE_timer_query + &__GLEW_ANGLE_timer_query, +#endif +#ifdef GL_ANGLE_translated_shader_source + &__GLEW_ANGLE_translated_shader_source, +#endif +#ifdef GL_APPLE_aux_depth_stencil + &__GLEW_APPLE_aux_depth_stencil, +#endif +#ifdef GL_APPLE_client_storage + &__GLEW_APPLE_client_storage, +#endif +#ifdef GL_APPLE_clip_distance + &__GLEW_APPLE_clip_distance, +#endif +#ifdef GL_APPLE_color_buffer_packed_float + &__GLEW_APPLE_color_buffer_packed_float, +#endif +#ifdef GL_APPLE_copy_texture_levels + &__GLEW_APPLE_copy_texture_levels, +#endif +#ifdef GL_APPLE_element_array + &__GLEW_APPLE_element_array, +#endif +#ifdef GL_APPLE_fence + &__GLEW_APPLE_fence, +#endif +#ifdef GL_APPLE_float_pixels + &__GLEW_APPLE_float_pixels, +#endif +#ifdef GL_APPLE_flush_buffer_range + &__GLEW_APPLE_flush_buffer_range, +#endif +#ifdef GL_APPLE_framebuffer_multisample + &__GLEW_APPLE_framebuffer_multisample, +#endif +#ifdef GL_APPLE_object_purgeable + &__GLEW_APPLE_object_purgeable, +#endif +#ifdef GL_APPLE_pixel_buffer + &__GLEW_APPLE_pixel_buffer, +#endif +#ifdef GL_APPLE_rgb_422 + &__GLEW_APPLE_rgb_422, +#endif +#ifdef GL_APPLE_row_bytes + &__GLEW_APPLE_row_bytes, +#endif +#ifdef GL_APPLE_specular_vector + &__GLEW_APPLE_specular_vector, +#endif +#ifdef GL_APPLE_sync + &__GLEW_APPLE_sync, +#endif +#ifdef GL_APPLE_texture_2D_limited_npot + &__GLEW_APPLE_texture_2D_limited_npot, +#endif +#ifdef GL_APPLE_texture_format_BGRA8888 + &__GLEW_APPLE_texture_format_BGRA8888, +#endif +#ifdef GL_APPLE_texture_max_level + &__GLEW_APPLE_texture_max_level, +#endif +#ifdef GL_APPLE_texture_packed_float + &__GLEW_APPLE_texture_packed_float, +#endif +#ifdef GL_APPLE_texture_range + &__GLEW_APPLE_texture_range, +#endif +#ifdef GL_APPLE_transform_hint + &__GLEW_APPLE_transform_hint, +#endif +#ifdef GL_APPLE_vertex_array_object + &__GLEW_APPLE_vertex_array_object, +#endif +#ifdef GL_APPLE_vertex_array_range + &__GLEW_APPLE_vertex_array_range, +#endif +#ifdef GL_APPLE_vertex_program_evaluators + &__GLEW_APPLE_vertex_program_evaluators, +#endif +#ifdef GL_APPLE_ycbcr_422 + &__GLEW_APPLE_ycbcr_422, +#endif +#ifdef GL_ARB_ES2_compatibility + &__GLEW_ARB_ES2_compatibility, +#endif +#ifdef GL_ARB_ES3_1_compatibility + &__GLEW_ARB_ES3_1_compatibility, +#endif +#ifdef GL_ARB_ES3_2_compatibility + &__GLEW_ARB_ES3_2_compatibility, +#endif +#ifdef GL_ARB_ES3_compatibility + &__GLEW_ARB_ES3_compatibility, +#endif +#ifdef GL_ARB_arrays_of_arrays + &__GLEW_ARB_arrays_of_arrays, +#endif +#ifdef GL_ARB_base_instance + &__GLEW_ARB_base_instance, +#endif +#ifdef GL_ARB_bindless_texture + &__GLEW_ARB_bindless_texture, +#endif +#ifdef GL_ARB_blend_func_extended + &__GLEW_ARB_blend_func_extended, +#endif +#ifdef GL_ARB_buffer_storage + &__GLEW_ARB_buffer_storage, +#endif +#ifdef GL_ARB_cl_event + &__GLEW_ARB_cl_event, +#endif +#ifdef GL_ARB_clear_buffer_object + &__GLEW_ARB_clear_buffer_object, +#endif +#ifdef GL_ARB_clear_texture + &__GLEW_ARB_clear_texture, +#endif +#ifdef GL_ARB_clip_control + &__GLEW_ARB_clip_control, +#endif +#ifdef GL_ARB_color_buffer_float + &__GLEW_ARB_color_buffer_float, +#endif +#ifdef GL_ARB_compatibility + &__GLEW_ARB_compatibility, +#endif +#ifdef GL_ARB_compressed_texture_pixel_storage + &__GLEW_ARB_compressed_texture_pixel_storage, +#endif +#ifdef GL_ARB_compute_shader + &__GLEW_ARB_compute_shader, +#endif +#ifdef GL_ARB_compute_variable_group_size + &__GLEW_ARB_compute_variable_group_size, +#endif +#ifdef GL_ARB_conditional_render_inverted + &__GLEW_ARB_conditional_render_inverted, +#endif +#ifdef GL_ARB_conservative_depth + &__GLEW_ARB_conservative_depth, +#endif +#ifdef GL_ARB_copy_buffer + &__GLEW_ARB_copy_buffer, +#endif +#ifdef GL_ARB_copy_image + &__GLEW_ARB_copy_image, +#endif +#ifdef GL_ARB_cull_distance + &__GLEW_ARB_cull_distance, +#endif +#ifdef GL_ARB_debug_output + &__GLEW_ARB_debug_output, +#endif +#ifdef GL_ARB_depth_buffer_float + &__GLEW_ARB_depth_buffer_float, +#endif +#ifdef GL_ARB_depth_clamp + &__GLEW_ARB_depth_clamp, +#endif +#ifdef GL_ARB_depth_texture + &__GLEW_ARB_depth_texture, +#endif +#ifdef GL_ARB_derivative_control + &__GLEW_ARB_derivative_control, +#endif +#ifdef GL_ARB_direct_state_access + &__GLEW_ARB_direct_state_access, +#endif +#ifdef GL_ARB_draw_buffers + &__GLEW_ARB_draw_buffers, +#endif +#ifdef GL_ARB_draw_buffers_blend + &__GLEW_ARB_draw_buffers_blend, +#endif +#ifdef GL_ARB_draw_elements_base_vertex + &__GLEW_ARB_draw_elements_base_vertex, +#endif +#ifdef GL_ARB_draw_indirect + &__GLEW_ARB_draw_indirect, +#endif +#ifdef GL_ARB_draw_instanced + &__GLEW_ARB_draw_instanced, +#endif +#ifdef GL_ARB_enhanced_layouts + &__GLEW_ARB_enhanced_layouts, +#endif +#ifdef GL_ARB_explicit_attrib_location + &__GLEW_ARB_explicit_attrib_location, +#endif +#ifdef GL_ARB_explicit_uniform_location + &__GLEW_ARB_explicit_uniform_location, +#endif +#ifdef GL_ARB_fragment_coord_conventions + &__GLEW_ARB_fragment_coord_conventions, +#endif +#ifdef GL_ARB_fragment_layer_viewport + &__GLEW_ARB_fragment_layer_viewport, +#endif +#ifdef GL_ARB_fragment_program + &__GLEW_ARB_fragment_program, +#endif +#ifdef GL_ARB_fragment_program_shadow + &__GLEW_ARB_fragment_program_shadow, +#endif +#ifdef GL_ARB_fragment_shader + &__GLEW_ARB_fragment_shader, +#endif +#ifdef GL_ARB_fragment_shader_interlock + &__GLEW_ARB_fragment_shader_interlock, +#endif +#ifdef GL_ARB_framebuffer_no_attachments + &__GLEW_ARB_framebuffer_no_attachments, +#endif +#ifdef GL_ARB_framebuffer_object + &__GLEW_ARB_framebuffer_object, +#endif +#ifdef GL_ARB_framebuffer_sRGB + &__GLEW_ARB_framebuffer_sRGB, +#endif +#ifdef GL_ARB_geometry_shader4 + &__GLEW_ARB_geometry_shader4, +#endif +#ifdef GL_ARB_get_program_binary + &__GLEW_ARB_get_program_binary, +#endif +#ifdef GL_ARB_get_texture_sub_image + &__GLEW_ARB_get_texture_sub_image, +#endif +#ifdef GL_ARB_gl_spirv + &__GLEW_ARB_gl_spirv, +#endif +#ifdef GL_ARB_gpu_shader5 + &__GLEW_ARB_gpu_shader5, +#endif +#ifdef GL_ARB_gpu_shader_fp64 + &__GLEW_ARB_gpu_shader_fp64, +#endif +#ifdef GL_ARB_gpu_shader_int64 + &__GLEW_ARB_gpu_shader_int64, +#endif +#ifdef GL_ARB_half_float_pixel + &__GLEW_ARB_half_float_pixel, +#endif +#ifdef GL_ARB_half_float_vertex + &__GLEW_ARB_half_float_vertex, +#endif +#ifdef GL_ARB_imaging + &__GLEW_ARB_imaging, +#endif +#ifdef GL_ARB_indirect_parameters + &__GLEW_ARB_indirect_parameters, +#endif +#ifdef GL_ARB_instanced_arrays + &__GLEW_ARB_instanced_arrays, +#endif +#ifdef GL_ARB_internalformat_query + &__GLEW_ARB_internalformat_query, +#endif +#ifdef GL_ARB_internalformat_query2 + &__GLEW_ARB_internalformat_query2, +#endif +#ifdef GL_ARB_invalidate_subdata + &__GLEW_ARB_invalidate_subdata, +#endif +#ifdef GL_ARB_map_buffer_alignment + &__GLEW_ARB_map_buffer_alignment, +#endif +#ifdef GL_ARB_map_buffer_range + &__GLEW_ARB_map_buffer_range, +#endif +#ifdef GL_ARB_matrix_palette + &__GLEW_ARB_matrix_palette, +#endif +#ifdef GL_ARB_multi_bind + &__GLEW_ARB_multi_bind, +#endif +#ifdef GL_ARB_multi_draw_indirect + &__GLEW_ARB_multi_draw_indirect, +#endif +#ifdef GL_ARB_multisample + &__GLEW_ARB_multisample, +#endif +#ifdef GL_ARB_multitexture + &__GLEW_ARB_multitexture, +#endif +#ifdef GL_ARB_occlusion_query + &__GLEW_ARB_occlusion_query, +#endif +#ifdef GL_ARB_occlusion_query2 + &__GLEW_ARB_occlusion_query2, +#endif +#ifdef GL_ARB_parallel_shader_compile + &__GLEW_ARB_parallel_shader_compile, +#endif +#ifdef GL_ARB_pipeline_statistics_query + &__GLEW_ARB_pipeline_statistics_query, +#endif +#ifdef GL_ARB_pixel_buffer_object + &__GLEW_ARB_pixel_buffer_object, +#endif +#ifdef GL_ARB_point_parameters + &__GLEW_ARB_point_parameters, +#endif +#ifdef GL_ARB_point_sprite + &__GLEW_ARB_point_sprite, +#endif +#ifdef GL_ARB_polygon_offset_clamp + &__GLEW_ARB_polygon_offset_clamp, +#endif +#ifdef GL_ARB_post_depth_coverage + &__GLEW_ARB_post_depth_coverage, +#endif +#ifdef GL_ARB_program_interface_query + &__GLEW_ARB_program_interface_query, +#endif +#ifdef GL_ARB_provoking_vertex + &__GLEW_ARB_provoking_vertex, +#endif +#ifdef GL_ARB_query_buffer_object + &__GLEW_ARB_query_buffer_object, +#endif +#ifdef GL_ARB_robust_buffer_access_behavior + &__GLEW_ARB_robust_buffer_access_behavior, +#endif +#ifdef GL_ARB_robustness + &__GLEW_ARB_robustness, +#endif +#ifdef GL_ARB_robustness_application_isolation + &__GLEW_ARB_robustness_application_isolation, +#endif +#ifdef GL_ARB_robustness_share_group_isolation + &__GLEW_ARB_robustness_share_group_isolation, +#endif +#ifdef GL_ARB_sample_locations + &__GLEW_ARB_sample_locations, +#endif +#ifdef GL_ARB_sample_shading + &__GLEW_ARB_sample_shading, +#endif +#ifdef GL_ARB_sampler_objects + &__GLEW_ARB_sampler_objects, +#endif +#ifdef GL_ARB_seamless_cube_map + &__GLEW_ARB_seamless_cube_map, +#endif +#ifdef GL_ARB_seamless_cubemap_per_texture + &__GLEW_ARB_seamless_cubemap_per_texture, +#endif +#ifdef GL_ARB_separate_shader_objects + &__GLEW_ARB_separate_shader_objects, +#endif +#ifdef GL_ARB_shader_atomic_counter_ops + &__GLEW_ARB_shader_atomic_counter_ops, +#endif +#ifdef GL_ARB_shader_atomic_counters + &__GLEW_ARB_shader_atomic_counters, +#endif +#ifdef GL_ARB_shader_ballot + &__GLEW_ARB_shader_ballot, +#endif +#ifdef GL_ARB_shader_bit_encoding + &__GLEW_ARB_shader_bit_encoding, +#endif +#ifdef GL_ARB_shader_clock + &__GLEW_ARB_shader_clock, +#endif +#ifdef GL_ARB_shader_draw_parameters + &__GLEW_ARB_shader_draw_parameters, +#endif +#ifdef GL_ARB_shader_group_vote + &__GLEW_ARB_shader_group_vote, +#endif +#ifdef GL_ARB_shader_image_load_store + &__GLEW_ARB_shader_image_load_store, +#endif +#ifdef GL_ARB_shader_image_size + &__GLEW_ARB_shader_image_size, +#endif +#ifdef GL_ARB_shader_objects + &__GLEW_ARB_shader_objects, +#endif +#ifdef GL_ARB_shader_precision + &__GLEW_ARB_shader_precision, +#endif +#ifdef GL_ARB_shader_stencil_export + &__GLEW_ARB_shader_stencil_export, +#endif +#ifdef GL_ARB_shader_storage_buffer_object + &__GLEW_ARB_shader_storage_buffer_object, +#endif +#ifdef GL_ARB_shader_subroutine + &__GLEW_ARB_shader_subroutine, +#endif +#ifdef GL_ARB_shader_texture_image_samples + &__GLEW_ARB_shader_texture_image_samples, +#endif +#ifdef GL_ARB_shader_texture_lod + &__GLEW_ARB_shader_texture_lod, +#endif +#ifdef GL_ARB_shader_viewport_layer_array + &__GLEW_ARB_shader_viewport_layer_array, +#endif +#ifdef GL_ARB_shading_language_100 + &__GLEW_ARB_shading_language_100, +#endif +#ifdef GL_ARB_shading_language_420pack + &__GLEW_ARB_shading_language_420pack, +#endif +#ifdef GL_ARB_shading_language_include + &__GLEW_ARB_shading_language_include, +#endif +#ifdef GL_ARB_shading_language_packing + &__GLEW_ARB_shading_language_packing, +#endif +#ifdef GL_ARB_shadow + &__GLEW_ARB_shadow, +#endif +#ifdef GL_ARB_shadow_ambient + &__GLEW_ARB_shadow_ambient, +#endif +#ifdef GL_ARB_sparse_buffer + &__GLEW_ARB_sparse_buffer, +#endif +#ifdef GL_ARB_sparse_texture + &__GLEW_ARB_sparse_texture, +#endif +#ifdef GL_ARB_sparse_texture2 + &__GLEW_ARB_sparse_texture2, +#endif +#ifdef GL_ARB_sparse_texture_clamp + &__GLEW_ARB_sparse_texture_clamp, +#endif +#ifdef GL_ARB_spirv_extensions + &__GLEW_ARB_spirv_extensions, +#endif +#ifdef GL_ARB_stencil_texturing + &__GLEW_ARB_stencil_texturing, +#endif +#ifdef GL_ARB_sync + &__GLEW_ARB_sync, +#endif +#ifdef GL_ARB_tessellation_shader + &__GLEW_ARB_tessellation_shader, +#endif +#ifdef GL_ARB_texture_barrier + &__GLEW_ARB_texture_barrier, +#endif +#ifdef GL_ARB_texture_border_clamp + &__GLEW_ARB_texture_border_clamp, +#endif +#ifdef GL_ARB_texture_buffer_object + &__GLEW_ARB_texture_buffer_object, +#endif +#ifdef GL_ARB_texture_buffer_object_rgb32 + &__GLEW_ARB_texture_buffer_object_rgb32, +#endif +#ifdef GL_ARB_texture_buffer_range + &__GLEW_ARB_texture_buffer_range, +#endif +#ifdef GL_ARB_texture_compression + &__GLEW_ARB_texture_compression, +#endif +#ifdef GL_ARB_texture_compression_bptc + &__GLEW_ARB_texture_compression_bptc, +#endif +#ifdef GL_ARB_texture_compression_rgtc + &__GLEW_ARB_texture_compression_rgtc, +#endif +#ifdef GL_ARB_texture_cube_map + &__GLEW_ARB_texture_cube_map, +#endif +#ifdef GL_ARB_texture_cube_map_array + &__GLEW_ARB_texture_cube_map_array, +#endif +#ifdef GL_ARB_texture_env_add + &__GLEW_ARB_texture_env_add, +#endif +#ifdef GL_ARB_texture_env_combine + &__GLEW_ARB_texture_env_combine, +#endif +#ifdef GL_ARB_texture_env_crossbar + &__GLEW_ARB_texture_env_crossbar, +#endif +#ifdef GL_ARB_texture_env_dot3 + &__GLEW_ARB_texture_env_dot3, +#endif +#ifdef GL_ARB_texture_filter_anisotropic + &__GLEW_ARB_texture_filter_anisotropic, +#endif +#ifdef GL_ARB_texture_filter_minmax + &__GLEW_ARB_texture_filter_minmax, +#endif +#ifdef GL_ARB_texture_float + &__GLEW_ARB_texture_float, +#endif +#ifdef GL_ARB_texture_gather + &__GLEW_ARB_texture_gather, +#endif +#ifdef GL_ARB_texture_mirror_clamp_to_edge + &__GLEW_ARB_texture_mirror_clamp_to_edge, +#endif +#ifdef GL_ARB_texture_mirrored_repeat + &__GLEW_ARB_texture_mirrored_repeat, +#endif +#ifdef GL_ARB_texture_multisample + &__GLEW_ARB_texture_multisample, +#endif +#ifdef GL_ARB_texture_non_power_of_two + &__GLEW_ARB_texture_non_power_of_two, +#endif +#ifdef GL_ARB_texture_query_levels + &__GLEW_ARB_texture_query_levels, +#endif +#ifdef GL_ARB_texture_query_lod + &__GLEW_ARB_texture_query_lod, +#endif +#ifdef GL_ARB_texture_rectangle + &__GLEW_ARB_texture_rectangle, +#endif +#ifdef GL_ARB_texture_rg + &__GLEW_ARB_texture_rg, +#endif +#ifdef GL_ARB_texture_rgb10_a2ui + &__GLEW_ARB_texture_rgb10_a2ui, +#endif +#ifdef GL_ARB_texture_stencil8 + &__GLEW_ARB_texture_stencil8, +#endif +#ifdef GL_ARB_texture_storage + &__GLEW_ARB_texture_storage, +#endif +#ifdef GL_ARB_texture_storage_multisample + &__GLEW_ARB_texture_storage_multisample, +#endif +#ifdef GL_ARB_texture_swizzle + &__GLEW_ARB_texture_swizzle, +#endif +#ifdef GL_ARB_texture_view + &__GLEW_ARB_texture_view, +#endif +#ifdef GL_ARB_timer_query + &__GLEW_ARB_timer_query, +#endif +#ifdef GL_ARB_transform_feedback2 + &__GLEW_ARB_transform_feedback2, +#endif +#ifdef GL_ARB_transform_feedback3 + &__GLEW_ARB_transform_feedback3, +#endif +#ifdef GL_ARB_transform_feedback_instanced + &__GLEW_ARB_transform_feedback_instanced, +#endif +#ifdef GL_ARB_transform_feedback_overflow_query + &__GLEW_ARB_transform_feedback_overflow_query, +#endif +#ifdef GL_ARB_transpose_matrix + &__GLEW_ARB_transpose_matrix, +#endif +#ifdef GL_ARB_uniform_buffer_object + &__GLEW_ARB_uniform_buffer_object, +#endif +#ifdef GL_ARB_vertex_array_bgra + &__GLEW_ARB_vertex_array_bgra, +#endif +#ifdef GL_ARB_vertex_array_object + &__GLEW_ARB_vertex_array_object, +#endif +#ifdef GL_ARB_vertex_attrib_64bit + &__GLEW_ARB_vertex_attrib_64bit, +#endif +#ifdef GL_ARB_vertex_attrib_binding + &__GLEW_ARB_vertex_attrib_binding, +#endif +#ifdef GL_ARB_vertex_blend + &__GLEW_ARB_vertex_blend, +#endif +#ifdef GL_ARB_vertex_buffer_object + &__GLEW_ARB_vertex_buffer_object, +#endif +#ifdef GL_ARB_vertex_program + &__GLEW_ARB_vertex_program, +#endif +#ifdef GL_ARB_vertex_shader + &__GLEW_ARB_vertex_shader, +#endif +#ifdef GL_ARB_vertex_type_10f_11f_11f_rev + &__GLEW_ARB_vertex_type_10f_11f_11f_rev, +#endif +#ifdef GL_ARB_vertex_type_2_10_10_10_rev + &__GLEW_ARB_vertex_type_2_10_10_10_rev, +#endif +#ifdef GL_ARB_viewport_array + &__GLEW_ARB_viewport_array, +#endif +#ifdef GL_ARB_window_pos + &__GLEW_ARB_window_pos, +#endif +#ifdef GL_ARM_mali_program_binary + &__GLEW_ARM_mali_program_binary, +#endif +#ifdef GL_ARM_mali_shader_binary + &__GLEW_ARM_mali_shader_binary, +#endif +#ifdef GL_ARM_rgba8 + &__GLEW_ARM_rgba8, +#endif +#ifdef GL_ARM_shader_framebuffer_fetch + &__GLEW_ARM_shader_framebuffer_fetch, +#endif +#ifdef GL_ARM_shader_framebuffer_fetch_depth_stencil + &__GLEW_ARM_shader_framebuffer_fetch_depth_stencil, +#endif +#ifdef GL_ATIX_point_sprites + &__GLEW_ATIX_point_sprites, +#endif +#ifdef GL_ATIX_texture_env_combine3 + &__GLEW_ATIX_texture_env_combine3, +#endif +#ifdef GL_ATIX_texture_env_route + &__GLEW_ATIX_texture_env_route, +#endif +#ifdef GL_ATIX_vertex_shader_output_point_size + &__GLEW_ATIX_vertex_shader_output_point_size, +#endif +#ifdef GL_ATI_draw_buffers + &__GLEW_ATI_draw_buffers, +#endif +#ifdef GL_ATI_element_array + &__GLEW_ATI_element_array, +#endif +#ifdef GL_ATI_envmap_bumpmap + &__GLEW_ATI_envmap_bumpmap, +#endif +#ifdef GL_ATI_fragment_shader + &__GLEW_ATI_fragment_shader, +#endif +#ifdef GL_ATI_map_object_buffer + &__GLEW_ATI_map_object_buffer, +#endif +#ifdef GL_ATI_meminfo + &__GLEW_ATI_meminfo, +#endif +#ifdef GL_ATI_pn_triangles + &__GLEW_ATI_pn_triangles, +#endif +#ifdef GL_ATI_separate_stencil + &__GLEW_ATI_separate_stencil, +#endif +#ifdef GL_ATI_shader_texture_lod + &__GLEW_ATI_shader_texture_lod, +#endif +#ifdef GL_ATI_text_fragment_shader + &__GLEW_ATI_text_fragment_shader, +#endif +#ifdef GL_ATI_texture_compression_3dc + &__GLEW_ATI_texture_compression_3dc, +#endif +#ifdef GL_ATI_texture_env_combine3 + &__GLEW_ATI_texture_env_combine3, +#endif +#ifdef GL_ATI_texture_float + &__GLEW_ATI_texture_float, +#endif +#ifdef GL_ATI_texture_mirror_once + &__GLEW_ATI_texture_mirror_once, +#endif +#ifdef GL_ATI_vertex_array_object + &__GLEW_ATI_vertex_array_object, +#endif +#ifdef GL_ATI_vertex_attrib_array_object + &__GLEW_ATI_vertex_attrib_array_object, +#endif +#ifdef GL_ATI_vertex_streams + &__GLEW_ATI_vertex_streams, +#endif +#ifdef GL_EGL_KHR_context_flush_control + &__GLEW_EGL_KHR_context_flush_control, +#endif +#ifdef GL_EGL_NV_robustness_video_memory_purge + &__GLEW_EGL_NV_robustness_video_memory_purge, +#endif +#ifdef GL_EXT_422_pixels + &__GLEW_EXT_422_pixels, +#endif +#ifdef GL_EXT_Cg_shader + &__GLEW_EXT_Cg_shader, +#endif +#ifdef GL_EXT_EGL_image_array + &__GLEW_EXT_EGL_image_array, +#endif +#ifdef GL_EXT_YUV_target + &__GLEW_EXT_YUV_target, +#endif +#ifdef GL_EXT_abgr + &__GLEW_EXT_abgr, +#endif +#ifdef GL_EXT_base_instance + &__GLEW_EXT_base_instance, +#endif +#ifdef GL_EXT_bgra + &__GLEW_EXT_bgra, +#endif +#ifdef GL_EXT_bindable_uniform + &__GLEW_EXT_bindable_uniform, +#endif +#ifdef GL_EXT_blend_color + &__GLEW_EXT_blend_color, +#endif +#ifdef GL_EXT_blend_equation_separate + &__GLEW_EXT_blend_equation_separate, +#endif +#ifdef GL_EXT_blend_func_extended + &__GLEW_EXT_blend_func_extended, +#endif +#ifdef GL_EXT_blend_func_separate + &__GLEW_EXT_blend_func_separate, +#endif +#ifdef GL_EXT_blend_logic_op + &__GLEW_EXT_blend_logic_op, +#endif +#ifdef GL_EXT_blend_minmax + &__GLEW_EXT_blend_minmax, +#endif +#ifdef GL_EXT_blend_subtract + &__GLEW_EXT_blend_subtract, +#endif +#ifdef GL_EXT_buffer_storage + &__GLEW_EXT_buffer_storage, +#endif +#ifdef GL_EXT_clear_texture + &__GLEW_EXT_clear_texture, +#endif +#ifdef GL_EXT_clip_cull_distance + &__GLEW_EXT_clip_cull_distance, +#endif +#ifdef GL_EXT_clip_volume_hint + &__GLEW_EXT_clip_volume_hint, +#endif +#ifdef GL_EXT_cmyka + &__GLEW_EXT_cmyka, +#endif +#ifdef GL_EXT_color_buffer_float + &__GLEW_EXT_color_buffer_float, +#endif +#ifdef GL_EXT_color_buffer_half_float + &__GLEW_EXT_color_buffer_half_float, +#endif +#ifdef GL_EXT_color_subtable + &__GLEW_EXT_color_subtable, +#endif +#ifdef GL_EXT_compiled_vertex_array + &__GLEW_EXT_compiled_vertex_array, +#endif +#ifdef GL_EXT_compressed_ETC1_RGB8_sub_texture + &__GLEW_EXT_compressed_ETC1_RGB8_sub_texture, +#endif +#ifdef GL_EXT_conservative_depth + &__GLEW_EXT_conservative_depth, +#endif +#ifdef GL_EXT_convolution + &__GLEW_EXT_convolution, +#endif +#ifdef GL_EXT_coordinate_frame + &__GLEW_EXT_coordinate_frame, +#endif +#ifdef GL_EXT_copy_image + &__GLEW_EXT_copy_image, +#endif +#ifdef GL_EXT_copy_texture + &__GLEW_EXT_copy_texture, +#endif +#ifdef GL_EXT_cull_vertex + &__GLEW_EXT_cull_vertex, +#endif +#ifdef GL_EXT_debug_label + &__GLEW_EXT_debug_label, +#endif +#ifdef GL_EXT_debug_marker + &__GLEW_EXT_debug_marker, +#endif +#ifdef GL_EXT_depth_bounds_test + &__GLEW_EXT_depth_bounds_test, +#endif +#ifdef GL_EXT_direct_state_access + &__GLEW_EXT_direct_state_access, +#endif +#ifdef GL_EXT_discard_framebuffer + &__GLEW_EXT_discard_framebuffer, +#endif +#ifdef GL_EXT_draw_buffers + &__GLEW_EXT_draw_buffers, +#endif +#ifdef GL_EXT_draw_buffers2 + &__GLEW_EXT_draw_buffers2, +#endif +#ifdef GL_EXT_draw_buffers_indexed + &__GLEW_EXT_draw_buffers_indexed, +#endif +#ifdef GL_EXT_draw_elements_base_vertex + &__GLEW_EXT_draw_elements_base_vertex, +#endif +#ifdef GL_EXT_draw_instanced + &__GLEW_EXT_draw_instanced, +#endif +#ifdef GL_EXT_draw_range_elements + &__GLEW_EXT_draw_range_elements, +#endif +#ifdef GL_EXT_external_buffer + &__GLEW_EXT_external_buffer, +#endif +#ifdef GL_EXT_float_blend + &__GLEW_EXT_float_blend, +#endif +#ifdef GL_EXT_fog_coord + &__GLEW_EXT_fog_coord, +#endif +#ifdef GL_EXT_frag_depth + &__GLEW_EXT_frag_depth, +#endif +#ifdef GL_EXT_fragment_lighting + &__GLEW_EXT_fragment_lighting, +#endif +#ifdef GL_EXT_framebuffer_blit + &__GLEW_EXT_framebuffer_blit, +#endif +#ifdef GL_EXT_framebuffer_multisample + &__GLEW_EXT_framebuffer_multisample, +#endif +#ifdef GL_EXT_framebuffer_multisample_blit_scaled + &__GLEW_EXT_framebuffer_multisample_blit_scaled, +#endif +#ifdef GL_EXT_framebuffer_object + &__GLEW_EXT_framebuffer_object, +#endif +#ifdef GL_EXT_framebuffer_sRGB + &__GLEW_EXT_framebuffer_sRGB, +#endif +#ifdef GL_EXT_geometry_point_size + &__GLEW_EXT_geometry_point_size, +#endif +#ifdef GL_EXT_geometry_shader + &__GLEW_EXT_geometry_shader, +#endif +#ifdef GL_EXT_geometry_shader4 + &__GLEW_EXT_geometry_shader4, +#endif +#ifdef GL_EXT_gpu_program_parameters + &__GLEW_EXT_gpu_program_parameters, +#endif +#ifdef GL_EXT_gpu_shader4 + &__GLEW_EXT_gpu_shader4, +#endif +#ifdef GL_EXT_gpu_shader5 + &__GLEW_EXT_gpu_shader5, +#endif +#ifdef GL_EXT_histogram + &__GLEW_EXT_histogram, +#endif +#ifdef GL_EXT_index_array_formats + &__GLEW_EXT_index_array_formats, +#endif +#ifdef GL_EXT_index_func + &__GLEW_EXT_index_func, +#endif +#ifdef GL_EXT_index_material + &__GLEW_EXT_index_material, +#endif +#ifdef GL_EXT_index_texture + &__GLEW_EXT_index_texture, +#endif +#ifdef GL_EXT_instanced_arrays + &__GLEW_EXT_instanced_arrays, +#endif +#ifdef GL_EXT_light_texture + &__GLEW_EXT_light_texture, +#endif +#ifdef GL_EXT_map_buffer_range + &__GLEW_EXT_map_buffer_range, +#endif +#ifdef GL_EXT_memory_object + &__GLEW_EXT_memory_object, +#endif +#ifdef GL_EXT_memory_object_fd + &__GLEW_EXT_memory_object_fd, +#endif +#ifdef GL_EXT_memory_object_win32 + &__GLEW_EXT_memory_object_win32, +#endif +#ifdef GL_EXT_misc_attribute + &__GLEW_EXT_misc_attribute, +#endif +#ifdef GL_EXT_multi_draw_arrays + &__GLEW_EXT_multi_draw_arrays, +#endif +#ifdef GL_EXT_multi_draw_indirect + &__GLEW_EXT_multi_draw_indirect, +#endif +#ifdef GL_EXT_multiple_textures + &__GLEW_EXT_multiple_textures, +#endif +#ifdef GL_EXT_multisample + &__GLEW_EXT_multisample, +#endif +#ifdef GL_EXT_multisample_compatibility + &__GLEW_EXT_multisample_compatibility, +#endif +#ifdef GL_EXT_multisampled_render_to_texture + &__GLEW_EXT_multisampled_render_to_texture, +#endif +#ifdef GL_EXT_multisampled_render_to_texture2 + &__GLEW_EXT_multisampled_render_to_texture2, +#endif +#ifdef GL_EXT_multiview_draw_buffers + &__GLEW_EXT_multiview_draw_buffers, +#endif +#ifdef GL_EXT_packed_depth_stencil + &__GLEW_EXT_packed_depth_stencil, +#endif +#ifdef GL_EXT_packed_float + &__GLEW_EXT_packed_float, +#endif +#ifdef GL_EXT_packed_pixels + &__GLEW_EXT_packed_pixels, +#endif +#ifdef GL_EXT_paletted_texture + &__GLEW_EXT_paletted_texture, +#endif +#ifdef GL_EXT_pixel_buffer_object + &__GLEW_EXT_pixel_buffer_object, +#endif +#ifdef GL_EXT_pixel_transform + &__GLEW_EXT_pixel_transform, +#endif +#ifdef GL_EXT_pixel_transform_color_table + &__GLEW_EXT_pixel_transform_color_table, +#endif +#ifdef GL_EXT_point_parameters + &__GLEW_EXT_point_parameters, +#endif +#ifdef GL_EXT_polygon_offset + &__GLEW_EXT_polygon_offset, +#endif +#ifdef GL_EXT_polygon_offset_clamp + &__GLEW_EXT_polygon_offset_clamp, +#endif +#ifdef GL_EXT_post_depth_coverage + &__GLEW_EXT_post_depth_coverage, +#endif +#ifdef GL_EXT_provoking_vertex + &__GLEW_EXT_provoking_vertex, +#endif +#ifdef GL_EXT_pvrtc_sRGB + &__GLEW_EXT_pvrtc_sRGB, +#endif +#ifdef GL_EXT_raster_multisample + &__GLEW_EXT_raster_multisample, +#endif +#ifdef GL_EXT_read_format_bgra + &__GLEW_EXT_read_format_bgra, +#endif +#ifdef GL_EXT_render_snorm + &__GLEW_EXT_render_snorm, +#endif +#ifdef GL_EXT_rescale_normal + &__GLEW_EXT_rescale_normal, +#endif +#ifdef GL_EXT_sRGB + &__GLEW_EXT_sRGB, +#endif +#ifdef GL_EXT_sRGB_write_control + &__GLEW_EXT_sRGB_write_control, +#endif +#ifdef GL_EXT_scene_marker + &__GLEW_EXT_scene_marker, +#endif +#ifdef GL_EXT_secondary_color + &__GLEW_EXT_secondary_color, +#endif +#ifdef GL_EXT_semaphore + &__GLEW_EXT_semaphore, +#endif +#ifdef GL_EXT_semaphore_fd + &__GLEW_EXT_semaphore_fd, +#endif +#ifdef GL_EXT_semaphore_win32 + &__GLEW_EXT_semaphore_win32, +#endif +#ifdef GL_EXT_separate_shader_objects + &__GLEW_EXT_separate_shader_objects, +#endif +#ifdef GL_EXT_separate_specular_color + &__GLEW_EXT_separate_specular_color, +#endif +#ifdef GL_EXT_shader_framebuffer_fetch + &__GLEW_EXT_shader_framebuffer_fetch, +#endif +#ifdef GL_EXT_shader_group_vote + &__GLEW_EXT_shader_group_vote, +#endif +#ifdef GL_EXT_shader_image_load_formatted + &__GLEW_EXT_shader_image_load_formatted, +#endif +#ifdef GL_EXT_shader_image_load_store + &__GLEW_EXT_shader_image_load_store, +#endif +#ifdef GL_EXT_shader_implicit_conversions + &__GLEW_EXT_shader_implicit_conversions, +#endif +#ifdef GL_EXT_shader_integer_mix + &__GLEW_EXT_shader_integer_mix, +#endif +#ifdef GL_EXT_shader_io_blocks + &__GLEW_EXT_shader_io_blocks, +#endif +#ifdef GL_EXT_shader_non_constant_global_initializers + &__GLEW_EXT_shader_non_constant_global_initializers, +#endif +#ifdef GL_EXT_shader_pixel_local_storage + &__GLEW_EXT_shader_pixel_local_storage, +#endif +#ifdef GL_EXT_shader_pixel_local_storage2 + &__GLEW_EXT_shader_pixel_local_storage2, +#endif +#ifdef GL_EXT_shader_texture_lod + &__GLEW_EXT_shader_texture_lod, +#endif +#ifdef GL_EXT_shadow_funcs + &__GLEW_EXT_shadow_funcs, +#endif +#ifdef GL_EXT_shadow_samplers + &__GLEW_EXT_shadow_samplers, +#endif +#ifdef GL_EXT_shared_texture_palette + &__GLEW_EXT_shared_texture_palette, +#endif +#ifdef GL_EXT_sparse_texture + &__GLEW_EXT_sparse_texture, +#endif +#ifdef GL_EXT_sparse_texture2 + &__GLEW_EXT_sparse_texture2, +#endif +#ifdef GL_EXT_stencil_clear_tag + &__GLEW_EXT_stencil_clear_tag, +#endif +#ifdef GL_EXT_stencil_two_side + &__GLEW_EXT_stencil_two_side, +#endif +#ifdef GL_EXT_stencil_wrap + &__GLEW_EXT_stencil_wrap, +#endif +#ifdef GL_EXT_subtexture + &__GLEW_EXT_subtexture, +#endif +#ifdef GL_EXT_texture + &__GLEW_EXT_texture, +#endif +#ifdef GL_EXT_texture3D + &__GLEW_EXT_texture3D, +#endif +#ifdef GL_EXT_texture_array + &__GLEW_EXT_texture_array, +#endif +#ifdef GL_EXT_texture_buffer_object + &__GLEW_EXT_texture_buffer_object, +#endif +#ifdef GL_EXT_texture_compression_astc_decode_mode + &__GLEW_EXT_texture_compression_astc_decode_mode, +#endif +#ifdef GL_EXT_texture_compression_astc_decode_mode_rgb9e5 + &__GLEW_EXT_texture_compression_astc_decode_mode_rgb9e5, +#endif +#ifdef GL_EXT_texture_compression_bptc + &__GLEW_EXT_texture_compression_bptc, +#endif +#ifdef GL_EXT_texture_compression_dxt1 + &__GLEW_EXT_texture_compression_dxt1, +#endif +#ifdef GL_EXT_texture_compression_latc + &__GLEW_EXT_texture_compression_latc, +#endif +#ifdef GL_EXT_texture_compression_rgtc + &__GLEW_EXT_texture_compression_rgtc, +#endif +#ifdef GL_EXT_texture_compression_s3tc + &__GLEW_EXT_texture_compression_s3tc, +#endif +#ifdef GL_EXT_texture_cube_map + &__GLEW_EXT_texture_cube_map, +#endif +#ifdef GL_EXT_texture_cube_map_array + &__GLEW_EXT_texture_cube_map_array, +#endif +#ifdef GL_EXT_texture_edge_clamp + &__GLEW_EXT_texture_edge_clamp, +#endif +#ifdef GL_EXT_texture_env + &__GLEW_EXT_texture_env, +#endif +#ifdef GL_EXT_texture_env_add + &__GLEW_EXT_texture_env_add, +#endif +#ifdef GL_EXT_texture_env_combine + &__GLEW_EXT_texture_env_combine, +#endif +#ifdef GL_EXT_texture_env_dot3 + &__GLEW_EXT_texture_env_dot3, +#endif +#ifdef GL_EXT_texture_filter_anisotropic + &__GLEW_EXT_texture_filter_anisotropic, +#endif +#ifdef GL_EXT_texture_filter_minmax + &__GLEW_EXT_texture_filter_minmax, +#endif +#ifdef GL_EXT_texture_format_BGRA8888 + &__GLEW_EXT_texture_format_BGRA8888, +#endif +#ifdef GL_EXT_texture_integer + &__GLEW_EXT_texture_integer, +#endif +#ifdef GL_EXT_texture_lod_bias + &__GLEW_EXT_texture_lod_bias, +#endif +#ifdef GL_EXT_texture_mirror_clamp + &__GLEW_EXT_texture_mirror_clamp, +#endif +#ifdef GL_EXT_texture_norm16 + &__GLEW_EXT_texture_norm16, +#endif +#ifdef GL_EXT_texture_object + &__GLEW_EXT_texture_object, +#endif +#ifdef GL_EXT_texture_perturb_normal + &__GLEW_EXT_texture_perturb_normal, +#endif +#ifdef GL_EXT_texture_rectangle + &__GLEW_EXT_texture_rectangle, +#endif +#ifdef GL_EXT_texture_rg + &__GLEW_EXT_texture_rg, +#endif +#ifdef GL_EXT_texture_sRGB + &__GLEW_EXT_texture_sRGB, +#endif +#ifdef GL_EXT_texture_sRGB_R8 + &__GLEW_EXT_texture_sRGB_R8, +#endif +#ifdef GL_EXT_texture_sRGB_RG8 + &__GLEW_EXT_texture_sRGB_RG8, +#endif +#ifdef GL_EXT_texture_sRGB_decode + &__GLEW_EXT_texture_sRGB_decode, +#endif +#ifdef GL_EXT_texture_shared_exponent + &__GLEW_EXT_texture_shared_exponent, +#endif +#ifdef GL_EXT_texture_snorm + &__GLEW_EXT_texture_snorm, +#endif +#ifdef GL_EXT_texture_storage + &__GLEW_EXT_texture_storage, +#endif +#ifdef GL_EXT_texture_swizzle + &__GLEW_EXT_texture_swizzle, +#endif +#ifdef GL_EXT_texture_type_2_10_10_10_REV + &__GLEW_EXT_texture_type_2_10_10_10_REV, +#endif +#ifdef GL_EXT_texture_view + &__GLEW_EXT_texture_view, +#endif +#ifdef GL_EXT_timer_query + &__GLEW_EXT_timer_query, +#endif +#ifdef GL_EXT_transform_feedback + &__GLEW_EXT_transform_feedback, +#endif +#ifdef GL_EXT_unpack_subimage + &__GLEW_EXT_unpack_subimage, +#endif +#ifdef GL_EXT_vertex_array + &__GLEW_EXT_vertex_array, +#endif +#ifdef GL_EXT_vertex_array_bgra + &__GLEW_EXT_vertex_array_bgra, +#endif +#ifdef GL_EXT_vertex_array_setXXX + &__GLEW_EXT_vertex_array_setXXX, +#endif +#ifdef GL_EXT_vertex_attrib_64bit + &__GLEW_EXT_vertex_attrib_64bit, +#endif +#ifdef GL_EXT_vertex_shader + &__GLEW_EXT_vertex_shader, +#endif +#ifdef GL_EXT_vertex_weighting + &__GLEW_EXT_vertex_weighting, +#endif +#ifdef GL_EXT_win32_keyed_mutex + &__GLEW_EXT_win32_keyed_mutex, +#endif +#ifdef GL_EXT_window_rectangles + &__GLEW_EXT_window_rectangles, +#endif +#ifdef GL_EXT_x11_sync_object + &__GLEW_EXT_x11_sync_object, +#endif +#ifdef GL_GREMEDY_frame_terminator + &__GLEW_GREMEDY_frame_terminator, +#endif +#ifdef GL_GREMEDY_string_marker + &__GLEW_GREMEDY_string_marker, +#endif +#ifdef GL_HP_convolution_border_modes + &__GLEW_HP_convolution_border_modes, +#endif +#ifdef GL_HP_image_transform + &__GLEW_HP_image_transform, +#endif +#ifdef GL_HP_occlusion_test + &__GLEW_HP_occlusion_test, +#endif +#ifdef GL_HP_texture_lighting + &__GLEW_HP_texture_lighting, +#endif +#ifdef GL_IBM_cull_vertex + &__GLEW_IBM_cull_vertex, +#endif +#ifdef GL_IBM_multimode_draw_arrays + &__GLEW_IBM_multimode_draw_arrays, +#endif +#ifdef GL_IBM_rasterpos_clip + &__GLEW_IBM_rasterpos_clip, +#endif +#ifdef GL_IBM_static_data + &__GLEW_IBM_static_data, +#endif +#ifdef GL_IBM_texture_mirrored_repeat + &__GLEW_IBM_texture_mirrored_repeat, +#endif +#ifdef GL_IBM_vertex_array_lists + &__GLEW_IBM_vertex_array_lists, +#endif +#ifdef GL_INGR_color_clamp + &__GLEW_INGR_color_clamp, +#endif +#ifdef GL_INGR_interlace_read + &__GLEW_INGR_interlace_read, +#endif +#ifdef GL_INTEL_conservative_rasterization + &__GLEW_INTEL_conservative_rasterization, +#endif +#ifdef GL_INTEL_fragment_shader_ordering + &__GLEW_INTEL_fragment_shader_ordering, +#endif +#ifdef GL_INTEL_framebuffer_CMAA + &__GLEW_INTEL_framebuffer_CMAA, +#endif +#ifdef GL_INTEL_map_texture + &__GLEW_INTEL_map_texture, +#endif +#ifdef GL_INTEL_parallel_arrays + &__GLEW_INTEL_parallel_arrays, +#endif +#ifdef GL_INTEL_performance_query + &__GLEW_INTEL_performance_query, +#endif +#ifdef GL_INTEL_texture_scissor + &__GLEW_INTEL_texture_scissor, +#endif +#ifdef GL_KHR_blend_equation_advanced + &__GLEW_KHR_blend_equation_advanced, +#endif +#ifdef GL_KHR_blend_equation_advanced_coherent + &__GLEW_KHR_blend_equation_advanced_coherent, +#endif +#ifdef GL_KHR_context_flush_control + &__GLEW_KHR_context_flush_control, +#endif +#ifdef GL_KHR_debug + &__GLEW_KHR_debug, +#endif +#ifdef GL_KHR_no_error + &__GLEW_KHR_no_error, +#endif +#ifdef GL_KHR_parallel_shader_compile + &__GLEW_KHR_parallel_shader_compile, +#endif +#ifdef GL_KHR_robust_buffer_access_behavior + &__GLEW_KHR_robust_buffer_access_behavior, +#endif +#ifdef GL_KHR_robustness + &__GLEW_KHR_robustness, +#endif +#ifdef GL_KHR_texture_compression_astc_hdr + &__GLEW_KHR_texture_compression_astc_hdr, +#endif +#ifdef GL_KHR_texture_compression_astc_ldr + &__GLEW_KHR_texture_compression_astc_ldr, +#endif +#ifdef GL_KHR_texture_compression_astc_sliced_3d + &__GLEW_KHR_texture_compression_astc_sliced_3d, +#endif +#ifdef GL_KTX_buffer_region + &__GLEW_KTX_buffer_region, +#endif +#ifdef GL_MESAX_texture_stack + &__GLEW_MESAX_texture_stack, +#endif +#ifdef GL_MESA_pack_invert + &__GLEW_MESA_pack_invert, +#endif +#ifdef GL_MESA_resize_buffers + &__GLEW_MESA_resize_buffers, +#endif +#ifdef GL_MESA_shader_integer_functions + &__GLEW_MESA_shader_integer_functions, +#endif +#ifdef GL_MESA_window_pos + &__GLEW_MESA_window_pos, +#endif +#ifdef GL_MESA_ycbcr_texture + &__GLEW_MESA_ycbcr_texture, +#endif +#ifdef GL_NVX_blend_equation_advanced_multi_draw_buffers + &__GLEW_NVX_blend_equation_advanced_multi_draw_buffers, +#endif +#ifdef GL_NVX_conditional_render + &__GLEW_NVX_conditional_render, +#endif +#ifdef GL_NVX_gpu_memory_info + &__GLEW_NVX_gpu_memory_info, +#endif +#ifdef GL_NVX_linked_gpu_multicast + &__GLEW_NVX_linked_gpu_multicast, +#endif +#ifdef GL_NV_3dvision_settings + &__GLEW_NV_3dvision_settings, +#endif +#ifdef GL_NV_EGL_stream_consumer_external + &__GLEW_NV_EGL_stream_consumer_external, +#endif +#ifdef GL_NV_alpha_to_coverage_dither_control + &__GLEW_NV_alpha_to_coverage_dither_control, +#endif +#ifdef GL_NV_bgr + &__GLEW_NV_bgr, +#endif +#ifdef GL_NV_bindless_multi_draw_indirect + &__GLEW_NV_bindless_multi_draw_indirect, +#endif +#ifdef GL_NV_bindless_multi_draw_indirect_count + &__GLEW_NV_bindless_multi_draw_indirect_count, +#endif +#ifdef GL_NV_bindless_texture + &__GLEW_NV_bindless_texture, +#endif +#ifdef GL_NV_blend_equation_advanced + &__GLEW_NV_blend_equation_advanced, +#endif +#ifdef GL_NV_blend_equation_advanced_coherent + &__GLEW_NV_blend_equation_advanced_coherent, +#endif +#ifdef GL_NV_blend_minmax_factor + &__GLEW_NV_blend_minmax_factor, +#endif +#ifdef GL_NV_blend_square + &__GLEW_NV_blend_square, +#endif +#ifdef GL_NV_clip_space_w_scaling + &__GLEW_NV_clip_space_w_scaling, +#endif +#ifdef GL_NV_command_list + &__GLEW_NV_command_list, +#endif +#ifdef GL_NV_compute_program5 + &__GLEW_NV_compute_program5, +#endif +#ifdef GL_NV_conditional_render + &__GLEW_NV_conditional_render, +#endif +#ifdef GL_NV_conservative_raster + &__GLEW_NV_conservative_raster, +#endif +#ifdef GL_NV_conservative_raster_dilate + &__GLEW_NV_conservative_raster_dilate, +#endif +#ifdef GL_NV_conservative_raster_pre_snap_triangles + &__GLEW_NV_conservative_raster_pre_snap_triangles, +#endif +#ifdef GL_NV_copy_buffer + &__GLEW_NV_copy_buffer, +#endif +#ifdef GL_NV_copy_depth_to_color + &__GLEW_NV_copy_depth_to_color, +#endif +#ifdef GL_NV_copy_image + &__GLEW_NV_copy_image, +#endif +#ifdef GL_NV_deep_texture3D + &__GLEW_NV_deep_texture3D, +#endif +#ifdef GL_NV_depth_buffer_float + &__GLEW_NV_depth_buffer_float, +#endif +#ifdef GL_NV_depth_clamp + &__GLEW_NV_depth_clamp, +#endif +#ifdef GL_NV_depth_range_unclamped + &__GLEW_NV_depth_range_unclamped, +#endif +#ifdef GL_NV_draw_buffers + &__GLEW_NV_draw_buffers, +#endif +#ifdef GL_NV_draw_instanced + &__GLEW_NV_draw_instanced, +#endif +#ifdef GL_NV_draw_texture + &__GLEW_NV_draw_texture, +#endif +#ifdef GL_NV_draw_vulkan_image + &__GLEW_NV_draw_vulkan_image, +#endif +#ifdef GL_NV_evaluators + &__GLEW_NV_evaluators, +#endif +#ifdef GL_NV_explicit_attrib_location + &__GLEW_NV_explicit_attrib_location, +#endif +#ifdef GL_NV_explicit_multisample + &__GLEW_NV_explicit_multisample, +#endif +#ifdef GL_NV_fbo_color_attachments + &__GLEW_NV_fbo_color_attachments, +#endif +#ifdef GL_NV_fence + &__GLEW_NV_fence, +#endif +#ifdef GL_NV_fill_rectangle + &__GLEW_NV_fill_rectangle, +#endif +#ifdef GL_NV_float_buffer + &__GLEW_NV_float_buffer, +#endif +#ifdef GL_NV_fog_distance + &__GLEW_NV_fog_distance, +#endif +#ifdef GL_NV_fragment_coverage_to_color + &__GLEW_NV_fragment_coverage_to_color, +#endif +#ifdef GL_NV_fragment_program + &__GLEW_NV_fragment_program, +#endif +#ifdef GL_NV_fragment_program2 + &__GLEW_NV_fragment_program2, +#endif +#ifdef GL_NV_fragment_program4 + &__GLEW_NV_fragment_program4, +#endif +#ifdef GL_NV_fragment_program_option + &__GLEW_NV_fragment_program_option, +#endif +#ifdef GL_NV_fragment_shader_interlock + &__GLEW_NV_fragment_shader_interlock, +#endif +#ifdef GL_NV_framebuffer_blit + &__GLEW_NV_framebuffer_blit, +#endif +#ifdef GL_NV_framebuffer_mixed_samples + &__GLEW_NV_framebuffer_mixed_samples, +#endif +#ifdef GL_NV_framebuffer_multisample + &__GLEW_NV_framebuffer_multisample, +#endif +#ifdef GL_NV_framebuffer_multisample_coverage + &__GLEW_NV_framebuffer_multisample_coverage, +#endif +#ifdef GL_NV_generate_mipmap_sRGB + &__GLEW_NV_generate_mipmap_sRGB, +#endif +#ifdef GL_NV_geometry_program4 + &__GLEW_NV_geometry_program4, +#endif +#ifdef GL_NV_geometry_shader4 + &__GLEW_NV_geometry_shader4, +#endif +#ifdef GL_NV_geometry_shader_passthrough + &__GLEW_NV_geometry_shader_passthrough, +#endif +#ifdef GL_NV_gpu_multicast + &__GLEW_NV_gpu_multicast, +#endif +#ifdef GL_NV_gpu_program4 + &__GLEW_NV_gpu_program4, +#endif +#ifdef GL_NV_gpu_program5 + &__GLEW_NV_gpu_program5, +#endif +#ifdef GL_NV_gpu_program5_mem_extended + &__GLEW_NV_gpu_program5_mem_extended, +#endif +#ifdef GL_NV_gpu_program_fp64 + &__GLEW_NV_gpu_program_fp64, +#endif +#ifdef GL_NV_gpu_shader5 + &__GLEW_NV_gpu_shader5, +#endif +#ifdef GL_NV_half_float + &__GLEW_NV_half_float, +#endif +#ifdef GL_NV_image_formats + &__GLEW_NV_image_formats, +#endif +#ifdef GL_NV_instanced_arrays + &__GLEW_NV_instanced_arrays, +#endif +#ifdef GL_NV_internalformat_sample_query + &__GLEW_NV_internalformat_sample_query, +#endif +#ifdef GL_NV_light_max_exponent + &__GLEW_NV_light_max_exponent, +#endif +#ifdef GL_NV_multisample_coverage + &__GLEW_NV_multisample_coverage, +#endif +#ifdef GL_NV_multisample_filter_hint + &__GLEW_NV_multisample_filter_hint, +#endif +#ifdef GL_NV_non_square_matrices + &__GLEW_NV_non_square_matrices, +#endif +#ifdef GL_NV_occlusion_query + &__GLEW_NV_occlusion_query, +#endif +#ifdef GL_NV_pack_subimage + &__GLEW_NV_pack_subimage, +#endif +#ifdef GL_NV_packed_depth_stencil + &__GLEW_NV_packed_depth_stencil, +#endif +#ifdef GL_NV_packed_float + &__GLEW_NV_packed_float, +#endif +#ifdef GL_NV_packed_float_linear + &__GLEW_NV_packed_float_linear, +#endif +#ifdef GL_NV_parameter_buffer_object + &__GLEW_NV_parameter_buffer_object, +#endif +#ifdef GL_NV_parameter_buffer_object2 + &__GLEW_NV_parameter_buffer_object2, +#endif +#ifdef GL_NV_path_rendering + &__GLEW_NV_path_rendering, +#endif +#ifdef GL_NV_path_rendering_shared_edge + &__GLEW_NV_path_rendering_shared_edge, +#endif +#ifdef GL_NV_pixel_buffer_object + &__GLEW_NV_pixel_buffer_object, +#endif +#ifdef GL_NV_pixel_data_range + &__GLEW_NV_pixel_data_range, +#endif +#ifdef GL_NV_platform_binary + &__GLEW_NV_platform_binary, +#endif +#ifdef GL_NV_point_sprite + &__GLEW_NV_point_sprite, +#endif +#ifdef GL_NV_polygon_mode + &__GLEW_NV_polygon_mode, +#endif +#ifdef GL_NV_present_video + &__GLEW_NV_present_video, +#endif +#ifdef GL_NV_primitive_restart + &__GLEW_NV_primitive_restart, +#endif +#ifdef GL_NV_read_depth + &__GLEW_NV_read_depth, +#endif +#ifdef GL_NV_read_depth_stencil + &__GLEW_NV_read_depth_stencil, +#endif +#ifdef GL_NV_read_stencil + &__GLEW_NV_read_stencil, +#endif +#ifdef GL_NV_register_combiners + &__GLEW_NV_register_combiners, +#endif +#ifdef GL_NV_register_combiners2 + &__GLEW_NV_register_combiners2, +#endif +#ifdef GL_NV_robustness_video_memory_purge + &__GLEW_NV_robustness_video_memory_purge, +#endif +#ifdef GL_NV_sRGB_formats + &__GLEW_NV_sRGB_formats, +#endif +#ifdef GL_NV_sample_locations + &__GLEW_NV_sample_locations, +#endif +#ifdef GL_NV_sample_mask_override_coverage + &__GLEW_NV_sample_mask_override_coverage, +#endif +#ifdef GL_NV_shader_atomic_counters + &__GLEW_NV_shader_atomic_counters, +#endif +#ifdef GL_NV_shader_atomic_float + &__GLEW_NV_shader_atomic_float, +#endif +#ifdef GL_NV_shader_atomic_float64 + &__GLEW_NV_shader_atomic_float64, +#endif +#ifdef GL_NV_shader_atomic_fp16_vector + &__GLEW_NV_shader_atomic_fp16_vector, +#endif +#ifdef GL_NV_shader_atomic_int64 + &__GLEW_NV_shader_atomic_int64, +#endif +#ifdef GL_NV_shader_buffer_load + &__GLEW_NV_shader_buffer_load, +#endif +#ifdef GL_NV_shader_noperspective_interpolation + &__GLEW_NV_shader_noperspective_interpolation, +#endif +#ifdef GL_NV_shader_storage_buffer_object + &__GLEW_NV_shader_storage_buffer_object, +#endif +#ifdef GL_NV_shader_thread_group + &__GLEW_NV_shader_thread_group, +#endif +#ifdef GL_NV_shader_thread_shuffle + &__GLEW_NV_shader_thread_shuffle, +#endif +#ifdef GL_NV_shadow_samplers_array + &__GLEW_NV_shadow_samplers_array, +#endif +#ifdef GL_NV_shadow_samplers_cube + &__GLEW_NV_shadow_samplers_cube, +#endif +#ifdef GL_NV_stereo_view_rendering + &__GLEW_NV_stereo_view_rendering, +#endif +#ifdef GL_NV_tessellation_program5 + &__GLEW_NV_tessellation_program5, +#endif +#ifdef GL_NV_texgen_emboss + &__GLEW_NV_texgen_emboss, +#endif +#ifdef GL_NV_texgen_reflection + &__GLEW_NV_texgen_reflection, +#endif +#ifdef GL_NV_texture_array + &__GLEW_NV_texture_array, +#endif +#ifdef GL_NV_texture_barrier + &__GLEW_NV_texture_barrier, +#endif +#ifdef GL_NV_texture_border_clamp + &__GLEW_NV_texture_border_clamp, +#endif +#ifdef GL_NV_texture_compression_latc + &__GLEW_NV_texture_compression_latc, +#endif +#ifdef GL_NV_texture_compression_s3tc + &__GLEW_NV_texture_compression_s3tc, +#endif +#ifdef GL_NV_texture_compression_s3tc_update + &__GLEW_NV_texture_compression_s3tc_update, +#endif +#ifdef GL_NV_texture_compression_vtc + &__GLEW_NV_texture_compression_vtc, +#endif +#ifdef GL_NV_texture_env_combine4 + &__GLEW_NV_texture_env_combine4, +#endif +#ifdef GL_NV_texture_expand_normal + &__GLEW_NV_texture_expand_normal, +#endif +#ifdef GL_NV_texture_multisample + &__GLEW_NV_texture_multisample, +#endif +#ifdef GL_NV_texture_npot_2D_mipmap + &__GLEW_NV_texture_npot_2D_mipmap, +#endif +#ifdef GL_NV_texture_rectangle + &__GLEW_NV_texture_rectangle, +#endif +#ifdef GL_NV_texture_rectangle_compressed + &__GLEW_NV_texture_rectangle_compressed, +#endif +#ifdef GL_NV_texture_shader + &__GLEW_NV_texture_shader, +#endif +#ifdef GL_NV_texture_shader2 + &__GLEW_NV_texture_shader2, +#endif +#ifdef GL_NV_texture_shader3 + &__GLEW_NV_texture_shader3, +#endif +#ifdef GL_NV_transform_feedback + &__GLEW_NV_transform_feedback, +#endif +#ifdef GL_NV_transform_feedback2 + &__GLEW_NV_transform_feedback2, +#endif +#ifdef GL_NV_uniform_buffer_unified_memory + &__GLEW_NV_uniform_buffer_unified_memory, +#endif +#ifdef GL_NV_vdpau_interop + &__GLEW_NV_vdpau_interop, +#endif +#ifdef GL_NV_vertex_array_range + &__GLEW_NV_vertex_array_range, +#endif +#ifdef GL_NV_vertex_array_range2 + &__GLEW_NV_vertex_array_range2, +#endif +#ifdef GL_NV_vertex_attrib_integer_64bit + &__GLEW_NV_vertex_attrib_integer_64bit, +#endif +#ifdef GL_NV_vertex_buffer_unified_memory + &__GLEW_NV_vertex_buffer_unified_memory, +#endif +#ifdef GL_NV_vertex_program + &__GLEW_NV_vertex_program, +#endif +#ifdef GL_NV_vertex_program1_1 + &__GLEW_NV_vertex_program1_1, +#endif +#ifdef GL_NV_vertex_program2 + &__GLEW_NV_vertex_program2, +#endif +#ifdef GL_NV_vertex_program2_option + &__GLEW_NV_vertex_program2_option, +#endif +#ifdef GL_NV_vertex_program3 + &__GLEW_NV_vertex_program3, +#endif +#ifdef GL_NV_vertex_program4 + &__GLEW_NV_vertex_program4, +#endif +#ifdef GL_NV_video_capture + &__GLEW_NV_video_capture, +#endif +#ifdef GL_NV_viewport_array + &__GLEW_NV_viewport_array, +#endif +#ifdef GL_NV_viewport_array2 + &__GLEW_NV_viewport_array2, +#endif +#ifdef GL_NV_viewport_swizzle + &__GLEW_NV_viewport_swizzle, +#endif +#ifdef GL_OES_byte_coordinates + &__GLEW_OES_byte_coordinates, +#endif +#ifdef GL_OML_interlace + &__GLEW_OML_interlace, +#endif +#ifdef GL_OML_resample + &__GLEW_OML_resample, +#endif +#ifdef GL_OML_subsample + &__GLEW_OML_subsample, +#endif +#ifdef GL_OVR_multiview + &__GLEW_OVR_multiview, +#endif +#ifdef GL_OVR_multiview2 + &__GLEW_OVR_multiview2, +#endif +#ifdef GL_OVR_multiview_multisampled_render_to_texture + &__GLEW_OVR_multiview_multisampled_render_to_texture, +#endif +#ifdef GL_PGI_misc_hints + &__GLEW_PGI_misc_hints, +#endif +#ifdef GL_PGI_vertex_hints + &__GLEW_PGI_vertex_hints, +#endif +#ifdef GL_QCOM_alpha_test + &__GLEW_QCOM_alpha_test, +#endif +#ifdef GL_QCOM_binning_control + &__GLEW_QCOM_binning_control, +#endif +#ifdef GL_QCOM_driver_control + &__GLEW_QCOM_driver_control, +#endif +#ifdef GL_QCOM_extended_get + &__GLEW_QCOM_extended_get, +#endif +#ifdef GL_QCOM_extended_get2 + &__GLEW_QCOM_extended_get2, +#endif +#ifdef GL_QCOM_framebuffer_foveated + &__GLEW_QCOM_framebuffer_foveated, +#endif +#ifdef GL_QCOM_perfmon_global_mode + &__GLEW_QCOM_perfmon_global_mode, +#endif +#ifdef GL_QCOM_shader_framebuffer_fetch_noncoherent + &__GLEW_QCOM_shader_framebuffer_fetch_noncoherent, +#endif +#ifdef GL_QCOM_tiled_rendering + &__GLEW_QCOM_tiled_rendering, +#endif +#ifdef GL_QCOM_writeonly_rendering + &__GLEW_QCOM_writeonly_rendering, +#endif +#ifdef GL_REGAL_ES1_0_compatibility + &__GLEW_REGAL_ES1_0_compatibility, +#endif +#ifdef GL_REGAL_ES1_1_compatibility + &__GLEW_REGAL_ES1_1_compatibility, +#endif +#ifdef GL_REGAL_enable + &__GLEW_REGAL_enable, +#endif +#ifdef GL_REGAL_error_string + &__GLEW_REGAL_error_string, +#endif +#ifdef GL_REGAL_extension_query + &__GLEW_REGAL_extension_query, +#endif +#ifdef GL_REGAL_log + &__GLEW_REGAL_log, +#endif +#ifdef GL_REGAL_proc_address + &__GLEW_REGAL_proc_address, +#endif +#ifdef GL_REND_screen_coordinates + &__GLEW_REND_screen_coordinates, +#endif +#ifdef GL_S3_s3tc + &__GLEW_S3_s3tc, +#endif +#ifdef GL_SGIS_clip_band_hint + &__GLEW_SGIS_clip_band_hint, +#endif +#ifdef GL_SGIS_color_range + &__GLEW_SGIS_color_range, +#endif +#ifdef GL_SGIS_detail_texture + &__GLEW_SGIS_detail_texture, +#endif +#ifdef GL_SGIS_fog_function + &__GLEW_SGIS_fog_function, +#endif +#ifdef GL_SGIS_generate_mipmap + &__GLEW_SGIS_generate_mipmap, +#endif +#ifdef GL_SGIS_line_texgen + &__GLEW_SGIS_line_texgen, +#endif +#ifdef GL_SGIS_multisample + &__GLEW_SGIS_multisample, +#endif +#ifdef GL_SGIS_multitexture + &__GLEW_SGIS_multitexture, +#endif +#ifdef GL_SGIS_pixel_texture + &__GLEW_SGIS_pixel_texture, +#endif +#ifdef GL_SGIS_point_line_texgen + &__GLEW_SGIS_point_line_texgen, +#endif +#ifdef GL_SGIS_shared_multisample + &__GLEW_SGIS_shared_multisample, +#endif +#ifdef GL_SGIS_sharpen_texture + &__GLEW_SGIS_sharpen_texture, +#endif +#ifdef GL_SGIS_texture4D + &__GLEW_SGIS_texture4D, +#endif +#ifdef GL_SGIS_texture_border_clamp + &__GLEW_SGIS_texture_border_clamp, +#endif +#ifdef GL_SGIS_texture_edge_clamp + &__GLEW_SGIS_texture_edge_clamp, +#endif +#ifdef GL_SGIS_texture_filter4 + &__GLEW_SGIS_texture_filter4, +#endif +#ifdef GL_SGIS_texture_lod + &__GLEW_SGIS_texture_lod, +#endif +#ifdef GL_SGIS_texture_select + &__GLEW_SGIS_texture_select, +#endif +#ifdef GL_SGIX_async + &__GLEW_SGIX_async, +#endif +#ifdef GL_SGIX_async_histogram + &__GLEW_SGIX_async_histogram, +#endif +#ifdef GL_SGIX_async_pixel + &__GLEW_SGIX_async_pixel, +#endif +#ifdef GL_SGIX_bali_g_instruments + &__GLEW_SGIX_bali_g_instruments, +#endif +#ifdef GL_SGIX_bali_r_instruments + &__GLEW_SGIX_bali_r_instruments, +#endif +#ifdef GL_SGIX_bali_timer_instruments + &__GLEW_SGIX_bali_timer_instruments, +#endif +#ifdef GL_SGIX_blend_alpha_minmax + &__GLEW_SGIX_blend_alpha_minmax, +#endif +#ifdef GL_SGIX_blend_cadd + &__GLEW_SGIX_blend_cadd, +#endif +#ifdef GL_SGIX_blend_cmultiply + &__GLEW_SGIX_blend_cmultiply, +#endif +#ifdef GL_SGIX_calligraphic_fragment + &__GLEW_SGIX_calligraphic_fragment, +#endif +#ifdef GL_SGIX_clipmap + &__GLEW_SGIX_clipmap, +#endif +#ifdef GL_SGIX_color_matrix_accuracy + &__GLEW_SGIX_color_matrix_accuracy, +#endif +#ifdef GL_SGIX_color_table_index_mode + &__GLEW_SGIX_color_table_index_mode, +#endif +#ifdef GL_SGIX_complex_polar + &__GLEW_SGIX_complex_polar, +#endif +#ifdef GL_SGIX_convolution_accuracy + &__GLEW_SGIX_convolution_accuracy, +#endif +#ifdef GL_SGIX_cube_map + &__GLEW_SGIX_cube_map, +#endif +#ifdef GL_SGIX_cylinder_texgen + &__GLEW_SGIX_cylinder_texgen, +#endif +#ifdef GL_SGIX_datapipe + &__GLEW_SGIX_datapipe, +#endif +#ifdef GL_SGIX_decimation + &__GLEW_SGIX_decimation, +#endif +#ifdef GL_SGIX_depth_pass_instrument + &__GLEW_SGIX_depth_pass_instrument, +#endif +#ifdef GL_SGIX_depth_texture + &__GLEW_SGIX_depth_texture, +#endif +#ifdef GL_SGIX_dvc + &__GLEW_SGIX_dvc, +#endif +#ifdef GL_SGIX_flush_raster + &__GLEW_SGIX_flush_raster, +#endif +#ifdef GL_SGIX_fog_blend + &__GLEW_SGIX_fog_blend, +#endif +#ifdef GL_SGIX_fog_factor_to_alpha + &__GLEW_SGIX_fog_factor_to_alpha, +#endif +#ifdef GL_SGIX_fog_layers + &__GLEW_SGIX_fog_layers, +#endif +#ifdef GL_SGIX_fog_offset + &__GLEW_SGIX_fog_offset, +#endif +#ifdef GL_SGIX_fog_patchy + &__GLEW_SGIX_fog_patchy, +#endif +#ifdef GL_SGIX_fog_scale + &__GLEW_SGIX_fog_scale, +#endif +#ifdef GL_SGIX_fog_texture + &__GLEW_SGIX_fog_texture, +#endif +#ifdef GL_SGIX_fragment_lighting_space + &__GLEW_SGIX_fragment_lighting_space, +#endif +#ifdef GL_SGIX_fragment_specular_lighting + &__GLEW_SGIX_fragment_specular_lighting, +#endif +#ifdef GL_SGIX_fragments_instrument + &__GLEW_SGIX_fragments_instrument, +#endif +#ifdef GL_SGIX_framezoom + &__GLEW_SGIX_framezoom, +#endif +#ifdef GL_SGIX_icc_texture + &__GLEW_SGIX_icc_texture, +#endif +#ifdef GL_SGIX_igloo_interface + &__GLEW_SGIX_igloo_interface, +#endif +#ifdef GL_SGIX_image_compression + &__GLEW_SGIX_image_compression, +#endif +#ifdef GL_SGIX_impact_pixel_texture + &__GLEW_SGIX_impact_pixel_texture, +#endif +#ifdef GL_SGIX_instrument_error + &__GLEW_SGIX_instrument_error, +#endif +#ifdef GL_SGIX_interlace + &__GLEW_SGIX_interlace, +#endif +#ifdef GL_SGIX_ir_instrument1 + &__GLEW_SGIX_ir_instrument1, +#endif +#ifdef GL_SGIX_line_quality_hint + &__GLEW_SGIX_line_quality_hint, +#endif +#ifdef GL_SGIX_list_priority + &__GLEW_SGIX_list_priority, +#endif +#ifdef GL_SGIX_mpeg1 + &__GLEW_SGIX_mpeg1, +#endif +#ifdef GL_SGIX_mpeg2 + &__GLEW_SGIX_mpeg2, +#endif +#ifdef GL_SGIX_nonlinear_lighting_pervertex + &__GLEW_SGIX_nonlinear_lighting_pervertex, +#endif +#ifdef GL_SGIX_nurbs_eval + &__GLEW_SGIX_nurbs_eval, +#endif +#ifdef GL_SGIX_occlusion_instrument + &__GLEW_SGIX_occlusion_instrument, +#endif +#ifdef GL_SGIX_packed_6bytes + &__GLEW_SGIX_packed_6bytes, +#endif +#ifdef GL_SGIX_pixel_texture + &__GLEW_SGIX_pixel_texture, +#endif +#ifdef GL_SGIX_pixel_texture_bits + &__GLEW_SGIX_pixel_texture_bits, +#endif +#ifdef GL_SGIX_pixel_texture_lod + &__GLEW_SGIX_pixel_texture_lod, +#endif +#ifdef GL_SGIX_pixel_tiles + &__GLEW_SGIX_pixel_tiles, +#endif +#ifdef GL_SGIX_polynomial_ffd + &__GLEW_SGIX_polynomial_ffd, +#endif +#ifdef GL_SGIX_quad_mesh + &__GLEW_SGIX_quad_mesh, +#endif +#ifdef GL_SGIX_reference_plane + &__GLEW_SGIX_reference_plane, +#endif +#ifdef GL_SGIX_resample + &__GLEW_SGIX_resample, +#endif +#ifdef GL_SGIX_scalebias_hint + &__GLEW_SGIX_scalebias_hint, +#endif +#ifdef GL_SGIX_shadow + &__GLEW_SGIX_shadow, +#endif +#ifdef GL_SGIX_shadow_ambient + &__GLEW_SGIX_shadow_ambient, +#endif +#ifdef GL_SGIX_slim + &__GLEW_SGIX_slim, +#endif +#ifdef GL_SGIX_spotlight_cutoff + &__GLEW_SGIX_spotlight_cutoff, +#endif +#ifdef GL_SGIX_sprite + &__GLEW_SGIX_sprite, +#endif +#ifdef GL_SGIX_subdiv_patch + &__GLEW_SGIX_subdiv_patch, +#endif +#ifdef GL_SGIX_subsample + &__GLEW_SGIX_subsample, +#endif +#ifdef GL_SGIX_tag_sample_buffer + &__GLEW_SGIX_tag_sample_buffer, +#endif +#ifdef GL_SGIX_texture_add_env + &__GLEW_SGIX_texture_add_env, +#endif +#ifdef GL_SGIX_texture_coordinate_clamp + &__GLEW_SGIX_texture_coordinate_clamp, +#endif +#ifdef GL_SGIX_texture_lod_bias + &__GLEW_SGIX_texture_lod_bias, +#endif +#ifdef GL_SGIX_texture_mipmap_anisotropic + &__GLEW_SGIX_texture_mipmap_anisotropic, +#endif +#ifdef GL_SGIX_texture_multi_buffer + &__GLEW_SGIX_texture_multi_buffer, +#endif +#ifdef GL_SGIX_texture_phase + &__GLEW_SGIX_texture_phase, +#endif +#ifdef GL_SGIX_texture_range + &__GLEW_SGIX_texture_range, +#endif +#ifdef GL_SGIX_texture_scale_bias + &__GLEW_SGIX_texture_scale_bias, +#endif +#ifdef GL_SGIX_texture_supersample + &__GLEW_SGIX_texture_supersample, +#endif +#ifdef GL_SGIX_vector_ops + &__GLEW_SGIX_vector_ops, +#endif +#ifdef GL_SGIX_vertex_array_object + &__GLEW_SGIX_vertex_array_object, +#endif +#ifdef GL_SGIX_vertex_preclip + &__GLEW_SGIX_vertex_preclip, +#endif +#ifdef GL_SGIX_vertex_preclip_hint + &__GLEW_SGIX_vertex_preclip_hint, +#endif +#ifdef GL_SGIX_ycrcb + &__GLEW_SGIX_ycrcb, +#endif +#ifdef GL_SGIX_ycrcb_subsample + &__GLEW_SGIX_ycrcb_subsample, +#endif +#ifdef GL_SGIX_ycrcba + &__GLEW_SGIX_ycrcba, +#endif +#ifdef GL_SGI_color_matrix + &__GLEW_SGI_color_matrix, +#endif +#ifdef GL_SGI_color_table + &__GLEW_SGI_color_table, +#endif +#ifdef GL_SGI_complex + &__GLEW_SGI_complex, +#endif +#ifdef GL_SGI_complex_type + &__GLEW_SGI_complex_type, +#endif +#ifdef GL_SGI_fft + &__GLEW_SGI_fft, +#endif +#ifdef GL_SGI_texture_color_table + &__GLEW_SGI_texture_color_table, +#endif +#ifdef GL_SUNX_constant_data + &__GLEW_SUNX_constant_data, +#endif +#ifdef GL_SUN_convolution_border_modes + &__GLEW_SUN_convolution_border_modes, +#endif +#ifdef GL_SUN_global_alpha + &__GLEW_SUN_global_alpha, +#endif +#ifdef GL_SUN_mesh_array + &__GLEW_SUN_mesh_array, +#endif +#ifdef GL_SUN_read_video_pixels + &__GLEW_SUN_read_video_pixels, +#endif +#ifdef GL_SUN_slice_accum + &__GLEW_SUN_slice_accum, +#endif +#ifdef GL_SUN_triangle_list + &__GLEW_SUN_triangle_list, +#endif +#ifdef GL_SUN_vertex + &__GLEW_SUN_vertex, +#endif +#ifdef GL_WIN_phong_shading + &__GLEW_WIN_phong_shading, +#endif +#ifdef GL_WIN_scene_markerXXX + &__GLEW_WIN_scene_markerXXX, +#endif +#ifdef GL_WIN_specular_fog + &__GLEW_WIN_specular_fog, +#endif +#ifdef GL_WIN_swap_hint + &__GLEW_WIN_swap_hint, +#endif + NULL +}; +static GLboolean _glewInit_GL_VERSION_1_2 (); +static GLboolean _glewInit_GL_VERSION_1_3 (); +static GLboolean _glewInit_GL_VERSION_1_4 (); +static GLboolean _glewInit_GL_VERSION_1_5 (); +static GLboolean _glewInit_GL_VERSION_2_0 (); +static GLboolean _glewInit_GL_VERSION_2_1 (); +static GLboolean _glewInit_GL_VERSION_3_0 (); +static GLboolean _glewInit_GL_VERSION_3_1 (); +static GLboolean _glewInit_GL_VERSION_3_2 (); +static GLboolean _glewInit_GL_VERSION_3_3 (); +static GLboolean _glewInit_GL_VERSION_4_0 (); +static GLboolean _glewInit_GL_VERSION_4_5 (); +static GLboolean _glewInit_GL_VERSION_4_6 (); +static GLboolean _glewInit_GL_3DFX_tbuffer (); +static GLboolean _glewInit_GL_AMD_debug_output (); +static GLboolean _glewInit_GL_AMD_draw_buffers_blend (); +static GLboolean _glewInit_GL_AMD_framebuffer_sample_positions (); +static GLboolean _glewInit_GL_AMD_interleaved_elements (); +static GLboolean _glewInit_GL_AMD_multi_draw_indirect (); +static GLboolean _glewInit_GL_AMD_name_gen_delete (); +static GLboolean _glewInit_GL_AMD_occlusion_query_event (); +static GLboolean _glewInit_GL_AMD_performance_monitor (); +static GLboolean _glewInit_GL_AMD_sample_positions (); +static GLboolean _glewInit_GL_AMD_sparse_texture (); +static GLboolean _glewInit_GL_AMD_stencil_operation_extended (); +static GLboolean _glewInit_GL_AMD_vertex_shader_tessellator (); +static GLboolean _glewInit_GL_ANGLE_framebuffer_blit (); +static GLboolean _glewInit_GL_ANGLE_framebuffer_multisample (); +static GLboolean _glewInit_GL_ANGLE_instanced_arrays (); +static GLboolean _glewInit_GL_ANGLE_timer_query (); +static GLboolean _glewInit_GL_ANGLE_translated_shader_source (); +static GLboolean _glewInit_GL_APPLE_copy_texture_levels (); +static GLboolean _glewInit_GL_APPLE_element_array (); +static GLboolean _glewInit_GL_APPLE_fence (); +static GLboolean _glewInit_GL_APPLE_flush_buffer_range (); +static GLboolean _glewInit_GL_APPLE_framebuffer_multisample (); +static GLboolean _glewInit_GL_APPLE_object_purgeable (); +static GLboolean _glewInit_GL_APPLE_sync (); +static GLboolean _glewInit_GL_APPLE_texture_range (); +static GLboolean _glewInit_GL_APPLE_vertex_array_object (); +static GLboolean _glewInit_GL_APPLE_vertex_array_range (); +static GLboolean _glewInit_GL_APPLE_vertex_program_evaluators (); +static GLboolean _glewInit_GL_ARB_ES2_compatibility (); +static GLboolean _glewInit_GL_ARB_ES3_1_compatibility (); +static GLboolean _glewInit_GL_ARB_ES3_2_compatibility (); +static GLboolean _glewInit_GL_ARB_base_instance (); +static GLboolean _glewInit_GL_ARB_bindless_texture (); +static GLboolean _glewInit_GL_ARB_blend_func_extended (); +static GLboolean _glewInit_GL_ARB_buffer_storage (); +static GLboolean _glewInit_GL_ARB_cl_event (); +static GLboolean _glewInit_GL_ARB_clear_buffer_object (); +static GLboolean _glewInit_GL_ARB_clear_texture (); +static GLboolean _glewInit_GL_ARB_clip_control (); +static GLboolean _glewInit_GL_ARB_color_buffer_float (); +static GLboolean _glewInit_GL_ARB_compute_shader (); +static GLboolean _glewInit_GL_ARB_compute_variable_group_size (); +static GLboolean _glewInit_GL_ARB_copy_buffer (); +static GLboolean _glewInit_GL_ARB_copy_image (); +static GLboolean _glewInit_GL_ARB_debug_output (); +static GLboolean _glewInit_GL_ARB_direct_state_access (); +static GLboolean _glewInit_GL_ARB_draw_buffers (); +static GLboolean _glewInit_GL_ARB_draw_buffers_blend (); +static GLboolean _glewInit_GL_ARB_draw_elements_base_vertex (); +static GLboolean _glewInit_GL_ARB_draw_indirect (); +static GLboolean _glewInit_GL_ARB_framebuffer_no_attachments (); +static GLboolean _glewInit_GL_ARB_framebuffer_object (); +static GLboolean _glewInit_GL_ARB_geometry_shader4 (); +static GLboolean _glewInit_GL_ARB_get_program_binary (); +static GLboolean _glewInit_GL_ARB_get_texture_sub_image (); +static GLboolean _glewInit_GL_ARB_gl_spirv (); +static GLboolean _glewInit_GL_ARB_gpu_shader_fp64 (); +static GLboolean _glewInit_GL_ARB_gpu_shader_int64 (); +static GLboolean _glewInit_GL_ARB_imaging (); +static GLboolean _glewInit_GL_ARB_indirect_parameters (); +static GLboolean _glewInit_GL_ARB_instanced_arrays (); +static GLboolean _glewInit_GL_ARB_internalformat_query (); +static GLboolean _glewInit_GL_ARB_internalformat_query2 (); +static GLboolean _glewInit_GL_ARB_invalidate_subdata (); +static GLboolean _glewInit_GL_ARB_map_buffer_range (); +static GLboolean _glewInit_GL_ARB_matrix_palette (); +static GLboolean _glewInit_GL_ARB_multi_bind (); +static GLboolean _glewInit_GL_ARB_multi_draw_indirect (); +static GLboolean _glewInit_GL_ARB_multisample (); +static GLboolean _glewInit_GL_ARB_multitexture (); +static GLboolean _glewInit_GL_ARB_occlusion_query (); +static GLboolean _glewInit_GL_ARB_parallel_shader_compile (); +static GLboolean _glewInit_GL_ARB_point_parameters (); +static GLboolean _glewInit_GL_ARB_polygon_offset_clamp (); +static GLboolean _glewInit_GL_ARB_program_interface_query (); +static GLboolean _glewInit_GL_ARB_provoking_vertex (); +static GLboolean _glewInit_GL_ARB_robustness (); +static GLboolean _glewInit_GL_ARB_sample_locations (); +static GLboolean _glewInit_GL_ARB_sample_shading (); +static GLboolean _glewInit_GL_ARB_sampler_objects (); +static GLboolean _glewInit_GL_ARB_separate_shader_objects (); +static GLboolean _glewInit_GL_ARB_shader_atomic_counters (); +static GLboolean _glewInit_GL_ARB_shader_image_load_store (); +static GLboolean _glewInit_GL_ARB_shader_objects (); +static GLboolean _glewInit_GL_ARB_shader_storage_buffer_object (); +static GLboolean _glewInit_GL_ARB_shader_subroutine (); +static GLboolean _glewInit_GL_ARB_shading_language_include (); +static GLboolean _glewInit_GL_ARB_sparse_buffer (); +static GLboolean _glewInit_GL_ARB_sparse_texture (); +static GLboolean _glewInit_GL_ARB_sync (); +static GLboolean _glewInit_GL_ARB_tessellation_shader (); +static GLboolean _glewInit_GL_ARB_texture_barrier (); +static GLboolean _glewInit_GL_ARB_texture_buffer_object (); +static GLboolean _glewInit_GL_ARB_texture_buffer_range (); +static GLboolean _glewInit_GL_ARB_texture_compression (); +static GLboolean _glewInit_GL_ARB_texture_multisample (); +static GLboolean _glewInit_GL_ARB_texture_storage (); +static GLboolean _glewInit_GL_ARB_texture_storage_multisample (); +static GLboolean _glewInit_GL_ARB_texture_view (); +static GLboolean _glewInit_GL_ARB_timer_query (); +static GLboolean _glewInit_GL_ARB_transform_feedback2 (); +static GLboolean _glewInit_GL_ARB_transform_feedback3 (); +static GLboolean _glewInit_GL_ARB_transform_feedback_instanced (); +static GLboolean _glewInit_GL_ARB_transpose_matrix (); +static GLboolean _glewInit_GL_ARB_uniform_buffer_object (); +static GLboolean _glewInit_GL_ARB_vertex_array_object (); +static GLboolean _glewInit_GL_ARB_vertex_attrib_64bit (); +static GLboolean _glewInit_GL_ARB_vertex_attrib_binding (); +static GLboolean _glewInit_GL_ARB_vertex_blend (); +static GLboolean _glewInit_GL_ARB_vertex_buffer_object (); +static GLboolean _glewInit_GL_ARB_vertex_program (); +static GLboolean _glewInit_GL_ARB_vertex_shader (); +static GLboolean _glewInit_GL_ARB_vertex_type_2_10_10_10_rev (); +static GLboolean _glewInit_GL_ARB_viewport_array (); +static GLboolean _glewInit_GL_ARB_window_pos (); +static GLboolean _glewInit_GL_ATI_draw_buffers (); +static GLboolean _glewInit_GL_ATI_element_array (); +static GLboolean _glewInit_GL_ATI_envmap_bumpmap (); +static GLboolean _glewInit_GL_ATI_fragment_shader (); +static GLboolean _glewInit_GL_ATI_map_object_buffer (); +static GLboolean _glewInit_GL_ATI_pn_triangles (); +static GLboolean _glewInit_GL_ATI_separate_stencil (); +static GLboolean _glewInit_GL_ATI_vertex_array_object (); +static GLboolean _glewInit_GL_ATI_vertex_attrib_array_object (); +static GLboolean _glewInit_GL_ATI_vertex_streams (); +static GLboolean _glewInit_GL_EXT_base_instance (); +static GLboolean _glewInit_GL_EXT_bindable_uniform (); +static GLboolean _glewInit_GL_EXT_blend_color (); +static GLboolean _glewInit_GL_EXT_blend_equation_separate (); +static GLboolean _glewInit_GL_EXT_blend_func_extended (); +static GLboolean _glewInit_GL_EXT_blend_func_separate (); +static GLboolean _glewInit_GL_EXT_blend_minmax (); +static GLboolean _glewInit_GL_EXT_buffer_storage (); +static GLboolean _glewInit_GL_EXT_clear_texture (); +static GLboolean _glewInit_GL_EXT_color_subtable (); +static GLboolean _glewInit_GL_EXT_compiled_vertex_array (); +static GLboolean _glewInit_GL_EXT_convolution (); +static GLboolean _glewInit_GL_EXT_coordinate_frame (); +static GLboolean _glewInit_GL_EXT_copy_image (); +static GLboolean _glewInit_GL_EXT_copy_texture (); +static GLboolean _glewInit_GL_EXT_cull_vertex (); +static GLboolean _glewInit_GL_EXT_debug_label (); +static GLboolean _glewInit_GL_EXT_debug_marker (); +static GLboolean _glewInit_GL_EXT_depth_bounds_test (); +static GLboolean _glewInit_GL_EXT_direct_state_access (); +static GLboolean _glewInit_GL_EXT_discard_framebuffer (); +static GLboolean _glewInit_GL_EXT_draw_buffers (); +static GLboolean _glewInit_GL_EXT_draw_buffers2 (); +static GLboolean _glewInit_GL_EXT_draw_buffers_indexed (); +static GLboolean _glewInit_GL_EXT_draw_elements_base_vertex (); +static GLboolean _glewInit_GL_EXT_draw_instanced (); +static GLboolean _glewInit_GL_EXT_draw_range_elements (); +static GLboolean _glewInit_GL_EXT_external_buffer (); +static GLboolean _glewInit_GL_EXT_fog_coord (); +static GLboolean _glewInit_GL_EXT_fragment_lighting (); +static GLboolean _glewInit_GL_EXT_framebuffer_blit (); +static GLboolean _glewInit_GL_EXT_framebuffer_multisample (); +static GLboolean _glewInit_GL_EXT_framebuffer_object (); +static GLboolean _glewInit_GL_EXT_geometry_shader4 (); +static GLboolean _glewInit_GL_EXT_gpu_program_parameters (); +static GLboolean _glewInit_GL_EXT_gpu_shader4 (); +static GLboolean _glewInit_GL_EXT_histogram (); +static GLboolean _glewInit_GL_EXT_index_func (); +static GLboolean _glewInit_GL_EXT_index_material (); +static GLboolean _glewInit_GL_EXT_instanced_arrays (); +static GLboolean _glewInit_GL_EXT_light_texture (); +static GLboolean _glewInit_GL_EXT_map_buffer_range (); +static GLboolean _glewInit_GL_EXT_memory_object (); +static GLboolean _glewInit_GL_EXT_memory_object_fd (); +static GLboolean _glewInit_GL_EXT_memory_object_win32 (); +static GLboolean _glewInit_GL_EXT_multi_draw_arrays (); +static GLboolean _glewInit_GL_EXT_multi_draw_indirect (); +static GLboolean _glewInit_GL_EXT_multisample (); +static GLboolean _glewInit_GL_EXT_multisampled_render_to_texture (); +static GLboolean _glewInit_GL_EXT_multiview_draw_buffers (); +static GLboolean _glewInit_GL_EXT_paletted_texture (); +static GLboolean _glewInit_GL_EXT_pixel_transform (); +static GLboolean _glewInit_GL_EXT_point_parameters (); +static GLboolean _glewInit_GL_EXT_polygon_offset (); +static GLboolean _glewInit_GL_EXT_polygon_offset_clamp (); +static GLboolean _glewInit_GL_EXT_provoking_vertex (); +static GLboolean _glewInit_GL_EXT_raster_multisample (); +static GLboolean _glewInit_GL_EXT_scene_marker (); +static GLboolean _glewInit_GL_EXT_secondary_color (); +static GLboolean _glewInit_GL_EXT_semaphore (); +static GLboolean _glewInit_GL_EXT_semaphore_fd (); +static GLboolean _glewInit_GL_EXT_semaphore_win32 (); +static GLboolean _glewInit_GL_EXT_separate_shader_objects (); +static GLboolean _glewInit_GL_EXT_shader_image_load_store (); +static GLboolean _glewInit_GL_EXT_shader_pixel_local_storage2 (); +static GLboolean _glewInit_GL_EXT_sparse_texture (); +static GLboolean _glewInit_GL_EXT_stencil_two_side (); +static GLboolean _glewInit_GL_EXT_subtexture (); +static GLboolean _glewInit_GL_EXT_texture3D (); +static GLboolean _glewInit_GL_EXT_texture_array (); +static GLboolean _glewInit_GL_EXT_texture_buffer_object (); +static GLboolean _glewInit_GL_EXT_texture_integer (); +static GLboolean _glewInit_GL_EXT_texture_object (); +static GLboolean _glewInit_GL_EXT_texture_perturb_normal (); +static GLboolean _glewInit_GL_EXT_texture_storage (); +static GLboolean _glewInit_GL_EXT_texture_view (); +static GLboolean _glewInit_GL_EXT_timer_query (); +static GLboolean _glewInit_GL_EXT_transform_feedback (); +static GLboolean _glewInit_GL_EXT_vertex_array (); +static GLboolean _glewInit_GL_EXT_vertex_array_setXXX (); +static GLboolean _glewInit_GL_EXT_vertex_attrib_64bit (); +static GLboolean _glewInit_GL_EXT_vertex_shader (); +static GLboolean _glewInit_GL_EXT_vertex_weighting (); +static GLboolean _glewInit_GL_EXT_win32_keyed_mutex (); +static GLboolean _glewInit_GL_EXT_window_rectangles (); +static GLboolean _glewInit_GL_EXT_x11_sync_object (); +static GLboolean _glewInit_GL_GREMEDY_frame_terminator (); +static GLboolean _glewInit_GL_GREMEDY_string_marker (); +static GLboolean _glewInit_GL_HP_image_transform (); +static GLboolean _glewInit_GL_IBM_multimode_draw_arrays (); +static GLboolean _glewInit_GL_IBM_vertex_array_lists (); +static GLboolean _glewInit_GL_INTEL_map_texture (); +static GLboolean _glewInit_GL_INTEL_parallel_arrays (); +static GLboolean _glewInit_GL_INTEL_performance_query (); +static GLboolean _glewInit_GL_INTEL_texture_scissor (); +static GLboolean _glewInit_GL_KHR_blend_equation_advanced (); +static GLboolean _glewInit_GL_KHR_debug (); +static GLboolean _glewInit_GL_KHR_parallel_shader_compile (); +static GLboolean _glewInit_GL_KHR_robustness (); +static GLboolean _glewInit_GL_KTX_buffer_region (); +static GLboolean _glewInit_GL_MESA_resize_buffers (); +static GLboolean _glewInit_GL_MESA_window_pos (); +static GLboolean _glewInit_GL_NVX_conditional_render (); +static GLboolean _glewInit_GL_NVX_linked_gpu_multicast (); +static GLboolean _glewInit_GL_NV_3dvision_settings (); +static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect (); +static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect_count (); +static GLboolean _glewInit_GL_NV_bindless_texture (); +static GLboolean _glewInit_GL_NV_blend_equation_advanced (); +static GLboolean _glewInit_GL_NV_clip_space_w_scaling (); +static GLboolean _glewInit_GL_NV_command_list (); +static GLboolean _glewInit_GL_NV_conditional_render (); +static GLboolean _glewInit_GL_NV_conservative_raster (); +static GLboolean _glewInit_GL_NV_conservative_raster_dilate (); +static GLboolean _glewInit_GL_NV_conservative_raster_pre_snap_triangles (); +static GLboolean _glewInit_GL_NV_copy_buffer (); +static GLboolean _glewInit_GL_NV_copy_image (); +static GLboolean _glewInit_GL_NV_depth_buffer_float (); +static GLboolean _glewInit_GL_NV_draw_buffers (); +static GLboolean _glewInit_GL_NV_draw_instanced (); +static GLboolean _glewInit_GL_NV_draw_texture (); +static GLboolean _glewInit_GL_NV_draw_vulkan_image (); +static GLboolean _glewInit_GL_NV_evaluators (); +static GLboolean _glewInit_GL_NV_explicit_multisample (); +static GLboolean _glewInit_GL_NV_fence (); +static GLboolean _glewInit_GL_NV_fragment_coverage_to_color (); +static GLboolean _glewInit_GL_NV_fragment_program (); +static GLboolean _glewInit_GL_NV_framebuffer_blit (); +static GLboolean _glewInit_GL_NV_framebuffer_multisample (); +static GLboolean _glewInit_GL_NV_framebuffer_multisample_coverage (); +static GLboolean _glewInit_GL_NV_geometry_program4 (); +static GLboolean _glewInit_GL_NV_gpu_multicast (); +static GLboolean _glewInit_GL_NV_gpu_program4 (); +static GLboolean _glewInit_GL_NV_gpu_shader5 (); +static GLboolean _glewInit_GL_NV_half_float (); +static GLboolean _glewInit_GL_NV_instanced_arrays (); +static GLboolean _glewInit_GL_NV_internalformat_sample_query (); +static GLboolean _glewInit_GL_NV_non_square_matrices (); +static GLboolean _glewInit_GL_NV_occlusion_query (); +static GLboolean _glewInit_GL_NV_parameter_buffer_object (); +static GLboolean _glewInit_GL_NV_path_rendering (); +static GLboolean _glewInit_GL_NV_pixel_data_range (); +static GLboolean _glewInit_GL_NV_point_sprite (); +static GLboolean _glewInit_GL_NV_polygon_mode (); +static GLboolean _glewInit_GL_NV_present_video (); +static GLboolean _glewInit_GL_NV_primitive_restart (); +static GLboolean _glewInit_GL_NV_register_combiners (); +static GLboolean _glewInit_GL_NV_register_combiners2 (); +static GLboolean _glewInit_GL_NV_sample_locations (); +static GLboolean _glewInit_GL_NV_shader_buffer_load (); +static GLboolean _glewInit_GL_NV_texture_array (); +static GLboolean _glewInit_GL_NV_texture_barrier (); +static GLboolean _glewInit_GL_NV_texture_multisample (); +static GLboolean _glewInit_GL_NV_transform_feedback (); +static GLboolean _glewInit_GL_NV_transform_feedback2 (); +static GLboolean _glewInit_GL_NV_vdpau_interop (); +static GLboolean _glewInit_GL_NV_vertex_array_range (); +static GLboolean _glewInit_GL_NV_vertex_attrib_integer_64bit (); +static GLboolean _glewInit_GL_NV_vertex_buffer_unified_memory (); +static GLboolean _glewInit_GL_NV_vertex_program (); +static GLboolean _glewInit_GL_NV_video_capture (); +static GLboolean _glewInit_GL_NV_viewport_array (); +static GLboolean _glewInit_GL_NV_viewport_swizzle (); +static GLboolean _glewInit_GL_OVR_multiview (); +static GLboolean _glewInit_GL_OVR_multiview_multisampled_render_to_texture (); +static GLboolean _glewInit_GL_QCOM_alpha_test (); +static GLboolean _glewInit_GL_QCOM_driver_control (); +static GLboolean _glewInit_GL_QCOM_extended_get (); +static GLboolean _glewInit_GL_QCOM_extended_get2 (); +static GLboolean _glewInit_GL_QCOM_framebuffer_foveated (); +static GLboolean _glewInit_GL_QCOM_shader_framebuffer_fetch_noncoherent (); +static GLboolean _glewInit_GL_QCOM_tiled_rendering (); +static GLboolean _glewInit_GL_REGAL_ES1_0_compatibility (); +static GLboolean _glewInit_GL_REGAL_ES1_1_compatibility (); +static GLboolean _glewInit_GL_REGAL_error_string (); +static GLboolean _glewInit_GL_REGAL_extension_query (); +static GLboolean _glewInit_GL_REGAL_log (); +static GLboolean _glewInit_GL_REGAL_proc_address (); +static GLboolean _glewInit_GL_SGIS_detail_texture (); +static GLboolean _glewInit_GL_SGIS_fog_function (); +static GLboolean _glewInit_GL_SGIS_multisample (); +static GLboolean _glewInit_GL_SGIS_multitexture (); +static GLboolean _glewInit_GL_SGIS_shared_multisample (); +static GLboolean _glewInit_GL_SGIS_sharpen_texture (); +static GLboolean _glewInit_GL_SGIS_texture4D (); +static GLboolean _glewInit_GL_SGIS_texture_filter4 (); +static GLboolean _glewInit_GL_SGIX_async (); +static GLboolean _glewInit_GL_SGIX_datapipe (); +static GLboolean _glewInit_GL_SGIX_flush_raster (); +static GLboolean _glewInit_GL_SGIX_fog_layers (); +static GLboolean _glewInit_GL_SGIX_fog_texture (); +static GLboolean _glewInit_GL_SGIX_fragment_specular_lighting (); +static GLboolean _glewInit_GL_SGIX_framezoom (); +static GLboolean _glewInit_GL_SGIX_igloo_interface (); +static GLboolean _glewInit_GL_SGIX_mpeg1 (); +static GLboolean _glewInit_GL_SGIX_nonlinear_lighting_pervertex (); +static GLboolean _glewInit_GL_SGIX_pixel_texture (); +static GLboolean _glewInit_GL_SGIX_polynomial_ffd (); +static GLboolean _glewInit_GL_SGIX_quad_mesh (); +static GLboolean _glewInit_GL_SGIX_reference_plane (); +static GLboolean _glewInit_GL_SGIX_sprite (); +static GLboolean _glewInit_GL_SGIX_tag_sample_buffer (); +static GLboolean _glewInit_GL_SGIX_vector_ops (); +static GLboolean _glewInit_GL_SGIX_vertex_array_object (); +static GLboolean _glewInit_GL_SGI_color_table (); +static GLboolean _glewInit_GL_SGI_fft (); +static GLboolean _glewInit_GL_SUNX_constant_data (); +static GLboolean _glewInit_GL_SUN_global_alpha (); +static GLboolean _glewInit_GL_SUN_read_video_pixels (); +static GLboolean _glewInit_GL_SUN_triangle_list (); +static GLboolean _glewInit_GL_SUN_vertex (); +static GLboolean _glewInit_GL_WIN_swap_hint (); + +#ifdef GL_VERSION_1_2 + +static GLboolean _glewInit_GL_VERSION_1_2 () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glCopyTexSubImage3D")) == NULL) || r; + r = ((glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)glewGetProcAddress((const GLubyte*)"glDrawRangeElements")) == NULL) || r; + r = ((glTexImage3D = (PFNGLTEXIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glTexImage3D")) == NULL) || r; + r = ((glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glTexSubImage3D")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_1_2 */ + +#ifdef GL_VERSION_1_3 + +static GLboolean _glewInit_GL_VERSION_1_3 () +{ + GLboolean r = GL_FALSE; + + r = ((glActiveTexture = (PFNGLACTIVETEXTUREPROC)glewGetProcAddress((const GLubyte*)"glActiveTexture")) == NULL) || r; + r = ((glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)glewGetProcAddress((const GLubyte*)"glClientActiveTexture")) == NULL) || r; + r = ((glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexImage1D")) == NULL) || r; + r = ((glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexImage2D")) == NULL) || r; + r = ((glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexImage3D")) == NULL) || r; + r = ((glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexSubImage1D")) == NULL) || r; + r = ((glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexSubImage2D")) == NULL) || r; + r = ((glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexSubImage3D")) == NULL) || r; + r = ((glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedTexImage")) == NULL) || r; + r = ((glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC)glewGetProcAddress((const GLubyte*)"glLoadTransposeMatrixd")) == NULL) || r; + r = ((glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC)glewGetProcAddress((const GLubyte*)"glLoadTransposeMatrixf")) == NULL) || r; + r = ((glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC)glewGetProcAddress((const GLubyte*)"glMultTransposeMatrixd")) == NULL) || r; + r = ((glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)glewGetProcAddress((const GLubyte*)"glMultTransposeMatrixf")) == NULL) || r; + r = ((glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1d")) == NULL) || r; + r = ((glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1dv")) == NULL) || r; + r = ((glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1f")) == NULL) || r; + r = ((glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1fv")) == NULL) || r; + r = ((glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1i")) == NULL) || r; + r = ((glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1iv")) == NULL) || r; + r = ((glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1s")) == NULL) || r; + r = ((glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1sv")) == NULL) || r; + r = ((glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2d")) == NULL) || r; + r = ((glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2dv")) == NULL) || r; + r = ((glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2f")) == NULL) || r; + r = ((glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2fv")) == NULL) || r; + r = ((glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2i")) == NULL) || r; + r = ((glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2iv")) == NULL) || r; + r = ((glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2s")) == NULL) || r; + r = ((glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2sv")) == NULL) || r; + r = ((glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3d")) == NULL) || r; + r = ((glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3dv")) == NULL) || r; + r = ((glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3f")) == NULL) || r; + r = ((glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3fv")) == NULL) || r; + r = ((glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3i")) == NULL) || r; + r = ((glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3iv")) == NULL) || r; + r = ((glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3s")) == NULL) || r; + r = ((glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3sv")) == NULL) || r; + r = ((glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4d")) == NULL) || r; + r = ((glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4dv")) == NULL) || r; + r = ((glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4f")) == NULL) || r; + r = ((glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4fv")) == NULL) || r; + r = ((glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4i")) == NULL) || r; + r = ((glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4iv")) == NULL) || r; + r = ((glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4s")) == NULL) || r; + r = ((glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4sv")) == NULL) || r; + r = ((glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)glewGetProcAddress((const GLubyte*)"glSampleCoverage")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_1_3 */ + +#ifdef GL_VERSION_1_4 + +static GLboolean _glewInit_GL_VERSION_1_4 () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendColor = (PFNGLBLENDCOLORPROC)glewGetProcAddress((const GLubyte*)"glBlendColor")) == NULL) || r; + r = ((glBlendEquation = (PFNGLBLENDEQUATIONPROC)glewGetProcAddress((const GLubyte*)"glBlendEquation")) == NULL) || r; + r = ((glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)glewGetProcAddress((const GLubyte*)"glBlendFuncSeparate")) == NULL) || r; + r = ((glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC)glewGetProcAddress((const GLubyte*)"glFogCoordPointer")) == NULL) || r; + r = ((glFogCoordd = (PFNGLFOGCOORDDPROC)glewGetProcAddress((const GLubyte*)"glFogCoordd")) == NULL) || r; + r = ((glFogCoorddv = (PFNGLFOGCOORDDVPROC)glewGetProcAddress((const GLubyte*)"glFogCoorddv")) == NULL) || r; + r = ((glFogCoordf = (PFNGLFOGCOORDFPROC)glewGetProcAddress((const GLubyte*)"glFogCoordf")) == NULL) || r; + r = ((glFogCoordfv = (PFNGLFOGCOORDFVPROC)glewGetProcAddress((const GLubyte*)"glFogCoordfv")) == NULL) || r; + r = ((glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArrays")) == NULL) || r; + r = ((glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElements")) == NULL) || r; + r = ((glPointParameterf = (PFNGLPOINTPARAMETERFPROC)glewGetProcAddress((const GLubyte*)"glPointParameterf")) == NULL) || r; + r = ((glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glPointParameterfv")) == NULL) || r; + r = ((glPointParameteri = (PFNGLPOINTPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glPointParameteri")) == NULL) || r; + r = ((glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glPointParameteriv")) == NULL) || r; + r = ((glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3b")) == NULL) || r; + r = ((glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3bv")) == NULL) || r; + r = ((glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3d")) == NULL) || r; + r = ((glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3dv")) == NULL) || r; + r = ((glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3f")) == NULL) || r; + r = ((glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3fv")) == NULL) || r; + r = ((glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3i")) == NULL) || r; + r = ((glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3iv")) == NULL) || r; + r = ((glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3s")) == NULL) || r; + r = ((glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3sv")) == NULL) || r; + r = ((glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3ub")) == NULL) || r; + r = ((glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3ubv")) == NULL) || r; + r = ((glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3ui")) == NULL) || r; + r = ((glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3uiv")) == NULL) || r; + r = ((glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3us")) == NULL) || r; + r = ((glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3usv")) == NULL) || r; + r = ((glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColorPointer")) == NULL) || r; + r = ((glWindowPos2d = (PFNGLWINDOWPOS2DPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2d")) == NULL) || r; + r = ((glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2dv")) == NULL) || r; + r = ((glWindowPos2f = (PFNGLWINDOWPOS2FPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2f")) == NULL) || r; + r = ((glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2fv")) == NULL) || r; + r = ((glWindowPos2i = (PFNGLWINDOWPOS2IPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2i")) == NULL) || r; + r = ((glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2iv")) == NULL) || r; + r = ((glWindowPos2s = (PFNGLWINDOWPOS2SPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2s")) == NULL) || r; + r = ((glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2sv")) == NULL) || r; + r = ((glWindowPos3d = (PFNGLWINDOWPOS3DPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3d")) == NULL) || r; + r = ((glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3dv")) == NULL) || r; + r = ((glWindowPos3f = (PFNGLWINDOWPOS3FPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3f")) == NULL) || r; + r = ((glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3fv")) == NULL) || r; + r = ((glWindowPos3i = (PFNGLWINDOWPOS3IPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3i")) == NULL) || r; + r = ((glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3iv")) == NULL) || r; + r = ((glWindowPos3s = (PFNGLWINDOWPOS3SPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3s")) == NULL) || r; + r = ((glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3sv")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_1_4 */ + +#ifdef GL_VERSION_1_5 + +static GLboolean _glewInit_GL_VERSION_1_5 () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginQuery = (PFNGLBEGINQUERYPROC)glewGetProcAddress((const GLubyte*)"glBeginQuery")) == NULL) || r; + r = ((glBindBuffer = (PFNGLBINDBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBindBuffer")) == NULL) || r; + r = ((glBufferData = (PFNGLBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glBufferData")) == NULL) || r; + r = ((glBufferSubData = (PFNGLBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glBufferSubData")) == NULL) || r; + r = ((glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glDeleteBuffers")) == NULL) || r; + r = ((glDeleteQueries = (PFNGLDELETEQUERIESPROC)glewGetProcAddress((const GLubyte*)"glDeleteQueries")) == NULL) || r; + r = ((glEndQuery = (PFNGLENDQUERYPROC)glewGetProcAddress((const GLubyte*)"glEndQuery")) == NULL) || r; + r = ((glGenBuffers = (PFNGLGENBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glGenBuffers")) == NULL) || r; + r = ((glGenQueries = (PFNGLGENQUERIESPROC)glewGetProcAddress((const GLubyte*)"glGenQueries")) == NULL) || r; + r = ((glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetBufferParameteriv")) == NULL) || r; + r = ((glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)glewGetProcAddress((const GLubyte*)"glGetBufferPointerv")) == NULL) || r; + r = ((glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glGetBufferSubData")) == NULL) || r; + r = ((glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectiv")) == NULL) || r; + r = ((glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectuiv")) == NULL) || r; + r = ((glGetQueryiv = (PFNGLGETQUERYIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryiv")) == NULL) || r; + r = ((glIsBuffer = (PFNGLISBUFFERPROC)glewGetProcAddress((const GLubyte*)"glIsBuffer")) == NULL) || r; + r = ((glIsQuery = (PFNGLISQUERYPROC)glewGetProcAddress((const GLubyte*)"glIsQuery")) == NULL) || r; + r = ((glMapBuffer = (PFNGLMAPBUFFERPROC)glewGetProcAddress((const GLubyte*)"glMapBuffer")) == NULL) || r; + r = ((glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)glewGetProcAddress((const GLubyte*)"glUnmapBuffer")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_1_5 */ + +#ifdef GL_VERSION_2_0 + +static GLboolean _glewInit_GL_VERSION_2_0 () +{ + GLboolean r = GL_FALSE; + + r = ((glAttachShader = (PFNGLATTACHSHADERPROC)glewGetProcAddress((const GLubyte*)"glAttachShader")) == NULL) || r; + r = ((glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)glewGetProcAddress((const GLubyte*)"glBindAttribLocation")) == NULL) || r; + r = ((glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationSeparate")) == NULL) || r; + r = ((glCompileShader = (PFNGLCOMPILESHADERPROC)glewGetProcAddress((const GLubyte*)"glCompileShader")) == NULL) || r; + r = ((glCreateProgram = (PFNGLCREATEPROGRAMPROC)glewGetProcAddress((const GLubyte*)"glCreateProgram")) == NULL) || r; + r = ((glCreateShader = (PFNGLCREATESHADERPROC)glewGetProcAddress((const GLubyte*)"glCreateShader")) == NULL) || r; + r = ((glDeleteProgram = (PFNGLDELETEPROGRAMPROC)glewGetProcAddress((const GLubyte*)"glDeleteProgram")) == NULL) || r; + r = ((glDeleteShader = (PFNGLDELETESHADERPROC)glewGetProcAddress((const GLubyte*)"glDeleteShader")) == NULL) || r; + r = ((glDetachShader = (PFNGLDETACHSHADERPROC)glewGetProcAddress((const GLubyte*)"glDetachShader")) == NULL) || r; + r = ((glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)glewGetProcAddress((const GLubyte*)"glDisableVertexAttribArray")) == NULL) || r; + r = ((glDrawBuffers = (PFNGLDRAWBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glDrawBuffers")) == NULL) || r; + r = ((glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)glewGetProcAddress((const GLubyte*)"glEnableVertexAttribArray")) == NULL) || r; + r = ((glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)glewGetProcAddress((const GLubyte*)"glGetActiveAttrib")) == NULL) || r; + r = ((glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)glewGetProcAddress((const GLubyte*)"glGetActiveUniform")) == NULL) || r; + r = ((glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)glewGetProcAddress((const GLubyte*)"glGetAttachedShaders")) == NULL) || r; + r = ((glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)glewGetProcAddress((const GLubyte*)"glGetAttribLocation")) == NULL) || r; + r = ((glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)glewGetProcAddress((const GLubyte*)"glGetProgramInfoLog")) == NULL) || r; + r = ((glGetProgramiv = (PFNGLGETPROGRAMIVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramiv")) == NULL) || r; + r = ((glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)glewGetProcAddress((const GLubyte*)"glGetShaderInfoLog")) == NULL) || r; + r = ((glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)glewGetProcAddress((const GLubyte*)"glGetShaderSource")) == NULL) || r; + r = ((glGetShaderiv = (PFNGLGETSHADERIVPROC)glewGetProcAddress((const GLubyte*)"glGetShaderiv")) == NULL) || r; + r = ((glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)glewGetProcAddress((const GLubyte*)"glGetUniformLocation")) == NULL) || r; + r = ((glGetUniformfv = (PFNGLGETUNIFORMFVPROC)glewGetProcAddress((const GLubyte*)"glGetUniformfv")) == NULL) || r; + r = ((glGetUniformiv = (PFNGLGETUNIFORMIVPROC)glewGetProcAddress((const GLubyte*)"glGetUniformiv")) == NULL) || r; + r = ((glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribPointerv")) == NULL) || r; + r = ((glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribdv")) == NULL) || r; + r = ((glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribfv")) == NULL) || r; + r = ((glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribiv")) == NULL) || r; + r = ((glIsProgram = (PFNGLISPROGRAMPROC)glewGetProcAddress((const GLubyte*)"glIsProgram")) == NULL) || r; + r = ((glIsShader = (PFNGLISSHADERPROC)glewGetProcAddress((const GLubyte*)"glIsShader")) == NULL) || r; + r = ((glLinkProgram = (PFNGLLINKPROGRAMPROC)glewGetProcAddress((const GLubyte*)"glLinkProgram")) == NULL) || r; + r = ((glShaderSource = (PFNGLSHADERSOURCEPROC)glewGetProcAddress((const GLubyte*)"glShaderSource")) == NULL) || r; + r = ((glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)glewGetProcAddress((const GLubyte*)"glStencilFuncSeparate")) == NULL) || r; + r = ((glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)glewGetProcAddress((const GLubyte*)"glStencilMaskSeparate")) == NULL) || r; + r = ((glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)glewGetProcAddress((const GLubyte*)"glStencilOpSeparate")) == NULL) || r; + r = ((glUniform1f = (PFNGLUNIFORM1FPROC)glewGetProcAddress((const GLubyte*)"glUniform1f")) == NULL) || r; + r = ((glUniform1fv = (PFNGLUNIFORM1FVPROC)glewGetProcAddress((const GLubyte*)"glUniform1fv")) == NULL) || r; + r = ((glUniform1i = (PFNGLUNIFORM1IPROC)glewGetProcAddress((const GLubyte*)"glUniform1i")) == NULL) || r; + r = ((glUniform1iv = (PFNGLUNIFORM1IVPROC)glewGetProcAddress((const GLubyte*)"glUniform1iv")) == NULL) || r; + r = ((glUniform2f = (PFNGLUNIFORM2FPROC)glewGetProcAddress((const GLubyte*)"glUniform2f")) == NULL) || r; + r = ((glUniform2fv = (PFNGLUNIFORM2FVPROC)glewGetProcAddress((const GLubyte*)"glUniform2fv")) == NULL) || r; + r = ((glUniform2i = (PFNGLUNIFORM2IPROC)glewGetProcAddress((const GLubyte*)"glUniform2i")) == NULL) || r; + r = ((glUniform2iv = (PFNGLUNIFORM2IVPROC)glewGetProcAddress((const GLubyte*)"glUniform2iv")) == NULL) || r; + r = ((glUniform3f = (PFNGLUNIFORM3FPROC)glewGetProcAddress((const GLubyte*)"glUniform3f")) == NULL) || r; + r = ((glUniform3fv = (PFNGLUNIFORM3FVPROC)glewGetProcAddress((const GLubyte*)"glUniform3fv")) == NULL) || r; + r = ((glUniform3i = (PFNGLUNIFORM3IPROC)glewGetProcAddress((const GLubyte*)"glUniform3i")) == NULL) || r; + r = ((glUniform3iv = (PFNGLUNIFORM3IVPROC)glewGetProcAddress((const GLubyte*)"glUniform3iv")) == NULL) || r; + r = ((glUniform4f = (PFNGLUNIFORM4FPROC)glewGetProcAddress((const GLubyte*)"glUniform4f")) == NULL) || r; + r = ((glUniform4fv = (PFNGLUNIFORM4FVPROC)glewGetProcAddress((const GLubyte*)"glUniform4fv")) == NULL) || r; + r = ((glUniform4i = (PFNGLUNIFORM4IPROC)glewGetProcAddress((const GLubyte*)"glUniform4i")) == NULL) || r; + r = ((glUniform4iv = (PFNGLUNIFORM4IVPROC)glewGetProcAddress((const GLubyte*)"glUniform4iv")) == NULL) || r; + r = ((glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2fv")) == NULL) || r; + r = ((glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3fv")) == NULL) || r; + r = ((glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4fv")) == NULL) || r; + r = ((glUseProgram = (PFNGLUSEPROGRAMPROC)glewGetProcAddress((const GLubyte*)"glUseProgram")) == NULL) || r; + r = ((glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)glewGetProcAddress((const GLubyte*)"glValidateProgram")) == NULL) || r; + r = ((glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1d")) == NULL) || r; + r = ((glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1dv")) == NULL) || r; + r = ((glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1f")) == NULL) || r; + r = ((glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1fv")) == NULL) || r; + r = ((glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1s")) == NULL) || r; + r = ((glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1sv")) == NULL) || r; + r = ((glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2d")) == NULL) || r; + r = ((glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2dv")) == NULL) || r; + r = ((glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2f")) == NULL) || r; + r = ((glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2fv")) == NULL) || r; + r = ((glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2s")) == NULL) || r; + r = ((glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2sv")) == NULL) || r; + r = ((glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3d")) == NULL) || r; + r = ((glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3dv")) == NULL) || r; + r = ((glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3f")) == NULL) || r; + r = ((glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3fv")) == NULL) || r; + r = ((glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3s")) == NULL) || r; + r = ((glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3sv")) == NULL) || r; + r = ((glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4Nbv")) == NULL) || r; + r = ((glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4Niv")) == NULL) || r; + r = ((glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4Nsv")) == NULL) || r; + r = ((glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4Nub")) == NULL) || r; + r = ((glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4Nubv")) == NULL) || r; + r = ((glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4Nuiv")) == NULL) || r; + r = ((glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4Nusv")) == NULL) || r; + r = ((glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4bv")) == NULL) || r; + r = ((glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4d")) == NULL) || r; + r = ((glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4dv")) == NULL) || r; + r = ((glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4f")) == NULL) || r; + r = ((glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4fv")) == NULL) || r; + r = ((glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4iv")) == NULL) || r; + r = ((glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4s")) == NULL) || r; + r = ((glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4sv")) == NULL) || r; + r = ((glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4ubv")) == NULL) || r; + r = ((glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4uiv")) == NULL) || r; + r = ((glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4usv")) == NULL) || r; + r = ((glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribPointer")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_2_0 */ + +#ifdef GL_VERSION_2_1 + +static GLboolean _glewInit_GL_VERSION_2_1 () +{ + GLboolean r = GL_FALSE; + + r = ((glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2x3fv")) == NULL) || r; + r = ((glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2x4fv")) == NULL) || r; + r = ((glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3x2fv")) == NULL) || r; + r = ((glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3x4fv")) == NULL) || r; + r = ((glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4x2fv")) == NULL) || r; + r = ((glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4x3fv")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_2_1 */ + +#ifdef GL_VERSION_3_0 + +static GLboolean _glewInit_GL_VERSION_3_0 () +{ + GLboolean r = GL_FALSE; + + r = _glewInit_GL_ARB_framebuffer_object() || r; + r = _glewInit_GL_ARB_map_buffer_range() || r; + r = _glewInit_GL_ARB_uniform_buffer_object() || r; + r = _glewInit_GL_ARB_vertex_array_object() || r; + + r = ((glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)glewGetProcAddress((const GLubyte*)"glBeginConditionalRender")) == NULL) || r; + r = ((glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)glewGetProcAddress((const GLubyte*)"glBeginTransformFeedback")) == NULL) || r; + r = ((glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)glewGetProcAddress((const GLubyte*)"glBindFragDataLocation")) == NULL) || r; + r = ((glClampColor = (PFNGLCLAMPCOLORPROC)glewGetProcAddress((const GLubyte*)"glClampColor")) == NULL) || r; + r = ((glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)glewGetProcAddress((const GLubyte*)"glClearBufferfi")) == NULL) || r; + r = ((glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)glewGetProcAddress((const GLubyte*)"glClearBufferfv")) == NULL) || r; + r = ((glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)glewGetProcAddress((const GLubyte*)"glClearBufferiv")) == NULL) || r; + r = ((glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)glewGetProcAddress((const GLubyte*)"glClearBufferuiv")) == NULL) || r; + r = ((glColorMaski = (PFNGLCOLORMASKIPROC)glewGetProcAddress((const GLubyte*)"glColorMaski")) == NULL) || r; + r = ((glDisablei = (PFNGLDISABLEIPROC)glewGetProcAddress((const GLubyte*)"glDisablei")) == NULL) || r; + r = ((glEnablei = (PFNGLENABLEIPROC)glewGetProcAddress((const GLubyte*)"glEnablei")) == NULL) || r; + r = ((glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)glewGetProcAddress((const GLubyte*)"glEndConditionalRender")) == NULL) || r; + r = ((glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)glewGetProcAddress((const GLubyte*)"glEndTransformFeedback")) == NULL) || r; + r = ((glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)glewGetProcAddress((const GLubyte*)"glGetBooleani_v")) == NULL) || r; + r = ((glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)glewGetProcAddress((const GLubyte*)"glGetFragDataLocation")) == NULL) || r; + r = ((glGetStringi = (PFNGLGETSTRINGIPROC)glewGetProcAddress((const GLubyte*)"glGetStringi")) == NULL) || r; + r = ((glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glGetTexParameterIiv")) == NULL) || r; + r = ((glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glGetTexParameterIuiv")) == NULL) || r; + r = ((glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbackVarying")) == NULL) || r; + r = ((glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)glewGetProcAddress((const GLubyte*)"glGetUniformuiv")) == NULL) || r; + r = ((glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribIiv")) == NULL) || r; + r = ((glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribIuiv")) == NULL) || r; + r = ((glIsEnabledi = (PFNGLISENABLEDIPROC)glewGetProcAddress((const GLubyte*)"glIsEnabledi")) == NULL) || r; + r = ((glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glTexParameterIiv")) == NULL) || r; + r = ((glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glTexParameterIuiv")) == NULL) || r; + r = ((glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackVaryings")) == NULL) || r; + r = ((glUniform1ui = (PFNGLUNIFORM1UIPROC)glewGetProcAddress((const GLubyte*)"glUniform1ui")) == NULL) || r; + r = ((glUniform1uiv = (PFNGLUNIFORM1UIVPROC)glewGetProcAddress((const GLubyte*)"glUniform1uiv")) == NULL) || r; + r = ((glUniform2ui = (PFNGLUNIFORM2UIPROC)glewGetProcAddress((const GLubyte*)"glUniform2ui")) == NULL) || r; + r = ((glUniform2uiv = (PFNGLUNIFORM2UIVPROC)glewGetProcAddress((const GLubyte*)"glUniform2uiv")) == NULL) || r; + r = ((glUniform3ui = (PFNGLUNIFORM3UIPROC)glewGetProcAddress((const GLubyte*)"glUniform3ui")) == NULL) || r; + r = ((glUniform3uiv = (PFNGLUNIFORM3UIVPROC)glewGetProcAddress((const GLubyte*)"glUniform3uiv")) == NULL) || r; + r = ((glUniform4ui = (PFNGLUNIFORM4UIPROC)glewGetProcAddress((const GLubyte*)"glUniform4ui")) == NULL) || r; + r = ((glUniform4uiv = (PFNGLUNIFORM4UIVPROC)glewGetProcAddress((const GLubyte*)"glUniform4uiv")) == NULL) || r; + r = ((glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1i")) == NULL) || r; + r = ((glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1iv")) == NULL) || r; + r = ((glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1ui")) == NULL) || r; + r = ((glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1uiv")) == NULL) || r; + r = ((glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2i")) == NULL) || r; + r = ((glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2iv")) == NULL) || r; + r = ((glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2ui")) == NULL) || r; + r = ((glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2uiv")) == NULL) || r; + r = ((glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3i")) == NULL) || r; + r = ((glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3iv")) == NULL) || r; + r = ((glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3ui")) == NULL) || r; + r = ((glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3uiv")) == NULL) || r; + r = ((glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4bv")) == NULL) || r; + r = ((glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4i")) == NULL) || r; + r = ((glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4iv")) == NULL) || r; + r = ((glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4sv")) == NULL) || r; + r = ((glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4ubv")) == NULL) || r; + r = ((glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4ui")) == NULL) || r; + r = ((glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4uiv")) == NULL) || r; + r = ((glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4usv")) == NULL) || r; + r = ((glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribIPointer")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_3_0 */ + +#ifdef GL_VERSION_3_1 + +static GLboolean _glewInit_GL_VERSION_3_1 () +{ + GLboolean r = GL_FALSE; + + r = _glewInit_GL_ARB_copy_buffer() || r; + + r = ((glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstanced")) == NULL) || r; + r = ((glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstanced")) == NULL) || r; + r = ((glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)glewGetProcAddress((const GLubyte*)"glPrimitiveRestartIndex")) == NULL) || r; + r = ((glTexBuffer = (PFNGLTEXBUFFERPROC)glewGetProcAddress((const GLubyte*)"glTexBuffer")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_3_1 */ + +#ifdef GL_VERSION_3_2 + +static GLboolean _glewInit_GL_VERSION_3_2 () +{ + GLboolean r = GL_FALSE; + + r = _glewInit_GL_ARB_draw_elements_base_vertex() || r; + r = _glewInit_GL_ARB_provoking_vertex() || r; + r = _glewInit_GL_ARB_sync() || r; + r = _glewInit_GL_ARB_texture_multisample() || r; + + r = ((glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture")) == NULL) || r; + r = ((glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)glewGetProcAddress((const GLubyte*)"glGetBufferParameteri64v")) == NULL) || r; + r = ((glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)glewGetProcAddress((const GLubyte*)"glGetInteger64i_v")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_3_2 */ + +#ifdef GL_VERSION_3_3 + +static GLboolean _glewInit_GL_VERSION_3_3 () +{ + GLboolean r = GL_FALSE; + + r = ((glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribDivisor")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_3_3 */ + +#ifdef GL_VERSION_4_0 + +static GLboolean _glewInit_GL_VERSION_4_0 () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationSeparatei")) == NULL) || r; + r = ((glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationi")) == NULL) || r; + r = ((glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)glewGetProcAddress((const GLubyte*)"glBlendFuncSeparatei")) == NULL) || r; + r = ((glBlendFunci = (PFNGLBLENDFUNCIPROC)glewGetProcAddress((const GLubyte*)"glBlendFunci")) == NULL) || r; + r = ((glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)glewGetProcAddress((const GLubyte*)"glMinSampleShading")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_4_0 */ + +#ifdef GL_VERSION_4_5 + +static GLboolean _glewInit_GL_VERSION_4_5 () +{ + GLboolean r = GL_FALSE; + + r = ((glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC)glewGetProcAddress((const GLubyte*)"glGetGraphicsResetStatus")) == NULL) || r; + r = ((glGetnCompressedTexImage = (PFNGLGETNCOMPRESSEDTEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetnCompressedTexImage")) == NULL) || r; + r = ((glGetnTexImage = (PFNGLGETNTEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetnTexImage")) == NULL) || r; + r = ((glGetnUniformdv = (PFNGLGETNUNIFORMDVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformdv")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_4_5 */ + +#ifdef GL_VERSION_4_6 + +static GLboolean _glewInit_GL_VERSION_4_6 () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectCount = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectCount")) == NULL) || r; + r = ((glMultiDrawElementsIndirectCount = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectCount")) == NULL) || r; + r = ((glSpecializeShader = (PFNGLSPECIALIZESHADERPROC)glewGetProcAddress((const GLubyte*)"glSpecializeShader")) == NULL) || r; + + return r; +} + +#endif /* GL_VERSION_4_6 */ + +#ifdef GL_3DFX_tbuffer + +static GLboolean _glewInit_GL_3DFX_tbuffer () +{ + GLboolean r = GL_FALSE; + + r = ((glTbufferMask3DFX = (PFNGLTBUFFERMASK3DFXPROC)glewGetProcAddress((const GLubyte*)"glTbufferMask3DFX")) == NULL) || r; + + return r; +} + +#endif /* GL_3DFX_tbuffer */ + +#ifdef GL_AMD_debug_output + +static GLboolean _glewInit_GL_AMD_debug_output () +{ + GLboolean r = GL_FALSE; + + r = ((glDebugMessageCallbackAMD = (PFNGLDEBUGMESSAGECALLBACKAMDPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageCallbackAMD")) == NULL) || r; + r = ((glDebugMessageEnableAMD = (PFNGLDEBUGMESSAGEENABLEAMDPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageEnableAMD")) == NULL) || r; + r = ((glDebugMessageInsertAMD = (PFNGLDEBUGMESSAGEINSERTAMDPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageInsertAMD")) == NULL) || r; + r = ((glGetDebugMessageLogAMD = (PFNGLGETDEBUGMESSAGELOGAMDPROC)glewGetProcAddress((const GLubyte*)"glGetDebugMessageLogAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_debug_output */ + +#ifdef GL_AMD_draw_buffers_blend + +static GLboolean _glewInit_GL_AMD_draw_buffers_blend () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendEquationIndexedAMD = (PFNGLBLENDEQUATIONINDEXEDAMDPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationIndexedAMD")) == NULL) || r; + r = ((glBlendEquationSeparateIndexedAMD = (PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationSeparateIndexedAMD")) == NULL) || r; + r = ((glBlendFuncIndexedAMD = (PFNGLBLENDFUNCINDEXEDAMDPROC)glewGetProcAddress((const GLubyte*)"glBlendFuncIndexedAMD")) == NULL) || r; + r = ((glBlendFuncSeparateIndexedAMD = (PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC)glewGetProcAddress((const GLubyte*)"glBlendFuncSeparateIndexedAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_draw_buffers_blend */ + +#ifdef GL_AMD_framebuffer_sample_positions + +static GLboolean _glewInit_GL_AMD_framebuffer_sample_positions () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferSamplePositionsfvAMD = (PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC)glewGetProcAddress((const GLubyte*)"glFramebufferSamplePositionsfvAMD")) == NULL) || r; + r = ((glGetFramebufferParameterfvAMD = (PFNGLGETFRAMEBUFFERPARAMETERFVAMDPROC)glewGetProcAddress((const GLubyte*)"glGetFramebufferParameterfvAMD")) == NULL) || r; + r = ((glGetNamedFramebufferParameterfvAMD = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERFVAMDPROC)glewGetProcAddress((const GLubyte*)"glGetNamedFramebufferParameterfvAMD")) == NULL) || r; + r = ((glNamedFramebufferSamplePositionsfvAMD = (PFNGLNAMEDFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferSamplePositionsfvAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_framebuffer_sample_positions */ + +#ifdef GL_AMD_interleaved_elements + +static GLboolean _glewInit_GL_AMD_interleaved_elements () +{ + GLboolean r = GL_FALSE; + + r = ((glVertexAttribParameteriAMD = (PFNGLVERTEXATTRIBPARAMETERIAMDPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribParameteriAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_interleaved_elements */ + +#ifdef GL_AMD_multi_draw_indirect + +static GLboolean _glewInit_GL_AMD_multi_draw_indirect () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectAMD = (PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectAMD")) == NULL) || r; + r = ((glMultiDrawElementsIndirectAMD = (PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_multi_draw_indirect */ + +#ifdef GL_AMD_name_gen_delete + +static GLboolean _glewInit_GL_AMD_name_gen_delete () +{ + GLboolean r = GL_FALSE; + + r = ((glDeleteNamesAMD = (PFNGLDELETENAMESAMDPROC)glewGetProcAddress((const GLubyte*)"glDeleteNamesAMD")) == NULL) || r; + r = ((glGenNamesAMD = (PFNGLGENNAMESAMDPROC)glewGetProcAddress((const GLubyte*)"glGenNamesAMD")) == NULL) || r; + r = ((glIsNameAMD = (PFNGLISNAMEAMDPROC)glewGetProcAddress((const GLubyte*)"glIsNameAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_name_gen_delete */ + +#ifdef GL_AMD_occlusion_query_event + +static GLboolean _glewInit_GL_AMD_occlusion_query_event () +{ + GLboolean r = GL_FALSE; + + r = ((glQueryObjectParameteruiAMD = (PFNGLQUERYOBJECTPARAMETERUIAMDPROC)glewGetProcAddress((const GLubyte*)"glQueryObjectParameteruiAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_occlusion_query_event */ + +#ifdef GL_AMD_performance_monitor + +static GLboolean _glewInit_GL_AMD_performance_monitor () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginPerfMonitorAMD = (PFNGLBEGINPERFMONITORAMDPROC)glewGetProcAddress((const GLubyte*)"glBeginPerfMonitorAMD")) == NULL) || r; + r = ((glDeletePerfMonitorsAMD = (PFNGLDELETEPERFMONITORSAMDPROC)glewGetProcAddress((const GLubyte*)"glDeletePerfMonitorsAMD")) == NULL) || r; + r = ((glEndPerfMonitorAMD = (PFNGLENDPERFMONITORAMDPROC)glewGetProcAddress((const GLubyte*)"glEndPerfMonitorAMD")) == NULL) || r; + r = ((glGenPerfMonitorsAMD = (PFNGLGENPERFMONITORSAMDPROC)glewGetProcAddress((const GLubyte*)"glGenPerfMonitorsAMD")) == NULL) || r; + r = ((glGetPerfMonitorCounterDataAMD = (PFNGLGETPERFMONITORCOUNTERDATAAMDPROC)glewGetProcAddress((const GLubyte*)"glGetPerfMonitorCounterDataAMD")) == NULL) || r; + r = ((glGetPerfMonitorCounterInfoAMD = (PFNGLGETPERFMONITORCOUNTERINFOAMDPROC)glewGetProcAddress((const GLubyte*)"glGetPerfMonitorCounterInfoAMD")) == NULL) || r; + r = ((glGetPerfMonitorCounterStringAMD = (PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC)glewGetProcAddress((const GLubyte*)"glGetPerfMonitorCounterStringAMD")) == NULL) || r; + r = ((glGetPerfMonitorCountersAMD = (PFNGLGETPERFMONITORCOUNTERSAMDPROC)glewGetProcAddress((const GLubyte*)"glGetPerfMonitorCountersAMD")) == NULL) || r; + r = ((glGetPerfMonitorGroupStringAMD = (PFNGLGETPERFMONITORGROUPSTRINGAMDPROC)glewGetProcAddress((const GLubyte*)"glGetPerfMonitorGroupStringAMD")) == NULL) || r; + r = ((glGetPerfMonitorGroupsAMD = (PFNGLGETPERFMONITORGROUPSAMDPROC)glewGetProcAddress((const GLubyte*)"glGetPerfMonitorGroupsAMD")) == NULL) || r; + r = ((glSelectPerfMonitorCountersAMD = (PFNGLSELECTPERFMONITORCOUNTERSAMDPROC)glewGetProcAddress((const GLubyte*)"glSelectPerfMonitorCountersAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_performance_monitor */ + +#ifdef GL_AMD_sample_positions + +static GLboolean _glewInit_GL_AMD_sample_positions () +{ + GLboolean r = GL_FALSE; + + r = ((glSetMultisamplefvAMD = (PFNGLSETMULTISAMPLEFVAMDPROC)glewGetProcAddress((const GLubyte*)"glSetMultisamplefvAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_sample_positions */ + +#ifdef GL_AMD_sparse_texture + +static GLboolean _glewInit_GL_AMD_sparse_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glTexStorageSparseAMD = (PFNGLTEXSTORAGESPARSEAMDPROC)glewGetProcAddress((const GLubyte*)"glTexStorageSparseAMD")) == NULL) || r; + r = ((glTextureStorageSparseAMD = (PFNGLTEXTURESTORAGESPARSEAMDPROC)glewGetProcAddress((const GLubyte*)"glTextureStorageSparseAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_sparse_texture */ + +#ifdef GL_AMD_stencil_operation_extended + +static GLboolean _glewInit_GL_AMD_stencil_operation_extended () +{ + GLboolean r = GL_FALSE; + + r = ((glStencilOpValueAMD = (PFNGLSTENCILOPVALUEAMDPROC)glewGetProcAddress((const GLubyte*)"glStencilOpValueAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_stencil_operation_extended */ + +#ifdef GL_AMD_vertex_shader_tessellator + +static GLboolean _glewInit_GL_AMD_vertex_shader_tessellator () +{ + GLboolean r = GL_FALSE; + + r = ((glTessellationFactorAMD = (PFNGLTESSELLATIONFACTORAMDPROC)glewGetProcAddress((const GLubyte*)"glTessellationFactorAMD")) == NULL) || r; + r = ((glTessellationModeAMD = (PFNGLTESSELLATIONMODEAMDPROC)glewGetProcAddress((const GLubyte*)"glTessellationModeAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_vertex_shader_tessellator */ + +#ifdef GL_ANGLE_framebuffer_blit + +static GLboolean _glewInit_GL_ANGLE_framebuffer_blit () +{ + GLboolean r = GL_FALSE; + + r = ((glBlitFramebufferANGLE = (PFNGLBLITFRAMEBUFFERANGLEPROC)glewGetProcAddress((const GLubyte*)"glBlitFramebufferANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_framebuffer_blit */ + +#ifdef GL_ANGLE_framebuffer_multisample + +static GLboolean _glewInit_GL_ANGLE_framebuffer_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glRenderbufferStorageMultisampleANGLE = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageMultisampleANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_framebuffer_multisample */ + +#ifdef GL_ANGLE_instanced_arrays + +static GLboolean _glewInit_GL_ANGLE_instanced_arrays () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysInstancedANGLE = (PFNGLDRAWARRAYSINSTANCEDANGLEPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstancedANGLE")) == NULL) || r; + r = ((glDrawElementsInstancedANGLE = (PFNGLDRAWELEMENTSINSTANCEDANGLEPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedANGLE")) == NULL) || r; + r = ((glVertexAttribDivisorANGLE = (PFNGLVERTEXATTRIBDIVISORANGLEPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribDivisorANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_instanced_arrays */ + +#ifdef GL_ANGLE_timer_query + +static GLboolean _glewInit_GL_ANGLE_timer_query () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginQueryANGLE = (PFNGLBEGINQUERYANGLEPROC)glewGetProcAddress((const GLubyte*)"glBeginQueryANGLE")) == NULL) || r; + r = ((glDeleteQueriesANGLE = (PFNGLDELETEQUERIESANGLEPROC)glewGetProcAddress((const GLubyte*)"glDeleteQueriesANGLE")) == NULL) || r; + r = ((glEndQueryANGLE = (PFNGLENDQUERYANGLEPROC)glewGetProcAddress((const GLubyte*)"glEndQueryANGLE")) == NULL) || r; + r = ((glGenQueriesANGLE = (PFNGLGENQUERIESANGLEPROC)glewGetProcAddress((const GLubyte*)"glGenQueriesANGLE")) == NULL) || r; + r = ((glGetQueryObjecti64vANGLE = (PFNGLGETQUERYOBJECTI64VANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjecti64vANGLE")) == NULL) || r; + r = ((glGetQueryObjectivANGLE = (PFNGLGETQUERYOBJECTIVANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectivANGLE")) == NULL) || r; + r = ((glGetQueryObjectui64vANGLE = (PFNGLGETQUERYOBJECTUI64VANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectui64vANGLE")) == NULL) || r; + r = ((glGetQueryObjectuivANGLE = (PFNGLGETQUERYOBJECTUIVANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectuivANGLE")) == NULL) || r; + r = ((glGetQueryivANGLE = (PFNGLGETQUERYIVANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryivANGLE")) == NULL) || r; + r = ((glIsQueryANGLE = (PFNGLISQUERYANGLEPROC)glewGetProcAddress((const GLubyte*)"glIsQueryANGLE")) == NULL) || r; + r = ((glQueryCounterANGLE = (PFNGLQUERYCOUNTERANGLEPROC)glewGetProcAddress((const GLubyte*)"glQueryCounterANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_timer_query */ + +#ifdef GL_ANGLE_translated_shader_source + +static GLboolean _glewInit_GL_ANGLE_translated_shader_source () +{ + GLboolean r = GL_FALSE; + + r = ((glGetTranslatedShaderSourceANGLE = (PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetTranslatedShaderSourceANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_translated_shader_source */ + +#ifdef GL_APPLE_copy_texture_levels + +static GLboolean _glewInit_GL_APPLE_copy_texture_levels () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyTextureLevelsAPPLE = (PFNGLCOPYTEXTURELEVELSAPPLEPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureLevelsAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_copy_texture_levels */ + +#ifdef GL_APPLE_element_array + +static GLboolean _glewInit_GL_APPLE_element_array () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawElementArrayAPPLE = (PFNGLDRAWELEMENTARRAYAPPLEPROC)glewGetProcAddress((const GLubyte*)"glDrawElementArrayAPPLE")) == NULL) || r; + r = ((glDrawRangeElementArrayAPPLE = (PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC)glewGetProcAddress((const GLubyte*)"glDrawRangeElementArrayAPPLE")) == NULL) || r; + r = ((glElementPointerAPPLE = (PFNGLELEMENTPOINTERAPPLEPROC)glewGetProcAddress((const GLubyte*)"glElementPointerAPPLE")) == NULL) || r; + r = ((glMultiDrawElementArrayAPPLE = (PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementArrayAPPLE")) == NULL) || r; + r = ((glMultiDrawRangeElementArrayAPPLE = (PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawRangeElementArrayAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_element_array */ + +#ifdef GL_APPLE_fence + +static GLboolean _glewInit_GL_APPLE_fence () +{ + GLboolean r = GL_FALSE; + + r = ((glDeleteFencesAPPLE = (PFNGLDELETEFENCESAPPLEPROC)glewGetProcAddress((const GLubyte*)"glDeleteFencesAPPLE")) == NULL) || r; + r = ((glFinishFenceAPPLE = (PFNGLFINISHFENCEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glFinishFenceAPPLE")) == NULL) || r; + r = ((glFinishObjectAPPLE = (PFNGLFINISHOBJECTAPPLEPROC)glewGetProcAddress((const GLubyte*)"glFinishObjectAPPLE")) == NULL) || r; + r = ((glGenFencesAPPLE = (PFNGLGENFENCESAPPLEPROC)glewGetProcAddress((const GLubyte*)"glGenFencesAPPLE")) == NULL) || r; + r = ((glIsFenceAPPLE = (PFNGLISFENCEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glIsFenceAPPLE")) == NULL) || r; + r = ((glSetFenceAPPLE = (PFNGLSETFENCEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glSetFenceAPPLE")) == NULL) || r; + r = ((glTestFenceAPPLE = (PFNGLTESTFENCEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glTestFenceAPPLE")) == NULL) || r; + r = ((glTestObjectAPPLE = (PFNGLTESTOBJECTAPPLEPROC)glewGetProcAddress((const GLubyte*)"glTestObjectAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_fence */ + +#ifdef GL_APPLE_flush_buffer_range + +static GLboolean _glewInit_GL_APPLE_flush_buffer_range () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferParameteriAPPLE = (PFNGLBUFFERPARAMETERIAPPLEPROC)glewGetProcAddress((const GLubyte*)"glBufferParameteriAPPLE")) == NULL) || r; + r = ((glFlushMappedBufferRangeAPPLE = (PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glFlushMappedBufferRangeAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_flush_buffer_range */ + +#ifdef GL_APPLE_framebuffer_multisample + +static GLboolean _glewInit_GL_APPLE_framebuffer_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glRenderbufferStorageMultisampleAPPLE = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageMultisampleAPPLE")) == NULL) || r; + r = ((glResolveMultisampleFramebufferAPPLE = (PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC)glewGetProcAddress((const GLubyte*)"glResolveMultisampleFramebufferAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_framebuffer_multisample */ + +#ifdef GL_APPLE_object_purgeable + +static GLboolean _glewInit_GL_APPLE_object_purgeable () +{ + GLboolean r = GL_FALSE; + + r = ((glGetObjectParameterivAPPLE = (PFNGLGETOBJECTPARAMETERIVAPPLEPROC)glewGetProcAddress((const GLubyte*)"glGetObjectParameterivAPPLE")) == NULL) || r; + r = ((glObjectPurgeableAPPLE = (PFNGLOBJECTPURGEABLEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glObjectPurgeableAPPLE")) == NULL) || r; + r = ((glObjectUnpurgeableAPPLE = (PFNGLOBJECTUNPURGEABLEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glObjectUnpurgeableAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_object_purgeable */ + +#ifdef GL_APPLE_sync + +static GLboolean _glewInit_GL_APPLE_sync () +{ + GLboolean r = GL_FALSE; + + r = ((glClientWaitSyncAPPLE = (PFNGLCLIENTWAITSYNCAPPLEPROC)glewGetProcAddress((const GLubyte*)"glClientWaitSyncAPPLE")) == NULL) || r; + r = ((glDeleteSyncAPPLE = (PFNGLDELETESYNCAPPLEPROC)glewGetProcAddress((const GLubyte*)"glDeleteSyncAPPLE")) == NULL) || r; + r = ((glFenceSyncAPPLE = (PFNGLFENCESYNCAPPLEPROC)glewGetProcAddress((const GLubyte*)"glFenceSyncAPPLE")) == NULL) || r; + r = ((glGetInteger64vAPPLE = (PFNGLGETINTEGER64VAPPLEPROC)glewGetProcAddress((const GLubyte*)"glGetInteger64vAPPLE")) == NULL) || r; + r = ((glGetSyncivAPPLE = (PFNGLGETSYNCIVAPPLEPROC)glewGetProcAddress((const GLubyte*)"glGetSyncivAPPLE")) == NULL) || r; + r = ((glIsSyncAPPLE = (PFNGLISSYNCAPPLEPROC)glewGetProcAddress((const GLubyte*)"glIsSyncAPPLE")) == NULL) || r; + r = ((glWaitSyncAPPLE = (PFNGLWAITSYNCAPPLEPROC)glewGetProcAddress((const GLubyte*)"glWaitSyncAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_sync */ + +#ifdef GL_APPLE_texture_range + +static GLboolean _glewInit_GL_APPLE_texture_range () +{ + GLboolean r = GL_FALSE; + + r = ((glGetTexParameterPointervAPPLE = (PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC)glewGetProcAddress((const GLubyte*)"glGetTexParameterPointervAPPLE")) == NULL) || r; + r = ((glTextureRangeAPPLE = (PFNGLTEXTURERANGEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glTextureRangeAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_texture_range */ + +#ifdef GL_APPLE_vertex_array_object + +static GLboolean _glewInit_GL_APPLE_vertex_array_object () +{ + GLboolean r = GL_FALSE; + + r = ((glBindVertexArrayAPPLE = (PFNGLBINDVERTEXARRAYAPPLEPROC)glewGetProcAddress((const GLubyte*)"glBindVertexArrayAPPLE")) == NULL) || r; + r = ((glDeleteVertexArraysAPPLE = (PFNGLDELETEVERTEXARRAYSAPPLEPROC)glewGetProcAddress((const GLubyte*)"glDeleteVertexArraysAPPLE")) == NULL) || r; + r = ((glGenVertexArraysAPPLE = (PFNGLGENVERTEXARRAYSAPPLEPROC)glewGetProcAddress((const GLubyte*)"glGenVertexArraysAPPLE")) == NULL) || r; + r = ((glIsVertexArrayAPPLE = (PFNGLISVERTEXARRAYAPPLEPROC)glewGetProcAddress((const GLubyte*)"glIsVertexArrayAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_vertex_array_object */ + +#ifdef GL_APPLE_vertex_array_range + +static GLboolean _glewInit_GL_APPLE_vertex_array_range () +{ + GLboolean r = GL_FALSE; + + r = ((glFlushVertexArrayRangeAPPLE = (PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glFlushVertexArrayRangeAPPLE")) == NULL) || r; + r = ((glVertexArrayParameteriAPPLE = (PFNGLVERTEXARRAYPARAMETERIAPPLEPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayParameteriAPPLE")) == NULL) || r; + r = ((glVertexArrayRangeAPPLE = (PFNGLVERTEXARRAYRANGEAPPLEPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayRangeAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_vertex_array_range */ + +#ifdef GL_APPLE_vertex_program_evaluators + +static GLboolean _glewInit_GL_APPLE_vertex_program_evaluators () +{ + GLboolean r = GL_FALSE; + + r = ((glDisableVertexAttribAPPLE = (PFNGLDISABLEVERTEXATTRIBAPPLEPROC)glewGetProcAddress((const GLubyte*)"glDisableVertexAttribAPPLE")) == NULL) || r; + r = ((glEnableVertexAttribAPPLE = (PFNGLENABLEVERTEXATTRIBAPPLEPROC)glewGetProcAddress((const GLubyte*)"glEnableVertexAttribAPPLE")) == NULL) || r; + r = ((glIsVertexAttribEnabledAPPLE = (PFNGLISVERTEXATTRIBENABLEDAPPLEPROC)glewGetProcAddress((const GLubyte*)"glIsVertexAttribEnabledAPPLE")) == NULL) || r; + r = ((glMapVertexAttrib1dAPPLE = (PFNGLMAPVERTEXATTRIB1DAPPLEPROC)glewGetProcAddress((const GLubyte*)"glMapVertexAttrib1dAPPLE")) == NULL) || r; + r = ((glMapVertexAttrib1fAPPLE = (PFNGLMAPVERTEXATTRIB1FAPPLEPROC)glewGetProcAddress((const GLubyte*)"glMapVertexAttrib1fAPPLE")) == NULL) || r; + r = ((glMapVertexAttrib2dAPPLE = (PFNGLMAPVERTEXATTRIB2DAPPLEPROC)glewGetProcAddress((const GLubyte*)"glMapVertexAttrib2dAPPLE")) == NULL) || r; + r = ((glMapVertexAttrib2fAPPLE = (PFNGLMAPVERTEXATTRIB2FAPPLEPROC)glewGetProcAddress((const GLubyte*)"glMapVertexAttrib2fAPPLE")) == NULL) || r; + + return r; +} + +#endif /* GL_APPLE_vertex_program_evaluators */ + +#ifdef GL_ARB_ES2_compatibility + +static GLboolean _glewInit_GL_ARB_ES2_compatibility () +{ + GLboolean r = GL_FALSE; + + r = ((glClearDepthf = (PFNGLCLEARDEPTHFPROC)glewGetProcAddress((const GLubyte*)"glClearDepthf")) == NULL) || r; + r = ((glDepthRangef = (PFNGLDEPTHRANGEFPROC)glewGetProcAddress((const GLubyte*)"glDepthRangef")) == NULL) || r; + r = ((glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)glewGetProcAddress((const GLubyte*)"glGetShaderPrecisionFormat")) == NULL) || r; + r = ((glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)glewGetProcAddress((const GLubyte*)"glReleaseShaderCompiler")) == NULL) || r; + r = ((glShaderBinary = (PFNGLSHADERBINARYPROC)glewGetProcAddress((const GLubyte*)"glShaderBinary")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_ES2_compatibility */ + +#ifdef GL_ARB_ES3_1_compatibility + +static GLboolean _glewInit_GL_ARB_ES3_1_compatibility () +{ + GLboolean r = GL_FALSE; + + r = ((glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC)glewGetProcAddress((const GLubyte*)"glMemoryBarrierByRegion")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_ES3_1_compatibility */ + +#ifdef GL_ARB_ES3_2_compatibility + +static GLboolean _glewInit_GL_ARB_ES3_2_compatibility () +{ + GLboolean r = GL_FALSE; + + r = ((glPrimitiveBoundingBoxARB = (PFNGLPRIMITIVEBOUNDINGBOXARBPROC)glewGetProcAddress((const GLubyte*)"glPrimitiveBoundingBoxARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_ES3_2_compatibility */ + +#ifdef GL_ARB_base_instance + +static GLboolean _glewInit_GL_ARB_base_instance () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstancedBaseInstance")) == NULL) || r; + r = ((glDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedBaseInstance")) == NULL) || r; + r = ((glDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedBaseVertexBaseInstance")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_base_instance */ + +#ifdef GL_ARB_bindless_texture + +static GLboolean _glewInit_GL_ARB_bindless_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glGetImageHandleARB = (PFNGLGETIMAGEHANDLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetImageHandleARB")) == NULL) || r; + r = ((glGetTextureHandleARB = (PFNGLGETTEXTUREHANDLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetTextureHandleARB")) == NULL) || r; + r = ((glGetTextureSamplerHandleARB = (PFNGLGETTEXTURESAMPLERHANDLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetTextureSamplerHandleARB")) == NULL) || r; + r = ((glGetVertexAttribLui64vARB = (PFNGLGETVERTEXATTRIBLUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribLui64vARB")) == NULL) || r; + r = ((glIsImageHandleResidentARB = (PFNGLISIMAGEHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glIsImageHandleResidentARB")) == NULL) || r; + r = ((glIsTextureHandleResidentARB = (PFNGLISTEXTUREHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glIsTextureHandleResidentARB")) == NULL) || r; + r = ((glMakeImageHandleNonResidentARB = (PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeImageHandleNonResidentARB")) == NULL) || r; + r = ((glMakeImageHandleResidentARB = (PFNGLMAKEIMAGEHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeImageHandleResidentARB")) == NULL) || r; + r = ((glMakeTextureHandleNonResidentARB = (PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeTextureHandleNonResidentARB")) == NULL) || r; + r = ((glMakeTextureHandleResidentARB = (PFNGLMAKETEXTUREHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeTextureHandleResidentARB")) == NULL) || r; + r = ((glProgramUniformHandleui64ARB = (PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformHandleui64ARB")) == NULL) || r; + r = ((glProgramUniformHandleui64vARB = (PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformHandleui64vARB")) == NULL) || r; + r = ((glUniformHandleui64ARB = (PFNGLUNIFORMHANDLEUI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniformHandleui64ARB")) == NULL) || r; + r = ((glUniformHandleui64vARB = (PFNGLUNIFORMHANDLEUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniformHandleui64vARB")) == NULL) || r; + r = ((glVertexAttribL1ui64ARB = (PFNGLVERTEXATTRIBL1UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1ui64ARB")) == NULL) || r; + r = ((glVertexAttribL1ui64vARB = (PFNGLVERTEXATTRIBL1UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1ui64vARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_bindless_texture */ + +#ifdef GL_ARB_blend_func_extended + +static GLboolean _glewInit_GL_ARB_blend_func_extended () +{ + GLboolean r = GL_FALSE; + + r = ((glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)glewGetProcAddress((const GLubyte*)"glBindFragDataLocationIndexed")) == NULL) || r; + r = ((glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)glewGetProcAddress((const GLubyte*)"glGetFragDataIndex")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_blend_func_extended */ + +#ifdef GL_ARB_buffer_storage + +static GLboolean _glewInit_GL_ARB_buffer_storage () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferStorage = (PFNGLBUFFERSTORAGEPROC)glewGetProcAddress((const GLubyte*)"glBufferStorage")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_buffer_storage */ + +#ifdef GL_ARB_cl_event + +static GLboolean _glewInit_GL_ARB_cl_event () +{ + GLboolean r = GL_FALSE; + + r = ((glCreateSyncFromCLeventARB = (PFNGLCREATESYNCFROMCLEVENTARBPROC)glewGetProcAddress((const GLubyte*)"glCreateSyncFromCLeventARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_cl_event */ + +#ifdef GL_ARB_clear_buffer_object + +static GLboolean _glewInit_GL_ARB_clear_buffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glClearBufferData = (PFNGLCLEARBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glClearBufferData")) == NULL) || r; + r = ((glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glClearBufferSubData")) == NULL) || r; + r = ((glClearNamedBufferDataEXT = (PFNGLCLEARNAMEDBUFFERDATAEXTPROC)glewGetProcAddress((const GLubyte*)"glClearNamedBufferDataEXT")) == NULL) || r; + r = ((glClearNamedBufferSubDataEXT = (PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC)glewGetProcAddress((const GLubyte*)"glClearNamedBufferSubDataEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_clear_buffer_object */ + +#ifdef GL_ARB_clear_texture + +static GLboolean _glewInit_GL_ARB_clear_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glClearTexImage")) == NULL) || r; + r = ((glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC)glewGetProcAddress((const GLubyte*)"glClearTexSubImage")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_clear_texture */ + +#ifdef GL_ARB_clip_control + +static GLboolean _glewInit_GL_ARB_clip_control () +{ + GLboolean r = GL_FALSE; + + r = ((glClipControl = (PFNGLCLIPCONTROLPROC)glewGetProcAddress((const GLubyte*)"glClipControl")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_clip_control */ + +#ifdef GL_ARB_color_buffer_float + +static GLboolean _glewInit_GL_ARB_color_buffer_float () +{ + GLboolean r = GL_FALSE; + + r = ((glClampColorARB = (PFNGLCLAMPCOLORARBPROC)glewGetProcAddress((const GLubyte*)"glClampColorARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_color_buffer_float */ + +#ifdef GL_ARB_compute_shader + +static GLboolean _glewInit_GL_ARB_compute_shader () +{ + GLboolean r = GL_FALSE; + + r = ((glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)glewGetProcAddress((const GLubyte*)"glDispatchCompute")) == NULL) || r; + r = ((glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC)glewGetProcAddress((const GLubyte*)"glDispatchComputeIndirect")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_compute_shader */ + +#ifdef GL_ARB_compute_variable_group_size + +static GLboolean _glewInit_GL_ARB_compute_variable_group_size () +{ + GLboolean r = GL_FALSE; + + r = ((glDispatchComputeGroupSizeARB = (PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC)glewGetProcAddress((const GLubyte*)"glDispatchComputeGroupSizeARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_compute_variable_group_size */ + +#ifdef GL_ARB_copy_buffer + +static GLboolean _glewInit_GL_ARB_copy_buffer () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glCopyBufferSubData")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_copy_buffer */ + +#ifdef GL_ARB_copy_image + +static GLboolean _glewInit_GL_ARB_copy_image () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC)glewGetProcAddress((const GLubyte*)"glCopyImageSubData")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_copy_image */ + +#ifdef GL_ARB_debug_output + +static GLboolean _glewInit_GL_ARB_debug_output () +{ + GLboolean r = GL_FALSE; + + r = ((glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageCallbackARB")) == NULL) || r; + r = ((glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageControlARB")) == NULL) || r; + r = ((glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageInsertARB")) == NULL) || r; + r = ((glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC)glewGetProcAddress((const GLubyte*)"glGetDebugMessageLogARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_debug_output */ + +#ifdef GL_ARB_direct_state_access + +static GLboolean _glewInit_GL_ARB_direct_state_access () +{ + GLboolean r = GL_FALSE; + + r = ((glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC)glewGetProcAddress((const GLubyte*)"glBindTextureUnit")) == NULL) || r; + r = ((glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBlitNamedFramebuffer")) == NULL) || r; + r = ((glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)glewGetProcAddress((const GLubyte*)"glCheckNamedFramebufferStatus")) == NULL) || r; + r = ((glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glClearNamedBufferData")) == NULL) || r; + r = ((glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glClearNamedBufferSubData")) == NULL) || r; + r = ((glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferfi")) == NULL) || r; + r = ((glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferfv")) == NULL) || r; + r = ((glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferiv")) == NULL) || r; + r = ((glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferuiv")) == NULL) || r; + r = ((glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage1D")) == NULL) || r; + r = ((glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage2D")) == NULL) || r; + r = ((glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage3D")) == NULL) || r; + r = ((glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glCopyNamedBufferSubData")) == NULL) || r; + r = ((glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage1D")) == NULL) || r; + r = ((glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage2D")) == NULL) || r; + r = ((glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage3D")) == NULL) || r; + r = ((glCreateBuffers = (PFNGLCREATEBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glCreateBuffers")) == NULL) || r; + r = ((glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glCreateFramebuffers")) == NULL) || r; + r = ((glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC)glewGetProcAddress((const GLubyte*)"glCreateProgramPipelines")) == NULL) || r; + r = ((glCreateQueries = (PFNGLCREATEQUERIESPROC)glewGetProcAddress((const GLubyte*)"glCreateQueries")) == NULL) || r; + r = ((glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glCreateRenderbuffers")) == NULL) || r; + r = ((glCreateSamplers = (PFNGLCREATESAMPLERSPROC)glewGetProcAddress((const GLubyte*)"glCreateSamplers")) == NULL) || r; + r = ((glCreateTextures = (PFNGLCREATETEXTURESPROC)glewGetProcAddress((const GLubyte*)"glCreateTextures")) == NULL) || r; + r = ((glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC)glewGetProcAddress((const GLubyte*)"glCreateTransformFeedbacks")) == NULL) || r; + r = ((glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC)glewGetProcAddress((const GLubyte*)"glCreateVertexArrays")) == NULL) || r; + r = ((glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC)glewGetProcAddress((const GLubyte*)"glDisableVertexArrayAttrib")) == NULL) || r; + r = ((glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC)glewGetProcAddress((const GLubyte*)"glEnableVertexArrayAttrib")) == NULL) || r; + r = ((glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glFlushMappedNamedBufferRange")) == NULL) || r; + r = ((glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)glewGetProcAddress((const GLubyte*)"glGenerateTextureMipmap")) == NULL) || r; + r = ((glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedTextureImage")) == NULL) || r; + r = ((glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferParameteri64v")) == NULL) || r; + r = ((glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferParameteriv")) == NULL) || r; + r = ((glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferPointerv")) == NULL) || r; + r = ((glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferSubData")) == NULL) || r; + r = ((glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedFramebufferAttachmentParameteriv")) == NULL) || r; + r = ((glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedFramebufferParameteriv")) == NULL) || r; + r = ((glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedRenderbufferParameteriv")) == NULL) || r; + r = ((glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjecti64v")) == NULL) || r; + r = ((glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjectiv")) == NULL) || r; + r = ((glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjectui64v")) == NULL) || r; + r = ((glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjectuiv")) == NULL) || r; + r = ((glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetTextureImage")) == NULL) || r; + r = ((glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureLevelParameterfv")) == NULL) || r; + r = ((glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureLevelParameteriv")) == NULL) || r; + r = ((glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterIiv")) == NULL) || r; + r = ((glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterIuiv")) == NULL) || r; + r = ((glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterfv")) == NULL) || r; + r = ((glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameteriv")) == NULL) || r; + r = ((glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbacki64_v")) == NULL) || r; + r = ((glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbacki_v")) == NULL) || r; + r = ((glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbackiv")) == NULL) || r; + r = ((glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayIndexed64iv")) == NULL) || r; + r = ((glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayIndexediv")) == NULL) || r; + r = ((glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayiv")) == NULL) || r; + r = ((glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glInvalidateNamedFramebufferData")) == NULL) || r; + r = ((glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glInvalidateNamedFramebufferSubData")) == NULL) || r; + r = ((glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC)glewGetProcAddress((const GLubyte*)"glMapNamedBuffer")) == NULL) || r; + r = ((glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glMapNamedBufferRange")) == NULL) || r; + r = ((glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferData")) == NULL) || r; + r = ((glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferStorage")) == NULL) || r; + r = ((glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferSubData")) == NULL) || r; + r = ((glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferDrawBuffer")) == NULL) || r; + r = ((glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferDrawBuffers")) == NULL) || r; + r = ((glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferParameteri")) == NULL) || r; + r = ((glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferReadBuffer")) == NULL) || r; + r = ((glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferRenderbuffer")) == NULL) || r; + r = ((glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTexture")) == NULL) || r; + r = ((glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTextureLayer")) == NULL) || r; + r = ((glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorage")) == NULL) || r; + r = ((glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageMultisample")) == NULL) || r; + r = ((glTextureBuffer = (PFNGLTEXTUREBUFFERPROC)glewGetProcAddress((const GLubyte*)"glTextureBuffer")) == NULL) || r; + r = ((glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glTextureBufferRange")) == NULL) || r; + r = ((glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterIiv")) == NULL) || r; + r = ((glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterIuiv")) == NULL) || r; + r = ((glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterf")) == NULL) || r; + r = ((glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterfv")) == NULL) || r; + r = ((glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glTextureParameteri")) == NULL) || r; + r = ((glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameteriv")) == NULL) || r; + r = ((glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage1D")) == NULL) || r; + r = ((glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage2D")) == NULL) || r; + r = ((glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage2DMultisample")) == NULL) || r; + r = ((glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage3D")) == NULL) || r; + r = ((glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage3DMultisample")) == NULL) || r; + r = ((glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage1D")) == NULL) || r; + r = ((glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage2D")) == NULL) || r; + r = ((glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage3D")) == NULL) || r; + r = ((glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackBufferBase")) == NULL) || r; + r = ((glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackBufferRange")) == NULL) || r; + r = ((glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC)glewGetProcAddress((const GLubyte*)"glUnmapNamedBuffer")) == NULL) || r; + r = ((glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribBinding")) == NULL) || r; + r = ((glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribFormat")) == NULL) || r; + r = ((glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribIFormat")) == NULL) || r; + r = ((glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribLFormat")) == NULL) || r; + r = ((glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayBindingDivisor")) == NULL) || r; + r = ((glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayElementBuffer")) == NULL) || r; + r = ((glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexBuffer")) == NULL) || r; + r = ((glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexBuffers")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_direct_state_access */ + +#ifdef GL_ARB_draw_buffers + +static GLboolean _glewInit_GL_ARB_draw_buffers () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC)glewGetProcAddress((const GLubyte*)"glDrawBuffersARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_draw_buffers */ + +#ifdef GL_ARB_draw_buffers_blend + +static GLboolean _glewInit_GL_ARB_draw_buffers_blend () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendEquationSeparateiARB = (PFNGLBLENDEQUATIONSEPARATEIARBPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationSeparateiARB")) == NULL) || r; + r = ((glBlendEquationiARB = (PFNGLBLENDEQUATIONIARBPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationiARB")) == NULL) || r; + r = ((glBlendFuncSeparateiARB = (PFNGLBLENDFUNCSEPARATEIARBPROC)glewGetProcAddress((const GLubyte*)"glBlendFuncSeparateiARB")) == NULL) || r; + r = ((glBlendFunciARB = (PFNGLBLENDFUNCIARBPROC)glewGetProcAddress((const GLubyte*)"glBlendFunciARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_draw_buffers_blend */ + +#ifdef GL_ARB_draw_elements_base_vertex + +static GLboolean _glewInit_GL_ARB_draw_elements_base_vertex () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsBaseVertex")) == NULL) || r; + r = ((glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedBaseVertex")) == NULL) || r; + r = ((glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)glewGetProcAddress((const GLubyte*)"glDrawRangeElementsBaseVertex")) == NULL) || r; + r = ((glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsBaseVertex")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_draw_elements_base_vertex */ + +#ifdef GL_ARB_draw_indirect + +static GLboolean _glewInit_GL_ARB_draw_indirect () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysIndirect")) == NULL) || r; + r = ((glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsIndirect")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_draw_indirect */ + +#ifdef GL_ARB_framebuffer_no_attachments + +static GLboolean _glewInit_GL_ARB_framebuffer_no_attachments () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glFramebufferParameteri")) == NULL) || r; + r = ((glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetFramebufferParameteriv")) == NULL) || r; + r = ((glGetNamedFramebufferParameterivEXT = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedFramebufferParameterivEXT")) == NULL) || r; + r = ((glNamedFramebufferParameteriEXT = (PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferParameteriEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_framebuffer_no_attachments */ + +#ifdef GL_ARB_framebuffer_object + +static GLboolean _glewInit_GL_ARB_framebuffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBindFramebuffer")) == NULL) || r; + r = ((glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBindRenderbuffer")) == NULL) || r; + r = ((glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBlitFramebuffer")) == NULL) || r; + r = ((glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)glewGetProcAddress((const GLubyte*)"glCheckFramebufferStatus")) == NULL) || r; + r = ((glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glDeleteFramebuffers")) == NULL) || r; + r = ((glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glDeleteRenderbuffers")) == NULL) || r; + r = ((glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)glewGetProcAddress((const GLubyte*)"glFramebufferRenderbuffer")) == NULL) || r; + r = ((glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture1D")) == NULL) || r; + r = ((glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture2D")) == NULL) || r; + r = ((glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture3D")) == NULL) || r; + r = ((glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureLayer")) == NULL) || r; + r = ((glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glGenFramebuffers")) == NULL) || r; + r = ((glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glGenRenderbuffers")) == NULL) || r; + r = ((glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)glewGetProcAddress((const GLubyte*)"glGenerateMipmap")) == NULL) || r; + r = ((glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetFramebufferAttachmentParameteriv")) == NULL) || r; + r = ((glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetRenderbufferParameteriv")) == NULL) || r; + r = ((glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)glewGetProcAddress((const GLubyte*)"glIsFramebuffer")) == NULL) || r; + r = ((glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)glewGetProcAddress((const GLubyte*)"glIsRenderbuffer")) == NULL) || r; + r = ((glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorage")) == NULL) || r; + r = ((glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageMultisample")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_framebuffer_object */ + +#ifdef GL_ARB_geometry_shader4 + +static GLboolean _glewInit_GL_ARB_geometry_shader4 () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferTextureARB = (PFNGLFRAMEBUFFERTEXTUREARBPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureARB")) == NULL) || r; + r = ((glFramebufferTextureFaceARB = (PFNGLFRAMEBUFFERTEXTUREFACEARBPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureFaceARB")) == NULL) || r; + r = ((glFramebufferTextureLayerARB = (PFNGLFRAMEBUFFERTEXTURELAYERARBPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureLayerARB")) == NULL) || r; + r = ((glProgramParameteriARB = (PFNGLPROGRAMPARAMETERIARBPROC)glewGetProcAddress((const GLubyte*)"glProgramParameteriARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_geometry_shader4 */ + +#ifdef GL_ARB_get_program_binary + +static GLboolean _glewInit_GL_ARB_get_program_binary () +{ + GLboolean r = GL_FALSE; + + r = ((glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)glewGetProcAddress((const GLubyte*)"glGetProgramBinary")) == NULL) || r; + r = ((glProgramBinary = (PFNGLPROGRAMBINARYPROC)glewGetProcAddress((const GLubyte*)"glProgramBinary")) == NULL) || r; + r = ((glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glProgramParameteri")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_get_program_binary */ + +#ifdef GL_ARB_get_texture_sub_image + +static GLboolean _glewInit_GL_ARB_get_texture_sub_image () +{ + GLboolean r = GL_FALSE; + + r = ((glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedTextureSubImage")) == NULL) || r; + r = ((glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetTextureSubImage")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_get_texture_sub_image */ + +#ifdef GL_ARB_gl_spirv + +static GLboolean _glewInit_GL_ARB_gl_spirv () +{ + GLboolean r = GL_FALSE; + + r = ((glSpecializeShaderARB = (PFNGLSPECIALIZESHADERARBPROC)glewGetProcAddress((const GLubyte*)"glSpecializeShaderARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_gl_spirv */ + +#ifdef GL_ARB_gpu_shader_fp64 + +static GLboolean _glewInit_GL_ARB_gpu_shader_fp64 () +{ + GLboolean r = GL_FALSE; + + r = ((glGetUniformdv = (PFNGLGETUNIFORMDVPROC)glewGetProcAddress((const GLubyte*)"glGetUniformdv")) == NULL) || r; + r = ((glUniform1d = (PFNGLUNIFORM1DPROC)glewGetProcAddress((const GLubyte*)"glUniform1d")) == NULL) || r; + r = ((glUniform1dv = (PFNGLUNIFORM1DVPROC)glewGetProcAddress((const GLubyte*)"glUniform1dv")) == NULL) || r; + r = ((glUniform2d = (PFNGLUNIFORM2DPROC)glewGetProcAddress((const GLubyte*)"glUniform2d")) == NULL) || r; + r = ((glUniform2dv = (PFNGLUNIFORM2DVPROC)glewGetProcAddress((const GLubyte*)"glUniform2dv")) == NULL) || r; + r = ((glUniform3d = (PFNGLUNIFORM3DPROC)glewGetProcAddress((const GLubyte*)"glUniform3d")) == NULL) || r; + r = ((glUniform3dv = (PFNGLUNIFORM3DVPROC)glewGetProcAddress((const GLubyte*)"glUniform3dv")) == NULL) || r; + r = ((glUniform4d = (PFNGLUNIFORM4DPROC)glewGetProcAddress((const GLubyte*)"glUniform4d")) == NULL) || r; + r = ((glUniform4dv = (PFNGLUNIFORM4DVPROC)glewGetProcAddress((const GLubyte*)"glUniform4dv")) == NULL) || r; + r = ((glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2dv")) == NULL) || r; + r = ((glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2x3dv")) == NULL) || r; + r = ((glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2x4dv")) == NULL) || r; + r = ((glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3dv")) == NULL) || r; + r = ((glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3x2dv")) == NULL) || r; + r = ((glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3x4dv")) == NULL) || r; + r = ((glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4dv")) == NULL) || r; + r = ((glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4x2dv")) == NULL) || r; + r = ((glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4x3dv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_gpu_shader_fp64 */ + +#ifdef GL_ARB_gpu_shader_int64 + +static GLboolean _glewInit_GL_ARB_gpu_shader_int64 () +{ + GLboolean r = GL_FALSE; + + r = ((glGetUniformi64vARB = (PFNGLGETUNIFORMI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetUniformi64vARB")) == NULL) || r; + r = ((glGetUniformui64vARB = (PFNGLGETUNIFORMUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetUniformui64vARB")) == NULL) || r; + r = ((glGetnUniformi64vARB = (PFNGLGETNUNIFORMI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformi64vARB")) == NULL) || r; + r = ((glGetnUniformui64vARB = (PFNGLGETNUNIFORMUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformui64vARB")) == NULL) || r; + r = ((glProgramUniform1i64ARB = (PFNGLPROGRAMUNIFORM1I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1i64ARB")) == NULL) || r; + r = ((glProgramUniform1i64vARB = (PFNGLPROGRAMUNIFORM1I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1i64vARB")) == NULL) || r; + r = ((glProgramUniform1ui64ARB = (PFNGLPROGRAMUNIFORM1UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ui64ARB")) == NULL) || r; + r = ((glProgramUniform1ui64vARB = (PFNGLPROGRAMUNIFORM1UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ui64vARB")) == NULL) || r; + r = ((glProgramUniform2i64ARB = (PFNGLPROGRAMUNIFORM2I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2i64ARB")) == NULL) || r; + r = ((glProgramUniform2i64vARB = (PFNGLPROGRAMUNIFORM2I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2i64vARB")) == NULL) || r; + r = ((glProgramUniform2ui64ARB = (PFNGLPROGRAMUNIFORM2UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ui64ARB")) == NULL) || r; + r = ((glProgramUniform2ui64vARB = (PFNGLPROGRAMUNIFORM2UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ui64vARB")) == NULL) || r; + r = ((glProgramUniform3i64ARB = (PFNGLPROGRAMUNIFORM3I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3i64ARB")) == NULL) || r; + r = ((glProgramUniform3i64vARB = (PFNGLPROGRAMUNIFORM3I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3i64vARB")) == NULL) || r; + r = ((glProgramUniform3ui64ARB = (PFNGLPROGRAMUNIFORM3UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ui64ARB")) == NULL) || r; + r = ((glProgramUniform3ui64vARB = (PFNGLPROGRAMUNIFORM3UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ui64vARB")) == NULL) || r; + r = ((glProgramUniform4i64ARB = (PFNGLPROGRAMUNIFORM4I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4i64ARB")) == NULL) || r; + r = ((glProgramUniform4i64vARB = (PFNGLPROGRAMUNIFORM4I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4i64vARB")) == NULL) || r; + r = ((glProgramUniform4ui64ARB = (PFNGLPROGRAMUNIFORM4UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ui64ARB")) == NULL) || r; + r = ((glProgramUniform4ui64vARB = (PFNGLPROGRAMUNIFORM4UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ui64vARB")) == NULL) || r; + r = ((glUniform1i64ARB = (PFNGLUNIFORM1I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1i64ARB")) == NULL) || r; + r = ((glUniform1i64vARB = (PFNGLUNIFORM1I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1i64vARB")) == NULL) || r; + r = ((glUniform1ui64ARB = (PFNGLUNIFORM1UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1ui64ARB")) == NULL) || r; + r = ((glUniform1ui64vARB = (PFNGLUNIFORM1UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1ui64vARB")) == NULL) || r; + r = ((glUniform2i64ARB = (PFNGLUNIFORM2I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2i64ARB")) == NULL) || r; + r = ((glUniform2i64vARB = (PFNGLUNIFORM2I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2i64vARB")) == NULL) || r; + r = ((glUniform2ui64ARB = (PFNGLUNIFORM2UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2ui64ARB")) == NULL) || r; + r = ((glUniform2ui64vARB = (PFNGLUNIFORM2UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2ui64vARB")) == NULL) || r; + r = ((glUniform3i64ARB = (PFNGLUNIFORM3I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3i64ARB")) == NULL) || r; + r = ((glUniform3i64vARB = (PFNGLUNIFORM3I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3i64vARB")) == NULL) || r; + r = ((glUniform3ui64ARB = (PFNGLUNIFORM3UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3ui64ARB")) == NULL) || r; + r = ((glUniform3ui64vARB = (PFNGLUNIFORM3UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3ui64vARB")) == NULL) || r; + r = ((glUniform4i64ARB = (PFNGLUNIFORM4I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4i64ARB")) == NULL) || r; + r = ((glUniform4i64vARB = (PFNGLUNIFORM4I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4i64vARB")) == NULL) || r; + r = ((glUniform4ui64ARB = (PFNGLUNIFORM4UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4ui64ARB")) == NULL) || r; + r = ((glUniform4ui64vARB = (PFNGLUNIFORM4UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4ui64vARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_gpu_shader_int64 */ + +#ifdef GL_ARB_imaging + +static GLboolean _glewInit_GL_ARB_imaging () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendEquation = (PFNGLBLENDEQUATIONPROC)glewGetProcAddress((const GLubyte*)"glBlendEquation")) == NULL) || r; + r = ((glColorSubTable = (PFNGLCOLORSUBTABLEPROC)glewGetProcAddress((const GLubyte*)"glColorSubTable")) == NULL) || r; + r = ((glColorTable = (PFNGLCOLORTABLEPROC)glewGetProcAddress((const GLubyte*)"glColorTable")) == NULL) || r; + r = ((glColorTableParameterfv = (PFNGLCOLORTABLEPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glColorTableParameterfv")) == NULL) || r; + r = ((glColorTableParameteriv = (PFNGLCOLORTABLEPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glColorTableParameteriv")) == NULL) || r; + r = ((glConvolutionFilter1D = (PFNGLCONVOLUTIONFILTER1DPROC)glewGetProcAddress((const GLubyte*)"glConvolutionFilter1D")) == NULL) || r; + r = ((glConvolutionFilter2D = (PFNGLCONVOLUTIONFILTER2DPROC)glewGetProcAddress((const GLubyte*)"glConvolutionFilter2D")) == NULL) || r; + r = ((glConvolutionParameterf = (PFNGLCONVOLUTIONPARAMETERFPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameterf")) == NULL) || r; + r = ((glConvolutionParameterfv = (PFNGLCONVOLUTIONPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameterfv")) == NULL) || r; + r = ((glConvolutionParameteri = (PFNGLCONVOLUTIONPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameteri")) == NULL) || r; + r = ((glConvolutionParameteriv = (PFNGLCONVOLUTIONPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameteriv")) == NULL) || r; + r = ((glCopyColorSubTable = (PFNGLCOPYCOLORSUBTABLEPROC)glewGetProcAddress((const GLubyte*)"glCopyColorSubTable")) == NULL) || r; + r = ((glCopyColorTable = (PFNGLCOPYCOLORTABLEPROC)glewGetProcAddress((const GLubyte*)"glCopyColorTable")) == NULL) || r; + r = ((glCopyConvolutionFilter1D = (PFNGLCOPYCONVOLUTIONFILTER1DPROC)glewGetProcAddress((const GLubyte*)"glCopyConvolutionFilter1D")) == NULL) || r; + r = ((glCopyConvolutionFilter2D = (PFNGLCOPYCONVOLUTIONFILTER2DPROC)glewGetProcAddress((const GLubyte*)"glCopyConvolutionFilter2D")) == NULL) || r; + r = ((glGetColorTable = (PFNGLGETCOLORTABLEPROC)glewGetProcAddress((const GLubyte*)"glGetColorTable")) == NULL) || r; + r = ((glGetColorTableParameterfv = (PFNGLGETCOLORTABLEPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableParameterfv")) == NULL) || r; + r = ((glGetColorTableParameteriv = (PFNGLGETCOLORTABLEPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableParameteriv")) == NULL) || r; + r = ((glGetConvolutionFilter = (PFNGLGETCONVOLUTIONFILTERPROC)glewGetProcAddress((const GLubyte*)"glGetConvolutionFilter")) == NULL) || r; + r = ((glGetConvolutionParameterfv = (PFNGLGETCONVOLUTIONPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetConvolutionParameterfv")) == NULL) || r; + r = ((glGetConvolutionParameteriv = (PFNGLGETCONVOLUTIONPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetConvolutionParameteriv")) == NULL) || r; + r = ((glGetHistogram = (PFNGLGETHISTOGRAMPROC)glewGetProcAddress((const GLubyte*)"glGetHistogram")) == NULL) || r; + r = ((glGetHistogramParameterfv = (PFNGLGETHISTOGRAMPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetHistogramParameterfv")) == NULL) || r; + r = ((glGetHistogramParameteriv = (PFNGLGETHISTOGRAMPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetHistogramParameteriv")) == NULL) || r; + r = ((glGetMinmax = (PFNGLGETMINMAXPROC)glewGetProcAddress((const GLubyte*)"glGetMinmax")) == NULL) || r; + r = ((glGetMinmaxParameterfv = (PFNGLGETMINMAXPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetMinmaxParameterfv")) == NULL) || r; + r = ((glGetMinmaxParameteriv = (PFNGLGETMINMAXPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetMinmaxParameteriv")) == NULL) || r; + r = ((glGetSeparableFilter = (PFNGLGETSEPARABLEFILTERPROC)glewGetProcAddress((const GLubyte*)"glGetSeparableFilter")) == NULL) || r; + r = ((glHistogram = (PFNGLHISTOGRAMPROC)glewGetProcAddress((const GLubyte*)"glHistogram")) == NULL) || r; + r = ((glMinmax = (PFNGLMINMAXPROC)glewGetProcAddress((const GLubyte*)"glMinmax")) == NULL) || r; + r = ((glResetHistogram = (PFNGLRESETHISTOGRAMPROC)glewGetProcAddress((const GLubyte*)"glResetHistogram")) == NULL) || r; + r = ((glResetMinmax = (PFNGLRESETMINMAXPROC)glewGetProcAddress((const GLubyte*)"glResetMinmax")) == NULL) || r; + r = ((glSeparableFilter2D = (PFNGLSEPARABLEFILTER2DPROC)glewGetProcAddress((const GLubyte*)"glSeparableFilter2D")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_imaging */ + +#ifdef GL_ARB_indirect_parameters + +static GLboolean _glewInit_GL_ARB_indirect_parameters () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectCountARB = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectCountARB")) == NULL) || r; + r = ((glMultiDrawElementsIndirectCountARB = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectCountARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_indirect_parameters */ + +#ifdef GL_ARB_instanced_arrays + +static GLboolean _glewInit_GL_ARB_instanced_arrays () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysInstancedARB = (PFNGLDRAWARRAYSINSTANCEDARBPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstancedARB")) == NULL) || r; + r = ((glDrawElementsInstancedARB = (PFNGLDRAWELEMENTSINSTANCEDARBPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedARB")) == NULL) || r; + r = ((glVertexAttribDivisorARB = (PFNGLVERTEXATTRIBDIVISORARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribDivisorARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_instanced_arrays */ + +#ifdef GL_ARB_internalformat_query + +static GLboolean _glewInit_GL_ARB_internalformat_query () +{ + GLboolean r = GL_FALSE; + + r = ((glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)glewGetProcAddress((const GLubyte*)"glGetInternalformativ")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_internalformat_query */ + +#ifdef GL_ARB_internalformat_query2 + +static GLboolean _glewInit_GL_ARB_internalformat_query2 () +{ + GLboolean r = GL_FALSE; + + r = ((glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC)glewGetProcAddress((const GLubyte*)"glGetInternalformati64v")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_internalformat_query2 */ + +#ifdef GL_ARB_invalidate_subdata + +static GLboolean _glewInit_GL_ARB_invalidate_subdata () +{ + GLboolean r = GL_FALSE; + + r = ((glInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glInvalidateBufferData")) == NULL) || r; + r = ((glInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glInvalidateBufferSubData")) == NULL) || r; + r = ((glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)glewGetProcAddress((const GLubyte*)"glInvalidateFramebuffer")) == NULL) || r; + r = ((glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)glewGetProcAddress((const GLubyte*)"glInvalidateSubFramebuffer")) == NULL) || r; + r = ((glInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glInvalidateTexImage")) == NULL) || r; + r = ((glInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC)glewGetProcAddress((const GLubyte*)"glInvalidateTexSubImage")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_invalidate_subdata */ + +#ifdef GL_ARB_map_buffer_range + +static GLboolean _glewInit_GL_ARB_map_buffer_range () +{ + GLboolean r = GL_FALSE; + + r = ((glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glFlushMappedBufferRange")) == NULL) || r; + r = ((glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glMapBufferRange")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_map_buffer_range */ + +#ifdef GL_ARB_matrix_palette + +static GLboolean _glewInit_GL_ARB_matrix_palette () +{ + GLboolean r = GL_FALSE; + + r = ((glCurrentPaletteMatrixARB = (PFNGLCURRENTPALETTEMATRIXARBPROC)glewGetProcAddress((const GLubyte*)"glCurrentPaletteMatrixARB")) == NULL) || r; + r = ((glMatrixIndexPointerARB = (PFNGLMATRIXINDEXPOINTERARBPROC)glewGetProcAddress((const GLubyte*)"glMatrixIndexPointerARB")) == NULL) || r; + r = ((glMatrixIndexubvARB = (PFNGLMATRIXINDEXUBVARBPROC)glewGetProcAddress((const GLubyte*)"glMatrixIndexubvARB")) == NULL) || r; + r = ((glMatrixIndexuivARB = (PFNGLMATRIXINDEXUIVARBPROC)glewGetProcAddress((const GLubyte*)"glMatrixIndexuivARB")) == NULL) || r; + r = ((glMatrixIndexusvARB = (PFNGLMATRIXINDEXUSVARBPROC)glewGetProcAddress((const GLubyte*)"glMatrixIndexusvARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_matrix_palette */ + +#ifdef GL_ARB_multi_bind + +static GLboolean _glewInit_GL_ARB_multi_bind () +{ + GLboolean r = GL_FALSE; + + r = ((glBindBuffersBase = (PFNGLBINDBUFFERSBASEPROC)glewGetProcAddress((const GLubyte*)"glBindBuffersBase")) == NULL) || r; + r = ((glBindBuffersRange = (PFNGLBINDBUFFERSRANGEPROC)glewGetProcAddress((const GLubyte*)"glBindBuffersRange")) == NULL) || r; + r = ((glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)glewGetProcAddress((const GLubyte*)"glBindImageTextures")) == NULL) || r; + r = ((glBindSamplers = (PFNGLBINDSAMPLERSPROC)glewGetProcAddress((const GLubyte*)"glBindSamplers")) == NULL) || r; + r = ((glBindTextures = (PFNGLBINDTEXTURESPROC)glewGetProcAddress((const GLubyte*)"glBindTextures")) == NULL) || r; + r = ((glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glBindVertexBuffers")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_multi_bind */ + +#ifdef GL_ARB_multi_draw_indirect + +static GLboolean _glewInit_GL_ARB_multi_draw_indirect () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirect")) == NULL) || r; + r = ((glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirect")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_multi_draw_indirect */ + +#ifdef GL_ARB_multisample + +static GLboolean _glewInit_GL_ARB_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC)glewGetProcAddress((const GLubyte*)"glSampleCoverageARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_multisample */ + +#ifdef GL_ARB_multitexture + +static GLboolean _glewInit_GL_ARB_multitexture () +{ + GLboolean r = GL_FALSE; + + r = ((glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)glewGetProcAddress((const GLubyte*)"glActiveTextureARB")) == NULL) || r; + r = ((glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)glewGetProcAddress((const GLubyte*)"glClientActiveTextureARB")) == NULL) || r; + r = ((glMultiTexCoord1dARB = (PFNGLMULTITEXCOORD1DARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1dARB")) == NULL) || r; + r = ((glMultiTexCoord1dvARB = (PFNGLMULTITEXCOORD1DVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1dvARB")) == NULL) || r; + r = ((glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1fARB")) == NULL) || r; + r = ((glMultiTexCoord1fvARB = (PFNGLMULTITEXCOORD1FVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1fvARB")) == NULL) || r; + r = ((glMultiTexCoord1iARB = (PFNGLMULTITEXCOORD1IARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1iARB")) == NULL) || r; + r = ((glMultiTexCoord1ivARB = (PFNGLMULTITEXCOORD1IVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1ivARB")) == NULL) || r; + r = ((glMultiTexCoord1sARB = (PFNGLMULTITEXCOORD1SARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1sARB")) == NULL) || r; + r = ((glMultiTexCoord1svARB = (PFNGLMULTITEXCOORD1SVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1svARB")) == NULL) || r; + r = ((glMultiTexCoord2dARB = (PFNGLMULTITEXCOORD2DARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2dARB")) == NULL) || r; + r = ((glMultiTexCoord2dvARB = (PFNGLMULTITEXCOORD2DVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2dvARB")) == NULL) || r; + r = ((glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2fARB")) == NULL) || r; + r = ((glMultiTexCoord2fvARB = (PFNGLMULTITEXCOORD2FVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2fvARB")) == NULL) || r; + r = ((glMultiTexCoord2iARB = (PFNGLMULTITEXCOORD2IARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2iARB")) == NULL) || r; + r = ((glMultiTexCoord2ivARB = (PFNGLMULTITEXCOORD2IVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2ivARB")) == NULL) || r; + r = ((glMultiTexCoord2sARB = (PFNGLMULTITEXCOORD2SARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2sARB")) == NULL) || r; + r = ((glMultiTexCoord2svARB = (PFNGLMULTITEXCOORD2SVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2svARB")) == NULL) || r; + r = ((glMultiTexCoord3dARB = (PFNGLMULTITEXCOORD3DARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3dARB")) == NULL) || r; + r = ((glMultiTexCoord3dvARB = (PFNGLMULTITEXCOORD3DVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3dvARB")) == NULL) || r; + r = ((glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3fARB")) == NULL) || r; + r = ((glMultiTexCoord3fvARB = (PFNGLMULTITEXCOORD3FVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3fvARB")) == NULL) || r; + r = ((glMultiTexCoord3iARB = (PFNGLMULTITEXCOORD3IARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3iARB")) == NULL) || r; + r = ((glMultiTexCoord3ivARB = (PFNGLMULTITEXCOORD3IVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3ivARB")) == NULL) || r; + r = ((glMultiTexCoord3sARB = (PFNGLMULTITEXCOORD3SARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3sARB")) == NULL) || r; + r = ((glMultiTexCoord3svARB = (PFNGLMULTITEXCOORD3SVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3svARB")) == NULL) || r; + r = ((glMultiTexCoord4dARB = (PFNGLMULTITEXCOORD4DARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4dARB")) == NULL) || r; + r = ((glMultiTexCoord4dvARB = (PFNGLMULTITEXCOORD4DVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4dvARB")) == NULL) || r; + r = ((glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4fARB")) == NULL) || r; + r = ((glMultiTexCoord4fvARB = (PFNGLMULTITEXCOORD4FVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4fvARB")) == NULL) || r; + r = ((glMultiTexCoord4iARB = (PFNGLMULTITEXCOORD4IARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4iARB")) == NULL) || r; + r = ((glMultiTexCoord4ivARB = (PFNGLMULTITEXCOORD4IVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4ivARB")) == NULL) || r; + r = ((glMultiTexCoord4sARB = (PFNGLMULTITEXCOORD4SARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4sARB")) == NULL) || r; + r = ((glMultiTexCoord4svARB = (PFNGLMULTITEXCOORD4SVARBPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4svARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_multitexture */ + +#ifdef GL_ARB_occlusion_query + +static GLboolean _glewInit_GL_ARB_occlusion_query () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginQueryARB = (PFNGLBEGINQUERYARBPROC)glewGetProcAddress((const GLubyte*)"glBeginQueryARB")) == NULL) || r; + r = ((glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)glewGetProcAddress((const GLubyte*)"glDeleteQueriesARB")) == NULL) || r; + r = ((glEndQueryARB = (PFNGLENDQUERYARBPROC)glewGetProcAddress((const GLubyte*)"glEndQueryARB")) == NULL) || r; + r = ((glGenQueriesARB = (PFNGLGENQUERIESARBPROC)glewGetProcAddress((const GLubyte*)"glGenQueriesARB")) == NULL) || r; + r = ((glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectivARB")) == NULL) || r; + r = ((glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectuivARB")) == NULL) || r; + r = ((glGetQueryivARB = (PFNGLGETQUERYIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetQueryivARB")) == NULL) || r; + r = ((glIsQueryARB = (PFNGLISQUERYARBPROC)glewGetProcAddress((const GLubyte*)"glIsQueryARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_occlusion_query */ + +#ifdef GL_ARB_parallel_shader_compile + +static GLboolean _glewInit_GL_ARB_parallel_shader_compile () +{ + GLboolean r = GL_FALSE; + + r = ((glMaxShaderCompilerThreadsARB = (PFNGLMAXSHADERCOMPILERTHREADSARBPROC)glewGetProcAddress((const GLubyte*)"glMaxShaderCompilerThreadsARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_parallel_shader_compile */ + +#ifdef GL_ARB_point_parameters + +static GLboolean _glewInit_GL_ARB_point_parameters () +{ + GLboolean r = GL_FALSE; + + r = ((glPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)glewGetProcAddress((const GLubyte*)"glPointParameterfARB")) == NULL) || r; + r = ((glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)glewGetProcAddress((const GLubyte*)"glPointParameterfvARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_point_parameters */ + +#ifdef GL_ARB_polygon_offset_clamp + +static GLboolean _glewInit_GL_ARB_polygon_offset_clamp () +{ + GLboolean r = GL_FALSE; + + r = ((glPolygonOffsetClamp = (PFNGLPOLYGONOFFSETCLAMPPROC)glewGetProcAddress((const GLubyte*)"glPolygonOffsetClamp")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_polygon_offset_clamp */ + +#ifdef GL_ARB_program_interface_query + +static GLboolean _glewInit_GL_ARB_program_interface_query () +{ + GLboolean r = GL_FALSE; + + r = ((glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramInterfaceiv")) == NULL) || r; + r = ((glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourceIndex")) == NULL) || r; + r = ((glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourceLocation")) == NULL) || r; + r = ((glGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourceLocationIndex")) == NULL) || r; + r = ((glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourceName")) == NULL) || r; + r = ((glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourceiv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_program_interface_query */ + +#ifdef GL_ARB_provoking_vertex + +static GLboolean _glewInit_GL_ARB_provoking_vertex () +{ + GLboolean r = GL_FALSE; + + r = ((glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)glewGetProcAddress((const GLubyte*)"glProvokingVertex")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_provoking_vertex */ + +#ifdef GL_ARB_robustness + +static GLboolean _glewInit_GL_ARB_robustness () +{ + GLboolean r = GL_FALSE; + + r = ((glGetGraphicsResetStatusARB = (PFNGLGETGRAPHICSRESETSTATUSARBPROC)glewGetProcAddress((const GLubyte*)"glGetGraphicsResetStatusARB")) == NULL) || r; + r = ((glGetnColorTableARB = (PFNGLGETNCOLORTABLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetnColorTableARB")) == NULL) || r; + r = ((glGetnCompressedTexImageARB = (PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)glewGetProcAddress((const GLubyte*)"glGetnCompressedTexImageARB")) == NULL) || r; + r = ((glGetnConvolutionFilterARB = (PFNGLGETNCONVOLUTIONFILTERARBPROC)glewGetProcAddress((const GLubyte*)"glGetnConvolutionFilterARB")) == NULL) || r; + r = ((glGetnHistogramARB = (PFNGLGETNHISTOGRAMARBPROC)glewGetProcAddress((const GLubyte*)"glGetnHistogramARB")) == NULL) || r; + r = ((glGetnMapdvARB = (PFNGLGETNMAPDVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnMapdvARB")) == NULL) || r; + r = ((glGetnMapfvARB = (PFNGLGETNMAPFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnMapfvARB")) == NULL) || r; + r = ((glGetnMapivARB = (PFNGLGETNMAPIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnMapivARB")) == NULL) || r; + r = ((glGetnMinmaxARB = (PFNGLGETNMINMAXARBPROC)glewGetProcAddress((const GLubyte*)"glGetnMinmaxARB")) == NULL) || r; + r = ((glGetnPixelMapfvARB = (PFNGLGETNPIXELMAPFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnPixelMapfvARB")) == NULL) || r; + r = ((glGetnPixelMapuivARB = (PFNGLGETNPIXELMAPUIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnPixelMapuivARB")) == NULL) || r; + r = ((glGetnPixelMapusvARB = (PFNGLGETNPIXELMAPUSVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnPixelMapusvARB")) == NULL) || r; + r = ((glGetnPolygonStippleARB = (PFNGLGETNPOLYGONSTIPPLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetnPolygonStippleARB")) == NULL) || r; + r = ((glGetnSeparableFilterARB = (PFNGLGETNSEPARABLEFILTERARBPROC)glewGetProcAddress((const GLubyte*)"glGetnSeparableFilterARB")) == NULL) || r; + r = ((glGetnTexImageARB = (PFNGLGETNTEXIMAGEARBPROC)glewGetProcAddress((const GLubyte*)"glGetnTexImageARB")) == NULL) || r; + r = ((glGetnUniformdvARB = (PFNGLGETNUNIFORMDVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformdvARB")) == NULL) || r; + r = ((glGetnUniformfvARB = (PFNGLGETNUNIFORMFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformfvARB")) == NULL) || r; + r = ((glGetnUniformivARB = (PFNGLGETNUNIFORMIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformivARB")) == NULL) || r; + r = ((glGetnUniformuivARB = (PFNGLGETNUNIFORMUIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformuivARB")) == NULL) || r; + r = ((glReadnPixelsARB = (PFNGLREADNPIXELSARBPROC)glewGetProcAddress((const GLubyte*)"glReadnPixelsARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_robustness */ + +#ifdef GL_ARB_sample_locations + +static GLboolean _glewInit_GL_ARB_sample_locations () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferSampleLocationsfvARB = (PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)glewGetProcAddress((const GLubyte*)"glFramebufferSampleLocationsfvARB")) == NULL) || r; + r = ((glNamedFramebufferSampleLocationsfvARB = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferSampleLocationsfvARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_sample_locations */ + +#ifdef GL_ARB_sample_shading + +static GLboolean _glewInit_GL_ARB_sample_shading () +{ + GLboolean r = GL_FALSE; + + r = ((glMinSampleShadingARB = (PFNGLMINSAMPLESHADINGARBPROC)glewGetProcAddress((const GLubyte*)"glMinSampleShadingARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_sample_shading */ + +#ifdef GL_ARB_sampler_objects + +static GLboolean _glewInit_GL_ARB_sampler_objects () +{ + GLboolean r = GL_FALSE; + + r = ((glBindSampler = (PFNGLBINDSAMPLERPROC)glewGetProcAddress((const GLubyte*)"glBindSampler")) == NULL) || r; + r = ((glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)glewGetProcAddress((const GLubyte*)"glDeleteSamplers")) == NULL) || r; + r = ((glGenSamplers = (PFNGLGENSAMPLERSPROC)glewGetProcAddress((const GLubyte*)"glGenSamplers")) == NULL) || r; + r = ((glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glGetSamplerParameterIiv")) == NULL) || r; + r = ((glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glGetSamplerParameterIuiv")) == NULL) || r; + r = ((glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetSamplerParameterfv")) == NULL) || r; + r = ((glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetSamplerParameteriv")) == NULL) || r; + r = ((glIsSampler = (PFNGLISSAMPLERPROC)glewGetProcAddress((const GLubyte*)"glIsSampler")) == NULL) || r; + r = ((glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glSamplerParameterIiv")) == NULL) || r; + r = ((glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glSamplerParameterIuiv")) == NULL) || r; + r = ((glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)glewGetProcAddress((const GLubyte*)"glSamplerParameterf")) == NULL) || r; + r = ((glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glSamplerParameterfv")) == NULL) || r; + r = ((glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glSamplerParameteri")) == NULL) || r; + r = ((glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glSamplerParameteriv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_sampler_objects */ + +#ifdef GL_ARB_separate_shader_objects + +static GLboolean _glewInit_GL_ARB_separate_shader_objects () +{ + GLboolean r = GL_FALSE; + + r = ((glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)glewGetProcAddress((const GLubyte*)"glActiveShaderProgram")) == NULL) || r; + r = ((glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)glewGetProcAddress((const GLubyte*)"glBindProgramPipeline")) == NULL) || r; + r = ((glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)glewGetProcAddress((const GLubyte*)"glCreateShaderProgramv")) == NULL) || r; + r = ((glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)glewGetProcAddress((const GLubyte*)"glDeleteProgramPipelines")) == NULL) || r; + r = ((glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)glewGetProcAddress((const GLubyte*)"glGenProgramPipelines")) == NULL) || r; + r = ((glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)glewGetProcAddress((const GLubyte*)"glGetProgramPipelineInfoLog")) == NULL) || r; + r = ((glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramPipelineiv")) == NULL) || r; + r = ((glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)glewGetProcAddress((const GLubyte*)"glIsProgramPipeline")) == NULL) || r; + r = ((glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1d")) == NULL) || r; + r = ((glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1dv")) == NULL) || r; + r = ((glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1f")) == NULL) || r; + r = ((glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1fv")) == NULL) || r; + r = ((glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1i")) == NULL) || r; + r = ((glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1iv")) == NULL) || r; + r = ((glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ui")) == NULL) || r; + r = ((glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1uiv")) == NULL) || r; + r = ((glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2d")) == NULL) || r; + r = ((glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2dv")) == NULL) || r; + r = ((glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2f")) == NULL) || r; + r = ((glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2fv")) == NULL) || r; + r = ((glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2i")) == NULL) || r; + r = ((glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2iv")) == NULL) || r; + r = ((glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ui")) == NULL) || r; + r = ((glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2uiv")) == NULL) || r; + r = ((glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3d")) == NULL) || r; + r = ((glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3dv")) == NULL) || r; + r = ((glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3f")) == NULL) || r; + r = ((glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3fv")) == NULL) || r; + r = ((glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3i")) == NULL) || r; + r = ((glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3iv")) == NULL) || r; + r = ((glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ui")) == NULL) || r; + r = ((glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3uiv")) == NULL) || r; + r = ((glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4d")) == NULL) || r; + r = ((glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4dv")) == NULL) || r; + r = ((glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4f")) == NULL) || r; + r = ((glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4fv")) == NULL) || r; + r = ((glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4i")) == NULL) || r; + r = ((glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4iv")) == NULL) || r; + r = ((glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ui")) == NULL) || r; + r = ((glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4uiv")) == NULL) || r; + r = ((glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2dv")) == NULL) || r; + r = ((glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2fv")) == NULL) || r; + r = ((glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x3dv")) == NULL) || r; + r = ((glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x3fv")) == NULL) || r; + r = ((glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x4dv")) == NULL) || r; + r = ((glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x4fv")) == NULL) || r; + r = ((glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3dv")) == NULL) || r; + r = ((glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3fv")) == NULL) || r; + r = ((glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x2dv")) == NULL) || r; + r = ((glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x2fv")) == NULL) || r; + r = ((glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x4dv")) == NULL) || r; + r = ((glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x4fv")) == NULL) || r; + r = ((glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4dv")) == NULL) || r; + r = ((glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4fv")) == NULL) || r; + r = ((glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x2dv")) == NULL) || r; + r = ((glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x2fv")) == NULL) || r; + r = ((glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x3dv")) == NULL) || r; + r = ((glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x3fv")) == NULL) || r; + r = ((glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)glewGetProcAddress((const GLubyte*)"glUseProgramStages")) == NULL) || r; + r = ((glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)glewGetProcAddress((const GLubyte*)"glValidateProgramPipeline")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_separate_shader_objects */ + +#ifdef GL_ARB_shader_atomic_counters + +static GLboolean _glewInit_GL_ARB_shader_atomic_counters () +{ + GLboolean r = GL_FALSE; + + r = ((glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)glewGetProcAddress((const GLubyte*)"glGetActiveAtomicCounterBufferiv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_shader_atomic_counters */ + +#ifdef GL_ARB_shader_image_load_store + +static GLboolean _glewInit_GL_ARB_shader_image_load_store () +{ + GLboolean r = GL_FALSE; + + r = ((glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)glewGetProcAddress((const GLubyte*)"glBindImageTexture")) == NULL) || r; + r = ((glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)glewGetProcAddress((const GLubyte*)"glMemoryBarrier")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_shader_image_load_store */ + +#ifdef GL_ARB_shader_objects + +static GLboolean _glewInit_GL_ARB_shader_objects () +{ + GLboolean r = GL_FALSE; + + r = ((glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)glewGetProcAddress((const GLubyte*)"glAttachObjectARB")) == NULL) || r; + r = ((glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)glewGetProcAddress((const GLubyte*)"glCompileShaderARB")) == NULL) || r; + r = ((glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)glewGetProcAddress((const GLubyte*)"glCreateProgramObjectARB")) == NULL) || r; + r = ((glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)glewGetProcAddress((const GLubyte*)"glCreateShaderObjectARB")) == NULL) || r; + r = ((glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)glewGetProcAddress((const GLubyte*)"glDeleteObjectARB")) == NULL) || r; + r = ((glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC)glewGetProcAddress((const GLubyte*)"glDetachObjectARB")) == NULL) || r; + r = ((glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC)glewGetProcAddress((const GLubyte*)"glGetActiveUniformARB")) == NULL) || r; + r = ((glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC)glewGetProcAddress((const GLubyte*)"glGetAttachedObjectsARB")) == NULL) || r; + r = ((glGetHandleARB = (PFNGLGETHANDLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetHandleARB")) == NULL) || r; + r = ((glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)glewGetProcAddress((const GLubyte*)"glGetInfoLogARB")) == NULL) || r; + r = ((glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetObjectParameterfvARB")) == NULL) || r; + r = ((glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetObjectParameterivARB")) == NULL) || r; + r = ((glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC)glewGetProcAddress((const GLubyte*)"glGetShaderSourceARB")) == NULL) || r; + r = ((glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)glewGetProcAddress((const GLubyte*)"glGetUniformLocationARB")) == NULL) || r; + r = ((glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetUniformfvARB")) == NULL) || r; + r = ((glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetUniformivARB")) == NULL) || r; + r = ((glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)glewGetProcAddress((const GLubyte*)"glLinkProgramARB")) == NULL) || r; + r = ((glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)glewGetProcAddress((const GLubyte*)"glShaderSourceARB")) == NULL) || r; + r = ((glUniform1fARB = (PFNGLUNIFORM1FARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1fARB")) == NULL) || r; + r = ((glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1fvARB")) == NULL) || r; + r = ((glUniform1iARB = (PFNGLUNIFORM1IARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1iARB")) == NULL) || r; + r = ((glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1ivARB")) == NULL) || r; + r = ((glUniform2fARB = (PFNGLUNIFORM2FARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2fARB")) == NULL) || r; + r = ((glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2fvARB")) == NULL) || r; + r = ((glUniform2iARB = (PFNGLUNIFORM2IARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2iARB")) == NULL) || r; + r = ((glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2ivARB")) == NULL) || r; + r = ((glUniform3fARB = (PFNGLUNIFORM3FARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3fARB")) == NULL) || r; + r = ((glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3fvARB")) == NULL) || r; + r = ((glUniform3iARB = (PFNGLUNIFORM3IARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3iARB")) == NULL) || r; + r = ((glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3ivARB")) == NULL) || r; + r = ((glUniform4fARB = (PFNGLUNIFORM4FARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4fARB")) == NULL) || r; + r = ((glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4fvARB")) == NULL) || r; + r = ((glUniform4iARB = (PFNGLUNIFORM4IARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4iARB")) == NULL) || r; + r = ((glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4ivARB")) == NULL) || r; + r = ((glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2fvARB")) == NULL) || r; + r = ((glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3fvARB")) == NULL) || r; + r = ((glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4fvARB")) == NULL) || r; + r = ((glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)glewGetProcAddress((const GLubyte*)"glUseProgramObjectARB")) == NULL) || r; + r = ((glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC)glewGetProcAddress((const GLubyte*)"glValidateProgramARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_shader_objects */ + +#ifdef GL_ARB_shader_storage_buffer_object + +static GLboolean _glewInit_GL_ARB_shader_storage_buffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC)glewGetProcAddress((const GLubyte*)"glShaderStorageBlockBinding")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_shader_storage_buffer_object */ + +#ifdef GL_ARB_shader_subroutine + +static GLboolean _glewInit_GL_ARB_shader_subroutine () +{ + GLboolean r = GL_FALSE; + + r = ((glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC)glewGetProcAddress((const GLubyte*)"glGetActiveSubroutineName")) == NULL) || r; + r = ((glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)glewGetProcAddress((const GLubyte*)"glGetActiveSubroutineUniformName")) == NULL) || r; + r = ((glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)glewGetProcAddress((const GLubyte*)"glGetActiveSubroutineUniformiv")) == NULL) || r; + r = ((glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramStageiv")) == NULL) || r; + r = ((glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC)glewGetProcAddress((const GLubyte*)"glGetSubroutineIndex")) == NULL) || r; + r = ((glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)glewGetProcAddress((const GLubyte*)"glGetSubroutineUniformLocation")) == NULL) || r; + r = ((glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC)glewGetProcAddress((const GLubyte*)"glGetUniformSubroutineuiv")) == NULL) || r; + r = ((glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC)glewGetProcAddress((const GLubyte*)"glUniformSubroutinesuiv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_shader_subroutine */ + +#ifdef GL_ARB_shading_language_include + +static GLboolean _glewInit_GL_ARB_shading_language_include () +{ + GLboolean r = GL_FALSE; + + r = ((glCompileShaderIncludeARB = (PFNGLCOMPILESHADERINCLUDEARBPROC)glewGetProcAddress((const GLubyte*)"glCompileShaderIncludeARB")) == NULL) || r; + r = ((glDeleteNamedStringARB = (PFNGLDELETENAMEDSTRINGARBPROC)glewGetProcAddress((const GLubyte*)"glDeleteNamedStringARB")) == NULL) || r; + r = ((glGetNamedStringARB = (PFNGLGETNAMEDSTRINGARBPROC)glewGetProcAddress((const GLubyte*)"glGetNamedStringARB")) == NULL) || r; + r = ((glGetNamedStringivARB = (PFNGLGETNAMEDSTRINGIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetNamedStringivARB")) == NULL) || r; + r = ((glIsNamedStringARB = (PFNGLISNAMEDSTRINGARBPROC)glewGetProcAddress((const GLubyte*)"glIsNamedStringARB")) == NULL) || r; + r = ((glNamedStringARB = (PFNGLNAMEDSTRINGARBPROC)glewGetProcAddress((const GLubyte*)"glNamedStringARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_shading_language_include */ + +#ifdef GL_ARB_sparse_buffer + +static GLboolean _glewInit_GL_ARB_sparse_buffer () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferPageCommitmentARB = (PFNGLBUFFERPAGECOMMITMENTARBPROC)glewGetProcAddress((const GLubyte*)"glBufferPageCommitmentARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_sparse_buffer */ + +#ifdef GL_ARB_sparse_texture + +static GLboolean _glewInit_GL_ARB_sparse_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glTexPageCommitmentARB = (PFNGLTEXPAGECOMMITMENTARBPROC)glewGetProcAddress((const GLubyte*)"glTexPageCommitmentARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_sparse_texture */ + +#ifdef GL_ARB_sync + +static GLboolean _glewInit_GL_ARB_sync () +{ + GLboolean r = GL_FALSE; + + r = ((glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)glewGetProcAddress((const GLubyte*)"glClientWaitSync")) == NULL) || r; + r = ((glDeleteSync = (PFNGLDELETESYNCPROC)glewGetProcAddress((const GLubyte*)"glDeleteSync")) == NULL) || r; + r = ((glFenceSync = (PFNGLFENCESYNCPROC)glewGetProcAddress((const GLubyte*)"glFenceSync")) == NULL) || r; + r = ((glGetInteger64v = (PFNGLGETINTEGER64VPROC)glewGetProcAddress((const GLubyte*)"glGetInteger64v")) == NULL) || r; + r = ((glGetSynciv = (PFNGLGETSYNCIVPROC)glewGetProcAddress((const GLubyte*)"glGetSynciv")) == NULL) || r; + r = ((glIsSync = (PFNGLISSYNCPROC)glewGetProcAddress((const GLubyte*)"glIsSync")) == NULL) || r; + r = ((glWaitSync = (PFNGLWAITSYNCPROC)glewGetProcAddress((const GLubyte*)"glWaitSync")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_sync */ + +#ifdef GL_ARB_tessellation_shader + +static GLboolean _glewInit_GL_ARB_tessellation_shader () +{ + GLboolean r = GL_FALSE; + + r = ((glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glPatchParameterfv")) == NULL) || r; + r = ((glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glPatchParameteri")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_tessellation_shader */ + +#ifdef GL_ARB_texture_barrier + +static GLboolean _glewInit_GL_ARB_texture_barrier () +{ + GLboolean r = GL_FALSE; + + r = ((glTextureBarrier = (PFNGLTEXTUREBARRIERPROC)glewGetProcAddress((const GLubyte*)"glTextureBarrier")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_barrier */ + +#ifdef GL_ARB_texture_buffer_object + +static GLboolean _glewInit_GL_ARB_texture_buffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glTexBufferARB = (PFNGLTEXBUFFERARBPROC)glewGetProcAddress((const GLubyte*)"glTexBufferARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_buffer_object */ + +#ifdef GL_ARB_texture_buffer_range + +static GLboolean _glewInit_GL_ARB_texture_buffer_range () +{ + GLboolean r = GL_FALSE; + + r = ((glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glTexBufferRange")) == NULL) || r; + r = ((glTextureBufferRangeEXT = (PFNGLTEXTUREBUFFERRANGEEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureBufferRangeEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_buffer_range */ + +#ifdef GL_ARB_texture_compression + +static GLboolean _glewInit_GL_ARB_texture_compression () +{ + GLboolean r = GL_FALSE; + + r = ((glCompressedTexImage1DARB = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexImage1DARB")) == NULL) || r; + r = ((glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexImage2DARB")) == NULL) || r; + r = ((glCompressedTexImage3DARB = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexImage3DARB")) == NULL) || r; + r = ((glCompressedTexSubImage1DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexSubImage1DARB")) == NULL) || r; + r = ((glCompressedTexSubImage2DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexSubImage2DARB")) == NULL) || r; + r = ((glCompressedTexSubImage3DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexSubImage3DARB")) == NULL) || r; + r = ((glGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedTexImageARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_compression */ + +#ifdef GL_ARB_texture_multisample + +static GLboolean _glewInit_GL_ARB_texture_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)glewGetProcAddress((const GLubyte*)"glGetMultisamplefv")) == NULL) || r; + r = ((glSampleMaski = (PFNGLSAMPLEMASKIPROC)glewGetProcAddress((const GLubyte*)"glSampleMaski")) == NULL) || r; + r = ((glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTexImage2DMultisample")) == NULL) || r; + r = ((glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTexImage3DMultisample")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_multisample */ + +#ifdef GL_ARB_texture_storage + +static GLboolean _glewInit_GL_ARB_texture_storage () +{ + GLboolean r = GL_FALSE; + + r = ((glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)glewGetProcAddress((const GLubyte*)"glTexStorage1D")) == NULL) || r; + r = ((glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)glewGetProcAddress((const GLubyte*)"glTexStorage2D")) == NULL) || r; + r = ((glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)glewGetProcAddress((const GLubyte*)"glTexStorage3D")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_storage */ + +#ifdef GL_ARB_texture_storage_multisample + +static GLboolean _glewInit_GL_ARB_texture_storage_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTexStorage2DMultisample")) == NULL) || r; + r = ((glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTexStorage3DMultisample")) == NULL) || r; + r = ((glTextureStorage2DMultisampleEXT = (PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage2DMultisampleEXT")) == NULL) || r; + r = ((glTextureStorage3DMultisampleEXT = (PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage3DMultisampleEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_storage_multisample */ + +#ifdef GL_ARB_texture_view + +static GLboolean _glewInit_GL_ARB_texture_view () +{ + GLboolean r = GL_FALSE; + + r = ((glTextureView = (PFNGLTEXTUREVIEWPROC)glewGetProcAddress((const GLubyte*)"glTextureView")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_texture_view */ + +#ifdef GL_ARB_timer_query + +static GLboolean _glewInit_GL_ARB_timer_query () +{ + GLboolean r = GL_FALSE; + + r = ((glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjecti64v")) == NULL) || r; + r = ((glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectui64v")) == NULL) || r; + r = ((glQueryCounter = (PFNGLQUERYCOUNTERPROC)glewGetProcAddress((const GLubyte*)"glQueryCounter")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_timer_query */ + +#ifdef GL_ARB_transform_feedback2 + +static GLboolean _glewInit_GL_ARB_transform_feedback2 () +{ + GLboolean r = GL_FALSE; + + r = ((glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)glewGetProcAddress((const GLubyte*)"glBindTransformFeedback")) == NULL) || r; + r = ((glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)glewGetProcAddress((const GLubyte*)"glDeleteTransformFeedbacks")) == NULL) || r; + r = ((glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC)glewGetProcAddress((const GLubyte*)"glDrawTransformFeedback")) == NULL) || r; + r = ((glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)glewGetProcAddress((const GLubyte*)"glGenTransformFeedbacks")) == NULL) || r; + r = ((glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)glewGetProcAddress((const GLubyte*)"glIsTransformFeedback")) == NULL) || r; + r = ((glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)glewGetProcAddress((const GLubyte*)"glPauseTransformFeedback")) == NULL) || r; + r = ((glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)glewGetProcAddress((const GLubyte*)"glResumeTransformFeedback")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_transform_feedback2 */ + +#ifdef GL_ARB_transform_feedback3 + +static GLboolean _glewInit_GL_ARB_transform_feedback3 () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC)glewGetProcAddress((const GLubyte*)"glBeginQueryIndexed")) == NULL) || r; + r = ((glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)glewGetProcAddress((const GLubyte*)"glDrawTransformFeedbackStream")) == NULL) || r; + r = ((glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC)glewGetProcAddress((const GLubyte*)"glEndQueryIndexed")) == NULL) || r; + r = ((glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryIndexediv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_transform_feedback3 */ + +#ifdef GL_ARB_transform_feedback_instanced + +static GLboolean _glewInit_GL_ARB_transform_feedback_instanced () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)glewGetProcAddress((const GLubyte*)"glDrawTransformFeedbackInstanced")) == NULL) || r; + r = ((glDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)glewGetProcAddress((const GLubyte*)"glDrawTransformFeedbackStreamInstanced")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_transform_feedback_instanced */ + +#ifdef GL_ARB_transpose_matrix + +static GLboolean _glewInit_GL_ARB_transpose_matrix () +{ + GLboolean r = GL_FALSE; + + r = ((glLoadTransposeMatrixdARB = (PFNGLLOADTRANSPOSEMATRIXDARBPROC)glewGetProcAddress((const GLubyte*)"glLoadTransposeMatrixdARB")) == NULL) || r; + r = ((glLoadTransposeMatrixfARB = (PFNGLLOADTRANSPOSEMATRIXFARBPROC)glewGetProcAddress((const GLubyte*)"glLoadTransposeMatrixfARB")) == NULL) || r; + r = ((glMultTransposeMatrixdARB = (PFNGLMULTTRANSPOSEMATRIXDARBPROC)glewGetProcAddress((const GLubyte*)"glMultTransposeMatrixdARB")) == NULL) || r; + r = ((glMultTransposeMatrixfARB = (PFNGLMULTTRANSPOSEMATRIXFARBPROC)glewGetProcAddress((const GLubyte*)"glMultTransposeMatrixfARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_transpose_matrix */ + +#ifdef GL_ARB_uniform_buffer_object + +static GLboolean _glewInit_GL_ARB_uniform_buffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)glewGetProcAddress((const GLubyte*)"glBindBufferBase")) == NULL) || r; + r = ((glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glBindBufferRange")) == NULL) || r; + r = ((glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)glewGetProcAddress((const GLubyte*)"glGetActiveUniformBlockName")) == NULL) || r; + r = ((glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)glewGetProcAddress((const GLubyte*)"glGetActiveUniformBlockiv")) == NULL) || r; + r = ((glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)glewGetProcAddress((const GLubyte*)"glGetActiveUniformName")) == NULL) || r; + r = ((glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)glewGetProcAddress((const GLubyte*)"glGetActiveUniformsiv")) == NULL) || r; + r = ((glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)glewGetProcAddress((const GLubyte*)"glGetIntegeri_v")) == NULL) || r; + r = ((glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)glewGetProcAddress((const GLubyte*)"glGetUniformBlockIndex")) == NULL) || r; + r = ((glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)glewGetProcAddress((const GLubyte*)"glGetUniformIndices")) == NULL) || r; + r = ((glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)glewGetProcAddress((const GLubyte*)"glUniformBlockBinding")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_uniform_buffer_object */ + +#ifdef GL_ARB_vertex_array_object + +static GLboolean _glewInit_GL_ARB_vertex_array_object () +{ + GLboolean r = GL_FALSE; + + r = ((glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)glewGetProcAddress((const GLubyte*)"glBindVertexArray")) == NULL) || r; + r = ((glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)glewGetProcAddress((const GLubyte*)"glDeleteVertexArrays")) == NULL) || r; + r = ((glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)glewGetProcAddress((const GLubyte*)"glGenVertexArrays")) == NULL) || r; + r = ((glIsVertexArray = (PFNGLISVERTEXARRAYPROC)glewGetProcAddress((const GLubyte*)"glIsVertexArray")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_array_object */ + +#ifdef GL_ARB_vertex_attrib_64bit + +static GLboolean _glewInit_GL_ARB_vertex_attrib_64bit () +{ + GLboolean r = GL_FALSE; + + r = ((glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribLdv")) == NULL) || r; + r = ((glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1d")) == NULL) || r; + r = ((glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1dv")) == NULL) || r; + r = ((glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2d")) == NULL) || r; + r = ((glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2dv")) == NULL) || r; + r = ((glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3d")) == NULL) || r; + r = ((glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3dv")) == NULL) || r; + r = ((glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4d")) == NULL) || r; + r = ((glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4dv")) == NULL) || r; + r = ((glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribLPointer")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_attrib_64bit */ + +#ifdef GL_ARB_vertex_attrib_binding + +static GLboolean _glewInit_GL_ARB_vertex_attrib_binding () +{ + GLboolean r = GL_FALSE; + + r = ((glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBindVertexBuffer")) == NULL) || r; + r = ((glVertexArrayBindVertexBufferEXT = (PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayBindVertexBufferEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribBindingEXT = (PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribBindingEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribFormatEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribIFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribIFormatEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribLFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribLFormatEXT")) == NULL) || r; + r = ((glVertexArrayVertexBindingDivisorEXT = (PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexBindingDivisorEXT")) == NULL) || r; + r = ((glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribBinding")) == NULL) || r; + r = ((glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribFormat")) == NULL) || r; + r = ((glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribIFormat")) == NULL) || r; + r = ((glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribLFormat")) == NULL) || r; + r = ((glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)glewGetProcAddress((const GLubyte*)"glVertexBindingDivisor")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_attrib_binding */ + +#ifdef GL_ARB_vertex_blend + +static GLboolean _glewInit_GL_ARB_vertex_blend () +{ + GLboolean r = GL_FALSE; + + r = ((glVertexBlendARB = (PFNGLVERTEXBLENDARBPROC)glewGetProcAddress((const GLubyte*)"glVertexBlendARB")) == NULL) || r; + r = ((glWeightPointerARB = (PFNGLWEIGHTPOINTERARBPROC)glewGetProcAddress((const GLubyte*)"glWeightPointerARB")) == NULL) || r; + r = ((glWeightbvARB = (PFNGLWEIGHTBVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightbvARB")) == NULL) || r; + r = ((glWeightdvARB = (PFNGLWEIGHTDVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightdvARB")) == NULL) || r; + r = ((glWeightfvARB = (PFNGLWEIGHTFVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightfvARB")) == NULL) || r; + r = ((glWeightivARB = (PFNGLWEIGHTIVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightivARB")) == NULL) || r; + r = ((glWeightsvARB = (PFNGLWEIGHTSVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightsvARB")) == NULL) || r; + r = ((glWeightubvARB = (PFNGLWEIGHTUBVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightubvARB")) == NULL) || r; + r = ((glWeightuivARB = (PFNGLWEIGHTUIVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightuivARB")) == NULL) || r; + r = ((glWeightusvARB = (PFNGLWEIGHTUSVARBPROC)glewGetProcAddress((const GLubyte*)"glWeightusvARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_blend */ + +#ifdef GL_ARB_vertex_buffer_object + +static GLboolean _glewInit_GL_ARB_vertex_buffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glBindBufferARB = (PFNGLBINDBUFFERARBPROC)glewGetProcAddress((const GLubyte*)"glBindBufferARB")) == NULL) || r; + r = ((glBufferDataARB = (PFNGLBUFFERDATAARBPROC)glewGetProcAddress((const GLubyte*)"glBufferDataARB")) == NULL) || r; + r = ((glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)glewGetProcAddress((const GLubyte*)"glBufferSubDataARB")) == NULL) || r; + r = ((glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)glewGetProcAddress((const GLubyte*)"glDeleteBuffersARB")) == NULL) || r; + r = ((glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)glewGetProcAddress((const GLubyte*)"glGenBuffersARB")) == NULL) || r; + r = ((glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetBufferParameterivARB")) == NULL) || r; + r = ((glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)glewGetProcAddress((const GLubyte*)"glGetBufferPointervARB")) == NULL) || r; + r = ((glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)glewGetProcAddress((const GLubyte*)"glGetBufferSubDataARB")) == NULL) || r; + r = ((glIsBufferARB = (PFNGLISBUFFERARBPROC)glewGetProcAddress((const GLubyte*)"glIsBufferARB")) == NULL) || r; + r = ((glMapBufferARB = (PFNGLMAPBUFFERARBPROC)glewGetProcAddress((const GLubyte*)"glMapBufferARB")) == NULL) || r; + r = ((glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)glewGetProcAddress((const GLubyte*)"glUnmapBufferARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_buffer_object */ + +#ifdef GL_ARB_vertex_program + +static GLboolean _glewInit_GL_ARB_vertex_program () +{ + GLboolean r = GL_FALSE; + + r = ((glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)glewGetProcAddress((const GLubyte*)"glBindProgramARB")) == NULL) || r; + r = ((glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)glewGetProcAddress((const GLubyte*)"glDeleteProgramsARB")) == NULL) || r; + r = ((glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)glewGetProcAddress((const GLubyte*)"glDisableVertexAttribArrayARB")) == NULL) || r; + r = ((glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)glewGetProcAddress((const GLubyte*)"glEnableVertexAttribArrayARB")) == NULL) || r; + r = ((glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)glewGetProcAddress((const GLubyte*)"glGenProgramsARB")) == NULL) || r; + r = ((glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)glewGetProcAddress((const GLubyte*)"glGetProgramEnvParameterdvARB")) == NULL) || r; + r = ((glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetProgramEnvParameterfvARB")) == NULL) || r; + r = ((glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)glewGetProcAddress((const GLubyte*)"glGetProgramLocalParameterdvARB")) == NULL) || r; + r = ((glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetProgramLocalParameterfvARB")) == NULL) || r; + r = ((glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)glewGetProcAddress((const GLubyte*)"glGetProgramStringARB")) == NULL) || r; + r = ((glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetProgramivARB")) == NULL) || r; + r = ((glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribPointervARB")) == NULL) || r; + r = ((glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribdvARB")) == NULL) || r; + r = ((glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribfvARB")) == NULL) || r; + r = ((glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribivARB")) == NULL) || r; + r = ((glIsProgramARB = (PFNGLISPROGRAMARBPROC)glewGetProcAddress((const GLubyte*)"glIsProgramARB")) == NULL) || r; + r = ((glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameter4dARB")) == NULL) || r; + r = ((glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameter4dvARB")) == NULL) || r; + r = ((glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameter4fARB")) == NULL) || r; + r = ((glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameter4fvARB")) == NULL) || r; + r = ((glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameter4dARB")) == NULL) || r; + r = ((glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameter4dvARB")) == NULL) || r; + r = ((glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameter4fARB")) == NULL) || r; + r = ((glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameter4fvARB")) == NULL) || r; + r = ((glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)glewGetProcAddress((const GLubyte*)"glProgramStringARB")) == NULL) || r; + r = ((glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1dARB")) == NULL) || r; + r = ((glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1dvARB")) == NULL) || r; + r = ((glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1fARB")) == NULL) || r; + r = ((glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1fvARB")) == NULL) || r; + r = ((glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1sARB")) == NULL) || r; + r = ((glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1svARB")) == NULL) || r; + r = ((glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2dARB")) == NULL) || r; + r = ((glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2dvARB")) == NULL) || r; + r = ((glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2fARB")) == NULL) || r; + r = ((glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2fvARB")) == NULL) || r; + r = ((glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2sARB")) == NULL) || r; + r = ((glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2svARB")) == NULL) || r; + r = ((glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3dARB")) == NULL) || r; + r = ((glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3dvARB")) == NULL) || r; + r = ((glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3fARB")) == NULL) || r; + r = ((glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3fvARB")) == NULL) || r; + r = ((glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3sARB")) == NULL) || r; + r = ((glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3svARB")) == NULL) || r; + r = ((glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4NbvARB")) == NULL) || r; + r = ((glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4NivARB")) == NULL) || r; + r = ((glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4NsvARB")) == NULL) || r; + r = ((glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4NubARB")) == NULL) || r; + r = ((glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4NubvARB")) == NULL) || r; + r = ((glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4NuivARB")) == NULL) || r; + r = ((glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4NusvARB")) == NULL) || r; + r = ((glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4bvARB")) == NULL) || r; + r = ((glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4dARB")) == NULL) || r; + r = ((glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4dvARB")) == NULL) || r; + r = ((glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4fARB")) == NULL) || r; + r = ((glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4fvARB")) == NULL) || r; + r = ((glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4ivARB")) == NULL) || r; + r = ((glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4sARB")) == NULL) || r; + r = ((glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4svARB")) == NULL) || r; + r = ((glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4ubvARB")) == NULL) || r; + r = ((glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4uivARB")) == NULL) || r; + r = ((glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4usvARB")) == NULL) || r; + r = ((glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribPointerARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_program */ + +#ifdef GL_ARB_vertex_shader + +static GLboolean _glewInit_GL_ARB_vertex_shader () +{ + GLboolean r = GL_FALSE; + + r = ((glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)glewGetProcAddress((const GLubyte*)"glBindAttribLocationARB")) == NULL) || r; + r = ((glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC)glewGetProcAddress((const GLubyte*)"glGetActiveAttribARB")) == NULL) || r; + r = ((glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)glewGetProcAddress((const GLubyte*)"glGetAttribLocationARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_shader */ + +#ifdef GL_ARB_vertex_type_2_10_10_10_rev + +static GLboolean _glewInit_GL_ARB_vertex_type_2_10_10_10_rev () +{ + GLboolean r = GL_FALSE; + + r = ((glColorP3ui = (PFNGLCOLORP3UIPROC)glewGetProcAddress((const GLubyte*)"glColorP3ui")) == NULL) || r; + r = ((glColorP3uiv = (PFNGLCOLORP3UIVPROC)glewGetProcAddress((const GLubyte*)"glColorP3uiv")) == NULL) || r; + r = ((glColorP4ui = (PFNGLCOLORP4UIPROC)glewGetProcAddress((const GLubyte*)"glColorP4ui")) == NULL) || r; + r = ((glColorP4uiv = (PFNGLCOLORP4UIVPROC)glewGetProcAddress((const GLubyte*)"glColorP4uiv")) == NULL) || r; + r = ((glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP1ui")) == NULL) || r; + r = ((glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP1uiv")) == NULL) || r; + r = ((glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP2ui")) == NULL) || r; + r = ((glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP2uiv")) == NULL) || r; + r = ((glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP3ui")) == NULL) || r; + r = ((glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP3uiv")) == NULL) || r; + r = ((glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP4ui")) == NULL) || r; + r = ((glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordP4uiv")) == NULL) || r; + r = ((glNormalP3ui = (PFNGLNORMALP3UIPROC)glewGetProcAddress((const GLubyte*)"glNormalP3ui")) == NULL) || r; + r = ((glNormalP3uiv = (PFNGLNORMALP3UIVPROC)glewGetProcAddress((const GLubyte*)"glNormalP3uiv")) == NULL) || r; + r = ((glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColorP3ui")) == NULL) || r; + r = ((glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColorP3uiv")) == NULL) || r; + r = ((glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP1ui")) == NULL) || r; + r = ((glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP1uiv")) == NULL) || r; + r = ((glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP2ui")) == NULL) || r; + r = ((glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP2uiv")) == NULL) || r; + r = ((glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP3ui")) == NULL) || r; + r = ((glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP3uiv")) == NULL) || r; + r = ((glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP4ui")) == NULL) || r; + r = ((glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)glewGetProcAddress((const GLubyte*)"glTexCoordP4uiv")) == NULL) || r; + r = ((glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP1ui")) == NULL) || r; + r = ((glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP1uiv")) == NULL) || r; + r = ((glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP2ui")) == NULL) || r; + r = ((glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP2uiv")) == NULL) || r; + r = ((glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP3ui")) == NULL) || r; + r = ((glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP3uiv")) == NULL) || r; + r = ((glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP4ui")) == NULL) || r; + r = ((glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribP4uiv")) == NULL) || r; + r = ((glVertexP2ui = (PFNGLVERTEXP2UIPROC)glewGetProcAddress((const GLubyte*)"glVertexP2ui")) == NULL) || r; + r = ((glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexP2uiv")) == NULL) || r; + r = ((glVertexP3ui = (PFNGLVERTEXP3UIPROC)glewGetProcAddress((const GLubyte*)"glVertexP3ui")) == NULL) || r; + r = ((glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexP3uiv")) == NULL) || r; + r = ((glVertexP4ui = (PFNGLVERTEXP4UIPROC)glewGetProcAddress((const GLubyte*)"glVertexP4ui")) == NULL) || r; + r = ((glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)glewGetProcAddress((const GLubyte*)"glVertexP4uiv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_vertex_type_2_10_10_10_rev */ + +#ifdef GL_ARB_viewport_array + +static GLboolean _glewInit_GL_ARB_viewport_array () +{ + GLboolean r = GL_FALSE; + + r = ((glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC)glewGetProcAddress((const GLubyte*)"glDepthRangeArrayv")) == NULL) || r; + r = ((glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC)glewGetProcAddress((const GLubyte*)"glDepthRangeIndexed")) == NULL) || r; + r = ((glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC)glewGetProcAddress((const GLubyte*)"glGetDoublei_v")) == NULL) || r; + r = ((glGetFloati_v = (PFNGLGETFLOATI_VPROC)glewGetProcAddress((const GLubyte*)"glGetFloati_v")) == NULL) || r; + r = ((glScissorArrayv = (PFNGLSCISSORARRAYVPROC)glewGetProcAddress((const GLubyte*)"glScissorArrayv")) == NULL) || r; + r = ((glScissorIndexed = (PFNGLSCISSORINDEXEDPROC)glewGetProcAddress((const GLubyte*)"glScissorIndexed")) == NULL) || r; + r = ((glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC)glewGetProcAddress((const GLubyte*)"glScissorIndexedv")) == NULL) || r; + r = ((glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC)glewGetProcAddress((const GLubyte*)"glViewportArrayv")) == NULL) || r; + r = ((glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC)glewGetProcAddress((const GLubyte*)"glViewportIndexedf")) == NULL) || r; + r = ((glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC)glewGetProcAddress((const GLubyte*)"glViewportIndexedfv")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_viewport_array */ + +#ifdef GL_ARB_window_pos + +static GLboolean _glewInit_GL_ARB_window_pos () +{ + GLboolean r = GL_FALSE; + + r = ((glWindowPos2dARB = (PFNGLWINDOWPOS2DARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2dARB")) == NULL) || r; + r = ((glWindowPos2dvARB = (PFNGLWINDOWPOS2DVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2dvARB")) == NULL) || r; + r = ((glWindowPos2fARB = (PFNGLWINDOWPOS2FARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2fARB")) == NULL) || r; + r = ((glWindowPos2fvARB = (PFNGLWINDOWPOS2FVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2fvARB")) == NULL) || r; + r = ((glWindowPos2iARB = (PFNGLWINDOWPOS2IARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2iARB")) == NULL) || r; + r = ((glWindowPos2ivARB = (PFNGLWINDOWPOS2IVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2ivARB")) == NULL) || r; + r = ((glWindowPos2sARB = (PFNGLWINDOWPOS2SARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2sARB")) == NULL) || r; + r = ((glWindowPos2svARB = (PFNGLWINDOWPOS2SVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2svARB")) == NULL) || r; + r = ((glWindowPos3dARB = (PFNGLWINDOWPOS3DARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3dARB")) == NULL) || r; + r = ((glWindowPos3dvARB = (PFNGLWINDOWPOS3DVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3dvARB")) == NULL) || r; + r = ((glWindowPos3fARB = (PFNGLWINDOWPOS3FARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3fARB")) == NULL) || r; + r = ((glWindowPos3fvARB = (PFNGLWINDOWPOS3FVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3fvARB")) == NULL) || r; + r = ((glWindowPos3iARB = (PFNGLWINDOWPOS3IARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3iARB")) == NULL) || r; + r = ((glWindowPos3ivARB = (PFNGLWINDOWPOS3IVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3ivARB")) == NULL) || r; + r = ((glWindowPos3sARB = (PFNGLWINDOWPOS3SARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3sARB")) == NULL) || r; + r = ((glWindowPos3svARB = (PFNGLWINDOWPOS3SVARBPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3svARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_window_pos */ + +#ifdef GL_ATI_draw_buffers + +static GLboolean _glewInit_GL_ATI_draw_buffers () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawBuffersATI = (PFNGLDRAWBUFFERSATIPROC)glewGetProcAddress((const GLubyte*)"glDrawBuffersATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_draw_buffers */ + +#ifdef GL_ATI_element_array + +static GLboolean _glewInit_GL_ATI_element_array () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawElementArrayATI = (PFNGLDRAWELEMENTARRAYATIPROC)glewGetProcAddress((const GLubyte*)"glDrawElementArrayATI")) == NULL) || r; + r = ((glDrawRangeElementArrayATI = (PFNGLDRAWRANGEELEMENTARRAYATIPROC)glewGetProcAddress((const GLubyte*)"glDrawRangeElementArrayATI")) == NULL) || r; + r = ((glElementPointerATI = (PFNGLELEMENTPOINTERATIPROC)glewGetProcAddress((const GLubyte*)"glElementPointerATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_element_array */ + +#ifdef GL_ATI_envmap_bumpmap + +static GLboolean _glewInit_GL_ATI_envmap_bumpmap () +{ + GLboolean r = GL_FALSE; + + r = ((glGetTexBumpParameterfvATI = (PFNGLGETTEXBUMPPARAMETERFVATIPROC)glewGetProcAddress((const GLubyte*)"glGetTexBumpParameterfvATI")) == NULL) || r; + r = ((glGetTexBumpParameterivATI = (PFNGLGETTEXBUMPPARAMETERIVATIPROC)glewGetProcAddress((const GLubyte*)"glGetTexBumpParameterivATI")) == NULL) || r; + r = ((glTexBumpParameterfvATI = (PFNGLTEXBUMPPARAMETERFVATIPROC)glewGetProcAddress((const GLubyte*)"glTexBumpParameterfvATI")) == NULL) || r; + r = ((glTexBumpParameterivATI = (PFNGLTEXBUMPPARAMETERIVATIPROC)glewGetProcAddress((const GLubyte*)"glTexBumpParameterivATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_envmap_bumpmap */ + +#ifdef GL_ATI_fragment_shader + +static GLboolean _glewInit_GL_ATI_fragment_shader () +{ + GLboolean r = GL_FALSE; + + r = ((glAlphaFragmentOp1ATI = (PFNGLALPHAFRAGMENTOP1ATIPROC)glewGetProcAddress((const GLubyte*)"glAlphaFragmentOp1ATI")) == NULL) || r; + r = ((glAlphaFragmentOp2ATI = (PFNGLALPHAFRAGMENTOP2ATIPROC)glewGetProcAddress((const GLubyte*)"glAlphaFragmentOp2ATI")) == NULL) || r; + r = ((glAlphaFragmentOp3ATI = (PFNGLALPHAFRAGMENTOP3ATIPROC)glewGetProcAddress((const GLubyte*)"glAlphaFragmentOp3ATI")) == NULL) || r; + r = ((glBeginFragmentShaderATI = (PFNGLBEGINFRAGMENTSHADERATIPROC)glewGetProcAddress((const GLubyte*)"glBeginFragmentShaderATI")) == NULL) || r; + r = ((glBindFragmentShaderATI = (PFNGLBINDFRAGMENTSHADERATIPROC)glewGetProcAddress((const GLubyte*)"glBindFragmentShaderATI")) == NULL) || r; + r = ((glColorFragmentOp1ATI = (PFNGLCOLORFRAGMENTOP1ATIPROC)glewGetProcAddress((const GLubyte*)"glColorFragmentOp1ATI")) == NULL) || r; + r = ((glColorFragmentOp2ATI = (PFNGLCOLORFRAGMENTOP2ATIPROC)glewGetProcAddress((const GLubyte*)"glColorFragmentOp2ATI")) == NULL) || r; + r = ((glColorFragmentOp3ATI = (PFNGLCOLORFRAGMENTOP3ATIPROC)glewGetProcAddress((const GLubyte*)"glColorFragmentOp3ATI")) == NULL) || r; + r = ((glDeleteFragmentShaderATI = (PFNGLDELETEFRAGMENTSHADERATIPROC)glewGetProcAddress((const GLubyte*)"glDeleteFragmentShaderATI")) == NULL) || r; + r = ((glEndFragmentShaderATI = (PFNGLENDFRAGMENTSHADERATIPROC)glewGetProcAddress((const GLubyte*)"glEndFragmentShaderATI")) == NULL) || r; + r = ((glGenFragmentShadersATI = (PFNGLGENFRAGMENTSHADERSATIPROC)glewGetProcAddress((const GLubyte*)"glGenFragmentShadersATI")) == NULL) || r; + r = ((glPassTexCoordATI = (PFNGLPASSTEXCOORDATIPROC)glewGetProcAddress((const GLubyte*)"glPassTexCoordATI")) == NULL) || r; + r = ((glSampleMapATI = (PFNGLSAMPLEMAPATIPROC)glewGetProcAddress((const GLubyte*)"glSampleMapATI")) == NULL) || r; + r = ((glSetFragmentShaderConstantATI = (PFNGLSETFRAGMENTSHADERCONSTANTATIPROC)glewGetProcAddress((const GLubyte*)"glSetFragmentShaderConstantATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_fragment_shader */ + +#ifdef GL_ATI_map_object_buffer + +static GLboolean _glewInit_GL_ATI_map_object_buffer () +{ + GLboolean r = GL_FALSE; + + r = ((glMapObjectBufferATI = (PFNGLMAPOBJECTBUFFERATIPROC)glewGetProcAddress((const GLubyte*)"glMapObjectBufferATI")) == NULL) || r; + r = ((glUnmapObjectBufferATI = (PFNGLUNMAPOBJECTBUFFERATIPROC)glewGetProcAddress((const GLubyte*)"glUnmapObjectBufferATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_map_object_buffer */ + +#ifdef GL_ATI_pn_triangles + +static GLboolean _glewInit_GL_ATI_pn_triangles () +{ + GLboolean r = GL_FALSE; + + r = ((glPNTrianglesfATI = (PFNGLPNTRIANGLESFATIPROC)glewGetProcAddress((const GLubyte*)"glPNTrianglesfATI")) == NULL) || r; + r = ((glPNTrianglesiATI = (PFNGLPNTRIANGLESIATIPROC)glewGetProcAddress((const GLubyte*)"glPNTrianglesiATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_pn_triangles */ + +#ifdef GL_ATI_separate_stencil + +static GLboolean _glewInit_GL_ATI_separate_stencil () +{ + GLboolean r = GL_FALSE; + + r = ((glStencilFuncSeparateATI = (PFNGLSTENCILFUNCSEPARATEATIPROC)glewGetProcAddress((const GLubyte*)"glStencilFuncSeparateATI")) == NULL) || r; + r = ((glStencilOpSeparateATI = (PFNGLSTENCILOPSEPARATEATIPROC)glewGetProcAddress((const GLubyte*)"glStencilOpSeparateATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_separate_stencil */ + +#ifdef GL_ATI_vertex_array_object + +static GLboolean _glewInit_GL_ATI_vertex_array_object () +{ + GLboolean r = GL_FALSE; + + r = ((glArrayObjectATI = (PFNGLARRAYOBJECTATIPROC)glewGetProcAddress((const GLubyte*)"glArrayObjectATI")) == NULL) || r; + r = ((glFreeObjectBufferATI = (PFNGLFREEOBJECTBUFFERATIPROC)glewGetProcAddress((const GLubyte*)"glFreeObjectBufferATI")) == NULL) || r; + r = ((glGetArrayObjectfvATI = (PFNGLGETARRAYOBJECTFVATIPROC)glewGetProcAddress((const GLubyte*)"glGetArrayObjectfvATI")) == NULL) || r; + r = ((glGetArrayObjectivATI = (PFNGLGETARRAYOBJECTIVATIPROC)glewGetProcAddress((const GLubyte*)"glGetArrayObjectivATI")) == NULL) || r; + r = ((glGetObjectBufferfvATI = (PFNGLGETOBJECTBUFFERFVATIPROC)glewGetProcAddress((const GLubyte*)"glGetObjectBufferfvATI")) == NULL) || r; + r = ((glGetObjectBufferivATI = (PFNGLGETOBJECTBUFFERIVATIPROC)glewGetProcAddress((const GLubyte*)"glGetObjectBufferivATI")) == NULL) || r; + r = ((glGetVariantArrayObjectfvATI = (PFNGLGETVARIANTARRAYOBJECTFVATIPROC)glewGetProcAddress((const GLubyte*)"glGetVariantArrayObjectfvATI")) == NULL) || r; + r = ((glGetVariantArrayObjectivATI = (PFNGLGETVARIANTARRAYOBJECTIVATIPROC)glewGetProcAddress((const GLubyte*)"glGetVariantArrayObjectivATI")) == NULL) || r; + r = ((glIsObjectBufferATI = (PFNGLISOBJECTBUFFERATIPROC)glewGetProcAddress((const GLubyte*)"glIsObjectBufferATI")) == NULL) || r; + r = ((glNewObjectBufferATI = (PFNGLNEWOBJECTBUFFERATIPROC)glewGetProcAddress((const GLubyte*)"glNewObjectBufferATI")) == NULL) || r; + r = ((glUpdateObjectBufferATI = (PFNGLUPDATEOBJECTBUFFERATIPROC)glewGetProcAddress((const GLubyte*)"glUpdateObjectBufferATI")) == NULL) || r; + r = ((glVariantArrayObjectATI = (PFNGLVARIANTARRAYOBJECTATIPROC)glewGetProcAddress((const GLubyte*)"glVariantArrayObjectATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_vertex_array_object */ + +#ifdef GL_ATI_vertex_attrib_array_object + +static GLboolean _glewInit_GL_ATI_vertex_attrib_array_object () +{ + GLboolean r = GL_FALSE; + + r = ((glGetVertexAttribArrayObjectfvATI = (PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribArrayObjectfvATI")) == NULL) || r; + r = ((glGetVertexAttribArrayObjectivATI = (PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribArrayObjectivATI")) == NULL) || r; + r = ((glVertexAttribArrayObjectATI = (PFNGLVERTEXATTRIBARRAYOBJECTATIPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribArrayObjectATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_vertex_attrib_array_object */ + +#ifdef GL_ATI_vertex_streams + +static GLboolean _glewInit_GL_ATI_vertex_streams () +{ + GLboolean r = GL_FALSE; + + r = ((glClientActiveVertexStreamATI = (PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC)glewGetProcAddress((const GLubyte*)"glClientActiveVertexStreamATI")) == NULL) || r; + r = ((glNormalStream3bATI = (PFNGLNORMALSTREAM3BATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3bATI")) == NULL) || r; + r = ((glNormalStream3bvATI = (PFNGLNORMALSTREAM3BVATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3bvATI")) == NULL) || r; + r = ((glNormalStream3dATI = (PFNGLNORMALSTREAM3DATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3dATI")) == NULL) || r; + r = ((glNormalStream3dvATI = (PFNGLNORMALSTREAM3DVATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3dvATI")) == NULL) || r; + r = ((glNormalStream3fATI = (PFNGLNORMALSTREAM3FATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3fATI")) == NULL) || r; + r = ((glNormalStream3fvATI = (PFNGLNORMALSTREAM3FVATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3fvATI")) == NULL) || r; + r = ((glNormalStream3iATI = (PFNGLNORMALSTREAM3IATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3iATI")) == NULL) || r; + r = ((glNormalStream3ivATI = (PFNGLNORMALSTREAM3IVATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3ivATI")) == NULL) || r; + r = ((glNormalStream3sATI = (PFNGLNORMALSTREAM3SATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3sATI")) == NULL) || r; + r = ((glNormalStream3svATI = (PFNGLNORMALSTREAM3SVATIPROC)glewGetProcAddress((const GLubyte*)"glNormalStream3svATI")) == NULL) || r; + r = ((glVertexBlendEnvfATI = (PFNGLVERTEXBLENDENVFATIPROC)glewGetProcAddress((const GLubyte*)"glVertexBlendEnvfATI")) == NULL) || r; + r = ((glVertexBlendEnviATI = (PFNGLVERTEXBLENDENVIATIPROC)glewGetProcAddress((const GLubyte*)"glVertexBlendEnviATI")) == NULL) || r; + r = ((glVertexStream1dATI = (PFNGLVERTEXSTREAM1DATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1dATI")) == NULL) || r; + r = ((glVertexStream1dvATI = (PFNGLVERTEXSTREAM1DVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1dvATI")) == NULL) || r; + r = ((glVertexStream1fATI = (PFNGLVERTEXSTREAM1FATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1fATI")) == NULL) || r; + r = ((glVertexStream1fvATI = (PFNGLVERTEXSTREAM1FVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1fvATI")) == NULL) || r; + r = ((glVertexStream1iATI = (PFNGLVERTEXSTREAM1IATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1iATI")) == NULL) || r; + r = ((glVertexStream1ivATI = (PFNGLVERTEXSTREAM1IVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1ivATI")) == NULL) || r; + r = ((glVertexStream1sATI = (PFNGLVERTEXSTREAM1SATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1sATI")) == NULL) || r; + r = ((glVertexStream1svATI = (PFNGLVERTEXSTREAM1SVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream1svATI")) == NULL) || r; + r = ((glVertexStream2dATI = (PFNGLVERTEXSTREAM2DATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2dATI")) == NULL) || r; + r = ((glVertexStream2dvATI = (PFNGLVERTEXSTREAM2DVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2dvATI")) == NULL) || r; + r = ((glVertexStream2fATI = (PFNGLVERTEXSTREAM2FATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2fATI")) == NULL) || r; + r = ((glVertexStream2fvATI = (PFNGLVERTEXSTREAM2FVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2fvATI")) == NULL) || r; + r = ((glVertexStream2iATI = (PFNGLVERTEXSTREAM2IATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2iATI")) == NULL) || r; + r = ((glVertexStream2ivATI = (PFNGLVERTEXSTREAM2IVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2ivATI")) == NULL) || r; + r = ((glVertexStream2sATI = (PFNGLVERTEXSTREAM2SATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2sATI")) == NULL) || r; + r = ((glVertexStream2svATI = (PFNGLVERTEXSTREAM2SVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream2svATI")) == NULL) || r; + r = ((glVertexStream3dATI = (PFNGLVERTEXSTREAM3DATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3dATI")) == NULL) || r; + r = ((glVertexStream3dvATI = (PFNGLVERTEXSTREAM3DVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3dvATI")) == NULL) || r; + r = ((glVertexStream3fATI = (PFNGLVERTEXSTREAM3FATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3fATI")) == NULL) || r; + r = ((glVertexStream3fvATI = (PFNGLVERTEXSTREAM3FVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3fvATI")) == NULL) || r; + r = ((glVertexStream3iATI = (PFNGLVERTEXSTREAM3IATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3iATI")) == NULL) || r; + r = ((glVertexStream3ivATI = (PFNGLVERTEXSTREAM3IVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3ivATI")) == NULL) || r; + r = ((glVertexStream3sATI = (PFNGLVERTEXSTREAM3SATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3sATI")) == NULL) || r; + r = ((glVertexStream3svATI = (PFNGLVERTEXSTREAM3SVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream3svATI")) == NULL) || r; + r = ((glVertexStream4dATI = (PFNGLVERTEXSTREAM4DATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4dATI")) == NULL) || r; + r = ((glVertexStream4dvATI = (PFNGLVERTEXSTREAM4DVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4dvATI")) == NULL) || r; + r = ((glVertexStream4fATI = (PFNGLVERTEXSTREAM4FATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4fATI")) == NULL) || r; + r = ((glVertexStream4fvATI = (PFNGLVERTEXSTREAM4FVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4fvATI")) == NULL) || r; + r = ((glVertexStream4iATI = (PFNGLVERTEXSTREAM4IATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4iATI")) == NULL) || r; + r = ((glVertexStream4ivATI = (PFNGLVERTEXSTREAM4IVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4ivATI")) == NULL) || r; + r = ((glVertexStream4sATI = (PFNGLVERTEXSTREAM4SATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4sATI")) == NULL) || r; + r = ((glVertexStream4svATI = (PFNGLVERTEXSTREAM4SVATIPROC)glewGetProcAddress((const GLubyte*)"glVertexStream4svATI")) == NULL) || r; + + return r; +} + +#endif /* GL_ATI_vertex_streams */ + +#ifdef GL_EXT_base_instance + +static GLboolean _glewInit_GL_EXT_base_instance () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysInstancedBaseInstanceEXT = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstancedBaseInstanceEXT")) == NULL) || r; + r = ((glDrawElementsInstancedBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedBaseInstanceEXT")) == NULL) || r; + r = ((glDrawElementsInstancedBaseVertexBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedBaseVertexBaseInstanceEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_base_instance */ + +#ifdef GL_EXT_bindable_uniform + +static GLboolean _glewInit_GL_EXT_bindable_uniform () +{ + GLboolean r = GL_FALSE; + + r = ((glGetUniformBufferSizeEXT = (PFNGLGETUNIFORMBUFFERSIZEEXTPROC)glewGetProcAddress((const GLubyte*)"glGetUniformBufferSizeEXT")) == NULL) || r; + r = ((glGetUniformOffsetEXT = (PFNGLGETUNIFORMOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glGetUniformOffsetEXT")) == NULL) || r; + r = ((glUniformBufferEXT = (PFNGLUNIFORMBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glUniformBufferEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_bindable_uniform */ + +#ifdef GL_EXT_blend_color + +static GLboolean _glewInit_GL_EXT_blend_color () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendColorEXT = (PFNGLBLENDCOLOREXTPROC)glewGetProcAddress((const GLubyte*)"glBlendColorEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_blend_color */ + +#ifdef GL_EXT_blend_equation_separate + +static GLboolean _glewInit_GL_EXT_blend_equation_separate () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendEquationSeparateEXT = (PFNGLBLENDEQUATIONSEPARATEEXTPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationSeparateEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_blend_equation_separate */ + +#ifdef GL_EXT_blend_func_extended + +static GLboolean _glewInit_GL_EXT_blend_func_extended () +{ + GLboolean r = GL_FALSE; + + r = ((glBindFragDataLocationIndexedEXT = (PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glBindFragDataLocationIndexedEXT")) == NULL) || r; + r = ((glGetFragDataIndexEXT = (PFNGLGETFRAGDATAINDEXEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFragDataIndexEXT")) == NULL) || r; + r = ((glGetProgramResourceLocationIndexEXT = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourceLocationIndexEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_blend_func_extended */ + +#ifdef GL_EXT_blend_func_separate + +static GLboolean _glewInit_GL_EXT_blend_func_separate () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)glewGetProcAddress((const GLubyte*)"glBlendFuncSeparateEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_blend_func_separate */ + +#ifdef GL_EXT_blend_minmax + +static GLboolean _glewInit_GL_EXT_blend_minmax () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendEquationEXT = (PFNGLBLENDEQUATIONEXTPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_blend_minmax */ + +#ifdef GL_EXT_buffer_storage + +static GLboolean _glewInit_GL_EXT_buffer_storage () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferStorageEXT = (PFNGLBUFFERSTORAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glBufferStorageEXT")) == NULL) || r; + r = ((glNamedBufferStorageEXT = (PFNGLNAMEDBUFFERSTORAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferStorageEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_buffer_storage */ + +#ifdef GL_EXT_clear_texture + +static GLboolean _glewInit_GL_EXT_clear_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glClearTexImageEXT = (PFNGLCLEARTEXIMAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glClearTexImageEXT")) == NULL) || r; + r = ((glClearTexSubImageEXT = (PFNGLCLEARTEXSUBIMAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glClearTexSubImageEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_clear_texture */ + +#ifdef GL_EXT_color_subtable + +static GLboolean _glewInit_GL_EXT_color_subtable () +{ + GLboolean r = GL_FALSE; + + r = ((glColorSubTableEXT = (PFNGLCOLORSUBTABLEEXTPROC)glewGetProcAddress((const GLubyte*)"glColorSubTableEXT")) == NULL) || r; + r = ((glCopyColorSubTableEXT = (PFNGLCOPYCOLORSUBTABLEEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyColorSubTableEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_color_subtable */ + +#ifdef GL_EXT_compiled_vertex_array + +static GLboolean _glewInit_GL_EXT_compiled_vertex_array () +{ + GLboolean r = GL_FALSE; + + r = ((glLockArraysEXT = (PFNGLLOCKARRAYSEXTPROC)glewGetProcAddress((const GLubyte*)"glLockArraysEXT")) == NULL) || r; + r = ((glUnlockArraysEXT = (PFNGLUNLOCKARRAYSEXTPROC)glewGetProcAddress((const GLubyte*)"glUnlockArraysEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_compiled_vertex_array */ + +#ifdef GL_EXT_convolution + +static GLboolean _glewInit_GL_EXT_convolution () +{ + GLboolean r = GL_FALSE; + + r = ((glConvolutionFilter1DEXT = (PFNGLCONVOLUTIONFILTER1DEXTPROC)glewGetProcAddress((const GLubyte*)"glConvolutionFilter1DEXT")) == NULL) || r; + r = ((glConvolutionFilter2DEXT = (PFNGLCONVOLUTIONFILTER2DEXTPROC)glewGetProcAddress((const GLubyte*)"glConvolutionFilter2DEXT")) == NULL) || r; + r = ((glConvolutionParameterfEXT = (PFNGLCONVOLUTIONPARAMETERFEXTPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameterfEXT")) == NULL) || r; + r = ((glConvolutionParameterfvEXT = (PFNGLCONVOLUTIONPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameterfvEXT")) == NULL) || r; + r = ((glConvolutionParameteriEXT = (PFNGLCONVOLUTIONPARAMETERIEXTPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameteriEXT")) == NULL) || r; + r = ((glConvolutionParameterivEXT = (PFNGLCONVOLUTIONPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glConvolutionParameterivEXT")) == NULL) || r; + r = ((glCopyConvolutionFilter1DEXT = (PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyConvolutionFilter1DEXT")) == NULL) || r; + r = ((glCopyConvolutionFilter2DEXT = (PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyConvolutionFilter2DEXT")) == NULL) || r; + r = ((glGetConvolutionFilterEXT = (PFNGLGETCONVOLUTIONFILTEREXTPROC)glewGetProcAddress((const GLubyte*)"glGetConvolutionFilterEXT")) == NULL) || r; + r = ((glGetConvolutionParameterfvEXT = (PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetConvolutionParameterfvEXT")) == NULL) || r; + r = ((glGetConvolutionParameterivEXT = (PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetConvolutionParameterivEXT")) == NULL) || r; + r = ((glGetSeparableFilterEXT = (PFNGLGETSEPARABLEFILTEREXTPROC)glewGetProcAddress((const GLubyte*)"glGetSeparableFilterEXT")) == NULL) || r; + r = ((glSeparableFilter2DEXT = (PFNGLSEPARABLEFILTER2DEXTPROC)glewGetProcAddress((const GLubyte*)"glSeparableFilter2DEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_convolution */ + +#ifdef GL_EXT_coordinate_frame + +static GLboolean _glewInit_GL_EXT_coordinate_frame () +{ + GLboolean r = GL_FALSE; + + r = ((glBinormalPointerEXT = (PFNGLBINORMALPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glBinormalPointerEXT")) == NULL) || r; + r = ((glTangentPointerEXT = (PFNGLTANGENTPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glTangentPointerEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_coordinate_frame */ + +#ifdef GL_EXT_copy_image + +static GLboolean _glewInit_GL_EXT_copy_image () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyImageSubDataEXT = (PFNGLCOPYIMAGESUBDATAEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyImageSubDataEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_copy_image */ + +#ifdef GL_EXT_copy_texture + +static GLboolean _glewInit_GL_EXT_copy_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyTexImage1DEXT = (PFNGLCOPYTEXIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTexImage1DEXT")) == NULL) || r; + r = ((glCopyTexImage2DEXT = (PFNGLCOPYTEXIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTexImage2DEXT")) == NULL) || r; + r = ((glCopyTexSubImage1DEXT = (PFNGLCOPYTEXSUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTexSubImage1DEXT")) == NULL) || r; + r = ((glCopyTexSubImage2DEXT = (PFNGLCOPYTEXSUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTexSubImage2DEXT")) == NULL) || r; + r = ((glCopyTexSubImage3DEXT = (PFNGLCOPYTEXSUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTexSubImage3DEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_copy_texture */ + +#ifdef GL_EXT_cull_vertex + +static GLboolean _glewInit_GL_EXT_cull_vertex () +{ + GLboolean r = GL_FALSE; + + r = ((glCullParameterdvEXT = (PFNGLCULLPARAMETERDVEXTPROC)glewGetProcAddress((const GLubyte*)"glCullParameterdvEXT")) == NULL) || r; + r = ((glCullParameterfvEXT = (PFNGLCULLPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glCullParameterfvEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_cull_vertex */ + +#ifdef GL_EXT_debug_label + +static GLboolean _glewInit_GL_EXT_debug_label () +{ + GLboolean r = GL_FALSE; + + r = ((glGetObjectLabelEXT = (PFNGLGETOBJECTLABELEXTPROC)glewGetProcAddress((const GLubyte*)"glGetObjectLabelEXT")) == NULL) || r; + r = ((glLabelObjectEXT = (PFNGLLABELOBJECTEXTPROC)glewGetProcAddress((const GLubyte*)"glLabelObjectEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_debug_label */ + +#ifdef GL_EXT_debug_marker + +static GLboolean _glewInit_GL_EXT_debug_marker () +{ + GLboolean r = GL_FALSE; + + r = ((glInsertEventMarkerEXT = (PFNGLINSERTEVENTMARKEREXTPROC)glewGetProcAddress((const GLubyte*)"glInsertEventMarkerEXT")) == NULL) || r; + r = ((glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC)glewGetProcAddress((const GLubyte*)"glPopGroupMarkerEXT")) == NULL) || r; + r = ((glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC)glewGetProcAddress((const GLubyte*)"glPushGroupMarkerEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_debug_marker */ + +#ifdef GL_EXT_depth_bounds_test + +static GLboolean _glewInit_GL_EXT_depth_bounds_test () +{ + GLboolean r = GL_FALSE; + + r = ((glDepthBoundsEXT = (PFNGLDEPTHBOUNDSEXTPROC)glewGetProcAddress((const GLubyte*)"glDepthBoundsEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_depth_bounds_test */ + +#ifdef GL_EXT_direct_state_access + +static GLboolean _glewInit_GL_EXT_direct_state_access () +{ + GLboolean r = GL_FALSE; + + r = ((glBindMultiTextureEXT = (PFNGLBINDMULTITEXTUREEXTPROC)glewGetProcAddress((const GLubyte*)"glBindMultiTextureEXT")) == NULL) || r; + r = ((glCheckNamedFramebufferStatusEXT = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC)glewGetProcAddress((const GLubyte*)"glCheckNamedFramebufferStatusEXT")) == NULL) || r; + r = ((glClientAttribDefaultEXT = (PFNGLCLIENTATTRIBDEFAULTEXTPROC)glewGetProcAddress((const GLubyte*)"glClientAttribDefaultEXT")) == NULL) || r; + r = ((glCompressedMultiTexImage1DEXT = (PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedMultiTexImage1DEXT")) == NULL) || r; + r = ((glCompressedMultiTexImage2DEXT = (PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedMultiTexImage2DEXT")) == NULL) || r; + r = ((glCompressedMultiTexImage3DEXT = (PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedMultiTexImage3DEXT")) == NULL) || r; + r = ((glCompressedMultiTexSubImage1DEXT = (PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedMultiTexSubImage1DEXT")) == NULL) || r; + r = ((glCompressedMultiTexSubImage2DEXT = (PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedMultiTexSubImage2DEXT")) == NULL) || r; + r = ((glCompressedMultiTexSubImage3DEXT = (PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedMultiTexSubImage3DEXT")) == NULL) || r; + r = ((glCompressedTextureImage1DEXT = (PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureImage1DEXT")) == NULL) || r; + r = ((glCompressedTextureImage2DEXT = (PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureImage2DEXT")) == NULL) || r; + r = ((glCompressedTextureImage3DEXT = (PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureImage3DEXT")) == NULL) || r; + r = ((glCompressedTextureSubImage1DEXT = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage1DEXT")) == NULL) || r; + r = ((glCompressedTextureSubImage2DEXT = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage2DEXT")) == NULL) || r; + r = ((glCompressedTextureSubImage3DEXT = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage3DEXT")) == NULL) || r; + r = ((glCopyMultiTexImage1DEXT = (PFNGLCOPYMULTITEXIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyMultiTexImage1DEXT")) == NULL) || r; + r = ((glCopyMultiTexImage2DEXT = (PFNGLCOPYMULTITEXIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyMultiTexImage2DEXT")) == NULL) || r; + r = ((glCopyMultiTexSubImage1DEXT = (PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyMultiTexSubImage1DEXT")) == NULL) || r; + r = ((glCopyMultiTexSubImage2DEXT = (PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyMultiTexSubImage2DEXT")) == NULL) || r; + r = ((glCopyMultiTexSubImage3DEXT = (PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyMultiTexSubImage3DEXT")) == NULL) || r; + r = ((glCopyTextureImage1DEXT = (PFNGLCOPYTEXTUREIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureImage1DEXT")) == NULL) || r; + r = ((glCopyTextureImage2DEXT = (PFNGLCOPYTEXTUREIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureImage2DEXT")) == NULL) || r; + r = ((glCopyTextureSubImage1DEXT = (PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage1DEXT")) == NULL) || r; + r = ((glCopyTextureSubImage2DEXT = (PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage2DEXT")) == NULL) || r; + r = ((glCopyTextureSubImage3DEXT = (PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage3DEXT")) == NULL) || r; + r = ((glDisableClientStateIndexedEXT = (PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glDisableClientStateIndexedEXT")) == NULL) || r; + r = ((glDisableClientStateiEXT = (PFNGLDISABLECLIENTSTATEIEXTPROC)glewGetProcAddress((const GLubyte*)"glDisableClientStateiEXT")) == NULL) || r; + r = ((glDisableVertexArrayAttribEXT = (PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC)glewGetProcAddress((const GLubyte*)"glDisableVertexArrayAttribEXT")) == NULL) || r; + r = ((glDisableVertexArrayEXT = (PFNGLDISABLEVERTEXARRAYEXTPROC)glewGetProcAddress((const GLubyte*)"glDisableVertexArrayEXT")) == NULL) || r; + r = ((glEnableClientStateIndexedEXT = (PFNGLENABLECLIENTSTATEINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glEnableClientStateIndexedEXT")) == NULL) || r; + r = ((glEnableClientStateiEXT = (PFNGLENABLECLIENTSTATEIEXTPROC)glewGetProcAddress((const GLubyte*)"glEnableClientStateiEXT")) == NULL) || r; + r = ((glEnableVertexArrayAttribEXT = (PFNGLENABLEVERTEXARRAYATTRIBEXTPROC)glewGetProcAddress((const GLubyte*)"glEnableVertexArrayAttribEXT")) == NULL) || r; + r = ((glEnableVertexArrayEXT = (PFNGLENABLEVERTEXARRAYEXTPROC)glewGetProcAddress((const GLubyte*)"glEnableVertexArrayEXT")) == NULL) || r; + r = ((glFlushMappedNamedBufferRangeEXT = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC)glewGetProcAddress((const GLubyte*)"glFlushMappedNamedBufferRangeEXT")) == NULL) || r; + r = ((glFramebufferDrawBufferEXT = (PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferDrawBufferEXT")) == NULL) || r; + r = ((glFramebufferDrawBuffersEXT = (PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferDrawBuffersEXT")) == NULL) || r; + r = ((glFramebufferReadBufferEXT = (PFNGLFRAMEBUFFERREADBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferReadBufferEXT")) == NULL) || r; + r = ((glGenerateMultiTexMipmapEXT = (PFNGLGENERATEMULTITEXMIPMAPEXTPROC)glewGetProcAddress((const GLubyte*)"glGenerateMultiTexMipmapEXT")) == NULL) || r; + r = ((glGenerateTextureMipmapEXT = (PFNGLGENERATETEXTUREMIPMAPEXTPROC)glewGetProcAddress((const GLubyte*)"glGenerateTextureMipmapEXT")) == NULL) || r; + r = ((glGetCompressedMultiTexImageEXT = (PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedMultiTexImageEXT")) == NULL) || r; + r = ((glGetCompressedTextureImageEXT = (PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedTextureImageEXT")) == NULL) || r; + r = ((glGetDoubleIndexedvEXT = (PFNGLGETDOUBLEINDEXEDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetDoubleIndexedvEXT")) == NULL) || r; + r = ((glGetDoublei_vEXT = (PFNGLGETDOUBLEI_VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetDoublei_vEXT")) == NULL) || r; + r = ((glGetFloatIndexedvEXT = (PFNGLGETFLOATINDEXEDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFloatIndexedvEXT")) == NULL) || r; + r = ((glGetFloati_vEXT = (PFNGLGETFLOATI_VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFloati_vEXT")) == NULL) || r; + r = ((glGetFramebufferParameterivEXT = (PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFramebufferParameterivEXT")) == NULL) || r; + r = ((glGetMultiTexEnvfvEXT = (PFNGLGETMULTITEXENVFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexEnvfvEXT")) == NULL) || r; + r = ((glGetMultiTexEnvivEXT = (PFNGLGETMULTITEXENVIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexEnvivEXT")) == NULL) || r; + r = ((glGetMultiTexGendvEXT = (PFNGLGETMULTITEXGENDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexGendvEXT")) == NULL) || r; + r = ((glGetMultiTexGenfvEXT = (PFNGLGETMULTITEXGENFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexGenfvEXT")) == NULL) || r; + r = ((glGetMultiTexGenivEXT = (PFNGLGETMULTITEXGENIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexGenivEXT")) == NULL) || r; + r = ((glGetMultiTexImageEXT = (PFNGLGETMULTITEXIMAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexImageEXT")) == NULL) || r; + r = ((glGetMultiTexLevelParameterfvEXT = (PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexLevelParameterfvEXT")) == NULL) || r; + r = ((glGetMultiTexLevelParameterivEXT = (PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexLevelParameterivEXT")) == NULL) || r; + r = ((glGetMultiTexParameterIivEXT = (PFNGLGETMULTITEXPARAMETERIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexParameterIivEXT")) == NULL) || r; + r = ((glGetMultiTexParameterIuivEXT = (PFNGLGETMULTITEXPARAMETERIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexParameterIuivEXT")) == NULL) || r; + r = ((glGetMultiTexParameterfvEXT = (PFNGLGETMULTITEXPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexParameterfvEXT")) == NULL) || r; + r = ((glGetMultiTexParameterivEXT = (PFNGLGETMULTITEXPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMultiTexParameterivEXT")) == NULL) || r; + r = ((glGetNamedBufferParameterivEXT = (PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferParameterivEXT")) == NULL) || r; + r = ((glGetNamedBufferPointervEXT = (PFNGLGETNAMEDBUFFERPOINTERVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferPointervEXT")) == NULL) || r; + r = ((glGetNamedBufferSubDataEXT = (PFNGLGETNAMEDBUFFERSUBDATAEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferSubDataEXT")) == NULL) || r; + r = ((glGetNamedFramebufferAttachmentParameterivEXT = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedFramebufferAttachmentParameterivEXT")) == NULL) || r; + r = ((glGetNamedProgramLocalParameterIivEXT = (PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedProgramLocalParameterIivEXT")) == NULL) || r; + r = ((glGetNamedProgramLocalParameterIuivEXT = (PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedProgramLocalParameterIuivEXT")) == NULL) || r; + r = ((glGetNamedProgramLocalParameterdvEXT = (PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedProgramLocalParameterdvEXT")) == NULL) || r; + r = ((glGetNamedProgramLocalParameterfvEXT = (PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedProgramLocalParameterfvEXT")) == NULL) || r; + r = ((glGetNamedProgramStringEXT = (PFNGLGETNAMEDPROGRAMSTRINGEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedProgramStringEXT")) == NULL) || r; + r = ((glGetNamedProgramivEXT = (PFNGLGETNAMEDPROGRAMIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedProgramivEXT")) == NULL) || r; + r = ((glGetNamedRenderbufferParameterivEXT = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetNamedRenderbufferParameterivEXT")) == NULL) || r; + r = ((glGetPointerIndexedvEXT = (PFNGLGETPOINTERINDEXEDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetPointerIndexedvEXT")) == NULL) || r; + r = ((glGetPointeri_vEXT = (PFNGLGETPOINTERI_VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetPointeri_vEXT")) == NULL) || r; + r = ((glGetTextureImageEXT = (PFNGLGETTEXTUREIMAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTextureImageEXT")) == NULL) || r; + r = ((glGetTextureLevelParameterfvEXT = (PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTextureLevelParameterfvEXT")) == NULL) || r; + r = ((glGetTextureLevelParameterivEXT = (PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTextureLevelParameterivEXT")) == NULL) || r; + r = ((glGetTextureParameterIivEXT = (PFNGLGETTEXTUREPARAMETERIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterIivEXT")) == NULL) || r; + r = ((glGetTextureParameterIuivEXT = (PFNGLGETTEXTUREPARAMETERIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterIuivEXT")) == NULL) || r; + r = ((glGetTextureParameterfvEXT = (PFNGLGETTEXTUREPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterfvEXT")) == NULL) || r; + r = ((glGetTextureParameterivEXT = (PFNGLGETTEXTUREPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterivEXT")) == NULL) || r; + r = ((glGetVertexArrayIntegeri_vEXT = (PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayIntegeri_vEXT")) == NULL) || r; + r = ((glGetVertexArrayIntegervEXT = (PFNGLGETVERTEXARRAYINTEGERVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayIntegervEXT")) == NULL) || r; + r = ((glGetVertexArrayPointeri_vEXT = (PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayPointeri_vEXT")) == NULL) || r; + r = ((glGetVertexArrayPointervEXT = (PFNGLGETVERTEXARRAYPOINTERVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayPointervEXT")) == NULL) || r; + r = ((glMapNamedBufferEXT = (PFNGLMAPNAMEDBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glMapNamedBufferEXT")) == NULL) || r; + r = ((glMapNamedBufferRangeEXT = (PFNGLMAPNAMEDBUFFERRANGEEXTPROC)glewGetProcAddress((const GLubyte*)"glMapNamedBufferRangeEXT")) == NULL) || r; + r = ((glMatrixFrustumEXT = (PFNGLMATRIXFRUSTUMEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixFrustumEXT")) == NULL) || r; + r = ((glMatrixLoadIdentityEXT = (PFNGLMATRIXLOADIDENTITYEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoadIdentityEXT")) == NULL) || r; + r = ((glMatrixLoadTransposedEXT = (PFNGLMATRIXLOADTRANSPOSEDEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoadTransposedEXT")) == NULL) || r; + r = ((glMatrixLoadTransposefEXT = (PFNGLMATRIXLOADTRANSPOSEFEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoadTransposefEXT")) == NULL) || r; + r = ((glMatrixLoaddEXT = (PFNGLMATRIXLOADDEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoaddEXT")) == NULL) || r; + r = ((glMatrixLoadfEXT = (PFNGLMATRIXLOADFEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoadfEXT")) == NULL) || r; + r = ((glMatrixMultTransposedEXT = (PFNGLMATRIXMULTTRANSPOSEDEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixMultTransposedEXT")) == NULL) || r; + r = ((glMatrixMultTransposefEXT = (PFNGLMATRIXMULTTRANSPOSEFEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixMultTransposefEXT")) == NULL) || r; + r = ((glMatrixMultdEXT = (PFNGLMATRIXMULTDEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixMultdEXT")) == NULL) || r; + r = ((glMatrixMultfEXT = (PFNGLMATRIXMULTFEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixMultfEXT")) == NULL) || r; + r = ((glMatrixOrthoEXT = (PFNGLMATRIXORTHOEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixOrthoEXT")) == NULL) || r; + r = ((glMatrixPopEXT = (PFNGLMATRIXPOPEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixPopEXT")) == NULL) || r; + r = ((glMatrixPushEXT = (PFNGLMATRIXPUSHEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixPushEXT")) == NULL) || r; + r = ((glMatrixRotatedEXT = (PFNGLMATRIXROTATEDEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixRotatedEXT")) == NULL) || r; + r = ((glMatrixRotatefEXT = (PFNGLMATRIXROTATEFEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixRotatefEXT")) == NULL) || r; + r = ((glMatrixScaledEXT = (PFNGLMATRIXSCALEDEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixScaledEXT")) == NULL) || r; + r = ((glMatrixScalefEXT = (PFNGLMATRIXSCALEFEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixScalefEXT")) == NULL) || r; + r = ((glMatrixTranslatedEXT = (PFNGLMATRIXTRANSLATEDEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixTranslatedEXT")) == NULL) || r; + r = ((glMatrixTranslatefEXT = (PFNGLMATRIXTRANSLATEFEXTPROC)glewGetProcAddress((const GLubyte*)"glMatrixTranslatefEXT")) == NULL) || r; + r = ((glMultiTexBufferEXT = (PFNGLMULTITEXBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexBufferEXT")) == NULL) || r; + r = ((glMultiTexCoordPointerEXT = (PFNGLMULTITEXCOORDPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoordPointerEXT")) == NULL) || r; + r = ((glMultiTexEnvfEXT = (PFNGLMULTITEXENVFEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexEnvfEXT")) == NULL) || r; + r = ((glMultiTexEnvfvEXT = (PFNGLMULTITEXENVFVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexEnvfvEXT")) == NULL) || r; + r = ((glMultiTexEnviEXT = (PFNGLMULTITEXENVIEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexEnviEXT")) == NULL) || r; + r = ((glMultiTexEnvivEXT = (PFNGLMULTITEXENVIVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexEnvivEXT")) == NULL) || r; + r = ((glMultiTexGendEXT = (PFNGLMULTITEXGENDEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexGendEXT")) == NULL) || r; + r = ((glMultiTexGendvEXT = (PFNGLMULTITEXGENDVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexGendvEXT")) == NULL) || r; + r = ((glMultiTexGenfEXT = (PFNGLMULTITEXGENFEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexGenfEXT")) == NULL) || r; + r = ((glMultiTexGenfvEXT = (PFNGLMULTITEXGENFVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexGenfvEXT")) == NULL) || r; + r = ((glMultiTexGeniEXT = (PFNGLMULTITEXGENIEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexGeniEXT")) == NULL) || r; + r = ((glMultiTexGenivEXT = (PFNGLMULTITEXGENIVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexGenivEXT")) == NULL) || r; + r = ((glMultiTexImage1DEXT = (PFNGLMULTITEXIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexImage1DEXT")) == NULL) || r; + r = ((glMultiTexImage2DEXT = (PFNGLMULTITEXIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexImage2DEXT")) == NULL) || r; + r = ((glMultiTexImage3DEXT = (PFNGLMULTITEXIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexImage3DEXT")) == NULL) || r; + r = ((glMultiTexParameterIivEXT = (PFNGLMULTITEXPARAMETERIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexParameterIivEXT")) == NULL) || r; + r = ((glMultiTexParameterIuivEXT = (PFNGLMULTITEXPARAMETERIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexParameterIuivEXT")) == NULL) || r; + r = ((glMultiTexParameterfEXT = (PFNGLMULTITEXPARAMETERFEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexParameterfEXT")) == NULL) || r; + r = ((glMultiTexParameterfvEXT = (PFNGLMULTITEXPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexParameterfvEXT")) == NULL) || r; + r = ((glMultiTexParameteriEXT = (PFNGLMULTITEXPARAMETERIEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexParameteriEXT")) == NULL) || r; + r = ((glMultiTexParameterivEXT = (PFNGLMULTITEXPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexParameterivEXT")) == NULL) || r; + r = ((glMultiTexRenderbufferEXT = (PFNGLMULTITEXRENDERBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexRenderbufferEXT")) == NULL) || r; + r = ((glMultiTexSubImage1DEXT = (PFNGLMULTITEXSUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexSubImage1DEXT")) == NULL) || r; + r = ((glMultiTexSubImage2DEXT = (PFNGLMULTITEXSUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexSubImage2DEXT")) == NULL) || r; + r = ((glMultiTexSubImage3DEXT = (PFNGLMULTITEXSUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiTexSubImage3DEXT")) == NULL) || r; + r = ((glNamedBufferDataEXT = (PFNGLNAMEDBUFFERDATAEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferDataEXT")) == NULL) || r; + r = ((glNamedBufferSubDataEXT = (PFNGLNAMEDBUFFERSUBDATAEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferSubDataEXT")) == NULL) || r; + r = ((glNamedCopyBufferSubDataEXT = (PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedCopyBufferSubDataEXT")) == NULL) || r; + r = ((glNamedFramebufferRenderbufferEXT = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferRenderbufferEXT")) == NULL) || r; + r = ((glNamedFramebufferTexture1DEXT = (PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTexture1DEXT")) == NULL) || r; + r = ((glNamedFramebufferTexture2DEXT = (PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTexture2DEXT")) == NULL) || r; + r = ((glNamedFramebufferTexture3DEXT = (PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTexture3DEXT")) == NULL) || r; + r = ((glNamedFramebufferTextureEXT = (PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTextureEXT")) == NULL) || r; + r = ((glNamedFramebufferTextureFaceEXT = (PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTextureFaceEXT")) == NULL) || r; + r = ((glNamedFramebufferTextureLayerEXT = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTextureLayerEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameter4dEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameter4dEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameter4dvEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameter4dvEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameter4fEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameter4fEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameter4fvEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameter4fvEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameterI4iEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameterI4iEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameterI4ivEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameterI4ivEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameterI4uiEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameterI4uiEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameterI4uivEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameterI4uivEXT")) == NULL) || r; + r = ((glNamedProgramLocalParameters4fvEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParameters4fvEXT")) == NULL) || r; + r = ((glNamedProgramLocalParametersI4ivEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParametersI4ivEXT")) == NULL) || r; + r = ((glNamedProgramLocalParametersI4uivEXT = (PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramLocalParametersI4uivEXT")) == NULL) || r; + r = ((glNamedProgramStringEXT = (PFNGLNAMEDPROGRAMSTRINGEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedProgramStringEXT")) == NULL) || r; + r = ((glNamedRenderbufferStorageEXT = (PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageEXT")) == NULL) || r; + r = ((glNamedRenderbufferStorageMultisampleCoverageEXT = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageMultisampleCoverageEXT")) == NULL) || r; + r = ((glNamedRenderbufferStorageMultisampleEXT = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageMultisampleEXT")) == NULL) || r; + r = ((glProgramUniform1fEXT = (PFNGLPROGRAMUNIFORM1FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1fEXT")) == NULL) || r; + r = ((glProgramUniform1fvEXT = (PFNGLPROGRAMUNIFORM1FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1fvEXT")) == NULL) || r; + r = ((glProgramUniform1iEXT = (PFNGLPROGRAMUNIFORM1IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1iEXT")) == NULL) || r; + r = ((glProgramUniform1ivEXT = (PFNGLPROGRAMUNIFORM1IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ivEXT")) == NULL) || r; + r = ((glProgramUniform1uiEXT = (PFNGLPROGRAMUNIFORM1UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1uiEXT")) == NULL) || r; + r = ((glProgramUniform1uivEXT = (PFNGLPROGRAMUNIFORM1UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1uivEXT")) == NULL) || r; + r = ((glProgramUniform2fEXT = (PFNGLPROGRAMUNIFORM2FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2fEXT")) == NULL) || r; + r = ((glProgramUniform2fvEXT = (PFNGLPROGRAMUNIFORM2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2fvEXT")) == NULL) || r; + r = ((glProgramUniform2iEXT = (PFNGLPROGRAMUNIFORM2IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2iEXT")) == NULL) || r; + r = ((glProgramUniform2ivEXT = (PFNGLPROGRAMUNIFORM2IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ivEXT")) == NULL) || r; + r = ((glProgramUniform2uiEXT = (PFNGLPROGRAMUNIFORM2UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2uiEXT")) == NULL) || r; + r = ((glProgramUniform2uivEXT = (PFNGLPROGRAMUNIFORM2UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2uivEXT")) == NULL) || r; + r = ((glProgramUniform3fEXT = (PFNGLPROGRAMUNIFORM3FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3fEXT")) == NULL) || r; + r = ((glProgramUniform3fvEXT = (PFNGLPROGRAMUNIFORM3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3fvEXT")) == NULL) || r; + r = ((glProgramUniform3iEXT = (PFNGLPROGRAMUNIFORM3IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3iEXT")) == NULL) || r; + r = ((glProgramUniform3ivEXT = (PFNGLPROGRAMUNIFORM3IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ivEXT")) == NULL) || r; + r = ((glProgramUniform3uiEXT = (PFNGLPROGRAMUNIFORM3UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3uiEXT")) == NULL) || r; + r = ((glProgramUniform3uivEXT = (PFNGLPROGRAMUNIFORM3UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3uivEXT")) == NULL) || r; + r = ((glProgramUniform4fEXT = (PFNGLPROGRAMUNIFORM4FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4fEXT")) == NULL) || r; + r = ((glProgramUniform4fvEXT = (PFNGLPROGRAMUNIFORM4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4fvEXT")) == NULL) || r; + r = ((glProgramUniform4iEXT = (PFNGLPROGRAMUNIFORM4IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4iEXT")) == NULL) || r; + r = ((glProgramUniform4ivEXT = (PFNGLPROGRAMUNIFORM4IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ivEXT")) == NULL) || r; + r = ((glProgramUniform4uiEXT = (PFNGLPROGRAMUNIFORM4UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4uiEXT")) == NULL) || r; + r = ((glProgramUniform4uivEXT = (PFNGLPROGRAMUNIFORM4UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4uivEXT")) == NULL) || r; + r = ((glProgramUniformMatrix2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix2x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x3fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix2x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x4fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix3x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x2fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix3x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x4fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix4x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x2fvEXT")) == NULL) || r; + r = ((glProgramUniformMatrix4x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x3fvEXT")) == NULL) || r; + r = ((glPushClientAttribDefaultEXT = (PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC)glewGetProcAddress((const GLubyte*)"glPushClientAttribDefaultEXT")) == NULL) || r; + r = ((glTextureBufferEXT = (PFNGLTEXTUREBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glTextureBufferEXT")) == NULL) || r; + r = ((glTextureImage1DEXT = (PFNGLTEXTUREIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureImage1DEXT")) == NULL) || r; + r = ((glTextureImage2DEXT = (PFNGLTEXTUREIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureImage2DEXT")) == NULL) || r; + r = ((glTextureImage3DEXT = (PFNGLTEXTUREIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureImage3DEXT")) == NULL) || r; + r = ((glTextureParameterIivEXT = (PFNGLTEXTUREPARAMETERIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterIivEXT")) == NULL) || r; + r = ((glTextureParameterIuivEXT = (PFNGLTEXTUREPARAMETERIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterIuivEXT")) == NULL) || r; + r = ((glTextureParameterfEXT = (PFNGLTEXTUREPARAMETERFEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterfEXT")) == NULL) || r; + r = ((glTextureParameterfvEXT = (PFNGLTEXTUREPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterfvEXT")) == NULL) || r; + r = ((glTextureParameteriEXT = (PFNGLTEXTUREPARAMETERIEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureParameteriEXT")) == NULL) || r; + r = ((glTextureParameterivEXT = (PFNGLTEXTUREPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterivEXT")) == NULL) || r; + r = ((glTextureRenderbufferEXT = (PFNGLTEXTURERENDERBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glTextureRenderbufferEXT")) == NULL) || r; + r = ((glTextureSubImage1DEXT = (PFNGLTEXTURESUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage1DEXT")) == NULL) || r; + r = ((glTextureSubImage2DEXT = (PFNGLTEXTURESUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage2DEXT")) == NULL) || r; + r = ((glTextureSubImage3DEXT = (PFNGLTEXTURESUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage3DEXT")) == NULL) || r; + r = ((glUnmapNamedBufferEXT = (PFNGLUNMAPNAMEDBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glUnmapNamedBufferEXT")) == NULL) || r; + r = ((glVertexArrayColorOffsetEXT = (PFNGLVERTEXARRAYCOLOROFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayColorOffsetEXT")) == NULL) || r; + r = ((glVertexArrayEdgeFlagOffsetEXT = (PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayEdgeFlagOffsetEXT")) == NULL) || r; + r = ((glVertexArrayFogCoordOffsetEXT = (PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayFogCoordOffsetEXT")) == NULL) || r; + r = ((glVertexArrayIndexOffsetEXT = (PFNGLVERTEXARRAYINDEXOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayIndexOffsetEXT")) == NULL) || r; + r = ((glVertexArrayMultiTexCoordOffsetEXT = (PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayMultiTexCoordOffsetEXT")) == NULL) || r; + r = ((glVertexArrayNormalOffsetEXT = (PFNGLVERTEXARRAYNORMALOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayNormalOffsetEXT")) == NULL) || r; + r = ((glVertexArraySecondaryColorOffsetEXT = (PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArraySecondaryColorOffsetEXT")) == NULL) || r; + r = ((glVertexArrayTexCoordOffsetEXT = (PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayTexCoordOffsetEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribDivisorEXT = (PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribDivisorEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribIOffsetEXT = (PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribIOffsetEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribOffsetEXT = (PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribOffsetEXT")) == NULL) || r; + r = ((glVertexArrayVertexOffsetEXT = (PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexOffsetEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_direct_state_access */ + +#ifdef GL_EXT_discard_framebuffer + +static GLboolean _glewInit_GL_EXT_discard_framebuffer () +{ + GLboolean r = GL_FALSE; + + r = ((glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glDiscardFramebufferEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_discard_framebuffer */ + +#ifdef GL_EXT_draw_buffers + +static GLboolean _glewInit_GL_EXT_draw_buffers () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawBuffersEXT = (PFNGLDRAWBUFFERSEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawBuffersEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_draw_buffers */ + +#ifdef GL_EXT_draw_buffers2 + +static GLboolean _glewInit_GL_EXT_draw_buffers2 () +{ + GLboolean r = GL_FALSE; + + r = ((glColorMaskIndexedEXT = (PFNGLCOLORMASKINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glColorMaskIndexedEXT")) == NULL) || r; + r = ((glDisableIndexedEXT = (PFNGLDISABLEINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glDisableIndexedEXT")) == NULL) || r; + r = ((glEnableIndexedEXT = (PFNGLENABLEINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glEnableIndexedEXT")) == NULL) || r; + r = ((glGetBooleanIndexedvEXT = (PFNGLGETBOOLEANINDEXEDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetBooleanIndexedvEXT")) == NULL) || r; + r = ((glGetIntegerIndexedvEXT = (PFNGLGETINTEGERINDEXEDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetIntegerIndexedvEXT")) == NULL) || r; + r = ((glIsEnabledIndexedEXT = (PFNGLISENABLEDINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glIsEnabledIndexedEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_draw_buffers2 */ + +#ifdef GL_EXT_draw_buffers_indexed + +static GLboolean _glewInit_GL_EXT_draw_buffers_indexed () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendEquationSeparateiEXT = (PFNGLBLENDEQUATIONSEPARATEIEXTPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationSeparateiEXT")) == NULL) || r; + r = ((glBlendEquationiEXT = (PFNGLBLENDEQUATIONIEXTPROC)glewGetProcAddress((const GLubyte*)"glBlendEquationiEXT")) == NULL) || r; + r = ((glBlendFuncSeparateiEXT = (PFNGLBLENDFUNCSEPARATEIEXTPROC)glewGetProcAddress((const GLubyte*)"glBlendFuncSeparateiEXT")) == NULL) || r; + r = ((glBlendFunciEXT = (PFNGLBLENDFUNCIEXTPROC)glewGetProcAddress((const GLubyte*)"glBlendFunciEXT")) == NULL) || r; + r = ((glColorMaskiEXT = (PFNGLCOLORMASKIEXTPROC)glewGetProcAddress((const GLubyte*)"glColorMaskiEXT")) == NULL) || r; + r = ((glDisableiEXT = (PFNGLDISABLEIEXTPROC)glewGetProcAddress((const GLubyte*)"glDisableiEXT")) == NULL) || r; + r = ((glEnableiEXT = (PFNGLENABLEIEXTPROC)glewGetProcAddress((const GLubyte*)"glEnableiEXT")) == NULL) || r; + r = ((glIsEnablediEXT = (PFNGLISENABLEDIEXTPROC)glewGetProcAddress((const GLubyte*)"glIsEnablediEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_draw_buffers_indexed */ + +#ifdef GL_EXT_draw_elements_base_vertex + +static GLboolean _glewInit_GL_EXT_draw_elements_base_vertex () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawElementsBaseVertexEXT = (PFNGLDRAWELEMENTSBASEVERTEXEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsBaseVertexEXT")) == NULL) || r; + r = ((glDrawElementsInstancedBaseVertexEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedBaseVertexEXT")) == NULL) || r; + r = ((glDrawRangeElementsBaseVertexEXT = (PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawRangeElementsBaseVertexEXT")) == NULL) || r; + r = ((glMultiDrawElementsBaseVertexEXT = (PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsBaseVertexEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_draw_elements_base_vertex */ + +#ifdef GL_EXT_draw_instanced + +static GLboolean _glewInit_GL_EXT_draw_instanced () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstancedEXT")) == NULL) || r; + r = ((glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_draw_instanced */ + +#ifdef GL_EXT_draw_range_elements + +static GLboolean _glewInit_GL_EXT_draw_range_elements () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawRangeElementsEXT = (PFNGLDRAWRANGEELEMENTSEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawRangeElementsEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_draw_range_elements */ + +#ifdef GL_EXT_external_buffer + +static GLboolean _glewInit_GL_EXT_external_buffer () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferStorageExternalEXT = (PFNGLBUFFERSTORAGEEXTERNALEXTPROC)glewGetProcAddress((const GLubyte*)"glBufferStorageExternalEXT")) == NULL) || r; + r = ((glNamedBufferStorageExternalEXT = (PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferStorageExternalEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_external_buffer */ + +#ifdef GL_EXT_fog_coord + +static GLboolean _glewInit_GL_EXT_fog_coord () +{ + GLboolean r = GL_FALSE; + + r = ((glFogCoordPointerEXT = (PFNGLFOGCOORDPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glFogCoordPointerEXT")) == NULL) || r; + r = ((glFogCoorddEXT = (PFNGLFOGCOORDDEXTPROC)glewGetProcAddress((const GLubyte*)"glFogCoorddEXT")) == NULL) || r; + r = ((glFogCoorddvEXT = (PFNGLFOGCOORDDVEXTPROC)glewGetProcAddress((const GLubyte*)"glFogCoorddvEXT")) == NULL) || r; + r = ((glFogCoordfEXT = (PFNGLFOGCOORDFEXTPROC)glewGetProcAddress((const GLubyte*)"glFogCoordfEXT")) == NULL) || r; + r = ((glFogCoordfvEXT = (PFNGLFOGCOORDFVEXTPROC)glewGetProcAddress((const GLubyte*)"glFogCoordfvEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_fog_coord */ + +#ifdef GL_EXT_fragment_lighting + +static GLboolean _glewInit_GL_EXT_fragment_lighting () +{ + GLboolean r = GL_FALSE; + + r = ((glFragmentColorMaterialEXT = (PFNGLFRAGMENTCOLORMATERIALEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentColorMaterialEXT")) == NULL) || r; + r = ((glFragmentLightModelfEXT = (PFNGLFRAGMENTLIGHTMODELFEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModelfEXT")) == NULL) || r; + r = ((glFragmentLightModelfvEXT = (PFNGLFRAGMENTLIGHTMODELFVEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModelfvEXT")) == NULL) || r; + r = ((glFragmentLightModeliEXT = (PFNGLFRAGMENTLIGHTMODELIEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModeliEXT")) == NULL) || r; + r = ((glFragmentLightModelivEXT = (PFNGLFRAGMENTLIGHTMODELIVEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModelivEXT")) == NULL) || r; + r = ((glFragmentLightfEXT = (PFNGLFRAGMENTLIGHTFEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightfEXT")) == NULL) || r; + r = ((glFragmentLightfvEXT = (PFNGLFRAGMENTLIGHTFVEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightfvEXT")) == NULL) || r; + r = ((glFragmentLightiEXT = (PFNGLFRAGMENTLIGHTIEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightiEXT")) == NULL) || r; + r = ((glFragmentLightivEXT = (PFNGLFRAGMENTLIGHTIVEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightivEXT")) == NULL) || r; + r = ((glFragmentMaterialfEXT = (PFNGLFRAGMENTMATERIALFEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialfEXT")) == NULL) || r; + r = ((glFragmentMaterialfvEXT = (PFNGLFRAGMENTMATERIALFVEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialfvEXT")) == NULL) || r; + r = ((glFragmentMaterialiEXT = (PFNGLFRAGMENTMATERIALIEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialiEXT")) == NULL) || r; + r = ((glFragmentMaterialivEXT = (PFNGLFRAGMENTMATERIALIVEXTPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialivEXT")) == NULL) || r; + r = ((glGetFragmentLightfvEXT = (PFNGLGETFRAGMENTLIGHTFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentLightfvEXT")) == NULL) || r; + r = ((glGetFragmentLightivEXT = (PFNGLGETFRAGMENTLIGHTIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentLightivEXT")) == NULL) || r; + r = ((glGetFragmentMaterialfvEXT = (PFNGLGETFRAGMENTMATERIALFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentMaterialfvEXT")) == NULL) || r; + r = ((glGetFragmentMaterialivEXT = (PFNGLGETFRAGMENTMATERIALIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentMaterialivEXT")) == NULL) || r; + r = ((glLightEnviEXT = (PFNGLLIGHTENVIEXTPROC)glewGetProcAddress((const GLubyte*)"glLightEnviEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_fragment_lighting */ + +#ifdef GL_EXT_framebuffer_blit + +static GLboolean _glewInit_GL_EXT_framebuffer_blit () +{ + GLboolean r = GL_FALSE; + + r = ((glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glBlitFramebufferEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_framebuffer_blit */ + +#ifdef GL_EXT_framebuffer_multisample + +static GLboolean _glewInit_GL_EXT_framebuffer_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageMultisampleEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_framebuffer_multisample */ + +#ifdef GL_EXT_framebuffer_object + +static GLboolean _glewInit_GL_EXT_framebuffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindFramebufferEXT")) == NULL) || r; + r = ((glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindRenderbufferEXT")) == NULL) || r; + r = ((glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)glewGetProcAddress((const GLubyte*)"glCheckFramebufferStatusEXT")) == NULL) || r; + r = ((glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)glewGetProcAddress((const GLubyte*)"glDeleteFramebuffersEXT")) == NULL) || r; + r = ((glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)glewGetProcAddress((const GLubyte*)"glDeleteRenderbuffersEXT")) == NULL) || r; + r = ((glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferRenderbufferEXT")) == NULL) || r; + r = ((glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture1DEXT")) == NULL) || r; + r = ((glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture2DEXT")) == NULL) || r; + r = ((glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture3DEXT")) == NULL) || r; + r = ((glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)glewGetProcAddress((const GLubyte*)"glGenFramebuffersEXT")) == NULL) || r; + r = ((glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)glewGetProcAddress((const GLubyte*)"glGenRenderbuffersEXT")) == NULL) || r; + r = ((glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)glewGetProcAddress((const GLubyte*)"glGenerateMipmapEXT")) == NULL) || r; + r = ((glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFramebufferAttachmentParameterivEXT")) == NULL) || r; + r = ((glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetRenderbufferParameterivEXT")) == NULL) || r; + r = ((glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glIsFramebufferEXT")) == NULL) || r; + r = ((glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glIsRenderbufferEXT")) == NULL) || r; + r = ((glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_framebuffer_object */ + +#ifdef GL_EXT_geometry_shader4 + +static GLboolean _glewInit_GL_EXT_geometry_shader4 () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferTextureEXT = (PFNGLFRAMEBUFFERTEXTUREEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureEXT")) == NULL) || r; + r = ((glFramebufferTextureFaceEXT = (PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureFaceEXT")) == NULL) || r; + r = ((glProgramParameteriEXT = (PFNGLPROGRAMPARAMETERIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramParameteriEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_geometry_shader4 */ + +#ifdef GL_EXT_gpu_program_parameters + +static GLboolean _glewInit_GL_EXT_gpu_program_parameters () +{ + GLboolean r = GL_FALSE; + + r = ((glProgramEnvParameters4fvEXT = (PFNGLPROGRAMENVPARAMETERS4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameters4fvEXT")) == NULL) || r; + r = ((glProgramLocalParameters4fvEXT = (PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameters4fvEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_gpu_program_parameters */ + +#ifdef GL_EXT_gpu_shader4 + +static GLboolean _glewInit_GL_EXT_gpu_shader4 () +{ + GLboolean r = GL_FALSE; + + r = ((glBindFragDataLocationEXT = (PFNGLBINDFRAGDATALOCATIONEXTPROC)glewGetProcAddress((const GLubyte*)"glBindFragDataLocationEXT")) == NULL) || r; + r = ((glGetFragDataLocationEXT = (PFNGLGETFRAGDATALOCATIONEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFragDataLocationEXT")) == NULL) || r; + r = ((glGetUniformuivEXT = (PFNGLGETUNIFORMUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetUniformuivEXT")) == NULL) || r; + r = ((glGetVertexAttribIivEXT = (PFNGLGETVERTEXATTRIBIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribIivEXT")) == NULL) || r; + r = ((glGetVertexAttribIuivEXT = (PFNGLGETVERTEXATTRIBIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribIuivEXT")) == NULL) || r; + r = ((glUniform1uiEXT = (PFNGLUNIFORM1UIEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform1uiEXT")) == NULL) || r; + r = ((glUniform1uivEXT = (PFNGLUNIFORM1UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform1uivEXT")) == NULL) || r; + r = ((glUniform2uiEXT = (PFNGLUNIFORM2UIEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform2uiEXT")) == NULL) || r; + r = ((glUniform2uivEXT = (PFNGLUNIFORM2UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform2uivEXT")) == NULL) || r; + r = ((glUniform3uiEXT = (PFNGLUNIFORM3UIEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform3uiEXT")) == NULL) || r; + r = ((glUniform3uivEXT = (PFNGLUNIFORM3UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform3uivEXT")) == NULL) || r; + r = ((glUniform4uiEXT = (PFNGLUNIFORM4UIEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform4uiEXT")) == NULL) || r; + r = ((glUniform4uivEXT = (PFNGLUNIFORM4UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glUniform4uivEXT")) == NULL) || r; + r = ((glVertexAttribI1iEXT = (PFNGLVERTEXATTRIBI1IEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1iEXT")) == NULL) || r; + r = ((glVertexAttribI1ivEXT = (PFNGLVERTEXATTRIBI1IVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1ivEXT")) == NULL) || r; + r = ((glVertexAttribI1uiEXT = (PFNGLVERTEXATTRIBI1UIEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1uiEXT")) == NULL) || r; + r = ((glVertexAttribI1uivEXT = (PFNGLVERTEXATTRIBI1UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI1uivEXT")) == NULL) || r; + r = ((glVertexAttribI2iEXT = (PFNGLVERTEXATTRIBI2IEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2iEXT")) == NULL) || r; + r = ((glVertexAttribI2ivEXT = (PFNGLVERTEXATTRIBI2IVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2ivEXT")) == NULL) || r; + r = ((glVertexAttribI2uiEXT = (PFNGLVERTEXATTRIBI2UIEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2uiEXT")) == NULL) || r; + r = ((glVertexAttribI2uivEXT = (PFNGLVERTEXATTRIBI2UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI2uivEXT")) == NULL) || r; + r = ((glVertexAttribI3iEXT = (PFNGLVERTEXATTRIBI3IEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3iEXT")) == NULL) || r; + r = ((glVertexAttribI3ivEXT = (PFNGLVERTEXATTRIBI3IVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3ivEXT")) == NULL) || r; + r = ((glVertexAttribI3uiEXT = (PFNGLVERTEXATTRIBI3UIEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3uiEXT")) == NULL) || r; + r = ((glVertexAttribI3uivEXT = (PFNGLVERTEXATTRIBI3UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI3uivEXT")) == NULL) || r; + r = ((glVertexAttribI4bvEXT = (PFNGLVERTEXATTRIBI4BVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4bvEXT")) == NULL) || r; + r = ((glVertexAttribI4iEXT = (PFNGLVERTEXATTRIBI4IEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4iEXT")) == NULL) || r; + r = ((glVertexAttribI4ivEXT = (PFNGLVERTEXATTRIBI4IVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4ivEXT")) == NULL) || r; + r = ((glVertexAttribI4svEXT = (PFNGLVERTEXATTRIBI4SVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4svEXT")) == NULL) || r; + r = ((glVertexAttribI4ubvEXT = (PFNGLVERTEXATTRIBI4UBVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4ubvEXT")) == NULL) || r; + r = ((glVertexAttribI4uiEXT = (PFNGLVERTEXATTRIBI4UIEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4uiEXT")) == NULL) || r; + r = ((glVertexAttribI4uivEXT = (PFNGLVERTEXATTRIBI4UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4uivEXT")) == NULL) || r; + r = ((glVertexAttribI4usvEXT = (PFNGLVERTEXATTRIBI4USVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribI4usvEXT")) == NULL) || r; + r = ((glVertexAttribIPointerEXT = (PFNGLVERTEXATTRIBIPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribIPointerEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_gpu_shader4 */ + +#ifdef GL_EXT_histogram + +static GLboolean _glewInit_GL_EXT_histogram () +{ + GLboolean r = GL_FALSE; + + r = ((glGetHistogramEXT = (PFNGLGETHISTOGRAMEXTPROC)glewGetProcAddress((const GLubyte*)"glGetHistogramEXT")) == NULL) || r; + r = ((glGetHistogramParameterfvEXT = (PFNGLGETHISTOGRAMPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetHistogramParameterfvEXT")) == NULL) || r; + r = ((glGetHistogramParameterivEXT = (PFNGLGETHISTOGRAMPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetHistogramParameterivEXT")) == NULL) || r; + r = ((glGetMinmaxEXT = (PFNGLGETMINMAXEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMinmaxEXT")) == NULL) || r; + r = ((glGetMinmaxParameterfvEXT = (PFNGLGETMINMAXPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMinmaxParameterfvEXT")) == NULL) || r; + r = ((glGetMinmaxParameterivEXT = (PFNGLGETMINMAXPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMinmaxParameterivEXT")) == NULL) || r; + r = ((glHistogramEXT = (PFNGLHISTOGRAMEXTPROC)glewGetProcAddress((const GLubyte*)"glHistogramEXT")) == NULL) || r; + r = ((glMinmaxEXT = (PFNGLMINMAXEXTPROC)glewGetProcAddress((const GLubyte*)"glMinmaxEXT")) == NULL) || r; + r = ((glResetHistogramEXT = (PFNGLRESETHISTOGRAMEXTPROC)glewGetProcAddress((const GLubyte*)"glResetHistogramEXT")) == NULL) || r; + r = ((glResetMinmaxEXT = (PFNGLRESETMINMAXEXTPROC)glewGetProcAddress((const GLubyte*)"glResetMinmaxEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_histogram */ + +#ifdef GL_EXT_index_func + +static GLboolean _glewInit_GL_EXT_index_func () +{ + GLboolean r = GL_FALSE; + + r = ((glIndexFuncEXT = (PFNGLINDEXFUNCEXTPROC)glewGetProcAddress((const GLubyte*)"glIndexFuncEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_index_func */ + +#ifdef GL_EXT_index_material + +static GLboolean _glewInit_GL_EXT_index_material () +{ + GLboolean r = GL_FALSE; + + r = ((glIndexMaterialEXT = (PFNGLINDEXMATERIALEXTPROC)glewGetProcAddress((const GLubyte*)"glIndexMaterialEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_index_material */ + +#ifdef GL_EXT_instanced_arrays + +static GLboolean _glewInit_GL_EXT_instanced_arrays () +{ + GLboolean r = GL_FALSE; + + r = ((glVertexAttribDivisorEXT = (PFNGLVERTEXATTRIBDIVISOREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribDivisorEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_instanced_arrays */ + +#ifdef GL_EXT_light_texture + +static GLboolean _glewInit_GL_EXT_light_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glApplyTextureEXT = (PFNGLAPPLYTEXTUREEXTPROC)glewGetProcAddress((const GLubyte*)"glApplyTextureEXT")) == NULL) || r; + r = ((glTextureLightEXT = (PFNGLTEXTURELIGHTEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureLightEXT")) == NULL) || r; + r = ((glTextureMaterialEXT = (PFNGLTEXTUREMATERIALEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureMaterialEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_light_texture */ + +#ifdef GL_EXT_map_buffer_range + +static GLboolean _glewInit_GL_EXT_map_buffer_range () +{ + GLboolean r = GL_FALSE; + + r = ((glFlushMappedBufferRangeEXT = (PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC)glewGetProcAddress((const GLubyte*)"glFlushMappedBufferRangeEXT")) == NULL) || r; + r = ((glMapBufferRangeEXT = (PFNGLMAPBUFFERRANGEEXTPROC)glewGetProcAddress((const GLubyte*)"glMapBufferRangeEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_map_buffer_range */ + +#ifdef GL_EXT_memory_object + +static GLboolean _glewInit_GL_EXT_memory_object () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferStorageMemEXT = (PFNGLBUFFERSTORAGEMEMEXTPROC)glewGetProcAddress((const GLubyte*)"glBufferStorageMemEXT")) == NULL) || r; + r = ((glCreateMemoryObjectsEXT = (PFNGLCREATEMEMORYOBJECTSEXTPROC)glewGetProcAddress((const GLubyte*)"glCreateMemoryObjectsEXT")) == NULL) || r; + r = ((glDeleteMemoryObjectsEXT = (PFNGLDELETEMEMORYOBJECTSEXTPROC)glewGetProcAddress((const GLubyte*)"glDeleteMemoryObjectsEXT")) == NULL) || r; + r = ((glGetMemoryObjectParameterivEXT = (PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetMemoryObjectParameterivEXT")) == NULL) || r; + r = ((glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetUnsignedBytei_vEXT")) == NULL) || r; + r = ((glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetUnsignedBytevEXT")) == NULL) || r; + r = ((glIsMemoryObjectEXT = (PFNGLISMEMORYOBJECTEXTPROC)glewGetProcAddress((const GLubyte*)"glIsMemoryObjectEXT")) == NULL) || r; + r = ((glMemoryObjectParameterivEXT = (PFNGLMEMORYOBJECTPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glMemoryObjectParameterivEXT")) == NULL) || r; + r = ((glNamedBufferStorageMemEXT = (PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferStorageMemEXT")) == NULL) || r; + r = ((glTexStorageMem1DEXT = (PFNGLTEXSTORAGEMEM1DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorageMem1DEXT")) == NULL) || r; + r = ((glTexStorageMem2DEXT = (PFNGLTEXSTORAGEMEM2DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorageMem2DEXT")) == NULL) || r; + r = ((glTexStorageMem2DMultisampleEXT = (PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorageMem2DMultisampleEXT")) == NULL) || r; + r = ((glTexStorageMem3DEXT = (PFNGLTEXSTORAGEMEM3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorageMem3DEXT")) == NULL) || r; + r = ((glTexStorageMem3DMultisampleEXT = (PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorageMem3DMultisampleEXT")) == NULL) || r; + r = ((glTextureStorageMem1DEXT = (PFNGLTEXTURESTORAGEMEM1DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorageMem1DEXT")) == NULL) || r; + r = ((glTextureStorageMem2DEXT = (PFNGLTEXTURESTORAGEMEM2DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorageMem2DEXT")) == NULL) || r; + r = ((glTextureStorageMem2DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorageMem2DMultisampleEXT")) == NULL) || r; + r = ((glTextureStorageMem3DEXT = (PFNGLTEXTURESTORAGEMEM3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorageMem3DEXT")) == NULL) || r; + r = ((glTextureStorageMem3DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorageMem3DMultisampleEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_memory_object */ + +#ifdef GL_EXT_memory_object_fd + +static GLboolean _glewInit_GL_EXT_memory_object_fd () +{ + GLboolean r = GL_FALSE; + + r = ((glImportMemoryFdEXT = (PFNGLIMPORTMEMORYFDEXTPROC)glewGetProcAddress((const GLubyte*)"glImportMemoryFdEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_memory_object_fd */ + +#ifdef GL_EXT_memory_object_win32 + +static GLboolean _glewInit_GL_EXT_memory_object_win32 () +{ + GLboolean r = GL_FALSE; + + r = ((glImportMemoryWin32HandleEXT = (PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC)glewGetProcAddress((const GLubyte*)"glImportMemoryWin32HandleEXT")) == NULL) || r; + r = ((glImportMemoryWin32NameEXT = (PFNGLIMPORTMEMORYWIN32NAMEEXTPROC)glewGetProcAddress((const GLubyte*)"glImportMemoryWin32NameEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_memory_object_win32 */ + +#ifdef GL_EXT_multi_draw_arrays + +static GLboolean _glewInit_GL_EXT_multi_draw_arrays () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysEXT")) == NULL) || r; + r = ((glMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_multi_draw_arrays */ + +#ifdef GL_EXT_multi_draw_indirect + +static GLboolean _glewInit_GL_EXT_multi_draw_indirect () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectEXT = (PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectEXT")) == NULL) || r; + r = ((glMultiDrawElementsIndirectEXT = (PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_multi_draw_indirect */ + +#ifdef GL_EXT_multisample + +static GLboolean _glewInit_GL_EXT_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glSampleMaskEXT = (PFNGLSAMPLEMASKEXTPROC)glewGetProcAddress((const GLubyte*)"glSampleMaskEXT")) == NULL) || r; + r = ((glSamplePatternEXT = (PFNGLSAMPLEPATTERNEXTPROC)glewGetProcAddress((const GLubyte*)"glSamplePatternEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_multisample */ + +#ifdef GL_EXT_multisampled_render_to_texture + +static GLboolean _glewInit_GL_EXT_multisampled_render_to_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTexture2DMultisampleEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_multisampled_render_to_texture */ + +#ifdef GL_EXT_multiview_draw_buffers + +static GLboolean _glewInit_GL_EXT_multiview_draw_buffers () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawBuffersIndexedEXT = (PFNGLDRAWBUFFERSINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawBuffersIndexedEXT")) == NULL) || r; + r = ((glGetIntegeri_vEXT = (PFNGLGETINTEGERI_VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetIntegeri_vEXT")) == NULL) || r; + r = ((glReadBufferIndexedEXT = (PFNGLREADBUFFERINDEXEDEXTPROC)glewGetProcAddress((const GLubyte*)"glReadBufferIndexedEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_multiview_draw_buffers */ + +#ifdef GL_EXT_paletted_texture + +static GLboolean _glewInit_GL_EXT_paletted_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glColorTableEXT = (PFNGLCOLORTABLEEXTPROC)glewGetProcAddress((const GLubyte*)"glColorTableEXT")) == NULL) || r; + r = ((glGetColorTableEXT = (PFNGLGETCOLORTABLEEXTPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableEXT")) == NULL) || r; + r = ((glGetColorTableParameterfvEXT = (PFNGLGETCOLORTABLEPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableParameterfvEXT")) == NULL) || r; + r = ((glGetColorTableParameterivEXT = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableParameterivEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_paletted_texture */ + +#ifdef GL_EXT_pixel_transform + +static GLboolean _glewInit_GL_EXT_pixel_transform () +{ + GLboolean r = GL_FALSE; + + r = ((glGetPixelTransformParameterfvEXT = (PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetPixelTransformParameterfvEXT")) == NULL) || r; + r = ((glGetPixelTransformParameterivEXT = (PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetPixelTransformParameterivEXT")) == NULL) || r; + r = ((glPixelTransformParameterfEXT = (PFNGLPIXELTRANSFORMPARAMETERFEXTPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameterfEXT")) == NULL) || r; + r = ((glPixelTransformParameterfvEXT = (PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameterfvEXT")) == NULL) || r; + r = ((glPixelTransformParameteriEXT = (PFNGLPIXELTRANSFORMPARAMETERIEXTPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameteriEXT")) == NULL) || r; + r = ((glPixelTransformParameterivEXT = (PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameterivEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_pixel_transform */ + +#ifdef GL_EXT_point_parameters + +static GLboolean _glewInit_GL_EXT_point_parameters () +{ + GLboolean r = GL_FALSE; + + r = ((glPointParameterfEXT = (PFNGLPOINTPARAMETERFEXTPROC)glewGetProcAddress((const GLubyte*)"glPointParameterfEXT")) == NULL) || r; + r = ((glPointParameterfvEXT = (PFNGLPOINTPARAMETERFVEXTPROC)glewGetProcAddress((const GLubyte*)"glPointParameterfvEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_point_parameters */ + +#ifdef GL_EXT_polygon_offset + +static GLboolean _glewInit_GL_EXT_polygon_offset () +{ + GLboolean r = GL_FALSE; + + r = ((glPolygonOffsetEXT = (PFNGLPOLYGONOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glPolygonOffsetEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_polygon_offset */ + +#ifdef GL_EXT_polygon_offset_clamp + +static GLboolean _glewInit_GL_EXT_polygon_offset_clamp () +{ + GLboolean r = GL_FALSE; + + r = ((glPolygonOffsetClampEXT = (PFNGLPOLYGONOFFSETCLAMPEXTPROC)glewGetProcAddress((const GLubyte*)"glPolygonOffsetClampEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_polygon_offset_clamp */ + +#ifdef GL_EXT_provoking_vertex + +static GLboolean _glewInit_GL_EXT_provoking_vertex () +{ + GLboolean r = GL_FALSE; + + r = ((glProvokingVertexEXT = (PFNGLPROVOKINGVERTEXEXTPROC)glewGetProcAddress((const GLubyte*)"glProvokingVertexEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_provoking_vertex */ + +#ifdef GL_EXT_raster_multisample + +static GLboolean _glewInit_GL_EXT_raster_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glCoverageModulationNV = (PFNGLCOVERAGEMODULATIONNVPROC)glewGetProcAddress((const GLubyte*)"glCoverageModulationNV")) == NULL) || r; + r = ((glCoverageModulationTableNV = (PFNGLCOVERAGEMODULATIONTABLENVPROC)glewGetProcAddress((const GLubyte*)"glCoverageModulationTableNV")) == NULL) || r; + r = ((glGetCoverageModulationTableNV = (PFNGLGETCOVERAGEMODULATIONTABLENVPROC)glewGetProcAddress((const GLubyte*)"glGetCoverageModulationTableNV")) == NULL) || r; + r = ((glRasterSamplesEXT = (PFNGLRASTERSAMPLESEXTPROC)glewGetProcAddress((const GLubyte*)"glRasterSamplesEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_raster_multisample */ + +#ifdef GL_EXT_scene_marker + +static GLboolean _glewInit_GL_EXT_scene_marker () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginSceneEXT = (PFNGLBEGINSCENEEXTPROC)glewGetProcAddress((const GLubyte*)"glBeginSceneEXT")) == NULL) || r; + r = ((glEndSceneEXT = (PFNGLENDSCENEEXTPROC)glewGetProcAddress((const GLubyte*)"glEndSceneEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_scene_marker */ + +#ifdef GL_EXT_secondary_color + +static GLboolean _glewInit_GL_EXT_secondary_color () +{ + GLboolean r = GL_FALSE; + + r = ((glSecondaryColor3bEXT = (PFNGLSECONDARYCOLOR3BEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3bEXT")) == NULL) || r; + r = ((glSecondaryColor3bvEXT = (PFNGLSECONDARYCOLOR3BVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3bvEXT")) == NULL) || r; + r = ((glSecondaryColor3dEXT = (PFNGLSECONDARYCOLOR3DEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3dEXT")) == NULL) || r; + r = ((glSecondaryColor3dvEXT = (PFNGLSECONDARYCOLOR3DVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3dvEXT")) == NULL) || r; + r = ((glSecondaryColor3fEXT = (PFNGLSECONDARYCOLOR3FEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3fEXT")) == NULL) || r; + r = ((glSecondaryColor3fvEXT = (PFNGLSECONDARYCOLOR3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3fvEXT")) == NULL) || r; + r = ((glSecondaryColor3iEXT = (PFNGLSECONDARYCOLOR3IEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3iEXT")) == NULL) || r; + r = ((glSecondaryColor3ivEXT = (PFNGLSECONDARYCOLOR3IVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3ivEXT")) == NULL) || r; + r = ((glSecondaryColor3sEXT = (PFNGLSECONDARYCOLOR3SEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3sEXT")) == NULL) || r; + r = ((glSecondaryColor3svEXT = (PFNGLSECONDARYCOLOR3SVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3svEXT")) == NULL) || r; + r = ((glSecondaryColor3ubEXT = (PFNGLSECONDARYCOLOR3UBEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3ubEXT")) == NULL) || r; + r = ((glSecondaryColor3ubvEXT = (PFNGLSECONDARYCOLOR3UBVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3ubvEXT")) == NULL) || r; + r = ((glSecondaryColor3uiEXT = (PFNGLSECONDARYCOLOR3UIEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3uiEXT")) == NULL) || r; + r = ((glSecondaryColor3uivEXT = (PFNGLSECONDARYCOLOR3UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3uivEXT")) == NULL) || r; + r = ((glSecondaryColor3usEXT = (PFNGLSECONDARYCOLOR3USEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3usEXT")) == NULL) || r; + r = ((glSecondaryColor3usvEXT = (PFNGLSECONDARYCOLOR3USVEXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3usvEXT")) == NULL) || r; + r = ((glSecondaryColorPointerEXT = (PFNGLSECONDARYCOLORPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColorPointerEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_secondary_color */ + +#ifdef GL_EXT_semaphore + +static GLboolean _glewInit_GL_EXT_semaphore () +{ + GLboolean r = GL_FALSE; + + r = ((glDeleteSemaphoresEXT = (PFNGLDELETESEMAPHORESEXTPROC)glewGetProcAddress((const GLubyte*)"glDeleteSemaphoresEXT")) == NULL) || r; + r = ((glGenSemaphoresEXT = (PFNGLGENSEMAPHORESEXTPROC)glewGetProcAddress((const GLubyte*)"glGenSemaphoresEXT")) == NULL) || r; + r = ((glGetSemaphoreParameterui64vEXT = (PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetSemaphoreParameterui64vEXT")) == NULL) || r; + r = ((glIsSemaphoreEXT = (PFNGLISSEMAPHOREEXTPROC)glewGetProcAddress((const GLubyte*)"glIsSemaphoreEXT")) == NULL) || r; + r = ((glSemaphoreParameterui64vEXT = (PFNGLSEMAPHOREPARAMETERUI64VEXTPROC)glewGetProcAddress((const GLubyte*)"glSemaphoreParameterui64vEXT")) == NULL) || r; + r = ((glSignalSemaphoreEXT = (PFNGLSIGNALSEMAPHOREEXTPROC)glewGetProcAddress((const GLubyte*)"glSignalSemaphoreEXT")) == NULL) || r; + r = ((glWaitSemaphoreEXT = (PFNGLWAITSEMAPHOREEXTPROC)glewGetProcAddress((const GLubyte*)"glWaitSemaphoreEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_semaphore */ + +#ifdef GL_EXT_semaphore_fd + +static GLboolean _glewInit_GL_EXT_semaphore_fd () +{ + GLboolean r = GL_FALSE; + + r = ((glImportSemaphoreFdEXT = (PFNGLIMPORTSEMAPHOREFDEXTPROC)glewGetProcAddress((const GLubyte*)"glImportSemaphoreFdEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_semaphore_fd */ + +#ifdef GL_EXT_semaphore_win32 + +static GLboolean _glewInit_GL_EXT_semaphore_win32 () +{ + GLboolean r = GL_FALSE; + + r = ((glImportSemaphoreWin32HandleEXT = (PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC)glewGetProcAddress((const GLubyte*)"glImportSemaphoreWin32HandleEXT")) == NULL) || r; + r = ((glImportSemaphoreWin32NameEXT = (PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC)glewGetProcAddress((const GLubyte*)"glImportSemaphoreWin32NameEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_semaphore_win32 */ + +#ifdef GL_EXT_separate_shader_objects + +static GLboolean _glewInit_GL_EXT_separate_shader_objects () +{ + GLboolean r = GL_FALSE; + + r = ((glActiveProgramEXT = (PFNGLACTIVEPROGRAMEXTPROC)glewGetProcAddress((const GLubyte*)"glActiveProgramEXT")) == NULL) || r; + r = ((glCreateShaderProgramEXT = (PFNGLCREATESHADERPROGRAMEXTPROC)glewGetProcAddress((const GLubyte*)"glCreateShaderProgramEXT")) == NULL) || r; + r = ((glUseShaderProgramEXT = (PFNGLUSESHADERPROGRAMEXTPROC)glewGetProcAddress((const GLubyte*)"glUseShaderProgramEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_separate_shader_objects */ + +#ifdef GL_EXT_shader_image_load_store + +static GLboolean _glewInit_GL_EXT_shader_image_load_store () +{ + GLboolean r = GL_FALSE; + + r = ((glBindImageTextureEXT = (PFNGLBINDIMAGETEXTUREEXTPROC)glewGetProcAddress((const GLubyte*)"glBindImageTextureEXT")) == NULL) || r; + r = ((glMemoryBarrierEXT = (PFNGLMEMORYBARRIEREXTPROC)glewGetProcAddress((const GLubyte*)"glMemoryBarrierEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_shader_image_load_store */ + +#ifdef GL_EXT_shader_pixel_local_storage2 + +static GLboolean _glewInit_GL_EXT_shader_pixel_local_storage2 () +{ + GLboolean r = GL_FALSE; + + r = ((glClearPixelLocalStorageuiEXT = (PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC)glewGetProcAddress((const GLubyte*)"glClearPixelLocalStorageuiEXT")) == NULL) || r; + r = ((glFramebufferPixelLocalStorageSizeEXT = (PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferPixelLocalStorageSizeEXT")) == NULL) || r; + r = ((glGetFramebufferPixelLocalStorageSizeEXT = (PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)glewGetProcAddress((const GLubyte*)"glGetFramebufferPixelLocalStorageSizeEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_shader_pixel_local_storage2 */ + +#ifdef GL_EXT_sparse_texture + +static GLboolean _glewInit_GL_EXT_sparse_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glTexPageCommitmentEXT = (PFNGLTEXPAGECOMMITMENTEXTPROC)glewGetProcAddress((const GLubyte*)"glTexPageCommitmentEXT")) == NULL) || r; + r = ((glTexturePageCommitmentEXT = (PFNGLTEXTUREPAGECOMMITMENTEXTPROC)glewGetProcAddress((const GLubyte*)"glTexturePageCommitmentEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_sparse_texture */ + +#ifdef GL_EXT_stencil_two_side + +static GLboolean _glewInit_GL_EXT_stencil_two_side () +{ + GLboolean r = GL_FALSE; + + r = ((glActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC)glewGetProcAddress((const GLubyte*)"glActiveStencilFaceEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_stencil_two_side */ + +#ifdef GL_EXT_subtexture + +static GLboolean _glewInit_GL_EXT_subtexture () +{ + GLboolean r = GL_FALSE; + + r = ((glTexSubImage1DEXT = (PFNGLTEXSUBIMAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexSubImage1DEXT")) == NULL) || r; + r = ((glTexSubImage2DEXT = (PFNGLTEXSUBIMAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexSubImage2DEXT")) == NULL) || r; + r = ((glTexSubImage3DEXT = (PFNGLTEXSUBIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexSubImage3DEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_subtexture */ + +#ifdef GL_EXT_texture3D + +static GLboolean _glewInit_GL_EXT_texture3D () +{ + GLboolean r = GL_FALSE; + + r = ((glTexImage3DEXT = (PFNGLTEXIMAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexImage3DEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture3D */ + +#ifdef GL_EXT_texture_array + +static GLboolean _glewInit_GL_EXT_texture_array () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferTextureLayerEXT = (PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureLayerEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture_array */ + +#ifdef GL_EXT_texture_buffer_object + +static GLboolean _glewInit_GL_EXT_texture_buffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glTexBufferEXT = (PFNGLTEXBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glTexBufferEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture_buffer_object */ + +#ifdef GL_EXT_texture_integer + +static GLboolean _glewInit_GL_EXT_texture_integer () +{ + GLboolean r = GL_FALSE; + + r = ((glClearColorIiEXT = (PFNGLCLEARCOLORIIEXTPROC)glewGetProcAddress((const GLubyte*)"glClearColorIiEXT")) == NULL) || r; + r = ((glClearColorIuiEXT = (PFNGLCLEARCOLORIUIEXTPROC)glewGetProcAddress((const GLubyte*)"glClearColorIuiEXT")) == NULL) || r; + r = ((glGetTexParameterIivEXT = (PFNGLGETTEXPARAMETERIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTexParameterIivEXT")) == NULL) || r; + r = ((glGetTexParameterIuivEXT = (PFNGLGETTEXPARAMETERIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTexParameterIuivEXT")) == NULL) || r; + r = ((glTexParameterIivEXT = (PFNGLTEXPARAMETERIIVEXTPROC)glewGetProcAddress((const GLubyte*)"glTexParameterIivEXT")) == NULL) || r; + r = ((glTexParameterIuivEXT = (PFNGLTEXPARAMETERIUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glTexParameterIuivEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture_integer */ + +#ifdef GL_EXT_texture_object + +static GLboolean _glewInit_GL_EXT_texture_object () +{ + GLboolean r = GL_FALSE; + + r = ((glAreTexturesResidentEXT = (PFNGLARETEXTURESRESIDENTEXTPROC)glewGetProcAddress((const GLubyte*)"glAreTexturesResidentEXT")) == NULL) || r; + r = ((glBindTextureEXT = (PFNGLBINDTEXTUREEXTPROC)glewGetProcAddress((const GLubyte*)"glBindTextureEXT")) == NULL) || r; + r = ((glDeleteTexturesEXT = (PFNGLDELETETEXTURESEXTPROC)glewGetProcAddress((const GLubyte*)"glDeleteTexturesEXT")) == NULL) || r; + r = ((glGenTexturesEXT = (PFNGLGENTEXTURESEXTPROC)glewGetProcAddress((const GLubyte*)"glGenTexturesEXT")) == NULL) || r; + r = ((glIsTextureEXT = (PFNGLISTEXTUREEXTPROC)glewGetProcAddress((const GLubyte*)"glIsTextureEXT")) == NULL) || r; + r = ((glPrioritizeTexturesEXT = (PFNGLPRIORITIZETEXTURESEXTPROC)glewGetProcAddress((const GLubyte*)"glPrioritizeTexturesEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture_object */ + +#ifdef GL_EXT_texture_perturb_normal + +static GLboolean _glewInit_GL_EXT_texture_perturb_normal () +{ + GLboolean r = GL_FALSE; + + r = ((glTextureNormalEXT = (PFNGLTEXTURENORMALEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureNormalEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture_perturb_normal */ + +#ifdef GL_EXT_texture_storage + +static GLboolean _glewInit_GL_EXT_texture_storage () +{ + GLboolean r = GL_FALSE; + + r = ((glTexStorage1DEXT = (PFNGLTEXSTORAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorage1DEXT")) == NULL) || r; + r = ((glTexStorage2DEXT = (PFNGLTEXSTORAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorage2DEXT")) == NULL) || r; + r = ((glTexStorage3DEXT = (PFNGLTEXSTORAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTexStorage3DEXT")) == NULL) || r; + r = ((glTextureStorage1DEXT = (PFNGLTEXTURESTORAGE1DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage1DEXT")) == NULL) || r; + r = ((glTextureStorage2DEXT = (PFNGLTEXTURESTORAGE2DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage2DEXT")) == NULL) || r; + r = ((glTextureStorage3DEXT = (PFNGLTEXTURESTORAGE3DEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage3DEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture_storage */ + +#ifdef GL_EXT_texture_view + +static GLboolean _glewInit_GL_EXT_texture_view () +{ + GLboolean r = GL_FALSE; + + r = ((glTextureViewEXT = (PFNGLTEXTUREVIEWEXTPROC)glewGetProcAddress((const GLubyte*)"glTextureViewEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_texture_view */ + +#ifdef GL_EXT_timer_query + +static GLboolean _glewInit_GL_EXT_timer_query () +{ + GLboolean r = GL_FALSE; + + r = ((glGetQueryObjecti64vEXT = (PFNGLGETQUERYOBJECTI64VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjecti64vEXT")) == NULL) || r; + r = ((glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectui64vEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_timer_query */ + +#ifdef GL_EXT_transform_feedback + +static GLboolean _glewInit_GL_EXT_transform_feedback () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginTransformFeedbackEXT = (PFNGLBEGINTRANSFORMFEEDBACKEXTPROC)glewGetProcAddress((const GLubyte*)"glBeginTransformFeedbackEXT")) == NULL) || r; + r = ((glBindBufferBaseEXT = (PFNGLBINDBUFFERBASEEXTPROC)glewGetProcAddress((const GLubyte*)"glBindBufferBaseEXT")) == NULL) || r; + r = ((glBindBufferOffsetEXT = (PFNGLBINDBUFFEROFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glBindBufferOffsetEXT")) == NULL) || r; + r = ((glBindBufferRangeEXT = (PFNGLBINDBUFFERRANGEEXTPROC)glewGetProcAddress((const GLubyte*)"glBindBufferRangeEXT")) == NULL) || r; + r = ((glEndTransformFeedbackEXT = (PFNGLENDTRANSFORMFEEDBACKEXTPROC)glewGetProcAddress((const GLubyte*)"glEndTransformFeedbackEXT")) == NULL) || r; + r = ((glGetTransformFeedbackVaryingEXT = (PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbackVaryingEXT")) == NULL) || r; + r = ((glTransformFeedbackVaryingsEXT = (PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackVaryingsEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_transform_feedback */ + +#ifdef GL_EXT_vertex_array + +static GLboolean _glewInit_GL_EXT_vertex_array () +{ + GLboolean r = GL_FALSE; + + r = ((glArrayElementEXT = (PFNGLARRAYELEMENTEXTPROC)glewGetProcAddress((const GLubyte*)"glArrayElementEXT")) == NULL) || r; + r = ((glColorPointerEXT = (PFNGLCOLORPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glColorPointerEXT")) == NULL) || r; + r = ((glDrawArraysEXT = (PFNGLDRAWARRAYSEXTPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysEXT")) == NULL) || r; + r = ((glEdgeFlagPointerEXT = (PFNGLEDGEFLAGPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glEdgeFlagPointerEXT")) == NULL) || r; + r = ((glIndexPointerEXT = (PFNGLINDEXPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glIndexPointerEXT")) == NULL) || r; + r = ((glNormalPointerEXT = (PFNGLNORMALPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glNormalPointerEXT")) == NULL) || r; + r = ((glTexCoordPointerEXT = (PFNGLTEXCOORDPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glTexCoordPointerEXT")) == NULL) || r; + r = ((glVertexPointerEXT = (PFNGLVERTEXPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexPointerEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_vertex_array */ + +#ifdef GL_EXT_vertex_array_setXXX + +static GLboolean _glewInit_GL_EXT_vertex_array_setXXX () +{ + GLboolean r = GL_FALSE; + + r = ((glBindArraySetEXT = (PFNGLBINDARRAYSETEXTPROC)glewGetProcAddress((const GLubyte*)"glBindArraySetEXT")) == NULL) || r; + r = ((glCreateArraySetExt = (PFNGLCREATEARRAYSETEXTPROC)glewGetProcAddress((const GLubyte*)"glCreateArraySetExt")) == NULL) || r; + r = ((glDeleteArraySetsEXT = (PFNGLDELETEARRAYSETSEXTPROC)glewGetProcAddress((const GLubyte*)"glDeleteArraySetsEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_vertex_array_setXXX */ + +#ifdef GL_EXT_vertex_attrib_64bit + +static GLboolean _glewInit_GL_EXT_vertex_attrib_64bit () +{ + GLboolean r = GL_FALSE; + + r = ((glGetVertexAttribLdvEXT = (PFNGLGETVERTEXATTRIBLDVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribLdvEXT")) == NULL) || r; + r = ((glVertexArrayVertexAttribLOffsetEXT = (PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribLOffsetEXT")) == NULL) || r; + r = ((glVertexAttribL1dEXT = (PFNGLVERTEXATTRIBL1DEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1dEXT")) == NULL) || r; + r = ((glVertexAttribL1dvEXT = (PFNGLVERTEXATTRIBL1DVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1dvEXT")) == NULL) || r; + r = ((glVertexAttribL2dEXT = (PFNGLVERTEXATTRIBL2DEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2dEXT")) == NULL) || r; + r = ((glVertexAttribL2dvEXT = (PFNGLVERTEXATTRIBL2DVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2dvEXT")) == NULL) || r; + r = ((glVertexAttribL3dEXT = (PFNGLVERTEXATTRIBL3DEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3dEXT")) == NULL) || r; + r = ((glVertexAttribL3dvEXT = (PFNGLVERTEXATTRIBL3DVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3dvEXT")) == NULL) || r; + r = ((glVertexAttribL4dEXT = (PFNGLVERTEXATTRIBL4DEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4dEXT")) == NULL) || r; + r = ((glVertexAttribL4dvEXT = (PFNGLVERTEXATTRIBL4DVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4dvEXT")) == NULL) || r; + r = ((glVertexAttribLPointerEXT = (PFNGLVERTEXATTRIBLPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribLPointerEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_vertex_attrib_64bit */ + +#ifdef GL_EXT_vertex_shader + +static GLboolean _glewInit_GL_EXT_vertex_shader () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginVertexShaderEXT = (PFNGLBEGINVERTEXSHADEREXTPROC)glewGetProcAddress((const GLubyte*)"glBeginVertexShaderEXT")) == NULL) || r; + r = ((glBindLightParameterEXT = (PFNGLBINDLIGHTPARAMETEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindLightParameterEXT")) == NULL) || r; + r = ((glBindMaterialParameterEXT = (PFNGLBINDMATERIALPARAMETEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindMaterialParameterEXT")) == NULL) || r; + r = ((glBindParameterEXT = (PFNGLBINDPARAMETEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindParameterEXT")) == NULL) || r; + r = ((glBindTexGenParameterEXT = (PFNGLBINDTEXGENPARAMETEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindTexGenParameterEXT")) == NULL) || r; + r = ((glBindTextureUnitParameterEXT = (PFNGLBINDTEXTUREUNITPARAMETEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindTextureUnitParameterEXT")) == NULL) || r; + r = ((glBindVertexShaderEXT = (PFNGLBINDVERTEXSHADEREXTPROC)glewGetProcAddress((const GLubyte*)"glBindVertexShaderEXT")) == NULL) || r; + r = ((glDeleteVertexShaderEXT = (PFNGLDELETEVERTEXSHADEREXTPROC)glewGetProcAddress((const GLubyte*)"glDeleteVertexShaderEXT")) == NULL) || r; + r = ((glDisableVariantClientStateEXT = (PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC)glewGetProcAddress((const GLubyte*)"glDisableVariantClientStateEXT")) == NULL) || r; + r = ((glEnableVariantClientStateEXT = (PFNGLENABLEVARIANTCLIENTSTATEEXTPROC)glewGetProcAddress((const GLubyte*)"glEnableVariantClientStateEXT")) == NULL) || r; + r = ((glEndVertexShaderEXT = (PFNGLENDVERTEXSHADEREXTPROC)glewGetProcAddress((const GLubyte*)"glEndVertexShaderEXT")) == NULL) || r; + r = ((glExtractComponentEXT = (PFNGLEXTRACTCOMPONENTEXTPROC)glewGetProcAddress((const GLubyte*)"glExtractComponentEXT")) == NULL) || r; + r = ((glGenSymbolsEXT = (PFNGLGENSYMBOLSEXTPROC)glewGetProcAddress((const GLubyte*)"glGenSymbolsEXT")) == NULL) || r; + r = ((glGenVertexShadersEXT = (PFNGLGENVERTEXSHADERSEXTPROC)glewGetProcAddress((const GLubyte*)"glGenVertexShadersEXT")) == NULL) || r; + r = ((glGetInvariantBooleanvEXT = (PFNGLGETINVARIANTBOOLEANVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetInvariantBooleanvEXT")) == NULL) || r; + r = ((glGetInvariantFloatvEXT = (PFNGLGETINVARIANTFLOATVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetInvariantFloatvEXT")) == NULL) || r; + r = ((glGetInvariantIntegervEXT = (PFNGLGETINVARIANTINTEGERVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetInvariantIntegervEXT")) == NULL) || r; + r = ((glGetLocalConstantBooleanvEXT = (PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetLocalConstantBooleanvEXT")) == NULL) || r; + r = ((glGetLocalConstantFloatvEXT = (PFNGLGETLOCALCONSTANTFLOATVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetLocalConstantFloatvEXT")) == NULL) || r; + r = ((glGetLocalConstantIntegervEXT = (PFNGLGETLOCALCONSTANTINTEGERVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetLocalConstantIntegervEXT")) == NULL) || r; + r = ((glGetVariantBooleanvEXT = (PFNGLGETVARIANTBOOLEANVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVariantBooleanvEXT")) == NULL) || r; + r = ((glGetVariantFloatvEXT = (PFNGLGETVARIANTFLOATVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVariantFloatvEXT")) == NULL) || r; + r = ((glGetVariantIntegervEXT = (PFNGLGETVARIANTINTEGERVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVariantIntegervEXT")) == NULL) || r; + r = ((glGetVariantPointervEXT = (PFNGLGETVARIANTPOINTERVEXTPROC)glewGetProcAddress((const GLubyte*)"glGetVariantPointervEXT")) == NULL) || r; + r = ((glInsertComponentEXT = (PFNGLINSERTCOMPONENTEXTPROC)glewGetProcAddress((const GLubyte*)"glInsertComponentEXT")) == NULL) || r; + r = ((glIsVariantEnabledEXT = (PFNGLISVARIANTENABLEDEXTPROC)glewGetProcAddress((const GLubyte*)"glIsVariantEnabledEXT")) == NULL) || r; + r = ((glSetInvariantEXT = (PFNGLSETINVARIANTEXTPROC)glewGetProcAddress((const GLubyte*)"glSetInvariantEXT")) == NULL) || r; + r = ((glSetLocalConstantEXT = (PFNGLSETLOCALCONSTANTEXTPROC)glewGetProcAddress((const GLubyte*)"glSetLocalConstantEXT")) == NULL) || r; + r = ((glShaderOp1EXT = (PFNGLSHADEROP1EXTPROC)glewGetProcAddress((const GLubyte*)"glShaderOp1EXT")) == NULL) || r; + r = ((glShaderOp2EXT = (PFNGLSHADEROP2EXTPROC)glewGetProcAddress((const GLubyte*)"glShaderOp2EXT")) == NULL) || r; + r = ((glShaderOp3EXT = (PFNGLSHADEROP3EXTPROC)glewGetProcAddress((const GLubyte*)"glShaderOp3EXT")) == NULL) || r; + r = ((glSwizzleEXT = (PFNGLSWIZZLEEXTPROC)glewGetProcAddress((const GLubyte*)"glSwizzleEXT")) == NULL) || r; + r = ((glVariantPointerEXT = (PFNGLVARIANTPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glVariantPointerEXT")) == NULL) || r; + r = ((glVariantbvEXT = (PFNGLVARIANTBVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantbvEXT")) == NULL) || r; + r = ((glVariantdvEXT = (PFNGLVARIANTDVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantdvEXT")) == NULL) || r; + r = ((glVariantfvEXT = (PFNGLVARIANTFVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantfvEXT")) == NULL) || r; + r = ((glVariantivEXT = (PFNGLVARIANTIVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantivEXT")) == NULL) || r; + r = ((glVariantsvEXT = (PFNGLVARIANTSVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantsvEXT")) == NULL) || r; + r = ((glVariantubvEXT = (PFNGLVARIANTUBVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantubvEXT")) == NULL) || r; + r = ((glVariantuivEXT = (PFNGLVARIANTUIVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantuivEXT")) == NULL) || r; + r = ((glVariantusvEXT = (PFNGLVARIANTUSVEXTPROC)glewGetProcAddress((const GLubyte*)"glVariantusvEXT")) == NULL) || r; + r = ((glWriteMaskEXT = (PFNGLWRITEMASKEXTPROC)glewGetProcAddress((const GLubyte*)"glWriteMaskEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_vertex_shader */ + +#ifdef GL_EXT_vertex_weighting + +static GLboolean _glewInit_GL_EXT_vertex_weighting () +{ + GLboolean r = GL_FALSE; + + r = ((glVertexWeightPointerEXT = (PFNGLVERTEXWEIGHTPOINTEREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexWeightPointerEXT")) == NULL) || r; + r = ((glVertexWeightfEXT = (PFNGLVERTEXWEIGHTFEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexWeightfEXT")) == NULL) || r; + r = ((glVertexWeightfvEXT = (PFNGLVERTEXWEIGHTFVEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexWeightfvEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_vertex_weighting */ + +#ifdef GL_EXT_win32_keyed_mutex + +static GLboolean _glewInit_GL_EXT_win32_keyed_mutex () +{ + GLboolean r = GL_FALSE; + + r = ((glAcquireKeyedMutexWin32EXT = (PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC)glewGetProcAddress((const GLubyte*)"glAcquireKeyedMutexWin32EXT")) == NULL) || r; + r = ((glReleaseKeyedMutexWin32EXT = (PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC)glewGetProcAddress((const GLubyte*)"glReleaseKeyedMutexWin32EXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_win32_keyed_mutex */ + +#ifdef GL_EXT_window_rectangles + +static GLboolean _glewInit_GL_EXT_window_rectangles () +{ + GLboolean r = GL_FALSE; + + r = ((glWindowRectanglesEXT = (PFNGLWINDOWRECTANGLESEXTPROC)glewGetProcAddress((const GLubyte*)"glWindowRectanglesEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_window_rectangles */ + +#ifdef GL_EXT_x11_sync_object + +static GLboolean _glewInit_GL_EXT_x11_sync_object () +{ + GLboolean r = GL_FALSE; + + r = ((glImportSyncEXT = (PFNGLIMPORTSYNCEXTPROC)glewGetProcAddress((const GLubyte*)"glImportSyncEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_EXT_x11_sync_object */ + +#ifdef GL_GREMEDY_frame_terminator + +static GLboolean _glewInit_GL_GREMEDY_frame_terminator () +{ + GLboolean r = GL_FALSE; + + r = ((glFrameTerminatorGREMEDY = (PFNGLFRAMETERMINATORGREMEDYPROC)glewGetProcAddress((const GLubyte*)"glFrameTerminatorGREMEDY")) == NULL) || r; + + return r; +} + +#endif /* GL_GREMEDY_frame_terminator */ + +#ifdef GL_GREMEDY_string_marker + +static GLboolean _glewInit_GL_GREMEDY_string_marker () +{ + GLboolean r = GL_FALSE; + + r = ((glStringMarkerGREMEDY = (PFNGLSTRINGMARKERGREMEDYPROC)glewGetProcAddress((const GLubyte*)"glStringMarkerGREMEDY")) == NULL) || r; + + return r; +} + +#endif /* GL_GREMEDY_string_marker */ + +#ifdef GL_HP_image_transform + +static GLboolean _glewInit_GL_HP_image_transform () +{ + GLboolean r = GL_FALSE; + + r = ((glGetImageTransformParameterfvHP = (PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC)glewGetProcAddress((const GLubyte*)"glGetImageTransformParameterfvHP")) == NULL) || r; + r = ((glGetImageTransformParameterivHP = (PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC)glewGetProcAddress((const GLubyte*)"glGetImageTransformParameterivHP")) == NULL) || r; + r = ((glImageTransformParameterfHP = (PFNGLIMAGETRANSFORMPARAMETERFHPPROC)glewGetProcAddress((const GLubyte*)"glImageTransformParameterfHP")) == NULL) || r; + r = ((glImageTransformParameterfvHP = (PFNGLIMAGETRANSFORMPARAMETERFVHPPROC)glewGetProcAddress((const GLubyte*)"glImageTransformParameterfvHP")) == NULL) || r; + r = ((glImageTransformParameteriHP = (PFNGLIMAGETRANSFORMPARAMETERIHPPROC)glewGetProcAddress((const GLubyte*)"glImageTransformParameteriHP")) == NULL) || r; + r = ((glImageTransformParameterivHP = (PFNGLIMAGETRANSFORMPARAMETERIVHPPROC)glewGetProcAddress((const GLubyte*)"glImageTransformParameterivHP")) == NULL) || r; + + return r; +} + +#endif /* GL_HP_image_transform */ + +#ifdef GL_IBM_multimode_draw_arrays + +static GLboolean _glewInit_GL_IBM_multimode_draw_arrays () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiModeDrawArraysIBM = (PFNGLMULTIMODEDRAWARRAYSIBMPROC)glewGetProcAddress((const GLubyte*)"glMultiModeDrawArraysIBM")) == NULL) || r; + r = ((glMultiModeDrawElementsIBM = (PFNGLMULTIMODEDRAWELEMENTSIBMPROC)glewGetProcAddress((const GLubyte*)"glMultiModeDrawElementsIBM")) == NULL) || r; + + return r; +} + +#endif /* GL_IBM_multimode_draw_arrays */ + +#ifdef GL_IBM_vertex_array_lists + +static GLboolean _glewInit_GL_IBM_vertex_array_lists () +{ + GLboolean r = GL_FALSE; + + r = ((glColorPointerListIBM = (PFNGLCOLORPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glColorPointerListIBM")) == NULL) || r; + r = ((glEdgeFlagPointerListIBM = (PFNGLEDGEFLAGPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glEdgeFlagPointerListIBM")) == NULL) || r; + r = ((glFogCoordPointerListIBM = (PFNGLFOGCOORDPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glFogCoordPointerListIBM")) == NULL) || r; + r = ((glIndexPointerListIBM = (PFNGLINDEXPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glIndexPointerListIBM")) == NULL) || r; + r = ((glNormalPointerListIBM = (PFNGLNORMALPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glNormalPointerListIBM")) == NULL) || r; + r = ((glSecondaryColorPointerListIBM = (PFNGLSECONDARYCOLORPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColorPointerListIBM")) == NULL) || r; + r = ((glTexCoordPointerListIBM = (PFNGLTEXCOORDPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glTexCoordPointerListIBM")) == NULL) || r; + r = ((glVertexPointerListIBM = (PFNGLVERTEXPOINTERLISTIBMPROC)glewGetProcAddress((const GLubyte*)"glVertexPointerListIBM")) == NULL) || r; + + return r; +} + +#endif /* GL_IBM_vertex_array_lists */ + +#ifdef GL_INTEL_map_texture + +static GLboolean _glewInit_GL_INTEL_map_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glMapTexture2DINTEL = (PFNGLMAPTEXTURE2DINTELPROC)glewGetProcAddress((const GLubyte*)"glMapTexture2DINTEL")) == NULL) || r; + r = ((glSyncTextureINTEL = (PFNGLSYNCTEXTUREINTELPROC)glewGetProcAddress((const GLubyte*)"glSyncTextureINTEL")) == NULL) || r; + r = ((glUnmapTexture2DINTEL = (PFNGLUNMAPTEXTURE2DINTELPROC)glewGetProcAddress((const GLubyte*)"glUnmapTexture2DINTEL")) == NULL) || r; + + return r; +} + +#endif /* GL_INTEL_map_texture */ + +#ifdef GL_INTEL_parallel_arrays + +static GLboolean _glewInit_GL_INTEL_parallel_arrays () +{ + GLboolean r = GL_FALSE; + + r = ((glColorPointervINTEL = (PFNGLCOLORPOINTERVINTELPROC)glewGetProcAddress((const GLubyte*)"glColorPointervINTEL")) == NULL) || r; + r = ((glNormalPointervINTEL = (PFNGLNORMALPOINTERVINTELPROC)glewGetProcAddress((const GLubyte*)"glNormalPointervINTEL")) == NULL) || r; + r = ((glTexCoordPointervINTEL = (PFNGLTEXCOORDPOINTERVINTELPROC)glewGetProcAddress((const GLubyte*)"glTexCoordPointervINTEL")) == NULL) || r; + r = ((glVertexPointervINTEL = (PFNGLVERTEXPOINTERVINTELPROC)glewGetProcAddress((const GLubyte*)"glVertexPointervINTEL")) == NULL) || r; + + return r; +} + +#endif /* GL_INTEL_parallel_arrays */ + +#ifdef GL_INTEL_performance_query + +static GLboolean _glewInit_GL_INTEL_performance_query () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginPerfQueryINTEL = (PFNGLBEGINPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glBeginPerfQueryINTEL")) == NULL) || r; + r = ((glCreatePerfQueryINTEL = (PFNGLCREATEPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glCreatePerfQueryINTEL")) == NULL) || r; + r = ((glDeletePerfQueryINTEL = (PFNGLDELETEPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glDeletePerfQueryINTEL")) == NULL) || r; + r = ((glEndPerfQueryINTEL = (PFNGLENDPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glEndPerfQueryINTEL")) == NULL) || r; + r = ((glGetFirstPerfQueryIdINTEL = (PFNGLGETFIRSTPERFQUERYIDINTELPROC)glewGetProcAddress((const GLubyte*)"glGetFirstPerfQueryIdINTEL")) == NULL) || r; + r = ((glGetNextPerfQueryIdINTEL = (PFNGLGETNEXTPERFQUERYIDINTELPROC)glewGetProcAddress((const GLubyte*)"glGetNextPerfQueryIdINTEL")) == NULL) || r; + r = ((glGetPerfCounterInfoINTEL = (PFNGLGETPERFCOUNTERINFOINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfCounterInfoINTEL")) == NULL) || r; + r = ((glGetPerfQueryDataINTEL = (PFNGLGETPERFQUERYDATAINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfQueryDataINTEL")) == NULL) || r; + r = ((glGetPerfQueryIdByNameINTEL = (PFNGLGETPERFQUERYIDBYNAMEINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfQueryIdByNameINTEL")) == NULL) || r; + r = ((glGetPerfQueryInfoINTEL = (PFNGLGETPERFQUERYINFOINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfQueryInfoINTEL")) == NULL) || r; + + return r; +} + +#endif /* GL_INTEL_performance_query */ + +#ifdef GL_INTEL_texture_scissor + +static GLboolean _glewInit_GL_INTEL_texture_scissor () +{ + GLboolean r = GL_FALSE; + + r = ((glTexScissorFuncINTEL = (PFNGLTEXSCISSORFUNCINTELPROC)glewGetProcAddress((const GLubyte*)"glTexScissorFuncINTEL")) == NULL) || r; + r = ((glTexScissorINTEL = (PFNGLTEXSCISSORINTELPROC)glewGetProcAddress((const GLubyte*)"glTexScissorINTEL")) == NULL) || r; + + return r; +} + +#endif /* GL_INTEL_texture_scissor */ + +#ifdef GL_KHR_blend_equation_advanced + +static GLboolean _glewInit_GL_KHR_blend_equation_advanced () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendBarrierKHR = (PFNGLBLENDBARRIERKHRPROC)glewGetProcAddress((const GLubyte*)"glBlendBarrierKHR")) == NULL) || r; + + return r; +} + +#endif /* GL_KHR_blend_equation_advanced */ + +#ifdef GL_KHR_debug + +static GLboolean _glewInit_GL_KHR_debug () +{ + GLboolean r = GL_FALSE; + + r = ((glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageCallback")) == NULL) || r; + r = ((glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageControl")) == NULL) || r; + r = ((glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)glewGetProcAddress((const GLubyte*)"glDebugMessageInsert")) == NULL) || r; + r = ((glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)glewGetProcAddress((const GLubyte*)"glGetDebugMessageLog")) == NULL) || r; + r = ((glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)glewGetProcAddress((const GLubyte*)"glGetObjectLabel")) == NULL) || r; + r = ((glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)glewGetProcAddress((const GLubyte*)"glGetObjectPtrLabel")) == NULL) || r; + r = ((glObjectLabel = (PFNGLOBJECTLABELPROC)glewGetProcAddress((const GLubyte*)"glObjectLabel")) == NULL) || r; + r = ((glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)glewGetProcAddress((const GLubyte*)"glObjectPtrLabel")) == NULL) || r; + r = ((glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)glewGetProcAddress((const GLubyte*)"glPopDebugGroup")) == NULL) || r; + r = ((glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)glewGetProcAddress((const GLubyte*)"glPushDebugGroup")) == NULL) || r; + + return r; +} + +#endif /* GL_KHR_debug */ + +#ifdef GL_KHR_parallel_shader_compile + +static GLboolean _glewInit_GL_KHR_parallel_shader_compile () +{ + GLboolean r = GL_FALSE; + + r = ((glMaxShaderCompilerThreadsKHR = (PFNGLMAXSHADERCOMPILERTHREADSKHRPROC)glewGetProcAddress((const GLubyte*)"glMaxShaderCompilerThreadsKHR")) == NULL) || r; + + return r; +} + +#endif /* GL_KHR_parallel_shader_compile */ + +#ifdef GL_KHR_robustness + +static GLboolean _glewInit_GL_KHR_robustness () +{ + GLboolean r = GL_FALSE; + + r = ((glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformfv")) == NULL) || r; + r = ((glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformiv")) == NULL) || r; + r = ((glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformuiv")) == NULL) || r; + r = ((glReadnPixels = (PFNGLREADNPIXELSPROC)glewGetProcAddress((const GLubyte*)"glReadnPixels")) == NULL) || r; + + return r; +} + +#endif /* GL_KHR_robustness */ + +#ifdef GL_KTX_buffer_region + +static GLboolean _glewInit_GL_KTX_buffer_region () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferRegionEnabled = (PFNGLBUFFERREGIONENABLEDPROC)glewGetProcAddress((const GLubyte*)"glBufferRegionEnabled")) == NULL) || r; + r = ((glDeleteBufferRegion = (PFNGLDELETEBUFFERREGIONPROC)glewGetProcAddress((const GLubyte*)"glDeleteBufferRegion")) == NULL) || r; + r = ((glDrawBufferRegion = (PFNGLDRAWBUFFERREGIONPROC)glewGetProcAddress((const GLubyte*)"glDrawBufferRegion")) == NULL) || r; + r = ((glNewBufferRegion = (PFNGLNEWBUFFERREGIONPROC)glewGetProcAddress((const GLubyte*)"glNewBufferRegion")) == NULL) || r; + r = ((glReadBufferRegion = (PFNGLREADBUFFERREGIONPROC)glewGetProcAddress((const GLubyte*)"glReadBufferRegion")) == NULL) || r; + + return r; +} + +#endif /* GL_KTX_buffer_region */ + +#ifdef GL_MESA_resize_buffers + +static GLboolean _glewInit_GL_MESA_resize_buffers () +{ + GLboolean r = GL_FALSE; + + r = ((glResizeBuffersMESA = (PFNGLRESIZEBUFFERSMESAPROC)glewGetProcAddress((const GLubyte*)"glResizeBuffersMESA")) == NULL) || r; + + return r; +} + +#endif /* GL_MESA_resize_buffers */ + +#ifdef GL_MESA_window_pos + +static GLboolean _glewInit_GL_MESA_window_pos () +{ + GLboolean r = GL_FALSE; + + r = ((glWindowPos2dMESA = (PFNGLWINDOWPOS2DMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2dMESA")) == NULL) || r; + r = ((glWindowPos2dvMESA = (PFNGLWINDOWPOS2DVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2dvMESA")) == NULL) || r; + r = ((glWindowPos2fMESA = (PFNGLWINDOWPOS2FMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2fMESA")) == NULL) || r; + r = ((glWindowPos2fvMESA = (PFNGLWINDOWPOS2FVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2fvMESA")) == NULL) || r; + r = ((glWindowPos2iMESA = (PFNGLWINDOWPOS2IMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2iMESA")) == NULL) || r; + r = ((glWindowPos2ivMESA = (PFNGLWINDOWPOS2IVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2ivMESA")) == NULL) || r; + r = ((glWindowPos2sMESA = (PFNGLWINDOWPOS2SMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2sMESA")) == NULL) || r; + r = ((glWindowPos2svMESA = (PFNGLWINDOWPOS2SVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos2svMESA")) == NULL) || r; + r = ((glWindowPos3dMESA = (PFNGLWINDOWPOS3DMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3dMESA")) == NULL) || r; + r = ((glWindowPos3dvMESA = (PFNGLWINDOWPOS3DVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3dvMESA")) == NULL) || r; + r = ((glWindowPos3fMESA = (PFNGLWINDOWPOS3FMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3fMESA")) == NULL) || r; + r = ((glWindowPos3fvMESA = (PFNGLWINDOWPOS3FVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3fvMESA")) == NULL) || r; + r = ((glWindowPos3iMESA = (PFNGLWINDOWPOS3IMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3iMESA")) == NULL) || r; + r = ((glWindowPos3ivMESA = (PFNGLWINDOWPOS3IVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3ivMESA")) == NULL) || r; + r = ((glWindowPos3sMESA = (PFNGLWINDOWPOS3SMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3sMESA")) == NULL) || r; + r = ((glWindowPos3svMESA = (PFNGLWINDOWPOS3SVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos3svMESA")) == NULL) || r; + r = ((glWindowPos4dMESA = (PFNGLWINDOWPOS4DMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4dMESA")) == NULL) || r; + r = ((glWindowPos4dvMESA = (PFNGLWINDOWPOS4DVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4dvMESA")) == NULL) || r; + r = ((glWindowPos4fMESA = (PFNGLWINDOWPOS4FMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4fMESA")) == NULL) || r; + r = ((glWindowPos4fvMESA = (PFNGLWINDOWPOS4FVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4fvMESA")) == NULL) || r; + r = ((glWindowPos4iMESA = (PFNGLWINDOWPOS4IMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4iMESA")) == NULL) || r; + r = ((glWindowPos4ivMESA = (PFNGLWINDOWPOS4IVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4ivMESA")) == NULL) || r; + r = ((glWindowPos4sMESA = (PFNGLWINDOWPOS4SMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4sMESA")) == NULL) || r; + r = ((glWindowPos4svMESA = (PFNGLWINDOWPOS4SVMESAPROC)glewGetProcAddress((const GLubyte*)"glWindowPos4svMESA")) == NULL) || r; + + return r; +} + +#endif /* GL_MESA_window_pos */ + +#ifdef GL_NVX_conditional_render + +static GLboolean _glewInit_GL_NVX_conditional_render () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginConditionalRenderNVX = (PFNGLBEGINCONDITIONALRENDERNVXPROC)glewGetProcAddress((const GLubyte*)"glBeginConditionalRenderNVX")) == NULL) || r; + r = ((glEndConditionalRenderNVX = (PFNGLENDCONDITIONALRENDERNVXPROC)glewGetProcAddress((const GLubyte*)"glEndConditionalRenderNVX")) == NULL) || r; + + return r; +} + +#endif /* GL_NVX_conditional_render */ + +#ifdef GL_NVX_linked_gpu_multicast + +static GLboolean _glewInit_GL_NVX_linked_gpu_multicast () +{ + GLboolean r = GL_FALSE; + + r = ((glLGPUCopyImageSubDataNVX = (PFNGLLGPUCOPYIMAGESUBDATANVXPROC)glewGetProcAddress((const GLubyte*)"glLGPUCopyImageSubDataNVX")) == NULL) || r; + r = ((glLGPUInterlockNVX = (PFNGLLGPUINTERLOCKNVXPROC)glewGetProcAddress((const GLubyte*)"glLGPUInterlockNVX")) == NULL) || r; + r = ((glLGPUNamedBufferSubDataNVX = (PFNGLLGPUNAMEDBUFFERSUBDATANVXPROC)glewGetProcAddress((const GLubyte*)"glLGPUNamedBufferSubDataNVX")) == NULL) || r; + + return r; +} + +#endif /* GL_NVX_linked_gpu_multicast */ + +#ifdef GL_NV_3dvision_settings + +static GLboolean _glewInit_GL_NV_3dvision_settings () +{ + GLboolean r = GL_FALSE; + + r = ((glStereoParameterfNV = (PFNGLSTEREOPARAMETERFNVPROC)glewGetProcAddress((const GLubyte*)"glStereoParameterfNV")) == NULL) || r; + r = ((glStereoParameteriNV = (PFNGLSTEREOPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glStereoParameteriNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_3dvision_settings */ + +#ifdef GL_NV_bindless_multi_draw_indirect + +static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectBindlessNV = (PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectBindlessNV")) == NULL) || r; + r = ((glMultiDrawElementsIndirectBindlessNV = (PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectBindlessNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_bindless_multi_draw_indirect */ + +#ifdef GL_NV_bindless_multi_draw_indirect_count + +static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect_count () +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectBindlessCountNV = (PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectBindlessCountNV")) == NULL) || r; + r = ((glMultiDrawElementsIndirectBindlessCountNV = (PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectBindlessCountNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_bindless_multi_draw_indirect_count */ + +#ifdef GL_NV_bindless_texture + +static GLboolean _glewInit_GL_NV_bindless_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glGetImageHandleNV = (PFNGLGETIMAGEHANDLENVPROC)glewGetProcAddress((const GLubyte*)"glGetImageHandleNV")) == NULL) || r; + r = ((glGetTextureHandleNV = (PFNGLGETTEXTUREHANDLENVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureHandleNV")) == NULL) || r; + r = ((glGetTextureSamplerHandleNV = (PFNGLGETTEXTURESAMPLERHANDLENVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureSamplerHandleNV")) == NULL) || r; + r = ((glIsImageHandleResidentNV = (PFNGLISIMAGEHANDLERESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glIsImageHandleResidentNV")) == NULL) || r; + r = ((glIsTextureHandleResidentNV = (PFNGLISTEXTUREHANDLERESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glIsTextureHandleResidentNV")) == NULL) || r; + r = ((glMakeImageHandleNonResidentNV = (PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeImageHandleNonResidentNV")) == NULL) || r; + r = ((glMakeImageHandleResidentNV = (PFNGLMAKEIMAGEHANDLERESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeImageHandleResidentNV")) == NULL) || r; + r = ((glMakeTextureHandleNonResidentNV = (PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeTextureHandleNonResidentNV")) == NULL) || r; + r = ((glMakeTextureHandleResidentNV = (PFNGLMAKETEXTUREHANDLERESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeTextureHandleResidentNV")) == NULL) || r; + r = ((glProgramUniformHandleui64NV = (PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformHandleui64NV")) == NULL) || r; + r = ((glProgramUniformHandleui64vNV = (PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformHandleui64vNV")) == NULL) || r; + r = ((glUniformHandleui64NV = (PFNGLUNIFORMHANDLEUI64NVPROC)glewGetProcAddress((const GLubyte*)"glUniformHandleui64NV")) == NULL) || r; + r = ((glUniformHandleui64vNV = (PFNGLUNIFORMHANDLEUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniformHandleui64vNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_bindless_texture */ + +#ifdef GL_NV_blend_equation_advanced + +static GLboolean _glewInit_GL_NV_blend_equation_advanced () +{ + GLboolean r = GL_FALSE; + + r = ((glBlendBarrierNV = (PFNGLBLENDBARRIERNVPROC)glewGetProcAddress((const GLubyte*)"glBlendBarrierNV")) == NULL) || r; + r = ((glBlendParameteriNV = (PFNGLBLENDPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glBlendParameteriNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_blend_equation_advanced */ + +#ifdef GL_NV_clip_space_w_scaling + +static GLboolean _glewInit_GL_NV_clip_space_w_scaling () +{ + GLboolean r = GL_FALSE; + + r = ((glViewportPositionWScaleNV = (PFNGLVIEWPORTPOSITIONWSCALENVPROC)glewGetProcAddress((const GLubyte*)"glViewportPositionWScaleNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_clip_space_w_scaling */ + +#ifdef GL_NV_command_list + +static GLboolean _glewInit_GL_NV_command_list () +{ + GLboolean r = GL_FALSE; + + r = ((glCallCommandListNV = (PFNGLCALLCOMMANDLISTNVPROC)glewGetProcAddress((const GLubyte*)"glCallCommandListNV")) == NULL) || r; + r = ((glCommandListSegmentsNV = (PFNGLCOMMANDLISTSEGMENTSNVPROC)glewGetProcAddress((const GLubyte*)"glCommandListSegmentsNV")) == NULL) || r; + r = ((glCompileCommandListNV = (PFNGLCOMPILECOMMANDLISTNVPROC)glewGetProcAddress((const GLubyte*)"glCompileCommandListNV")) == NULL) || r; + r = ((glCreateCommandListsNV = (PFNGLCREATECOMMANDLISTSNVPROC)glewGetProcAddress((const GLubyte*)"glCreateCommandListsNV")) == NULL) || r; + r = ((glCreateStatesNV = (PFNGLCREATESTATESNVPROC)glewGetProcAddress((const GLubyte*)"glCreateStatesNV")) == NULL) || r; + r = ((glDeleteCommandListsNV = (PFNGLDELETECOMMANDLISTSNVPROC)glewGetProcAddress((const GLubyte*)"glDeleteCommandListsNV")) == NULL) || r; + r = ((glDeleteStatesNV = (PFNGLDELETESTATESNVPROC)glewGetProcAddress((const GLubyte*)"glDeleteStatesNV")) == NULL) || r; + r = ((glDrawCommandsAddressNV = (PFNGLDRAWCOMMANDSADDRESSNVPROC)glewGetProcAddress((const GLubyte*)"glDrawCommandsAddressNV")) == NULL) || r; + r = ((glDrawCommandsNV = (PFNGLDRAWCOMMANDSNVPROC)glewGetProcAddress((const GLubyte*)"glDrawCommandsNV")) == NULL) || r; + r = ((glDrawCommandsStatesAddressNV = (PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC)glewGetProcAddress((const GLubyte*)"glDrawCommandsStatesAddressNV")) == NULL) || r; + r = ((glDrawCommandsStatesNV = (PFNGLDRAWCOMMANDSSTATESNVPROC)glewGetProcAddress((const GLubyte*)"glDrawCommandsStatesNV")) == NULL) || r; + r = ((glGetCommandHeaderNV = (PFNGLGETCOMMANDHEADERNVPROC)glewGetProcAddress((const GLubyte*)"glGetCommandHeaderNV")) == NULL) || r; + r = ((glGetStageIndexNV = (PFNGLGETSTAGEINDEXNVPROC)glewGetProcAddress((const GLubyte*)"glGetStageIndexNV")) == NULL) || r; + r = ((glIsCommandListNV = (PFNGLISCOMMANDLISTNVPROC)glewGetProcAddress((const GLubyte*)"glIsCommandListNV")) == NULL) || r; + r = ((glIsStateNV = (PFNGLISSTATENVPROC)glewGetProcAddress((const GLubyte*)"glIsStateNV")) == NULL) || r; + r = ((glListDrawCommandsStatesClientNV = (PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC)glewGetProcAddress((const GLubyte*)"glListDrawCommandsStatesClientNV")) == NULL) || r; + r = ((glStateCaptureNV = (PFNGLSTATECAPTURENVPROC)glewGetProcAddress((const GLubyte*)"glStateCaptureNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_command_list */ + +#ifdef GL_NV_conditional_render + +static GLboolean _glewInit_GL_NV_conditional_render () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginConditionalRenderNV = (PFNGLBEGINCONDITIONALRENDERNVPROC)glewGetProcAddress((const GLubyte*)"glBeginConditionalRenderNV")) == NULL) || r; + r = ((glEndConditionalRenderNV = (PFNGLENDCONDITIONALRENDERNVPROC)glewGetProcAddress((const GLubyte*)"glEndConditionalRenderNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_conditional_render */ + +#ifdef GL_NV_conservative_raster + +static GLboolean _glewInit_GL_NV_conservative_raster () +{ + GLboolean r = GL_FALSE; + + r = ((glSubpixelPrecisionBiasNV = (PFNGLSUBPIXELPRECISIONBIASNVPROC)glewGetProcAddress((const GLubyte*)"glSubpixelPrecisionBiasNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_conservative_raster */ + +#ifdef GL_NV_conservative_raster_dilate + +static GLboolean _glewInit_GL_NV_conservative_raster_dilate () +{ + GLboolean r = GL_FALSE; + + r = ((glConservativeRasterParameterfNV = (PFNGLCONSERVATIVERASTERPARAMETERFNVPROC)glewGetProcAddress((const GLubyte*)"glConservativeRasterParameterfNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_conservative_raster_dilate */ + +#ifdef GL_NV_conservative_raster_pre_snap_triangles + +static GLboolean _glewInit_GL_NV_conservative_raster_pre_snap_triangles () +{ + GLboolean r = GL_FALSE; + + r = ((glConservativeRasterParameteriNV = (PFNGLCONSERVATIVERASTERPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glConservativeRasterParameteriNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_conservative_raster_pre_snap_triangles */ + +#ifdef GL_NV_copy_buffer + +static GLboolean _glewInit_GL_NV_copy_buffer () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyBufferSubDataNV = (PFNGLCOPYBUFFERSUBDATANVPROC)glewGetProcAddress((const GLubyte*)"glCopyBufferSubDataNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_copy_buffer */ + +#ifdef GL_NV_copy_image + +static GLboolean _glewInit_GL_NV_copy_image () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyImageSubDataNV = (PFNGLCOPYIMAGESUBDATANVPROC)glewGetProcAddress((const GLubyte*)"glCopyImageSubDataNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_copy_image */ + +#ifdef GL_NV_depth_buffer_float + +static GLboolean _glewInit_GL_NV_depth_buffer_float () +{ + GLboolean r = GL_FALSE; + + r = ((glClearDepthdNV = (PFNGLCLEARDEPTHDNVPROC)glewGetProcAddress((const GLubyte*)"glClearDepthdNV")) == NULL) || r; + r = ((glDepthBoundsdNV = (PFNGLDEPTHBOUNDSDNVPROC)glewGetProcAddress((const GLubyte*)"glDepthBoundsdNV")) == NULL) || r; + r = ((glDepthRangedNV = (PFNGLDEPTHRANGEDNVPROC)glewGetProcAddress((const GLubyte*)"glDepthRangedNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_depth_buffer_float */ + +#ifdef GL_NV_draw_buffers + +static GLboolean _glewInit_GL_NV_draw_buffers () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawBuffersNV = (PFNGLDRAWBUFFERSNVPROC)glewGetProcAddress((const GLubyte*)"glDrawBuffersNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_draw_buffers */ + +#ifdef GL_NV_draw_instanced + +static GLboolean _glewInit_GL_NV_draw_instanced () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysInstancedNV = (PFNGLDRAWARRAYSINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstancedNV")) == NULL) || r; + r = ((glDrawElementsInstancedNV = (PFNGLDRAWELEMENTSINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_draw_instanced */ + +#ifdef GL_NV_draw_texture + +static GLboolean _glewInit_GL_NV_draw_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawTextureNV = (PFNGLDRAWTEXTURENVPROC)glewGetProcAddress((const GLubyte*)"glDrawTextureNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_draw_texture */ + +#ifdef GL_NV_draw_vulkan_image + +static GLboolean _glewInit_GL_NV_draw_vulkan_image () +{ + GLboolean r = GL_FALSE; + + r = ((glDrawVkImageNV = (PFNGLDRAWVKIMAGENVPROC)glewGetProcAddress((const GLubyte*)"glDrawVkImageNV")) == NULL) || r; + r = ((glGetVkProcAddrNV = (PFNGLGETVKPROCADDRNVPROC)glewGetProcAddress((const GLubyte*)"glGetVkProcAddrNV")) == NULL) || r; + r = ((glSignalVkFenceNV = (PFNGLSIGNALVKFENCENVPROC)glewGetProcAddress((const GLubyte*)"glSignalVkFenceNV")) == NULL) || r; + r = ((glSignalVkSemaphoreNV = (PFNGLSIGNALVKSEMAPHORENVPROC)glewGetProcAddress((const GLubyte*)"glSignalVkSemaphoreNV")) == NULL) || r; + r = ((glWaitVkSemaphoreNV = (PFNGLWAITVKSEMAPHORENVPROC)glewGetProcAddress((const GLubyte*)"glWaitVkSemaphoreNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_draw_vulkan_image */ + +#ifdef GL_NV_evaluators + +static GLboolean _glewInit_GL_NV_evaluators () +{ + GLboolean r = GL_FALSE; + + r = ((glEvalMapsNV = (PFNGLEVALMAPSNVPROC)glewGetProcAddress((const GLubyte*)"glEvalMapsNV")) == NULL) || r; + r = ((glGetMapAttribParameterfvNV = (PFNGLGETMAPATTRIBPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetMapAttribParameterfvNV")) == NULL) || r; + r = ((glGetMapAttribParameterivNV = (PFNGLGETMAPATTRIBPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetMapAttribParameterivNV")) == NULL) || r; + r = ((glGetMapControlPointsNV = (PFNGLGETMAPCONTROLPOINTSNVPROC)glewGetProcAddress((const GLubyte*)"glGetMapControlPointsNV")) == NULL) || r; + r = ((glGetMapParameterfvNV = (PFNGLGETMAPPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetMapParameterfvNV")) == NULL) || r; + r = ((glGetMapParameterivNV = (PFNGLGETMAPPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetMapParameterivNV")) == NULL) || r; + r = ((glMapControlPointsNV = (PFNGLMAPCONTROLPOINTSNVPROC)glewGetProcAddress((const GLubyte*)"glMapControlPointsNV")) == NULL) || r; + r = ((glMapParameterfvNV = (PFNGLMAPPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glMapParameterfvNV")) == NULL) || r; + r = ((glMapParameterivNV = (PFNGLMAPPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glMapParameterivNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_evaluators */ + +#ifdef GL_NV_explicit_multisample + +static GLboolean _glewInit_GL_NV_explicit_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glGetMultisamplefvNV = (PFNGLGETMULTISAMPLEFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetMultisamplefvNV")) == NULL) || r; + r = ((glSampleMaskIndexedNV = (PFNGLSAMPLEMASKINDEXEDNVPROC)glewGetProcAddress((const GLubyte*)"glSampleMaskIndexedNV")) == NULL) || r; + r = ((glTexRenderbufferNV = (PFNGLTEXRENDERBUFFERNVPROC)glewGetProcAddress((const GLubyte*)"glTexRenderbufferNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_explicit_multisample */ + +#ifdef GL_NV_fence + +static GLboolean _glewInit_GL_NV_fence () +{ + GLboolean r = GL_FALSE; + + r = ((glDeleteFencesNV = (PFNGLDELETEFENCESNVPROC)glewGetProcAddress((const GLubyte*)"glDeleteFencesNV")) == NULL) || r; + r = ((glFinishFenceNV = (PFNGLFINISHFENCENVPROC)glewGetProcAddress((const GLubyte*)"glFinishFenceNV")) == NULL) || r; + r = ((glGenFencesNV = (PFNGLGENFENCESNVPROC)glewGetProcAddress((const GLubyte*)"glGenFencesNV")) == NULL) || r; + r = ((glGetFenceivNV = (PFNGLGETFENCEIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetFenceivNV")) == NULL) || r; + r = ((glIsFenceNV = (PFNGLISFENCENVPROC)glewGetProcAddress((const GLubyte*)"glIsFenceNV")) == NULL) || r; + r = ((glSetFenceNV = (PFNGLSETFENCENVPROC)glewGetProcAddress((const GLubyte*)"glSetFenceNV")) == NULL) || r; + r = ((glTestFenceNV = (PFNGLTESTFENCENVPROC)glewGetProcAddress((const GLubyte*)"glTestFenceNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_fence */ + +#ifdef GL_NV_fragment_coverage_to_color + +static GLboolean _glewInit_GL_NV_fragment_coverage_to_color () +{ + GLboolean r = GL_FALSE; + + r = ((glFragmentCoverageColorNV = (PFNGLFRAGMENTCOVERAGECOLORNVPROC)glewGetProcAddress((const GLubyte*)"glFragmentCoverageColorNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_fragment_coverage_to_color */ + +#ifdef GL_NV_fragment_program + +static GLboolean _glewInit_GL_NV_fragment_program () +{ + GLboolean r = GL_FALSE; + + r = ((glGetProgramNamedParameterdvNV = (PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramNamedParameterdvNV")) == NULL) || r; + r = ((glGetProgramNamedParameterfvNV = (PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramNamedParameterfvNV")) == NULL) || r; + r = ((glProgramNamedParameter4dNV = (PFNGLPROGRAMNAMEDPARAMETER4DNVPROC)glewGetProcAddress((const GLubyte*)"glProgramNamedParameter4dNV")) == NULL) || r; + r = ((glProgramNamedParameter4dvNV = (PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramNamedParameter4dvNV")) == NULL) || r; + r = ((glProgramNamedParameter4fNV = (PFNGLPROGRAMNAMEDPARAMETER4FNVPROC)glewGetProcAddress((const GLubyte*)"glProgramNamedParameter4fNV")) == NULL) || r; + r = ((glProgramNamedParameter4fvNV = (PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramNamedParameter4fvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_fragment_program */ + +#ifdef GL_NV_framebuffer_blit + +static GLboolean _glewInit_GL_NV_framebuffer_blit () +{ + GLboolean r = GL_FALSE; + + r = ((glBlitFramebufferNV = (PFNGLBLITFRAMEBUFFERNVPROC)glewGetProcAddress((const GLubyte*)"glBlitFramebufferNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_framebuffer_blit */ + +#ifdef GL_NV_framebuffer_multisample + +static GLboolean _glewInit_GL_NV_framebuffer_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glRenderbufferStorageMultisampleNV = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageMultisampleNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_framebuffer_multisample */ + +#ifdef GL_NV_framebuffer_multisample_coverage + +static GLboolean _glewInit_GL_NV_framebuffer_multisample_coverage () +{ + GLboolean r = GL_FALSE; + + r = ((glRenderbufferStorageMultisampleCoverageNV = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageMultisampleCoverageNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_framebuffer_multisample_coverage */ + +#ifdef GL_NV_geometry_program4 + +static GLboolean _glewInit_GL_NV_geometry_program4 () +{ + GLboolean r = GL_FALSE; + + r = ((glProgramVertexLimitNV = (PFNGLPROGRAMVERTEXLIMITNVPROC)glewGetProcAddress((const GLubyte*)"glProgramVertexLimitNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_geometry_program4 */ + +#ifdef GL_NV_gpu_multicast + +static GLboolean _glewInit_GL_NV_gpu_multicast () +{ + GLboolean r = GL_FALSE; + + r = ((glMulticastBarrierNV = (PFNGLMULTICASTBARRIERNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastBarrierNV")) == NULL) || r; + r = ((glMulticastBlitFramebufferNV = (PFNGLMULTICASTBLITFRAMEBUFFERNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastBlitFramebufferNV")) == NULL) || r; + r = ((glMulticastBufferSubDataNV = (PFNGLMULTICASTBUFFERSUBDATANVPROC)glewGetProcAddress((const GLubyte*)"glMulticastBufferSubDataNV")) == NULL) || r; + r = ((glMulticastCopyBufferSubDataNV = (PFNGLMULTICASTCOPYBUFFERSUBDATANVPROC)glewGetProcAddress((const GLubyte*)"glMulticastCopyBufferSubDataNV")) == NULL) || r; + r = ((glMulticastCopyImageSubDataNV = (PFNGLMULTICASTCOPYIMAGESUBDATANVPROC)glewGetProcAddress((const GLubyte*)"glMulticastCopyImageSubDataNV")) == NULL) || r; + r = ((glMulticastFramebufferSampleLocationsfvNV = (PFNGLMULTICASTFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastFramebufferSampleLocationsfvNV")) == NULL) || r; + r = ((glMulticastGetQueryObjecti64vNV = (PFNGLMULTICASTGETQUERYOBJECTI64VNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastGetQueryObjecti64vNV")) == NULL) || r; + r = ((glMulticastGetQueryObjectivNV = (PFNGLMULTICASTGETQUERYOBJECTIVNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastGetQueryObjectivNV")) == NULL) || r; + r = ((glMulticastGetQueryObjectui64vNV = (PFNGLMULTICASTGETQUERYOBJECTUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastGetQueryObjectui64vNV")) == NULL) || r; + r = ((glMulticastGetQueryObjectuivNV = (PFNGLMULTICASTGETQUERYOBJECTUIVNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastGetQueryObjectuivNV")) == NULL) || r; + r = ((glMulticastWaitSyncNV = (PFNGLMULTICASTWAITSYNCNVPROC)glewGetProcAddress((const GLubyte*)"glMulticastWaitSyncNV")) == NULL) || r; + r = ((glRenderGpuMaskNV = (PFNGLRENDERGPUMASKNVPROC)glewGetProcAddress((const GLubyte*)"glRenderGpuMaskNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_gpu_multicast */ + +#ifdef GL_NV_gpu_program4 + +static GLboolean _glewInit_GL_NV_gpu_program4 () +{ + GLboolean r = GL_FALSE; + + r = ((glProgramEnvParameterI4iNV = (PFNGLPROGRAMENVPARAMETERI4INVPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameterI4iNV")) == NULL) || r; + r = ((glProgramEnvParameterI4ivNV = (PFNGLPROGRAMENVPARAMETERI4IVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameterI4ivNV")) == NULL) || r; + r = ((glProgramEnvParameterI4uiNV = (PFNGLPROGRAMENVPARAMETERI4UINVPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameterI4uiNV")) == NULL) || r; + r = ((glProgramEnvParameterI4uivNV = (PFNGLPROGRAMENVPARAMETERI4UIVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParameterI4uivNV")) == NULL) || r; + r = ((glProgramEnvParametersI4ivNV = (PFNGLPROGRAMENVPARAMETERSI4IVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParametersI4ivNV")) == NULL) || r; + r = ((glProgramEnvParametersI4uivNV = (PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramEnvParametersI4uivNV")) == NULL) || r; + r = ((glProgramLocalParameterI4iNV = (PFNGLPROGRAMLOCALPARAMETERI4INVPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameterI4iNV")) == NULL) || r; + r = ((glProgramLocalParameterI4ivNV = (PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameterI4ivNV")) == NULL) || r; + r = ((glProgramLocalParameterI4uiNV = (PFNGLPROGRAMLOCALPARAMETERI4UINVPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameterI4uiNV")) == NULL) || r; + r = ((glProgramLocalParameterI4uivNV = (PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParameterI4uivNV")) == NULL) || r; + r = ((glProgramLocalParametersI4ivNV = (PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParametersI4ivNV")) == NULL) || r; + r = ((glProgramLocalParametersI4uivNV = (PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramLocalParametersI4uivNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_gpu_program4 */ + +#ifdef GL_NV_gpu_shader5 + +static GLboolean _glewInit_GL_NV_gpu_shader5 () +{ + GLboolean r = GL_FALSE; + + r = ((glGetUniformi64vNV = (PFNGLGETUNIFORMI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetUniformi64vNV")) == NULL) || r; + r = ((glGetUniformui64vNV = (PFNGLGETUNIFORMUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetUniformui64vNV")) == NULL) || r; + r = ((glProgramUniform1i64NV = (PFNGLPROGRAMUNIFORM1I64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1i64NV")) == NULL) || r; + r = ((glProgramUniform1i64vNV = (PFNGLPROGRAMUNIFORM1I64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1i64vNV")) == NULL) || r; + r = ((glProgramUniform1ui64NV = (PFNGLPROGRAMUNIFORM1UI64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ui64NV")) == NULL) || r; + r = ((glProgramUniform1ui64vNV = (PFNGLPROGRAMUNIFORM1UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ui64vNV")) == NULL) || r; + r = ((glProgramUniform2i64NV = (PFNGLPROGRAMUNIFORM2I64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2i64NV")) == NULL) || r; + r = ((glProgramUniform2i64vNV = (PFNGLPROGRAMUNIFORM2I64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2i64vNV")) == NULL) || r; + r = ((glProgramUniform2ui64NV = (PFNGLPROGRAMUNIFORM2UI64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ui64NV")) == NULL) || r; + r = ((glProgramUniform2ui64vNV = (PFNGLPROGRAMUNIFORM2UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ui64vNV")) == NULL) || r; + r = ((glProgramUniform3i64NV = (PFNGLPROGRAMUNIFORM3I64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3i64NV")) == NULL) || r; + r = ((glProgramUniform3i64vNV = (PFNGLPROGRAMUNIFORM3I64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3i64vNV")) == NULL) || r; + r = ((glProgramUniform3ui64NV = (PFNGLPROGRAMUNIFORM3UI64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ui64NV")) == NULL) || r; + r = ((glProgramUniform3ui64vNV = (PFNGLPROGRAMUNIFORM3UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ui64vNV")) == NULL) || r; + r = ((glProgramUniform4i64NV = (PFNGLPROGRAMUNIFORM4I64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4i64NV")) == NULL) || r; + r = ((glProgramUniform4i64vNV = (PFNGLPROGRAMUNIFORM4I64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4i64vNV")) == NULL) || r; + r = ((glProgramUniform4ui64NV = (PFNGLPROGRAMUNIFORM4UI64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ui64NV")) == NULL) || r; + r = ((glProgramUniform4ui64vNV = (PFNGLPROGRAMUNIFORM4UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ui64vNV")) == NULL) || r; + r = ((glUniform1i64NV = (PFNGLUNIFORM1I64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform1i64NV")) == NULL) || r; + r = ((glUniform1i64vNV = (PFNGLUNIFORM1I64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform1i64vNV")) == NULL) || r; + r = ((glUniform1ui64NV = (PFNGLUNIFORM1UI64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform1ui64NV")) == NULL) || r; + r = ((glUniform1ui64vNV = (PFNGLUNIFORM1UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform1ui64vNV")) == NULL) || r; + r = ((glUniform2i64NV = (PFNGLUNIFORM2I64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform2i64NV")) == NULL) || r; + r = ((glUniform2i64vNV = (PFNGLUNIFORM2I64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform2i64vNV")) == NULL) || r; + r = ((glUniform2ui64NV = (PFNGLUNIFORM2UI64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform2ui64NV")) == NULL) || r; + r = ((glUniform2ui64vNV = (PFNGLUNIFORM2UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform2ui64vNV")) == NULL) || r; + r = ((glUniform3i64NV = (PFNGLUNIFORM3I64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform3i64NV")) == NULL) || r; + r = ((glUniform3i64vNV = (PFNGLUNIFORM3I64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform3i64vNV")) == NULL) || r; + r = ((glUniform3ui64NV = (PFNGLUNIFORM3UI64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform3ui64NV")) == NULL) || r; + r = ((glUniform3ui64vNV = (PFNGLUNIFORM3UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform3ui64vNV")) == NULL) || r; + r = ((glUniform4i64NV = (PFNGLUNIFORM4I64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform4i64NV")) == NULL) || r; + r = ((glUniform4i64vNV = (PFNGLUNIFORM4I64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform4i64vNV")) == NULL) || r; + r = ((glUniform4ui64NV = (PFNGLUNIFORM4UI64NVPROC)glewGetProcAddress((const GLubyte*)"glUniform4ui64NV")) == NULL) || r; + r = ((glUniform4ui64vNV = (PFNGLUNIFORM4UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniform4ui64vNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_gpu_shader5 */ + +#ifdef GL_NV_half_float + +static GLboolean _glewInit_GL_NV_half_float () +{ + GLboolean r = GL_FALSE; + + r = ((glColor3hNV = (PFNGLCOLOR3HNVPROC)glewGetProcAddress((const GLubyte*)"glColor3hNV")) == NULL) || r; + r = ((glColor3hvNV = (PFNGLCOLOR3HVNVPROC)glewGetProcAddress((const GLubyte*)"glColor3hvNV")) == NULL) || r; + r = ((glColor4hNV = (PFNGLCOLOR4HNVPROC)glewGetProcAddress((const GLubyte*)"glColor4hNV")) == NULL) || r; + r = ((glColor4hvNV = (PFNGLCOLOR4HVNVPROC)glewGetProcAddress((const GLubyte*)"glColor4hvNV")) == NULL) || r; + r = ((glFogCoordhNV = (PFNGLFOGCOORDHNVPROC)glewGetProcAddress((const GLubyte*)"glFogCoordhNV")) == NULL) || r; + r = ((glFogCoordhvNV = (PFNGLFOGCOORDHVNVPROC)glewGetProcAddress((const GLubyte*)"glFogCoordhvNV")) == NULL) || r; + r = ((glMultiTexCoord1hNV = (PFNGLMULTITEXCOORD1HNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1hNV")) == NULL) || r; + r = ((glMultiTexCoord1hvNV = (PFNGLMULTITEXCOORD1HVNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord1hvNV")) == NULL) || r; + r = ((glMultiTexCoord2hNV = (PFNGLMULTITEXCOORD2HNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2hNV")) == NULL) || r; + r = ((glMultiTexCoord2hvNV = (PFNGLMULTITEXCOORD2HVNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord2hvNV")) == NULL) || r; + r = ((glMultiTexCoord3hNV = (PFNGLMULTITEXCOORD3HNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3hNV")) == NULL) || r; + r = ((glMultiTexCoord3hvNV = (PFNGLMULTITEXCOORD3HVNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord3hvNV")) == NULL) || r; + r = ((glMultiTexCoord4hNV = (PFNGLMULTITEXCOORD4HNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4hNV")) == NULL) || r; + r = ((glMultiTexCoord4hvNV = (PFNGLMULTITEXCOORD4HVNVPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4hvNV")) == NULL) || r; + r = ((glNormal3hNV = (PFNGLNORMAL3HNVPROC)glewGetProcAddress((const GLubyte*)"glNormal3hNV")) == NULL) || r; + r = ((glNormal3hvNV = (PFNGLNORMAL3HVNVPROC)glewGetProcAddress((const GLubyte*)"glNormal3hvNV")) == NULL) || r; + r = ((glSecondaryColor3hNV = (PFNGLSECONDARYCOLOR3HNVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3hNV")) == NULL) || r; + r = ((glSecondaryColor3hvNV = (PFNGLSECONDARYCOLOR3HVNVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColor3hvNV")) == NULL) || r; + r = ((glTexCoord1hNV = (PFNGLTEXCOORD1HNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord1hNV")) == NULL) || r; + r = ((glTexCoord1hvNV = (PFNGLTEXCOORD1HVNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord1hvNV")) == NULL) || r; + r = ((glTexCoord2hNV = (PFNGLTEXCOORD2HNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2hNV")) == NULL) || r; + r = ((glTexCoord2hvNV = (PFNGLTEXCOORD2HVNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2hvNV")) == NULL) || r; + r = ((glTexCoord3hNV = (PFNGLTEXCOORD3HNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord3hNV")) == NULL) || r; + r = ((glTexCoord3hvNV = (PFNGLTEXCOORD3HVNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord3hvNV")) == NULL) || r; + r = ((glTexCoord4hNV = (PFNGLTEXCOORD4HNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord4hNV")) == NULL) || r; + r = ((glTexCoord4hvNV = (PFNGLTEXCOORD4HVNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoord4hvNV")) == NULL) || r; + r = ((glVertex2hNV = (PFNGLVERTEX2HNVPROC)glewGetProcAddress((const GLubyte*)"glVertex2hNV")) == NULL) || r; + r = ((glVertex2hvNV = (PFNGLVERTEX2HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertex2hvNV")) == NULL) || r; + r = ((glVertex3hNV = (PFNGLVERTEX3HNVPROC)glewGetProcAddress((const GLubyte*)"glVertex3hNV")) == NULL) || r; + r = ((glVertex3hvNV = (PFNGLVERTEX3HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertex3hvNV")) == NULL) || r; + r = ((glVertex4hNV = (PFNGLVERTEX4HNVPROC)glewGetProcAddress((const GLubyte*)"glVertex4hNV")) == NULL) || r; + r = ((glVertex4hvNV = (PFNGLVERTEX4HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertex4hvNV")) == NULL) || r; + r = ((glVertexAttrib1hNV = (PFNGLVERTEXATTRIB1HNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1hNV")) == NULL) || r; + r = ((glVertexAttrib1hvNV = (PFNGLVERTEXATTRIB1HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1hvNV")) == NULL) || r; + r = ((glVertexAttrib2hNV = (PFNGLVERTEXATTRIB2HNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2hNV")) == NULL) || r; + r = ((glVertexAttrib2hvNV = (PFNGLVERTEXATTRIB2HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2hvNV")) == NULL) || r; + r = ((glVertexAttrib3hNV = (PFNGLVERTEXATTRIB3HNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3hNV")) == NULL) || r; + r = ((glVertexAttrib3hvNV = (PFNGLVERTEXATTRIB3HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3hvNV")) == NULL) || r; + r = ((glVertexAttrib4hNV = (PFNGLVERTEXATTRIB4HNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4hNV")) == NULL) || r; + r = ((glVertexAttrib4hvNV = (PFNGLVERTEXATTRIB4HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4hvNV")) == NULL) || r; + r = ((glVertexAttribs1hvNV = (PFNGLVERTEXATTRIBS1HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs1hvNV")) == NULL) || r; + r = ((glVertexAttribs2hvNV = (PFNGLVERTEXATTRIBS2HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs2hvNV")) == NULL) || r; + r = ((glVertexAttribs3hvNV = (PFNGLVERTEXATTRIBS3HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs3hvNV")) == NULL) || r; + r = ((glVertexAttribs4hvNV = (PFNGLVERTEXATTRIBS4HVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs4hvNV")) == NULL) || r; + r = ((glVertexWeighthNV = (PFNGLVERTEXWEIGHTHNVPROC)glewGetProcAddress((const GLubyte*)"glVertexWeighthNV")) == NULL) || r; + r = ((glVertexWeighthvNV = (PFNGLVERTEXWEIGHTHVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexWeighthvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_half_float */ + +#ifdef GL_NV_instanced_arrays + +static GLboolean _glewInit_GL_NV_instanced_arrays () +{ + GLboolean r = GL_FALSE; + + r = ((glVertexAttribDivisorNV = (PFNGLVERTEXATTRIBDIVISORNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribDivisorNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_instanced_arrays */ + +#ifdef GL_NV_internalformat_sample_query + +static GLboolean _glewInit_GL_NV_internalformat_sample_query () +{ + GLboolean r = GL_FALSE; + + r = ((glGetInternalformatSampleivNV = (PFNGLGETINTERNALFORMATSAMPLEIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetInternalformatSampleivNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_internalformat_sample_query */ + +#ifdef GL_NV_non_square_matrices + +static GLboolean _glewInit_GL_NV_non_square_matrices () +{ + GLboolean r = GL_FALSE; + + r = ((glUniformMatrix2x3fvNV = (PFNGLUNIFORMMATRIX2X3FVNVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2x3fvNV")) == NULL) || r; + r = ((glUniformMatrix2x4fvNV = (PFNGLUNIFORMMATRIX2X4FVNVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix2x4fvNV")) == NULL) || r; + r = ((glUniformMatrix3x2fvNV = (PFNGLUNIFORMMATRIX3X2FVNVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3x2fvNV")) == NULL) || r; + r = ((glUniformMatrix3x4fvNV = (PFNGLUNIFORMMATRIX3X4FVNVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix3x4fvNV")) == NULL) || r; + r = ((glUniformMatrix4x2fvNV = (PFNGLUNIFORMMATRIX4X2FVNVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4x2fvNV")) == NULL) || r; + r = ((glUniformMatrix4x3fvNV = (PFNGLUNIFORMMATRIX4X3FVNVPROC)glewGetProcAddress((const GLubyte*)"glUniformMatrix4x3fvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_non_square_matrices */ + +#ifdef GL_NV_occlusion_query + +static GLboolean _glewInit_GL_NV_occlusion_query () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginOcclusionQueryNV = (PFNGLBEGINOCCLUSIONQUERYNVPROC)glewGetProcAddress((const GLubyte*)"glBeginOcclusionQueryNV")) == NULL) || r; + r = ((glDeleteOcclusionQueriesNV = (PFNGLDELETEOCCLUSIONQUERIESNVPROC)glewGetProcAddress((const GLubyte*)"glDeleteOcclusionQueriesNV")) == NULL) || r; + r = ((glEndOcclusionQueryNV = (PFNGLENDOCCLUSIONQUERYNVPROC)glewGetProcAddress((const GLubyte*)"glEndOcclusionQueryNV")) == NULL) || r; + r = ((glGenOcclusionQueriesNV = (PFNGLGENOCCLUSIONQUERIESNVPROC)glewGetProcAddress((const GLubyte*)"glGenOcclusionQueriesNV")) == NULL) || r; + r = ((glGetOcclusionQueryivNV = (PFNGLGETOCCLUSIONQUERYIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetOcclusionQueryivNV")) == NULL) || r; + r = ((glGetOcclusionQueryuivNV = (PFNGLGETOCCLUSIONQUERYUIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetOcclusionQueryuivNV")) == NULL) || r; + r = ((glIsOcclusionQueryNV = (PFNGLISOCCLUSIONQUERYNVPROC)glewGetProcAddress((const GLubyte*)"glIsOcclusionQueryNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_occlusion_query */ + +#ifdef GL_NV_parameter_buffer_object + +static GLboolean _glewInit_GL_NV_parameter_buffer_object () +{ + GLboolean r = GL_FALSE; + + r = ((glProgramBufferParametersIivNV = (PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramBufferParametersIivNV")) == NULL) || r; + r = ((glProgramBufferParametersIuivNV = (PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramBufferParametersIuivNV")) == NULL) || r; + r = ((glProgramBufferParametersfvNV = (PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramBufferParametersfvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_parameter_buffer_object */ + +#ifdef GL_NV_path_rendering + +static GLboolean _glewInit_GL_NV_path_rendering () +{ + GLboolean r = GL_FALSE; + + r = ((glCopyPathNV = (PFNGLCOPYPATHNVPROC)glewGetProcAddress((const GLubyte*)"glCopyPathNV")) == NULL) || r; + r = ((glCoverFillPathInstancedNV = (PFNGLCOVERFILLPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glCoverFillPathInstancedNV")) == NULL) || r; + r = ((glCoverFillPathNV = (PFNGLCOVERFILLPATHNVPROC)glewGetProcAddress((const GLubyte*)"glCoverFillPathNV")) == NULL) || r; + r = ((glCoverStrokePathInstancedNV = (PFNGLCOVERSTROKEPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glCoverStrokePathInstancedNV")) == NULL) || r; + r = ((glCoverStrokePathNV = (PFNGLCOVERSTROKEPATHNVPROC)glewGetProcAddress((const GLubyte*)"glCoverStrokePathNV")) == NULL) || r; + r = ((glDeletePathsNV = (PFNGLDELETEPATHSNVPROC)glewGetProcAddress((const GLubyte*)"glDeletePathsNV")) == NULL) || r; + r = ((glGenPathsNV = (PFNGLGENPATHSNVPROC)glewGetProcAddress((const GLubyte*)"glGenPathsNV")) == NULL) || r; + r = ((glGetPathColorGenfvNV = (PFNGLGETPATHCOLORGENFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathColorGenfvNV")) == NULL) || r; + r = ((glGetPathColorGenivNV = (PFNGLGETPATHCOLORGENIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathColorGenivNV")) == NULL) || r; + r = ((glGetPathCommandsNV = (PFNGLGETPATHCOMMANDSNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathCommandsNV")) == NULL) || r; + r = ((glGetPathCoordsNV = (PFNGLGETPATHCOORDSNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathCoordsNV")) == NULL) || r; + r = ((glGetPathDashArrayNV = (PFNGLGETPATHDASHARRAYNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathDashArrayNV")) == NULL) || r; + r = ((glGetPathLengthNV = (PFNGLGETPATHLENGTHNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathLengthNV")) == NULL) || r; + r = ((glGetPathMetricRangeNV = (PFNGLGETPATHMETRICRANGENVPROC)glewGetProcAddress((const GLubyte*)"glGetPathMetricRangeNV")) == NULL) || r; + r = ((glGetPathMetricsNV = (PFNGLGETPATHMETRICSNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathMetricsNV")) == NULL) || r; + r = ((glGetPathParameterfvNV = (PFNGLGETPATHPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathParameterfvNV")) == NULL) || r; + r = ((glGetPathParameterivNV = (PFNGLGETPATHPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathParameterivNV")) == NULL) || r; + r = ((glGetPathSpacingNV = (PFNGLGETPATHSPACINGNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathSpacingNV")) == NULL) || r; + r = ((glGetPathTexGenfvNV = (PFNGLGETPATHTEXGENFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathTexGenfvNV")) == NULL) || r; + r = ((glGetPathTexGenivNV = (PFNGLGETPATHTEXGENIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathTexGenivNV")) == NULL) || r; + r = ((glGetProgramResourcefvNV = (PFNGLGETPROGRAMRESOURCEFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourcefvNV")) == NULL) || r; + r = ((glInterpolatePathsNV = (PFNGLINTERPOLATEPATHSNVPROC)glewGetProcAddress((const GLubyte*)"glInterpolatePathsNV")) == NULL) || r; + r = ((glIsPathNV = (PFNGLISPATHNVPROC)glewGetProcAddress((const GLubyte*)"glIsPathNV")) == NULL) || r; + r = ((glIsPointInFillPathNV = (PFNGLISPOINTINFILLPATHNVPROC)glewGetProcAddress((const GLubyte*)"glIsPointInFillPathNV")) == NULL) || r; + r = ((glIsPointInStrokePathNV = (PFNGLISPOINTINSTROKEPATHNVPROC)glewGetProcAddress((const GLubyte*)"glIsPointInStrokePathNV")) == NULL) || r; + r = ((glMatrixLoad3x2fNV = (PFNGLMATRIXLOAD3X2FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoad3x2fNV")) == NULL) || r; + r = ((glMatrixLoad3x3fNV = (PFNGLMATRIXLOAD3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoad3x3fNV")) == NULL) || r; + r = ((glMatrixLoadTranspose3x3fNV = (PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoadTranspose3x3fNV")) == NULL) || r; + r = ((glMatrixMult3x2fNV = (PFNGLMATRIXMULT3X2FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixMult3x2fNV")) == NULL) || r; + r = ((glMatrixMult3x3fNV = (PFNGLMATRIXMULT3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixMult3x3fNV")) == NULL) || r; + r = ((glMatrixMultTranspose3x3fNV = (PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixMultTranspose3x3fNV")) == NULL) || r; + r = ((glPathColorGenNV = (PFNGLPATHCOLORGENNVPROC)glewGetProcAddress((const GLubyte*)"glPathColorGenNV")) == NULL) || r; + r = ((glPathCommandsNV = (PFNGLPATHCOMMANDSNVPROC)glewGetProcAddress((const GLubyte*)"glPathCommandsNV")) == NULL) || r; + r = ((glPathCoordsNV = (PFNGLPATHCOORDSNVPROC)glewGetProcAddress((const GLubyte*)"glPathCoordsNV")) == NULL) || r; + r = ((glPathCoverDepthFuncNV = (PFNGLPATHCOVERDEPTHFUNCNVPROC)glewGetProcAddress((const GLubyte*)"glPathCoverDepthFuncNV")) == NULL) || r; + r = ((glPathDashArrayNV = (PFNGLPATHDASHARRAYNVPROC)glewGetProcAddress((const GLubyte*)"glPathDashArrayNV")) == NULL) || r; + r = ((glPathFogGenNV = (PFNGLPATHFOGGENNVPROC)glewGetProcAddress((const GLubyte*)"glPathFogGenNV")) == NULL) || r; + r = ((glPathGlyphIndexArrayNV = (PFNGLPATHGLYPHINDEXARRAYNVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphIndexArrayNV")) == NULL) || r; + r = ((glPathGlyphIndexRangeNV = (PFNGLPATHGLYPHINDEXRANGENVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphIndexRangeNV")) == NULL) || r; + r = ((glPathGlyphRangeNV = (PFNGLPATHGLYPHRANGENVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphRangeNV")) == NULL) || r; + r = ((glPathGlyphsNV = (PFNGLPATHGLYPHSNVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphsNV")) == NULL) || r; + r = ((glPathMemoryGlyphIndexArrayNV = (PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC)glewGetProcAddress((const GLubyte*)"glPathMemoryGlyphIndexArrayNV")) == NULL) || r; + r = ((glPathParameterfNV = (PFNGLPATHPARAMETERFNVPROC)glewGetProcAddress((const GLubyte*)"glPathParameterfNV")) == NULL) || r; + r = ((glPathParameterfvNV = (PFNGLPATHPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glPathParameterfvNV")) == NULL) || r; + r = ((glPathParameteriNV = (PFNGLPATHPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glPathParameteriNV")) == NULL) || r; + r = ((glPathParameterivNV = (PFNGLPATHPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glPathParameterivNV")) == NULL) || r; + r = ((glPathStencilDepthOffsetNV = (PFNGLPATHSTENCILDEPTHOFFSETNVPROC)glewGetProcAddress((const GLubyte*)"glPathStencilDepthOffsetNV")) == NULL) || r; + r = ((glPathStencilFuncNV = (PFNGLPATHSTENCILFUNCNVPROC)glewGetProcAddress((const GLubyte*)"glPathStencilFuncNV")) == NULL) || r; + r = ((glPathStringNV = (PFNGLPATHSTRINGNVPROC)glewGetProcAddress((const GLubyte*)"glPathStringNV")) == NULL) || r; + r = ((glPathSubCommandsNV = (PFNGLPATHSUBCOMMANDSNVPROC)glewGetProcAddress((const GLubyte*)"glPathSubCommandsNV")) == NULL) || r; + r = ((glPathSubCoordsNV = (PFNGLPATHSUBCOORDSNVPROC)glewGetProcAddress((const GLubyte*)"glPathSubCoordsNV")) == NULL) || r; + r = ((glPathTexGenNV = (PFNGLPATHTEXGENNVPROC)glewGetProcAddress((const GLubyte*)"glPathTexGenNV")) == NULL) || r; + r = ((glPointAlongPathNV = (PFNGLPOINTALONGPATHNVPROC)glewGetProcAddress((const GLubyte*)"glPointAlongPathNV")) == NULL) || r; + r = ((glProgramPathFragmentInputGenNV = (PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC)glewGetProcAddress((const GLubyte*)"glProgramPathFragmentInputGenNV")) == NULL) || r; + r = ((glStencilFillPathInstancedNV = (PFNGLSTENCILFILLPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilFillPathInstancedNV")) == NULL) || r; + r = ((glStencilFillPathNV = (PFNGLSTENCILFILLPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilFillPathNV")) == NULL) || r; + r = ((glStencilStrokePathInstancedNV = (PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilStrokePathInstancedNV")) == NULL) || r; + r = ((glStencilStrokePathNV = (PFNGLSTENCILSTROKEPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilStrokePathNV")) == NULL) || r; + r = ((glStencilThenCoverFillPathInstancedNV = (PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverFillPathInstancedNV")) == NULL) || r; + r = ((glStencilThenCoverFillPathNV = (PFNGLSTENCILTHENCOVERFILLPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverFillPathNV")) == NULL) || r; + r = ((glStencilThenCoverStrokePathInstancedNV = (PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverStrokePathInstancedNV")) == NULL) || r; + r = ((glStencilThenCoverStrokePathNV = (PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverStrokePathNV")) == NULL) || r; + r = ((glTransformPathNV = (PFNGLTRANSFORMPATHNVPROC)glewGetProcAddress((const GLubyte*)"glTransformPathNV")) == NULL) || r; + r = ((glWeightPathsNV = (PFNGLWEIGHTPATHSNVPROC)glewGetProcAddress((const GLubyte*)"glWeightPathsNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_path_rendering */ + +#ifdef GL_NV_pixel_data_range + +static GLboolean _glewInit_GL_NV_pixel_data_range () +{ + GLboolean r = GL_FALSE; + + r = ((glFlushPixelDataRangeNV = (PFNGLFLUSHPIXELDATARANGENVPROC)glewGetProcAddress((const GLubyte*)"glFlushPixelDataRangeNV")) == NULL) || r; + r = ((glPixelDataRangeNV = (PFNGLPIXELDATARANGENVPROC)glewGetProcAddress((const GLubyte*)"glPixelDataRangeNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_pixel_data_range */ + +#ifdef GL_NV_point_sprite + +static GLboolean _glewInit_GL_NV_point_sprite () +{ + GLboolean r = GL_FALSE; + + r = ((glPointParameteriNV = (PFNGLPOINTPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glPointParameteriNV")) == NULL) || r; + r = ((glPointParameterivNV = (PFNGLPOINTPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glPointParameterivNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_point_sprite */ + +#ifdef GL_NV_polygon_mode + +static GLboolean _glewInit_GL_NV_polygon_mode () +{ + GLboolean r = GL_FALSE; + + r = ((glPolygonModeNV = (PFNGLPOLYGONMODENVPROC)glewGetProcAddress((const GLubyte*)"glPolygonModeNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_polygon_mode */ + +#ifdef GL_NV_present_video + +static GLboolean _glewInit_GL_NV_present_video () +{ + GLboolean r = GL_FALSE; + + r = ((glGetVideoi64vNV = (PFNGLGETVIDEOI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideoi64vNV")) == NULL) || r; + r = ((glGetVideoivNV = (PFNGLGETVIDEOIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideoivNV")) == NULL) || r; + r = ((glGetVideoui64vNV = (PFNGLGETVIDEOUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideoui64vNV")) == NULL) || r; + r = ((glGetVideouivNV = (PFNGLGETVIDEOUIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideouivNV")) == NULL) || r; + r = ((glPresentFrameDualFillNV = (PFNGLPRESENTFRAMEDUALFILLNVPROC)glewGetProcAddress((const GLubyte*)"glPresentFrameDualFillNV")) == NULL) || r; + r = ((glPresentFrameKeyedNV = (PFNGLPRESENTFRAMEKEYEDNVPROC)glewGetProcAddress((const GLubyte*)"glPresentFrameKeyedNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_present_video */ + +#ifdef GL_NV_primitive_restart + +static GLboolean _glewInit_GL_NV_primitive_restart () +{ + GLboolean r = GL_FALSE; + + r = ((glPrimitiveRestartIndexNV = (PFNGLPRIMITIVERESTARTINDEXNVPROC)glewGetProcAddress((const GLubyte*)"glPrimitiveRestartIndexNV")) == NULL) || r; + r = ((glPrimitiveRestartNV = (PFNGLPRIMITIVERESTARTNVPROC)glewGetProcAddress((const GLubyte*)"glPrimitiveRestartNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_primitive_restart */ + +#ifdef GL_NV_register_combiners + +static GLboolean _glewInit_GL_NV_register_combiners () +{ + GLboolean r = GL_FALSE; + + r = ((glCombinerInputNV = (PFNGLCOMBINERINPUTNVPROC)glewGetProcAddress((const GLubyte*)"glCombinerInputNV")) == NULL) || r; + r = ((glCombinerOutputNV = (PFNGLCOMBINEROUTPUTNVPROC)glewGetProcAddress((const GLubyte*)"glCombinerOutputNV")) == NULL) || r; + r = ((glCombinerParameterfNV = (PFNGLCOMBINERPARAMETERFNVPROC)glewGetProcAddress((const GLubyte*)"glCombinerParameterfNV")) == NULL) || r; + r = ((glCombinerParameterfvNV = (PFNGLCOMBINERPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glCombinerParameterfvNV")) == NULL) || r; + r = ((glCombinerParameteriNV = (PFNGLCOMBINERPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glCombinerParameteriNV")) == NULL) || r; + r = ((glCombinerParameterivNV = (PFNGLCOMBINERPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glCombinerParameterivNV")) == NULL) || r; + r = ((glFinalCombinerInputNV = (PFNGLFINALCOMBINERINPUTNVPROC)glewGetProcAddress((const GLubyte*)"glFinalCombinerInputNV")) == NULL) || r; + r = ((glGetCombinerInputParameterfvNV = (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetCombinerInputParameterfvNV")) == NULL) || r; + r = ((glGetCombinerInputParameterivNV = (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetCombinerInputParameterivNV")) == NULL) || r; + r = ((glGetCombinerOutputParameterfvNV = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetCombinerOutputParameterfvNV")) == NULL) || r; + r = ((glGetCombinerOutputParameterivNV = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetCombinerOutputParameterivNV")) == NULL) || r; + r = ((glGetFinalCombinerInputParameterfvNV = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetFinalCombinerInputParameterfvNV")) == NULL) || r; + r = ((glGetFinalCombinerInputParameterivNV = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetFinalCombinerInputParameterivNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_register_combiners */ + +#ifdef GL_NV_register_combiners2 + +static GLboolean _glewInit_GL_NV_register_combiners2 () +{ + GLboolean r = GL_FALSE; + + r = ((glCombinerStageParameterfvNV = (PFNGLCOMBINERSTAGEPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glCombinerStageParameterfvNV")) == NULL) || r; + r = ((glGetCombinerStageParameterfvNV = (PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetCombinerStageParameterfvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_register_combiners2 */ + +#ifdef GL_NV_sample_locations + +static GLboolean _glewInit_GL_NV_sample_locations () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferSampleLocationsfvNV = (PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)glewGetProcAddress((const GLubyte*)"glFramebufferSampleLocationsfvNV")) == NULL) || r; + r = ((glNamedFramebufferSampleLocationsfvNV = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferSampleLocationsfvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_sample_locations */ + +#ifdef GL_NV_shader_buffer_load + +static GLboolean _glewInit_GL_NV_shader_buffer_load () +{ + GLboolean r = GL_FALSE; + + r = ((glGetBufferParameterui64vNV = (PFNGLGETBUFFERPARAMETERUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetBufferParameterui64vNV")) == NULL) || r; + r = ((glGetIntegerui64vNV = (PFNGLGETINTEGERUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetIntegerui64vNV")) == NULL) || r; + r = ((glGetNamedBufferParameterui64vNV = (PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferParameterui64vNV")) == NULL) || r; + r = ((glIsBufferResidentNV = (PFNGLISBUFFERRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glIsBufferResidentNV")) == NULL) || r; + r = ((glIsNamedBufferResidentNV = (PFNGLISNAMEDBUFFERRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glIsNamedBufferResidentNV")) == NULL) || r; + r = ((glMakeBufferNonResidentNV = (PFNGLMAKEBUFFERNONRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeBufferNonResidentNV")) == NULL) || r; + r = ((glMakeBufferResidentNV = (PFNGLMAKEBUFFERRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeBufferResidentNV")) == NULL) || r; + r = ((glMakeNamedBufferNonResidentNV = (PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeNamedBufferNonResidentNV")) == NULL) || r; + r = ((glMakeNamedBufferResidentNV = (PFNGLMAKENAMEDBUFFERRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glMakeNamedBufferResidentNV")) == NULL) || r; + r = ((glProgramUniformui64NV = (PFNGLPROGRAMUNIFORMUI64NVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformui64NV")) == NULL) || r; + r = ((glProgramUniformui64vNV = (PFNGLPROGRAMUNIFORMUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformui64vNV")) == NULL) || r; + r = ((glUniformui64NV = (PFNGLUNIFORMUI64NVPROC)glewGetProcAddress((const GLubyte*)"glUniformui64NV")) == NULL) || r; + r = ((glUniformui64vNV = (PFNGLUNIFORMUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glUniformui64vNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_shader_buffer_load */ + +#ifdef GL_NV_texture_array + +static GLboolean _glewInit_GL_NV_texture_array () +{ + GLboolean r = GL_FALSE; + + r = ((glCompressedTexImage3DNV = (PFNGLCOMPRESSEDTEXIMAGE3DNVPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexImage3DNV")) == NULL) || r; + r = ((glCompressedTexSubImage3DNV = (PFNGLCOMPRESSEDTEXSUBIMAGE3DNVPROC)glewGetProcAddress((const GLubyte*)"glCompressedTexSubImage3DNV")) == NULL) || r; + r = ((glCopyTexSubImage3DNV = (PFNGLCOPYTEXSUBIMAGE3DNVPROC)glewGetProcAddress((const GLubyte*)"glCopyTexSubImage3DNV")) == NULL) || r; + r = ((glFramebufferTextureLayerNV = (PFNGLFRAMEBUFFERTEXTURELAYERNVPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureLayerNV")) == NULL) || r; + r = ((glTexImage3DNV = (PFNGLTEXIMAGE3DNVPROC)glewGetProcAddress((const GLubyte*)"glTexImage3DNV")) == NULL) || r; + r = ((glTexSubImage3DNV = (PFNGLTEXSUBIMAGE3DNVPROC)glewGetProcAddress((const GLubyte*)"glTexSubImage3DNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_texture_array */ + +#ifdef GL_NV_texture_barrier + +static GLboolean _glewInit_GL_NV_texture_barrier () +{ + GLboolean r = GL_FALSE; + + r = ((glTextureBarrierNV = (PFNGLTEXTUREBARRIERNVPROC)glewGetProcAddress((const GLubyte*)"glTextureBarrierNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_texture_barrier */ + +#ifdef GL_NV_texture_multisample + +static GLboolean _glewInit_GL_NV_texture_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glTexImage2DMultisampleCoverageNV = (PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC)glewGetProcAddress((const GLubyte*)"glTexImage2DMultisampleCoverageNV")) == NULL) || r; + r = ((glTexImage3DMultisampleCoverageNV = (PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC)glewGetProcAddress((const GLubyte*)"glTexImage3DMultisampleCoverageNV")) == NULL) || r; + r = ((glTextureImage2DMultisampleCoverageNV = (PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC)glewGetProcAddress((const GLubyte*)"glTextureImage2DMultisampleCoverageNV")) == NULL) || r; + r = ((glTextureImage2DMultisampleNV = (PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC)glewGetProcAddress((const GLubyte*)"glTextureImage2DMultisampleNV")) == NULL) || r; + r = ((glTextureImage3DMultisampleCoverageNV = (PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC)glewGetProcAddress((const GLubyte*)"glTextureImage3DMultisampleCoverageNV")) == NULL) || r; + r = ((glTextureImage3DMultisampleNV = (PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC)glewGetProcAddress((const GLubyte*)"glTextureImage3DMultisampleNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_texture_multisample */ + +#ifdef GL_NV_transform_feedback + +static GLboolean _glewInit_GL_NV_transform_feedback () +{ + GLboolean r = GL_FALSE; + + r = ((glActiveVaryingNV = (PFNGLACTIVEVARYINGNVPROC)glewGetProcAddress((const GLubyte*)"glActiveVaryingNV")) == NULL) || r; + r = ((glBeginTransformFeedbackNV = (PFNGLBEGINTRANSFORMFEEDBACKNVPROC)glewGetProcAddress((const GLubyte*)"glBeginTransformFeedbackNV")) == NULL) || r; + r = ((glBindBufferBaseNV = (PFNGLBINDBUFFERBASENVPROC)glewGetProcAddress((const GLubyte*)"glBindBufferBaseNV")) == NULL) || r; + r = ((glBindBufferOffsetNV = (PFNGLBINDBUFFEROFFSETNVPROC)glewGetProcAddress((const GLubyte*)"glBindBufferOffsetNV")) == NULL) || r; + r = ((glBindBufferRangeNV = (PFNGLBINDBUFFERRANGENVPROC)glewGetProcAddress((const GLubyte*)"glBindBufferRangeNV")) == NULL) || r; + r = ((glEndTransformFeedbackNV = (PFNGLENDTRANSFORMFEEDBACKNVPROC)glewGetProcAddress((const GLubyte*)"glEndTransformFeedbackNV")) == NULL) || r; + r = ((glGetActiveVaryingNV = (PFNGLGETACTIVEVARYINGNVPROC)glewGetProcAddress((const GLubyte*)"glGetActiveVaryingNV")) == NULL) || r; + r = ((glGetTransformFeedbackVaryingNV = (PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbackVaryingNV")) == NULL) || r; + r = ((glGetVaryingLocationNV = (PFNGLGETVARYINGLOCATIONNVPROC)glewGetProcAddress((const GLubyte*)"glGetVaryingLocationNV")) == NULL) || r; + r = ((glTransformFeedbackAttribsNV = (PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackAttribsNV")) == NULL) || r; + r = ((glTransformFeedbackVaryingsNV = (PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackVaryingsNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_transform_feedback */ + +#ifdef GL_NV_transform_feedback2 + +static GLboolean _glewInit_GL_NV_transform_feedback2 () +{ + GLboolean r = GL_FALSE; + + r = ((glBindTransformFeedbackNV = (PFNGLBINDTRANSFORMFEEDBACKNVPROC)glewGetProcAddress((const GLubyte*)"glBindTransformFeedbackNV")) == NULL) || r; + r = ((glDeleteTransformFeedbacksNV = (PFNGLDELETETRANSFORMFEEDBACKSNVPROC)glewGetProcAddress((const GLubyte*)"glDeleteTransformFeedbacksNV")) == NULL) || r; + r = ((glDrawTransformFeedbackNV = (PFNGLDRAWTRANSFORMFEEDBACKNVPROC)glewGetProcAddress((const GLubyte*)"glDrawTransformFeedbackNV")) == NULL) || r; + r = ((glGenTransformFeedbacksNV = (PFNGLGENTRANSFORMFEEDBACKSNVPROC)glewGetProcAddress((const GLubyte*)"glGenTransformFeedbacksNV")) == NULL) || r; + r = ((glIsTransformFeedbackNV = (PFNGLISTRANSFORMFEEDBACKNVPROC)glewGetProcAddress((const GLubyte*)"glIsTransformFeedbackNV")) == NULL) || r; + r = ((glPauseTransformFeedbackNV = (PFNGLPAUSETRANSFORMFEEDBACKNVPROC)glewGetProcAddress((const GLubyte*)"glPauseTransformFeedbackNV")) == NULL) || r; + r = ((glResumeTransformFeedbackNV = (PFNGLRESUMETRANSFORMFEEDBACKNVPROC)glewGetProcAddress((const GLubyte*)"glResumeTransformFeedbackNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_transform_feedback2 */ + +#ifdef GL_NV_vdpau_interop + +static GLboolean _glewInit_GL_NV_vdpau_interop () +{ + GLboolean r = GL_FALSE; + + r = ((glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUFiniNV")) == NULL) || r; + r = ((glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUGetSurfaceivNV")) == NULL) || r; + r = ((glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUInitNV")) == NULL) || r; + r = ((glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUIsSurfaceNV")) == NULL) || r; + r = ((glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUMapSurfacesNV")) == NULL) || r; + r = ((glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glewGetProcAddress((const GLubyte*)"glVDPAURegisterOutputSurfaceNV")) == NULL) || r; + r = ((glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glewGetProcAddress((const GLubyte*)"glVDPAURegisterVideoSurfaceNV")) == NULL) || r; + r = ((glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUSurfaceAccessNV")) == NULL) || r; + r = ((glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUUnmapSurfacesNV")) == NULL) || r; + r = ((glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glewGetProcAddress((const GLubyte*)"glVDPAUUnregisterSurfaceNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_vdpau_interop */ + +#ifdef GL_NV_vertex_array_range + +static GLboolean _glewInit_GL_NV_vertex_array_range () +{ + GLboolean r = GL_FALSE; + + r = ((glFlushVertexArrayRangeNV = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)glewGetProcAddress((const GLubyte*)"glFlushVertexArrayRangeNV")) == NULL) || r; + r = ((glVertexArrayRangeNV = (PFNGLVERTEXARRAYRANGENVPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayRangeNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_vertex_array_range */ + +#ifdef GL_NV_vertex_attrib_integer_64bit + +static GLboolean _glewInit_GL_NV_vertex_attrib_integer_64bit () +{ + GLboolean r = GL_FALSE; + + r = ((glGetVertexAttribLi64vNV = (PFNGLGETVERTEXATTRIBLI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribLi64vNV")) == NULL) || r; + r = ((glGetVertexAttribLui64vNV = (PFNGLGETVERTEXATTRIBLUI64VNVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribLui64vNV")) == NULL) || r; + r = ((glVertexAttribL1i64NV = (PFNGLVERTEXATTRIBL1I64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1i64NV")) == NULL) || r; + r = ((glVertexAttribL1i64vNV = (PFNGLVERTEXATTRIBL1I64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1i64vNV")) == NULL) || r; + r = ((glVertexAttribL1ui64NV = (PFNGLVERTEXATTRIBL1UI64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1ui64NV")) == NULL) || r; + r = ((glVertexAttribL1ui64vNV = (PFNGLVERTEXATTRIBL1UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1ui64vNV")) == NULL) || r; + r = ((glVertexAttribL2i64NV = (PFNGLVERTEXATTRIBL2I64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2i64NV")) == NULL) || r; + r = ((glVertexAttribL2i64vNV = (PFNGLVERTEXATTRIBL2I64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2i64vNV")) == NULL) || r; + r = ((glVertexAttribL2ui64NV = (PFNGLVERTEXATTRIBL2UI64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2ui64NV")) == NULL) || r; + r = ((glVertexAttribL2ui64vNV = (PFNGLVERTEXATTRIBL2UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL2ui64vNV")) == NULL) || r; + r = ((glVertexAttribL3i64NV = (PFNGLVERTEXATTRIBL3I64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3i64NV")) == NULL) || r; + r = ((glVertexAttribL3i64vNV = (PFNGLVERTEXATTRIBL3I64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3i64vNV")) == NULL) || r; + r = ((glVertexAttribL3ui64NV = (PFNGLVERTEXATTRIBL3UI64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3ui64NV")) == NULL) || r; + r = ((glVertexAttribL3ui64vNV = (PFNGLVERTEXATTRIBL3UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL3ui64vNV")) == NULL) || r; + r = ((glVertexAttribL4i64NV = (PFNGLVERTEXATTRIBL4I64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4i64NV")) == NULL) || r; + r = ((glVertexAttribL4i64vNV = (PFNGLVERTEXATTRIBL4I64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4i64vNV")) == NULL) || r; + r = ((glVertexAttribL4ui64NV = (PFNGLVERTEXATTRIBL4UI64NVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4ui64NV")) == NULL) || r; + r = ((glVertexAttribL4ui64vNV = (PFNGLVERTEXATTRIBL4UI64VNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL4ui64vNV")) == NULL) || r; + r = ((glVertexAttribLFormatNV = (PFNGLVERTEXATTRIBLFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribLFormatNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_vertex_attrib_integer_64bit */ + +#ifdef GL_NV_vertex_buffer_unified_memory + +static GLboolean _glewInit_GL_NV_vertex_buffer_unified_memory () +{ + GLboolean r = GL_FALSE; + + r = ((glBufferAddressRangeNV = (PFNGLBUFFERADDRESSRANGENVPROC)glewGetProcAddress((const GLubyte*)"glBufferAddressRangeNV")) == NULL) || r; + r = ((glColorFormatNV = (PFNGLCOLORFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glColorFormatNV")) == NULL) || r; + r = ((glEdgeFlagFormatNV = (PFNGLEDGEFLAGFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glEdgeFlagFormatNV")) == NULL) || r; + r = ((glFogCoordFormatNV = (PFNGLFOGCOORDFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glFogCoordFormatNV")) == NULL) || r; + r = ((glGetIntegerui64i_vNV = (PFNGLGETINTEGERUI64I_VNVPROC)glewGetProcAddress((const GLubyte*)"glGetIntegerui64i_vNV")) == NULL) || r; + r = ((glIndexFormatNV = (PFNGLINDEXFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glIndexFormatNV")) == NULL) || r; + r = ((glNormalFormatNV = (PFNGLNORMALFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glNormalFormatNV")) == NULL) || r; + r = ((glSecondaryColorFormatNV = (PFNGLSECONDARYCOLORFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glSecondaryColorFormatNV")) == NULL) || r; + r = ((glTexCoordFormatNV = (PFNGLTEXCOORDFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glTexCoordFormatNV")) == NULL) || r; + r = ((glVertexAttribFormatNV = (PFNGLVERTEXATTRIBFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribFormatNV")) == NULL) || r; + r = ((glVertexAttribIFormatNV = (PFNGLVERTEXATTRIBIFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribIFormatNV")) == NULL) || r; + r = ((glVertexFormatNV = (PFNGLVERTEXFORMATNVPROC)glewGetProcAddress((const GLubyte*)"glVertexFormatNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_vertex_buffer_unified_memory */ + +#ifdef GL_NV_vertex_program + +static GLboolean _glewInit_GL_NV_vertex_program () +{ + GLboolean r = GL_FALSE; + + r = ((glAreProgramsResidentNV = (PFNGLAREPROGRAMSRESIDENTNVPROC)glewGetProcAddress((const GLubyte*)"glAreProgramsResidentNV")) == NULL) || r; + r = ((glBindProgramNV = (PFNGLBINDPROGRAMNVPROC)glewGetProcAddress((const GLubyte*)"glBindProgramNV")) == NULL) || r; + r = ((glDeleteProgramsNV = (PFNGLDELETEPROGRAMSNVPROC)glewGetProcAddress((const GLubyte*)"glDeleteProgramsNV")) == NULL) || r; + r = ((glExecuteProgramNV = (PFNGLEXECUTEPROGRAMNVPROC)glewGetProcAddress((const GLubyte*)"glExecuteProgramNV")) == NULL) || r; + r = ((glGenProgramsNV = (PFNGLGENPROGRAMSNVPROC)glewGetProcAddress((const GLubyte*)"glGenProgramsNV")) == NULL) || r; + r = ((glGetProgramParameterdvNV = (PFNGLGETPROGRAMPARAMETERDVNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramParameterdvNV")) == NULL) || r; + r = ((glGetProgramParameterfvNV = (PFNGLGETPROGRAMPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramParameterfvNV")) == NULL) || r; + r = ((glGetProgramStringNV = (PFNGLGETPROGRAMSTRINGNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramStringNV")) == NULL) || r; + r = ((glGetProgramivNV = (PFNGLGETPROGRAMIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramivNV")) == NULL) || r; + r = ((glGetTrackMatrixivNV = (PFNGLGETTRACKMATRIXIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetTrackMatrixivNV")) == NULL) || r; + r = ((glGetVertexAttribPointervNV = (PFNGLGETVERTEXATTRIBPOINTERVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribPointervNV")) == NULL) || r; + r = ((glGetVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribdvNV")) == NULL) || r; + r = ((glGetVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribfvNV")) == NULL) || r; + r = ((glGetVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribivNV")) == NULL) || r; + r = ((glIsProgramNV = (PFNGLISPROGRAMNVPROC)glewGetProcAddress((const GLubyte*)"glIsProgramNV")) == NULL) || r; + r = ((glLoadProgramNV = (PFNGLLOADPROGRAMNVPROC)glewGetProcAddress((const GLubyte*)"glLoadProgramNV")) == NULL) || r; + r = ((glProgramParameter4dNV = (PFNGLPROGRAMPARAMETER4DNVPROC)glewGetProcAddress((const GLubyte*)"glProgramParameter4dNV")) == NULL) || r; + r = ((glProgramParameter4dvNV = (PFNGLPROGRAMPARAMETER4DVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramParameter4dvNV")) == NULL) || r; + r = ((glProgramParameter4fNV = (PFNGLPROGRAMPARAMETER4FNVPROC)glewGetProcAddress((const GLubyte*)"glProgramParameter4fNV")) == NULL) || r; + r = ((glProgramParameter4fvNV = (PFNGLPROGRAMPARAMETER4FVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramParameter4fvNV")) == NULL) || r; + r = ((glProgramParameters4dvNV = (PFNGLPROGRAMPARAMETERS4DVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramParameters4dvNV")) == NULL) || r; + r = ((glProgramParameters4fvNV = (PFNGLPROGRAMPARAMETERS4FVNVPROC)glewGetProcAddress((const GLubyte*)"glProgramParameters4fvNV")) == NULL) || r; + r = ((glRequestResidentProgramsNV = (PFNGLREQUESTRESIDENTPROGRAMSNVPROC)glewGetProcAddress((const GLubyte*)"glRequestResidentProgramsNV")) == NULL) || r; + r = ((glTrackMatrixNV = (PFNGLTRACKMATRIXNVPROC)glewGetProcAddress((const GLubyte*)"glTrackMatrixNV")) == NULL) || r; + r = ((glVertexAttrib1dNV = (PFNGLVERTEXATTRIB1DNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1dNV")) == NULL) || r; + r = ((glVertexAttrib1dvNV = (PFNGLVERTEXATTRIB1DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1dvNV")) == NULL) || r; + r = ((glVertexAttrib1fNV = (PFNGLVERTEXATTRIB1FNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1fNV")) == NULL) || r; + r = ((glVertexAttrib1fvNV = (PFNGLVERTEXATTRIB1FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1fvNV")) == NULL) || r; + r = ((glVertexAttrib1sNV = (PFNGLVERTEXATTRIB1SNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1sNV")) == NULL) || r; + r = ((glVertexAttrib1svNV = (PFNGLVERTEXATTRIB1SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib1svNV")) == NULL) || r; + r = ((glVertexAttrib2dNV = (PFNGLVERTEXATTRIB2DNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2dNV")) == NULL) || r; + r = ((glVertexAttrib2dvNV = (PFNGLVERTEXATTRIB2DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2dvNV")) == NULL) || r; + r = ((glVertexAttrib2fNV = (PFNGLVERTEXATTRIB2FNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2fNV")) == NULL) || r; + r = ((glVertexAttrib2fvNV = (PFNGLVERTEXATTRIB2FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2fvNV")) == NULL) || r; + r = ((glVertexAttrib2sNV = (PFNGLVERTEXATTRIB2SNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2sNV")) == NULL) || r; + r = ((glVertexAttrib2svNV = (PFNGLVERTEXATTRIB2SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib2svNV")) == NULL) || r; + r = ((glVertexAttrib3dNV = (PFNGLVERTEXATTRIB3DNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3dNV")) == NULL) || r; + r = ((glVertexAttrib3dvNV = (PFNGLVERTEXATTRIB3DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3dvNV")) == NULL) || r; + r = ((glVertexAttrib3fNV = (PFNGLVERTEXATTRIB3FNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3fNV")) == NULL) || r; + r = ((glVertexAttrib3fvNV = (PFNGLVERTEXATTRIB3FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3fvNV")) == NULL) || r; + r = ((glVertexAttrib3sNV = (PFNGLVERTEXATTRIB3SNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3sNV")) == NULL) || r; + r = ((glVertexAttrib3svNV = (PFNGLVERTEXATTRIB3SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib3svNV")) == NULL) || r; + r = ((glVertexAttrib4dNV = (PFNGLVERTEXATTRIB4DNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4dNV")) == NULL) || r; + r = ((glVertexAttrib4dvNV = (PFNGLVERTEXATTRIB4DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4dvNV")) == NULL) || r; + r = ((glVertexAttrib4fNV = (PFNGLVERTEXATTRIB4FNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4fNV")) == NULL) || r; + r = ((glVertexAttrib4fvNV = (PFNGLVERTEXATTRIB4FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4fvNV")) == NULL) || r; + r = ((glVertexAttrib4sNV = (PFNGLVERTEXATTRIB4SNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4sNV")) == NULL) || r; + r = ((glVertexAttrib4svNV = (PFNGLVERTEXATTRIB4SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4svNV")) == NULL) || r; + r = ((glVertexAttrib4ubNV = (PFNGLVERTEXATTRIB4UBNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4ubNV")) == NULL) || r; + r = ((glVertexAttrib4ubvNV = (PFNGLVERTEXATTRIB4UBVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttrib4ubvNV")) == NULL) || r; + r = ((glVertexAttribPointerNV = (PFNGLVERTEXATTRIBPOINTERNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribPointerNV")) == NULL) || r; + r = ((glVertexAttribs1dvNV = (PFNGLVERTEXATTRIBS1DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs1dvNV")) == NULL) || r; + r = ((glVertexAttribs1fvNV = (PFNGLVERTEXATTRIBS1FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs1fvNV")) == NULL) || r; + r = ((glVertexAttribs1svNV = (PFNGLVERTEXATTRIBS1SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs1svNV")) == NULL) || r; + r = ((glVertexAttribs2dvNV = (PFNGLVERTEXATTRIBS2DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs2dvNV")) == NULL) || r; + r = ((glVertexAttribs2fvNV = (PFNGLVERTEXATTRIBS2FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs2fvNV")) == NULL) || r; + r = ((glVertexAttribs2svNV = (PFNGLVERTEXATTRIBS2SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs2svNV")) == NULL) || r; + r = ((glVertexAttribs3dvNV = (PFNGLVERTEXATTRIBS3DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs3dvNV")) == NULL) || r; + r = ((glVertexAttribs3fvNV = (PFNGLVERTEXATTRIBS3FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs3fvNV")) == NULL) || r; + r = ((glVertexAttribs3svNV = (PFNGLVERTEXATTRIBS3SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs3svNV")) == NULL) || r; + r = ((glVertexAttribs4dvNV = (PFNGLVERTEXATTRIBS4DVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs4dvNV")) == NULL) || r; + r = ((glVertexAttribs4fvNV = (PFNGLVERTEXATTRIBS4FVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs4fvNV")) == NULL) || r; + r = ((glVertexAttribs4svNV = (PFNGLVERTEXATTRIBS4SVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs4svNV")) == NULL) || r; + r = ((glVertexAttribs4ubvNV = (PFNGLVERTEXATTRIBS4UBVNVPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribs4ubvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_vertex_program */ + +#ifdef GL_NV_video_capture + +static GLboolean _glewInit_GL_NV_video_capture () +{ + GLboolean r = GL_FALSE; + + r = ((glBeginVideoCaptureNV = (PFNGLBEGINVIDEOCAPTURENVPROC)glewGetProcAddress((const GLubyte*)"glBeginVideoCaptureNV")) == NULL) || r; + r = ((glBindVideoCaptureStreamBufferNV = (PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC)glewGetProcAddress((const GLubyte*)"glBindVideoCaptureStreamBufferNV")) == NULL) || r; + r = ((glBindVideoCaptureStreamTextureNV = (PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC)glewGetProcAddress((const GLubyte*)"glBindVideoCaptureStreamTextureNV")) == NULL) || r; + r = ((glEndVideoCaptureNV = (PFNGLENDVIDEOCAPTURENVPROC)glewGetProcAddress((const GLubyte*)"glEndVideoCaptureNV")) == NULL) || r; + r = ((glGetVideoCaptureStreamdvNV = (PFNGLGETVIDEOCAPTURESTREAMDVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideoCaptureStreamdvNV")) == NULL) || r; + r = ((glGetVideoCaptureStreamfvNV = (PFNGLGETVIDEOCAPTURESTREAMFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideoCaptureStreamfvNV")) == NULL) || r; + r = ((glGetVideoCaptureStreamivNV = (PFNGLGETVIDEOCAPTURESTREAMIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideoCaptureStreamivNV")) == NULL) || r; + r = ((glGetVideoCaptureivNV = (PFNGLGETVIDEOCAPTUREIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetVideoCaptureivNV")) == NULL) || r; + r = ((glVideoCaptureNV = (PFNGLVIDEOCAPTURENVPROC)glewGetProcAddress((const GLubyte*)"glVideoCaptureNV")) == NULL) || r; + r = ((glVideoCaptureStreamParameterdvNV = (PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC)glewGetProcAddress((const GLubyte*)"glVideoCaptureStreamParameterdvNV")) == NULL) || r; + r = ((glVideoCaptureStreamParameterfvNV = (PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glVideoCaptureStreamParameterfvNV")) == NULL) || r; + r = ((glVideoCaptureStreamParameterivNV = (PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC)glewGetProcAddress((const GLubyte*)"glVideoCaptureStreamParameterivNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_video_capture */ + +#ifdef GL_NV_viewport_array + +static GLboolean _glewInit_GL_NV_viewport_array () +{ + GLboolean r = GL_FALSE; + + r = ((glDepthRangeArrayfvNV = (PFNGLDEPTHRANGEARRAYFVNVPROC)glewGetProcAddress((const GLubyte*)"glDepthRangeArrayfvNV")) == NULL) || r; + r = ((glDepthRangeIndexedfNV = (PFNGLDEPTHRANGEINDEXEDFNVPROC)glewGetProcAddress((const GLubyte*)"glDepthRangeIndexedfNV")) == NULL) || r; + r = ((glDisableiNV = (PFNGLDISABLEINVPROC)glewGetProcAddress((const GLubyte*)"glDisableiNV")) == NULL) || r; + r = ((glEnableiNV = (PFNGLENABLEINVPROC)glewGetProcAddress((const GLubyte*)"glEnableiNV")) == NULL) || r; + r = ((glGetFloati_vNV = (PFNGLGETFLOATI_VNVPROC)glewGetProcAddress((const GLubyte*)"glGetFloati_vNV")) == NULL) || r; + r = ((glIsEnablediNV = (PFNGLISENABLEDINVPROC)glewGetProcAddress((const GLubyte*)"glIsEnablediNV")) == NULL) || r; + r = ((glScissorArrayvNV = (PFNGLSCISSORARRAYVNVPROC)glewGetProcAddress((const GLubyte*)"glScissorArrayvNV")) == NULL) || r; + r = ((glScissorIndexedNV = (PFNGLSCISSORINDEXEDNVPROC)glewGetProcAddress((const GLubyte*)"glScissorIndexedNV")) == NULL) || r; + r = ((glScissorIndexedvNV = (PFNGLSCISSORINDEXEDVNVPROC)glewGetProcAddress((const GLubyte*)"glScissorIndexedvNV")) == NULL) || r; + r = ((glViewportArrayvNV = (PFNGLVIEWPORTARRAYVNVPROC)glewGetProcAddress((const GLubyte*)"glViewportArrayvNV")) == NULL) || r; + r = ((glViewportIndexedfNV = (PFNGLVIEWPORTINDEXEDFNVPROC)glewGetProcAddress((const GLubyte*)"glViewportIndexedfNV")) == NULL) || r; + r = ((glViewportIndexedfvNV = (PFNGLVIEWPORTINDEXEDFVNVPROC)glewGetProcAddress((const GLubyte*)"glViewportIndexedfvNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_viewport_array */ + +#ifdef GL_NV_viewport_swizzle + +static GLboolean _glewInit_GL_NV_viewport_swizzle () +{ + GLboolean r = GL_FALSE; + + r = ((glViewportSwizzleNV = (PFNGLVIEWPORTSWIZZLENVPROC)glewGetProcAddress((const GLubyte*)"glViewportSwizzleNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_viewport_swizzle */ + +#ifdef GL_OVR_multiview + +static GLboolean _glewInit_GL_OVR_multiview () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureMultiviewOVR")) == NULL) || r; + + return r; +} + +#endif /* GL_OVR_multiview */ + +#ifdef GL_OVR_multiview_multisampled_render_to_texture + +static GLboolean _glewInit_GL_OVR_multiview_multisampled_render_to_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferTextureMultisampleMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureMultisampleMultiviewOVR")) == NULL) || r; + + return r; +} + +#endif /* GL_OVR_multiview_multisampled_render_to_texture */ + +#ifdef GL_QCOM_alpha_test + +static GLboolean _glewInit_GL_QCOM_alpha_test () +{ + GLboolean r = GL_FALSE; + + r = ((glAlphaFuncQCOM = (PFNGLALPHAFUNCQCOMPROC)glewGetProcAddress((const GLubyte*)"glAlphaFuncQCOM")) == NULL) || r; + + return r; +} + +#endif /* GL_QCOM_alpha_test */ + +#ifdef GL_QCOM_driver_control + +static GLboolean _glewInit_GL_QCOM_driver_control () +{ + GLboolean r = GL_FALSE; + + r = ((glDisableDriverControlQCOM = (PFNGLDISABLEDRIVERCONTROLQCOMPROC)glewGetProcAddress((const GLubyte*)"glDisableDriverControlQCOM")) == NULL) || r; + r = ((glEnableDriverControlQCOM = (PFNGLENABLEDRIVERCONTROLQCOMPROC)glewGetProcAddress((const GLubyte*)"glEnableDriverControlQCOM")) == NULL) || r; + r = ((glGetDriverControlStringQCOM = (PFNGLGETDRIVERCONTROLSTRINGQCOMPROC)glewGetProcAddress((const GLubyte*)"glGetDriverControlStringQCOM")) == NULL) || r; + r = ((glGetDriverControlsQCOM = (PFNGLGETDRIVERCONTROLSQCOMPROC)glewGetProcAddress((const GLubyte*)"glGetDriverControlsQCOM")) == NULL) || r; + + return r; +} + +#endif /* GL_QCOM_driver_control */ + +#ifdef GL_QCOM_extended_get + +static GLboolean _glewInit_GL_QCOM_extended_get () +{ + GLboolean r = GL_FALSE; + + r = ((glExtGetBufferPointervQCOM = (PFNGLEXTGETBUFFERPOINTERVQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetBufferPointervQCOM")) == NULL) || r; + r = ((glExtGetBuffersQCOM = (PFNGLEXTGETBUFFERSQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetBuffersQCOM")) == NULL) || r; + r = ((glExtGetFramebuffersQCOM = (PFNGLEXTGETFRAMEBUFFERSQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetFramebuffersQCOM")) == NULL) || r; + r = ((glExtGetRenderbuffersQCOM = (PFNGLEXTGETRENDERBUFFERSQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetRenderbuffersQCOM")) == NULL) || r; + r = ((glExtGetTexLevelParameterivQCOM = (PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetTexLevelParameterivQCOM")) == NULL) || r; + r = ((glExtGetTexSubImageQCOM = (PFNGLEXTGETTEXSUBIMAGEQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetTexSubImageQCOM")) == NULL) || r; + r = ((glExtGetTexturesQCOM = (PFNGLEXTGETTEXTURESQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetTexturesQCOM")) == NULL) || r; + r = ((glExtTexObjectStateOverrideiQCOM = (PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtTexObjectStateOverrideiQCOM")) == NULL) || r; + + return r; +} + +#endif /* GL_QCOM_extended_get */ + +#ifdef GL_QCOM_extended_get2 + +static GLboolean _glewInit_GL_QCOM_extended_get2 () +{ + GLboolean r = GL_FALSE; + + r = ((glExtGetProgramBinarySourceQCOM = (PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetProgramBinarySourceQCOM")) == NULL) || r; + r = ((glExtGetProgramsQCOM = (PFNGLEXTGETPROGRAMSQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetProgramsQCOM")) == NULL) || r; + r = ((glExtGetShadersQCOM = (PFNGLEXTGETSHADERSQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtGetShadersQCOM")) == NULL) || r; + r = ((glExtIsProgramBinaryQCOM = (PFNGLEXTISPROGRAMBINARYQCOMPROC)glewGetProcAddress((const GLubyte*)"glExtIsProgramBinaryQCOM")) == NULL) || r; + + return r; +} + +#endif /* GL_QCOM_extended_get2 */ + +#ifdef GL_QCOM_framebuffer_foveated + +static GLboolean _glewInit_GL_QCOM_framebuffer_foveated () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferFoveationConfigQCOM = (PFNGLFRAMEBUFFERFOVEATIONCONFIGQCOMPROC)glewGetProcAddress((const GLubyte*)"glFramebufferFoveationConfigQCOM")) == NULL) || r; + r = ((glFramebufferFoveationParametersQCOM = (PFNGLFRAMEBUFFERFOVEATIONPARAMETERSQCOMPROC)glewGetProcAddress((const GLubyte*)"glFramebufferFoveationParametersQCOM")) == NULL) || r; + + return r; +} + +#endif /* GL_QCOM_framebuffer_foveated */ + +#ifdef GL_QCOM_shader_framebuffer_fetch_noncoherent + +static GLboolean _glewInit_GL_QCOM_shader_framebuffer_fetch_noncoherent () +{ + GLboolean r = GL_FALSE; + + r = ((glFramebufferFetchBarrierQCOM = (PFNGLFRAMEBUFFERFETCHBARRIERQCOMPROC)glewGetProcAddress((const GLubyte*)"glFramebufferFetchBarrierQCOM")) == NULL) || r; + + return r; +} + +#endif /* GL_QCOM_shader_framebuffer_fetch_noncoherent */ + +#ifdef GL_QCOM_tiled_rendering + +static GLboolean _glewInit_GL_QCOM_tiled_rendering () +{ + GLboolean r = GL_FALSE; + + r = ((glEndTilingQCOM = (PFNGLENDTILINGQCOMPROC)glewGetProcAddress((const GLubyte*)"glEndTilingQCOM")) == NULL) || r; + r = ((glStartTilingQCOM = (PFNGLSTARTTILINGQCOMPROC)glewGetProcAddress((const GLubyte*)"glStartTilingQCOM")) == NULL) || r; + + return r; +} + +#endif /* GL_QCOM_tiled_rendering */ + +#ifdef GL_REGAL_ES1_0_compatibility + +static GLboolean _glewInit_GL_REGAL_ES1_0_compatibility () +{ + GLboolean r = GL_FALSE; + + r = ((glAlphaFuncx = (PFNGLALPHAFUNCXPROC)glewGetProcAddress((const GLubyte*)"glAlphaFuncx")) == NULL) || r; + r = ((glClearColorx = (PFNGLCLEARCOLORXPROC)glewGetProcAddress((const GLubyte*)"glClearColorx")) == NULL) || r; + r = ((glClearDepthx = (PFNGLCLEARDEPTHXPROC)glewGetProcAddress((const GLubyte*)"glClearDepthx")) == NULL) || r; + r = ((glColor4x = (PFNGLCOLOR4XPROC)glewGetProcAddress((const GLubyte*)"glColor4x")) == NULL) || r; + r = ((glDepthRangex = (PFNGLDEPTHRANGEXPROC)glewGetProcAddress((const GLubyte*)"glDepthRangex")) == NULL) || r; + r = ((glFogx = (PFNGLFOGXPROC)glewGetProcAddress((const GLubyte*)"glFogx")) == NULL) || r; + r = ((glFogxv = (PFNGLFOGXVPROC)glewGetProcAddress((const GLubyte*)"glFogxv")) == NULL) || r; + r = ((glFrustumf = (PFNGLFRUSTUMFPROC)glewGetProcAddress((const GLubyte*)"glFrustumf")) == NULL) || r; + r = ((glFrustumx = (PFNGLFRUSTUMXPROC)glewGetProcAddress((const GLubyte*)"glFrustumx")) == NULL) || r; + r = ((glLightModelx = (PFNGLLIGHTMODELXPROC)glewGetProcAddress((const GLubyte*)"glLightModelx")) == NULL) || r; + r = ((glLightModelxv = (PFNGLLIGHTMODELXVPROC)glewGetProcAddress((const GLubyte*)"glLightModelxv")) == NULL) || r; + r = ((glLightx = (PFNGLLIGHTXPROC)glewGetProcAddress((const GLubyte*)"glLightx")) == NULL) || r; + r = ((glLightxv = (PFNGLLIGHTXVPROC)glewGetProcAddress((const GLubyte*)"glLightxv")) == NULL) || r; + r = ((glLineWidthx = (PFNGLLINEWIDTHXPROC)glewGetProcAddress((const GLubyte*)"glLineWidthx")) == NULL) || r; + r = ((glLoadMatrixx = (PFNGLLOADMATRIXXPROC)glewGetProcAddress((const GLubyte*)"glLoadMatrixx")) == NULL) || r; + r = ((glMaterialx = (PFNGLMATERIALXPROC)glewGetProcAddress((const GLubyte*)"glMaterialx")) == NULL) || r; + r = ((glMaterialxv = (PFNGLMATERIALXVPROC)glewGetProcAddress((const GLubyte*)"glMaterialxv")) == NULL) || r; + r = ((glMultMatrixx = (PFNGLMULTMATRIXXPROC)glewGetProcAddress((const GLubyte*)"glMultMatrixx")) == NULL) || r; + r = ((glMultiTexCoord4x = (PFNGLMULTITEXCOORD4XPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4x")) == NULL) || r; + r = ((glNormal3x = (PFNGLNORMAL3XPROC)glewGetProcAddress((const GLubyte*)"glNormal3x")) == NULL) || r; + r = ((glOrthof = (PFNGLORTHOFPROC)glewGetProcAddress((const GLubyte*)"glOrthof")) == NULL) || r; + r = ((glOrthox = (PFNGLORTHOXPROC)glewGetProcAddress((const GLubyte*)"glOrthox")) == NULL) || r; + r = ((glPointSizex = (PFNGLPOINTSIZEXPROC)glewGetProcAddress((const GLubyte*)"glPointSizex")) == NULL) || r; + r = ((glPolygonOffsetx = (PFNGLPOLYGONOFFSETXPROC)glewGetProcAddress((const GLubyte*)"glPolygonOffsetx")) == NULL) || r; + r = ((glRotatex = (PFNGLROTATEXPROC)glewGetProcAddress((const GLubyte*)"glRotatex")) == NULL) || r; + r = ((glSampleCoveragex = (PFNGLSAMPLECOVERAGEXPROC)glewGetProcAddress((const GLubyte*)"glSampleCoveragex")) == NULL) || r; + r = ((glScalex = (PFNGLSCALEXPROC)glewGetProcAddress((const GLubyte*)"glScalex")) == NULL) || r; + r = ((glTexEnvx = (PFNGLTEXENVXPROC)glewGetProcAddress((const GLubyte*)"glTexEnvx")) == NULL) || r; + r = ((glTexEnvxv = (PFNGLTEXENVXVPROC)glewGetProcAddress((const GLubyte*)"glTexEnvxv")) == NULL) || r; + r = ((glTexParameterx = (PFNGLTEXPARAMETERXPROC)glewGetProcAddress((const GLubyte*)"glTexParameterx")) == NULL) || r; + r = ((glTranslatex = (PFNGLTRANSLATEXPROC)glewGetProcAddress((const GLubyte*)"glTranslatex")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_ES1_0_compatibility */ + +#ifdef GL_REGAL_ES1_1_compatibility + +static GLboolean _glewInit_GL_REGAL_ES1_1_compatibility () +{ + GLboolean r = GL_FALSE; + + r = ((glClipPlanef = (PFNGLCLIPPLANEFPROC)glewGetProcAddress((const GLubyte*)"glClipPlanef")) == NULL) || r; + r = ((glClipPlanex = (PFNGLCLIPPLANEXPROC)glewGetProcAddress((const GLubyte*)"glClipPlanex")) == NULL) || r; + r = ((glGetClipPlanef = (PFNGLGETCLIPPLANEFPROC)glewGetProcAddress((const GLubyte*)"glGetClipPlanef")) == NULL) || r; + r = ((glGetClipPlanex = (PFNGLGETCLIPPLANEXPROC)glewGetProcAddress((const GLubyte*)"glGetClipPlanex")) == NULL) || r; + r = ((glGetFixedv = (PFNGLGETFIXEDVPROC)glewGetProcAddress((const GLubyte*)"glGetFixedv")) == NULL) || r; + r = ((glGetLightxv = (PFNGLGETLIGHTXVPROC)glewGetProcAddress((const GLubyte*)"glGetLightxv")) == NULL) || r; + r = ((glGetMaterialxv = (PFNGLGETMATERIALXVPROC)glewGetProcAddress((const GLubyte*)"glGetMaterialxv")) == NULL) || r; + r = ((glGetTexEnvxv = (PFNGLGETTEXENVXVPROC)glewGetProcAddress((const GLubyte*)"glGetTexEnvxv")) == NULL) || r; + r = ((glGetTexParameterxv = (PFNGLGETTEXPARAMETERXVPROC)glewGetProcAddress((const GLubyte*)"glGetTexParameterxv")) == NULL) || r; + r = ((glPointParameterx = (PFNGLPOINTPARAMETERXPROC)glewGetProcAddress((const GLubyte*)"glPointParameterx")) == NULL) || r; + r = ((glPointParameterxv = (PFNGLPOINTPARAMETERXVPROC)glewGetProcAddress((const GLubyte*)"glPointParameterxv")) == NULL) || r; + r = ((glPointSizePointerOES = (PFNGLPOINTSIZEPOINTEROESPROC)glewGetProcAddress((const GLubyte*)"glPointSizePointerOES")) == NULL) || r; + r = ((glTexParameterxv = (PFNGLTEXPARAMETERXVPROC)glewGetProcAddress((const GLubyte*)"glTexParameterxv")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_ES1_1_compatibility */ + +#ifdef GL_REGAL_error_string + +static GLboolean _glewInit_GL_REGAL_error_string () +{ + GLboolean r = GL_FALSE; + + r = ((glErrorStringREGAL = (PFNGLERRORSTRINGREGALPROC)glewGetProcAddress((const GLubyte*)"glErrorStringREGAL")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_error_string */ + +#ifdef GL_REGAL_extension_query + +static GLboolean _glewInit_GL_REGAL_extension_query () +{ + GLboolean r = GL_FALSE; + + r = ((glGetExtensionREGAL = (PFNGLGETEXTENSIONREGALPROC)glewGetProcAddress((const GLubyte*)"glGetExtensionREGAL")) == NULL) || r; + r = ((glIsSupportedREGAL = (PFNGLISSUPPORTEDREGALPROC)glewGetProcAddress((const GLubyte*)"glIsSupportedREGAL")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_extension_query */ + +#ifdef GL_REGAL_log + +static GLboolean _glewInit_GL_REGAL_log () +{ + GLboolean r = GL_FALSE; + + r = ((glLogMessageCallbackREGAL = (PFNGLLOGMESSAGECALLBACKREGALPROC)glewGetProcAddress((const GLubyte*)"glLogMessageCallbackREGAL")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_log */ + +#ifdef GL_REGAL_proc_address + +static GLboolean _glewInit_GL_REGAL_proc_address () +{ + GLboolean r = GL_FALSE; + + r = ((glGetProcAddressREGAL = (PFNGLGETPROCADDRESSREGALPROC)glewGetProcAddress((const GLubyte*)"glGetProcAddressREGAL")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_proc_address */ + +#ifdef GL_SGIS_detail_texture + +static GLboolean _glewInit_GL_SGIS_detail_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glDetailTexFuncSGIS = (PFNGLDETAILTEXFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glDetailTexFuncSGIS")) == NULL) || r; + r = ((glGetDetailTexFuncSGIS = (PFNGLGETDETAILTEXFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glGetDetailTexFuncSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_detail_texture */ + +#ifdef GL_SGIS_fog_function + +static GLboolean _glewInit_GL_SGIS_fog_function () +{ + GLboolean r = GL_FALSE; + + r = ((glFogFuncSGIS = (PFNGLFOGFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glFogFuncSGIS")) == NULL) || r; + r = ((glGetFogFuncSGIS = (PFNGLGETFOGFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glGetFogFuncSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_fog_function */ + +#ifdef GL_SGIS_multisample + +static GLboolean _glewInit_GL_SGIS_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glSampleMaskSGIS = (PFNGLSAMPLEMASKSGISPROC)glewGetProcAddress((const GLubyte*)"glSampleMaskSGIS")) == NULL) || r; + r = ((glSamplePatternSGIS = (PFNGLSAMPLEPATTERNSGISPROC)glewGetProcAddress((const GLubyte*)"glSamplePatternSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_multisample */ + +#ifdef GL_SGIS_multitexture + +static GLboolean _glewInit_GL_SGIS_multitexture () +{ + GLboolean r = GL_FALSE; + + r = ((glInterleavedTextureCoordSetsSGIS = (PFNGLINTERLEAVEDTEXTURECOORDSETSSGISPROC)glewGetProcAddress((const GLubyte*)"glInterleavedTextureCoordSetsSGIS")) == NULL) || r; + r = ((glSelectTextureCoordSetSGIS = (PFNGLSELECTTEXTURECOORDSETSGISPROC)glewGetProcAddress((const GLubyte*)"glSelectTextureCoordSetSGIS")) == NULL) || r; + r = ((glSelectTextureSGIS = (PFNGLSELECTTEXTURESGISPROC)glewGetProcAddress((const GLubyte*)"glSelectTextureSGIS")) == NULL) || r; + r = ((glSelectTextureTransformSGIS = (PFNGLSELECTTEXTURETRANSFORMSGISPROC)glewGetProcAddress((const GLubyte*)"glSelectTextureTransformSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_multitexture */ + +#ifdef GL_SGIS_shared_multisample + +static GLboolean _glewInit_GL_SGIS_shared_multisample () +{ + GLboolean r = GL_FALSE; + + r = ((glMultisampleSubRectPosSGIS = (PFNGLMULTISAMPLESUBRECTPOSSGISPROC)glewGetProcAddress((const GLubyte*)"glMultisampleSubRectPosSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_shared_multisample */ + +#ifdef GL_SGIS_sharpen_texture + +static GLboolean _glewInit_GL_SGIS_sharpen_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glGetSharpenTexFuncSGIS = (PFNGLGETSHARPENTEXFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glGetSharpenTexFuncSGIS")) == NULL) || r; + r = ((glSharpenTexFuncSGIS = (PFNGLSHARPENTEXFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glSharpenTexFuncSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_sharpen_texture */ + +#ifdef GL_SGIS_texture4D + +static GLboolean _glewInit_GL_SGIS_texture4D () +{ + GLboolean r = GL_FALSE; + + r = ((glTexImage4DSGIS = (PFNGLTEXIMAGE4DSGISPROC)glewGetProcAddress((const GLubyte*)"glTexImage4DSGIS")) == NULL) || r; + r = ((glTexSubImage4DSGIS = (PFNGLTEXSUBIMAGE4DSGISPROC)glewGetProcAddress((const GLubyte*)"glTexSubImage4DSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_texture4D */ + +#ifdef GL_SGIS_texture_filter4 + +static GLboolean _glewInit_GL_SGIS_texture_filter4 () +{ + GLboolean r = GL_FALSE; + + r = ((glGetTexFilterFuncSGIS = (PFNGLGETTEXFILTERFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glGetTexFilterFuncSGIS")) == NULL) || r; + r = ((glTexFilterFuncSGIS = (PFNGLTEXFILTERFUNCSGISPROC)glewGetProcAddress((const GLubyte*)"glTexFilterFuncSGIS")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIS_texture_filter4 */ + +#ifdef GL_SGIX_async + +static GLboolean _glewInit_GL_SGIX_async () +{ + GLboolean r = GL_FALSE; + + r = ((glAsyncMarkerSGIX = (PFNGLASYNCMARKERSGIXPROC)glewGetProcAddress((const GLubyte*)"glAsyncMarkerSGIX")) == NULL) || r; + r = ((glDeleteAsyncMarkersSGIX = (PFNGLDELETEASYNCMARKERSSGIXPROC)glewGetProcAddress((const GLubyte*)"glDeleteAsyncMarkersSGIX")) == NULL) || r; + r = ((glFinishAsyncSGIX = (PFNGLFINISHASYNCSGIXPROC)glewGetProcAddress((const GLubyte*)"glFinishAsyncSGIX")) == NULL) || r; + r = ((glGenAsyncMarkersSGIX = (PFNGLGENASYNCMARKERSSGIXPROC)glewGetProcAddress((const GLubyte*)"glGenAsyncMarkersSGIX")) == NULL) || r; + r = ((glIsAsyncMarkerSGIX = (PFNGLISASYNCMARKERSGIXPROC)glewGetProcAddress((const GLubyte*)"glIsAsyncMarkerSGIX")) == NULL) || r; + r = ((glPollAsyncSGIX = (PFNGLPOLLASYNCSGIXPROC)glewGetProcAddress((const GLubyte*)"glPollAsyncSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_async */ + +#ifdef GL_SGIX_datapipe + +static GLboolean _glewInit_GL_SGIX_datapipe () +{ + GLboolean r = GL_FALSE; + + r = ((glAddressSpace = (PFNGLADDRESSSPACEPROC)glewGetProcAddress((const GLubyte*)"glAddressSpace")) == NULL) || r; + r = ((glDataPipe = (PFNGLDATAPIPEPROC)glewGetProcAddress((const GLubyte*)"glDataPipe")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_datapipe */ + +#ifdef GL_SGIX_flush_raster + +static GLboolean _glewInit_GL_SGIX_flush_raster () +{ + GLboolean r = GL_FALSE; + + r = ((glFlushRasterSGIX = (PFNGLFLUSHRASTERSGIXPROC)glewGetProcAddress((const GLubyte*)"glFlushRasterSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_flush_raster */ + +#ifdef GL_SGIX_fog_layers + +static GLboolean _glewInit_GL_SGIX_fog_layers () +{ + GLboolean r = GL_FALSE; + + r = ((glFogLayersSGIX = (PFNGLFOGLAYERSSGIXPROC)glewGetProcAddress((const GLubyte*)"glFogLayersSGIX")) == NULL) || r; + r = ((glGetFogLayersSGIX = (PFNGLGETFOGLAYERSSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetFogLayersSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_fog_layers */ + +#ifdef GL_SGIX_fog_texture + +static GLboolean _glewInit_GL_SGIX_fog_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glTextureFogSGIX = (PFNGLTEXTUREFOGSGIXPROC)glewGetProcAddress((const GLubyte*)"glTextureFogSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_fog_texture */ + +#ifdef GL_SGIX_fragment_specular_lighting + +static GLboolean _glewInit_GL_SGIX_fragment_specular_lighting () +{ + GLboolean r = GL_FALSE; + + r = ((glFragmentColorMaterialSGIX = (PFNGLFRAGMENTCOLORMATERIALSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentColorMaterialSGIX")) == NULL) || r; + r = ((glFragmentLightModelfSGIX = (PFNGLFRAGMENTLIGHTMODELFSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModelfSGIX")) == NULL) || r; + r = ((glFragmentLightModelfvSGIX = (PFNGLFRAGMENTLIGHTMODELFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModelfvSGIX")) == NULL) || r; + r = ((glFragmentLightModeliSGIX = (PFNGLFRAGMENTLIGHTMODELISGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModeliSGIX")) == NULL) || r; + r = ((glFragmentLightModelivSGIX = (PFNGLFRAGMENTLIGHTMODELIVSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightModelivSGIX")) == NULL) || r; + r = ((glFragmentLightfSGIX = (PFNGLFRAGMENTLIGHTFSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightfSGIX")) == NULL) || r; + r = ((glFragmentLightfvSGIX = (PFNGLFRAGMENTLIGHTFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightfvSGIX")) == NULL) || r; + r = ((glFragmentLightiSGIX = (PFNGLFRAGMENTLIGHTISGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightiSGIX")) == NULL) || r; + r = ((glFragmentLightivSGIX = (PFNGLFRAGMENTLIGHTIVSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentLightivSGIX")) == NULL) || r; + r = ((glFragmentMaterialfSGIX = (PFNGLFRAGMENTMATERIALFSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialfSGIX")) == NULL) || r; + r = ((glFragmentMaterialfvSGIX = (PFNGLFRAGMENTMATERIALFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialfvSGIX")) == NULL) || r; + r = ((glFragmentMaterialiSGIX = (PFNGLFRAGMENTMATERIALISGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialiSGIX")) == NULL) || r; + r = ((glFragmentMaterialivSGIX = (PFNGLFRAGMENTMATERIALIVSGIXPROC)glewGetProcAddress((const GLubyte*)"glFragmentMaterialivSGIX")) == NULL) || r; + r = ((glGetFragmentLightfvSGIX = (PFNGLGETFRAGMENTLIGHTFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentLightfvSGIX")) == NULL) || r; + r = ((glGetFragmentLightivSGIX = (PFNGLGETFRAGMENTLIGHTIVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentLightivSGIX")) == NULL) || r; + r = ((glGetFragmentMaterialfvSGIX = (PFNGLGETFRAGMENTMATERIALFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentMaterialfvSGIX")) == NULL) || r; + r = ((glGetFragmentMaterialivSGIX = (PFNGLGETFRAGMENTMATERIALIVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetFragmentMaterialivSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_fragment_specular_lighting */ + +#ifdef GL_SGIX_framezoom + +static GLboolean _glewInit_GL_SGIX_framezoom () +{ + GLboolean r = GL_FALSE; + + r = ((glFrameZoomSGIX = (PFNGLFRAMEZOOMSGIXPROC)glewGetProcAddress((const GLubyte*)"glFrameZoomSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_framezoom */ + +#ifdef GL_SGIX_igloo_interface + +static GLboolean _glewInit_GL_SGIX_igloo_interface () +{ + GLboolean r = GL_FALSE; + + r = ((glIglooInterfaceSGIX = (PFNGLIGLOOINTERFACESGIXPROC)glewGetProcAddress((const GLubyte*)"glIglooInterfaceSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_igloo_interface */ + +#ifdef GL_SGIX_mpeg1 + +static GLboolean _glewInit_GL_SGIX_mpeg1 () +{ + GLboolean r = GL_FALSE; + + r = ((glAllocMPEGPredictorsSGIX = (PFNGLALLOCMPEGPREDICTORSSGIXPROC)glewGetProcAddress((const GLubyte*)"glAllocMPEGPredictorsSGIX")) == NULL) || r; + r = ((glDeleteMPEGPredictorsSGIX = (PFNGLDELETEMPEGPREDICTORSSGIXPROC)glewGetProcAddress((const GLubyte*)"glDeleteMPEGPredictorsSGIX")) == NULL) || r; + r = ((glGenMPEGPredictorsSGIX = (PFNGLGENMPEGPREDICTORSSGIXPROC)glewGetProcAddress((const GLubyte*)"glGenMPEGPredictorsSGIX")) == NULL) || r; + r = ((glGetMPEGParameterfvSGIX = (PFNGLGETMPEGPARAMETERFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetMPEGParameterfvSGIX")) == NULL) || r; + r = ((glGetMPEGParameterivSGIX = (PFNGLGETMPEGPARAMETERIVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetMPEGParameterivSGIX")) == NULL) || r; + r = ((glGetMPEGPredictorSGIX = (PFNGLGETMPEGPREDICTORSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetMPEGPredictorSGIX")) == NULL) || r; + r = ((glGetMPEGQuantTableubv = (PFNGLGETMPEGQUANTTABLEUBVPROC)glewGetProcAddress((const GLubyte*)"glGetMPEGQuantTableubv")) == NULL) || r; + r = ((glIsMPEGPredictorSGIX = (PFNGLISMPEGPREDICTORSGIXPROC)glewGetProcAddress((const GLubyte*)"glIsMPEGPredictorSGIX")) == NULL) || r; + r = ((glMPEGPredictorSGIX = (PFNGLMPEGPREDICTORSGIXPROC)glewGetProcAddress((const GLubyte*)"glMPEGPredictorSGIX")) == NULL) || r; + r = ((glMPEGQuantTableubv = (PFNGLMPEGQUANTTABLEUBVPROC)glewGetProcAddress((const GLubyte*)"glMPEGQuantTableubv")) == NULL) || r; + r = ((glSwapMPEGPredictorsSGIX = (PFNGLSWAPMPEGPREDICTORSSGIXPROC)glewGetProcAddress((const GLubyte*)"glSwapMPEGPredictorsSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_mpeg1 */ + +#ifdef GL_SGIX_nonlinear_lighting_pervertex + +static GLboolean _glewInit_GL_SGIX_nonlinear_lighting_pervertex () +{ + GLboolean r = GL_FALSE; + + r = ((glGetNonlinLightfvSGIX = (PFNGLGETNONLINLIGHTFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetNonlinLightfvSGIX")) == NULL) || r; + r = ((glGetNonlinMaterialfvSGIX = (PFNGLGETNONLINMATERIALFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetNonlinMaterialfvSGIX")) == NULL) || r; + r = ((glNonlinLightfvSGIX = (PFNGLNONLINLIGHTFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glNonlinLightfvSGIX")) == NULL) || r; + r = ((glNonlinMaterialfvSGIX = (PFNGLNONLINMATERIALFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glNonlinMaterialfvSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_nonlinear_lighting_pervertex */ + +#ifdef GL_SGIX_pixel_texture + +static GLboolean _glewInit_GL_SGIX_pixel_texture () +{ + GLboolean r = GL_FALSE; + + r = ((glPixelTexGenSGIX = (PFNGLPIXELTEXGENSGIXPROC)glewGetProcAddress((const GLubyte*)"glPixelTexGenSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_pixel_texture */ + +#ifdef GL_SGIX_polynomial_ffd + +static GLboolean _glewInit_GL_SGIX_polynomial_ffd () +{ + GLboolean r = GL_FALSE; + + r = ((glDeformSGIX = (PFNGLDEFORMSGIXPROC)glewGetProcAddress((const GLubyte*)"glDeformSGIX")) == NULL) || r; + r = ((glLoadIdentityDeformationMapSGIX = (PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC)glewGetProcAddress((const GLubyte*)"glLoadIdentityDeformationMapSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_polynomial_ffd */ + +#ifdef GL_SGIX_quad_mesh + +static GLboolean _glewInit_GL_SGIX_quad_mesh () +{ + GLboolean r = GL_FALSE; + + r = ((glMeshBreadthSGIX = (PFNGLMESHBREADTHSGIXPROC)glewGetProcAddress((const GLubyte*)"glMeshBreadthSGIX")) == NULL) || r; + r = ((glMeshStrideSGIX = (PFNGLMESHSTRIDESGIXPROC)glewGetProcAddress((const GLubyte*)"glMeshStrideSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_quad_mesh */ + +#ifdef GL_SGIX_reference_plane + +static GLboolean _glewInit_GL_SGIX_reference_plane () +{ + GLboolean r = GL_FALSE; + + r = ((glReferencePlaneSGIX = (PFNGLREFERENCEPLANESGIXPROC)glewGetProcAddress((const GLubyte*)"glReferencePlaneSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_reference_plane */ + +#ifdef GL_SGIX_sprite + +static GLboolean _glewInit_GL_SGIX_sprite () +{ + GLboolean r = GL_FALSE; + + r = ((glSpriteParameterfSGIX = (PFNGLSPRITEPARAMETERFSGIXPROC)glewGetProcAddress((const GLubyte*)"glSpriteParameterfSGIX")) == NULL) || r; + r = ((glSpriteParameterfvSGIX = (PFNGLSPRITEPARAMETERFVSGIXPROC)glewGetProcAddress((const GLubyte*)"glSpriteParameterfvSGIX")) == NULL) || r; + r = ((glSpriteParameteriSGIX = (PFNGLSPRITEPARAMETERISGIXPROC)glewGetProcAddress((const GLubyte*)"glSpriteParameteriSGIX")) == NULL) || r; + r = ((glSpriteParameterivSGIX = (PFNGLSPRITEPARAMETERIVSGIXPROC)glewGetProcAddress((const GLubyte*)"glSpriteParameterivSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_sprite */ + +#ifdef GL_SGIX_tag_sample_buffer + +static GLboolean _glewInit_GL_SGIX_tag_sample_buffer () +{ + GLboolean r = GL_FALSE; + + r = ((glTagSampleBufferSGIX = (PFNGLTAGSAMPLEBUFFERSGIXPROC)glewGetProcAddress((const GLubyte*)"glTagSampleBufferSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_tag_sample_buffer */ + +#ifdef GL_SGIX_vector_ops + +static GLboolean _glewInit_GL_SGIX_vector_ops () +{ + GLboolean r = GL_FALSE; + + r = ((glGetVectorOperationSGIX = (PFNGLGETVECTOROPERATIONSGIXPROC)glewGetProcAddress((const GLubyte*)"glGetVectorOperationSGIX")) == NULL) || r; + r = ((glVectorOperationSGIX = (PFNGLVECTOROPERATIONSGIXPROC)glewGetProcAddress((const GLubyte*)"glVectorOperationSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_vector_ops */ + +#ifdef GL_SGIX_vertex_array_object + +static GLboolean _glewInit_GL_SGIX_vertex_array_object () +{ + GLboolean r = GL_FALSE; + + r = ((glAreVertexArraysResidentSGIX = (PFNGLAREVERTEXARRAYSRESIDENTSGIXPROC)glewGetProcAddress((const GLubyte*)"glAreVertexArraysResidentSGIX")) == NULL) || r; + r = ((glBindVertexArraySGIX = (PFNGLBINDVERTEXARRAYSGIXPROC)glewGetProcAddress((const GLubyte*)"glBindVertexArraySGIX")) == NULL) || r; + r = ((glDeleteVertexArraysSGIX = (PFNGLDELETEVERTEXARRAYSSGIXPROC)glewGetProcAddress((const GLubyte*)"glDeleteVertexArraysSGIX")) == NULL) || r; + r = ((glGenVertexArraysSGIX = (PFNGLGENVERTEXARRAYSSGIXPROC)glewGetProcAddress((const GLubyte*)"glGenVertexArraysSGIX")) == NULL) || r; + r = ((glIsVertexArraySGIX = (PFNGLISVERTEXARRAYSGIXPROC)glewGetProcAddress((const GLubyte*)"glIsVertexArraySGIX")) == NULL) || r; + r = ((glPrioritizeVertexArraysSGIX = (PFNGLPRIORITIZEVERTEXARRAYSSGIXPROC)glewGetProcAddress((const GLubyte*)"glPrioritizeVertexArraysSGIX")) == NULL) || r; + + return r; +} + +#endif /* GL_SGIX_vertex_array_object */ + +#ifdef GL_SGI_color_table + +static GLboolean _glewInit_GL_SGI_color_table () +{ + GLboolean r = GL_FALSE; + + r = ((glColorTableParameterfvSGI = (PFNGLCOLORTABLEPARAMETERFVSGIPROC)glewGetProcAddress((const GLubyte*)"glColorTableParameterfvSGI")) == NULL) || r; + r = ((glColorTableParameterivSGI = (PFNGLCOLORTABLEPARAMETERIVSGIPROC)glewGetProcAddress((const GLubyte*)"glColorTableParameterivSGI")) == NULL) || r; + r = ((glColorTableSGI = (PFNGLCOLORTABLESGIPROC)glewGetProcAddress((const GLubyte*)"glColorTableSGI")) == NULL) || r; + r = ((glCopyColorTableSGI = (PFNGLCOPYCOLORTABLESGIPROC)glewGetProcAddress((const GLubyte*)"glCopyColorTableSGI")) == NULL) || r; + r = ((glGetColorTableParameterfvSGI = (PFNGLGETCOLORTABLEPARAMETERFVSGIPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableParameterfvSGI")) == NULL) || r; + r = ((glGetColorTableParameterivSGI = (PFNGLGETCOLORTABLEPARAMETERIVSGIPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableParameterivSGI")) == NULL) || r; + r = ((glGetColorTableSGI = (PFNGLGETCOLORTABLESGIPROC)glewGetProcAddress((const GLubyte*)"glGetColorTableSGI")) == NULL) || r; + + return r; +} + +#endif /* GL_SGI_color_table */ + +#ifdef GL_SGI_fft + +static GLboolean _glewInit_GL_SGI_fft () +{ + GLboolean r = GL_FALSE; + + r = ((glGetPixelTransformParameterfvSGI = (PFNGLGETPIXELTRANSFORMPARAMETERFVSGIPROC)glewGetProcAddress((const GLubyte*)"glGetPixelTransformParameterfvSGI")) == NULL) || r; + r = ((glGetPixelTransformParameterivSGI = (PFNGLGETPIXELTRANSFORMPARAMETERIVSGIPROC)glewGetProcAddress((const GLubyte*)"glGetPixelTransformParameterivSGI")) == NULL) || r; + r = ((glPixelTransformParameterfSGI = (PFNGLPIXELTRANSFORMPARAMETERFSGIPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameterfSGI")) == NULL) || r; + r = ((glPixelTransformParameterfvSGI = (PFNGLPIXELTRANSFORMPARAMETERFVSGIPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameterfvSGI")) == NULL) || r; + r = ((glPixelTransformParameteriSGI = (PFNGLPIXELTRANSFORMPARAMETERISGIPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameteriSGI")) == NULL) || r; + r = ((glPixelTransformParameterivSGI = (PFNGLPIXELTRANSFORMPARAMETERIVSGIPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformParameterivSGI")) == NULL) || r; + r = ((glPixelTransformSGI = (PFNGLPIXELTRANSFORMSGIPROC)glewGetProcAddress((const GLubyte*)"glPixelTransformSGI")) == NULL) || r; + + return r; +} + +#endif /* GL_SGI_fft */ + +#ifdef GL_SUNX_constant_data + +static GLboolean _glewInit_GL_SUNX_constant_data () +{ + GLboolean r = GL_FALSE; + + r = ((glFinishTextureSUNX = (PFNGLFINISHTEXTURESUNXPROC)glewGetProcAddress((const GLubyte*)"glFinishTextureSUNX")) == NULL) || r; + + return r; +} + +#endif /* GL_SUNX_constant_data */ + +#ifdef GL_SUN_global_alpha + +static GLboolean _glewInit_GL_SUN_global_alpha () +{ + GLboolean r = GL_FALSE; + + r = ((glGlobalAlphaFactorbSUN = (PFNGLGLOBALALPHAFACTORBSUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactorbSUN")) == NULL) || r; + r = ((glGlobalAlphaFactordSUN = (PFNGLGLOBALALPHAFACTORDSUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactordSUN")) == NULL) || r; + r = ((glGlobalAlphaFactorfSUN = (PFNGLGLOBALALPHAFACTORFSUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactorfSUN")) == NULL) || r; + r = ((glGlobalAlphaFactoriSUN = (PFNGLGLOBALALPHAFACTORISUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactoriSUN")) == NULL) || r; + r = ((glGlobalAlphaFactorsSUN = (PFNGLGLOBALALPHAFACTORSSUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactorsSUN")) == NULL) || r; + r = ((glGlobalAlphaFactorubSUN = (PFNGLGLOBALALPHAFACTORUBSUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactorubSUN")) == NULL) || r; + r = ((glGlobalAlphaFactoruiSUN = (PFNGLGLOBALALPHAFACTORUISUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactoruiSUN")) == NULL) || r; + r = ((glGlobalAlphaFactorusSUN = (PFNGLGLOBALALPHAFACTORUSSUNPROC)glewGetProcAddress((const GLubyte*)"glGlobalAlphaFactorusSUN")) == NULL) || r; + + return r; +} + +#endif /* GL_SUN_global_alpha */ + +#ifdef GL_SUN_read_video_pixels + +static GLboolean _glewInit_GL_SUN_read_video_pixels () +{ + GLboolean r = GL_FALSE; + + r = ((glReadVideoPixelsSUN = (PFNGLREADVIDEOPIXELSSUNPROC)glewGetProcAddress((const GLubyte*)"glReadVideoPixelsSUN")) == NULL) || r; + + return r; +} + +#endif /* GL_SUN_read_video_pixels */ + +#ifdef GL_SUN_triangle_list + +static GLboolean _glewInit_GL_SUN_triangle_list () +{ + GLboolean r = GL_FALSE; + + r = ((glReplacementCodePointerSUN = (PFNGLREPLACEMENTCODEPOINTERSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodePointerSUN")) == NULL) || r; + r = ((glReplacementCodeubSUN = (PFNGLREPLACEMENTCODEUBSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeubSUN")) == NULL) || r; + r = ((glReplacementCodeubvSUN = (PFNGLREPLACEMENTCODEUBVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeubvSUN")) == NULL) || r; + r = ((glReplacementCodeuiSUN = (PFNGLREPLACEMENTCODEUISUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiSUN")) == NULL) || r; + r = ((glReplacementCodeuivSUN = (PFNGLREPLACEMENTCODEUIVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuivSUN")) == NULL) || r; + r = ((glReplacementCodeusSUN = (PFNGLREPLACEMENTCODEUSSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeusSUN")) == NULL) || r; + r = ((glReplacementCodeusvSUN = (PFNGLREPLACEMENTCODEUSVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeusvSUN")) == NULL) || r; + + return r; +} + +#endif /* GL_SUN_triangle_list */ + +#ifdef GL_SUN_vertex + +static GLboolean _glewInit_GL_SUN_vertex () +{ + GLboolean r = GL_FALSE; + + r = ((glColor3fVertex3fSUN = (PFNGLCOLOR3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glColor3fVertex3fSUN")) == NULL) || r; + r = ((glColor3fVertex3fvSUN = (PFNGLCOLOR3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glColor3fVertex3fvSUN")) == NULL) || r; + r = ((glColor4fNormal3fVertex3fSUN = (PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glColor4fNormal3fVertex3fSUN")) == NULL) || r; + r = ((glColor4fNormal3fVertex3fvSUN = (PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glColor4fNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glColor4ubVertex2fSUN = (PFNGLCOLOR4UBVERTEX2FSUNPROC)glewGetProcAddress((const GLubyte*)"glColor4ubVertex2fSUN")) == NULL) || r; + r = ((glColor4ubVertex2fvSUN = (PFNGLCOLOR4UBVERTEX2FVSUNPROC)glewGetProcAddress((const GLubyte*)"glColor4ubVertex2fvSUN")) == NULL) || r; + r = ((glColor4ubVertex3fSUN = (PFNGLCOLOR4UBVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glColor4ubVertex3fSUN")) == NULL) || r; + r = ((glColor4ubVertex3fvSUN = (PFNGLCOLOR4UBVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glColor4ubVertex3fvSUN")) == NULL) || r; + r = ((glNormal3fVertex3fSUN = (PFNGLNORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glNormal3fVertex3fSUN")) == NULL) || r; + r = ((glNormal3fVertex3fvSUN = (PFNGLNORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiColor3fVertex3fSUN = (PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiColor3fVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiColor3fVertex3fvSUN = (PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiColor3fVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiColor4fNormal3fVertex3fSUN = (PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiColor4fNormal3fVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiColor4fNormal3fVertex3fvSUN = (PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiColor4fNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiColor4ubVertex3fSUN = (PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiColor4ubVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiColor4ubVertex3fvSUN = (PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiColor4ubVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiNormal3fVertex3fSUN = (PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiNormal3fVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiNormal3fVertex3fvSUN = (PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = (PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = (PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = (PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = (PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiTexCoord2fVertex3fSUN = (PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiTexCoord2fVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiTexCoord2fVertex3fvSUN = (PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiTexCoord2fVertex3fvSUN")) == NULL) || r; + r = ((glReplacementCodeuiVertex3fSUN = (PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiVertex3fSUN")) == NULL) || r; + r = ((glReplacementCodeuiVertex3fvSUN = (PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glReplacementCodeuiVertex3fvSUN")) == NULL) || r; + r = ((glTexCoord2fColor3fVertex3fSUN = (PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fColor3fVertex3fSUN")) == NULL) || r; + r = ((glTexCoord2fColor3fVertex3fvSUN = (PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fColor3fVertex3fvSUN")) == NULL) || r; + r = ((glTexCoord2fColor4fNormal3fVertex3fSUN = (PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fColor4fNormal3fVertex3fSUN")) == NULL) || r; + r = ((glTexCoord2fColor4fNormal3fVertex3fvSUN = (PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fColor4fNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glTexCoord2fColor4ubVertex3fSUN = (PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fColor4ubVertex3fSUN")) == NULL) || r; + r = ((glTexCoord2fColor4ubVertex3fvSUN = (PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fColor4ubVertex3fvSUN")) == NULL) || r; + r = ((glTexCoord2fNormal3fVertex3fSUN = (PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fNormal3fVertex3fSUN")) == NULL) || r; + r = ((glTexCoord2fNormal3fVertex3fvSUN = (PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fNormal3fVertex3fvSUN")) == NULL) || r; + r = ((glTexCoord2fVertex3fSUN = (PFNGLTEXCOORD2FVERTEX3FSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fVertex3fSUN")) == NULL) || r; + r = ((glTexCoord2fVertex3fvSUN = (PFNGLTEXCOORD2FVERTEX3FVSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord2fVertex3fvSUN")) == NULL) || r; + r = ((glTexCoord4fColor4fNormal3fVertex4fSUN = (PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord4fColor4fNormal3fVertex4fSUN")) == NULL) || r; + r = ((glTexCoord4fColor4fNormal3fVertex4fvSUN = (PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord4fColor4fNormal3fVertex4fvSUN")) == NULL) || r; + r = ((glTexCoord4fVertex4fSUN = (PFNGLTEXCOORD4FVERTEX4FSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord4fVertex4fSUN")) == NULL) || r; + r = ((glTexCoord4fVertex4fvSUN = (PFNGLTEXCOORD4FVERTEX4FVSUNPROC)glewGetProcAddress((const GLubyte*)"glTexCoord4fVertex4fvSUN")) == NULL) || r; + + return r; +} + +#endif /* GL_SUN_vertex */ + +#ifdef GL_WIN_swap_hint + +static GLboolean _glewInit_GL_WIN_swap_hint () +{ + GLboolean r = GL_FALSE; + + r = ((glAddSwapHintRectWIN = (PFNGLADDSWAPHINTRECTWINPROC)glewGetProcAddress((const GLubyte*)"glAddSwapHintRectWIN")) == NULL) || r; + + return r; +} + +#endif /* GL_WIN_swap_hint */ + +/* ------------------------------------------------------------------------- */ + +static int _glewExtensionCompare(const char *s1, const char *s2) +{ + /* http://www.chanduthedev.com/2012/07/strcmp-implementation-in-c.html */ + while (*s1 || *s2) + { + if (*s1 > *s2) + return 1; + if (*s1 < *s2) + return -1; + s1++; + s2++; + } + return 0; +} + +static ptrdiff_t _glewBsearchExtension(const char* name) +{ + ptrdiff_t lo = 0, hi = sizeof(_glewExtensionLookup) / sizeof(char*) - 2; + + while (lo <= hi) + { + ptrdiff_t mid = (lo + hi) / 2; + const int cmp = _glewExtensionCompare(name, _glewExtensionLookup[mid]); + if (cmp < 0) hi = mid - 1; + else if (cmp > 0) lo = mid + 1; + else return mid; + } + return -1; +} + +static GLboolean *_glewGetExtensionString(const char *name) +{ + ptrdiff_t n = _glewBsearchExtension(name); + if (n >= 0) return &_glewExtensionString[n]; + return NULL; +} + +static GLboolean *_glewGetExtensionEnable(const char *name) +{ + ptrdiff_t n = _glewBsearchExtension(name); + if (n >= 0) return _glewExtensionEnabled[n]; + return NULL; +} + +static const char *_glewNextSpace(const char *i) +{ + const char *j = i; + if (j) + while (*j!=' ' && *j) ++j; + return j; +} + +static const char *_glewNextNonSpace(const char *i) +{ + const char *j = i; + if (j) + while (*j==' ') ++j; + return j; +} + +GLboolean GLEWAPIENTRY glewGetExtension (const char* name) +{ + GLboolean *enable = _glewGetExtensionString(name); + if (enable) + return *enable; + return GL_FALSE; +} + +/* ------------------------------------------------------------------------- */ + +typedef const GLubyte* (GLAPIENTRY * PFNGLGETSTRINGPROC) (GLenum name); +typedef void (GLAPIENTRY * PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params); + +static GLenum GLEWAPIENTRY glewContextInit () +{ + PFNGLGETSTRINGPROC getString; + const GLubyte* s; + GLuint dot; + GLint major, minor; + size_t n; + + getString = (PFNGLGETSTRINGPROC) glewGetProcAddress((const GLubyte*)"glGetString"); + if (!getString) + return GLEW_ERROR_NO_GL_VERSION; + + /* query opengl version */ + s = getString(GL_VERSION); + dot = _glewStrCLen(s, '.'); + if (dot == 0) + return GLEW_ERROR_NO_GL_VERSION; + + major = s[dot-1]-'0'; + minor = s[dot+1]-'0'; + + if (minor < 0 || minor > 9) + minor = 0; + if (major<0 || major>9) + return GLEW_ERROR_NO_GL_VERSION; + + if (major == 1 && minor == 0) + { + return GLEW_ERROR_GL_VERSION_10_ONLY; + } + else + { + CONST_CAST(GLEW_VERSION_4_6) = ( major > 4 ) || ( major == 4 && minor >= 6 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_5) = GLEW_VERSION_4_4 == GL_TRUE || ( major == 4 && minor >= 5 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_4) = GLEW_VERSION_4_5 == GL_TRUE || ( major == 4 && minor >= 4 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_3) = GLEW_VERSION_4_4 == GL_TRUE || ( major == 4 && minor >= 3 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_2) = GLEW_VERSION_4_3 == GL_TRUE || ( major == 4 && minor >= 2 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_1) = GLEW_VERSION_4_2 == GL_TRUE || ( major == 4 && minor >= 1 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_0) = GLEW_VERSION_4_1 == GL_TRUE || ( major == 4 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_3_3) = GLEW_VERSION_4_0 == GL_TRUE || ( major == 3 && minor >= 3 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_3_2) = GLEW_VERSION_3_3 == GL_TRUE || ( major == 3 && minor >= 2 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_3_1) = GLEW_VERSION_3_2 == GL_TRUE || ( major == 3 && minor >= 1 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_3_0) = GLEW_VERSION_3_1 == GL_TRUE || ( major == 3 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_2_1) = GLEW_VERSION_3_0 == GL_TRUE || ( major == 2 && minor >= 1 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_2_0) = GLEW_VERSION_2_1 == GL_TRUE || ( major == 2 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_1_5) = GLEW_VERSION_2_0 == GL_TRUE || ( major == 1 && minor >= 5 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_1_4) = GLEW_VERSION_1_5 == GL_TRUE || ( major == 1 && minor >= 4 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_1_3) = GLEW_VERSION_1_4 == GL_TRUE || ( major == 1 && minor >= 3 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_1_2_1) = GLEW_VERSION_1_3 == GL_TRUE ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_1_2) = GLEW_VERSION_1_2_1 == GL_TRUE || ( major == 1 && minor >= 2 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_1_1) = GLEW_VERSION_1_2 == GL_TRUE || ( major == 1 && minor >= 1 ) ? GL_TRUE : GL_FALSE; + } + + for (n = 0; n < sizeof(_glewExtensionString) / sizeof(_glewExtensionString[0]); ++n) + _glewExtensionString[n] = GL_FALSE; + + if (GLEW_VERSION_3_0) + { + GLint n = 0; + GLint i; + PFNGLGETINTEGERVPROC getIntegerv; + PFNGLGETSTRINGIPROC getStringi; + const char *ext; + GLboolean *enable; + + getIntegerv = (PFNGLGETINTEGERVPROC) glewGetProcAddress((const GLubyte*)"glGetIntegerv"); + + if (getIntegerv) + getIntegerv(GL_NUM_EXTENSIONS, &n); + + /* glGetStringi is OpenGL 3.0 */ + getStringi = (PFNGLGETSTRINGIPROC) glewGetProcAddress((const GLubyte*)"glGetStringi"); + if (getStringi) + for (i = 0; i= (ptrdiff_t) sizeof(ext)) + continue; + _glewStrCopy(ext, i, ' '); + + /* Based on extension string(s), glewGetExtension purposes */ + enable = _glewGetExtensionString(ext); + if (enable) + *enable = GL_TRUE; + + /* Based on extension string(s), experimental mode, glewIsSupported purposes */ + enable = _glewGetExtensionEnable(ext); + if (enable) + *enable = GL_TRUE; + } + } + } + +#ifdef GL_VERSION_1_2 + if (glewExperimental || GLEW_VERSION_1_2) CONST_CAST(GLEW_VERSION_1_2) = !_glewInit_GL_VERSION_1_2(); +#endif /* GL_VERSION_1_2 */ +#ifdef GL_VERSION_1_3 + if (glewExperimental || GLEW_VERSION_1_3) CONST_CAST(GLEW_VERSION_1_3) = !_glewInit_GL_VERSION_1_3(); +#endif /* GL_VERSION_1_3 */ +#ifdef GL_VERSION_1_4 + if (glewExperimental || GLEW_VERSION_1_4) CONST_CAST(GLEW_VERSION_1_4) = !_glewInit_GL_VERSION_1_4(); +#endif /* GL_VERSION_1_4 */ +#ifdef GL_VERSION_1_5 + if (glewExperimental || GLEW_VERSION_1_5) CONST_CAST(GLEW_VERSION_1_5) = !_glewInit_GL_VERSION_1_5(); +#endif /* GL_VERSION_1_5 */ +#ifdef GL_VERSION_2_0 + if (glewExperimental || GLEW_VERSION_2_0) CONST_CAST(GLEW_VERSION_2_0) = !_glewInit_GL_VERSION_2_0(); +#endif /* GL_VERSION_2_0 */ +#ifdef GL_VERSION_2_1 + if (glewExperimental || GLEW_VERSION_2_1) CONST_CAST(GLEW_VERSION_2_1) = !_glewInit_GL_VERSION_2_1(); +#endif /* GL_VERSION_2_1 */ +#ifdef GL_VERSION_3_0 + if (glewExperimental || GLEW_VERSION_3_0) CONST_CAST(GLEW_VERSION_3_0) = !_glewInit_GL_VERSION_3_0(); +#endif /* GL_VERSION_3_0 */ +#ifdef GL_VERSION_3_1 + if (glewExperimental || GLEW_VERSION_3_1) CONST_CAST(GLEW_VERSION_3_1) = !_glewInit_GL_VERSION_3_1(); +#endif /* GL_VERSION_3_1 */ +#ifdef GL_VERSION_3_2 + if (glewExperimental || GLEW_VERSION_3_2) CONST_CAST(GLEW_VERSION_3_2) = !_glewInit_GL_VERSION_3_2(); +#endif /* GL_VERSION_3_2 */ +#ifdef GL_VERSION_3_3 + if (glewExperimental || GLEW_VERSION_3_3) CONST_CAST(GLEW_VERSION_3_3) = !_glewInit_GL_VERSION_3_3(); +#endif /* GL_VERSION_3_3 */ +#ifdef GL_VERSION_4_0 + if (glewExperimental || GLEW_VERSION_4_0) CONST_CAST(GLEW_VERSION_4_0) = !_glewInit_GL_VERSION_4_0(); +#endif /* GL_VERSION_4_0 */ +#ifdef GL_VERSION_4_5 + if (glewExperimental || GLEW_VERSION_4_5) CONST_CAST(GLEW_VERSION_4_5) = !_glewInit_GL_VERSION_4_5(); +#endif /* GL_VERSION_4_5 */ +#ifdef GL_VERSION_4_6 + if (glewExperimental || GLEW_VERSION_4_6) CONST_CAST(GLEW_VERSION_4_6) = !_glewInit_GL_VERSION_4_6(); +#endif /* GL_VERSION_4_6 */ +#ifdef GL_3DFX_tbuffer + if (glewExperimental || GLEW_3DFX_tbuffer) CONST_CAST(GLEW_3DFX_tbuffer) = !_glewInit_GL_3DFX_tbuffer(); +#endif /* GL_3DFX_tbuffer */ +#ifdef GL_AMD_debug_output + if (glewExperimental || GLEW_AMD_debug_output) CONST_CAST(GLEW_AMD_debug_output) = !_glewInit_GL_AMD_debug_output(); +#endif /* GL_AMD_debug_output */ +#ifdef GL_AMD_draw_buffers_blend + if (glewExperimental || GLEW_AMD_draw_buffers_blend) CONST_CAST(GLEW_AMD_draw_buffers_blend) = !_glewInit_GL_AMD_draw_buffers_blend(); +#endif /* GL_AMD_draw_buffers_blend */ +#ifdef GL_AMD_framebuffer_sample_positions + if (glewExperimental || GLEW_AMD_framebuffer_sample_positions) CONST_CAST(GLEW_AMD_framebuffer_sample_positions) = !_glewInit_GL_AMD_framebuffer_sample_positions(); +#endif /* GL_AMD_framebuffer_sample_positions */ +#ifdef GL_AMD_interleaved_elements + if (glewExperimental || GLEW_AMD_interleaved_elements) CONST_CAST(GLEW_AMD_interleaved_elements) = !_glewInit_GL_AMD_interleaved_elements(); +#endif /* GL_AMD_interleaved_elements */ +#ifdef GL_AMD_multi_draw_indirect + if (glewExperimental || GLEW_AMD_multi_draw_indirect) CONST_CAST(GLEW_AMD_multi_draw_indirect) = !_glewInit_GL_AMD_multi_draw_indirect(); +#endif /* GL_AMD_multi_draw_indirect */ +#ifdef GL_AMD_name_gen_delete + if (glewExperimental || GLEW_AMD_name_gen_delete) CONST_CAST(GLEW_AMD_name_gen_delete) = !_glewInit_GL_AMD_name_gen_delete(); +#endif /* GL_AMD_name_gen_delete */ +#ifdef GL_AMD_occlusion_query_event + if (glewExperimental || GLEW_AMD_occlusion_query_event) CONST_CAST(GLEW_AMD_occlusion_query_event) = !_glewInit_GL_AMD_occlusion_query_event(); +#endif /* GL_AMD_occlusion_query_event */ +#ifdef GL_AMD_performance_monitor + if (glewExperimental || GLEW_AMD_performance_monitor) CONST_CAST(GLEW_AMD_performance_monitor) = !_glewInit_GL_AMD_performance_monitor(); +#endif /* GL_AMD_performance_monitor */ +#ifdef GL_AMD_sample_positions + if (glewExperimental || GLEW_AMD_sample_positions) CONST_CAST(GLEW_AMD_sample_positions) = !_glewInit_GL_AMD_sample_positions(); +#endif /* GL_AMD_sample_positions */ +#ifdef GL_AMD_sparse_texture + if (glewExperimental || GLEW_AMD_sparse_texture) CONST_CAST(GLEW_AMD_sparse_texture) = !_glewInit_GL_AMD_sparse_texture(); +#endif /* GL_AMD_sparse_texture */ +#ifdef GL_AMD_stencil_operation_extended + if (glewExperimental || GLEW_AMD_stencil_operation_extended) CONST_CAST(GLEW_AMD_stencil_operation_extended) = !_glewInit_GL_AMD_stencil_operation_extended(); +#endif /* GL_AMD_stencil_operation_extended */ +#ifdef GL_AMD_vertex_shader_tessellator + if (glewExperimental || GLEW_AMD_vertex_shader_tessellator) CONST_CAST(GLEW_AMD_vertex_shader_tessellator) = !_glewInit_GL_AMD_vertex_shader_tessellator(); +#endif /* GL_AMD_vertex_shader_tessellator */ +#ifdef GL_ANGLE_framebuffer_blit + if (glewExperimental || GLEW_ANGLE_framebuffer_blit) CONST_CAST(GLEW_ANGLE_framebuffer_blit) = !_glewInit_GL_ANGLE_framebuffer_blit(); +#endif /* GL_ANGLE_framebuffer_blit */ +#ifdef GL_ANGLE_framebuffer_multisample + if (glewExperimental || GLEW_ANGLE_framebuffer_multisample) CONST_CAST(GLEW_ANGLE_framebuffer_multisample) = !_glewInit_GL_ANGLE_framebuffer_multisample(); +#endif /* GL_ANGLE_framebuffer_multisample */ +#ifdef GL_ANGLE_instanced_arrays + if (glewExperimental || GLEW_ANGLE_instanced_arrays) CONST_CAST(GLEW_ANGLE_instanced_arrays) = !_glewInit_GL_ANGLE_instanced_arrays(); +#endif /* GL_ANGLE_instanced_arrays */ +#ifdef GL_ANGLE_timer_query + if (glewExperimental || GLEW_ANGLE_timer_query) CONST_CAST(GLEW_ANGLE_timer_query) = !_glewInit_GL_ANGLE_timer_query(); +#endif /* GL_ANGLE_timer_query */ +#ifdef GL_ANGLE_translated_shader_source + if (glewExperimental || GLEW_ANGLE_translated_shader_source) CONST_CAST(GLEW_ANGLE_translated_shader_source) = !_glewInit_GL_ANGLE_translated_shader_source(); +#endif /* GL_ANGLE_translated_shader_source */ +#ifdef GL_APPLE_copy_texture_levels + if (glewExperimental || GLEW_APPLE_copy_texture_levels) CONST_CAST(GLEW_APPLE_copy_texture_levels) = !_glewInit_GL_APPLE_copy_texture_levels(); +#endif /* GL_APPLE_copy_texture_levels */ +#ifdef GL_APPLE_element_array + if (glewExperimental || GLEW_APPLE_element_array) CONST_CAST(GLEW_APPLE_element_array) = !_glewInit_GL_APPLE_element_array(); +#endif /* GL_APPLE_element_array */ +#ifdef GL_APPLE_fence + if (glewExperimental || GLEW_APPLE_fence) CONST_CAST(GLEW_APPLE_fence) = !_glewInit_GL_APPLE_fence(); +#endif /* GL_APPLE_fence */ +#ifdef GL_APPLE_flush_buffer_range + if (glewExperimental || GLEW_APPLE_flush_buffer_range) CONST_CAST(GLEW_APPLE_flush_buffer_range) = !_glewInit_GL_APPLE_flush_buffer_range(); +#endif /* GL_APPLE_flush_buffer_range */ +#ifdef GL_APPLE_framebuffer_multisample + if (glewExperimental || GLEW_APPLE_framebuffer_multisample) CONST_CAST(GLEW_APPLE_framebuffer_multisample) = !_glewInit_GL_APPLE_framebuffer_multisample(); +#endif /* GL_APPLE_framebuffer_multisample */ +#ifdef GL_APPLE_object_purgeable + if (glewExperimental || GLEW_APPLE_object_purgeable) CONST_CAST(GLEW_APPLE_object_purgeable) = !_glewInit_GL_APPLE_object_purgeable(); +#endif /* GL_APPLE_object_purgeable */ +#ifdef GL_APPLE_sync + if (glewExperimental || GLEW_APPLE_sync) CONST_CAST(GLEW_APPLE_sync) = !_glewInit_GL_APPLE_sync(); +#endif /* GL_APPLE_sync */ +#ifdef GL_APPLE_texture_range + if (glewExperimental || GLEW_APPLE_texture_range) CONST_CAST(GLEW_APPLE_texture_range) = !_glewInit_GL_APPLE_texture_range(); +#endif /* GL_APPLE_texture_range */ +#ifdef GL_APPLE_vertex_array_object + if (glewExperimental || GLEW_APPLE_vertex_array_object) CONST_CAST(GLEW_APPLE_vertex_array_object) = !_glewInit_GL_APPLE_vertex_array_object(); +#endif /* GL_APPLE_vertex_array_object */ +#ifdef GL_APPLE_vertex_array_range + if (glewExperimental || GLEW_APPLE_vertex_array_range) CONST_CAST(GLEW_APPLE_vertex_array_range) = !_glewInit_GL_APPLE_vertex_array_range(); +#endif /* GL_APPLE_vertex_array_range */ +#ifdef GL_APPLE_vertex_program_evaluators + if (glewExperimental || GLEW_APPLE_vertex_program_evaluators) CONST_CAST(GLEW_APPLE_vertex_program_evaluators) = !_glewInit_GL_APPLE_vertex_program_evaluators(); +#endif /* GL_APPLE_vertex_program_evaluators */ +#ifdef GL_ARB_ES2_compatibility + if (glewExperimental || GLEW_ARB_ES2_compatibility) CONST_CAST(GLEW_ARB_ES2_compatibility) = !_glewInit_GL_ARB_ES2_compatibility(); +#endif /* GL_ARB_ES2_compatibility */ +#ifdef GL_ARB_ES3_1_compatibility + if (glewExperimental || GLEW_ARB_ES3_1_compatibility) CONST_CAST(GLEW_ARB_ES3_1_compatibility) = !_glewInit_GL_ARB_ES3_1_compatibility(); +#endif /* GL_ARB_ES3_1_compatibility */ +#ifdef GL_ARB_ES3_2_compatibility + if (glewExperimental || GLEW_ARB_ES3_2_compatibility) CONST_CAST(GLEW_ARB_ES3_2_compatibility) = !_glewInit_GL_ARB_ES3_2_compatibility(); +#endif /* GL_ARB_ES3_2_compatibility */ +#ifdef GL_ARB_base_instance + if (glewExperimental || GLEW_ARB_base_instance) CONST_CAST(GLEW_ARB_base_instance) = !_glewInit_GL_ARB_base_instance(); +#endif /* GL_ARB_base_instance */ +#ifdef GL_ARB_bindless_texture + if (glewExperimental || GLEW_ARB_bindless_texture) CONST_CAST(GLEW_ARB_bindless_texture) = !_glewInit_GL_ARB_bindless_texture(); +#endif /* GL_ARB_bindless_texture */ +#ifdef GL_ARB_blend_func_extended + if (glewExperimental || GLEW_ARB_blend_func_extended) CONST_CAST(GLEW_ARB_blend_func_extended) = !_glewInit_GL_ARB_blend_func_extended(); +#endif /* GL_ARB_blend_func_extended */ +#ifdef GL_ARB_buffer_storage + if (glewExperimental || GLEW_ARB_buffer_storage) CONST_CAST(GLEW_ARB_buffer_storage) = !_glewInit_GL_ARB_buffer_storage(); +#endif /* GL_ARB_buffer_storage */ +#ifdef GL_ARB_cl_event + if (glewExperimental || GLEW_ARB_cl_event) CONST_CAST(GLEW_ARB_cl_event) = !_glewInit_GL_ARB_cl_event(); +#endif /* GL_ARB_cl_event */ +#ifdef GL_ARB_clear_buffer_object + if (glewExperimental || GLEW_ARB_clear_buffer_object) CONST_CAST(GLEW_ARB_clear_buffer_object) = !_glewInit_GL_ARB_clear_buffer_object(); +#endif /* GL_ARB_clear_buffer_object */ +#ifdef GL_ARB_clear_texture + if (glewExperimental || GLEW_ARB_clear_texture) CONST_CAST(GLEW_ARB_clear_texture) = !_glewInit_GL_ARB_clear_texture(); +#endif /* GL_ARB_clear_texture */ +#ifdef GL_ARB_clip_control + if (glewExperimental || GLEW_ARB_clip_control) CONST_CAST(GLEW_ARB_clip_control) = !_glewInit_GL_ARB_clip_control(); +#endif /* GL_ARB_clip_control */ +#ifdef GL_ARB_color_buffer_float + if (glewExperimental || GLEW_ARB_color_buffer_float) CONST_CAST(GLEW_ARB_color_buffer_float) = !_glewInit_GL_ARB_color_buffer_float(); +#endif /* GL_ARB_color_buffer_float */ +#ifdef GL_ARB_compute_shader + if (glewExperimental || GLEW_ARB_compute_shader) CONST_CAST(GLEW_ARB_compute_shader) = !_glewInit_GL_ARB_compute_shader(); +#endif /* GL_ARB_compute_shader */ +#ifdef GL_ARB_compute_variable_group_size + if (glewExperimental || GLEW_ARB_compute_variable_group_size) CONST_CAST(GLEW_ARB_compute_variable_group_size) = !_glewInit_GL_ARB_compute_variable_group_size(); +#endif /* GL_ARB_compute_variable_group_size */ +#ifdef GL_ARB_copy_buffer + if (glewExperimental || GLEW_ARB_copy_buffer) CONST_CAST(GLEW_ARB_copy_buffer) = !_glewInit_GL_ARB_copy_buffer(); +#endif /* GL_ARB_copy_buffer */ +#ifdef GL_ARB_copy_image + if (glewExperimental || GLEW_ARB_copy_image) CONST_CAST(GLEW_ARB_copy_image) = !_glewInit_GL_ARB_copy_image(); +#endif /* GL_ARB_copy_image */ +#ifdef GL_ARB_debug_output + if (glewExperimental || GLEW_ARB_debug_output) CONST_CAST(GLEW_ARB_debug_output) = !_glewInit_GL_ARB_debug_output(); +#endif /* GL_ARB_debug_output */ +#ifdef GL_ARB_direct_state_access + if (glewExperimental || GLEW_ARB_direct_state_access) CONST_CAST(GLEW_ARB_direct_state_access) = !_glewInit_GL_ARB_direct_state_access(); +#endif /* GL_ARB_direct_state_access */ +#ifdef GL_ARB_draw_buffers + if (glewExperimental || GLEW_ARB_draw_buffers) CONST_CAST(GLEW_ARB_draw_buffers) = !_glewInit_GL_ARB_draw_buffers(); +#endif /* GL_ARB_draw_buffers */ +#ifdef GL_ARB_draw_buffers_blend + if (glewExperimental || GLEW_ARB_draw_buffers_blend) CONST_CAST(GLEW_ARB_draw_buffers_blend) = !_glewInit_GL_ARB_draw_buffers_blend(); +#endif /* GL_ARB_draw_buffers_blend */ +#ifdef GL_ARB_draw_elements_base_vertex + if (glewExperimental || GLEW_ARB_draw_elements_base_vertex) CONST_CAST(GLEW_ARB_draw_elements_base_vertex) = !_glewInit_GL_ARB_draw_elements_base_vertex(); +#endif /* GL_ARB_draw_elements_base_vertex */ +#ifdef GL_ARB_draw_indirect + if (glewExperimental || GLEW_ARB_draw_indirect) CONST_CAST(GLEW_ARB_draw_indirect) = !_glewInit_GL_ARB_draw_indirect(); +#endif /* GL_ARB_draw_indirect */ +#ifdef GL_ARB_framebuffer_no_attachments + if (glewExperimental || GLEW_ARB_framebuffer_no_attachments) CONST_CAST(GLEW_ARB_framebuffer_no_attachments) = !_glewInit_GL_ARB_framebuffer_no_attachments(); +#endif /* GL_ARB_framebuffer_no_attachments */ +#ifdef GL_ARB_framebuffer_object + if (glewExperimental || GLEW_ARB_framebuffer_object) CONST_CAST(GLEW_ARB_framebuffer_object) = !_glewInit_GL_ARB_framebuffer_object(); +#endif /* GL_ARB_framebuffer_object */ +#ifdef GL_ARB_geometry_shader4 + if (glewExperimental || GLEW_ARB_geometry_shader4) CONST_CAST(GLEW_ARB_geometry_shader4) = !_glewInit_GL_ARB_geometry_shader4(); +#endif /* GL_ARB_geometry_shader4 */ +#ifdef GL_ARB_get_program_binary + if (glewExperimental || GLEW_ARB_get_program_binary) CONST_CAST(GLEW_ARB_get_program_binary) = !_glewInit_GL_ARB_get_program_binary(); +#endif /* GL_ARB_get_program_binary */ +#ifdef GL_ARB_get_texture_sub_image + if (glewExperimental || GLEW_ARB_get_texture_sub_image) CONST_CAST(GLEW_ARB_get_texture_sub_image) = !_glewInit_GL_ARB_get_texture_sub_image(); +#endif /* GL_ARB_get_texture_sub_image */ +#ifdef GL_ARB_gl_spirv + if (glewExperimental || GLEW_ARB_gl_spirv) CONST_CAST(GLEW_ARB_gl_spirv) = !_glewInit_GL_ARB_gl_spirv(); +#endif /* GL_ARB_gl_spirv */ +#ifdef GL_ARB_gpu_shader_fp64 + if (glewExperimental || GLEW_ARB_gpu_shader_fp64) CONST_CAST(GLEW_ARB_gpu_shader_fp64) = !_glewInit_GL_ARB_gpu_shader_fp64(); +#endif /* GL_ARB_gpu_shader_fp64 */ +#ifdef GL_ARB_gpu_shader_int64 + if (glewExperimental || GLEW_ARB_gpu_shader_int64) CONST_CAST(GLEW_ARB_gpu_shader_int64) = !_glewInit_GL_ARB_gpu_shader_int64(); +#endif /* GL_ARB_gpu_shader_int64 */ +#ifdef GL_ARB_imaging + if (glewExperimental || GLEW_ARB_imaging) CONST_CAST(GLEW_ARB_imaging) = !_glewInit_GL_ARB_imaging(); +#endif /* GL_ARB_imaging */ +#ifdef GL_ARB_indirect_parameters + if (glewExperimental || GLEW_ARB_indirect_parameters) CONST_CAST(GLEW_ARB_indirect_parameters) = !_glewInit_GL_ARB_indirect_parameters(); +#endif /* GL_ARB_indirect_parameters */ +#ifdef GL_ARB_instanced_arrays + if (glewExperimental || GLEW_ARB_instanced_arrays) CONST_CAST(GLEW_ARB_instanced_arrays) = !_glewInit_GL_ARB_instanced_arrays(); +#endif /* GL_ARB_instanced_arrays */ +#ifdef GL_ARB_internalformat_query + if (glewExperimental || GLEW_ARB_internalformat_query) CONST_CAST(GLEW_ARB_internalformat_query) = !_glewInit_GL_ARB_internalformat_query(); +#endif /* GL_ARB_internalformat_query */ +#ifdef GL_ARB_internalformat_query2 + if (glewExperimental || GLEW_ARB_internalformat_query2) CONST_CAST(GLEW_ARB_internalformat_query2) = !_glewInit_GL_ARB_internalformat_query2(); +#endif /* GL_ARB_internalformat_query2 */ +#ifdef GL_ARB_invalidate_subdata + if (glewExperimental || GLEW_ARB_invalidate_subdata) CONST_CAST(GLEW_ARB_invalidate_subdata) = !_glewInit_GL_ARB_invalidate_subdata(); +#endif /* GL_ARB_invalidate_subdata */ +#ifdef GL_ARB_map_buffer_range + if (glewExperimental || GLEW_ARB_map_buffer_range) CONST_CAST(GLEW_ARB_map_buffer_range) = !_glewInit_GL_ARB_map_buffer_range(); +#endif /* GL_ARB_map_buffer_range */ +#ifdef GL_ARB_matrix_palette + if (glewExperimental || GLEW_ARB_matrix_palette) CONST_CAST(GLEW_ARB_matrix_palette) = !_glewInit_GL_ARB_matrix_palette(); +#endif /* GL_ARB_matrix_palette */ +#ifdef GL_ARB_multi_bind + if (glewExperimental || GLEW_ARB_multi_bind) CONST_CAST(GLEW_ARB_multi_bind) = !_glewInit_GL_ARB_multi_bind(); +#endif /* GL_ARB_multi_bind */ +#ifdef GL_ARB_multi_draw_indirect + if (glewExperimental || GLEW_ARB_multi_draw_indirect) CONST_CAST(GLEW_ARB_multi_draw_indirect) = !_glewInit_GL_ARB_multi_draw_indirect(); +#endif /* GL_ARB_multi_draw_indirect */ +#ifdef GL_ARB_multisample + if (glewExperimental || GLEW_ARB_multisample) CONST_CAST(GLEW_ARB_multisample) = !_glewInit_GL_ARB_multisample(); +#endif /* GL_ARB_multisample */ +#ifdef GL_ARB_multitexture + if (glewExperimental || GLEW_ARB_multitexture) CONST_CAST(GLEW_ARB_multitexture) = !_glewInit_GL_ARB_multitexture(); +#endif /* GL_ARB_multitexture */ +#ifdef GL_ARB_occlusion_query + if (glewExperimental || GLEW_ARB_occlusion_query) CONST_CAST(GLEW_ARB_occlusion_query) = !_glewInit_GL_ARB_occlusion_query(); +#endif /* GL_ARB_occlusion_query */ +#ifdef GL_ARB_parallel_shader_compile + if (glewExperimental || GLEW_ARB_parallel_shader_compile) CONST_CAST(GLEW_ARB_parallel_shader_compile) = !_glewInit_GL_ARB_parallel_shader_compile(); +#endif /* GL_ARB_parallel_shader_compile */ +#ifdef GL_ARB_point_parameters + if (glewExperimental || GLEW_ARB_point_parameters) CONST_CAST(GLEW_ARB_point_parameters) = !_glewInit_GL_ARB_point_parameters(); +#endif /* GL_ARB_point_parameters */ +#ifdef GL_ARB_polygon_offset_clamp + if (glewExperimental || GLEW_ARB_polygon_offset_clamp) CONST_CAST(GLEW_ARB_polygon_offset_clamp) = !_glewInit_GL_ARB_polygon_offset_clamp(); +#endif /* GL_ARB_polygon_offset_clamp */ +#ifdef GL_ARB_program_interface_query + if (glewExperimental || GLEW_ARB_program_interface_query) CONST_CAST(GLEW_ARB_program_interface_query) = !_glewInit_GL_ARB_program_interface_query(); +#endif /* GL_ARB_program_interface_query */ +#ifdef GL_ARB_provoking_vertex + if (glewExperimental || GLEW_ARB_provoking_vertex) CONST_CAST(GLEW_ARB_provoking_vertex) = !_glewInit_GL_ARB_provoking_vertex(); +#endif /* GL_ARB_provoking_vertex */ +#ifdef GL_ARB_robustness + if (glewExperimental || GLEW_ARB_robustness) CONST_CAST(GLEW_ARB_robustness) = !_glewInit_GL_ARB_robustness(); +#endif /* GL_ARB_robustness */ +#ifdef GL_ARB_sample_locations + if (glewExperimental || GLEW_ARB_sample_locations) CONST_CAST(GLEW_ARB_sample_locations) = !_glewInit_GL_ARB_sample_locations(); +#endif /* GL_ARB_sample_locations */ +#ifdef GL_ARB_sample_shading + if (glewExperimental || GLEW_ARB_sample_shading) CONST_CAST(GLEW_ARB_sample_shading) = !_glewInit_GL_ARB_sample_shading(); +#endif /* GL_ARB_sample_shading */ +#ifdef GL_ARB_sampler_objects + if (glewExperimental || GLEW_ARB_sampler_objects) CONST_CAST(GLEW_ARB_sampler_objects) = !_glewInit_GL_ARB_sampler_objects(); +#endif /* GL_ARB_sampler_objects */ +#ifdef GL_ARB_separate_shader_objects + if (glewExperimental || GLEW_ARB_separate_shader_objects) CONST_CAST(GLEW_ARB_separate_shader_objects) = !_glewInit_GL_ARB_separate_shader_objects(); +#endif /* GL_ARB_separate_shader_objects */ +#ifdef GL_ARB_shader_atomic_counters + if (glewExperimental || GLEW_ARB_shader_atomic_counters) CONST_CAST(GLEW_ARB_shader_atomic_counters) = !_glewInit_GL_ARB_shader_atomic_counters(); +#endif /* GL_ARB_shader_atomic_counters */ +#ifdef GL_ARB_shader_image_load_store + if (glewExperimental || GLEW_ARB_shader_image_load_store) CONST_CAST(GLEW_ARB_shader_image_load_store) = !_glewInit_GL_ARB_shader_image_load_store(); +#endif /* GL_ARB_shader_image_load_store */ +#ifdef GL_ARB_shader_objects + if (glewExperimental || GLEW_ARB_shader_objects) CONST_CAST(GLEW_ARB_shader_objects) = !_glewInit_GL_ARB_shader_objects(); +#endif /* GL_ARB_shader_objects */ +#ifdef GL_ARB_shader_storage_buffer_object + if (glewExperimental || GLEW_ARB_shader_storage_buffer_object) CONST_CAST(GLEW_ARB_shader_storage_buffer_object) = !_glewInit_GL_ARB_shader_storage_buffer_object(); +#endif /* GL_ARB_shader_storage_buffer_object */ +#ifdef GL_ARB_shader_subroutine + if (glewExperimental || GLEW_ARB_shader_subroutine) CONST_CAST(GLEW_ARB_shader_subroutine) = !_glewInit_GL_ARB_shader_subroutine(); +#endif /* GL_ARB_shader_subroutine */ +#ifdef GL_ARB_shading_language_include + if (glewExperimental || GLEW_ARB_shading_language_include) CONST_CAST(GLEW_ARB_shading_language_include) = !_glewInit_GL_ARB_shading_language_include(); +#endif /* GL_ARB_shading_language_include */ +#ifdef GL_ARB_sparse_buffer + if (glewExperimental || GLEW_ARB_sparse_buffer) CONST_CAST(GLEW_ARB_sparse_buffer) = !_glewInit_GL_ARB_sparse_buffer(); +#endif /* GL_ARB_sparse_buffer */ +#ifdef GL_ARB_sparse_texture + if (glewExperimental || GLEW_ARB_sparse_texture) CONST_CAST(GLEW_ARB_sparse_texture) = !_glewInit_GL_ARB_sparse_texture(); +#endif /* GL_ARB_sparse_texture */ +#ifdef GL_ARB_sync + if (glewExperimental || GLEW_ARB_sync) CONST_CAST(GLEW_ARB_sync) = !_glewInit_GL_ARB_sync(); +#endif /* GL_ARB_sync */ +#ifdef GL_ARB_tessellation_shader + if (glewExperimental || GLEW_ARB_tessellation_shader) CONST_CAST(GLEW_ARB_tessellation_shader) = !_glewInit_GL_ARB_tessellation_shader(); +#endif /* GL_ARB_tessellation_shader */ +#ifdef GL_ARB_texture_barrier + if (glewExperimental || GLEW_ARB_texture_barrier) CONST_CAST(GLEW_ARB_texture_barrier) = !_glewInit_GL_ARB_texture_barrier(); +#endif /* GL_ARB_texture_barrier */ +#ifdef GL_ARB_texture_buffer_object + if (glewExperimental || GLEW_ARB_texture_buffer_object) CONST_CAST(GLEW_ARB_texture_buffer_object) = !_glewInit_GL_ARB_texture_buffer_object(); +#endif /* GL_ARB_texture_buffer_object */ +#ifdef GL_ARB_texture_buffer_range + if (glewExperimental || GLEW_ARB_texture_buffer_range) CONST_CAST(GLEW_ARB_texture_buffer_range) = !_glewInit_GL_ARB_texture_buffer_range(); +#endif /* GL_ARB_texture_buffer_range */ +#ifdef GL_ARB_texture_compression + if (glewExperimental || GLEW_ARB_texture_compression) CONST_CAST(GLEW_ARB_texture_compression) = !_glewInit_GL_ARB_texture_compression(); +#endif /* GL_ARB_texture_compression */ +#ifdef GL_ARB_texture_multisample + if (glewExperimental || GLEW_ARB_texture_multisample) CONST_CAST(GLEW_ARB_texture_multisample) = !_glewInit_GL_ARB_texture_multisample(); +#endif /* GL_ARB_texture_multisample */ +#ifdef GL_ARB_texture_storage + if (glewExperimental || GLEW_ARB_texture_storage) CONST_CAST(GLEW_ARB_texture_storage) = !_glewInit_GL_ARB_texture_storage(); +#endif /* GL_ARB_texture_storage */ +#ifdef GL_ARB_texture_storage_multisample + if (glewExperimental || GLEW_ARB_texture_storage_multisample) CONST_CAST(GLEW_ARB_texture_storage_multisample) = !_glewInit_GL_ARB_texture_storage_multisample(); +#endif /* GL_ARB_texture_storage_multisample */ +#ifdef GL_ARB_texture_view + if (glewExperimental || GLEW_ARB_texture_view) CONST_CAST(GLEW_ARB_texture_view) = !_glewInit_GL_ARB_texture_view(); +#endif /* GL_ARB_texture_view */ +#ifdef GL_ARB_timer_query + if (glewExperimental || GLEW_ARB_timer_query) CONST_CAST(GLEW_ARB_timer_query) = !_glewInit_GL_ARB_timer_query(); +#endif /* GL_ARB_timer_query */ +#ifdef GL_ARB_transform_feedback2 + if (glewExperimental || GLEW_ARB_transform_feedback2) CONST_CAST(GLEW_ARB_transform_feedback2) = !_glewInit_GL_ARB_transform_feedback2(); +#endif /* GL_ARB_transform_feedback2 */ +#ifdef GL_ARB_transform_feedback3 + if (glewExperimental || GLEW_ARB_transform_feedback3) CONST_CAST(GLEW_ARB_transform_feedback3) = !_glewInit_GL_ARB_transform_feedback3(); +#endif /* GL_ARB_transform_feedback3 */ +#ifdef GL_ARB_transform_feedback_instanced + if (glewExperimental || GLEW_ARB_transform_feedback_instanced) CONST_CAST(GLEW_ARB_transform_feedback_instanced) = !_glewInit_GL_ARB_transform_feedback_instanced(); +#endif /* GL_ARB_transform_feedback_instanced */ +#ifdef GL_ARB_transpose_matrix + if (glewExperimental || GLEW_ARB_transpose_matrix) CONST_CAST(GLEW_ARB_transpose_matrix) = !_glewInit_GL_ARB_transpose_matrix(); +#endif /* GL_ARB_transpose_matrix */ +#ifdef GL_ARB_uniform_buffer_object + if (glewExperimental || GLEW_ARB_uniform_buffer_object) CONST_CAST(GLEW_ARB_uniform_buffer_object) = !_glewInit_GL_ARB_uniform_buffer_object(); +#endif /* GL_ARB_uniform_buffer_object */ +#ifdef GL_ARB_vertex_array_object + if (glewExperimental || GLEW_ARB_vertex_array_object) CONST_CAST(GLEW_ARB_vertex_array_object) = !_glewInit_GL_ARB_vertex_array_object(); +#endif /* GL_ARB_vertex_array_object */ +#ifdef GL_ARB_vertex_attrib_64bit + if (glewExperimental || GLEW_ARB_vertex_attrib_64bit) CONST_CAST(GLEW_ARB_vertex_attrib_64bit) = !_glewInit_GL_ARB_vertex_attrib_64bit(); +#endif /* GL_ARB_vertex_attrib_64bit */ +#ifdef GL_ARB_vertex_attrib_binding + if (glewExperimental || GLEW_ARB_vertex_attrib_binding) CONST_CAST(GLEW_ARB_vertex_attrib_binding) = !_glewInit_GL_ARB_vertex_attrib_binding(); +#endif /* GL_ARB_vertex_attrib_binding */ +#ifdef GL_ARB_vertex_blend + if (glewExperimental || GLEW_ARB_vertex_blend) CONST_CAST(GLEW_ARB_vertex_blend) = !_glewInit_GL_ARB_vertex_blend(); +#endif /* GL_ARB_vertex_blend */ +#ifdef GL_ARB_vertex_buffer_object + if (glewExperimental || GLEW_ARB_vertex_buffer_object) CONST_CAST(GLEW_ARB_vertex_buffer_object) = !_glewInit_GL_ARB_vertex_buffer_object(); +#endif /* GL_ARB_vertex_buffer_object */ +#ifdef GL_ARB_vertex_program + if (glewExperimental || GLEW_ARB_vertex_program) CONST_CAST(GLEW_ARB_vertex_program) = !_glewInit_GL_ARB_vertex_program(); +#endif /* GL_ARB_vertex_program */ +#ifdef GL_ARB_vertex_shader + if (glewExperimental || GLEW_ARB_vertex_shader) { CONST_CAST(GLEW_ARB_vertex_shader) = !_glewInit_GL_ARB_vertex_shader(); _glewInit_GL_ARB_vertex_program(); } +#endif /* GL_ARB_vertex_shader */ +#ifdef GL_ARB_vertex_type_2_10_10_10_rev + if (glewExperimental || GLEW_ARB_vertex_type_2_10_10_10_rev) CONST_CAST(GLEW_ARB_vertex_type_2_10_10_10_rev) = !_glewInit_GL_ARB_vertex_type_2_10_10_10_rev(); +#endif /* GL_ARB_vertex_type_2_10_10_10_rev */ +#ifdef GL_ARB_viewport_array + if (glewExperimental || GLEW_ARB_viewport_array) CONST_CAST(GLEW_ARB_viewport_array) = !_glewInit_GL_ARB_viewport_array(); +#endif /* GL_ARB_viewport_array */ +#ifdef GL_ARB_window_pos + if (glewExperimental || GLEW_ARB_window_pos) CONST_CAST(GLEW_ARB_window_pos) = !_glewInit_GL_ARB_window_pos(); +#endif /* GL_ARB_window_pos */ +#ifdef GL_ATI_draw_buffers + if (glewExperimental || GLEW_ATI_draw_buffers) CONST_CAST(GLEW_ATI_draw_buffers) = !_glewInit_GL_ATI_draw_buffers(); +#endif /* GL_ATI_draw_buffers */ +#ifdef GL_ATI_element_array + if (glewExperimental || GLEW_ATI_element_array) CONST_CAST(GLEW_ATI_element_array) = !_glewInit_GL_ATI_element_array(); +#endif /* GL_ATI_element_array */ +#ifdef GL_ATI_envmap_bumpmap + if (glewExperimental || GLEW_ATI_envmap_bumpmap) CONST_CAST(GLEW_ATI_envmap_bumpmap) = !_glewInit_GL_ATI_envmap_bumpmap(); +#endif /* GL_ATI_envmap_bumpmap */ +#ifdef GL_ATI_fragment_shader + if (glewExperimental || GLEW_ATI_fragment_shader) CONST_CAST(GLEW_ATI_fragment_shader) = !_glewInit_GL_ATI_fragment_shader(); +#endif /* GL_ATI_fragment_shader */ +#ifdef GL_ATI_map_object_buffer + if (glewExperimental || GLEW_ATI_map_object_buffer) CONST_CAST(GLEW_ATI_map_object_buffer) = !_glewInit_GL_ATI_map_object_buffer(); +#endif /* GL_ATI_map_object_buffer */ +#ifdef GL_ATI_pn_triangles + if (glewExperimental || GLEW_ATI_pn_triangles) CONST_CAST(GLEW_ATI_pn_triangles) = !_glewInit_GL_ATI_pn_triangles(); +#endif /* GL_ATI_pn_triangles */ +#ifdef GL_ATI_separate_stencil + if (glewExperimental || GLEW_ATI_separate_stencil) CONST_CAST(GLEW_ATI_separate_stencil) = !_glewInit_GL_ATI_separate_stencil(); +#endif /* GL_ATI_separate_stencil */ +#ifdef GL_ATI_vertex_array_object + if (glewExperimental || GLEW_ATI_vertex_array_object) CONST_CAST(GLEW_ATI_vertex_array_object) = !_glewInit_GL_ATI_vertex_array_object(); +#endif /* GL_ATI_vertex_array_object */ +#ifdef GL_ATI_vertex_attrib_array_object + if (glewExperimental || GLEW_ATI_vertex_attrib_array_object) CONST_CAST(GLEW_ATI_vertex_attrib_array_object) = !_glewInit_GL_ATI_vertex_attrib_array_object(); +#endif /* GL_ATI_vertex_attrib_array_object */ +#ifdef GL_ATI_vertex_streams + if (glewExperimental || GLEW_ATI_vertex_streams) CONST_CAST(GLEW_ATI_vertex_streams) = !_glewInit_GL_ATI_vertex_streams(); +#endif /* GL_ATI_vertex_streams */ +#ifdef GL_EXT_base_instance + if (glewExperimental || GLEW_EXT_base_instance) CONST_CAST(GLEW_EXT_base_instance) = !_glewInit_GL_EXT_base_instance(); +#endif /* GL_EXT_base_instance */ +#ifdef GL_EXT_bindable_uniform + if (glewExperimental || GLEW_EXT_bindable_uniform) CONST_CAST(GLEW_EXT_bindable_uniform) = !_glewInit_GL_EXT_bindable_uniform(); +#endif /* GL_EXT_bindable_uniform */ +#ifdef GL_EXT_blend_color + if (glewExperimental || GLEW_EXT_blend_color) CONST_CAST(GLEW_EXT_blend_color) = !_glewInit_GL_EXT_blend_color(); +#endif /* GL_EXT_blend_color */ +#ifdef GL_EXT_blend_equation_separate + if (glewExperimental || GLEW_EXT_blend_equation_separate) CONST_CAST(GLEW_EXT_blend_equation_separate) = !_glewInit_GL_EXT_blend_equation_separate(); +#endif /* GL_EXT_blend_equation_separate */ +#ifdef GL_EXT_blend_func_extended + if (glewExperimental || GLEW_EXT_blend_func_extended) CONST_CAST(GLEW_EXT_blend_func_extended) = !_glewInit_GL_EXT_blend_func_extended(); +#endif /* GL_EXT_blend_func_extended */ +#ifdef GL_EXT_blend_func_separate + if (glewExperimental || GLEW_EXT_blend_func_separate) CONST_CAST(GLEW_EXT_blend_func_separate) = !_glewInit_GL_EXT_blend_func_separate(); +#endif /* GL_EXT_blend_func_separate */ +#ifdef GL_EXT_blend_minmax + if (glewExperimental || GLEW_EXT_blend_minmax) CONST_CAST(GLEW_EXT_blend_minmax) = !_glewInit_GL_EXT_blend_minmax(); +#endif /* GL_EXT_blend_minmax */ +#ifdef GL_EXT_buffer_storage + if (glewExperimental || GLEW_EXT_buffer_storage) CONST_CAST(GLEW_EXT_buffer_storage) = !_glewInit_GL_EXT_buffer_storage(); +#endif /* GL_EXT_buffer_storage */ +#ifdef GL_EXT_clear_texture + if (glewExperimental || GLEW_EXT_clear_texture) CONST_CAST(GLEW_EXT_clear_texture) = !_glewInit_GL_EXT_clear_texture(); +#endif /* GL_EXT_clear_texture */ +#ifdef GL_EXT_color_subtable + if (glewExperimental || GLEW_EXT_color_subtable) CONST_CAST(GLEW_EXT_color_subtable) = !_glewInit_GL_EXT_color_subtable(); +#endif /* GL_EXT_color_subtable */ +#ifdef GL_EXT_compiled_vertex_array + if (glewExperimental || GLEW_EXT_compiled_vertex_array) CONST_CAST(GLEW_EXT_compiled_vertex_array) = !_glewInit_GL_EXT_compiled_vertex_array(); +#endif /* GL_EXT_compiled_vertex_array */ +#ifdef GL_EXT_convolution + if (glewExperimental || GLEW_EXT_convolution) CONST_CAST(GLEW_EXT_convolution) = !_glewInit_GL_EXT_convolution(); +#endif /* GL_EXT_convolution */ +#ifdef GL_EXT_coordinate_frame + if (glewExperimental || GLEW_EXT_coordinate_frame) CONST_CAST(GLEW_EXT_coordinate_frame) = !_glewInit_GL_EXT_coordinate_frame(); +#endif /* GL_EXT_coordinate_frame */ +#ifdef GL_EXT_copy_image + if (glewExperimental || GLEW_EXT_copy_image) CONST_CAST(GLEW_EXT_copy_image) = !_glewInit_GL_EXT_copy_image(); +#endif /* GL_EXT_copy_image */ +#ifdef GL_EXT_copy_texture + if (glewExperimental || GLEW_EXT_copy_texture) CONST_CAST(GLEW_EXT_copy_texture) = !_glewInit_GL_EXT_copy_texture(); +#endif /* GL_EXT_copy_texture */ +#ifdef GL_EXT_cull_vertex + if (glewExperimental || GLEW_EXT_cull_vertex) CONST_CAST(GLEW_EXT_cull_vertex) = !_glewInit_GL_EXT_cull_vertex(); +#endif /* GL_EXT_cull_vertex */ +#ifdef GL_EXT_debug_label + if (glewExperimental || GLEW_EXT_debug_label) CONST_CAST(GLEW_EXT_debug_label) = !_glewInit_GL_EXT_debug_label(); +#endif /* GL_EXT_debug_label */ +#ifdef GL_EXT_debug_marker + if (glewExperimental || GLEW_EXT_debug_marker) CONST_CAST(GLEW_EXT_debug_marker) = !_glewInit_GL_EXT_debug_marker(); +#endif /* GL_EXT_debug_marker */ +#ifdef GL_EXT_depth_bounds_test + if (glewExperimental || GLEW_EXT_depth_bounds_test) CONST_CAST(GLEW_EXT_depth_bounds_test) = !_glewInit_GL_EXT_depth_bounds_test(); +#endif /* GL_EXT_depth_bounds_test */ +#ifdef GL_EXT_direct_state_access + if (glewExperimental || GLEW_EXT_direct_state_access) CONST_CAST(GLEW_EXT_direct_state_access) = !_glewInit_GL_EXT_direct_state_access(); +#endif /* GL_EXT_direct_state_access */ +#ifdef GL_EXT_discard_framebuffer + if (glewExperimental || GLEW_EXT_discard_framebuffer) CONST_CAST(GLEW_EXT_discard_framebuffer) = !_glewInit_GL_EXT_discard_framebuffer(); +#endif /* GL_EXT_discard_framebuffer */ +#ifdef GL_EXT_draw_buffers + if (glewExperimental || GLEW_EXT_draw_buffers) CONST_CAST(GLEW_EXT_draw_buffers) = !_glewInit_GL_EXT_draw_buffers(); +#endif /* GL_EXT_draw_buffers */ +#ifdef GL_EXT_draw_buffers2 + if (glewExperimental || GLEW_EXT_draw_buffers2) CONST_CAST(GLEW_EXT_draw_buffers2) = !_glewInit_GL_EXT_draw_buffers2(); +#endif /* GL_EXT_draw_buffers2 */ +#ifdef GL_EXT_draw_buffers_indexed + if (glewExperimental || GLEW_EXT_draw_buffers_indexed) CONST_CAST(GLEW_EXT_draw_buffers_indexed) = !_glewInit_GL_EXT_draw_buffers_indexed(); +#endif /* GL_EXT_draw_buffers_indexed */ +#ifdef GL_EXT_draw_elements_base_vertex + if (glewExperimental || GLEW_EXT_draw_elements_base_vertex) CONST_CAST(GLEW_EXT_draw_elements_base_vertex) = !_glewInit_GL_EXT_draw_elements_base_vertex(); +#endif /* GL_EXT_draw_elements_base_vertex */ +#ifdef GL_EXT_draw_instanced + if (glewExperimental || GLEW_EXT_draw_instanced) CONST_CAST(GLEW_EXT_draw_instanced) = !_glewInit_GL_EXT_draw_instanced(); +#endif /* GL_EXT_draw_instanced */ +#ifdef GL_EXT_draw_range_elements + if (glewExperimental || GLEW_EXT_draw_range_elements) CONST_CAST(GLEW_EXT_draw_range_elements) = !_glewInit_GL_EXT_draw_range_elements(); +#endif /* GL_EXT_draw_range_elements */ +#ifdef GL_EXT_external_buffer + if (glewExperimental || GLEW_EXT_external_buffer) CONST_CAST(GLEW_EXT_external_buffer) = !_glewInit_GL_EXT_external_buffer(); +#endif /* GL_EXT_external_buffer */ +#ifdef GL_EXT_fog_coord + if (glewExperimental || GLEW_EXT_fog_coord) CONST_CAST(GLEW_EXT_fog_coord) = !_glewInit_GL_EXT_fog_coord(); +#endif /* GL_EXT_fog_coord */ +#ifdef GL_EXT_fragment_lighting + if (glewExperimental || GLEW_EXT_fragment_lighting) CONST_CAST(GLEW_EXT_fragment_lighting) = !_glewInit_GL_EXT_fragment_lighting(); +#endif /* GL_EXT_fragment_lighting */ +#ifdef GL_EXT_framebuffer_blit + if (glewExperimental || GLEW_EXT_framebuffer_blit) CONST_CAST(GLEW_EXT_framebuffer_blit) = !_glewInit_GL_EXT_framebuffer_blit(); +#endif /* GL_EXT_framebuffer_blit */ +#ifdef GL_EXT_framebuffer_multisample + if (glewExperimental || GLEW_EXT_framebuffer_multisample) CONST_CAST(GLEW_EXT_framebuffer_multisample) = !_glewInit_GL_EXT_framebuffer_multisample(); +#endif /* GL_EXT_framebuffer_multisample */ +#ifdef GL_EXT_framebuffer_object + if (glewExperimental || GLEW_EXT_framebuffer_object) CONST_CAST(GLEW_EXT_framebuffer_object) = !_glewInit_GL_EXT_framebuffer_object(); +#endif /* GL_EXT_framebuffer_object */ +#ifdef GL_EXT_geometry_shader4 + if (glewExperimental || GLEW_EXT_geometry_shader4) CONST_CAST(GLEW_EXT_geometry_shader4) = !_glewInit_GL_EXT_geometry_shader4(); +#endif /* GL_EXT_geometry_shader4 */ +#ifdef GL_EXT_gpu_program_parameters + if (glewExperimental || GLEW_EXT_gpu_program_parameters) CONST_CAST(GLEW_EXT_gpu_program_parameters) = !_glewInit_GL_EXT_gpu_program_parameters(); +#endif /* GL_EXT_gpu_program_parameters */ +#ifdef GL_EXT_gpu_shader4 + if (glewExperimental || GLEW_EXT_gpu_shader4) CONST_CAST(GLEW_EXT_gpu_shader4) = !_glewInit_GL_EXT_gpu_shader4(); +#endif /* GL_EXT_gpu_shader4 */ +#ifdef GL_EXT_histogram + if (glewExperimental || GLEW_EXT_histogram) CONST_CAST(GLEW_EXT_histogram) = !_glewInit_GL_EXT_histogram(); +#endif /* GL_EXT_histogram */ +#ifdef GL_EXT_index_func + if (glewExperimental || GLEW_EXT_index_func) CONST_CAST(GLEW_EXT_index_func) = !_glewInit_GL_EXT_index_func(); +#endif /* GL_EXT_index_func */ +#ifdef GL_EXT_index_material + if (glewExperimental || GLEW_EXT_index_material) CONST_CAST(GLEW_EXT_index_material) = !_glewInit_GL_EXT_index_material(); +#endif /* GL_EXT_index_material */ +#ifdef GL_EXT_instanced_arrays + if (glewExperimental || GLEW_EXT_instanced_arrays) CONST_CAST(GLEW_EXT_instanced_arrays) = !_glewInit_GL_EXT_instanced_arrays(); +#endif /* GL_EXT_instanced_arrays */ +#ifdef GL_EXT_light_texture + if (glewExperimental || GLEW_EXT_light_texture) CONST_CAST(GLEW_EXT_light_texture) = !_glewInit_GL_EXT_light_texture(); +#endif /* GL_EXT_light_texture */ +#ifdef GL_EXT_map_buffer_range + if (glewExperimental || GLEW_EXT_map_buffer_range) CONST_CAST(GLEW_EXT_map_buffer_range) = !_glewInit_GL_EXT_map_buffer_range(); +#endif /* GL_EXT_map_buffer_range */ +#ifdef GL_EXT_memory_object + if (glewExperimental || GLEW_EXT_memory_object) CONST_CAST(GLEW_EXT_memory_object) = !_glewInit_GL_EXT_memory_object(); +#endif /* GL_EXT_memory_object */ +#ifdef GL_EXT_memory_object_fd + if (glewExperimental || GLEW_EXT_memory_object_fd) CONST_CAST(GLEW_EXT_memory_object_fd) = !_glewInit_GL_EXT_memory_object_fd(); +#endif /* GL_EXT_memory_object_fd */ +#ifdef GL_EXT_memory_object_win32 + if (glewExperimental || GLEW_EXT_memory_object_win32) CONST_CAST(GLEW_EXT_memory_object_win32) = !_glewInit_GL_EXT_memory_object_win32(); +#endif /* GL_EXT_memory_object_win32 */ +#ifdef GL_EXT_multi_draw_arrays + if (glewExperimental || GLEW_EXT_multi_draw_arrays) CONST_CAST(GLEW_EXT_multi_draw_arrays) = !_glewInit_GL_EXT_multi_draw_arrays(); +#endif /* GL_EXT_multi_draw_arrays */ +#ifdef GL_EXT_multi_draw_indirect + if (glewExperimental || GLEW_EXT_multi_draw_indirect) CONST_CAST(GLEW_EXT_multi_draw_indirect) = !_glewInit_GL_EXT_multi_draw_indirect(); +#endif /* GL_EXT_multi_draw_indirect */ +#ifdef GL_EXT_multisample + if (glewExperimental || GLEW_EXT_multisample) CONST_CAST(GLEW_EXT_multisample) = !_glewInit_GL_EXT_multisample(); +#endif /* GL_EXT_multisample */ +#ifdef GL_EXT_multisampled_render_to_texture + if (glewExperimental || GLEW_EXT_multisampled_render_to_texture) CONST_CAST(GLEW_EXT_multisampled_render_to_texture) = !_glewInit_GL_EXT_multisampled_render_to_texture(); +#endif /* GL_EXT_multisampled_render_to_texture */ +#ifdef GL_EXT_multiview_draw_buffers + if (glewExperimental || GLEW_EXT_multiview_draw_buffers) CONST_CAST(GLEW_EXT_multiview_draw_buffers) = !_glewInit_GL_EXT_multiview_draw_buffers(); +#endif /* GL_EXT_multiview_draw_buffers */ +#ifdef GL_EXT_paletted_texture + if (glewExperimental || GLEW_EXT_paletted_texture) CONST_CAST(GLEW_EXT_paletted_texture) = !_glewInit_GL_EXT_paletted_texture(); +#endif /* GL_EXT_paletted_texture */ +#ifdef GL_EXT_pixel_transform + if (glewExperimental || GLEW_EXT_pixel_transform) CONST_CAST(GLEW_EXT_pixel_transform) = !_glewInit_GL_EXT_pixel_transform(); +#endif /* GL_EXT_pixel_transform */ +#ifdef GL_EXT_point_parameters + if (glewExperimental || GLEW_EXT_point_parameters) CONST_CAST(GLEW_EXT_point_parameters) = !_glewInit_GL_EXT_point_parameters(); +#endif /* GL_EXT_point_parameters */ +#ifdef GL_EXT_polygon_offset + if (glewExperimental || GLEW_EXT_polygon_offset) CONST_CAST(GLEW_EXT_polygon_offset) = !_glewInit_GL_EXT_polygon_offset(); +#endif /* GL_EXT_polygon_offset */ +#ifdef GL_EXT_polygon_offset_clamp + if (glewExperimental || GLEW_EXT_polygon_offset_clamp) CONST_CAST(GLEW_EXT_polygon_offset_clamp) = !_glewInit_GL_EXT_polygon_offset_clamp(); +#endif /* GL_EXT_polygon_offset_clamp */ +#ifdef GL_EXT_provoking_vertex + if (glewExperimental || GLEW_EXT_provoking_vertex) CONST_CAST(GLEW_EXT_provoking_vertex) = !_glewInit_GL_EXT_provoking_vertex(); +#endif /* GL_EXT_provoking_vertex */ +#ifdef GL_EXT_raster_multisample + if (glewExperimental || GLEW_EXT_raster_multisample) CONST_CAST(GLEW_EXT_raster_multisample) = !_glewInit_GL_EXT_raster_multisample(); +#endif /* GL_EXT_raster_multisample */ +#ifdef GL_EXT_scene_marker + if (glewExperimental || GLEW_EXT_scene_marker) CONST_CAST(GLEW_EXT_scene_marker) = !_glewInit_GL_EXT_scene_marker(); +#endif /* GL_EXT_scene_marker */ +#ifdef GL_EXT_secondary_color + if (glewExperimental || GLEW_EXT_secondary_color) CONST_CAST(GLEW_EXT_secondary_color) = !_glewInit_GL_EXT_secondary_color(); +#endif /* GL_EXT_secondary_color */ +#ifdef GL_EXT_semaphore + if (glewExperimental || GLEW_EXT_semaphore) CONST_CAST(GLEW_EXT_semaphore) = !_glewInit_GL_EXT_semaphore(); +#endif /* GL_EXT_semaphore */ +#ifdef GL_EXT_semaphore_fd + if (glewExperimental || GLEW_EXT_semaphore_fd) CONST_CAST(GLEW_EXT_semaphore_fd) = !_glewInit_GL_EXT_semaphore_fd(); +#endif /* GL_EXT_semaphore_fd */ +#ifdef GL_EXT_semaphore_win32 + if (glewExperimental || GLEW_EXT_semaphore_win32) CONST_CAST(GLEW_EXT_semaphore_win32) = !_glewInit_GL_EXT_semaphore_win32(); +#endif /* GL_EXT_semaphore_win32 */ +#ifdef GL_EXT_separate_shader_objects + if (glewExperimental || GLEW_EXT_separate_shader_objects) CONST_CAST(GLEW_EXT_separate_shader_objects) = !_glewInit_GL_EXT_separate_shader_objects(); +#endif /* GL_EXT_separate_shader_objects */ +#ifdef GL_EXT_shader_image_load_store + if (glewExperimental || GLEW_EXT_shader_image_load_store) CONST_CAST(GLEW_EXT_shader_image_load_store) = !_glewInit_GL_EXT_shader_image_load_store(); +#endif /* GL_EXT_shader_image_load_store */ +#ifdef GL_EXT_shader_pixel_local_storage2 + if (glewExperimental || GLEW_EXT_shader_pixel_local_storage2) CONST_CAST(GLEW_EXT_shader_pixel_local_storage2) = !_glewInit_GL_EXT_shader_pixel_local_storage2(); +#endif /* GL_EXT_shader_pixel_local_storage2 */ +#ifdef GL_EXT_sparse_texture + if (glewExperimental || GLEW_EXT_sparse_texture) CONST_CAST(GLEW_EXT_sparse_texture) = !_glewInit_GL_EXT_sparse_texture(); +#endif /* GL_EXT_sparse_texture */ +#ifdef GL_EXT_stencil_two_side + if (glewExperimental || GLEW_EXT_stencil_two_side) CONST_CAST(GLEW_EXT_stencil_two_side) = !_glewInit_GL_EXT_stencil_two_side(); +#endif /* GL_EXT_stencil_two_side */ +#ifdef GL_EXT_subtexture + if (glewExperimental || GLEW_EXT_subtexture) CONST_CAST(GLEW_EXT_subtexture) = !_glewInit_GL_EXT_subtexture(); +#endif /* GL_EXT_subtexture */ +#ifdef GL_EXT_texture3D + if (glewExperimental || GLEW_EXT_texture3D) CONST_CAST(GLEW_EXT_texture3D) = !_glewInit_GL_EXT_texture3D(); +#endif /* GL_EXT_texture3D */ +#ifdef GL_EXT_texture_array + if (glewExperimental || GLEW_EXT_texture_array) CONST_CAST(GLEW_EXT_texture_array) = !_glewInit_GL_EXT_texture_array(); +#endif /* GL_EXT_texture_array */ +#ifdef GL_EXT_texture_buffer_object + if (glewExperimental || GLEW_EXT_texture_buffer_object) CONST_CAST(GLEW_EXT_texture_buffer_object) = !_glewInit_GL_EXT_texture_buffer_object(); +#endif /* GL_EXT_texture_buffer_object */ +#ifdef GL_EXT_texture_integer + if (glewExperimental || GLEW_EXT_texture_integer) CONST_CAST(GLEW_EXT_texture_integer) = !_glewInit_GL_EXT_texture_integer(); +#endif /* GL_EXT_texture_integer */ +#ifdef GL_EXT_texture_object + if (glewExperimental || GLEW_EXT_texture_object) CONST_CAST(GLEW_EXT_texture_object) = !_glewInit_GL_EXT_texture_object(); +#endif /* GL_EXT_texture_object */ +#ifdef GL_EXT_texture_perturb_normal + if (glewExperimental || GLEW_EXT_texture_perturb_normal) CONST_CAST(GLEW_EXT_texture_perturb_normal) = !_glewInit_GL_EXT_texture_perturb_normal(); +#endif /* GL_EXT_texture_perturb_normal */ +#ifdef GL_EXT_texture_storage + if (glewExperimental || GLEW_EXT_texture_storage) CONST_CAST(GLEW_EXT_texture_storage) = !_glewInit_GL_EXT_texture_storage(); +#endif /* GL_EXT_texture_storage */ +#ifdef GL_EXT_texture_view + if (glewExperimental || GLEW_EXT_texture_view) CONST_CAST(GLEW_EXT_texture_view) = !_glewInit_GL_EXT_texture_view(); +#endif /* GL_EXT_texture_view */ +#ifdef GL_EXT_timer_query + if (glewExperimental || GLEW_EXT_timer_query) CONST_CAST(GLEW_EXT_timer_query) = !_glewInit_GL_EXT_timer_query(); +#endif /* GL_EXT_timer_query */ +#ifdef GL_EXT_transform_feedback + if (glewExperimental || GLEW_EXT_transform_feedback) CONST_CAST(GLEW_EXT_transform_feedback) = !_glewInit_GL_EXT_transform_feedback(); +#endif /* GL_EXT_transform_feedback */ +#ifdef GL_EXT_vertex_array + if (glewExperimental || GLEW_EXT_vertex_array) CONST_CAST(GLEW_EXT_vertex_array) = !_glewInit_GL_EXT_vertex_array(); +#endif /* GL_EXT_vertex_array */ +#ifdef GL_EXT_vertex_array_setXXX + if (glewExperimental || GLEW_EXT_vertex_array_setXXX) CONST_CAST(GLEW_EXT_vertex_array_setXXX) = !_glewInit_GL_EXT_vertex_array_setXXX(); +#endif /* GL_EXT_vertex_array_setXXX */ +#ifdef GL_EXT_vertex_attrib_64bit + if (glewExperimental || GLEW_EXT_vertex_attrib_64bit) CONST_CAST(GLEW_EXT_vertex_attrib_64bit) = !_glewInit_GL_EXT_vertex_attrib_64bit(); +#endif /* GL_EXT_vertex_attrib_64bit */ +#ifdef GL_EXT_vertex_shader + if (glewExperimental || GLEW_EXT_vertex_shader) CONST_CAST(GLEW_EXT_vertex_shader) = !_glewInit_GL_EXT_vertex_shader(); +#endif /* GL_EXT_vertex_shader */ +#ifdef GL_EXT_vertex_weighting + if (glewExperimental || GLEW_EXT_vertex_weighting) CONST_CAST(GLEW_EXT_vertex_weighting) = !_glewInit_GL_EXT_vertex_weighting(); +#endif /* GL_EXT_vertex_weighting */ +#ifdef GL_EXT_win32_keyed_mutex + if (glewExperimental || GLEW_EXT_win32_keyed_mutex) CONST_CAST(GLEW_EXT_win32_keyed_mutex) = !_glewInit_GL_EXT_win32_keyed_mutex(); +#endif /* GL_EXT_win32_keyed_mutex */ +#ifdef GL_EXT_window_rectangles + if (glewExperimental || GLEW_EXT_window_rectangles) CONST_CAST(GLEW_EXT_window_rectangles) = !_glewInit_GL_EXT_window_rectangles(); +#endif /* GL_EXT_window_rectangles */ +#ifdef GL_EXT_x11_sync_object + if (glewExperimental || GLEW_EXT_x11_sync_object) CONST_CAST(GLEW_EXT_x11_sync_object) = !_glewInit_GL_EXT_x11_sync_object(); +#endif /* GL_EXT_x11_sync_object */ +#ifdef GL_GREMEDY_frame_terminator + if (glewExperimental || GLEW_GREMEDY_frame_terminator) CONST_CAST(GLEW_GREMEDY_frame_terminator) = !_glewInit_GL_GREMEDY_frame_terminator(); +#endif /* GL_GREMEDY_frame_terminator */ +#ifdef GL_GREMEDY_string_marker + if (glewExperimental || GLEW_GREMEDY_string_marker) CONST_CAST(GLEW_GREMEDY_string_marker) = !_glewInit_GL_GREMEDY_string_marker(); +#endif /* GL_GREMEDY_string_marker */ +#ifdef GL_HP_image_transform + if (glewExperimental || GLEW_HP_image_transform) CONST_CAST(GLEW_HP_image_transform) = !_glewInit_GL_HP_image_transform(); +#endif /* GL_HP_image_transform */ +#ifdef GL_IBM_multimode_draw_arrays + if (glewExperimental || GLEW_IBM_multimode_draw_arrays) CONST_CAST(GLEW_IBM_multimode_draw_arrays) = !_glewInit_GL_IBM_multimode_draw_arrays(); +#endif /* GL_IBM_multimode_draw_arrays */ +#ifdef GL_IBM_vertex_array_lists + if (glewExperimental || GLEW_IBM_vertex_array_lists) CONST_CAST(GLEW_IBM_vertex_array_lists) = !_glewInit_GL_IBM_vertex_array_lists(); +#endif /* GL_IBM_vertex_array_lists */ +#ifdef GL_INTEL_map_texture + if (glewExperimental || GLEW_INTEL_map_texture) CONST_CAST(GLEW_INTEL_map_texture) = !_glewInit_GL_INTEL_map_texture(); +#endif /* GL_INTEL_map_texture */ +#ifdef GL_INTEL_parallel_arrays + if (glewExperimental || GLEW_INTEL_parallel_arrays) CONST_CAST(GLEW_INTEL_parallel_arrays) = !_glewInit_GL_INTEL_parallel_arrays(); +#endif /* GL_INTEL_parallel_arrays */ +#ifdef GL_INTEL_performance_query + if (glewExperimental || GLEW_INTEL_performance_query) CONST_CAST(GLEW_INTEL_performance_query) = !_glewInit_GL_INTEL_performance_query(); +#endif /* GL_INTEL_performance_query */ +#ifdef GL_INTEL_texture_scissor + if (glewExperimental || GLEW_INTEL_texture_scissor) CONST_CAST(GLEW_INTEL_texture_scissor) = !_glewInit_GL_INTEL_texture_scissor(); +#endif /* GL_INTEL_texture_scissor */ +#ifdef GL_KHR_blend_equation_advanced + if (glewExperimental || GLEW_KHR_blend_equation_advanced) CONST_CAST(GLEW_KHR_blend_equation_advanced) = !_glewInit_GL_KHR_blend_equation_advanced(); +#endif /* GL_KHR_blend_equation_advanced */ +#ifdef GL_KHR_debug + if (glewExperimental || GLEW_KHR_debug) CONST_CAST(GLEW_KHR_debug) = !_glewInit_GL_KHR_debug(); +#endif /* GL_KHR_debug */ +#ifdef GL_KHR_parallel_shader_compile + if (glewExperimental || GLEW_KHR_parallel_shader_compile) CONST_CAST(GLEW_KHR_parallel_shader_compile) = !_glewInit_GL_KHR_parallel_shader_compile(); +#endif /* GL_KHR_parallel_shader_compile */ +#ifdef GL_KHR_robustness + if (glewExperimental || GLEW_KHR_robustness) CONST_CAST(GLEW_KHR_robustness) = !_glewInit_GL_KHR_robustness(); +#endif /* GL_KHR_robustness */ +#ifdef GL_KTX_buffer_region + if (glewExperimental || GLEW_KTX_buffer_region) CONST_CAST(GLEW_KTX_buffer_region) = !_glewInit_GL_KTX_buffer_region(); +#endif /* GL_KTX_buffer_region */ +#ifdef GL_MESA_resize_buffers + if (glewExperimental || GLEW_MESA_resize_buffers) CONST_CAST(GLEW_MESA_resize_buffers) = !_glewInit_GL_MESA_resize_buffers(); +#endif /* GL_MESA_resize_buffers */ +#ifdef GL_MESA_window_pos + if (glewExperimental || GLEW_MESA_window_pos) CONST_CAST(GLEW_MESA_window_pos) = !_glewInit_GL_MESA_window_pos(); +#endif /* GL_MESA_window_pos */ +#ifdef GL_NVX_conditional_render + if (glewExperimental || GLEW_NVX_conditional_render) CONST_CAST(GLEW_NVX_conditional_render) = !_glewInit_GL_NVX_conditional_render(); +#endif /* GL_NVX_conditional_render */ +#ifdef GL_NVX_linked_gpu_multicast + if (glewExperimental || GLEW_NVX_linked_gpu_multicast) CONST_CAST(GLEW_NVX_linked_gpu_multicast) = !_glewInit_GL_NVX_linked_gpu_multicast(); +#endif /* GL_NVX_linked_gpu_multicast */ +#ifdef GL_NV_3dvision_settings + if (glewExperimental || GLEW_NV_3dvision_settings) CONST_CAST(GLEW_NV_3dvision_settings) = !_glewInit_GL_NV_3dvision_settings(); +#endif /* GL_NV_3dvision_settings */ +#ifdef GL_NV_bindless_multi_draw_indirect + if (glewExperimental || GLEW_NV_bindless_multi_draw_indirect) CONST_CAST(GLEW_NV_bindless_multi_draw_indirect) = !_glewInit_GL_NV_bindless_multi_draw_indirect(); +#endif /* GL_NV_bindless_multi_draw_indirect */ +#ifdef GL_NV_bindless_multi_draw_indirect_count + if (glewExperimental || GLEW_NV_bindless_multi_draw_indirect_count) CONST_CAST(GLEW_NV_bindless_multi_draw_indirect_count) = !_glewInit_GL_NV_bindless_multi_draw_indirect_count(); +#endif /* GL_NV_bindless_multi_draw_indirect_count */ +#ifdef GL_NV_bindless_texture + if (glewExperimental || GLEW_NV_bindless_texture) CONST_CAST(GLEW_NV_bindless_texture) = !_glewInit_GL_NV_bindless_texture(); +#endif /* GL_NV_bindless_texture */ +#ifdef GL_NV_blend_equation_advanced + if (glewExperimental || GLEW_NV_blend_equation_advanced) CONST_CAST(GLEW_NV_blend_equation_advanced) = !_glewInit_GL_NV_blend_equation_advanced(); +#endif /* GL_NV_blend_equation_advanced */ +#ifdef GL_NV_clip_space_w_scaling + if (glewExperimental || GLEW_NV_clip_space_w_scaling) CONST_CAST(GLEW_NV_clip_space_w_scaling) = !_glewInit_GL_NV_clip_space_w_scaling(); +#endif /* GL_NV_clip_space_w_scaling */ +#ifdef GL_NV_command_list + if (glewExperimental || GLEW_NV_command_list) CONST_CAST(GLEW_NV_command_list) = !_glewInit_GL_NV_command_list(); +#endif /* GL_NV_command_list */ +#ifdef GL_NV_conditional_render + if (glewExperimental || GLEW_NV_conditional_render) CONST_CAST(GLEW_NV_conditional_render) = !_glewInit_GL_NV_conditional_render(); +#endif /* GL_NV_conditional_render */ +#ifdef GL_NV_conservative_raster + if (glewExperimental || GLEW_NV_conservative_raster) CONST_CAST(GLEW_NV_conservative_raster) = !_glewInit_GL_NV_conservative_raster(); +#endif /* GL_NV_conservative_raster */ +#ifdef GL_NV_conservative_raster_dilate + if (glewExperimental || GLEW_NV_conservative_raster_dilate) CONST_CAST(GLEW_NV_conservative_raster_dilate) = !_glewInit_GL_NV_conservative_raster_dilate(); +#endif /* GL_NV_conservative_raster_dilate */ +#ifdef GL_NV_conservative_raster_pre_snap_triangles + if (glewExperimental || GLEW_NV_conservative_raster_pre_snap_triangles) CONST_CAST(GLEW_NV_conservative_raster_pre_snap_triangles) = !_glewInit_GL_NV_conservative_raster_pre_snap_triangles(); +#endif /* GL_NV_conservative_raster_pre_snap_triangles */ +#ifdef GL_NV_copy_buffer + if (glewExperimental || GLEW_NV_copy_buffer) CONST_CAST(GLEW_NV_copy_buffer) = !_glewInit_GL_NV_copy_buffer(); +#endif /* GL_NV_copy_buffer */ +#ifdef GL_NV_copy_image + if (glewExperimental || GLEW_NV_copy_image) CONST_CAST(GLEW_NV_copy_image) = !_glewInit_GL_NV_copy_image(); +#endif /* GL_NV_copy_image */ +#ifdef GL_NV_depth_buffer_float + if (glewExperimental || GLEW_NV_depth_buffer_float) CONST_CAST(GLEW_NV_depth_buffer_float) = !_glewInit_GL_NV_depth_buffer_float(); +#endif /* GL_NV_depth_buffer_float */ +#ifdef GL_NV_draw_buffers + if (glewExperimental || GLEW_NV_draw_buffers) CONST_CAST(GLEW_NV_draw_buffers) = !_glewInit_GL_NV_draw_buffers(); +#endif /* GL_NV_draw_buffers */ +#ifdef GL_NV_draw_instanced + if (glewExperimental || GLEW_NV_draw_instanced) CONST_CAST(GLEW_NV_draw_instanced) = !_glewInit_GL_NV_draw_instanced(); +#endif /* GL_NV_draw_instanced */ +#ifdef GL_NV_draw_texture + if (glewExperimental || GLEW_NV_draw_texture) CONST_CAST(GLEW_NV_draw_texture) = !_glewInit_GL_NV_draw_texture(); +#endif /* GL_NV_draw_texture */ +#ifdef GL_NV_draw_vulkan_image + if (glewExperimental || GLEW_NV_draw_vulkan_image) CONST_CAST(GLEW_NV_draw_vulkan_image) = !_glewInit_GL_NV_draw_vulkan_image(); +#endif /* GL_NV_draw_vulkan_image */ +#ifdef GL_NV_evaluators + if (glewExperimental || GLEW_NV_evaluators) CONST_CAST(GLEW_NV_evaluators) = !_glewInit_GL_NV_evaluators(); +#endif /* GL_NV_evaluators */ +#ifdef GL_NV_explicit_multisample + if (glewExperimental || GLEW_NV_explicit_multisample) CONST_CAST(GLEW_NV_explicit_multisample) = !_glewInit_GL_NV_explicit_multisample(); +#endif /* GL_NV_explicit_multisample */ +#ifdef GL_NV_fence + if (glewExperimental || GLEW_NV_fence) CONST_CAST(GLEW_NV_fence) = !_glewInit_GL_NV_fence(); +#endif /* GL_NV_fence */ +#ifdef GL_NV_fragment_coverage_to_color + if (glewExperimental || GLEW_NV_fragment_coverage_to_color) CONST_CAST(GLEW_NV_fragment_coverage_to_color) = !_glewInit_GL_NV_fragment_coverage_to_color(); +#endif /* GL_NV_fragment_coverage_to_color */ +#ifdef GL_NV_fragment_program + if (glewExperimental || GLEW_NV_fragment_program) CONST_CAST(GLEW_NV_fragment_program) = !_glewInit_GL_NV_fragment_program(); +#endif /* GL_NV_fragment_program */ +#ifdef GL_NV_framebuffer_blit + if (glewExperimental || GLEW_NV_framebuffer_blit) CONST_CAST(GLEW_NV_framebuffer_blit) = !_glewInit_GL_NV_framebuffer_blit(); +#endif /* GL_NV_framebuffer_blit */ +#ifdef GL_NV_framebuffer_multisample + if (glewExperimental || GLEW_NV_framebuffer_multisample) CONST_CAST(GLEW_NV_framebuffer_multisample) = !_glewInit_GL_NV_framebuffer_multisample(); +#endif /* GL_NV_framebuffer_multisample */ +#ifdef GL_NV_framebuffer_multisample_coverage + if (glewExperimental || GLEW_NV_framebuffer_multisample_coverage) CONST_CAST(GLEW_NV_framebuffer_multisample_coverage) = !_glewInit_GL_NV_framebuffer_multisample_coverage(); +#endif /* GL_NV_framebuffer_multisample_coverage */ +#ifdef GL_NV_geometry_program4 + if (glewExperimental || GLEW_NV_geometry_program4) CONST_CAST(GLEW_NV_geometry_program4) = !_glewInit_GL_NV_geometry_program4(); +#endif /* GL_NV_geometry_program4 */ +#ifdef GL_NV_gpu_multicast + if (glewExperimental || GLEW_NV_gpu_multicast) CONST_CAST(GLEW_NV_gpu_multicast) = !_glewInit_GL_NV_gpu_multicast(); +#endif /* GL_NV_gpu_multicast */ +#ifdef GL_NV_gpu_program4 + if (glewExperimental || GLEW_NV_gpu_program4) CONST_CAST(GLEW_NV_gpu_program4) = !_glewInit_GL_NV_gpu_program4(); +#endif /* GL_NV_gpu_program4 */ +#ifdef GL_NV_gpu_shader5 + if (glewExperimental || GLEW_NV_gpu_shader5) CONST_CAST(GLEW_NV_gpu_shader5) = !_glewInit_GL_NV_gpu_shader5(); +#endif /* GL_NV_gpu_shader5 */ +#ifdef GL_NV_half_float + if (glewExperimental || GLEW_NV_half_float) CONST_CAST(GLEW_NV_half_float) = !_glewInit_GL_NV_half_float(); +#endif /* GL_NV_half_float */ +#ifdef GL_NV_instanced_arrays + if (glewExperimental || GLEW_NV_instanced_arrays) CONST_CAST(GLEW_NV_instanced_arrays) = !_glewInit_GL_NV_instanced_arrays(); +#endif /* GL_NV_instanced_arrays */ +#ifdef GL_NV_internalformat_sample_query + if (glewExperimental || GLEW_NV_internalformat_sample_query) CONST_CAST(GLEW_NV_internalformat_sample_query) = !_glewInit_GL_NV_internalformat_sample_query(); +#endif /* GL_NV_internalformat_sample_query */ +#ifdef GL_NV_non_square_matrices + if (glewExperimental || GLEW_NV_non_square_matrices) CONST_CAST(GLEW_NV_non_square_matrices) = !_glewInit_GL_NV_non_square_matrices(); +#endif /* GL_NV_non_square_matrices */ +#ifdef GL_NV_occlusion_query + if (glewExperimental || GLEW_NV_occlusion_query) CONST_CAST(GLEW_NV_occlusion_query) = !_glewInit_GL_NV_occlusion_query(); +#endif /* GL_NV_occlusion_query */ +#ifdef GL_NV_parameter_buffer_object + if (glewExperimental || GLEW_NV_parameter_buffer_object) CONST_CAST(GLEW_NV_parameter_buffer_object) = !_glewInit_GL_NV_parameter_buffer_object(); +#endif /* GL_NV_parameter_buffer_object */ +#ifdef GL_NV_path_rendering + if (glewExperimental || GLEW_NV_path_rendering) CONST_CAST(GLEW_NV_path_rendering) = !_glewInit_GL_NV_path_rendering(); +#endif /* GL_NV_path_rendering */ +#ifdef GL_NV_pixel_data_range + if (glewExperimental || GLEW_NV_pixel_data_range) CONST_CAST(GLEW_NV_pixel_data_range) = !_glewInit_GL_NV_pixel_data_range(); +#endif /* GL_NV_pixel_data_range */ +#ifdef GL_NV_point_sprite + if (glewExperimental || GLEW_NV_point_sprite) CONST_CAST(GLEW_NV_point_sprite) = !_glewInit_GL_NV_point_sprite(); +#endif /* GL_NV_point_sprite */ +#ifdef GL_NV_polygon_mode + if (glewExperimental || GLEW_NV_polygon_mode) CONST_CAST(GLEW_NV_polygon_mode) = !_glewInit_GL_NV_polygon_mode(); +#endif /* GL_NV_polygon_mode */ +#ifdef GL_NV_present_video + if (glewExperimental || GLEW_NV_present_video) CONST_CAST(GLEW_NV_present_video) = !_glewInit_GL_NV_present_video(); +#endif /* GL_NV_present_video */ +#ifdef GL_NV_primitive_restart + if (glewExperimental || GLEW_NV_primitive_restart) CONST_CAST(GLEW_NV_primitive_restart) = !_glewInit_GL_NV_primitive_restart(); +#endif /* GL_NV_primitive_restart */ +#ifdef GL_NV_register_combiners + if (glewExperimental || GLEW_NV_register_combiners) CONST_CAST(GLEW_NV_register_combiners) = !_glewInit_GL_NV_register_combiners(); +#endif /* GL_NV_register_combiners */ +#ifdef GL_NV_register_combiners2 + if (glewExperimental || GLEW_NV_register_combiners2) CONST_CAST(GLEW_NV_register_combiners2) = !_glewInit_GL_NV_register_combiners2(); +#endif /* GL_NV_register_combiners2 */ +#ifdef GL_NV_sample_locations + if (glewExperimental || GLEW_NV_sample_locations) CONST_CAST(GLEW_NV_sample_locations) = !_glewInit_GL_NV_sample_locations(); +#endif /* GL_NV_sample_locations */ +#ifdef GL_NV_shader_buffer_load + if (glewExperimental || GLEW_NV_shader_buffer_load) CONST_CAST(GLEW_NV_shader_buffer_load) = !_glewInit_GL_NV_shader_buffer_load(); +#endif /* GL_NV_shader_buffer_load */ +#ifdef GL_NV_texture_array + if (glewExperimental || GLEW_NV_texture_array) CONST_CAST(GLEW_NV_texture_array) = !_glewInit_GL_NV_texture_array(); +#endif /* GL_NV_texture_array */ +#ifdef GL_NV_texture_barrier + if (glewExperimental || GLEW_NV_texture_barrier) CONST_CAST(GLEW_NV_texture_barrier) = !_glewInit_GL_NV_texture_barrier(); +#endif /* GL_NV_texture_barrier */ +#ifdef GL_NV_texture_multisample + if (glewExperimental || GLEW_NV_texture_multisample) CONST_CAST(GLEW_NV_texture_multisample) = !_glewInit_GL_NV_texture_multisample(); +#endif /* GL_NV_texture_multisample */ +#ifdef GL_NV_transform_feedback + if (glewExperimental || GLEW_NV_transform_feedback) CONST_CAST(GLEW_NV_transform_feedback) = !_glewInit_GL_NV_transform_feedback(); +#endif /* GL_NV_transform_feedback */ +#ifdef GL_NV_transform_feedback2 + if (glewExperimental || GLEW_NV_transform_feedback2) CONST_CAST(GLEW_NV_transform_feedback2) = !_glewInit_GL_NV_transform_feedback2(); +#endif /* GL_NV_transform_feedback2 */ +#ifdef GL_NV_vdpau_interop + if (glewExperimental || GLEW_NV_vdpau_interop) CONST_CAST(GLEW_NV_vdpau_interop) = !_glewInit_GL_NV_vdpau_interop(); +#endif /* GL_NV_vdpau_interop */ +#ifdef GL_NV_vertex_array_range + if (glewExperimental || GLEW_NV_vertex_array_range) CONST_CAST(GLEW_NV_vertex_array_range) = !_glewInit_GL_NV_vertex_array_range(); +#endif /* GL_NV_vertex_array_range */ +#ifdef GL_NV_vertex_attrib_integer_64bit + if (glewExperimental || GLEW_NV_vertex_attrib_integer_64bit) CONST_CAST(GLEW_NV_vertex_attrib_integer_64bit) = !_glewInit_GL_NV_vertex_attrib_integer_64bit(); +#endif /* GL_NV_vertex_attrib_integer_64bit */ +#ifdef GL_NV_vertex_buffer_unified_memory + if (glewExperimental || GLEW_NV_vertex_buffer_unified_memory) CONST_CAST(GLEW_NV_vertex_buffer_unified_memory) = !_glewInit_GL_NV_vertex_buffer_unified_memory(); +#endif /* GL_NV_vertex_buffer_unified_memory */ +#ifdef GL_NV_vertex_program + if (glewExperimental || GLEW_NV_vertex_program) CONST_CAST(GLEW_NV_vertex_program) = !_glewInit_GL_NV_vertex_program(); +#endif /* GL_NV_vertex_program */ +#ifdef GL_NV_video_capture + if (glewExperimental || GLEW_NV_video_capture) CONST_CAST(GLEW_NV_video_capture) = !_glewInit_GL_NV_video_capture(); +#endif /* GL_NV_video_capture */ +#ifdef GL_NV_viewport_array + if (glewExperimental || GLEW_NV_viewport_array) CONST_CAST(GLEW_NV_viewport_array) = !_glewInit_GL_NV_viewport_array(); +#endif /* GL_NV_viewport_array */ +#ifdef GL_NV_viewport_swizzle + if (glewExperimental || GLEW_NV_viewport_swizzle) CONST_CAST(GLEW_NV_viewport_swizzle) = !_glewInit_GL_NV_viewport_swizzle(); +#endif /* GL_NV_viewport_swizzle */ +#ifdef GL_OVR_multiview + if (glewExperimental || GLEW_OVR_multiview) CONST_CAST(GLEW_OVR_multiview) = !_glewInit_GL_OVR_multiview(); +#endif /* GL_OVR_multiview */ +#ifdef GL_OVR_multiview_multisampled_render_to_texture + if (glewExperimental || GLEW_OVR_multiview_multisampled_render_to_texture) CONST_CAST(GLEW_OVR_multiview_multisampled_render_to_texture) = !_glewInit_GL_OVR_multiview_multisampled_render_to_texture(); +#endif /* GL_OVR_multiview_multisampled_render_to_texture */ +#ifdef GL_QCOM_alpha_test + if (glewExperimental || GLEW_QCOM_alpha_test) CONST_CAST(GLEW_QCOM_alpha_test) = !_glewInit_GL_QCOM_alpha_test(); +#endif /* GL_QCOM_alpha_test */ +#ifdef GL_QCOM_driver_control + if (glewExperimental || GLEW_QCOM_driver_control) CONST_CAST(GLEW_QCOM_driver_control) = !_glewInit_GL_QCOM_driver_control(); +#endif /* GL_QCOM_driver_control */ +#ifdef GL_QCOM_extended_get + if (glewExperimental || GLEW_QCOM_extended_get) CONST_CAST(GLEW_QCOM_extended_get) = !_glewInit_GL_QCOM_extended_get(); +#endif /* GL_QCOM_extended_get */ +#ifdef GL_QCOM_extended_get2 + if (glewExperimental || GLEW_QCOM_extended_get2) CONST_CAST(GLEW_QCOM_extended_get2) = !_glewInit_GL_QCOM_extended_get2(); +#endif /* GL_QCOM_extended_get2 */ +#ifdef GL_QCOM_framebuffer_foveated + if (glewExperimental || GLEW_QCOM_framebuffer_foveated) CONST_CAST(GLEW_QCOM_framebuffer_foveated) = !_glewInit_GL_QCOM_framebuffer_foveated(); +#endif /* GL_QCOM_framebuffer_foveated */ +#ifdef GL_QCOM_shader_framebuffer_fetch_noncoherent + if (glewExperimental || GLEW_QCOM_shader_framebuffer_fetch_noncoherent) CONST_CAST(GLEW_QCOM_shader_framebuffer_fetch_noncoherent) = !_glewInit_GL_QCOM_shader_framebuffer_fetch_noncoherent(); +#endif /* GL_QCOM_shader_framebuffer_fetch_noncoherent */ +#ifdef GL_QCOM_tiled_rendering + if (glewExperimental || GLEW_QCOM_tiled_rendering) CONST_CAST(GLEW_QCOM_tiled_rendering) = !_glewInit_GL_QCOM_tiled_rendering(); +#endif /* GL_QCOM_tiled_rendering */ +#ifdef GL_REGAL_ES1_0_compatibility + if (glewExperimental || GLEW_REGAL_ES1_0_compatibility) CONST_CAST(GLEW_REGAL_ES1_0_compatibility) = !_glewInit_GL_REGAL_ES1_0_compatibility(); +#endif /* GL_REGAL_ES1_0_compatibility */ +#ifdef GL_REGAL_ES1_1_compatibility + if (glewExperimental || GLEW_REGAL_ES1_1_compatibility) CONST_CAST(GLEW_REGAL_ES1_1_compatibility) = !_glewInit_GL_REGAL_ES1_1_compatibility(); +#endif /* GL_REGAL_ES1_1_compatibility */ +#ifdef GL_REGAL_error_string + if (glewExperimental || GLEW_REGAL_error_string) CONST_CAST(GLEW_REGAL_error_string) = !_glewInit_GL_REGAL_error_string(); +#endif /* GL_REGAL_error_string */ +#ifdef GL_REGAL_extension_query + if (glewExperimental || GLEW_REGAL_extension_query) CONST_CAST(GLEW_REGAL_extension_query) = !_glewInit_GL_REGAL_extension_query(); +#endif /* GL_REGAL_extension_query */ +#ifdef GL_REGAL_log + if (glewExperimental || GLEW_REGAL_log) CONST_CAST(GLEW_REGAL_log) = !_glewInit_GL_REGAL_log(); +#endif /* GL_REGAL_log */ +#ifdef GL_REGAL_proc_address + if (glewExperimental || GLEW_REGAL_proc_address) CONST_CAST(GLEW_REGAL_proc_address) = !_glewInit_GL_REGAL_proc_address(); +#endif /* GL_REGAL_proc_address */ +#ifdef GL_SGIS_detail_texture + if (glewExperimental || GLEW_SGIS_detail_texture) CONST_CAST(GLEW_SGIS_detail_texture) = !_glewInit_GL_SGIS_detail_texture(); +#endif /* GL_SGIS_detail_texture */ +#ifdef GL_SGIS_fog_function + if (glewExperimental || GLEW_SGIS_fog_function) CONST_CAST(GLEW_SGIS_fog_function) = !_glewInit_GL_SGIS_fog_function(); +#endif /* GL_SGIS_fog_function */ +#ifdef GL_SGIS_multisample + if (glewExperimental || GLEW_SGIS_multisample) CONST_CAST(GLEW_SGIS_multisample) = !_glewInit_GL_SGIS_multisample(); +#endif /* GL_SGIS_multisample */ +#ifdef GL_SGIS_multitexture + if (glewExperimental || GLEW_SGIS_multitexture) CONST_CAST(GLEW_SGIS_multitexture) = !_glewInit_GL_SGIS_multitexture(); +#endif /* GL_SGIS_multitexture */ +#ifdef GL_SGIS_shared_multisample + if (glewExperimental || GLEW_SGIS_shared_multisample) CONST_CAST(GLEW_SGIS_shared_multisample) = !_glewInit_GL_SGIS_shared_multisample(); +#endif /* GL_SGIS_shared_multisample */ +#ifdef GL_SGIS_sharpen_texture + if (glewExperimental || GLEW_SGIS_sharpen_texture) CONST_CAST(GLEW_SGIS_sharpen_texture) = !_glewInit_GL_SGIS_sharpen_texture(); +#endif /* GL_SGIS_sharpen_texture */ +#ifdef GL_SGIS_texture4D + if (glewExperimental || GLEW_SGIS_texture4D) CONST_CAST(GLEW_SGIS_texture4D) = !_glewInit_GL_SGIS_texture4D(); +#endif /* GL_SGIS_texture4D */ +#ifdef GL_SGIS_texture_filter4 + if (glewExperimental || GLEW_SGIS_texture_filter4) CONST_CAST(GLEW_SGIS_texture_filter4) = !_glewInit_GL_SGIS_texture_filter4(); +#endif /* GL_SGIS_texture_filter4 */ +#ifdef GL_SGIX_async + if (glewExperimental || GLEW_SGIX_async) CONST_CAST(GLEW_SGIX_async) = !_glewInit_GL_SGIX_async(); +#endif /* GL_SGIX_async */ +#ifdef GL_SGIX_datapipe + if (glewExperimental || GLEW_SGIX_datapipe) CONST_CAST(GLEW_SGIX_datapipe) = !_glewInit_GL_SGIX_datapipe(); +#endif /* GL_SGIX_datapipe */ +#ifdef GL_SGIX_flush_raster + if (glewExperimental || GLEW_SGIX_flush_raster) CONST_CAST(GLEW_SGIX_flush_raster) = !_glewInit_GL_SGIX_flush_raster(); +#endif /* GL_SGIX_flush_raster */ +#ifdef GL_SGIX_fog_layers + if (glewExperimental || GLEW_SGIX_fog_layers) CONST_CAST(GLEW_SGIX_fog_layers) = !_glewInit_GL_SGIX_fog_layers(); +#endif /* GL_SGIX_fog_layers */ +#ifdef GL_SGIX_fog_texture + if (glewExperimental || GLEW_SGIX_fog_texture) CONST_CAST(GLEW_SGIX_fog_texture) = !_glewInit_GL_SGIX_fog_texture(); +#endif /* GL_SGIX_fog_texture */ +#ifdef GL_SGIX_fragment_specular_lighting + if (glewExperimental || GLEW_SGIX_fragment_specular_lighting) CONST_CAST(GLEW_SGIX_fragment_specular_lighting) = !_glewInit_GL_SGIX_fragment_specular_lighting(); +#endif /* GL_SGIX_fragment_specular_lighting */ +#ifdef GL_SGIX_framezoom + if (glewExperimental || GLEW_SGIX_framezoom) CONST_CAST(GLEW_SGIX_framezoom) = !_glewInit_GL_SGIX_framezoom(); +#endif /* GL_SGIX_framezoom */ +#ifdef GL_SGIX_igloo_interface + if (glewExperimental || GLEW_SGIX_igloo_interface) CONST_CAST(GLEW_SGIX_igloo_interface) = !_glewInit_GL_SGIX_igloo_interface(); +#endif /* GL_SGIX_igloo_interface */ +#ifdef GL_SGIX_mpeg1 + if (glewExperimental || GLEW_SGIX_mpeg1) CONST_CAST(GLEW_SGIX_mpeg1) = !_glewInit_GL_SGIX_mpeg1(); +#endif /* GL_SGIX_mpeg1 */ +#ifdef GL_SGIX_nonlinear_lighting_pervertex + if (glewExperimental || GLEW_SGIX_nonlinear_lighting_pervertex) CONST_CAST(GLEW_SGIX_nonlinear_lighting_pervertex) = !_glewInit_GL_SGIX_nonlinear_lighting_pervertex(); +#endif /* GL_SGIX_nonlinear_lighting_pervertex */ +#ifdef GL_SGIX_pixel_texture + if (glewExperimental || GLEW_SGIX_pixel_texture) CONST_CAST(GLEW_SGIX_pixel_texture) = !_glewInit_GL_SGIX_pixel_texture(); +#endif /* GL_SGIX_pixel_texture */ +#ifdef GL_SGIX_polynomial_ffd + if (glewExperimental || GLEW_SGIX_polynomial_ffd) CONST_CAST(GLEW_SGIX_polynomial_ffd) = !_glewInit_GL_SGIX_polynomial_ffd(); +#endif /* GL_SGIX_polynomial_ffd */ +#ifdef GL_SGIX_quad_mesh + if (glewExperimental || GLEW_SGIX_quad_mesh) CONST_CAST(GLEW_SGIX_quad_mesh) = !_glewInit_GL_SGIX_quad_mesh(); +#endif /* GL_SGIX_quad_mesh */ +#ifdef GL_SGIX_reference_plane + if (glewExperimental || GLEW_SGIX_reference_plane) CONST_CAST(GLEW_SGIX_reference_plane) = !_glewInit_GL_SGIX_reference_plane(); +#endif /* GL_SGIX_reference_plane */ +#ifdef GL_SGIX_sprite + if (glewExperimental || GLEW_SGIX_sprite) CONST_CAST(GLEW_SGIX_sprite) = !_glewInit_GL_SGIX_sprite(); +#endif /* GL_SGIX_sprite */ +#ifdef GL_SGIX_tag_sample_buffer + if (glewExperimental || GLEW_SGIX_tag_sample_buffer) CONST_CAST(GLEW_SGIX_tag_sample_buffer) = !_glewInit_GL_SGIX_tag_sample_buffer(); +#endif /* GL_SGIX_tag_sample_buffer */ +#ifdef GL_SGIX_vector_ops + if (glewExperimental || GLEW_SGIX_vector_ops) CONST_CAST(GLEW_SGIX_vector_ops) = !_glewInit_GL_SGIX_vector_ops(); +#endif /* GL_SGIX_vector_ops */ +#ifdef GL_SGIX_vertex_array_object + if (glewExperimental || GLEW_SGIX_vertex_array_object) CONST_CAST(GLEW_SGIX_vertex_array_object) = !_glewInit_GL_SGIX_vertex_array_object(); +#endif /* GL_SGIX_vertex_array_object */ +#ifdef GL_SGI_color_table + if (glewExperimental || GLEW_SGI_color_table) CONST_CAST(GLEW_SGI_color_table) = !_glewInit_GL_SGI_color_table(); +#endif /* GL_SGI_color_table */ +#ifdef GL_SGI_fft + if (glewExperimental || GLEW_SGI_fft) CONST_CAST(GLEW_SGI_fft) = !_glewInit_GL_SGI_fft(); +#endif /* GL_SGI_fft */ +#ifdef GL_SUNX_constant_data + if (glewExperimental || GLEW_SUNX_constant_data) CONST_CAST(GLEW_SUNX_constant_data) = !_glewInit_GL_SUNX_constant_data(); +#endif /* GL_SUNX_constant_data */ +#ifdef GL_SUN_global_alpha + if (glewExperimental || GLEW_SUN_global_alpha) CONST_CAST(GLEW_SUN_global_alpha) = !_glewInit_GL_SUN_global_alpha(); +#endif /* GL_SUN_global_alpha */ +#ifdef GL_SUN_read_video_pixels + if (glewExperimental || GLEW_SUN_read_video_pixels) CONST_CAST(GLEW_SUN_read_video_pixels) = !_glewInit_GL_SUN_read_video_pixels(); +#endif /* GL_SUN_read_video_pixels */ +#ifdef GL_SUN_triangle_list + if (glewExperimental || GLEW_SUN_triangle_list) CONST_CAST(GLEW_SUN_triangle_list) = !_glewInit_GL_SUN_triangle_list(); +#endif /* GL_SUN_triangle_list */ +#ifdef GL_SUN_vertex + if (glewExperimental || GLEW_SUN_vertex) CONST_CAST(GLEW_SUN_vertex) = !_glewInit_GL_SUN_vertex(); +#endif /* GL_SUN_vertex */ +#ifdef GL_WIN_swap_hint + if (glewExperimental || GLEW_WIN_swap_hint) CONST_CAST(GLEW_WIN_swap_hint) = !_glewInit_GL_WIN_swap_hint(); +#endif /* GL_WIN_swap_hint */ +#ifdef GL_NV_fragment_program4 + CONST_CAST(GLEW_NV_fragment_program4) = GLEW_NV_gpu_program4; +#endif /* GL_NV_fragment_program4 */ +#ifdef GL_NV_geometry_program4 + CONST_CAST(GLEW_NV_geometry_program4) = GLEW_NV_gpu_program4; +#endif /* GL_NV_geometry_program4 */ +#ifdef GL_NV_tessellation_program5 + CONST_CAST(GLEW_NV_tessellation_program5) = GLEW_NV_gpu_program5; +#endif /* GL_NV_tessellation_program5 */ +#ifdef GL_NV_vertex_program4 + CONST_CAST(GLEW_NV_vertex_program4) = GLEW_NV_gpu_program4; +#endif /* GL_NV_vertex_program4 */ + + return GLEW_OK; +} + +/* ------------------------------------------------------------------------ */ + +const GLubyte * GLEWAPIENTRY glewGetErrorString (GLenum error) +{ + static const GLubyte* _glewErrorString[] = + { + (const GLubyte*)"No error", + (const GLubyte*)"Missing GL version", + (const GLubyte*)"GL 1.1 and up are not supported", + (const GLubyte*)"GLX 1.2 and up are not supported", + (const GLubyte*)"Unknown error" + }; + const size_t max_error = sizeof(_glewErrorString)/sizeof(*_glewErrorString) - 1; + return _glewErrorString[(size_t)error > max_error ? max_error : (size_t)error]; +} + +const GLubyte * GLEWAPIENTRY glewGetString (GLenum name) +{ + static const GLubyte* _glewString[] = + { + (const GLubyte*)NULL, + (const GLubyte*)"2.1.0", + (const GLubyte*)"2", + (const GLubyte*)"1", + (const GLubyte*)"0" + }; + const size_t max_string = sizeof(_glewString)/sizeof(*_glewString) - 1; + return _glewString[(size_t)name > max_string ? 0 : (size_t)name]; +} + +/* ------------------------------------------------------------------------ */ + +GLboolean glewExperimental = GL_FALSE; + +GLenum GLEWAPIENTRY glewInit (void) +{ + return glewContextInit(); +} + +GLboolean GLEWAPIENTRY glewIsSupported (const char* name) +{ + const GLubyte* pos = (const GLubyte*)name; + GLuint len = _glewStrLen(pos); + GLboolean ret = GL_TRUE; + while (ret && len > 0) + { + if (_glewStrSame1(&pos, &len, (const GLubyte*)"GL_", 3)) + { + if (_glewStrSame2(&pos, &len, (const GLubyte*)"VERSION_", 8)) + { +#ifdef GL_VERSION_1_2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"1_2", 3)) + { + ret = GLEW_VERSION_1_2; + continue; + } +#endif +#ifdef GL_VERSION_1_2_1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"1_2_1", 5)) + { + ret = GLEW_VERSION_1_2_1; + continue; + } +#endif +#ifdef GL_VERSION_1_3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"1_3", 3)) + { + ret = GLEW_VERSION_1_3; + continue; + } +#endif +#ifdef GL_VERSION_1_4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"1_4", 3)) + { + ret = GLEW_VERSION_1_4; + continue; + } +#endif +#ifdef GL_VERSION_1_5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"1_5", 3)) + { + ret = GLEW_VERSION_1_5; + continue; + } +#endif +#ifdef GL_VERSION_2_0 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"2_0", 3)) + { + ret = GLEW_VERSION_2_0; + continue; + } +#endif +#ifdef GL_VERSION_2_1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"2_1", 3)) + { + ret = GLEW_VERSION_2_1; + continue; + } +#endif +#ifdef GL_VERSION_3_0 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"3_0", 3)) + { + ret = GLEW_VERSION_3_0; + continue; + } +#endif +#ifdef GL_VERSION_3_1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"3_1", 3)) + { + ret = GLEW_VERSION_3_1; + continue; + } +#endif +#ifdef GL_VERSION_3_2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"3_2", 3)) + { + ret = GLEW_VERSION_3_2; + continue; + } +#endif +#ifdef GL_VERSION_3_3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"3_3", 3)) + { + ret = GLEW_VERSION_3_3; + continue; + } +#endif +#ifdef GL_VERSION_4_0 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_0", 3)) + { + ret = GLEW_VERSION_4_0; + continue; + } +#endif +#ifdef GL_VERSION_4_1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_1", 3)) + { + ret = GLEW_VERSION_4_1; + continue; + } +#endif +#ifdef GL_VERSION_4_2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_2", 3)) + { + ret = GLEW_VERSION_4_2; + continue; + } +#endif +#ifdef GL_VERSION_4_3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_3", 3)) + { + ret = GLEW_VERSION_4_3; + continue; + } +#endif +#ifdef GL_VERSION_4_4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_4", 3)) + { + ret = GLEW_VERSION_4_4; + continue; + } +#endif +#ifdef GL_VERSION_4_5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_5", 3)) + { + ret = GLEW_VERSION_4_5; + continue; + } +#endif +#ifdef GL_VERSION_4_6 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_6", 3)) + { + ret = GLEW_VERSION_4_6; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"3DFX_", 5)) + { +#ifdef GL_3DFX_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisample", 11)) + { + ret = GLEW_3DFX_multisample; + continue; + } +#endif +#ifdef GL_3DFX_tbuffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"tbuffer", 7)) + { + ret = GLEW_3DFX_tbuffer; + continue; + } +#endif +#ifdef GL_3DFX_texture_compression_FXT1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_FXT1", 24)) + { + ret = GLEW_3DFX_texture_compression_FXT1; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"AMD_", 4)) + { +#ifdef GL_AMD_blend_minmax_factor + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_minmax_factor", 19)) + { + ret = GLEW_AMD_blend_minmax_factor; + continue; + } +#endif +#ifdef GL_AMD_compressed_3DC_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compressed_3DC_texture", 22)) + { + ret = GLEW_AMD_compressed_3DC_texture; + continue; + } +#endif +#ifdef GL_AMD_compressed_ATC_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compressed_ATC_texture", 22)) + { + ret = GLEW_AMD_compressed_ATC_texture; + continue; + } +#endif +#ifdef GL_AMD_conservative_depth + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_depth", 18)) + { + ret = GLEW_AMD_conservative_depth; + continue; + } +#endif +#ifdef GL_AMD_debug_output + if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug_output", 12)) + { + ret = GLEW_AMD_debug_output; + continue; + } +#endif +#ifdef GL_AMD_depth_clamp_separate + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_clamp_separate", 20)) + { + ret = GLEW_AMD_depth_clamp_separate; + continue; + } +#endif +#ifdef GL_AMD_draw_buffers_blend + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers_blend", 18)) + { + ret = GLEW_AMD_draw_buffers_blend; + continue; + } +#endif +#ifdef GL_AMD_framebuffer_sample_positions + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_sample_positions", 28)) + { + ret = GLEW_AMD_framebuffer_sample_positions; + continue; + } +#endif +#ifdef GL_AMD_gcn_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gcn_shader", 10)) + { + ret = GLEW_AMD_gcn_shader; + continue; + } +#endif +#ifdef GL_AMD_gpu_shader_half_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader_half_float", 21)) + { + ret = GLEW_AMD_gpu_shader_half_float; + continue; + } +#endif +#ifdef GL_AMD_gpu_shader_int16 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader_int16", 16)) + { + ret = GLEW_AMD_gpu_shader_int16; + continue; + } +#endif +#ifdef GL_AMD_gpu_shader_int64 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader_int64", 16)) + { + ret = GLEW_AMD_gpu_shader_int64; + continue; + } +#endif +#ifdef GL_AMD_interleaved_elements + if (_glewStrSame3(&pos, &len, (const GLubyte*)"interleaved_elements", 20)) + { + ret = GLEW_AMD_interleaved_elements; + continue; + } +#endif +#ifdef GL_AMD_multi_draw_indirect + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_draw_indirect", 19)) + { + ret = GLEW_AMD_multi_draw_indirect; + continue; + } +#endif +#ifdef GL_AMD_name_gen_delete + if (_glewStrSame3(&pos, &len, (const GLubyte*)"name_gen_delete", 15)) + { + ret = GLEW_AMD_name_gen_delete; + continue; + } +#endif +#ifdef GL_AMD_occlusion_query_event + if (_glewStrSame3(&pos, &len, (const GLubyte*)"occlusion_query_event", 21)) + { + ret = GLEW_AMD_occlusion_query_event; + continue; + } +#endif +#ifdef GL_AMD_performance_monitor + if (_glewStrSame3(&pos, &len, (const GLubyte*)"performance_monitor", 19)) + { + ret = GLEW_AMD_performance_monitor; + continue; + } +#endif +#ifdef GL_AMD_pinned_memory + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pinned_memory", 13)) + { + ret = GLEW_AMD_pinned_memory; + continue; + } +#endif +#ifdef GL_AMD_program_binary_Z400 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"program_binary_Z400", 19)) + { + ret = GLEW_AMD_program_binary_Z400; + continue; + } +#endif +#ifdef GL_AMD_query_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"query_buffer_object", 19)) + { + ret = GLEW_AMD_query_buffer_object; + continue; + } +#endif +#ifdef GL_AMD_sample_positions + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_positions", 16)) + { + ret = GLEW_AMD_sample_positions; + continue; + } +#endif +#ifdef GL_AMD_seamless_cubemap_per_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"seamless_cubemap_per_texture", 28)) + { + ret = GLEW_AMD_seamless_cubemap_per_texture; + continue; + } +#endif +#ifdef GL_AMD_shader_atomic_counter_ops + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counter_ops", 25)) + { + ret = GLEW_AMD_shader_atomic_counter_ops; + continue; + } +#endif +#ifdef GL_AMD_shader_ballot + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_ballot", 13)) + { + ret = GLEW_AMD_shader_ballot; + continue; + } +#endif +#ifdef GL_AMD_shader_explicit_vertex_parameter + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_explicit_vertex_parameter", 32)) + { + ret = GLEW_AMD_shader_explicit_vertex_parameter; + continue; + } +#endif +#ifdef GL_AMD_shader_stencil_export + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_stencil_export", 21)) + { + ret = GLEW_AMD_shader_stencil_export; + continue; + } +#endif +#ifdef GL_AMD_shader_stencil_value_export + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_stencil_value_export", 27)) + { + ret = GLEW_AMD_shader_stencil_value_export; + continue; + } +#endif +#ifdef GL_AMD_shader_trinary_minmax + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_trinary_minmax", 21)) + { + ret = GLEW_AMD_shader_trinary_minmax; + continue; + } +#endif +#ifdef GL_AMD_sparse_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture", 14)) + { + ret = GLEW_AMD_sparse_texture; + continue; + } +#endif +#ifdef GL_AMD_stencil_operation_extended + if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_operation_extended", 26)) + { + ret = GLEW_AMD_stencil_operation_extended; + continue; + } +#endif +#ifdef GL_AMD_texture_gather_bias_lod + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_gather_bias_lod", 23)) + { + ret = GLEW_AMD_texture_gather_bias_lod; + continue; + } +#endif +#ifdef GL_AMD_texture_texture4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_texture4", 16)) + { + ret = GLEW_AMD_texture_texture4; + continue; + } +#endif +#ifdef GL_AMD_transform_feedback3_lines_triangles + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback3_lines_triangles", 35)) + { + ret = GLEW_AMD_transform_feedback3_lines_triangles; + continue; + } +#endif +#ifdef GL_AMD_transform_feedback4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback4", 19)) + { + ret = GLEW_AMD_transform_feedback4; + continue; + } +#endif +#ifdef GL_AMD_vertex_shader_layer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_shader_layer", 19)) + { + ret = GLEW_AMD_vertex_shader_layer; + continue; + } +#endif +#ifdef GL_AMD_vertex_shader_tessellator + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_shader_tessellator", 25)) + { + ret = GLEW_AMD_vertex_shader_tessellator; + continue; + } +#endif +#ifdef GL_AMD_vertex_shader_viewport_index + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_shader_viewport_index", 28)) + { + ret = GLEW_AMD_vertex_shader_viewport_index; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"ANDROID_", 8)) + { +#ifdef GL_ANDROID_extension_pack_es31a + if (_glewStrSame3(&pos, &len, (const GLubyte*)"extension_pack_es31a", 20)) + { + ret = GLEW_ANDROID_extension_pack_es31a; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"ANGLE_", 6)) + { +#ifdef GL_ANGLE_depth_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_texture", 13)) + { + ret = GLEW_ANGLE_depth_texture; + continue; + } +#endif +#ifdef GL_ANGLE_framebuffer_blit + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_blit", 16)) + { + ret = GLEW_ANGLE_framebuffer_blit; + continue; + } +#endif +#ifdef GL_ANGLE_framebuffer_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample", 23)) + { + ret = GLEW_ANGLE_framebuffer_multisample; + continue; + } +#endif +#ifdef GL_ANGLE_instanced_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"instanced_arrays", 16)) + { + ret = GLEW_ANGLE_instanced_arrays; + continue; + } +#endif +#ifdef GL_ANGLE_pack_reverse_row_order + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pack_reverse_row_order", 22)) + { + ret = GLEW_ANGLE_pack_reverse_row_order; + continue; + } +#endif +#ifdef GL_ANGLE_program_binary + if (_glewStrSame3(&pos, &len, (const GLubyte*)"program_binary", 14)) + { + ret = GLEW_ANGLE_program_binary; + continue; + } +#endif +#ifdef GL_ANGLE_texture_compression_dxt1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_dxt1", 24)) + { + ret = GLEW_ANGLE_texture_compression_dxt1; + continue; + } +#endif +#ifdef GL_ANGLE_texture_compression_dxt3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_dxt3", 24)) + { + ret = GLEW_ANGLE_texture_compression_dxt3; + continue; + } +#endif +#ifdef GL_ANGLE_texture_compression_dxt5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_dxt5", 24)) + { + ret = GLEW_ANGLE_texture_compression_dxt5; + continue; + } +#endif +#ifdef GL_ANGLE_texture_usage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_usage", 13)) + { + ret = GLEW_ANGLE_texture_usage; + continue; + } +#endif +#ifdef GL_ANGLE_timer_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"timer_query", 11)) + { + ret = GLEW_ANGLE_timer_query; + continue; + } +#endif +#ifdef GL_ANGLE_translated_shader_source + if (_glewStrSame3(&pos, &len, (const GLubyte*)"translated_shader_source", 24)) + { + ret = GLEW_ANGLE_translated_shader_source; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"APPLE_", 6)) + { +#ifdef GL_APPLE_aux_depth_stencil + if (_glewStrSame3(&pos, &len, (const GLubyte*)"aux_depth_stencil", 17)) + { + ret = GLEW_APPLE_aux_depth_stencil; + continue; + } +#endif +#ifdef GL_APPLE_client_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"client_storage", 14)) + { + ret = GLEW_APPLE_client_storage; + continue; + } +#endif +#ifdef GL_APPLE_clip_distance + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clip_distance", 13)) + { + ret = GLEW_APPLE_clip_distance; + continue; + } +#endif +#ifdef GL_APPLE_color_buffer_packed_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_buffer_packed_float", 25)) + { + ret = GLEW_APPLE_color_buffer_packed_float; + continue; + } +#endif +#ifdef GL_APPLE_copy_texture_levels + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_texture_levels", 19)) + { + ret = GLEW_APPLE_copy_texture_levels; + continue; + } +#endif +#ifdef GL_APPLE_element_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"element_array", 13)) + { + ret = GLEW_APPLE_element_array; + continue; + } +#endif +#ifdef GL_APPLE_fence + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fence", 5)) + { + ret = GLEW_APPLE_fence; + continue; + } +#endif +#ifdef GL_APPLE_float_pixels + if (_glewStrSame3(&pos, &len, (const GLubyte*)"float_pixels", 12)) + { + ret = GLEW_APPLE_float_pixels; + continue; + } +#endif +#ifdef GL_APPLE_flush_buffer_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"flush_buffer_range", 18)) + { + ret = GLEW_APPLE_flush_buffer_range; + continue; + } +#endif +#ifdef GL_APPLE_framebuffer_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample", 23)) + { + ret = GLEW_APPLE_framebuffer_multisample; + continue; + } +#endif +#ifdef GL_APPLE_object_purgeable + if (_glewStrSame3(&pos, &len, (const GLubyte*)"object_purgeable", 16)) + { + ret = GLEW_APPLE_object_purgeable; + continue; + } +#endif +#ifdef GL_APPLE_pixel_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_buffer", 12)) + { + ret = GLEW_APPLE_pixel_buffer; + continue; + } +#endif +#ifdef GL_APPLE_rgb_422 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"rgb_422", 7)) + { + ret = GLEW_APPLE_rgb_422; + continue; + } +#endif +#ifdef GL_APPLE_row_bytes + if (_glewStrSame3(&pos, &len, (const GLubyte*)"row_bytes", 9)) + { + ret = GLEW_APPLE_row_bytes; + continue; + } +#endif +#ifdef GL_APPLE_specular_vector + if (_glewStrSame3(&pos, &len, (const GLubyte*)"specular_vector", 15)) + { + ret = GLEW_APPLE_specular_vector; + continue; + } +#endif +#ifdef GL_APPLE_sync + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sync", 4)) + { + ret = GLEW_APPLE_sync; + continue; + } +#endif +#ifdef GL_APPLE_texture_2D_limited_npot + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_2D_limited_npot", 23)) + { + ret = GLEW_APPLE_texture_2D_limited_npot; + continue; + } +#endif +#ifdef GL_APPLE_texture_format_BGRA8888 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_format_BGRA8888", 23)) + { + ret = GLEW_APPLE_texture_format_BGRA8888; + continue; + } +#endif +#ifdef GL_APPLE_texture_max_level + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_max_level", 17)) + { + ret = GLEW_APPLE_texture_max_level; + continue; + } +#endif +#ifdef GL_APPLE_texture_packed_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_packed_float", 20)) + { + ret = GLEW_APPLE_texture_packed_float; + continue; + } +#endif +#ifdef GL_APPLE_texture_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_range", 13)) + { + ret = GLEW_APPLE_texture_range; + continue; + } +#endif +#ifdef GL_APPLE_transform_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_hint", 14)) + { + ret = GLEW_APPLE_transform_hint; + continue; + } +#endif +#ifdef GL_APPLE_vertex_array_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_object", 19)) + { + ret = GLEW_APPLE_vertex_array_object; + continue; + } +#endif +#ifdef GL_APPLE_vertex_array_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_range", 18)) + { + ret = GLEW_APPLE_vertex_array_range; + continue; + } +#endif +#ifdef GL_APPLE_vertex_program_evaluators + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program_evaluators", 25)) + { + ret = GLEW_APPLE_vertex_program_evaluators; + continue; + } +#endif +#ifdef GL_APPLE_ycbcr_422 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ycbcr_422", 9)) + { + ret = GLEW_APPLE_ycbcr_422; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"ARB_", 4)) + { +#ifdef GL_ARB_ES2_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES2_compatibility", 17)) + { + ret = GLEW_ARB_ES2_compatibility; + continue; + } +#endif +#ifdef GL_ARB_ES3_1_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES3_1_compatibility", 19)) + { + ret = GLEW_ARB_ES3_1_compatibility; + continue; + } +#endif +#ifdef GL_ARB_ES3_2_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES3_2_compatibility", 19)) + { + ret = GLEW_ARB_ES3_2_compatibility; + continue; + } +#endif +#ifdef GL_ARB_ES3_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES3_compatibility", 17)) + { + ret = GLEW_ARB_ES3_compatibility; + continue; + } +#endif +#ifdef GL_ARB_arrays_of_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"arrays_of_arrays", 16)) + { + ret = GLEW_ARB_arrays_of_arrays; + continue; + } +#endif +#ifdef GL_ARB_base_instance + if (_glewStrSame3(&pos, &len, (const GLubyte*)"base_instance", 13)) + { + ret = GLEW_ARB_base_instance; + continue; + } +#endif +#ifdef GL_ARB_bindless_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_texture", 16)) + { + ret = GLEW_ARB_bindless_texture; + continue; + } +#endif +#ifdef GL_ARB_blend_func_extended + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_func_extended", 19)) + { + ret = GLEW_ARB_blend_func_extended; + continue; + } +#endif +#ifdef GL_ARB_buffer_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"buffer_storage", 14)) + { + ret = GLEW_ARB_buffer_storage; + continue; + } +#endif +#ifdef GL_ARB_cl_event + if (_glewStrSame3(&pos, &len, (const GLubyte*)"cl_event", 8)) + { + ret = GLEW_ARB_cl_event; + continue; + } +#endif +#ifdef GL_ARB_clear_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clear_buffer_object", 19)) + { + ret = GLEW_ARB_clear_buffer_object; + continue; + } +#endif +#ifdef GL_ARB_clear_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clear_texture", 13)) + { + ret = GLEW_ARB_clear_texture; + continue; + } +#endif +#ifdef GL_ARB_clip_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clip_control", 12)) + { + ret = GLEW_ARB_clip_control; + continue; + } +#endif +#ifdef GL_ARB_color_buffer_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_buffer_float", 18)) + { + ret = GLEW_ARB_color_buffer_float; + continue; + } +#endif +#ifdef GL_ARB_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compatibility", 13)) + { + ret = GLEW_ARB_compatibility; + continue; + } +#endif +#ifdef GL_ARB_compressed_texture_pixel_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compressed_texture_pixel_storage", 32)) + { + ret = GLEW_ARB_compressed_texture_pixel_storage; + continue; + } +#endif +#ifdef GL_ARB_compute_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compute_shader", 14)) + { + ret = GLEW_ARB_compute_shader; + continue; + } +#endif +#ifdef GL_ARB_compute_variable_group_size + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compute_variable_group_size", 27)) + { + ret = GLEW_ARB_compute_variable_group_size; + continue; + } +#endif +#ifdef GL_ARB_conditional_render_inverted + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conditional_render_inverted", 27)) + { + ret = GLEW_ARB_conditional_render_inverted; + continue; + } +#endif +#ifdef GL_ARB_conservative_depth + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_depth", 18)) + { + ret = GLEW_ARB_conservative_depth; + continue; + } +#endif +#ifdef GL_ARB_copy_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_buffer", 11)) + { + ret = GLEW_ARB_copy_buffer; + continue; + } +#endif +#ifdef GL_ARB_copy_image + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_image", 10)) + { + ret = GLEW_ARB_copy_image; + continue; + } +#endif +#ifdef GL_ARB_cull_distance + if (_glewStrSame3(&pos, &len, (const GLubyte*)"cull_distance", 13)) + { + ret = GLEW_ARB_cull_distance; + continue; + } +#endif +#ifdef GL_ARB_debug_output + if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug_output", 12)) + { + ret = GLEW_ARB_debug_output; + continue; + } +#endif +#ifdef GL_ARB_depth_buffer_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_buffer_float", 18)) + { + ret = GLEW_ARB_depth_buffer_float; + continue; + } +#endif +#ifdef GL_ARB_depth_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_clamp", 11)) + { + ret = GLEW_ARB_depth_clamp; + continue; + } +#endif +#ifdef GL_ARB_depth_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_texture", 13)) + { + ret = GLEW_ARB_depth_texture; + continue; + } +#endif +#ifdef GL_ARB_derivative_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"derivative_control", 18)) + { + ret = GLEW_ARB_derivative_control; + continue; + } +#endif +#ifdef GL_ARB_direct_state_access + if (_glewStrSame3(&pos, &len, (const GLubyte*)"direct_state_access", 19)) + { + ret = GLEW_ARB_direct_state_access; + continue; + } +#endif +#ifdef GL_ARB_draw_buffers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers", 12)) + { + ret = GLEW_ARB_draw_buffers; + continue; + } +#endif +#ifdef GL_ARB_draw_buffers_blend + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers_blend", 18)) + { + ret = GLEW_ARB_draw_buffers_blend; + continue; + } +#endif +#ifdef GL_ARB_draw_elements_base_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_elements_base_vertex", 25)) + { + ret = GLEW_ARB_draw_elements_base_vertex; + continue; + } +#endif +#ifdef GL_ARB_draw_indirect + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_indirect", 13)) + { + ret = GLEW_ARB_draw_indirect; + continue; + } +#endif +#ifdef GL_ARB_draw_instanced + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_instanced", 14)) + { + ret = GLEW_ARB_draw_instanced; + continue; + } +#endif +#ifdef GL_ARB_enhanced_layouts + if (_glewStrSame3(&pos, &len, (const GLubyte*)"enhanced_layouts", 16)) + { + ret = GLEW_ARB_enhanced_layouts; + continue; + } +#endif +#ifdef GL_ARB_explicit_attrib_location + if (_glewStrSame3(&pos, &len, (const GLubyte*)"explicit_attrib_location", 24)) + { + ret = GLEW_ARB_explicit_attrib_location; + continue; + } +#endif +#ifdef GL_ARB_explicit_uniform_location + if (_glewStrSame3(&pos, &len, (const GLubyte*)"explicit_uniform_location", 25)) + { + ret = GLEW_ARB_explicit_uniform_location; + continue; + } +#endif +#ifdef GL_ARB_fragment_coord_conventions + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_coord_conventions", 26)) + { + ret = GLEW_ARB_fragment_coord_conventions; + continue; + } +#endif +#ifdef GL_ARB_fragment_layer_viewport + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_layer_viewport", 23)) + { + ret = GLEW_ARB_fragment_layer_viewport; + continue; + } +#endif +#ifdef GL_ARB_fragment_program + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_program", 16)) + { + ret = GLEW_ARB_fragment_program; + continue; + } +#endif +#ifdef GL_ARB_fragment_program_shadow + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_program_shadow", 23)) + { + ret = GLEW_ARB_fragment_program_shadow; + continue; + } +#endif +#ifdef GL_ARB_fragment_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader", 15)) + { + ret = GLEW_ARB_fragment_shader; + continue; + } +#endif +#ifdef GL_ARB_fragment_shader_interlock + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader_interlock", 25)) + { + ret = GLEW_ARB_fragment_shader_interlock; + continue; + } +#endif +#ifdef GL_ARB_framebuffer_no_attachments + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_no_attachments", 26)) + { + ret = GLEW_ARB_framebuffer_no_attachments; + continue; + } +#endif +#ifdef GL_ARB_framebuffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_object", 18)) + { + ret = GLEW_ARB_framebuffer_object; + continue; + } +#endif +#ifdef GL_ARB_framebuffer_sRGB + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_sRGB", 16)) + { + ret = GLEW_ARB_framebuffer_sRGB; + continue; + } +#endif +#ifdef GL_ARB_geometry_shader4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_shader4", 16)) + { + ret = GLEW_ARB_geometry_shader4; + continue; + } +#endif +#ifdef GL_ARB_get_program_binary + if (_glewStrSame3(&pos, &len, (const GLubyte*)"get_program_binary", 18)) + { + ret = GLEW_ARB_get_program_binary; + continue; + } +#endif +#ifdef GL_ARB_get_texture_sub_image + if (_glewStrSame3(&pos, &len, (const GLubyte*)"get_texture_sub_image", 21)) + { + ret = GLEW_ARB_get_texture_sub_image; + continue; + } +#endif +#ifdef GL_ARB_gl_spirv + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gl_spirv", 8)) + { + ret = GLEW_ARB_gl_spirv; + continue; + } +#endif +#ifdef GL_ARB_gpu_shader5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader5", 11)) + { + ret = GLEW_ARB_gpu_shader5; + continue; + } +#endif +#ifdef GL_ARB_gpu_shader_fp64 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader_fp64", 15)) + { + ret = GLEW_ARB_gpu_shader_fp64; + continue; + } +#endif +#ifdef GL_ARB_gpu_shader_int64 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader_int64", 16)) + { + ret = GLEW_ARB_gpu_shader_int64; + continue; + } +#endif +#ifdef GL_ARB_half_float_pixel + if (_glewStrSame3(&pos, &len, (const GLubyte*)"half_float_pixel", 16)) + { + ret = GLEW_ARB_half_float_pixel; + continue; + } +#endif +#ifdef GL_ARB_half_float_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"half_float_vertex", 17)) + { + ret = GLEW_ARB_half_float_vertex; + continue; + } +#endif +#ifdef GL_ARB_imaging + if (_glewStrSame3(&pos, &len, (const GLubyte*)"imaging", 7)) + { + ret = GLEW_ARB_imaging; + continue; + } +#endif +#ifdef GL_ARB_indirect_parameters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"indirect_parameters", 19)) + { + ret = GLEW_ARB_indirect_parameters; + continue; + } +#endif +#ifdef GL_ARB_instanced_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"instanced_arrays", 16)) + { + ret = GLEW_ARB_instanced_arrays; + continue; + } +#endif +#ifdef GL_ARB_internalformat_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"internalformat_query", 20)) + { + ret = GLEW_ARB_internalformat_query; + continue; + } +#endif +#ifdef GL_ARB_internalformat_query2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"internalformat_query2", 21)) + { + ret = GLEW_ARB_internalformat_query2; + continue; + } +#endif +#ifdef GL_ARB_invalidate_subdata + if (_glewStrSame3(&pos, &len, (const GLubyte*)"invalidate_subdata", 18)) + { + ret = GLEW_ARB_invalidate_subdata; + continue; + } +#endif +#ifdef GL_ARB_map_buffer_alignment + if (_glewStrSame3(&pos, &len, (const GLubyte*)"map_buffer_alignment", 20)) + { + ret = GLEW_ARB_map_buffer_alignment; + continue; + } +#endif +#ifdef GL_ARB_map_buffer_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"map_buffer_range", 16)) + { + ret = GLEW_ARB_map_buffer_range; + continue; + } +#endif +#ifdef GL_ARB_matrix_palette + if (_glewStrSame3(&pos, &len, (const GLubyte*)"matrix_palette", 14)) + { + ret = GLEW_ARB_matrix_palette; + continue; + } +#endif +#ifdef GL_ARB_multi_bind + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_bind", 10)) + { + ret = GLEW_ARB_multi_bind; + continue; + } +#endif +#ifdef GL_ARB_multi_draw_indirect + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_draw_indirect", 19)) + { + ret = GLEW_ARB_multi_draw_indirect; + continue; + } +#endif +#ifdef GL_ARB_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisample", 11)) + { + ret = GLEW_ARB_multisample; + continue; + } +#endif +#ifdef GL_ARB_multitexture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multitexture", 12)) + { + ret = GLEW_ARB_multitexture; + continue; + } +#endif +#ifdef GL_ARB_occlusion_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"occlusion_query", 15)) + { + ret = GLEW_ARB_occlusion_query; + continue; + } +#endif +#ifdef GL_ARB_occlusion_query2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"occlusion_query2", 16)) + { + ret = GLEW_ARB_occlusion_query2; + continue; + } +#endif +#ifdef GL_ARB_parallel_shader_compile + if (_glewStrSame3(&pos, &len, (const GLubyte*)"parallel_shader_compile", 23)) + { + ret = GLEW_ARB_parallel_shader_compile; + continue; + } +#endif +#ifdef GL_ARB_pipeline_statistics_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pipeline_statistics_query", 25)) + { + ret = GLEW_ARB_pipeline_statistics_query; + continue; + } +#endif +#ifdef GL_ARB_pixel_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_buffer_object", 19)) + { + ret = GLEW_ARB_pixel_buffer_object; + continue; + } +#endif +#ifdef GL_ARB_point_parameters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"point_parameters", 16)) + { + ret = GLEW_ARB_point_parameters; + continue; + } +#endif +#ifdef GL_ARB_point_sprite + if (_glewStrSame3(&pos, &len, (const GLubyte*)"point_sprite", 12)) + { + ret = GLEW_ARB_point_sprite; + continue; + } +#endif +#ifdef GL_ARB_polygon_offset_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"polygon_offset_clamp", 20)) + { + ret = GLEW_ARB_polygon_offset_clamp; + continue; + } +#endif +#ifdef GL_ARB_post_depth_coverage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"post_depth_coverage", 19)) + { + ret = GLEW_ARB_post_depth_coverage; + continue; + } +#endif +#ifdef GL_ARB_program_interface_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"program_interface_query", 23)) + { + ret = GLEW_ARB_program_interface_query; + continue; + } +#endif +#ifdef GL_ARB_provoking_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"provoking_vertex", 16)) + { + ret = GLEW_ARB_provoking_vertex; + continue; + } +#endif +#ifdef GL_ARB_query_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"query_buffer_object", 19)) + { + ret = GLEW_ARB_query_buffer_object; + continue; + } +#endif +#ifdef GL_ARB_robust_buffer_access_behavior + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robust_buffer_access_behavior", 29)) + { + ret = GLEW_ARB_robust_buffer_access_behavior; + continue; + } +#endif +#ifdef GL_ARB_robustness + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness", 10)) + { + ret = GLEW_ARB_robustness; + continue; + } +#endif +#ifdef GL_ARB_robustness_application_isolation + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness_application_isolation", 32)) + { + ret = GLEW_ARB_robustness_application_isolation; + continue; + } +#endif +#ifdef GL_ARB_robustness_share_group_isolation + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness_share_group_isolation", 32)) + { + ret = GLEW_ARB_robustness_share_group_isolation; + continue; + } +#endif +#ifdef GL_ARB_sample_locations + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_locations", 16)) + { + ret = GLEW_ARB_sample_locations; + continue; + } +#endif +#ifdef GL_ARB_sample_shading + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_shading", 14)) + { + ret = GLEW_ARB_sample_shading; + continue; + } +#endif +#ifdef GL_ARB_sampler_objects + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sampler_objects", 15)) + { + ret = GLEW_ARB_sampler_objects; + continue; + } +#endif +#ifdef GL_ARB_seamless_cube_map + if (_glewStrSame3(&pos, &len, (const GLubyte*)"seamless_cube_map", 17)) + { + ret = GLEW_ARB_seamless_cube_map; + continue; + } +#endif +#ifdef GL_ARB_seamless_cubemap_per_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"seamless_cubemap_per_texture", 28)) + { + ret = GLEW_ARB_seamless_cubemap_per_texture; + continue; + } +#endif +#ifdef GL_ARB_separate_shader_objects + if (_glewStrSame3(&pos, &len, (const GLubyte*)"separate_shader_objects", 23)) + { + ret = GLEW_ARB_separate_shader_objects; + continue; + } +#endif +#ifdef GL_ARB_shader_atomic_counter_ops + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counter_ops", 25)) + { + ret = GLEW_ARB_shader_atomic_counter_ops; + continue; + } +#endif +#ifdef GL_ARB_shader_atomic_counters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counters", 22)) + { + ret = GLEW_ARB_shader_atomic_counters; + continue; + } +#endif +#ifdef GL_ARB_shader_ballot + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_ballot", 13)) + { + ret = GLEW_ARB_shader_ballot; + continue; + } +#endif +#ifdef GL_ARB_shader_bit_encoding + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_bit_encoding", 19)) + { + ret = GLEW_ARB_shader_bit_encoding; + continue; + } +#endif +#ifdef GL_ARB_shader_clock + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_clock", 12)) + { + ret = GLEW_ARB_shader_clock; + continue; + } +#endif +#ifdef GL_ARB_shader_draw_parameters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_draw_parameters", 22)) + { + ret = GLEW_ARB_shader_draw_parameters; + continue; + } +#endif +#ifdef GL_ARB_shader_group_vote + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_group_vote", 17)) + { + ret = GLEW_ARB_shader_group_vote; + continue; + } +#endif +#ifdef GL_ARB_shader_image_load_store + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_image_load_store", 23)) + { + ret = GLEW_ARB_shader_image_load_store; + continue; + } +#endif +#ifdef GL_ARB_shader_image_size + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_image_size", 17)) + { + ret = GLEW_ARB_shader_image_size; + continue; + } +#endif +#ifdef GL_ARB_shader_objects + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_objects", 14)) + { + ret = GLEW_ARB_shader_objects; + continue; + } +#endif +#ifdef GL_ARB_shader_precision + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_precision", 16)) + { + ret = GLEW_ARB_shader_precision; + continue; + } +#endif +#ifdef GL_ARB_shader_stencil_export + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_stencil_export", 21)) + { + ret = GLEW_ARB_shader_stencil_export; + continue; + } +#endif +#ifdef GL_ARB_shader_storage_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_storage_buffer_object", 28)) + { + ret = GLEW_ARB_shader_storage_buffer_object; + continue; + } +#endif +#ifdef GL_ARB_shader_subroutine + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_subroutine", 17)) + { + ret = GLEW_ARB_shader_subroutine; + continue; + } +#endif +#ifdef GL_ARB_shader_texture_image_samples + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_texture_image_samples", 28)) + { + ret = GLEW_ARB_shader_texture_image_samples; + continue; + } +#endif +#ifdef GL_ARB_shader_texture_lod + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_texture_lod", 18)) + { + ret = GLEW_ARB_shader_texture_lod; + continue; + } +#endif +#ifdef GL_ARB_shader_viewport_layer_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_viewport_layer_array", 27)) + { + ret = GLEW_ARB_shader_viewport_layer_array; + continue; + } +#endif +#ifdef GL_ARB_shading_language_100 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shading_language_100", 20)) + { + ret = GLEW_ARB_shading_language_100; + continue; + } +#endif +#ifdef GL_ARB_shading_language_420pack + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shading_language_420pack", 24)) + { + ret = GLEW_ARB_shading_language_420pack; + continue; + } +#endif +#ifdef GL_ARB_shading_language_include + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shading_language_include", 24)) + { + ret = GLEW_ARB_shading_language_include; + continue; + } +#endif +#ifdef GL_ARB_shading_language_packing + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shading_language_packing", 24)) + { + ret = GLEW_ARB_shading_language_packing; + continue; + } +#endif +#ifdef GL_ARB_shadow + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow", 6)) + { + ret = GLEW_ARB_shadow; + continue; + } +#endif +#ifdef GL_ARB_shadow_ambient + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow_ambient", 14)) + { + ret = GLEW_ARB_shadow_ambient; + continue; + } +#endif +#ifdef GL_ARB_sparse_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_buffer", 13)) + { + ret = GLEW_ARB_sparse_buffer; + continue; + } +#endif +#ifdef GL_ARB_sparse_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture", 14)) + { + ret = GLEW_ARB_sparse_texture; + continue; + } +#endif +#ifdef GL_ARB_sparse_texture2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture2", 15)) + { + ret = GLEW_ARB_sparse_texture2; + continue; + } +#endif +#ifdef GL_ARB_sparse_texture_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture_clamp", 20)) + { + ret = GLEW_ARB_sparse_texture_clamp; + continue; + } +#endif +#ifdef GL_ARB_spirv_extensions + if (_glewStrSame3(&pos, &len, (const GLubyte*)"spirv_extensions", 16)) + { + ret = GLEW_ARB_spirv_extensions; + continue; + } +#endif +#ifdef GL_ARB_stencil_texturing + if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_texturing", 17)) + { + ret = GLEW_ARB_stencil_texturing; + continue; + } +#endif +#ifdef GL_ARB_sync + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sync", 4)) + { + ret = GLEW_ARB_sync; + continue; + } +#endif +#ifdef GL_ARB_tessellation_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"tessellation_shader", 19)) + { + ret = GLEW_ARB_tessellation_shader; + continue; + } +#endif +#ifdef GL_ARB_texture_barrier + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_barrier", 15)) + { + ret = GLEW_ARB_texture_barrier; + continue; + } +#endif +#ifdef GL_ARB_texture_border_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_border_clamp", 20)) + { + ret = GLEW_ARB_texture_border_clamp; + continue; + } +#endif +#ifdef GL_ARB_texture_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_buffer_object", 21)) + { + ret = GLEW_ARB_texture_buffer_object; + continue; + } +#endif +#ifdef GL_ARB_texture_buffer_object_rgb32 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_buffer_object_rgb32", 27)) + { + ret = GLEW_ARB_texture_buffer_object_rgb32; + continue; + } +#endif +#ifdef GL_ARB_texture_buffer_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_buffer_range", 20)) + { + ret = GLEW_ARB_texture_buffer_range; + continue; + } +#endif +#ifdef GL_ARB_texture_compression + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression", 19)) + { + ret = GLEW_ARB_texture_compression; + continue; + } +#endif +#ifdef GL_ARB_texture_compression_bptc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_bptc", 24)) + { + ret = GLEW_ARB_texture_compression_bptc; + continue; + } +#endif +#ifdef GL_ARB_texture_compression_rgtc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_rgtc", 24)) + { + ret = GLEW_ARB_texture_compression_rgtc; + continue; + } +#endif +#ifdef GL_ARB_texture_cube_map + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_cube_map", 16)) + { + ret = GLEW_ARB_texture_cube_map; + continue; + } +#endif +#ifdef GL_ARB_texture_cube_map_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_cube_map_array", 22)) + { + ret = GLEW_ARB_texture_cube_map_array; + continue; + } +#endif +#ifdef GL_ARB_texture_env_add + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_add", 15)) + { + ret = GLEW_ARB_texture_env_add; + continue; + } +#endif +#ifdef GL_ARB_texture_env_combine + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_combine", 19)) + { + ret = GLEW_ARB_texture_env_combine; + continue; + } +#endif +#ifdef GL_ARB_texture_env_crossbar + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_crossbar", 20)) + { + ret = GLEW_ARB_texture_env_crossbar; + continue; + } +#endif +#ifdef GL_ARB_texture_env_dot3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_dot3", 16)) + { + ret = GLEW_ARB_texture_env_dot3; + continue; + } +#endif +#ifdef GL_ARB_texture_filter_anisotropic + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_filter_anisotropic", 26)) + { + ret = GLEW_ARB_texture_filter_anisotropic; + continue; + } +#endif +#ifdef GL_ARB_texture_filter_minmax + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_filter_minmax", 21)) + { + ret = GLEW_ARB_texture_filter_minmax; + continue; + } +#endif +#ifdef GL_ARB_texture_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_float", 13)) + { + ret = GLEW_ARB_texture_float; + continue; + } +#endif +#ifdef GL_ARB_texture_gather + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_gather", 14)) + { + ret = GLEW_ARB_texture_gather; + continue; + } +#endif +#ifdef GL_ARB_texture_mirror_clamp_to_edge + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mirror_clamp_to_edge", 28)) + { + ret = GLEW_ARB_texture_mirror_clamp_to_edge; + continue; + } +#endif +#ifdef GL_ARB_texture_mirrored_repeat + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mirrored_repeat", 23)) + { + ret = GLEW_ARB_texture_mirrored_repeat; + continue; + } +#endif +#ifdef GL_ARB_texture_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_multisample", 19)) + { + ret = GLEW_ARB_texture_multisample; + continue; + } +#endif +#ifdef GL_ARB_texture_non_power_of_two + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_non_power_of_two", 24)) + { + ret = GLEW_ARB_texture_non_power_of_two; + continue; + } +#endif +#ifdef GL_ARB_texture_query_levels + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_query_levels", 20)) + { + ret = GLEW_ARB_texture_query_levels; + continue; + } +#endif +#ifdef GL_ARB_texture_query_lod + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_query_lod", 17)) + { + ret = GLEW_ARB_texture_query_lod; + continue; + } +#endif +#ifdef GL_ARB_texture_rectangle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_rectangle", 17)) + { + ret = GLEW_ARB_texture_rectangle; + continue; + } +#endif +#ifdef GL_ARB_texture_rg + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_rg", 10)) + { + ret = GLEW_ARB_texture_rg; + continue; + } +#endif +#ifdef GL_ARB_texture_rgb10_a2ui + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_rgb10_a2ui", 18)) + { + ret = GLEW_ARB_texture_rgb10_a2ui; + continue; + } +#endif +#ifdef GL_ARB_texture_stencil8 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_stencil8", 16)) + { + ret = GLEW_ARB_texture_stencil8; + continue; + } +#endif +#ifdef GL_ARB_texture_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_storage", 15)) + { + ret = GLEW_ARB_texture_storage; + continue; + } +#endif +#ifdef GL_ARB_texture_storage_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_storage_multisample", 27)) + { + ret = GLEW_ARB_texture_storage_multisample; + continue; + } +#endif +#ifdef GL_ARB_texture_swizzle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_swizzle", 15)) + { + ret = GLEW_ARB_texture_swizzle; + continue; + } +#endif +#ifdef GL_ARB_texture_view + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_view", 12)) + { + ret = GLEW_ARB_texture_view; + continue; + } +#endif +#ifdef GL_ARB_timer_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"timer_query", 11)) + { + ret = GLEW_ARB_timer_query; + continue; + } +#endif +#ifdef GL_ARB_transform_feedback2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback2", 19)) + { + ret = GLEW_ARB_transform_feedback2; + continue; + } +#endif +#ifdef GL_ARB_transform_feedback3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback3", 19)) + { + ret = GLEW_ARB_transform_feedback3; + continue; + } +#endif +#ifdef GL_ARB_transform_feedback_instanced + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback_instanced", 28)) + { + ret = GLEW_ARB_transform_feedback_instanced; + continue; + } +#endif +#ifdef GL_ARB_transform_feedback_overflow_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback_overflow_query", 33)) + { + ret = GLEW_ARB_transform_feedback_overflow_query; + continue; + } +#endif +#ifdef GL_ARB_transpose_matrix + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transpose_matrix", 16)) + { + ret = GLEW_ARB_transpose_matrix; + continue; + } +#endif +#ifdef GL_ARB_uniform_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"uniform_buffer_object", 21)) + { + ret = GLEW_ARB_uniform_buffer_object; + continue; + } +#endif +#ifdef GL_ARB_vertex_array_bgra + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_bgra", 17)) + { + ret = GLEW_ARB_vertex_array_bgra; + continue; + } +#endif +#ifdef GL_ARB_vertex_array_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_object", 19)) + { + ret = GLEW_ARB_vertex_array_object; + continue; + } +#endif +#ifdef GL_ARB_vertex_attrib_64bit + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_attrib_64bit", 19)) + { + ret = GLEW_ARB_vertex_attrib_64bit; + continue; + } +#endif +#ifdef GL_ARB_vertex_attrib_binding + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_attrib_binding", 21)) + { + ret = GLEW_ARB_vertex_attrib_binding; + continue; + } +#endif +#ifdef GL_ARB_vertex_blend + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_blend", 12)) + { + ret = GLEW_ARB_vertex_blend; + continue; + } +#endif +#ifdef GL_ARB_vertex_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_buffer_object", 20)) + { + ret = GLEW_ARB_vertex_buffer_object; + continue; + } +#endif +#ifdef GL_ARB_vertex_program + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program", 14)) + { + ret = GLEW_ARB_vertex_program; + continue; + } +#endif +#ifdef GL_ARB_vertex_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_shader", 13)) + { + ret = GLEW_ARB_vertex_shader; + continue; + } +#endif +#ifdef GL_ARB_vertex_type_10f_11f_11f_rev + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_type_10f_11f_11f_rev", 27)) + { + ret = GLEW_ARB_vertex_type_10f_11f_11f_rev; + continue; + } +#endif +#ifdef GL_ARB_vertex_type_2_10_10_10_rev + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_type_2_10_10_10_rev", 26)) + { + ret = GLEW_ARB_vertex_type_2_10_10_10_rev; + continue; + } +#endif +#ifdef GL_ARB_viewport_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"viewport_array", 14)) + { + ret = GLEW_ARB_viewport_array; + continue; + } +#endif +#ifdef GL_ARB_window_pos + if (_glewStrSame3(&pos, &len, (const GLubyte*)"window_pos", 10)) + { + ret = GLEW_ARB_window_pos; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"ARM_", 4)) + { +#ifdef GL_ARM_mali_program_binary + if (_glewStrSame3(&pos, &len, (const GLubyte*)"mali_program_binary", 19)) + { + ret = GLEW_ARM_mali_program_binary; + continue; + } +#endif +#ifdef GL_ARM_mali_shader_binary + if (_glewStrSame3(&pos, &len, (const GLubyte*)"mali_shader_binary", 18)) + { + ret = GLEW_ARM_mali_shader_binary; + continue; + } +#endif +#ifdef GL_ARM_rgba8 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"rgba8", 5)) + { + ret = GLEW_ARM_rgba8; + continue; + } +#endif +#ifdef GL_ARM_shader_framebuffer_fetch + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_framebuffer_fetch", 24)) + { + ret = GLEW_ARM_shader_framebuffer_fetch; + continue; + } +#endif +#ifdef GL_ARM_shader_framebuffer_fetch_depth_stencil + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_framebuffer_fetch_depth_stencil", 38)) + { + ret = GLEW_ARM_shader_framebuffer_fetch_depth_stencil; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"ATIX_", 5)) + { +#ifdef GL_ATIX_point_sprites + if (_glewStrSame3(&pos, &len, (const GLubyte*)"point_sprites", 13)) + { + ret = GLEW_ATIX_point_sprites; + continue; + } +#endif +#ifdef GL_ATIX_texture_env_combine3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_combine3", 20)) + { + ret = GLEW_ATIX_texture_env_combine3; + continue; + } +#endif +#ifdef GL_ATIX_texture_env_route + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_route", 17)) + { + ret = GLEW_ATIX_texture_env_route; + continue; + } +#endif +#ifdef GL_ATIX_vertex_shader_output_point_size + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_shader_output_point_size", 31)) + { + ret = GLEW_ATIX_vertex_shader_output_point_size; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"ATI_", 4)) + { +#ifdef GL_ATI_draw_buffers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers", 12)) + { + ret = GLEW_ATI_draw_buffers; + continue; + } +#endif +#ifdef GL_ATI_element_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"element_array", 13)) + { + ret = GLEW_ATI_element_array; + continue; + } +#endif +#ifdef GL_ATI_envmap_bumpmap + if (_glewStrSame3(&pos, &len, (const GLubyte*)"envmap_bumpmap", 14)) + { + ret = GLEW_ATI_envmap_bumpmap; + continue; + } +#endif +#ifdef GL_ATI_fragment_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader", 15)) + { + ret = GLEW_ATI_fragment_shader; + continue; + } +#endif +#ifdef GL_ATI_map_object_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"map_object_buffer", 17)) + { + ret = GLEW_ATI_map_object_buffer; + continue; + } +#endif +#ifdef GL_ATI_meminfo + if (_glewStrSame3(&pos, &len, (const GLubyte*)"meminfo", 7)) + { + ret = GLEW_ATI_meminfo; + continue; + } +#endif +#ifdef GL_ATI_pn_triangles + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pn_triangles", 12)) + { + ret = GLEW_ATI_pn_triangles; + continue; + } +#endif +#ifdef GL_ATI_separate_stencil + if (_glewStrSame3(&pos, &len, (const GLubyte*)"separate_stencil", 16)) + { + ret = GLEW_ATI_separate_stencil; + continue; + } +#endif +#ifdef GL_ATI_shader_texture_lod + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_texture_lod", 18)) + { + ret = GLEW_ATI_shader_texture_lod; + continue; + } +#endif +#ifdef GL_ATI_text_fragment_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"text_fragment_shader", 20)) + { + ret = GLEW_ATI_text_fragment_shader; + continue; + } +#endif +#ifdef GL_ATI_texture_compression_3dc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_3dc", 23)) + { + ret = GLEW_ATI_texture_compression_3dc; + continue; + } +#endif +#ifdef GL_ATI_texture_env_combine3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_combine3", 20)) + { + ret = GLEW_ATI_texture_env_combine3; + continue; + } +#endif +#ifdef GL_ATI_texture_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_float", 13)) + { + ret = GLEW_ATI_texture_float; + continue; + } +#endif +#ifdef GL_ATI_texture_mirror_once + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mirror_once", 19)) + { + ret = GLEW_ATI_texture_mirror_once; + continue; + } +#endif +#ifdef GL_ATI_vertex_array_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_object", 19)) + { + ret = GLEW_ATI_vertex_array_object; + continue; + } +#endif +#ifdef GL_ATI_vertex_attrib_array_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_attrib_array_object", 26)) + { + ret = GLEW_ATI_vertex_attrib_array_object; + continue; + } +#endif +#ifdef GL_ATI_vertex_streams + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_streams", 14)) + { + ret = GLEW_ATI_vertex_streams; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"EGL_", 4)) + { +#ifdef GL_EGL_KHR_context_flush_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"KHR_context_flush_control", 25)) + { + ret = GLEW_EGL_KHR_context_flush_control; + continue; + } +#endif +#ifdef GL_EGL_NV_robustness_video_memory_purge + if (_glewStrSame3(&pos, &len, (const GLubyte*)"NV_robustness_video_memory_purge", 32)) + { + ret = GLEW_EGL_NV_robustness_video_memory_purge; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"EXT_", 4)) + { +#ifdef GL_EXT_422_pixels + if (_glewStrSame3(&pos, &len, (const GLubyte*)"422_pixels", 10)) + { + ret = GLEW_EXT_422_pixels; + continue; + } +#endif +#ifdef GL_EXT_Cg_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"Cg_shader", 9)) + { + ret = GLEW_EXT_Cg_shader; + continue; + } +#endif +#ifdef GL_EXT_EGL_image_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"EGL_image_array", 15)) + { + ret = GLEW_EXT_EGL_image_array; + continue; + } +#endif +#ifdef GL_EXT_YUV_target + if (_glewStrSame3(&pos, &len, (const GLubyte*)"YUV_target", 10)) + { + ret = GLEW_EXT_YUV_target; + continue; + } +#endif +#ifdef GL_EXT_abgr + if (_glewStrSame3(&pos, &len, (const GLubyte*)"abgr", 4)) + { + ret = GLEW_EXT_abgr; + continue; + } +#endif +#ifdef GL_EXT_base_instance + if (_glewStrSame3(&pos, &len, (const GLubyte*)"base_instance", 13)) + { + ret = GLEW_EXT_base_instance; + continue; + } +#endif +#ifdef GL_EXT_bgra + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bgra", 4)) + { + ret = GLEW_EXT_bgra; + continue; + } +#endif +#ifdef GL_EXT_bindable_uniform + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindable_uniform", 16)) + { + ret = GLEW_EXT_bindable_uniform; + continue; + } +#endif +#ifdef GL_EXT_blend_color + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_color", 11)) + { + ret = GLEW_EXT_blend_color; + continue; + } +#endif +#ifdef GL_EXT_blend_equation_separate + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_separate", 23)) + { + ret = GLEW_EXT_blend_equation_separate; + continue; + } +#endif +#ifdef GL_EXT_blend_func_extended + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_func_extended", 19)) + { + ret = GLEW_EXT_blend_func_extended; + continue; + } +#endif +#ifdef GL_EXT_blend_func_separate + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_func_separate", 19)) + { + ret = GLEW_EXT_blend_func_separate; + continue; + } +#endif +#ifdef GL_EXT_blend_logic_op + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_logic_op", 14)) + { + ret = GLEW_EXT_blend_logic_op; + continue; + } +#endif +#ifdef GL_EXT_blend_minmax + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_minmax", 12)) + { + ret = GLEW_EXT_blend_minmax; + continue; + } +#endif +#ifdef GL_EXT_blend_subtract + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_subtract", 14)) + { + ret = GLEW_EXT_blend_subtract; + continue; + } +#endif +#ifdef GL_EXT_buffer_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"buffer_storage", 14)) + { + ret = GLEW_EXT_buffer_storage; + continue; + } +#endif +#ifdef GL_EXT_clear_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clear_texture", 13)) + { + ret = GLEW_EXT_clear_texture; + continue; + } +#endif +#ifdef GL_EXT_clip_cull_distance + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clip_cull_distance", 18)) + { + ret = GLEW_EXT_clip_cull_distance; + continue; + } +#endif +#ifdef GL_EXT_clip_volume_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clip_volume_hint", 16)) + { + ret = GLEW_EXT_clip_volume_hint; + continue; + } +#endif +#ifdef GL_EXT_cmyka + if (_glewStrSame3(&pos, &len, (const GLubyte*)"cmyka", 5)) + { + ret = GLEW_EXT_cmyka; + continue; + } +#endif +#ifdef GL_EXT_color_buffer_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_buffer_float", 18)) + { + ret = GLEW_EXT_color_buffer_float; + continue; + } +#endif +#ifdef GL_EXT_color_buffer_half_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_buffer_half_float", 23)) + { + ret = GLEW_EXT_color_buffer_half_float; + continue; + } +#endif +#ifdef GL_EXT_color_subtable + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_subtable", 14)) + { + ret = GLEW_EXT_color_subtable; + continue; + } +#endif +#ifdef GL_EXT_compiled_vertex_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compiled_vertex_array", 21)) + { + ret = GLEW_EXT_compiled_vertex_array; + continue; + } +#endif +#ifdef GL_EXT_compressed_ETC1_RGB8_sub_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compressed_ETC1_RGB8_sub_texture", 32)) + { + ret = GLEW_EXT_compressed_ETC1_RGB8_sub_texture; + continue; + } +#endif +#ifdef GL_EXT_conservative_depth + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_depth", 18)) + { + ret = GLEW_EXT_conservative_depth; + continue; + } +#endif +#ifdef GL_EXT_convolution + if (_glewStrSame3(&pos, &len, (const GLubyte*)"convolution", 11)) + { + ret = GLEW_EXT_convolution; + continue; + } +#endif +#ifdef GL_EXT_coordinate_frame + if (_glewStrSame3(&pos, &len, (const GLubyte*)"coordinate_frame", 16)) + { + ret = GLEW_EXT_coordinate_frame; + continue; + } +#endif +#ifdef GL_EXT_copy_image + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_image", 10)) + { + ret = GLEW_EXT_copy_image; + continue; + } +#endif +#ifdef GL_EXT_copy_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_texture", 12)) + { + ret = GLEW_EXT_copy_texture; + continue; + } +#endif +#ifdef GL_EXT_cull_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"cull_vertex", 11)) + { + ret = GLEW_EXT_cull_vertex; + continue; + } +#endif +#ifdef GL_EXT_debug_label + if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug_label", 11)) + { + ret = GLEW_EXT_debug_label; + continue; + } +#endif +#ifdef GL_EXT_debug_marker + if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug_marker", 12)) + { + ret = GLEW_EXT_debug_marker; + continue; + } +#endif +#ifdef GL_EXT_depth_bounds_test + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_bounds_test", 17)) + { + ret = GLEW_EXT_depth_bounds_test; + continue; + } +#endif +#ifdef GL_EXT_direct_state_access + if (_glewStrSame3(&pos, &len, (const GLubyte*)"direct_state_access", 19)) + { + ret = GLEW_EXT_direct_state_access; + continue; + } +#endif +#ifdef GL_EXT_discard_framebuffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"discard_framebuffer", 19)) + { + ret = GLEW_EXT_discard_framebuffer; + continue; + } +#endif +#ifdef GL_EXT_draw_buffers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers", 12)) + { + ret = GLEW_EXT_draw_buffers; + continue; + } +#endif +#ifdef GL_EXT_draw_buffers2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers2", 13)) + { + ret = GLEW_EXT_draw_buffers2; + continue; + } +#endif +#ifdef GL_EXT_draw_buffers_indexed + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers_indexed", 20)) + { + ret = GLEW_EXT_draw_buffers_indexed; + continue; + } +#endif +#ifdef GL_EXT_draw_elements_base_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_elements_base_vertex", 25)) + { + ret = GLEW_EXT_draw_elements_base_vertex; + continue; + } +#endif +#ifdef GL_EXT_draw_instanced + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_instanced", 14)) + { + ret = GLEW_EXT_draw_instanced; + continue; + } +#endif +#ifdef GL_EXT_draw_range_elements + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_range_elements", 19)) + { + ret = GLEW_EXT_draw_range_elements; + continue; + } +#endif +#ifdef GL_EXT_external_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"external_buffer", 15)) + { + ret = GLEW_EXT_external_buffer; + continue; + } +#endif +#ifdef GL_EXT_float_blend + if (_glewStrSame3(&pos, &len, (const GLubyte*)"float_blend", 11)) + { + ret = GLEW_EXT_float_blend; + continue; + } +#endif +#ifdef GL_EXT_fog_coord + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_coord", 9)) + { + ret = GLEW_EXT_fog_coord; + continue; + } +#endif +#ifdef GL_EXT_frag_depth + if (_glewStrSame3(&pos, &len, (const GLubyte*)"frag_depth", 10)) + { + ret = GLEW_EXT_frag_depth; + continue; + } +#endif +#ifdef GL_EXT_fragment_lighting + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_lighting", 17)) + { + ret = GLEW_EXT_fragment_lighting; + continue; + } +#endif +#ifdef GL_EXT_framebuffer_blit + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_blit", 16)) + { + ret = GLEW_EXT_framebuffer_blit; + continue; + } +#endif +#ifdef GL_EXT_framebuffer_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample", 23)) + { + ret = GLEW_EXT_framebuffer_multisample; + continue; + } +#endif +#ifdef GL_EXT_framebuffer_multisample_blit_scaled + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample_blit_scaled", 35)) + { + ret = GLEW_EXT_framebuffer_multisample_blit_scaled; + continue; + } +#endif +#ifdef GL_EXT_framebuffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_object", 18)) + { + ret = GLEW_EXT_framebuffer_object; + continue; + } +#endif +#ifdef GL_EXT_framebuffer_sRGB + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_sRGB", 16)) + { + ret = GLEW_EXT_framebuffer_sRGB; + continue; + } +#endif +#ifdef GL_EXT_geometry_point_size + if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_point_size", 19)) + { + ret = GLEW_EXT_geometry_point_size; + continue; + } +#endif +#ifdef GL_EXT_geometry_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_shader", 15)) + { + ret = GLEW_EXT_geometry_shader; + continue; + } +#endif +#ifdef GL_EXT_geometry_shader4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_shader4", 16)) + { + ret = GLEW_EXT_geometry_shader4; + continue; + } +#endif +#ifdef GL_EXT_gpu_program_parameters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program_parameters", 22)) + { + ret = GLEW_EXT_gpu_program_parameters; + continue; + } +#endif +#ifdef GL_EXT_gpu_shader4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader4", 11)) + { + ret = GLEW_EXT_gpu_shader4; + continue; + } +#endif +#ifdef GL_EXT_gpu_shader5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader5", 11)) + { + ret = GLEW_EXT_gpu_shader5; + continue; + } +#endif +#ifdef GL_EXT_histogram + if (_glewStrSame3(&pos, &len, (const GLubyte*)"histogram", 9)) + { + ret = GLEW_EXT_histogram; + continue; + } +#endif +#ifdef GL_EXT_index_array_formats + if (_glewStrSame3(&pos, &len, (const GLubyte*)"index_array_formats", 19)) + { + ret = GLEW_EXT_index_array_formats; + continue; + } +#endif +#ifdef GL_EXT_index_func + if (_glewStrSame3(&pos, &len, (const GLubyte*)"index_func", 10)) + { + ret = GLEW_EXT_index_func; + continue; + } +#endif +#ifdef GL_EXT_index_material + if (_glewStrSame3(&pos, &len, (const GLubyte*)"index_material", 14)) + { + ret = GLEW_EXT_index_material; + continue; + } +#endif +#ifdef GL_EXT_index_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"index_texture", 13)) + { + ret = GLEW_EXT_index_texture; + continue; + } +#endif +#ifdef GL_EXT_instanced_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"instanced_arrays", 16)) + { + ret = GLEW_EXT_instanced_arrays; + continue; + } +#endif +#ifdef GL_EXT_light_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"light_texture", 13)) + { + ret = GLEW_EXT_light_texture; + continue; + } +#endif +#ifdef GL_EXT_map_buffer_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"map_buffer_range", 16)) + { + ret = GLEW_EXT_map_buffer_range; + continue; + } +#endif +#ifdef GL_EXT_memory_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"memory_object", 13)) + { + ret = GLEW_EXT_memory_object; + continue; + } +#endif +#ifdef GL_EXT_memory_object_fd + if (_glewStrSame3(&pos, &len, (const GLubyte*)"memory_object_fd", 16)) + { + ret = GLEW_EXT_memory_object_fd; + continue; + } +#endif +#ifdef GL_EXT_memory_object_win32 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"memory_object_win32", 19)) + { + ret = GLEW_EXT_memory_object_win32; + continue; + } +#endif +#ifdef GL_EXT_misc_attribute + if (_glewStrSame3(&pos, &len, (const GLubyte*)"misc_attribute", 14)) + { + ret = GLEW_EXT_misc_attribute; + continue; + } +#endif +#ifdef GL_EXT_multi_draw_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_draw_arrays", 17)) + { + ret = GLEW_EXT_multi_draw_arrays; + continue; + } +#endif +#ifdef GL_EXT_multi_draw_indirect + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_draw_indirect", 19)) + { + ret = GLEW_EXT_multi_draw_indirect; + continue; + } +#endif +#ifdef GL_EXT_multiple_textures + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multiple_textures", 17)) + { + ret = GLEW_EXT_multiple_textures; + continue; + } +#endif +#ifdef GL_EXT_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisample", 11)) + { + ret = GLEW_EXT_multisample; + continue; + } +#endif +#ifdef GL_EXT_multisample_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisample_compatibility", 25)) + { + ret = GLEW_EXT_multisample_compatibility; + continue; + } +#endif +#ifdef GL_EXT_multisampled_render_to_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisampled_render_to_texture", 30)) + { + ret = GLEW_EXT_multisampled_render_to_texture; + continue; + } +#endif +#ifdef GL_EXT_multisampled_render_to_texture2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisampled_render_to_texture2", 31)) + { + ret = GLEW_EXT_multisampled_render_to_texture2; + continue; + } +#endif +#ifdef GL_EXT_multiview_draw_buffers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multiview_draw_buffers", 22)) + { + ret = GLEW_EXT_multiview_draw_buffers; + continue; + } +#endif +#ifdef GL_EXT_packed_depth_stencil + if (_glewStrSame3(&pos, &len, (const GLubyte*)"packed_depth_stencil", 20)) + { + ret = GLEW_EXT_packed_depth_stencil; + continue; + } +#endif +#ifdef GL_EXT_packed_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"packed_float", 12)) + { + ret = GLEW_EXT_packed_float; + continue; + } +#endif +#ifdef GL_EXT_packed_pixels + if (_glewStrSame3(&pos, &len, (const GLubyte*)"packed_pixels", 13)) + { + ret = GLEW_EXT_packed_pixels; + continue; + } +#endif +#ifdef GL_EXT_paletted_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"paletted_texture", 16)) + { + ret = GLEW_EXT_paletted_texture; + continue; + } +#endif +#ifdef GL_EXT_pixel_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_buffer_object", 19)) + { + ret = GLEW_EXT_pixel_buffer_object; + continue; + } +#endif +#ifdef GL_EXT_pixel_transform + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_transform", 15)) + { + ret = GLEW_EXT_pixel_transform; + continue; + } +#endif +#ifdef GL_EXT_pixel_transform_color_table + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_transform_color_table", 27)) + { + ret = GLEW_EXT_pixel_transform_color_table; + continue; + } +#endif +#ifdef GL_EXT_point_parameters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"point_parameters", 16)) + { + ret = GLEW_EXT_point_parameters; + continue; + } +#endif +#ifdef GL_EXT_polygon_offset + if (_glewStrSame3(&pos, &len, (const GLubyte*)"polygon_offset", 14)) + { + ret = GLEW_EXT_polygon_offset; + continue; + } +#endif +#ifdef GL_EXT_polygon_offset_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"polygon_offset_clamp", 20)) + { + ret = GLEW_EXT_polygon_offset_clamp; + continue; + } +#endif +#ifdef GL_EXT_post_depth_coverage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"post_depth_coverage", 19)) + { + ret = GLEW_EXT_post_depth_coverage; + continue; + } +#endif +#ifdef GL_EXT_provoking_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"provoking_vertex", 16)) + { + ret = GLEW_EXT_provoking_vertex; + continue; + } +#endif +#ifdef GL_EXT_pvrtc_sRGB + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pvrtc_sRGB", 10)) + { + ret = GLEW_EXT_pvrtc_sRGB; + continue; + } +#endif +#ifdef GL_EXT_raster_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"raster_multisample", 18)) + { + ret = GLEW_EXT_raster_multisample; + continue; + } +#endif +#ifdef GL_EXT_read_format_bgra + if (_glewStrSame3(&pos, &len, (const GLubyte*)"read_format_bgra", 16)) + { + ret = GLEW_EXT_read_format_bgra; + continue; + } +#endif +#ifdef GL_EXT_render_snorm + if (_glewStrSame3(&pos, &len, (const GLubyte*)"render_snorm", 12)) + { + ret = GLEW_EXT_render_snorm; + continue; + } +#endif +#ifdef GL_EXT_rescale_normal + if (_glewStrSame3(&pos, &len, (const GLubyte*)"rescale_normal", 14)) + { + ret = GLEW_EXT_rescale_normal; + continue; + } +#endif +#ifdef GL_EXT_sRGB + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sRGB", 4)) + { + ret = GLEW_EXT_sRGB; + continue; + } +#endif +#ifdef GL_EXT_sRGB_write_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sRGB_write_control", 18)) + { + ret = GLEW_EXT_sRGB_write_control; + continue; + } +#endif +#ifdef GL_EXT_scene_marker + if (_glewStrSame3(&pos, &len, (const GLubyte*)"scene_marker", 12)) + { + ret = GLEW_EXT_scene_marker; + continue; + } +#endif +#ifdef GL_EXT_secondary_color + if (_glewStrSame3(&pos, &len, (const GLubyte*)"secondary_color", 15)) + { + ret = GLEW_EXT_secondary_color; + continue; + } +#endif +#ifdef GL_EXT_semaphore + if (_glewStrSame3(&pos, &len, (const GLubyte*)"semaphore", 9)) + { + ret = GLEW_EXT_semaphore; + continue; + } +#endif +#ifdef GL_EXT_semaphore_fd + if (_glewStrSame3(&pos, &len, (const GLubyte*)"semaphore_fd", 12)) + { + ret = GLEW_EXT_semaphore_fd; + continue; + } +#endif +#ifdef GL_EXT_semaphore_win32 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"semaphore_win32", 15)) + { + ret = GLEW_EXT_semaphore_win32; + continue; + } +#endif +#ifdef GL_EXT_separate_shader_objects + if (_glewStrSame3(&pos, &len, (const GLubyte*)"separate_shader_objects", 23)) + { + ret = GLEW_EXT_separate_shader_objects; + continue; + } +#endif +#ifdef GL_EXT_separate_specular_color + if (_glewStrSame3(&pos, &len, (const GLubyte*)"separate_specular_color", 23)) + { + ret = GLEW_EXT_separate_specular_color; + continue; + } +#endif +#ifdef GL_EXT_shader_framebuffer_fetch + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_framebuffer_fetch", 24)) + { + ret = GLEW_EXT_shader_framebuffer_fetch; + continue; + } +#endif +#ifdef GL_EXT_shader_group_vote + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_group_vote", 17)) + { + ret = GLEW_EXT_shader_group_vote; + continue; + } +#endif +#ifdef GL_EXT_shader_image_load_formatted + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_image_load_formatted", 27)) + { + ret = GLEW_EXT_shader_image_load_formatted; + continue; + } +#endif +#ifdef GL_EXT_shader_image_load_store + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_image_load_store", 23)) + { + ret = GLEW_EXT_shader_image_load_store; + continue; + } +#endif +#ifdef GL_EXT_shader_implicit_conversions + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_implicit_conversions", 27)) + { + ret = GLEW_EXT_shader_implicit_conversions; + continue; + } +#endif +#ifdef GL_EXT_shader_integer_mix + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_integer_mix", 18)) + { + ret = GLEW_EXT_shader_integer_mix; + continue; + } +#endif +#ifdef GL_EXT_shader_io_blocks + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_io_blocks", 16)) + { + ret = GLEW_EXT_shader_io_blocks; + continue; + } +#endif +#ifdef GL_EXT_shader_non_constant_global_initializers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_non_constant_global_initializers", 39)) + { + ret = GLEW_EXT_shader_non_constant_global_initializers; + continue; + } +#endif +#ifdef GL_EXT_shader_pixel_local_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_pixel_local_storage", 26)) + { + ret = GLEW_EXT_shader_pixel_local_storage; + continue; + } +#endif +#ifdef GL_EXT_shader_pixel_local_storage2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_pixel_local_storage2", 27)) + { + ret = GLEW_EXT_shader_pixel_local_storage2; + continue; + } +#endif +#ifdef GL_EXT_shader_texture_lod + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_texture_lod", 18)) + { + ret = GLEW_EXT_shader_texture_lod; + continue; + } +#endif +#ifdef GL_EXT_shadow_funcs + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow_funcs", 12)) + { + ret = GLEW_EXT_shadow_funcs; + continue; + } +#endif +#ifdef GL_EXT_shadow_samplers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow_samplers", 15)) + { + ret = GLEW_EXT_shadow_samplers; + continue; + } +#endif +#ifdef GL_EXT_shared_texture_palette + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shared_texture_palette", 22)) + { + ret = GLEW_EXT_shared_texture_palette; + continue; + } +#endif +#ifdef GL_EXT_sparse_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture", 14)) + { + ret = GLEW_EXT_sparse_texture; + continue; + } +#endif +#ifdef GL_EXT_sparse_texture2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture2", 15)) + { + ret = GLEW_EXT_sparse_texture2; + continue; + } +#endif +#ifdef GL_EXT_stencil_clear_tag + if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_clear_tag", 17)) + { + ret = GLEW_EXT_stencil_clear_tag; + continue; + } +#endif +#ifdef GL_EXT_stencil_two_side + if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_two_side", 16)) + { + ret = GLEW_EXT_stencil_two_side; + continue; + } +#endif +#ifdef GL_EXT_stencil_wrap + if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_wrap", 12)) + { + ret = GLEW_EXT_stencil_wrap; + continue; + } +#endif +#ifdef GL_EXT_subtexture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"subtexture", 10)) + { + ret = GLEW_EXT_subtexture; + continue; + } +#endif +#ifdef GL_EXT_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture", 7)) + { + ret = GLEW_EXT_texture; + continue; + } +#endif +#ifdef GL_EXT_texture3D + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture3D", 9)) + { + ret = GLEW_EXT_texture3D; + continue; + } +#endif +#ifdef GL_EXT_texture_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_array", 13)) + { + ret = GLEW_EXT_texture_array; + continue; + } +#endif +#ifdef GL_EXT_texture_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_buffer_object", 21)) + { + ret = GLEW_EXT_texture_buffer_object; + continue; + } +#endif +#ifdef GL_EXT_texture_compression_astc_decode_mode + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_astc_decode_mode", 36)) + { + ret = GLEW_EXT_texture_compression_astc_decode_mode; + continue; + } +#endif +#ifdef GL_EXT_texture_compression_astc_decode_mode_rgb9e5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_astc_decode_mode_rgb9e5", 43)) + { + ret = GLEW_EXT_texture_compression_astc_decode_mode_rgb9e5; + continue; + } +#endif +#ifdef GL_EXT_texture_compression_bptc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_bptc", 24)) + { + ret = GLEW_EXT_texture_compression_bptc; + continue; + } +#endif +#ifdef GL_EXT_texture_compression_dxt1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_dxt1", 24)) + { + ret = GLEW_EXT_texture_compression_dxt1; + continue; + } +#endif +#ifdef GL_EXT_texture_compression_latc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_latc", 24)) + { + ret = GLEW_EXT_texture_compression_latc; + continue; + } +#endif +#ifdef GL_EXT_texture_compression_rgtc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_rgtc", 24)) + { + ret = GLEW_EXT_texture_compression_rgtc; + continue; + } +#endif +#ifdef GL_EXT_texture_compression_s3tc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_s3tc", 24)) + { + ret = GLEW_EXT_texture_compression_s3tc; + continue; + } +#endif +#ifdef GL_EXT_texture_cube_map + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_cube_map", 16)) + { + ret = GLEW_EXT_texture_cube_map; + continue; + } +#endif +#ifdef GL_EXT_texture_cube_map_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_cube_map_array", 22)) + { + ret = GLEW_EXT_texture_cube_map_array; + continue; + } +#endif +#ifdef GL_EXT_texture_edge_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_edge_clamp", 18)) + { + ret = GLEW_EXT_texture_edge_clamp; + continue; + } +#endif +#ifdef GL_EXT_texture_env + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env", 11)) + { + ret = GLEW_EXT_texture_env; + continue; + } +#endif +#ifdef GL_EXT_texture_env_add + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_add", 15)) + { + ret = GLEW_EXT_texture_env_add; + continue; + } +#endif +#ifdef GL_EXT_texture_env_combine + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_combine", 19)) + { + ret = GLEW_EXT_texture_env_combine; + continue; + } +#endif +#ifdef GL_EXT_texture_env_dot3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_dot3", 16)) + { + ret = GLEW_EXT_texture_env_dot3; + continue; + } +#endif +#ifdef GL_EXT_texture_filter_anisotropic + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_filter_anisotropic", 26)) + { + ret = GLEW_EXT_texture_filter_anisotropic; + continue; + } +#endif +#ifdef GL_EXT_texture_filter_minmax + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_filter_minmax", 21)) + { + ret = GLEW_EXT_texture_filter_minmax; + continue; + } +#endif +#ifdef GL_EXT_texture_format_BGRA8888 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_format_BGRA8888", 23)) + { + ret = GLEW_EXT_texture_format_BGRA8888; + continue; + } +#endif +#ifdef GL_EXT_texture_integer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_integer", 15)) + { + ret = GLEW_EXT_texture_integer; + continue; + } +#endif +#ifdef GL_EXT_texture_lod_bias + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_lod_bias", 16)) + { + ret = GLEW_EXT_texture_lod_bias; + continue; + } +#endif +#ifdef GL_EXT_texture_mirror_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mirror_clamp", 20)) + { + ret = GLEW_EXT_texture_mirror_clamp; + continue; + } +#endif +#ifdef GL_EXT_texture_norm16 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_norm16", 14)) + { + ret = GLEW_EXT_texture_norm16; + continue; + } +#endif +#ifdef GL_EXT_texture_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_object", 14)) + { + ret = GLEW_EXT_texture_object; + continue; + } +#endif +#ifdef GL_EXT_texture_perturb_normal + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_perturb_normal", 22)) + { + ret = GLEW_EXT_texture_perturb_normal; + continue; + } +#endif +#ifdef GL_EXT_texture_rectangle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_rectangle", 17)) + { + ret = GLEW_EXT_texture_rectangle; + continue; + } +#endif +#ifdef GL_EXT_texture_rg + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_rg", 10)) + { + ret = GLEW_EXT_texture_rg; + continue; + } +#endif +#ifdef GL_EXT_texture_sRGB + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_sRGB", 12)) + { + ret = GLEW_EXT_texture_sRGB; + continue; + } +#endif +#ifdef GL_EXT_texture_sRGB_R8 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_sRGB_R8", 15)) + { + ret = GLEW_EXT_texture_sRGB_R8; + continue; + } +#endif +#ifdef GL_EXT_texture_sRGB_RG8 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_sRGB_RG8", 16)) + { + ret = GLEW_EXT_texture_sRGB_RG8; + continue; + } +#endif +#ifdef GL_EXT_texture_sRGB_decode + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_sRGB_decode", 19)) + { + ret = GLEW_EXT_texture_sRGB_decode; + continue; + } +#endif +#ifdef GL_EXT_texture_shared_exponent + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_shared_exponent", 23)) + { + ret = GLEW_EXT_texture_shared_exponent; + continue; + } +#endif +#ifdef GL_EXT_texture_snorm + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_snorm", 13)) + { + ret = GLEW_EXT_texture_snorm; + continue; + } +#endif +#ifdef GL_EXT_texture_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_storage", 15)) + { + ret = GLEW_EXT_texture_storage; + continue; + } +#endif +#ifdef GL_EXT_texture_swizzle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_swizzle", 15)) + { + ret = GLEW_EXT_texture_swizzle; + continue; + } +#endif +#ifdef GL_EXT_texture_type_2_10_10_10_REV + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_type_2_10_10_10_REV", 27)) + { + ret = GLEW_EXT_texture_type_2_10_10_10_REV; + continue; + } +#endif +#ifdef GL_EXT_texture_view + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_view", 12)) + { + ret = GLEW_EXT_texture_view; + continue; + } +#endif +#ifdef GL_EXT_timer_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"timer_query", 11)) + { + ret = GLEW_EXT_timer_query; + continue; + } +#endif +#ifdef GL_EXT_transform_feedback + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback", 18)) + { + ret = GLEW_EXT_transform_feedback; + continue; + } +#endif +#ifdef GL_EXT_unpack_subimage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"unpack_subimage", 15)) + { + ret = GLEW_EXT_unpack_subimage; + continue; + } +#endif +#ifdef GL_EXT_vertex_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array", 12)) + { + ret = GLEW_EXT_vertex_array; + continue; + } +#endif +#ifdef GL_EXT_vertex_array_bgra + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_bgra", 17)) + { + ret = GLEW_EXT_vertex_array_bgra; + continue; + } +#endif +#ifdef GL_EXT_vertex_array_setXXX + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_setXXX", 19)) + { + ret = GLEW_EXT_vertex_array_setXXX; + continue; + } +#endif +#ifdef GL_EXT_vertex_attrib_64bit + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_attrib_64bit", 19)) + { + ret = GLEW_EXT_vertex_attrib_64bit; + continue; + } +#endif +#ifdef GL_EXT_vertex_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_shader", 13)) + { + ret = GLEW_EXT_vertex_shader; + continue; + } +#endif +#ifdef GL_EXT_vertex_weighting + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_weighting", 16)) + { + ret = GLEW_EXT_vertex_weighting; + continue; + } +#endif +#ifdef GL_EXT_win32_keyed_mutex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"win32_keyed_mutex", 17)) + { + ret = GLEW_EXT_win32_keyed_mutex; + continue; + } +#endif +#ifdef GL_EXT_window_rectangles + if (_glewStrSame3(&pos, &len, (const GLubyte*)"window_rectangles", 17)) + { + ret = GLEW_EXT_window_rectangles; + continue; + } +#endif +#ifdef GL_EXT_x11_sync_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"x11_sync_object", 15)) + { + ret = GLEW_EXT_x11_sync_object; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"GREMEDY_", 8)) + { +#ifdef GL_GREMEDY_frame_terminator + if (_glewStrSame3(&pos, &len, (const GLubyte*)"frame_terminator", 16)) + { + ret = GLEW_GREMEDY_frame_terminator; + continue; + } +#endif +#ifdef GL_GREMEDY_string_marker + if (_glewStrSame3(&pos, &len, (const GLubyte*)"string_marker", 13)) + { + ret = GLEW_GREMEDY_string_marker; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"HP_", 3)) + { +#ifdef GL_HP_convolution_border_modes + if (_glewStrSame3(&pos, &len, (const GLubyte*)"convolution_border_modes", 24)) + { + ret = GLEW_HP_convolution_border_modes; + continue; + } +#endif +#ifdef GL_HP_image_transform + if (_glewStrSame3(&pos, &len, (const GLubyte*)"image_transform", 15)) + { + ret = GLEW_HP_image_transform; + continue; + } +#endif +#ifdef GL_HP_occlusion_test + if (_glewStrSame3(&pos, &len, (const GLubyte*)"occlusion_test", 14)) + { + ret = GLEW_HP_occlusion_test; + continue; + } +#endif +#ifdef GL_HP_texture_lighting + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_lighting", 16)) + { + ret = GLEW_HP_texture_lighting; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"IBM_", 4)) + { +#ifdef GL_IBM_cull_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"cull_vertex", 11)) + { + ret = GLEW_IBM_cull_vertex; + continue; + } +#endif +#ifdef GL_IBM_multimode_draw_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multimode_draw_arrays", 21)) + { + ret = GLEW_IBM_multimode_draw_arrays; + continue; + } +#endif +#ifdef GL_IBM_rasterpos_clip + if (_glewStrSame3(&pos, &len, (const GLubyte*)"rasterpos_clip", 14)) + { + ret = GLEW_IBM_rasterpos_clip; + continue; + } +#endif +#ifdef GL_IBM_static_data + if (_glewStrSame3(&pos, &len, (const GLubyte*)"static_data", 11)) + { + ret = GLEW_IBM_static_data; + continue; + } +#endif +#ifdef GL_IBM_texture_mirrored_repeat + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mirrored_repeat", 23)) + { + ret = GLEW_IBM_texture_mirrored_repeat; + continue; + } +#endif +#ifdef GL_IBM_vertex_array_lists + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_lists", 18)) + { + ret = GLEW_IBM_vertex_array_lists; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"INGR_", 5)) + { +#ifdef GL_INGR_color_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_clamp", 11)) + { + ret = GLEW_INGR_color_clamp; + continue; + } +#endif +#ifdef GL_INGR_interlace_read + if (_glewStrSame3(&pos, &len, (const GLubyte*)"interlace_read", 14)) + { + ret = GLEW_INGR_interlace_read; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"INTEL_", 6)) + { +#ifdef GL_INTEL_conservative_rasterization + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_rasterization", 26)) + { + ret = GLEW_INTEL_conservative_rasterization; + continue; + } +#endif +#ifdef GL_INTEL_fragment_shader_ordering + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader_ordering", 24)) + { + ret = GLEW_INTEL_fragment_shader_ordering; + continue; + } +#endif +#ifdef GL_INTEL_framebuffer_CMAA + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_CMAA", 16)) + { + ret = GLEW_INTEL_framebuffer_CMAA; + continue; + } +#endif +#ifdef GL_INTEL_map_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"map_texture", 11)) + { + ret = GLEW_INTEL_map_texture; + continue; + } +#endif +#ifdef GL_INTEL_parallel_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"parallel_arrays", 15)) + { + ret = GLEW_INTEL_parallel_arrays; + continue; + } +#endif +#ifdef GL_INTEL_performance_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"performance_query", 17)) + { + ret = GLEW_INTEL_performance_query; + continue; + } +#endif +#ifdef GL_INTEL_texture_scissor + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_scissor", 15)) + { + ret = GLEW_INTEL_texture_scissor; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"KHR_", 4)) + { +#ifdef GL_KHR_blend_equation_advanced + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced", 23)) + { + ret = GLEW_KHR_blend_equation_advanced; + continue; + } +#endif +#ifdef GL_KHR_blend_equation_advanced_coherent + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced_coherent", 32)) + { + ret = GLEW_KHR_blend_equation_advanced_coherent; + continue; + } +#endif +#ifdef GL_KHR_context_flush_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"context_flush_control", 21)) + { + ret = GLEW_KHR_context_flush_control; + continue; + } +#endif +#ifdef GL_KHR_debug + if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug", 5)) + { + ret = GLEW_KHR_debug; + continue; + } +#endif +#ifdef GL_KHR_no_error + if (_glewStrSame3(&pos, &len, (const GLubyte*)"no_error", 8)) + { + ret = GLEW_KHR_no_error; + continue; + } +#endif +#ifdef GL_KHR_parallel_shader_compile + if (_glewStrSame3(&pos, &len, (const GLubyte*)"parallel_shader_compile", 23)) + { + ret = GLEW_KHR_parallel_shader_compile; + continue; + } +#endif +#ifdef GL_KHR_robust_buffer_access_behavior + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robust_buffer_access_behavior", 29)) + { + ret = GLEW_KHR_robust_buffer_access_behavior; + continue; + } +#endif +#ifdef GL_KHR_robustness + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness", 10)) + { + ret = GLEW_KHR_robustness; + continue; + } +#endif +#ifdef GL_KHR_texture_compression_astc_hdr + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_astc_hdr", 28)) + { + ret = GLEW_KHR_texture_compression_astc_hdr; + continue; + } +#endif +#ifdef GL_KHR_texture_compression_astc_ldr + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_astc_ldr", 28)) + { + ret = GLEW_KHR_texture_compression_astc_ldr; + continue; + } +#endif +#ifdef GL_KHR_texture_compression_astc_sliced_3d + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_astc_sliced_3d", 34)) + { + ret = GLEW_KHR_texture_compression_astc_sliced_3d; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"KTX_", 4)) + { +#ifdef GL_KTX_buffer_region + if (_glewStrSame3(&pos, &len, (const GLubyte*)"buffer_region", 13)) + { + ret = GLEW_KTX_buffer_region; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"MESAX_", 6)) + { +#ifdef GL_MESAX_texture_stack + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_stack", 13)) + { + ret = GLEW_MESAX_texture_stack; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"MESA_", 5)) + { +#ifdef GL_MESA_pack_invert + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pack_invert", 11)) + { + ret = GLEW_MESA_pack_invert; + continue; + } +#endif +#ifdef GL_MESA_resize_buffers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"resize_buffers", 14)) + { + ret = GLEW_MESA_resize_buffers; + continue; + } +#endif +#ifdef GL_MESA_shader_integer_functions + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_integer_functions", 24)) + { + ret = GLEW_MESA_shader_integer_functions; + continue; + } +#endif +#ifdef GL_MESA_window_pos + if (_glewStrSame3(&pos, &len, (const GLubyte*)"window_pos", 10)) + { + ret = GLEW_MESA_window_pos; + continue; + } +#endif +#ifdef GL_MESA_ycbcr_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ycbcr_texture", 13)) + { + ret = GLEW_MESA_ycbcr_texture; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"NVX_", 4)) + { +#ifdef GL_NVX_blend_equation_advanced_multi_draw_buffers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced_multi_draw_buffers", 42)) + { + ret = GLEW_NVX_blend_equation_advanced_multi_draw_buffers; + continue; + } +#endif +#ifdef GL_NVX_conditional_render + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conditional_render", 18)) + { + ret = GLEW_NVX_conditional_render; + continue; + } +#endif +#ifdef GL_NVX_gpu_memory_info + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_memory_info", 15)) + { + ret = GLEW_NVX_gpu_memory_info; + continue; + } +#endif +#ifdef GL_NVX_linked_gpu_multicast + if (_glewStrSame3(&pos, &len, (const GLubyte*)"linked_gpu_multicast", 20)) + { + ret = GLEW_NVX_linked_gpu_multicast; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"NV_", 3)) + { +#ifdef GL_NV_3dvision_settings + if (_glewStrSame3(&pos, &len, (const GLubyte*)"3dvision_settings", 17)) + { + ret = GLEW_NV_3dvision_settings; + continue; + } +#endif +#ifdef GL_NV_EGL_stream_consumer_external + if (_glewStrSame3(&pos, &len, (const GLubyte*)"EGL_stream_consumer_external", 28)) + { + ret = GLEW_NV_EGL_stream_consumer_external; + continue; + } +#endif +#ifdef GL_NV_alpha_to_coverage_dither_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"alpha_to_coverage_dither_control", 32)) + { + ret = GLEW_NV_alpha_to_coverage_dither_control; + continue; + } +#endif +#ifdef GL_NV_bgr + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bgr", 3)) + { + ret = GLEW_NV_bgr; + continue; + } +#endif +#ifdef GL_NV_bindless_multi_draw_indirect + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_multi_draw_indirect", 28)) + { + ret = GLEW_NV_bindless_multi_draw_indirect; + continue; + } +#endif +#ifdef GL_NV_bindless_multi_draw_indirect_count + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_multi_draw_indirect_count", 34)) + { + ret = GLEW_NV_bindless_multi_draw_indirect_count; + continue; + } +#endif +#ifdef GL_NV_bindless_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_texture", 16)) + { + ret = GLEW_NV_bindless_texture; + continue; + } +#endif +#ifdef GL_NV_blend_equation_advanced + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced", 23)) + { + ret = GLEW_NV_blend_equation_advanced; + continue; + } +#endif +#ifdef GL_NV_blend_equation_advanced_coherent + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced_coherent", 32)) + { + ret = GLEW_NV_blend_equation_advanced_coherent; + continue; + } +#endif +#ifdef GL_NV_blend_minmax_factor + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_minmax_factor", 19)) + { + ret = GLEW_NV_blend_minmax_factor; + continue; + } +#endif +#ifdef GL_NV_blend_square + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_square", 12)) + { + ret = GLEW_NV_blend_square; + continue; + } +#endif +#ifdef GL_NV_clip_space_w_scaling + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clip_space_w_scaling", 20)) + { + ret = GLEW_NV_clip_space_w_scaling; + continue; + } +#endif +#ifdef GL_NV_command_list + if (_glewStrSame3(&pos, &len, (const GLubyte*)"command_list", 12)) + { + ret = GLEW_NV_command_list; + continue; + } +#endif +#ifdef GL_NV_compute_program5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compute_program5", 16)) + { + ret = GLEW_NV_compute_program5; + continue; + } +#endif +#ifdef GL_NV_conditional_render + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conditional_render", 18)) + { + ret = GLEW_NV_conditional_render; + continue; + } +#endif +#ifdef GL_NV_conservative_raster + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_raster", 19)) + { + ret = GLEW_NV_conservative_raster; + continue; + } +#endif +#ifdef GL_NV_conservative_raster_dilate + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_raster_dilate", 26)) + { + ret = GLEW_NV_conservative_raster_dilate; + continue; + } +#endif +#ifdef GL_NV_conservative_raster_pre_snap_triangles + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_raster_pre_snap_triangles", 38)) + { + ret = GLEW_NV_conservative_raster_pre_snap_triangles; + continue; + } +#endif +#ifdef GL_NV_copy_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_buffer", 11)) + { + ret = GLEW_NV_copy_buffer; + continue; + } +#endif +#ifdef GL_NV_copy_depth_to_color + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_depth_to_color", 19)) + { + ret = GLEW_NV_copy_depth_to_color; + continue; + } +#endif +#ifdef GL_NV_copy_image + if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_image", 10)) + { + ret = GLEW_NV_copy_image; + continue; + } +#endif +#ifdef GL_NV_deep_texture3D + if (_glewStrSame3(&pos, &len, (const GLubyte*)"deep_texture3D", 14)) + { + ret = GLEW_NV_deep_texture3D; + continue; + } +#endif +#ifdef GL_NV_depth_buffer_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_buffer_float", 18)) + { + ret = GLEW_NV_depth_buffer_float; + continue; + } +#endif +#ifdef GL_NV_depth_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_clamp", 11)) + { + ret = GLEW_NV_depth_clamp; + continue; + } +#endif +#ifdef GL_NV_depth_range_unclamped + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_range_unclamped", 21)) + { + ret = GLEW_NV_depth_range_unclamped; + continue; + } +#endif +#ifdef GL_NV_draw_buffers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers", 12)) + { + ret = GLEW_NV_draw_buffers; + continue; + } +#endif +#ifdef GL_NV_draw_instanced + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_instanced", 14)) + { + ret = GLEW_NV_draw_instanced; + continue; + } +#endif +#ifdef GL_NV_draw_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_texture", 12)) + { + ret = GLEW_NV_draw_texture; + continue; + } +#endif +#ifdef GL_NV_draw_vulkan_image + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_vulkan_image", 17)) + { + ret = GLEW_NV_draw_vulkan_image; + continue; + } +#endif +#ifdef GL_NV_evaluators + if (_glewStrSame3(&pos, &len, (const GLubyte*)"evaluators", 10)) + { + ret = GLEW_NV_evaluators; + continue; + } +#endif +#ifdef GL_NV_explicit_attrib_location + if (_glewStrSame3(&pos, &len, (const GLubyte*)"explicit_attrib_location", 24)) + { + ret = GLEW_NV_explicit_attrib_location; + continue; + } +#endif +#ifdef GL_NV_explicit_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"explicit_multisample", 20)) + { + ret = GLEW_NV_explicit_multisample; + continue; + } +#endif +#ifdef GL_NV_fbo_color_attachments + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fbo_color_attachments", 21)) + { + ret = GLEW_NV_fbo_color_attachments; + continue; + } +#endif +#ifdef GL_NV_fence + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fence", 5)) + { + ret = GLEW_NV_fence; + continue; + } +#endif +#ifdef GL_NV_fill_rectangle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fill_rectangle", 14)) + { + ret = GLEW_NV_fill_rectangle; + continue; + } +#endif +#ifdef GL_NV_float_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"float_buffer", 12)) + { + ret = GLEW_NV_float_buffer; + continue; + } +#endif +#ifdef GL_NV_fog_distance + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_distance", 12)) + { + ret = GLEW_NV_fog_distance; + continue; + } +#endif +#ifdef GL_NV_fragment_coverage_to_color + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_coverage_to_color", 26)) + { + ret = GLEW_NV_fragment_coverage_to_color; + continue; + } +#endif +#ifdef GL_NV_fragment_program + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_program", 16)) + { + ret = GLEW_NV_fragment_program; + continue; + } +#endif +#ifdef GL_NV_fragment_program2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_program2", 17)) + { + ret = GLEW_NV_fragment_program2; + continue; + } +#endif +#ifdef GL_NV_fragment_program4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_program4", 17)) + { + ret = GLEW_NV_fragment_program4; + continue; + } +#endif +#ifdef GL_NV_fragment_program_option + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_program_option", 23)) + { + ret = GLEW_NV_fragment_program_option; + continue; + } +#endif +#ifdef GL_NV_fragment_shader_interlock + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader_interlock", 25)) + { + ret = GLEW_NV_fragment_shader_interlock; + continue; + } +#endif +#ifdef GL_NV_framebuffer_blit + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_blit", 16)) + { + ret = GLEW_NV_framebuffer_blit; + continue; + } +#endif +#ifdef GL_NV_framebuffer_mixed_samples + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_mixed_samples", 25)) + { + ret = GLEW_NV_framebuffer_mixed_samples; + continue; + } +#endif +#ifdef GL_NV_framebuffer_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample", 23)) + { + ret = GLEW_NV_framebuffer_multisample; + continue; + } +#endif +#ifdef GL_NV_framebuffer_multisample_coverage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample_coverage", 32)) + { + ret = GLEW_NV_framebuffer_multisample_coverage; + continue; + } +#endif +#ifdef GL_NV_generate_mipmap_sRGB + if (_glewStrSame3(&pos, &len, (const GLubyte*)"generate_mipmap_sRGB", 20)) + { + ret = GLEW_NV_generate_mipmap_sRGB; + continue; + } +#endif +#ifdef GL_NV_geometry_program4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_program4", 17)) + { + ret = GLEW_NV_geometry_program4; + continue; + } +#endif +#ifdef GL_NV_geometry_shader4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_shader4", 16)) + { + ret = GLEW_NV_geometry_shader4; + continue; + } +#endif +#ifdef GL_NV_geometry_shader_passthrough + if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_shader_passthrough", 27)) + { + ret = GLEW_NV_geometry_shader_passthrough; + continue; + } +#endif +#ifdef GL_NV_gpu_multicast + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_multicast", 13)) + { + ret = GLEW_NV_gpu_multicast; + continue; + } +#endif +#ifdef GL_NV_gpu_program4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program4", 12)) + { + ret = GLEW_NV_gpu_program4; + continue; + } +#endif +#ifdef GL_NV_gpu_program5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program5", 12)) + { + ret = GLEW_NV_gpu_program5; + continue; + } +#endif +#ifdef GL_NV_gpu_program5_mem_extended + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program5_mem_extended", 25)) + { + ret = GLEW_NV_gpu_program5_mem_extended; + continue; + } +#endif +#ifdef GL_NV_gpu_program_fp64 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program_fp64", 16)) + { + ret = GLEW_NV_gpu_program_fp64; + continue; + } +#endif +#ifdef GL_NV_gpu_shader5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader5", 11)) + { + ret = GLEW_NV_gpu_shader5; + continue; + } +#endif +#ifdef GL_NV_half_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"half_float", 10)) + { + ret = GLEW_NV_half_float; + continue; + } +#endif +#ifdef GL_NV_image_formats + if (_glewStrSame3(&pos, &len, (const GLubyte*)"image_formats", 13)) + { + ret = GLEW_NV_image_formats; + continue; + } +#endif +#ifdef GL_NV_instanced_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"instanced_arrays", 16)) + { + ret = GLEW_NV_instanced_arrays; + continue; + } +#endif +#ifdef GL_NV_internalformat_sample_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"internalformat_sample_query", 27)) + { + ret = GLEW_NV_internalformat_sample_query; + continue; + } +#endif +#ifdef GL_NV_light_max_exponent + if (_glewStrSame3(&pos, &len, (const GLubyte*)"light_max_exponent", 18)) + { + ret = GLEW_NV_light_max_exponent; + continue; + } +#endif +#ifdef GL_NV_multisample_coverage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisample_coverage", 20)) + { + ret = GLEW_NV_multisample_coverage; + continue; + } +#endif +#ifdef GL_NV_multisample_filter_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisample_filter_hint", 23)) + { + ret = GLEW_NV_multisample_filter_hint; + continue; + } +#endif +#ifdef GL_NV_non_square_matrices + if (_glewStrSame3(&pos, &len, (const GLubyte*)"non_square_matrices", 19)) + { + ret = GLEW_NV_non_square_matrices; + continue; + } +#endif +#ifdef GL_NV_occlusion_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"occlusion_query", 15)) + { + ret = GLEW_NV_occlusion_query; + continue; + } +#endif +#ifdef GL_NV_pack_subimage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pack_subimage", 13)) + { + ret = GLEW_NV_pack_subimage; + continue; + } +#endif +#ifdef GL_NV_packed_depth_stencil + if (_glewStrSame3(&pos, &len, (const GLubyte*)"packed_depth_stencil", 20)) + { + ret = GLEW_NV_packed_depth_stencil; + continue; + } +#endif +#ifdef GL_NV_packed_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"packed_float", 12)) + { + ret = GLEW_NV_packed_float; + continue; + } +#endif +#ifdef GL_NV_packed_float_linear + if (_glewStrSame3(&pos, &len, (const GLubyte*)"packed_float_linear", 19)) + { + ret = GLEW_NV_packed_float_linear; + continue; + } +#endif +#ifdef GL_NV_parameter_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"parameter_buffer_object", 23)) + { + ret = GLEW_NV_parameter_buffer_object; + continue; + } +#endif +#ifdef GL_NV_parameter_buffer_object2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"parameter_buffer_object2", 24)) + { + ret = GLEW_NV_parameter_buffer_object2; + continue; + } +#endif +#ifdef GL_NV_path_rendering + if (_glewStrSame3(&pos, &len, (const GLubyte*)"path_rendering", 14)) + { + ret = GLEW_NV_path_rendering; + continue; + } +#endif +#ifdef GL_NV_path_rendering_shared_edge + if (_glewStrSame3(&pos, &len, (const GLubyte*)"path_rendering_shared_edge", 26)) + { + ret = GLEW_NV_path_rendering_shared_edge; + continue; + } +#endif +#ifdef GL_NV_pixel_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_buffer_object", 19)) + { + ret = GLEW_NV_pixel_buffer_object; + continue; + } +#endif +#ifdef GL_NV_pixel_data_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_data_range", 16)) + { + ret = GLEW_NV_pixel_data_range; + continue; + } +#endif +#ifdef GL_NV_platform_binary + if (_glewStrSame3(&pos, &len, (const GLubyte*)"platform_binary", 15)) + { + ret = GLEW_NV_platform_binary; + continue; + } +#endif +#ifdef GL_NV_point_sprite + if (_glewStrSame3(&pos, &len, (const GLubyte*)"point_sprite", 12)) + { + ret = GLEW_NV_point_sprite; + continue; + } +#endif +#ifdef GL_NV_polygon_mode + if (_glewStrSame3(&pos, &len, (const GLubyte*)"polygon_mode", 12)) + { + ret = GLEW_NV_polygon_mode; + continue; + } +#endif +#ifdef GL_NV_present_video + if (_glewStrSame3(&pos, &len, (const GLubyte*)"present_video", 13)) + { + ret = GLEW_NV_present_video; + continue; + } +#endif +#ifdef GL_NV_primitive_restart + if (_glewStrSame3(&pos, &len, (const GLubyte*)"primitive_restart", 17)) + { + ret = GLEW_NV_primitive_restart; + continue; + } +#endif +#ifdef GL_NV_read_depth + if (_glewStrSame3(&pos, &len, (const GLubyte*)"read_depth", 10)) + { + ret = GLEW_NV_read_depth; + continue; + } +#endif +#ifdef GL_NV_read_depth_stencil + if (_glewStrSame3(&pos, &len, (const GLubyte*)"read_depth_stencil", 18)) + { + ret = GLEW_NV_read_depth_stencil; + continue; + } +#endif +#ifdef GL_NV_read_stencil + if (_glewStrSame3(&pos, &len, (const GLubyte*)"read_stencil", 12)) + { + ret = GLEW_NV_read_stencil; + continue; + } +#endif +#ifdef GL_NV_register_combiners + if (_glewStrSame3(&pos, &len, (const GLubyte*)"register_combiners", 18)) + { + ret = GLEW_NV_register_combiners; + continue; + } +#endif +#ifdef GL_NV_register_combiners2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"register_combiners2", 19)) + { + ret = GLEW_NV_register_combiners2; + continue; + } +#endif +#ifdef GL_NV_robustness_video_memory_purge + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness_video_memory_purge", 29)) + { + ret = GLEW_NV_robustness_video_memory_purge; + continue; + } +#endif +#ifdef GL_NV_sRGB_formats + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sRGB_formats", 12)) + { + ret = GLEW_NV_sRGB_formats; + continue; + } +#endif +#ifdef GL_NV_sample_locations + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_locations", 16)) + { + ret = GLEW_NV_sample_locations; + continue; + } +#endif +#ifdef GL_NV_sample_mask_override_coverage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_mask_override_coverage", 29)) + { + ret = GLEW_NV_sample_mask_override_coverage; + continue; + } +#endif +#ifdef GL_NV_shader_atomic_counters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counters", 22)) + { + ret = GLEW_NV_shader_atomic_counters; + continue; + } +#endif +#ifdef GL_NV_shader_atomic_float + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_float", 19)) + { + ret = GLEW_NV_shader_atomic_float; + continue; + } +#endif +#ifdef GL_NV_shader_atomic_float64 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_float64", 21)) + { + ret = GLEW_NV_shader_atomic_float64; + continue; + } +#endif +#ifdef GL_NV_shader_atomic_fp16_vector + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_fp16_vector", 25)) + { + ret = GLEW_NV_shader_atomic_fp16_vector; + continue; + } +#endif +#ifdef GL_NV_shader_atomic_int64 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_int64", 19)) + { + ret = GLEW_NV_shader_atomic_int64; + continue; + } +#endif +#ifdef GL_NV_shader_buffer_load + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_buffer_load", 18)) + { + ret = GLEW_NV_shader_buffer_load; + continue; + } +#endif +#ifdef GL_NV_shader_noperspective_interpolation + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_noperspective_interpolation", 34)) + { + ret = GLEW_NV_shader_noperspective_interpolation; + continue; + } +#endif +#ifdef GL_NV_shader_storage_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_storage_buffer_object", 28)) + { + ret = GLEW_NV_shader_storage_buffer_object; + continue; + } +#endif +#ifdef GL_NV_shader_thread_group + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_thread_group", 19)) + { + ret = GLEW_NV_shader_thread_group; + continue; + } +#endif +#ifdef GL_NV_shader_thread_shuffle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_thread_shuffle", 21)) + { + ret = GLEW_NV_shader_thread_shuffle; + continue; + } +#endif +#ifdef GL_NV_shadow_samplers_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow_samplers_array", 21)) + { + ret = GLEW_NV_shadow_samplers_array; + continue; + } +#endif +#ifdef GL_NV_shadow_samplers_cube + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow_samplers_cube", 20)) + { + ret = GLEW_NV_shadow_samplers_cube; + continue; + } +#endif +#ifdef GL_NV_stereo_view_rendering + if (_glewStrSame3(&pos, &len, (const GLubyte*)"stereo_view_rendering", 21)) + { + ret = GLEW_NV_stereo_view_rendering; + continue; + } +#endif +#ifdef GL_NV_tessellation_program5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"tessellation_program5", 21)) + { + ret = GLEW_NV_tessellation_program5; + continue; + } +#endif +#ifdef GL_NV_texgen_emboss + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texgen_emboss", 13)) + { + ret = GLEW_NV_texgen_emboss; + continue; + } +#endif +#ifdef GL_NV_texgen_reflection + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texgen_reflection", 17)) + { + ret = GLEW_NV_texgen_reflection; + continue; + } +#endif +#ifdef GL_NV_texture_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_array", 13)) + { + ret = GLEW_NV_texture_array; + continue; + } +#endif +#ifdef GL_NV_texture_barrier + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_barrier", 15)) + { + ret = GLEW_NV_texture_barrier; + continue; + } +#endif +#ifdef GL_NV_texture_border_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_border_clamp", 20)) + { + ret = GLEW_NV_texture_border_clamp; + continue; + } +#endif +#ifdef GL_NV_texture_compression_latc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_latc", 24)) + { + ret = GLEW_NV_texture_compression_latc; + continue; + } +#endif +#ifdef GL_NV_texture_compression_s3tc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_s3tc", 24)) + { + ret = GLEW_NV_texture_compression_s3tc; + continue; + } +#endif +#ifdef GL_NV_texture_compression_s3tc_update + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_s3tc_update", 31)) + { + ret = GLEW_NV_texture_compression_s3tc_update; + continue; + } +#endif +#ifdef GL_NV_texture_compression_vtc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_vtc", 23)) + { + ret = GLEW_NV_texture_compression_vtc; + continue; + } +#endif +#ifdef GL_NV_texture_env_combine4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_env_combine4", 20)) + { + ret = GLEW_NV_texture_env_combine4; + continue; + } +#endif +#ifdef GL_NV_texture_expand_normal + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_expand_normal", 21)) + { + ret = GLEW_NV_texture_expand_normal; + continue; + } +#endif +#ifdef GL_NV_texture_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_multisample", 19)) + { + ret = GLEW_NV_texture_multisample; + continue; + } +#endif +#ifdef GL_NV_texture_npot_2D_mipmap + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_npot_2D_mipmap", 22)) + { + ret = GLEW_NV_texture_npot_2D_mipmap; + continue; + } +#endif +#ifdef GL_NV_texture_rectangle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_rectangle", 17)) + { + ret = GLEW_NV_texture_rectangle; + continue; + } +#endif +#ifdef GL_NV_texture_rectangle_compressed + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_rectangle_compressed", 28)) + { + ret = GLEW_NV_texture_rectangle_compressed; + continue; + } +#endif +#ifdef GL_NV_texture_shader + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_shader", 14)) + { + ret = GLEW_NV_texture_shader; + continue; + } +#endif +#ifdef GL_NV_texture_shader2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_shader2", 15)) + { + ret = GLEW_NV_texture_shader2; + continue; + } +#endif +#ifdef GL_NV_texture_shader3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_shader3", 15)) + { + ret = GLEW_NV_texture_shader3; + continue; + } +#endif +#ifdef GL_NV_transform_feedback + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback", 18)) + { + ret = GLEW_NV_transform_feedback; + continue; + } +#endif +#ifdef GL_NV_transform_feedback2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback2", 19)) + { + ret = GLEW_NV_transform_feedback2; + continue; + } +#endif +#ifdef GL_NV_uniform_buffer_unified_memory + if (_glewStrSame3(&pos, &len, (const GLubyte*)"uniform_buffer_unified_memory", 29)) + { + ret = GLEW_NV_uniform_buffer_unified_memory; + continue; + } +#endif +#ifdef GL_NV_vdpau_interop + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vdpau_interop", 13)) + { + ret = GLEW_NV_vdpau_interop; + continue; + } +#endif +#ifdef GL_NV_vertex_array_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_range", 18)) + { + ret = GLEW_NV_vertex_array_range; + continue; + } +#endif +#ifdef GL_NV_vertex_array_range2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_range2", 19)) + { + ret = GLEW_NV_vertex_array_range2; + continue; + } +#endif +#ifdef GL_NV_vertex_attrib_integer_64bit + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_attrib_integer_64bit", 27)) + { + ret = GLEW_NV_vertex_attrib_integer_64bit; + continue; + } +#endif +#ifdef GL_NV_vertex_buffer_unified_memory + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_buffer_unified_memory", 28)) + { + ret = GLEW_NV_vertex_buffer_unified_memory; + continue; + } +#endif +#ifdef GL_NV_vertex_program + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program", 14)) + { + ret = GLEW_NV_vertex_program; + continue; + } +#endif +#ifdef GL_NV_vertex_program1_1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program1_1", 17)) + { + ret = GLEW_NV_vertex_program1_1; + continue; + } +#endif +#ifdef GL_NV_vertex_program2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program2", 15)) + { + ret = GLEW_NV_vertex_program2; + continue; + } +#endif +#ifdef GL_NV_vertex_program2_option + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program2_option", 22)) + { + ret = GLEW_NV_vertex_program2_option; + continue; + } +#endif +#ifdef GL_NV_vertex_program3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program3", 15)) + { + ret = GLEW_NV_vertex_program3; + continue; + } +#endif +#ifdef GL_NV_vertex_program4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_program4", 15)) + { + ret = GLEW_NV_vertex_program4; + continue; + } +#endif +#ifdef GL_NV_video_capture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"video_capture", 13)) + { + ret = GLEW_NV_video_capture; + continue; + } +#endif +#ifdef GL_NV_viewport_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"viewport_array", 14)) + { + ret = GLEW_NV_viewport_array; + continue; + } +#endif +#ifdef GL_NV_viewport_array2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"viewport_array2", 15)) + { + ret = GLEW_NV_viewport_array2; + continue; + } +#endif +#ifdef GL_NV_viewport_swizzle + if (_glewStrSame3(&pos, &len, (const GLubyte*)"viewport_swizzle", 16)) + { + ret = GLEW_NV_viewport_swizzle; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"OES_", 4)) + { +#ifdef GL_OES_byte_coordinates + if (_glewStrSame3(&pos, &len, (const GLubyte*)"byte_coordinates", 16)) + { + ret = GLEW_OES_byte_coordinates; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"OML_", 4)) + { +#ifdef GL_OML_interlace + if (_glewStrSame3(&pos, &len, (const GLubyte*)"interlace", 9)) + { + ret = GLEW_OML_interlace; + continue; + } +#endif +#ifdef GL_OML_resample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"resample", 8)) + { + ret = GLEW_OML_resample; + continue; + } +#endif +#ifdef GL_OML_subsample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"subsample", 9)) + { + ret = GLEW_OML_subsample; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"OVR_", 4)) + { +#ifdef GL_OVR_multiview + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multiview", 9)) + { + ret = GLEW_OVR_multiview; + continue; + } +#endif +#ifdef GL_OVR_multiview2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multiview2", 10)) + { + ret = GLEW_OVR_multiview2; + continue; + } +#endif +#ifdef GL_OVR_multiview_multisampled_render_to_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multiview_multisampled_render_to_texture", 40)) + { + ret = GLEW_OVR_multiview_multisampled_render_to_texture; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"PGI_", 4)) + { +#ifdef GL_PGI_misc_hints + if (_glewStrSame3(&pos, &len, (const GLubyte*)"misc_hints", 10)) + { + ret = GLEW_PGI_misc_hints; + continue; + } +#endif +#ifdef GL_PGI_vertex_hints + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_hints", 12)) + { + ret = GLEW_PGI_vertex_hints; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"QCOM_", 5)) + { +#ifdef GL_QCOM_alpha_test + if (_glewStrSame3(&pos, &len, (const GLubyte*)"alpha_test", 10)) + { + ret = GLEW_QCOM_alpha_test; + continue; + } +#endif +#ifdef GL_QCOM_binning_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"binning_control", 15)) + { + ret = GLEW_QCOM_binning_control; + continue; + } +#endif +#ifdef GL_QCOM_driver_control + if (_glewStrSame3(&pos, &len, (const GLubyte*)"driver_control", 14)) + { + ret = GLEW_QCOM_driver_control; + continue; + } +#endif +#ifdef GL_QCOM_extended_get + if (_glewStrSame3(&pos, &len, (const GLubyte*)"extended_get", 12)) + { + ret = GLEW_QCOM_extended_get; + continue; + } +#endif +#ifdef GL_QCOM_extended_get2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"extended_get2", 13)) + { + ret = GLEW_QCOM_extended_get2; + continue; + } +#endif +#ifdef GL_QCOM_framebuffer_foveated + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_foveated", 20)) + { + ret = GLEW_QCOM_framebuffer_foveated; + continue; + } +#endif +#ifdef GL_QCOM_perfmon_global_mode + if (_glewStrSame3(&pos, &len, (const GLubyte*)"perfmon_global_mode", 19)) + { + ret = GLEW_QCOM_perfmon_global_mode; + continue; + } +#endif +#ifdef GL_QCOM_shader_framebuffer_fetch_noncoherent + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_framebuffer_fetch_noncoherent", 36)) + { + ret = GLEW_QCOM_shader_framebuffer_fetch_noncoherent; + continue; + } +#endif +#ifdef GL_QCOM_tiled_rendering + if (_glewStrSame3(&pos, &len, (const GLubyte*)"tiled_rendering", 15)) + { + ret = GLEW_QCOM_tiled_rendering; + continue; + } +#endif +#ifdef GL_QCOM_writeonly_rendering + if (_glewStrSame3(&pos, &len, (const GLubyte*)"writeonly_rendering", 19)) + { + ret = GLEW_QCOM_writeonly_rendering; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"REGAL_", 6)) + { +#ifdef GL_REGAL_ES1_0_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES1_0_compatibility", 19)) + { + ret = GLEW_REGAL_ES1_0_compatibility; + continue; + } +#endif +#ifdef GL_REGAL_ES1_1_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES1_1_compatibility", 19)) + { + ret = GLEW_REGAL_ES1_1_compatibility; + continue; + } +#endif +#ifdef GL_REGAL_enable + if (_glewStrSame3(&pos, &len, (const GLubyte*)"enable", 6)) + { + ret = GLEW_REGAL_enable; + continue; + } +#endif +#ifdef GL_REGAL_error_string + if (_glewStrSame3(&pos, &len, (const GLubyte*)"error_string", 12)) + { + ret = GLEW_REGAL_error_string; + continue; + } +#endif +#ifdef GL_REGAL_extension_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"extension_query", 15)) + { + ret = GLEW_REGAL_extension_query; + continue; + } +#endif +#ifdef GL_REGAL_log + if (_glewStrSame3(&pos, &len, (const GLubyte*)"log", 3)) + { + ret = GLEW_REGAL_log; + continue; + } +#endif +#ifdef GL_REGAL_proc_address + if (_glewStrSame3(&pos, &len, (const GLubyte*)"proc_address", 12)) + { + ret = GLEW_REGAL_proc_address; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"REND_", 5)) + { +#ifdef GL_REND_screen_coordinates + if (_glewStrSame3(&pos, &len, (const GLubyte*)"screen_coordinates", 18)) + { + ret = GLEW_REND_screen_coordinates; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"S3_", 3)) + { +#ifdef GL_S3_s3tc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"s3tc", 4)) + { + ret = GLEW_S3_s3tc; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"SGIS_", 5)) + { +#ifdef GL_SGIS_clip_band_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clip_band_hint", 14)) + { + ret = GLEW_SGIS_clip_band_hint; + continue; + } +#endif +#ifdef GL_SGIS_color_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_range", 11)) + { + ret = GLEW_SGIS_color_range; + continue; + } +#endif +#ifdef GL_SGIS_detail_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"detail_texture", 14)) + { + ret = GLEW_SGIS_detail_texture; + continue; + } +#endif +#ifdef GL_SGIS_fog_function + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_function", 12)) + { + ret = GLEW_SGIS_fog_function; + continue; + } +#endif +#ifdef GL_SGIS_generate_mipmap + if (_glewStrSame3(&pos, &len, (const GLubyte*)"generate_mipmap", 15)) + { + ret = GLEW_SGIS_generate_mipmap; + continue; + } +#endif +#ifdef GL_SGIS_line_texgen + if (_glewStrSame3(&pos, &len, (const GLubyte*)"line_texgen", 11)) + { + ret = GLEW_SGIS_line_texgen; + continue; + } +#endif +#ifdef GL_SGIS_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multisample", 11)) + { + ret = GLEW_SGIS_multisample; + continue; + } +#endif +#ifdef GL_SGIS_multitexture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multitexture", 12)) + { + ret = GLEW_SGIS_multitexture; + continue; + } +#endif +#ifdef GL_SGIS_pixel_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_texture", 13)) + { + ret = GLEW_SGIS_pixel_texture; + continue; + } +#endif +#ifdef GL_SGIS_point_line_texgen + if (_glewStrSame3(&pos, &len, (const GLubyte*)"point_line_texgen", 17)) + { + ret = GLEW_SGIS_point_line_texgen; + continue; + } +#endif +#ifdef GL_SGIS_shared_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shared_multisample", 18)) + { + ret = GLEW_SGIS_shared_multisample; + continue; + } +#endif +#ifdef GL_SGIS_sharpen_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sharpen_texture", 15)) + { + ret = GLEW_SGIS_sharpen_texture; + continue; + } +#endif +#ifdef GL_SGIS_texture4D + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture4D", 9)) + { + ret = GLEW_SGIS_texture4D; + continue; + } +#endif +#ifdef GL_SGIS_texture_border_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_border_clamp", 20)) + { + ret = GLEW_SGIS_texture_border_clamp; + continue; + } +#endif +#ifdef GL_SGIS_texture_edge_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_edge_clamp", 18)) + { + ret = GLEW_SGIS_texture_edge_clamp; + continue; + } +#endif +#ifdef GL_SGIS_texture_filter4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_filter4", 15)) + { + ret = GLEW_SGIS_texture_filter4; + continue; + } +#endif +#ifdef GL_SGIS_texture_lod + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_lod", 11)) + { + ret = GLEW_SGIS_texture_lod; + continue; + } +#endif +#ifdef GL_SGIS_texture_select + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_select", 14)) + { + ret = GLEW_SGIS_texture_select; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"SGIX_", 5)) + { +#ifdef GL_SGIX_async + if (_glewStrSame3(&pos, &len, (const GLubyte*)"async", 5)) + { + ret = GLEW_SGIX_async; + continue; + } +#endif +#ifdef GL_SGIX_async_histogram + if (_glewStrSame3(&pos, &len, (const GLubyte*)"async_histogram", 15)) + { + ret = GLEW_SGIX_async_histogram; + continue; + } +#endif +#ifdef GL_SGIX_async_pixel + if (_glewStrSame3(&pos, &len, (const GLubyte*)"async_pixel", 11)) + { + ret = GLEW_SGIX_async_pixel; + continue; + } +#endif +#ifdef GL_SGIX_bali_g_instruments + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bali_g_instruments", 18)) + { + ret = GLEW_SGIX_bali_g_instruments; + continue; + } +#endif +#ifdef GL_SGIX_bali_r_instruments + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bali_r_instruments", 18)) + { + ret = GLEW_SGIX_bali_r_instruments; + continue; + } +#endif +#ifdef GL_SGIX_bali_timer_instruments + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bali_timer_instruments", 22)) + { + ret = GLEW_SGIX_bali_timer_instruments; + continue; + } +#endif +#ifdef GL_SGIX_blend_alpha_minmax + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_alpha_minmax", 18)) + { + ret = GLEW_SGIX_blend_alpha_minmax; + continue; + } +#endif +#ifdef GL_SGIX_blend_cadd + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_cadd", 10)) + { + ret = GLEW_SGIX_blend_cadd; + continue; + } +#endif +#ifdef GL_SGIX_blend_cmultiply + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_cmultiply", 15)) + { + ret = GLEW_SGIX_blend_cmultiply; + continue; + } +#endif +#ifdef GL_SGIX_calligraphic_fragment + if (_glewStrSame3(&pos, &len, (const GLubyte*)"calligraphic_fragment", 21)) + { + ret = GLEW_SGIX_calligraphic_fragment; + continue; + } +#endif +#ifdef GL_SGIX_clipmap + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clipmap", 7)) + { + ret = GLEW_SGIX_clipmap; + continue; + } +#endif +#ifdef GL_SGIX_color_matrix_accuracy + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_matrix_accuracy", 21)) + { + ret = GLEW_SGIX_color_matrix_accuracy; + continue; + } +#endif +#ifdef GL_SGIX_color_table_index_mode + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_table_index_mode", 22)) + { + ret = GLEW_SGIX_color_table_index_mode; + continue; + } +#endif +#ifdef GL_SGIX_complex_polar + if (_glewStrSame3(&pos, &len, (const GLubyte*)"complex_polar", 13)) + { + ret = GLEW_SGIX_complex_polar; + continue; + } +#endif +#ifdef GL_SGIX_convolution_accuracy + if (_glewStrSame3(&pos, &len, (const GLubyte*)"convolution_accuracy", 20)) + { + ret = GLEW_SGIX_convolution_accuracy; + continue; + } +#endif +#ifdef GL_SGIX_cube_map + if (_glewStrSame3(&pos, &len, (const GLubyte*)"cube_map", 8)) + { + ret = GLEW_SGIX_cube_map; + continue; + } +#endif +#ifdef GL_SGIX_cylinder_texgen + if (_glewStrSame3(&pos, &len, (const GLubyte*)"cylinder_texgen", 15)) + { + ret = GLEW_SGIX_cylinder_texgen; + continue; + } +#endif +#ifdef GL_SGIX_datapipe + if (_glewStrSame3(&pos, &len, (const GLubyte*)"datapipe", 8)) + { + ret = GLEW_SGIX_datapipe; + continue; + } +#endif +#ifdef GL_SGIX_decimation + if (_glewStrSame3(&pos, &len, (const GLubyte*)"decimation", 10)) + { + ret = GLEW_SGIX_decimation; + continue; + } +#endif +#ifdef GL_SGIX_depth_pass_instrument + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_pass_instrument", 21)) + { + ret = GLEW_SGIX_depth_pass_instrument; + continue; + } +#endif +#ifdef GL_SGIX_depth_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_texture", 13)) + { + ret = GLEW_SGIX_depth_texture; + continue; + } +#endif +#ifdef GL_SGIX_dvc + if (_glewStrSame3(&pos, &len, (const GLubyte*)"dvc", 3)) + { + ret = GLEW_SGIX_dvc; + continue; + } +#endif +#ifdef GL_SGIX_flush_raster + if (_glewStrSame3(&pos, &len, (const GLubyte*)"flush_raster", 12)) + { + ret = GLEW_SGIX_flush_raster; + continue; + } +#endif +#ifdef GL_SGIX_fog_blend + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_blend", 9)) + { + ret = GLEW_SGIX_fog_blend; + continue; + } +#endif +#ifdef GL_SGIX_fog_factor_to_alpha + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_factor_to_alpha", 19)) + { + ret = GLEW_SGIX_fog_factor_to_alpha; + continue; + } +#endif +#ifdef GL_SGIX_fog_layers + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_layers", 10)) + { + ret = GLEW_SGIX_fog_layers; + continue; + } +#endif +#ifdef GL_SGIX_fog_offset + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_offset", 10)) + { + ret = GLEW_SGIX_fog_offset; + continue; + } +#endif +#ifdef GL_SGIX_fog_patchy + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_patchy", 10)) + { + ret = GLEW_SGIX_fog_patchy; + continue; + } +#endif +#ifdef GL_SGIX_fog_scale + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_scale", 9)) + { + ret = GLEW_SGIX_fog_scale; + continue; + } +#endif +#ifdef GL_SGIX_fog_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fog_texture", 11)) + { + ret = GLEW_SGIX_fog_texture; + continue; + } +#endif +#ifdef GL_SGIX_fragment_lighting_space + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_lighting_space", 23)) + { + ret = GLEW_SGIX_fragment_lighting_space; + continue; + } +#endif +#ifdef GL_SGIX_fragment_specular_lighting + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_specular_lighting", 26)) + { + ret = GLEW_SGIX_fragment_specular_lighting; + continue; + } +#endif +#ifdef GL_SGIX_fragments_instrument + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragments_instrument", 20)) + { + ret = GLEW_SGIX_fragments_instrument; + continue; + } +#endif +#ifdef GL_SGIX_framezoom + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framezoom", 9)) + { + ret = GLEW_SGIX_framezoom; + continue; + } +#endif +#ifdef GL_SGIX_icc_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"icc_texture", 11)) + { + ret = GLEW_SGIX_icc_texture; + continue; + } +#endif +#ifdef GL_SGIX_igloo_interface + if (_glewStrSame3(&pos, &len, (const GLubyte*)"igloo_interface", 15)) + { + ret = GLEW_SGIX_igloo_interface; + continue; + } +#endif +#ifdef GL_SGIX_image_compression + if (_glewStrSame3(&pos, &len, (const GLubyte*)"image_compression", 17)) + { + ret = GLEW_SGIX_image_compression; + continue; + } +#endif +#ifdef GL_SGIX_impact_pixel_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"impact_pixel_texture", 20)) + { + ret = GLEW_SGIX_impact_pixel_texture; + continue; + } +#endif +#ifdef GL_SGIX_instrument_error + if (_glewStrSame3(&pos, &len, (const GLubyte*)"instrument_error", 16)) + { + ret = GLEW_SGIX_instrument_error; + continue; + } +#endif +#ifdef GL_SGIX_interlace + if (_glewStrSame3(&pos, &len, (const GLubyte*)"interlace", 9)) + { + ret = GLEW_SGIX_interlace; + continue; + } +#endif +#ifdef GL_SGIX_ir_instrument1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ir_instrument1", 14)) + { + ret = GLEW_SGIX_ir_instrument1; + continue; + } +#endif +#ifdef GL_SGIX_line_quality_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"line_quality_hint", 17)) + { + ret = GLEW_SGIX_line_quality_hint; + continue; + } +#endif +#ifdef GL_SGIX_list_priority + if (_glewStrSame3(&pos, &len, (const GLubyte*)"list_priority", 13)) + { + ret = GLEW_SGIX_list_priority; + continue; + } +#endif +#ifdef GL_SGIX_mpeg1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"mpeg1", 5)) + { + ret = GLEW_SGIX_mpeg1; + continue; + } +#endif +#ifdef GL_SGIX_mpeg2 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"mpeg2", 5)) + { + ret = GLEW_SGIX_mpeg2; + continue; + } +#endif +#ifdef GL_SGIX_nonlinear_lighting_pervertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"nonlinear_lighting_pervertex", 28)) + { + ret = GLEW_SGIX_nonlinear_lighting_pervertex; + continue; + } +#endif +#ifdef GL_SGIX_nurbs_eval + if (_glewStrSame3(&pos, &len, (const GLubyte*)"nurbs_eval", 10)) + { + ret = GLEW_SGIX_nurbs_eval; + continue; + } +#endif +#ifdef GL_SGIX_occlusion_instrument + if (_glewStrSame3(&pos, &len, (const GLubyte*)"occlusion_instrument", 20)) + { + ret = GLEW_SGIX_occlusion_instrument; + continue; + } +#endif +#ifdef GL_SGIX_packed_6bytes + if (_glewStrSame3(&pos, &len, (const GLubyte*)"packed_6bytes", 13)) + { + ret = GLEW_SGIX_packed_6bytes; + continue; + } +#endif +#ifdef GL_SGIX_pixel_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_texture", 13)) + { + ret = GLEW_SGIX_pixel_texture; + continue; + } +#endif +#ifdef GL_SGIX_pixel_texture_bits + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_texture_bits", 18)) + { + ret = GLEW_SGIX_pixel_texture_bits; + continue; + } +#endif +#ifdef GL_SGIX_pixel_texture_lod + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_texture_lod", 17)) + { + ret = GLEW_SGIX_pixel_texture_lod; + continue; + } +#endif +#ifdef GL_SGIX_pixel_tiles + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_tiles", 11)) + { + ret = GLEW_SGIX_pixel_tiles; + continue; + } +#endif +#ifdef GL_SGIX_polynomial_ffd + if (_glewStrSame3(&pos, &len, (const GLubyte*)"polynomial_ffd", 14)) + { + ret = GLEW_SGIX_polynomial_ffd; + continue; + } +#endif +#ifdef GL_SGIX_quad_mesh + if (_glewStrSame3(&pos, &len, (const GLubyte*)"quad_mesh", 9)) + { + ret = GLEW_SGIX_quad_mesh; + continue; + } +#endif +#ifdef GL_SGIX_reference_plane + if (_glewStrSame3(&pos, &len, (const GLubyte*)"reference_plane", 15)) + { + ret = GLEW_SGIX_reference_plane; + continue; + } +#endif +#ifdef GL_SGIX_resample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"resample", 8)) + { + ret = GLEW_SGIX_resample; + continue; + } +#endif +#ifdef GL_SGIX_scalebias_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"scalebias_hint", 14)) + { + ret = GLEW_SGIX_scalebias_hint; + continue; + } +#endif +#ifdef GL_SGIX_shadow + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow", 6)) + { + ret = GLEW_SGIX_shadow; + continue; + } +#endif +#ifdef GL_SGIX_shadow_ambient + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow_ambient", 14)) + { + ret = GLEW_SGIX_shadow_ambient; + continue; + } +#endif +#ifdef GL_SGIX_slim + if (_glewStrSame3(&pos, &len, (const GLubyte*)"slim", 4)) + { + ret = GLEW_SGIX_slim; + continue; + } +#endif +#ifdef GL_SGIX_spotlight_cutoff + if (_glewStrSame3(&pos, &len, (const GLubyte*)"spotlight_cutoff", 16)) + { + ret = GLEW_SGIX_spotlight_cutoff; + continue; + } +#endif +#ifdef GL_SGIX_sprite + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sprite", 6)) + { + ret = GLEW_SGIX_sprite; + continue; + } +#endif +#ifdef GL_SGIX_subdiv_patch + if (_glewStrSame3(&pos, &len, (const GLubyte*)"subdiv_patch", 12)) + { + ret = GLEW_SGIX_subdiv_patch; + continue; + } +#endif +#ifdef GL_SGIX_subsample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"subsample", 9)) + { + ret = GLEW_SGIX_subsample; + continue; + } +#endif +#ifdef GL_SGIX_tag_sample_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"tag_sample_buffer", 17)) + { + ret = GLEW_SGIX_tag_sample_buffer; + continue; + } +#endif +#ifdef GL_SGIX_texture_add_env + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_add_env", 15)) + { + ret = GLEW_SGIX_texture_add_env; + continue; + } +#endif +#ifdef GL_SGIX_texture_coordinate_clamp + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_coordinate_clamp", 24)) + { + ret = GLEW_SGIX_texture_coordinate_clamp; + continue; + } +#endif +#ifdef GL_SGIX_texture_lod_bias + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_lod_bias", 16)) + { + ret = GLEW_SGIX_texture_lod_bias; + continue; + } +#endif +#ifdef GL_SGIX_texture_mipmap_anisotropic + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mipmap_anisotropic", 26)) + { + ret = GLEW_SGIX_texture_mipmap_anisotropic; + continue; + } +#endif +#ifdef GL_SGIX_texture_multi_buffer + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_multi_buffer", 20)) + { + ret = GLEW_SGIX_texture_multi_buffer; + continue; + } +#endif +#ifdef GL_SGIX_texture_phase + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_phase", 13)) + { + ret = GLEW_SGIX_texture_phase; + continue; + } +#endif +#ifdef GL_SGIX_texture_range + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_range", 13)) + { + ret = GLEW_SGIX_texture_range; + continue; + } +#endif +#ifdef GL_SGIX_texture_scale_bias + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_scale_bias", 18)) + { + ret = GLEW_SGIX_texture_scale_bias; + continue; + } +#endif +#ifdef GL_SGIX_texture_supersample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_supersample", 19)) + { + ret = GLEW_SGIX_texture_supersample; + continue; + } +#endif +#ifdef GL_SGIX_vector_ops + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vector_ops", 10)) + { + ret = GLEW_SGIX_vector_ops; + continue; + } +#endif +#ifdef GL_SGIX_vertex_array_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_array_object", 19)) + { + ret = GLEW_SGIX_vertex_array_object; + continue; + } +#endif +#ifdef GL_SGIX_vertex_preclip + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_preclip", 14)) + { + ret = GLEW_SGIX_vertex_preclip; + continue; + } +#endif +#ifdef GL_SGIX_vertex_preclip_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_preclip_hint", 19)) + { + ret = GLEW_SGIX_vertex_preclip_hint; + continue; + } +#endif +#ifdef GL_SGIX_ycrcb + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ycrcb", 5)) + { + ret = GLEW_SGIX_ycrcb; + continue; + } +#endif +#ifdef GL_SGIX_ycrcb_subsample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ycrcb_subsample", 15)) + { + ret = GLEW_SGIX_ycrcb_subsample; + continue; + } +#endif +#ifdef GL_SGIX_ycrcba + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ycrcba", 6)) + { + ret = GLEW_SGIX_ycrcba; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"SGI_", 4)) + { +#ifdef GL_SGI_color_matrix + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_matrix", 12)) + { + ret = GLEW_SGI_color_matrix; + continue; + } +#endif +#ifdef GL_SGI_color_table + if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_table", 11)) + { + ret = GLEW_SGI_color_table; + continue; + } +#endif +#ifdef GL_SGI_complex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"complex", 7)) + { + ret = GLEW_SGI_complex; + continue; + } +#endif +#ifdef GL_SGI_complex_type + if (_glewStrSame3(&pos, &len, (const GLubyte*)"complex_type", 12)) + { + ret = GLEW_SGI_complex_type; + continue; + } +#endif +#ifdef GL_SGI_fft + if (_glewStrSame3(&pos, &len, (const GLubyte*)"fft", 3)) + { + ret = GLEW_SGI_fft; + continue; + } +#endif +#ifdef GL_SGI_texture_color_table + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_color_table", 19)) + { + ret = GLEW_SGI_texture_color_table; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"SUNX_", 5)) + { +#ifdef GL_SUNX_constant_data + if (_glewStrSame3(&pos, &len, (const GLubyte*)"constant_data", 13)) + { + ret = GLEW_SUNX_constant_data; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"SUN_", 4)) + { +#ifdef GL_SUN_convolution_border_modes + if (_glewStrSame3(&pos, &len, (const GLubyte*)"convolution_border_modes", 24)) + { + ret = GLEW_SUN_convolution_border_modes; + continue; + } +#endif +#ifdef GL_SUN_global_alpha + if (_glewStrSame3(&pos, &len, (const GLubyte*)"global_alpha", 12)) + { + ret = GLEW_SUN_global_alpha; + continue; + } +#endif +#ifdef GL_SUN_mesh_array + if (_glewStrSame3(&pos, &len, (const GLubyte*)"mesh_array", 10)) + { + ret = GLEW_SUN_mesh_array; + continue; + } +#endif +#ifdef GL_SUN_read_video_pixels + if (_glewStrSame3(&pos, &len, (const GLubyte*)"read_video_pixels", 17)) + { + ret = GLEW_SUN_read_video_pixels; + continue; + } +#endif +#ifdef GL_SUN_slice_accum + if (_glewStrSame3(&pos, &len, (const GLubyte*)"slice_accum", 11)) + { + ret = GLEW_SUN_slice_accum; + continue; + } +#endif +#ifdef GL_SUN_triangle_list + if (_glewStrSame3(&pos, &len, (const GLubyte*)"triangle_list", 13)) + { + ret = GLEW_SUN_triangle_list; + continue; + } +#endif +#ifdef GL_SUN_vertex + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex", 6)) + { + ret = GLEW_SUN_vertex; + continue; + } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"WIN_", 4)) + { +#ifdef GL_WIN_phong_shading + if (_glewStrSame3(&pos, &len, (const GLubyte*)"phong_shading", 13)) + { + ret = GLEW_WIN_phong_shading; + continue; + } +#endif +#ifdef GL_WIN_scene_markerXXX + if (_glewStrSame3(&pos, &len, (const GLubyte*)"scene_markerXXX", 15)) + { + ret = GLEW_WIN_scene_markerXXX; + continue; + } +#endif +#ifdef GL_WIN_specular_fog + if (_glewStrSame3(&pos, &len, (const GLubyte*)"specular_fog", 12)) + { + ret = GLEW_WIN_specular_fog; + continue; + } +#endif +#ifdef GL_WIN_swap_hint + if (_glewStrSame3(&pos, &len, (const GLubyte*)"swap_hint", 9)) + { + ret = GLEW_WIN_swap_hint; + continue; + } +#endif + } + } + ret = (len == 0); + } + return ret; +} diff --git a/libretro/jni/Android.mk b/libretro/jni/Android.mk index e9b773c024..f5703ba4c4 100644 --- a/libretro/jni/Android.mk +++ b/libretro/jni/Android.mk @@ -9,6 +9,7 @@ COREFLAGS := CORE_DIR := ../.. FFMPEGDIR := $(CORE_DIR)/ffmpeg FFMPEGLIBS += libavformat libavcodec libavutil libswresample libswscale +WITH_DYNAREC := 1 ifeq ($(TARGET_ARCH),arm64) COREFLAGS += -DARM64 -D_ARCH_64 @@ -71,7 +72,7 @@ LOCAL_MODULE := retro include $(CORE_DIR)/libretro/Makefile.common -COREFLAGS += -DINLINE="inline" -DPPSSPP -DUSE_FFMPEG -DMOBILE_DEVICE -DBAKE_IN_GIT -DDYNAREC -D__LIBRETRO__ -DUSING_GLES2 -D__STDC_CONSTANT_MACROS -DGLEW_NO_GLU $(INCFLAGS) +COREFLAGS += -DINLINE="inline" -DPPSSPP -DUSE_FFMPEG -DMOBILE_DEVICE -DBAKE_IN_GIT -DDYNAREC -D__LIBRETRO__ -DUSING_GLES2 -D__STDC_CONSTANT_MACROS -DGLEW_NO_GLU -DMINIUPNP_STATICLIB $(INCFLAGS) LOCAL_SRC_FILES = $(SOURCES_CXX) $(SOURCES_C) $(ASMFILES) LOCAL_CPPFLAGS := -Wall -std=gnu++11 $(COREFLAGS) -DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS LOCAL_CFLAGS := -O2 -DANDROID $(COREFLAGS) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 9f29455794..bdb5f8d1b1 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -1,12 +1,24 @@ - #include #include #include #include #include +#include + +#include "Common/Log.h" +#include "Common/LogManager.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/TimeUtil.h" +#include "Common/File/FileUtil.h" +#include "Common/Serialize/Serializer.h" +#include "Common/ConsoleListener.h" +#include "Common/Input/InputState.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/File/VFS/VFS.h" +#include "Common/File/VFS/AssetReader.h" -#include "base/timeutil.h" -#include "Common/ChunkFile.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Core.h" @@ -17,22 +29,19 @@ #include "Core/Host.h" #include "Core/MemMap.h" #include "Core/System.h" -#include "Log.h" -#include "LogManager.h" -#include "ConsoleListener.h" -#include "file/vfs.h" -#include "file/zip_read.h" + #include "GPU/GPUState.h" #include "GPU/GPUInterface.h" -#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/TextureScalerCommon.h" -#include "input/input_state.h" -#include "base/NativeApp.h" -#include "thread/threadutil.h" #include "libretro/libretro.h" #include "libretro/LibretroGraphicsContext.h" +#if PPSSPP_PLATFORM(ANDROID) +#include +#endif + #define DIR_SEP "/" #ifdef _WIN32 #define DIR_SEP_CHRS "/\\" @@ -42,125 +51,146 @@ #define SAMPLERATE 44100 -namespace Libretro { -LibretroGraphicsContext *ctx; -retro_environment_t environ_cb; -static retro_audio_sample_batch_t audio_batch_cb; -static retro_input_poll_t input_poll_cb; -static retro_input_state_t input_state_cb; +static bool libretro_supports_bitmasks = false; + +namespace Libretro +{ + LibretroGraphicsContext *ctx; + retro_environment_t environ_cb; + static retro_audio_sample_batch_t audio_batch_cb; + static retro_input_poll_t input_poll_cb; + static retro_input_state_t input_state_cb; } // namespace Libretro using namespace Libretro; -class LibretroHost : public Host { -public: - LibretroHost() {} - bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override { return true; } - void ShutdownGraphics() override {} - void InitSound() override {} - void UpdateSound() override { - extern int hostAttemptBlockSize; - const int blockSizeMax = 512; - static int16_t audio[blockSizeMax * 2]; - assert(hostAttemptBlockSize <= blockSizeMax); +class LibretroHost : public Host +{ + public: + LibretroHost() {} + bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override { return true; } + void ShutdownGraphics() override {} + void InitSound() override {} + void UpdateSound() override + { + extern int hostAttemptBlockSize; + const int blockSizeMax = 512; + static int16_t audio[blockSizeMax * 2]; + assert(hostAttemptBlockSize <= blockSizeMax); - int samples = __AudioMix(audio, hostAttemptBlockSize, SAMPLERATE); - audio_batch_cb(audio, samples); - } - void ShutdownSound() override {} - bool IsDebuggingEnabled() override { return false; } - bool AttemptLoadSymbolMap() override { return false; } + int samples = __AudioMix(audio, hostAttemptBlockSize, SAMPLERATE); + audio_batch_cb(audio, samples); + } + void ShutdownSound() override {} + bool IsDebuggingEnabled() override { return false; } + bool AttemptLoadSymbolMap() override { return false; } }; -class PrintfLogger : public LogListener { -public: - PrintfLogger(retro_log_callback log) : log_(log.log) {} - void Log(const LogMessage &message) { - switch (message.level) { - case LogTypes::LVERBOSE: - case LogTypes::LDEBUG: - log_(RETRO_LOG_DEBUG, "[%s] %s", message.log, message.msg.c_str()); - return; +class PrintfLogger : public LogListener +{ + public: + PrintfLogger(retro_log_callback log) : log_(log.log) {} + void Log(const LogMessage &message) + { + switch (message.level) + { + case LogTypes::LVERBOSE: + case LogTypes::LDEBUG: + log_(RETRO_LOG_DEBUG, "[%s] %s", + message.log, message.msg.c_str()); + break; - case LogTypes::LERROR: - log_(RETRO_LOG_ERROR, "[%s] %s", message.log, message.msg.c_str()); - return; + case LogTypes::LERROR: + log_(RETRO_LOG_ERROR, "[%s] %s", + message.log, message.msg.c_str()); + break; + case LogTypes::LNOTICE: + case LogTypes::LWARNING: + log_(RETRO_LOG_WARN, "[%s] %s", + message.log, message.msg.c_str()); + break; + case LogTypes::LINFO: + default: + log_(RETRO_LOG_INFO, "[%s] %s", + message.log, message.msg.c_str()); + break; + } + } - case LogTypes::LNOTICE: - case LogTypes::LWARNING: - log_(RETRO_LOG_WARN, "[%s] %s", message.log, message.msg.c_str()); - return; - - case LogTypes::LINFO: - default: - log_(RETRO_LOG_INFO, "[%s] %s", message.log, message.msg.c_str()); - return; - } - } - -private: - retro_log_printf_t log_; + private: + retro_log_printf_t log_; }; static PrintfLogger *printfLogger; -template class RetroOption { -public: - RetroOption(const char *id, const char *name, std::initializer_list> list) : id_(id), name_(name), list_(list.begin(), list.end()) {} - RetroOption(const char *id, const char *name, std::initializer_list list) : id_(id), name_(name) { - for (auto option : list) - list_.push_back({ option, (T)list_.size() }); - } - RetroOption(const char *id, const char *name, T first, std::initializer_list list) : id_(id), name_(name) { - for (auto option : list) - list_.push_back({ option, first + (int)list_.size() }); - } - RetroOption(const char *id, const char *name, T first, int count, int step = 1) : id_(id), name_(name) { - for (T i = first; i < first + count; i += step) - list_.push_back({ std::to_string(i), i }); - } - RetroOption(const char *id, const char *name, bool initial) : id_(id), name_(name) { - list_.push_back({ initial ? "enabled" : "disabled", initial }); - list_.push_back({ !initial ? "enabled" : "disabled", !initial }); - } - retro_variable GetOptions() { - if (options_.empty()) { - options_ = name_; - options_.push_back(';'); - for (auto &option : list_) { - if (option.first == list_.begin()->first) - options_ += std::string(" ") + option.first; - else - options_ += std::string("|") + option.first; - } - } - return { id_, options_.c_str() }; - } - bool Update(T *dest) { - retro_variable var{ id_ }; - T val = list_.front().second; +template class RetroOption +{ + public: + RetroOption(const char *id, const char *name, std::initializer_list> list) : id_(id), name_(name), list_(list.begin(), list.end()) {} + RetroOption(const char *id, const char *name, std::initializer_list list) : id_(id), name_(name) { + for (auto option : list) + list_.push_back({ option, (T)list_.size() }); + } + RetroOption(const char *id, const char *name, T first, std::initializer_list list) : id_(id), name_(name) { + for (auto option : list) + list_.push_back({ option, first + (int)list_.size() }); + } + RetroOption(const char *id, const char *name, T first, int count, int step = 1) : id_(id), name_(name) { + for (T i = first; i < first + count; i += step) + list_.push_back({ std::to_string(i), i }); + } + RetroOption(const char *id, const char *name, bool initial) : id_(id), name_(name) { + list_.push_back({ initial ? "enabled" : "disabled", initial }); + list_.push_back({ !initial ? "enabled" : "disabled", !initial }); + } - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - for (auto option : list_) { - if (option.first == var.value) { - val = option.second; - break; - } - } - } + retro_variable GetOptions() + { + if (options_.empty()) + { + options_ = name_; + options_.push_back(';'); + for (auto &option : list_) + { + if (option.first == list_.begin()->first) + options_ += std::string(" ") + option.first; + else + options_ += std::string("|") + option.first; + } + } + return { id_, options_.c_str() }; + } - if (*dest != val) { - *dest = val; - return true; - } + bool Update(T *dest) + { + retro_variable var{ id_ }; + T val = list_.front().second; - return false; - } + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + for (auto option : list_) + { + if (option.first == var.value) + { + val = option.second; + break; + } + } + } -private: - const char *id_; - const char *name_; - std::string options_; - std::vector> list_; + if (*dest != val) + { + *dest = val; + return true; + } + + return false; + } + + private: + const char *id_; + const char *name_; + std::string options_; + std::vector> list_; }; static RetroOption ppsspp_cpu_core("ppsspp_cpu_core", "CPU Core", { { "jit", CPUCore::JIT }, { "IR jit", CPUCore::IR_JIT }, { "interpreter", CPUCore::INTERPRETER } }); @@ -186,119 +216,127 @@ static RetroOption ppsspp_unsafe_func_replacements("ppsspp_unsafe_func_rep static RetroOption ppsspp_cheats("ppsspp_cheats", "Internal Cheats Support", false); static RetroOption ppsspp_io_timing_method("ppsspp_io_timing_method", "IO Timing Method", { { "Fast", IOTimingMethods::IOTIMING_FAST }, { "Host", IOTimingMethods::IOTIMING_HOST }, { "Simulate UMD delays", IOTimingMethods::IOTIMING_REALISTIC } }); -void retro_set_environment(retro_environment_t cb) { - std::vector vars; - vars.push_back(ppsspp_cpu_core.GetOptions()); - vars.push_back(ppsspp_locked_cpu_speed.GetOptions()); - vars.push_back(ppsspp_language.GetOptions()); - vars.push_back(ppsspp_rendering_mode.GetOptions()); - vars.push_back(ppsspp_auto_frameskip.GetOptions()); - vars.push_back(ppsspp_frameskip.GetOptions()); - vars.push_back(ppsspp_frameskiptype.GetOptions()); - vars.push_back(ppsspp_internal_resolution.GetOptions()); - vars.push_back(ppsspp_button_preference.GetOptions()); - vars.push_back(ppsspp_fast_memory.GetOptions()); - vars.push_back(ppsspp_block_transfer_gpu.GetOptions()); - vars.push_back(ppsspp_texture_scaling_level.GetOptions()); - vars.push_back(ppsspp_texture_scaling_type.GetOptions()); - vars.push_back(ppsspp_texture_filtering.GetOptions()); - vars.push_back(ppsspp_texture_anisotropic_filtering.GetOptions()); - vars.push_back(ppsspp_texture_deposterize.GetOptions()); - vars.push_back(ppsspp_texture_replacement.GetOptions()); - vars.push_back(ppsspp_gpu_hardware_transform.GetOptions()); - vars.push_back(ppsspp_vertex_cache.GetOptions()); - vars.push_back(ppsspp_unsafe_func_replacements.GetOptions()); - vars.push_back(ppsspp_cheats.GetOptions()); - vars.push_back(ppsspp_io_timing_method.GetOptions()); - vars.push_back({}); +void retro_set_environment(retro_environment_t cb) +{ + std::vector vars; + vars.push_back(ppsspp_cpu_core.GetOptions()); + vars.push_back(ppsspp_locked_cpu_speed.GetOptions()); + vars.push_back(ppsspp_language.GetOptions()); + vars.push_back(ppsspp_rendering_mode.GetOptions()); + vars.push_back(ppsspp_auto_frameskip.GetOptions()); + vars.push_back(ppsspp_frameskip.GetOptions()); + vars.push_back(ppsspp_frameskiptype.GetOptions()); + vars.push_back(ppsspp_internal_resolution.GetOptions()); + vars.push_back(ppsspp_button_preference.GetOptions()); + vars.push_back(ppsspp_fast_memory.GetOptions()); + vars.push_back(ppsspp_block_transfer_gpu.GetOptions()); + vars.push_back(ppsspp_texture_scaling_level.GetOptions()); + vars.push_back(ppsspp_texture_scaling_type.GetOptions()); + vars.push_back(ppsspp_texture_filtering.GetOptions()); + vars.push_back(ppsspp_texture_anisotropic_filtering.GetOptions()); + vars.push_back(ppsspp_texture_deposterize.GetOptions()); + vars.push_back(ppsspp_texture_replacement.GetOptions()); + vars.push_back(ppsspp_gpu_hardware_transform.GetOptions()); + vars.push_back(ppsspp_vertex_cache.GetOptions()); + vars.push_back(ppsspp_unsafe_func_replacements.GetOptions()); + vars.push_back(ppsspp_cheats.GetOptions()); + vars.push_back(ppsspp_io_timing_method.GetOptions()); + vars.push_back({}); - environ_cb = cb; + environ_cb = cb; - cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars.data()); + cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars.data()); } -static int get_language_auto(void) { - retro_language val = RETRO_LANGUAGE_ENGLISH; - environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &val); +static int get_language_auto(void) +{ + retro_language val = RETRO_LANGUAGE_ENGLISH; + environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &val); - switch (val) { - default: - case RETRO_LANGUAGE_ENGLISH: - return PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; - case RETRO_LANGUAGE_JAPANESE: - return PSP_SYSTEMPARAM_LANGUAGE_JAPANESE; - case RETRO_LANGUAGE_FRENCH: - return PSP_SYSTEMPARAM_LANGUAGE_FRENCH; - case RETRO_LANGUAGE_GERMAN: - return PSP_SYSTEMPARAM_LANGUAGE_GERMAN; - case RETRO_LANGUAGE_SPANISH: - return PSP_SYSTEMPARAM_LANGUAGE_SPANISH; - case RETRO_LANGUAGE_ITALIAN: - return PSP_SYSTEMPARAM_LANGUAGE_ITALIAN; - case RETRO_LANGUAGE_PORTUGUESE_BRAZIL: - case RETRO_LANGUAGE_PORTUGUESE_PORTUGAL: - return PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE; - case RETRO_LANGUAGE_RUSSIAN: - return PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN; - case RETRO_LANGUAGE_DUTCH: - return PSP_SYSTEMPARAM_LANGUAGE_DUTCH; - case RETRO_LANGUAGE_KOREAN: - return PSP_SYSTEMPARAM_LANGUAGE_KOREAN; - case RETRO_LANGUAGE_CHINESE_TRADITIONAL: - return PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL; - case RETRO_LANGUAGE_CHINESE_SIMPLIFIED: - return PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED; - } + switch (val) + { + default: + case RETRO_LANGUAGE_ENGLISH: + return PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; + case RETRO_LANGUAGE_JAPANESE: + return PSP_SYSTEMPARAM_LANGUAGE_JAPANESE; + case RETRO_LANGUAGE_FRENCH: + return PSP_SYSTEMPARAM_LANGUAGE_FRENCH; + case RETRO_LANGUAGE_GERMAN: + return PSP_SYSTEMPARAM_LANGUAGE_GERMAN; + case RETRO_LANGUAGE_SPANISH: + return PSP_SYSTEMPARAM_LANGUAGE_SPANISH; + case RETRO_LANGUAGE_ITALIAN: + return PSP_SYSTEMPARAM_LANGUAGE_ITALIAN; + case RETRO_LANGUAGE_PORTUGUESE_BRAZIL: + case RETRO_LANGUAGE_PORTUGUESE_PORTUGAL: + return PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE; + case RETRO_LANGUAGE_RUSSIAN: + return PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN; + case RETRO_LANGUAGE_DUTCH: + return PSP_SYSTEMPARAM_LANGUAGE_DUTCH; + case RETRO_LANGUAGE_KOREAN: + return PSP_SYSTEMPARAM_LANGUAGE_KOREAN; + case RETRO_LANGUAGE_CHINESE_TRADITIONAL: + return PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL; + case RETRO_LANGUAGE_CHINESE_SIMPLIFIED: + return PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED; + } } -static void check_variables(CoreParameter &coreParam) { - bool updated = false; +static void check_variables(CoreParameter &coreParam) +{ + bool updated = false; - if (coreState != CORE_POWERUP && environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && !updated) - return; + if ( coreState != CORE_POWERUP + && environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) + && !updated) + return; - ppsspp_button_preference.Update(&g_Config.iButtonPreference); - ppsspp_fast_memory.Update(&g_Config.bFastMemory); - ppsspp_vertex_cache.Update(&g_Config.bVertexCache); - ppsspp_gpu_hardware_transform.Update(&g_Config.bHardwareTransform); - ppsspp_frameskip.Update(&g_Config.iFrameSkip); - ppsspp_frameskiptype.Update(&g_Config.iFrameSkipType); - ppsspp_auto_frameskip.Update(&g_Config.bAutoFrameSkip); - ppsspp_block_transfer_gpu.Update(&g_Config.bBlockTransferGPU); - ppsspp_texture_filtering.Update(&g_Config.iTexFiltering); - ppsspp_texture_anisotropic_filtering.Update(&g_Config.iAnisotropyLevel); - ppsspp_texture_deposterize.Update(&g_Config.bTexDeposterize); - ppsspp_texture_replacement.Update(&g_Config.bReplaceTextures); - ppsspp_unsafe_func_replacements.Update(&g_Config.bFuncReplacements); - ppsspp_cheats.Update(&g_Config.bEnableCheats); - ppsspp_locked_cpu_speed.Update(&g_Config.iLockedCPUSpeed); - ppsspp_rendering_mode.Update(&g_Config.iRenderingMode); - ppsspp_cpu_core.Update((CPUCore *)&g_Config.iCpuCore); - ppsspp_io_timing_method.Update((IOTimingMethods *)&g_Config.iIOTimingMethod); + ppsspp_button_preference.Update(&g_Config.iButtonPreference); + ppsspp_fast_memory.Update(&g_Config.bFastMemory); + ppsspp_vertex_cache.Update(&g_Config.bVertexCache); + ppsspp_gpu_hardware_transform.Update(&g_Config.bHardwareTransform); + ppsspp_frameskip.Update(&g_Config.iFrameSkip); + ppsspp_frameskiptype.Update(&g_Config.iFrameSkipType); + ppsspp_auto_frameskip.Update(&g_Config.bAutoFrameSkip); + ppsspp_block_transfer_gpu.Update(&g_Config.bBlockTransferGPU); + ppsspp_texture_filtering.Update(&g_Config.iTexFiltering); + ppsspp_texture_anisotropic_filtering.Update(&g_Config.iAnisotropyLevel); + ppsspp_texture_deposterize.Update(&g_Config.bTexDeposterize); + ppsspp_texture_replacement.Update(&g_Config.bReplaceTextures); + ppsspp_unsafe_func_replacements.Update(&g_Config.bFuncReplacements); + ppsspp_cheats.Update(&g_Config.bEnableCheats); + ppsspp_locked_cpu_speed.Update(&g_Config.iLockedCPUSpeed); + ppsspp_rendering_mode.Update(&g_Config.iRenderingMode); + ppsspp_cpu_core.Update((CPUCore *)&g_Config.iCpuCore); + ppsspp_io_timing_method.Update((IOTimingMethods *)&g_Config.iIOTimingMethod); - ppsspp_language.Update(&g_Config.iLanguage); - if (g_Config.iLanguage < 0) { - g_Config.iLanguage = get_language_auto(); - } + ppsspp_language.Update(&g_Config.iLanguage); + if (g_Config.iLanguage < 0) + g_Config.iLanguage = get_language_auto(); - if (!PSP_IsInited() && ppsspp_internal_resolution.Update(&g_Config.iInternalResolution)) { - coreParam.pixelWidth = coreParam.renderWidth = g_Config.iInternalResolution * 480; - coreParam.pixelHeight = coreParam.renderHeight = g_Config.iInternalResolution * 272; - if (gpu) { - retro_system_av_info av_info; - retro_get_system_av_info(&av_info); - environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info); - gpu->Resized(); - } - } + if (!PSP_IsInited() && ppsspp_internal_resolution.Update(&g_Config.iInternalResolution)) + { + coreParam.pixelWidth = coreParam.renderWidth = + g_Config.iInternalResolution * 480; + coreParam.pixelHeight = coreParam.renderHeight = + g_Config.iInternalResolution * 272; - if (ppsspp_texture_scaling_type.Update(&g_Config.iTexScalingType) && gpu) { - gpu->ClearCacheNextFrame(); - } + if (gpu) + { + retro_system_av_info av_info; + retro_get_system_av_info(&av_info); + environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info); + gpu->Resized(); + } + } - if (ppsspp_texture_scaling_level.Update(&g_Config.iTexScalingLevel) && gpu) { - gpu->ClearCacheNextFrame(); - } + if (ppsspp_texture_scaling_type.Update(&g_Config.iTexScalingType) && gpu) + gpu->ClearCacheNextFrame(); + + if (ppsspp_texture_scaling_level.Update(&g_Config.iTexScalingLevel) && gpu) + gpu->ClearCacheNextFrame(); } void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; } @@ -306,283 +344,303 @@ void retro_set_audio_sample(retro_audio_sample_t cb) { (void)cb; } void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; } void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; } -void retro_init(void) { +void retro_init(void) +{ + struct retro_log_callback log; #if 0 - g_Config.Load(""); + g_Config.Load(""); #endif - g_Config.bEnableLogging = true; - g_Config.bFrameSkipUnthrottle = false; - g_Config.bMemStickInserted = PSP_MEMORYSTICK_STATE_INSERTED; - g_Config.iGlobalVolume = VOLUME_MAX - 1; - g_Config.iAltSpeedVolume = -1; - g_Config.bEnableSound = true; - g_Config.iCwCheatRefreshRate = 60; + g_Config.bEnableLogging = true; + g_Config.iUnthrottleMode = (int)UnthrottleMode::CONTINUOUS; + g_Config.bMemStickInserted = PSP_MEMORYSTICK_STATE_INSERTED; + g_Config.iGlobalVolume = VOLUME_MAX - 1; + g_Config.iAltSpeedVolume = -1; + g_Config.bEnableSound = true; + g_Config.iCwCheatRefreshRate = 60; - g_Config.iFirmwareVersion = PSP_DEFAULT_FIRMWARE; - g_Config.iPSPModel = PSP_MODEL_SLIM; + g_Config.iFirmwareVersion = PSP_DEFAULT_FIRMWARE; + g_Config.iPSPModel = PSP_MODEL_SLIM; - LogManager::Init(); + LogManager::Init(&g_Config.bEnableLogging); - host = new LibretroHost; + host = new LibretroHost; - struct retro_log_callback log; - if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) { - printfLogger = new PrintfLogger(log); - LogManager *logman = LogManager::GetInstance(); - logman->RemoveListener(logman->GetConsoleListener()); - logman->RemoveListener(logman->GetDebuggerListener()); - logman->ChangeFileLog(nullptr); - logman->AddListener(printfLogger); + if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) + { + printfLogger = new PrintfLogger(log); + LogManager *logman = LogManager::GetInstance(); + logman->RemoveListener(logman->GetConsoleListener()); + logman->RemoveListener(logman->GetDebuggerListener()); + logman->ChangeFileLog(nullptr); + logman->AddListener(printfLogger); #if 1 - logman->SetAllLogLevels(LogTypes::LINFO); + logman->SetAllLogLevels(LogTypes::LINFO); #endif - } + } + + if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) + libretro_supports_bitmasks = true; } -void retro_deinit(void) { - LogManager::Shutdown(); +void retro_deinit(void) +{ + LogManager::Shutdown(); - delete printfLogger; - printfLogger = nullptr; + delete printfLogger; + printfLogger = nullptr; - delete host; - host = nullptr; + delete host; + host = nullptr; + + libretro_supports_bitmasks = false; } -void retro_set_controller_port_device(unsigned port, unsigned device) { +void retro_set_controller_port_device(unsigned port, unsigned device) +{ (void)port; (void)device; } -void retro_get_system_info(struct retro_system_info *info) { - *info = {}; - info->library_name = "PPSSPP"; - info->library_version = PPSSPP_GIT_VERSION; - info->need_fullpath = true; - info->valid_extensions = "elf|iso|cso|prx|pbp"; +void retro_get_system_info(struct retro_system_info *info) +{ + *info = {}; + info->library_name = "PPSSPP"; + info->library_version = PPSSPP_GIT_VERSION; + info->need_fullpath = true; + info->valid_extensions = "elf|iso|cso|prx|pbp"; } -void retro_get_system_av_info(struct retro_system_av_info *info) { - *info = {}; - info->timing.fps = 60.0f / 1.001f; - info->timing.sample_rate = SAMPLERATE; +void retro_get_system_av_info(struct retro_system_av_info *info) +{ + *info = {}; + info->timing.fps = 60.0f / 1.001f; + info->timing.sample_rate = SAMPLERATE; - info->geometry.base_width = g_Config.iInternalResolution * 480; - info->geometry.base_height = g_Config.iInternalResolution * 272; - info->geometry.max_width = g_Config.iInternalResolution * 480; - info->geometry.max_height = g_Config.iInternalResolution * 272; - info->geometry.aspect_ratio = 16.0 / 9.0; + info->geometry.base_width = g_Config.iInternalResolution * 480; + info->geometry.base_height = g_Config.iInternalResolution * 272; + info->geometry.max_width = g_Config.iInternalResolution * 480; + info->geometry.max_height = g_Config.iInternalResolution * 272; + info->geometry.aspect_ratio = 16.0 / 9.0; } unsigned retro_api_version(void) { return RETRO_API_VERSION; } -namespace Libretro { -bool useEmuThread = false; -std::atomic emuThreadState(EmuThreadState::DISABLED); +namespace Libretro +{ + bool useEmuThread = false; + std::atomic emuThreadState(EmuThreadState::DISABLED); -static std::thread emuThread; -static void EmuFrame() { - ctx->SetRenderTarget(); - if (ctx->GetDrawContext()) { - ctx->GetDrawContext()->BeginFrame(); - } + static std::thread emuThread; + static void EmuFrame() + { + ctx->SetRenderTarget(); + if (ctx->GetDrawContext()) + ctx->GetDrawContext()->BeginFrame(); - gpu->BeginHostFrame(); + gpu->BeginHostFrame(); - coreState = CORE_RUNNING; - PSP_RunLoopUntil(UINT64_MAX); + coreState = CORE_RUNNING; + PSP_RunLoopUntil(UINT64_MAX); - gpu->EndHostFrame(); + gpu->EndHostFrame(); - if (ctx->GetDrawContext()) { - ctx->GetDrawContext()->EndFrame(); - } -} + if (ctx->GetDrawContext()) + ctx->GetDrawContext()->EndFrame(); + } -static void EmuThreadFunc() { - setCurrentThreadName("Emu"); + static void EmuThreadFunc() + { + setCurrentThreadName("Emu"); - while (true) { - switch ((EmuThreadState)emuThreadState) { - case EmuThreadState::START_REQUESTED: - emuThreadState = EmuThreadState::RUNNING; - /* fallthrough */ - case EmuThreadState::RUNNING: - EmuFrame(); - break; - case EmuThreadState::PAUSE_REQUESTED: - emuThreadState = EmuThreadState::PAUSED; - /* fallthrough */ - case EmuThreadState::PAUSED: - sleep_ms(1); - break; - default: - case EmuThreadState::QUIT_REQUESTED: - emuThreadState = EmuThreadState::STOPPED; - ctx->StopThread(); - return; - } - } -} + for (;;) + { + switch ((EmuThreadState)emuThreadState) + { + case EmuThreadState::START_REQUESTED: + emuThreadState = EmuThreadState::RUNNING; + /* fallthrough */ + case EmuThreadState::RUNNING: + EmuFrame(); + break; + case EmuThreadState::PAUSE_REQUESTED: + emuThreadState = EmuThreadState::PAUSED; + /* fallthrough */ + case EmuThreadState::PAUSED: + sleep_ms(1); + break; + default: + case EmuThreadState::QUIT_REQUESTED: + emuThreadState = EmuThreadState::STOPPED; + ctx->StopThread(); + return; + } + } + } -void EmuThreadStart() { - bool wasPaused = emuThreadState == EmuThreadState::PAUSED; - emuThreadState = EmuThreadState::START_REQUESTED; + void EmuThreadStart() + { + bool wasPaused = emuThreadState == EmuThreadState::PAUSED; + emuThreadState = EmuThreadState::START_REQUESTED; - if (!wasPaused) { - ctx->ThreadStart(); - emuThread = std::thread(&EmuThreadFunc); - } -} + if (!wasPaused) + { + ctx->ThreadStart(); + emuThread = std::thread(&EmuThreadFunc); + } + } -void EmuThreadStop() { - if (emuThreadState != EmuThreadState::RUNNING) { - return; - } + void EmuThreadStop() + { + if (emuThreadState != EmuThreadState::RUNNING) + return; - emuThreadState = EmuThreadState::QUIT_REQUESTED; + emuThreadState = EmuThreadState::QUIT_REQUESTED; - while (ctx->ThreadFrame()) { - // Need to keep eating frames to allow the EmuThread to exit correctly. - continue; - } + // Need to keep eating frames to allow the EmuThread to exit correctly. + while (ctx->ThreadFrame()) + continue; - emuThread.join(); - emuThread = std::thread(); - ctx->ThreadEnd(); -} + emuThread.join(); + emuThread = std::thread(); + ctx->ThreadEnd(); + } -void EmuThreadPause() { - if (emuThreadState != EmuThreadState::RUNNING) { - return; - } + void EmuThreadPause() + { + if (emuThreadState != EmuThreadState::RUNNING) + return; - emuThreadState = EmuThreadState::PAUSE_REQUESTED; + emuThreadState = EmuThreadState::PAUSE_REQUESTED; - ctx->ThreadFrame(); // Eat 1 frame + ctx->ThreadFrame(); // Eat 1 frame - while (emuThreadState != EmuThreadState::PAUSED) { - sleep_ms(1); - } -} + while (emuThreadState != EmuThreadState::PAUSED) + sleep_ms(1); + } } // namespace Libretro -bool retro_load_game(const struct retro_game_info *game) { - struct retro_input_descriptor desc[] = { - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" }, - { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" }, - { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" }, - { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" }, - { 0 }, - }; - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); +bool retro_load_game(const struct retro_game_info *game) +{ + static std::string retro_base_dir; + static std::string retro_save_dir; + std::string error_string; + enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; + const char *nickname = NULL; + const char *dir_ptr = NULL; + struct retro_input_descriptor desc[] = { + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" }, + { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" }, + { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" }, + { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" }, + { 0 }, + }; - enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; - if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) { - ERROR_LOG(SYSTEM, "XRGB8888 is not supported.\n"); - return false; - } + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); - const char *nickname = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_USERNAME, &nickname) && nickname) { - g_Config.sNickName = std::string(nickname); - } + if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) + { + ERROR_LOG(SYSTEM, "XRGB8888 is not supported.\n"); + return false; + } - const char *dir_ptr = NULL; - static std::string retro_base_dir; - static std::string retro_save_dir; + if (environ_cb(RETRO_ENVIRONMENT_GET_USERNAME, &nickname) && nickname) + g_Config.sNickName = std::string(nickname); - if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir_ptr) && dir_ptr) { - retro_base_dir = dir_ptr; - // Make sure that we don't have any lingering slashes, etc, as they break Windows. - size_t last = retro_base_dir.find_last_not_of(DIR_SEP_CHRS); - if (last != std::string::npos) - last++; - retro_base_dir = retro_base_dir.substr(0, last) + DIR_SEP; - } + if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir_ptr) + && dir_ptr) + { + size_t last; + retro_base_dir = dir_ptr; + // Make sure that we don't have any lingering slashes, etc, as they break Windows. + last = retro_base_dir.find_last_not_of(DIR_SEP_CHRS); + if (last != std::string::npos) + last++; - if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir_ptr) && dir_ptr) { - retro_save_dir = dir_ptr; - // Make sure that we don't have any lingering slashes, etc, as they break Windows. - size_t last = retro_save_dir.find_last_not_of(DIR_SEP_CHRS); - if (last != std::string::npos) - last++; + retro_base_dir = retro_base_dir.substr(0, last) + DIR_SEP; + } - retro_save_dir = retro_save_dir.substr(0, last) + DIR_SEP; - } + if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir_ptr) + && dir_ptr) + { + retro_save_dir = dir_ptr; + // Make sure that we don't have any lingering slashes, etc, as they break Windows. + size_t last = retro_save_dir.find_last_not_of(DIR_SEP_CHRS); + if (last != std::string::npos) + last++; - if (retro_base_dir.empty()) { - retro_base_dir = File::GetDir(game->path); - } + retro_save_dir = retro_save_dir.substr(0, last) + DIR_SEP; + } - retro_base_dir += "PPSSPP" DIR_SEP; + if (retro_base_dir.empty()) + retro_base_dir = File::GetDir(game->path); - if (retro_save_dir.empty()) { - retro_save_dir = File::GetDir(game->path); - } + retro_base_dir += "PPSSPP" DIR_SEP; - g_Config.currentDirectory = retro_base_dir; - g_Config.externalDirectory = retro_base_dir; - g_Config.memStickDirectory = retro_save_dir; - g_Config.flash0Directory = retro_base_dir + "flash0" DIR_SEP; - g_Config.internalDataDirectory = retro_base_dir; + if (retro_save_dir.empty()) + retro_save_dir = File::GetDir(game->path); - VFSRegister("", new DirectoryAssetReader(retro_base_dir.c_str())); + g_Config.currentDirectory = retro_base_dir; + g_Config.externalDirectory = retro_base_dir; + g_Config.memStickDirectory = retro_save_dir; + g_Config.flash0Directory = retro_base_dir + "flash0" DIR_SEP; + g_Config.internalDataDirectory = retro_base_dir; - coreState = CORE_POWERUP; - ctx = LibretroGraphicsContext::CreateGraphicsContext(); - INFO_LOG(SYSTEM, "Using %s backend", ctx->Ident()); + VFSRegister("", new DirectoryAssetReader(retro_base_dir.c_str())); - Core_SetGraphicsContext(ctx); - SetGPUBackend((GPUBackend)g_Config.iGPUBackend); + coreState = CORE_POWERUP; + ctx = LibretroGraphicsContext::CreateGraphicsContext(); + INFO_LOG(SYSTEM, "Using %s backend", ctx->Ident()); - useEmuThread = ctx->GetGPUCore() == GPUCORE_GLES; + Core_SetGraphicsContext(ctx); + SetGPUBackend((GPUBackend)g_Config.iGPUBackend); - CoreParameter coreParam = {}; - coreParam.enableSound = true; - coreParam.fileToStart = std::string(game->path); - coreParam.mountIso = ""; - coreParam.startBreak = false; - coreParam.printfEmuLog = true; - coreParam.headLess = true; - coreParam.unthrottle = true; - coreParam.graphicsContext = ctx; - coreParam.gpuCore = ctx->GetGPUCore(); - coreParam.cpuCore = CPUCore::JIT; - check_variables(coreParam); + useEmuThread = ctx->GetGPUCore() == GPUCORE_GLES; + + CoreParameter coreParam = {}; + coreParam.enableSound = true; + coreParam.fileToStart = std::string(game->path); + coreParam.mountIso = ""; + coreParam.startBreak = false; + coreParam.printfEmuLog = true; + coreParam.headLess = true; + coreParam.unthrottle = true; + coreParam.graphicsContext = ctx; + coreParam.gpuCore = ctx->GetGPUCore(); + coreParam.cpuCore = CPUCore::JIT; + check_variables(coreParam); #if 0 - g_Config.bVertexDecoderJit = (coreParam.cpuCore == CPU_JIT) ? true : false; + g_Config.bVertexDecoderJit = (coreParam.cpuCore == CPU_JIT) ? true : false; #endif - std::string error_string; - if (!PSP_InitStart(coreParam, &error_string)) { - ERROR_LOG(BOOT, "%s", error_string.c_str()); - return false; - } + if (!PSP_InitStart(coreParam, &error_string)) + { + ERROR_LOG(BOOT, "%s", error_string.c_str()); + return false; + } - return true; + return true; } -void retro_unload_game(void) { - if (Libretro::useEmuThread) { +void retro_unload_game(void) +{ + if (Libretro::useEmuThread) Libretro::EmuThreadStop(); - } PSP_Shutdown(); VFSShutdown(); @@ -592,208 +650,250 @@ void retro_unload_game(void) { PSP_CoreParameter().graphicsContext = nullptr; } -void retro_reset(void) { - std::string error_string; +void retro_reset(void) +{ + std::string error_string; - PSP_Shutdown(); + PSP_Shutdown(); #if 0 - coreState = CORE_POWERUP; - if (!PSP_InitStart(PSP_CoreParameter(), &error_string)) - { - ERROR_LOG(BOOT, "%s", error_string.c_str()); - environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); - } + coreState = CORE_POWERUP; + if (!PSP_InitStart(PSP_CoreParameter(), &error_string)) + { + ERROR_LOG(BOOT, "%s", error_string.c_str()); + environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); + } #else - if (!PSP_Init(PSP_CoreParameter(), &error_string)) { - ERROR_LOG(BOOT, "%s", error_string.c_str()); - environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); - } + if (!PSP_Init(PSP_CoreParameter(), &error_string)) + { + ERROR_LOG(BOOT, "%s", error_string.c_str()); + environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); + } #endif } -static void retro_input(void) { - // clang-format off - static struct - { - u32 retro; - u32 sceCtrl; - } map[] = { - { RETRO_DEVICE_ID_JOYPAD_UP, CTRL_UP }, - { RETRO_DEVICE_ID_JOYPAD_DOWN, CTRL_DOWN }, - { RETRO_DEVICE_ID_JOYPAD_LEFT, CTRL_LEFT }, - { RETRO_DEVICE_ID_JOYPAD_RIGHT, CTRL_RIGHT }, - { RETRO_DEVICE_ID_JOYPAD_X, CTRL_TRIANGLE }, - { RETRO_DEVICE_ID_JOYPAD_A, CTRL_CIRCLE }, - { RETRO_DEVICE_ID_JOYPAD_B, CTRL_CROSS }, - { RETRO_DEVICE_ID_JOYPAD_Y, CTRL_SQUARE }, - { RETRO_DEVICE_ID_JOYPAD_L, CTRL_LTRIGGER }, - { RETRO_DEVICE_ID_JOYPAD_R, CTRL_RTRIGGER }, - { RETRO_DEVICE_ID_JOYPAD_START, CTRL_START }, - { RETRO_DEVICE_ID_JOYPAD_SELECT, CTRL_SELECT }, - }; - // clang-format on +static void retro_input(void) +{ + unsigned i; + int16_t ret = 0; + // clang-format off + static struct + { + u32 retro; + u32 sceCtrl; + } map[] = { + { RETRO_DEVICE_ID_JOYPAD_UP, CTRL_UP }, + { RETRO_DEVICE_ID_JOYPAD_DOWN, CTRL_DOWN }, + { RETRO_DEVICE_ID_JOYPAD_LEFT, CTRL_LEFT }, + { RETRO_DEVICE_ID_JOYPAD_RIGHT, CTRL_RIGHT }, + { RETRO_DEVICE_ID_JOYPAD_X, CTRL_TRIANGLE }, + { RETRO_DEVICE_ID_JOYPAD_A, CTRL_CIRCLE }, + { RETRO_DEVICE_ID_JOYPAD_B, CTRL_CROSS }, + { RETRO_DEVICE_ID_JOYPAD_Y, CTRL_SQUARE }, + { RETRO_DEVICE_ID_JOYPAD_L, CTRL_LTRIGGER }, + { RETRO_DEVICE_ID_JOYPAD_R, CTRL_RTRIGGER }, + { RETRO_DEVICE_ID_JOYPAD_START, CTRL_START }, + { RETRO_DEVICE_ID_JOYPAD_SELECT, CTRL_SELECT }, + }; + // clang-format on - input_poll_cb(); + input_poll_cb(); - for (int i = 0; i < sizeof(map) / sizeof(*map); i++) { - if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, map[i].retro)) { - __CtrlButtonDown(map[i].sceCtrl); - } else { - __CtrlButtonUp(map[i].sceCtrl); - } - } + if (libretro_supports_bitmasks) + ret = input_state_cb(0, RETRO_DEVICE_JOYPAD, + 0, RETRO_DEVICE_ID_JOYPAD_MASK); + else + { + for (i = RETRO_DEVICE_ID_JOYPAD_B; i <= RETRO_DEVICE_ID_JOYPAD_R; i++) + if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, i)) + ret |= (1 << i); + } - __CtrlSetAnalogX(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / 32768.0f, CTRL_STICK_LEFT); - __CtrlSetAnalogY(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / -32768.0f, CTRL_STICK_LEFT); - __CtrlSetAnalogX(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / 32768.0f, CTRL_STICK_RIGHT); - __CtrlSetAnalogY(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / -32768.0f, CTRL_STICK_RIGHT); + for (i = 0; i < sizeof(map) / sizeof(*map); i++) + { + bool pressed = ret & (1 << map[i].retro); + + if (pressed) + { + __CtrlButtonDown(map[i].sceCtrl); + } + else + { + __CtrlButtonUp(map[i].sceCtrl); + } + } + + __CtrlSetAnalogX(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / 32768.0f, CTRL_STICK_LEFT); + __CtrlSetAnalogY(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / -32768.0f, CTRL_STICK_LEFT); + __CtrlSetAnalogX(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / 32768.0f, CTRL_STICK_RIGHT); + __CtrlSetAnalogY(input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / -32768.0f, CTRL_STICK_RIGHT); } -void retro_run(void) { - if (PSP_IsIniting()) { - std::string error_string; +void retro_run(void) +{ + if (PSP_IsIniting()) + { + std::string error_string; #if 0 - if (!PSP_InitUpdate(&error_string)) - { - graphics_context->SwapBuffers(); - return; - } + if (!PSP_InitUpdate(&error_string)) + { + graphics_context->SwapBuffers(); + return; + } #else - while (!PSP_InitUpdate(&error_string)) { - sleep_ms(4); - } + while (!PSP_InitUpdate(&error_string)) + sleep_ms(4); #endif - if (!PSP_IsInited()) { - ERROR_LOG(BOOT, "%s", error_string.c_str()); - environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); - return; - } - } + if (!PSP_IsInited()) + { + ERROR_LOG(BOOT, "%s", error_string.c_str()); + environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); + return; + } + } - check_variables(PSP_CoreParameter()); + check_variables(PSP_CoreParameter()); - retro_input(); + retro_input(); - if (useEmuThread) { - if(emuThreadState == EmuThreadState::PAUSED || emuThreadState == EmuThreadState::PAUSE_REQUESTED) { - ctx->SwapBuffers(); - return; - } + if (useEmuThread) + { + if( emuThreadState == EmuThreadState::PAUSED || + emuThreadState == EmuThreadState::PAUSE_REQUESTED) + { + ctx->SwapBuffers(); + return; + } - if (emuThreadState != EmuThreadState::RUNNING) { - EmuThreadStart(); - } + if (emuThreadState != EmuThreadState::RUNNING) + EmuThreadStart(); - if (!ctx->ThreadFrame()) { - return; - } - } else { - EmuFrame(); - } + if (!ctx->ThreadFrame()) + return; + } + else + EmuFrame(); - ctx->SwapBuffers(); + ctx->SwapBuffers(); } unsigned retro_get_region(void) { return RETRO_REGION_NTSC; } -bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num) { - (void)type; - (void)info; - (void)num; - return false; -} +bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num) { return false; } -namespace SaveState { -struct SaveStart { - void DoState(PointerWrap &p); -}; +namespace SaveState +{ + struct SaveStart + { + void DoState(PointerWrap &p); + }; } // namespace SaveState -size_t retro_serialize_size(void) { - // TODO: Libretro API extension to use the savestate queue - if (useEmuThread) { - EmuThreadPause(); - } +size_t retro_serialize_size(void) +{ + SaveState::SaveStart state; + // TODO: Libretro API extension to use the savestate queue + if (useEmuThread) + EmuThreadPause(); - SaveState::SaveStart state; - return (CChunkFileReader::MeasurePtr(state) + 0x800000) & ~0x7FFFFF; // We don't unpause intentionally + return (CChunkFileReader::MeasurePtr(state) + 0x800000) + & ~0x7FFFFF; // We don't unpause intentionally } -bool retro_serialize(void *data, size_t size) { - // TODO: Libretro API extension to use the savestate queue - if (useEmuThread) { - EmuThreadPause(); // Does nothing if already paused - } +bool retro_serialize(void *data, size_t size) +{ + bool retVal; + SaveState::SaveStart state; + // TODO: Libretro API extension to use the savestate queue + if (useEmuThread) + EmuThreadPause(); // Does nothing if already paused - SaveState::SaveStart state; - assert(CChunkFileReader::MeasurePtr(state) <= size); - bool retVal = CChunkFileReader::SavePtr((u8 *)data, state) == CChunkFileReader::ERROR_NONE; + assert(CChunkFileReader::MeasurePtr(state) <= size); + retVal = CChunkFileReader::SavePtr((u8 *)data, state) + == CChunkFileReader::ERROR_NONE; - if (useEmuThread) { - EmuThreadStart(); - sleep_ms(4); - } + if (useEmuThread) + { + EmuThreadStart(); + sleep_ms(4); + } - return retVal; + return retVal; } -bool retro_unserialize(const void *data, size_t size) { - // TODO: Libretro API extension to use the savestate queue - if (useEmuThread) { - EmuThreadPause(); // Does nothing if already paused - } +bool retro_unserialize(const void *data, size_t size) +{ + bool retVal; + SaveState::SaveStart state; + // TODO: Libretro API extension to use the savestate queue + if (useEmuThread) + EmuThreadPause(); // Does nothing if already paused - SaveState::SaveStart state; - bool retVal = CChunkFileReader::LoadPtr((u8 *)data, state) == CChunkFileReader::ERROR_NONE; + std::string errorString; + retVal = CChunkFileReader::LoadPtr((u8 *)data, state, &errorString) + == CChunkFileReader::ERROR_NONE; - if (useEmuThread) { - EmuThreadStart(); - sleep_ms(4); - } + if (useEmuThread) + { + EmuThreadStart(); + sleep_ms(4); + } - return retVal; + return retVal; } -void *retro_get_memory_data(unsigned id) { - if ( id == RETRO_MEMORY_SYSTEM_RAM ) { - return Memory::GetPointerUnchecked(PSP_GetKernelMemoryBase()) ; - } - return NULL; +void *retro_get_memory_data(unsigned id) +{ + if ( id == RETRO_MEMORY_SYSTEM_RAM ) + return Memory::GetPointerUnchecked(PSP_GetKernelMemoryBase()) ; + return NULL; } -size_t retro_get_memory_size(unsigned id) { - if ( id == RETRO_MEMORY_SYSTEM_RAM ) { +size_t retro_get_memory_size(unsigned id) +{ + if ( id == RETRO_MEMORY_SYSTEM_RAM ) return Memory::g_MemorySize ; - } return 0; } void retro_cheat_reset(void) {} -void retro_cheat_set(unsigned index, bool enabled, const char *code) { - (void)index; - (void)enabled; - (void)code; +void retro_cheat_set(unsigned index, bool enabled, const char *code) { } + +int System_GetPropertyInt(SystemProperty prop) +{ + switch (prop) + { + case SYSPROP_AUDIO_SAMPLE_RATE: + return SAMPLERATE; +#if PPSSPP_PLATFORM(ANDROID) + case SYSPROP_SYSTEMVERSION: { + char sdk[PROP_VALUE_MAX] = {0}; + if (__system_property_get("ro.build.version.sdk", sdk) != 0) { + return atoi(sdk); + } + return -1; + } +#endif + default: + break; + } + + return -1; } -int System_GetPropertyInt(SystemProperty prop) { - switch (prop) { - case SYSPROP_AUDIO_SAMPLE_RATE: - return SAMPLERATE; - default: - return -1; - } -} +float System_GetPropertyFloat(SystemProperty prop) +{ + switch (prop) + { + case SYSPROP_DISPLAY_REFRESH_RATE: + return 60.f; + default: + break; + } -float System_GetPropertyFloat(SystemProperty prop) { - switch (prop) { - case SYSPROP_DISPLAY_REFRESH_RATE: - return 60.f; - default: - return -1; - } + return -1; } std::string System_GetProperty(SystemProperty prop) { return ""; } @@ -801,12 +901,9 @@ void System_SendMessage(const char *command, const char *parameter) {} void NativeUpdate() {} void NativeRender(GraphicsContext *graphicsContext) {} void NativeResized() {} -bool System_InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) { return false; } #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) std::vector __cameraGetDeviceList() { return std::vector(); } -void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { - cb(false, ""); -} +void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); } #endif diff --git a/libretro/libretro.h b/libretro/libretro.h index bfe832c202..1ae508fc93 100644 --- a/libretro/libretro.h +++ b/libretro/libretro.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this libretro API header (libretro.h). @@ -128,7 +128,8 @@ extern "C" { /* LIGHTGUN device is similar to Guncon-2 for PlayStation 2. * It reports X/Y coordinates in screen space (similar to the pointer) - * in the range [-0x8000, 0x7fff] in both axes, with zero being center. + * in the range [-0x8000, 0x7fff] in both axes, with zero being center and + * -0x8000 being out of bounds. * As well as reporting on/off screen state. It features a trigger, * start/select buttons, auxiliary action buttons and a * directional pad. A forced off-screen shot can be requested for @@ -139,7 +140,8 @@ extern "C" { /* The ANALOG device is an extension to JOYPAD (RetroPad). * Similar to DualShock2 it adds two analog sticks and all buttons can * be analog. This is treated as a separate device type as it returns - * axis values in the full analog range of [-0x8000, 0x7fff]. + * axis values in the full analog range of [-0x7fff, 0x7fff], + * although some devices may return -0x8000. * Positive X axis is right. Positive Y axis is down. * Buttons are returned in the range [0, 0x7fff]. * Only use ANALOG type when polling for analog values. @@ -200,6 +202,8 @@ extern "C" { #define RETRO_DEVICE_ID_JOYPAD_L3 14 #define RETRO_DEVICE_ID_JOYPAD_R3 15 +#define RETRO_DEVICE_ID_JOYPAD_MASK 256 + /* Index / Id values for ANALOG device. */ #define RETRO_DEVICE_INDEX_ANALOG_LEFT 0 #define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1 @@ -246,6 +250,7 @@ extern "C" { #define RETRO_DEVICE_ID_POINTER_X 0 #define RETRO_DEVICE_ID_POINTER_Y 1 #define RETRO_DEVICE_ID_POINTER_PRESSED 2 +#define RETRO_DEVICE_ID_POINTER_COUNT 3 /* Returned from retro_get_region(). */ #define RETRO_REGION_NTSC 0 @@ -271,6 +276,12 @@ enum retro_language RETRO_LANGUAGE_POLISH = 14, RETRO_LANGUAGE_VIETNAMESE = 15, RETRO_LANGUAGE_ARABIC = 16, + RETRO_LANGUAGE_GREEK = 17, + RETRO_LANGUAGE_TURKISH = 18, + RETRO_LANGUAGE_SLOVAK = 19, + RETRO_LANGUAGE_PERSIAN = 20, + RETRO_LANGUAGE_HEBREW = 21, + RETRO_LANGUAGE_ASTURIAN = 22, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -450,6 +461,7 @@ enum retro_key RETROK_POWER = 320, RETROK_EURO = 321, RETROK_UNDO = 322, + RETROK_OEM_102 = 323, RETROK_LAST, @@ -481,11 +493,13 @@ enum retro_mod /* Environment commands. */ #define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * -- * Sets screen rotation of graphics. - * Is only implemented if rotation can be accelerated by hardware. * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, * 270 degrees counter-clockwise respectively. */ #define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * -- + * NOTE: As of 2019 this callback is considered deprecated in favor of + * using core options to manage overscan in a more nuanced, core-specific way. + * * Boolean value whether or not the implementation should use overscan, * or crop away overscan. */ @@ -599,8 +613,11 @@ enum retro_mod * GET_VARIABLE. * This allows the frontend to present these variables to * a user dynamically. - * This should be called as early as possible (ideally in - * retro_set_environment). + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterward it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. * * 'data' points to an array of retro_variable structs * terminated by a { NULL, NULL } element. @@ -654,6 +671,15 @@ enum retro_mod /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. * It was not used by any known core at the time, * and was removed from the API. */ +#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 + /* const struct retro_frame_time_callback * -- + * Lets the core know how much time has passed since last + * invocation of retro_run(). + * The frontend can tamper with the timing to fake fast-forward, + * slow-motion, frame stepping, etc. + * In this case the delta time will use the reference value + * in frame_time_callback.. + */ #define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 /* const struct retro_audio_callback * -- * Sets an interface which is used to notify a libretro core about audio @@ -680,15 +706,6 @@ enum retro_mod * A libretro core using SET_AUDIO_CALLBACK should also make use of * SET_FRAME_TIME_CALLBACK. */ -#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 - /* const struct retro_frame_time_callback * -- - * Lets the core know how much time has passed since last - * invocation of retro_run(). - * The frontend can tamper with the timing to fake fast-forward, - * slow-motion, frame stepping, etc. - * In this case the delta time will use the reference value - * in frame_time_callback.. - */ #define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 /* struct retro_rumble_interface * -- * Gets an interface which is used by a libretro core to set @@ -775,17 +792,18 @@ enum retro_mod */ #define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31 /* const char ** -- - * Returns the "save" directory of the frontend. - * This directory can be used to store SRAM, memory cards, - * high scores, etc, if the libretro core + * Returns the "save" directory of the frontend, unless there is no + * save directory available. The save directory should be used to + * store SRAM, memory cards, high scores, etc, if the libretro core * cannot use the regular memory interface (retro_get_memory_data()). * - * NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for - * similar things before. - * They should still check GET_SYSTEM_DIRECTORY if they want to - * be backwards compatible. - * The path here can be NULL. It should only be non-NULL if the - * frontend user has set a specific save path. + * If the frontend cannot designate a save directory, it will return + * NULL to indicate that the core should attempt to operate without a + * save directory set. + * + * NOTE: early libretro cores used the system directory for save + * files. Cores that need to be backwards-compatible can still check + * GET_SYSTEM_DIRECTORY. */ #define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32 /* const struct retro_system_av_info * -- @@ -853,26 +871,39 @@ enum retro_mod #define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35 /* const struct retro_controller_info * -- * This environment call lets a libretro core tell the frontend - * which controller types are recognized in calls to + * which controller subclasses are recognized in calls to * retro_set_controller_port_device(). * - * Some emulators such as Super Nintendo - * support multiple lightgun types which must be specifically - * selected from. - * It is therefore sometimes necessary for a frontend to be able - * to tell the core about a special kind of input device which is - * not covered by the libretro input API. + * Some emulators such as Super Nintendo support multiple lightgun + * types which must be specifically selected from. It is therefore + * sometimes necessary for a frontend to be able to tell the core + * about a special kind of input device which is not specifcally + * provided by the Libretro API. * - * In order for a frontend to understand the workings of an input device, - * it must be a specialized type - * of the generic device types already defined in the libretro API. + * In order for a frontend to understand the workings of those devices, + * they must be defined as a specialized subclass of the generic device + * types already defined in the libretro API. * - * Which devices are supported can vary per input port. * The core must pass an array of const struct retro_controller_info which - * is terminated with a blanked out struct. Each element of the struct - * corresponds to an ascending port index to - * retro_set_controller_port_device(). - * Even if special device types are set in the libretro core, + * is terminated with a blanked out struct. Each element of the + * retro_controller_info struct corresponds to the ascending port index + * that is passed to retro_set_controller_port_device() when that function + * is called to indicate to the core that the frontend has changed the + * active device subclass. SEE ALSO: retro_set_controller_port_device() + * + * The ascending input port indexes provided by the core in the struct + * are generally presented by frontends as ascending User # or Player #, + * such as Player 1, Player 2, Player 3, etc. Which device subclasses are + * supported can vary per input port. + * + * The first inner element of each entry in the retro_controller_info array + * is a retro_controller_description struct that specifies the names and + * codes of all device subclasses that are available for the corresponding + * User or Player, beginning with the generic Libretro device that the + * subclasses are derived from. The second inner element of each entry is the + * total number of subclasses that are listed in the retro_controller_description. + * + * NOTE: Even if special device types are set in the libretro core, * libretro should only poll input based on the base input device types. */ #define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL) @@ -951,7 +982,37 @@ enum retro_mod * A frontend must make sure that the pointer obtained from this function is * writeable (and readable). */ - +#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const struct retro_hw_render_interface ** -- + * Returns an API specific rendering interface for accessing API specific data. + * Not all HW rendering APIs support or need this. + * The contents of the returned pointer is specific to the rendering API + * being used. See the various headers like libretro_vulkan.h, etc. + * + * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called. + * Similarly, after context_destroyed callback returns, + * the contents of the HW_RENDER_INTERFACE are invalidated. + */ +#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const bool * -- + * If true, the libretro implementation supports achievements + * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS + * or via retro_get_memory_data/retro_get_memory_size. + * + * This must be called before the first call to retro_run. + */ +#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const struct retro_hw_render_context_negotiation_interface * -- + * Sets an interface which lets the libretro core negotiate with frontend how a context is created. + * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier. + * This interface will be used when the frontend is trying to create a HW rendering context, + * so it will be used after SET_HW_RENDER, but before the context_reset callback. + */ +#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 + /* uint64_t * -- + * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't + * recognize or support. Should be set in either retro_init or retro_load_game, but not both. + */ #define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* N/A (null) * -- * The frontend will try to use a 'shared' hardware context (mostly applicable @@ -963,19 +1024,307 @@ enum retro_mod * This will do nothing on its own until SET_HW_RENDER env callbacks are * being used. */ - #define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* struct retro_vfs_interface_info * -- * Gets access to the VFS interface. * VFS presence needs to be queried prior to load_game or any * get_system/save/other_directory being called to let front end know * core supports VFS before it starts handing out paths. - * It is recomended to do so in retro_set_environment */ + * It is recomended to do so in retro_set_environment + */ +#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_led_interface * -- + * Gets an interface which is used by a libretro core to set + * state of LEDs. + */ +#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* int * -- + * Tells the core if the frontend wants audio or video. + * If disabled, the frontend will discard the audio or video, + * so the core may decide to skip generating a frame or generating audio. + * This is mainly used for increasing performance. + * Bit 0 (value 1): Enable Video + * Bit 1 (value 2): Enable Audio + * Bit 2 (value 4): Use Fast Savestates. + * Bit 3 (value 8): Hard Disable Audio + * Other bits are reserved for future use and will default to zero. + * If video is disabled: + * * The frontend wants the core to not generate any video, + * including presenting frames via hardware acceleration. + * * The frontend's video frame callback will do nothing. + * * After running the frame, the video output of the next frame should be + * no different than if video was enabled, and saving and loading state + * should have no issues. + * If audio is disabled: + * * The frontend wants the core to not generate any audio. + * * The frontend's audio callbacks will do nothing. + * * After running the frame, the audio output of the next frame should be + * no different than if audio was enabled, and saving and loading state + * should have no issues. + * Fast Savestates: + * * Guaranteed to be created by the same binary that will load them. + * * Will not be written to or read from the disk. + * * Suggest that the core assumes loading state will succeed. + * * Suggest that the core updates its memory buffers in-place if possible. + * * Suggest that the core skips clearing memory. + * * Suggest that the core skips resetting the system. + * * Suggest that the core may skip validation steps. + * Hard Disable Audio: + * * Used for a secondary core when running ahead. + * * Indicates that the frontend will never need audio from the core. + * * Suggests that the core may stop synthesizing audio, but this should not + * compromise emulation accuracy. + * * Audio output for the next frame does not matter, and the frontend will + * never need an accurate audio state in the future. + * * State will never be saved when using Hard Disable Audio. + */ +#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_midi_interface ** -- + * Returns a MIDI interface that can be used for raw data I/O. + */ + +#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* bool * -- + * Boolean value that indicates whether or not the frontend is in + * fastforwarding mode. + */ + +#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* float * -- + * Float value that lets us know what target refresh rate + * is curently in use by the frontend. + * + * The core can use the returned value to set an ideal + * refresh rate/framerate. + */ + +#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* bool * -- + * Boolean value that indicates whether or not the frontend supports + * input bitmasks being returned by retro_input_state_t. The advantage + * of this is that retro_input_state_t has to be only called once to + * grab all button states instead of multiple times. + * + * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id' + * to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD). + * It will return a bitmask of all the digital buttons. + */ + +#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52 + /* unsigned * -- + * Unsigned value is the API version number of the core options + * interface supported by the frontend. If callback return false, + * API version is assumed to be 0. + * + * In legacy code, core options are set by passing an array of + * retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES. + * This may be still be done regardless of the core options + * interface version. + * + * If version is >= 1 however, core options may instead be set by + * passing an array of retro_core_option_definition structs to + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of + * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. + * This allows the core to additionally set option sublabel information + * and/or provide localisation support. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53 + /* const struct retro_core_option_definition ** -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * 'data' points to an array of retro_core_option_definition structs + * terminated by a { NULL, NULL, NULL, {{0}}, NULL } element. + * retro_core_option_definition::key should be namespaced to not collide + * with other implementations' keys. e.g. A core called + * 'foo' should use keys named as 'foo_option'. + * retro_core_option_definition::desc should contain a human readable + * description of the key. + * retro_core_option_definition::info should contain any additional human + * readable information text that a typical user may need to + * understand the functionality of the option. + * retro_core_option_definition::values is an array of retro_core_option_value + * structs terminated by a { NULL, NULL } element. + * > retro_core_option_definition::values[index].value is an expected option + * value. + * > retro_core_option_definition::values[index].label is a human readable + * label used when displaying the value on screen. If NULL, + * the value itself is used. + * retro_core_option_definition::default_value is the default core option + * setting. It must match one of the expected option values in the + * retro_core_option_definition::values array. If it does not, or the + * default value is NULL, the first entry in the + * retro_core_option_definition::values array is treated as the default. + * + * The number of possible options should be very limited, + * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX. + * i.e. it should be feasible to cycle through options + * without a keyboard. + * + * Example entry: + * { + * "foo_option", + * "Speed hack coprocessor X", + * "Provides increased performance at the expense of reduced accuracy", + * { + * { "false", NULL }, + * { "true", NULL }, + * { "unstable", "Turbo (Unstable)" }, + * { NULL, NULL }, + * }, + * "false" + * } + * + * Only strings are operated on. The possible values will + * generally be displayed and stored as-is by the frontend. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54 + /* const struct retro_core_options_intl * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS, + * with the addition of localisation support. The description of the + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted + * for further details. + * + * 'data' points to a retro_core_options_intl struct. + * + * retro_core_options_intl::us is a pointer to an array of + * retro_core_option_definition structs defining the US English + * core options implementation. It must point to a valid array. + * + * retro_core_options_intl::local is a pointer to an array of + * retro_core_option_definition structs defining core options for + * the current frontend language. It may be NULL (in which case + * retro_core_options_intl::us is used by the frontend). Any items + * missing from this array will be read from retro_core_options_intl::us + * instead. + * + * NOTE: Default core option values are always taken from the + * retro_core_options_intl::us array. Any default values in + * retro_core_options_intl::local array will be ignored. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55 + /* struct retro_core_option_display * -- + * + * Allows an implementation to signal the environment to show + * or hide a variable when displaying core options. This is + * considered a *suggestion*. The frontend is free to ignore + * this callback, and its implementation not considered mandatory. + * + * 'data' points to a retro_core_option_display struct + * + * retro_core_option_display::key is a variable identifier + * which has already been set by SET_VARIABLES/SET_CORE_OPTIONS. + * + * retro_core_option_display::visible is a boolean, specifying + * whether variable should be displayed + * + * Note that all core option variables will be set visible by + * default when calling SET_VARIABLES/SET_CORE_OPTIONS. + */ + +#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56 + /* unsigned * -- + * + * Allows an implementation to ask frontend preferred hardware + * context to use. Core should use this information to deal + * with what specific context to request with SET_HW_RENDER. + * + * 'data' points to an unsigned variable + */ + +#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57 + /* unsigned * -- + * Unsigned value is the API version number of the disk control + * interface supported by the frontend. If callback return false, + * API version is assumed to be 0. + * + * In legacy code, the disk control interface is defined by passing + * a struct of type retro_disk_control_callback to + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. + * This may be still be done regardless of the disk control + * interface version. + * + * If version is >= 1 however, the disk control interface may + * instead be defined by passing a struct of type + * retro_disk_control_ext_callback to + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. + * This allows the core to provide additional information about + * disk images to the frontend and/or enables extra + * disk control functionality by the frontend. + */ + +#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58 + /* const struct retro_disk_control_ext_callback * -- + * Sets an interface which frontend can use to eject and insert + * disk images, and also obtain information about individual + * disk image files registered by the core. + * This is used for games which consist of multiple images and + * must be manually swapped out by the user (e.g. PSX, floppy disk + * based systems). + */ + +#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59 + /* unsigned * -- + * Unsigned value is the API version number of the message + * interface supported by the frontend. If callback returns + * false, API version is assumed to be 0. + * + * In legacy code, messages may be displayed in an + * implementation-specific manner by passing a struct + * of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE. + * This may be still be done regardless of the message + * interface version. + * + * If version is >= 1 however, messages may instead be + * displayed by passing a struct of type retro_message_ext + * to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the + * core to specify message logging level, priority and + * destination (OSD, logging interface or both). + */ + +#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60 + /* const struct retro_message_ext * -- + * Sets a message to be displayed in an implementation-specific + * manner for a certain amount of 'frames'. Additionally allows + * the core to specify message logging level, priority and + * destination (OSD, logging interface or both). + * Should not be used for trivial messages, which should simply be + * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a + * fallback, stderr). + */ /* VFS functionality */ /* File paths: - * File paths passed as parameters when using this api shall be well formed unix-style, + * File paths passed as parameters when using this API shall be well formed UNIX-style, * using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator. * Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead). * Other than the directory separator, cores shall not make assumptions about path format: @@ -993,6 +1342,10 @@ enum retro_mod * Introduced in VFS API v1 */ struct retro_vfs_file_handle; +/* Opaque directory handle + * Introduced in VFS API v3 */ +struct retro_vfs_dir_handle; + /* File open flags * Introduced in VFS API v1 */ #define RETRO_VFS_FILE_ACCESS_READ (1 << 0) /* Read only mode */ @@ -1012,6 +1365,12 @@ struct retro_vfs_file_handle; #define RETRO_VFS_SEEK_POSITION_CURRENT 1 #define RETRO_VFS_SEEK_POSITION_END 2 +/* stat() result flags + * Introduced in VFS API v3 */ +#define RETRO_VFS_STAT_IS_VALID (1 << 0) +#define RETRO_VFS_STAT_IS_DIRECTORY (1 << 1) +#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL (1 << 2) + /* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle * Introduced in VFS API v1 */ typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream); @@ -1021,7 +1380,7 @@ typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file * Introduced in VFS API v1 */ typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints); -/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on succes, -1 on failure. +/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure. * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. * Introduced in VFS API v1 */ typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream); @@ -1030,7 +1389,11 @@ typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *st * Introduced in VFS API v1 */ typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream); -/* Get the current read / write position for the file. Returns - 1 for error. +/* Truncate file to specified size. Returns 0 on success or -1 on error + * Introduced in VFS API v2 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length); + +/* Get the current read / write position for the file. Returns -1 for error. * Introduced in VFS API v1 */ typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream); @@ -1058,8 +1421,42 @@ typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path); * Introduced in VFS API v1 */ typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path); +/* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid. + * Additionally stores file size in given variable, unless NULL is given. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size); + +/* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir); + +/* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error. + * Support for the include_hidden argument may vary depending on the platform. + * Introduced in VFS API v3 */ +typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden); + +/* Read the directory entry at the current position, and move the read pointer to the next position. + * Returns true on success, false if already on the last entry. + * Introduced in VFS API v3 */ +typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream); + +/* Get the name of the last entry read. Returns a string on success, or NULL for error. + * The returned string pointer is valid until the next call to readdir or closedir. + * Introduced in VFS API v3 */ +typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream); + +/* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error). + * Introduced in VFS API v3 */ +typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream); + +/* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure. + * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream); + struct retro_vfs_interface { + /* VFS API v1 */ retro_vfs_get_path_t get_path; retro_vfs_open_t open; retro_vfs_close_t close; @@ -1071,6 +1468,16 @@ struct retro_vfs_interface retro_vfs_flush_t flush; retro_vfs_remove_t remove; retro_vfs_rename_t rename; + /* VFS API v2 */ + retro_vfs_truncate_t truncate; + /* VFS API v3 */ + retro_vfs_stat_t stat; + retro_vfs_mkdir_t mkdir; + retro_vfs_opendir_t opendir; + retro_vfs_readdir_t readdir; + retro_vfs_dirent_get_name_t dirent_get_name; + retro_vfs_dirent_is_dir_t dirent_is_dir; + retro_vfs_closedir_t closedir; }; struct retro_vfs_interface_info @@ -1093,6 +1500,7 @@ enum retro_hw_render_interface_type RETRO_HW_RENDER_INTERFACE_D3D10 = 2, RETRO_HW_RENDER_INTERFACE_D3D11 = 3, RETRO_HW_RENDER_INTERFACE_D3D12 = 4, + RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5, RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX }; @@ -1104,49 +1512,41 @@ struct retro_hw_render_interface unsigned interface_version; }; - -#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_led_interface * -- - * Gets an interface which is used by a libretro core to set - * state of LEDs. - */ - typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state); struct retro_led_interface { retro_set_led_state_t set_led_state; }; -#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* int * -- - * Queries the frontend if audio and video are enabled or not. - * If not enabled, the frontend will discard the audio or video, - * so the core may decide to skip producing audio or video. - * Bit 0 (value 1) is set if Video is enabled, - * Bit 1 (value 2) is set if Audio is enabled. - * Other bits are reserved for future use. - */ +/* Retrieves the current state of the MIDI input. + * Returns true if it's enabled, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void); -#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_hw_render_interface ** -- - * Returns an API specific rendering interface for accessing API specific data. - * Not all HW rendering APIs support or need this. - * The contents of the returned pointer is specific to the rendering API - * being used. See the various headers like libretro_vulkan.h, etc. - * - * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called. - * Similarly, after context_destroyed callback returns, - * the contents of the HW_RENDER_INTERFACE are invalidated. - */ +/* Retrieves the current state of the MIDI output. + * Returns true if it's enabled, false otherwise */ +typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void); -#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const bool * -- - * If true, the libretro implementation supports achievements - * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS - * or via retro_get_memory_data/retro_get_memory_size. - * - * This must be called before the first call to retro_run. - */ +/* Reads next byte from the input stream. + * Returns true if byte is read, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte); + +/* Writes byte to the output stream. + * 'delta_time' is in microseconds and represent time elapsed since previous write. + * Returns true if byte is written, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time); + +/* Flushes previously written data. + * Returns true if successful, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void); + +struct retro_midi_interface +{ + retro_midi_input_enabled_t input_enabled; + retro_midi_output_enabled_t output_enabled; + retro_midi_read_t read; + retro_midi_write_t write; + retro_midi_flush_t flush; +}; enum retro_hw_render_context_negotiation_interface_type { @@ -1161,13 +1561,6 @@ struct retro_hw_render_context_negotiation_interface enum retro_hw_render_context_negotiation_interface_type interface_type; unsigned interface_version; }; -#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_hw_render_context_negotiation_interface * -- - * Sets an interface which lets the libretro core negotiate with frontend how a context is created. - * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier. - * This interface will be used when the frontend is trying to create a HW rendering context, - * so it will be used after SET_HW_RENDER, but before the context_reset callback. - */ /* Serialized state is incomplete in some way. Set if serialization is * usable in typical end-user cases but should not be relied upon to @@ -1193,20 +1586,17 @@ struct retro_hw_render_context_negotiation_interface * dependence */ #define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6) -#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 - /* uint64_t * -- - * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't - * recognize or support. Should be set in either retro_init or retro_load_game, but not both. - */ - -#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ -#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ -#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ -#define RETRO_MEMDESC_ALIGN_4 (2 << 16) -#define RETRO_MEMDESC_ALIGN_8 (3 << 16) -#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */ -#define RETRO_MEMDESC_MINSIZE_4 (2 << 24) -#define RETRO_MEMDESC_MINSIZE_8 (3 << 24) +#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ +#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ +#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2) /* The memory area is system RAM. This is main RAM of the gaming system. */ +#define RETRO_MEMDESC_SAVE_RAM (1 << 3) /* The memory area is save RAM. This RAM is usually found on a game cartridge, backed up by a battery. */ +#define RETRO_MEMDESC_VIDEO_RAM (1 << 4) /* The memory area is video RAM (VRAM) */ +#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ +#define RETRO_MEMDESC_ALIGN_4 (2 << 16) +#define RETRO_MEMDESC_ALIGN_8 (3 << 16) +#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */ +#define RETRO_MEMDESC_MINSIZE_4 (2 << 24) +#define RETRO_MEMDESC_MINSIZE_8 (3 << 24) struct retro_memory_descriptor { uint64_t flags; @@ -1607,6 +1997,10 @@ enum retro_sensor_action { RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, RETRO_SENSOR_ACCELEROMETER_DISABLE, + RETRO_SENSOR_GYROSCOPE_ENABLE, + RETRO_SENSOR_GYROSCOPE_DISABLE, + RETRO_SENSOR_ILLUMINANCE_ENABLE, + RETRO_SENSOR_ILLUMINANCE_DISABLE, RETRO_SENSOR_DUMMY = INT_MAX }; @@ -1615,6 +2009,10 @@ enum retro_sensor_action #define RETRO_SENSOR_ACCELEROMETER_X 0 #define RETRO_SENSOR_ACCELEROMETER_Y 1 #define RETRO_SENSOR_ACCELEROMETER_Z 2 +#define RETRO_SENSOR_GYROSCOPE_X 3 +#define RETRO_SENSOR_GYROSCOPE_Y 4 +#define RETRO_SENSOR_GYROSCOPE_Z 5 +#define RETRO_SENSOR_ILLUMINANCE 6 typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port, enum retro_sensor_action action, unsigned rate); @@ -1972,7 +2370,8 @@ struct retro_keyboard_callback retro_keyboard_event_t callback; }; -/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. +/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE & + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. * Should be set for implementations which can swap out multiple disk * images in runtime. * @@ -2030,6 +2429,53 @@ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index, * with replace_image_index. */ typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void); +/* Sets initial image to insert in drive when calling + * core_load_game(). + * Since we cannot pass the initial index when loading + * content (this would require a major API change), this + * is set by the frontend *before* calling the core's + * retro_load_game()/retro_load_game_special() implementation. + * A core should therefore cache the index/path values and handle + * them inside retro_load_game()/retro_load_game_special(). + * - If 'index' is invalid (index >= get_num_images()), the + * core should ignore the set value and instead use 0 + * - 'path' is used purely for error checking - i.e. when + * content is loaded, the core should verify that the + * disk specified by 'index' has the specified file path. + * This is to guard against auto selecting the wrong image + * if (for example) the user should modify an existing M3U + * playlist. We have to let the core handle this because + * set_initial_image() must be called before loading content, + * i.e. the frontend cannot access image paths in advance + * and thus cannot perform the error check itself. + * If set path and content path do not match, the core should + * ignore the set 'index' value and instead use 0 + * Returns 'false' if index or 'path' are invalid, or core + * does not support this functionality + */ +typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path); + +/* Fetches the path of the specified disk image file. + * Returns 'false' if index is invalid (index >= get_num_images()) + * or path is otherwise unavailable. + */ +typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len); + +/* Fetches a core-provided 'label' for the specified disk + * image file. In the simplest case this may be a file name + * (without extension), but for cores with more complex + * content requirements information may be provided to + * facilitate user disk swapping - for example, a core + * running floppy-disk-based content may uniquely label + * save disks, data disks, level disks, etc. with names + * corresponding to in-game disk change prompts (so the + * frontend can provide better user guidance than a 'dumb' + * disk index value). + * Returns 'false' if index is invalid (index >= get_num_images()) + * or label is otherwise unavailable. + */ +typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len); + struct retro_disk_control_callback { retro_set_eject_state_t set_eject_state; @@ -2043,6 +2489,27 @@ struct retro_disk_control_callback retro_add_image_index_t add_image_index; }; +struct retro_disk_control_ext_callback +{ + retro_set_eject_state_t set_eject_state; + retro_get_eject_state_t get_eject_state; + + retro_get_image_index_t get_image_index; + retro_set_image_index_t set_image_index; + retro_get_num_images_t get_num_images; + + retro_replace_image_index_t replace_image_index; + retro_add_image_index_t add_image_index; + + /* NOTE: Frontend will only attempt to record/restore + * last used disk index if both set_initial_image() + * and get_image_path() are implemented */ + retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */ + + retro_get_image_path_t get_image_path; /* Optional - may be NULL */ + retro_get_image_label_t get_image_label; /* Optional - may be NULL */ +}; + enum retro_pixel_format { /* 0RGB1555, native endian. @@ -2073,6 +2540,104 @@ struct retro_message unsigned frames; /* Duration in frames of message. */ }; +enum retro_message_target +{ + RETRO_MESSAGE_TARGET_ALL = 0, + RETRO_MESSAGE_TARGET_OSD, + RETRO_MESSAGE_TARGET_LOG +}; + +enum retro_message_type +{ + RETRO_MESSAGE_TYPE_NOTIFICATION = 0, + RETRO_MESSAGE_TYPE_NOTIFICATION_ALT, + RETRO_MESSAGE_TYPE_STATUS, + RETRO_MESSAGE_TYPE_PROGRESS +}; + +struct retro_message_ext +{ + /* Message string to be displayed/logged */ + const char *msg; + /* Duration (in ms) of message when targeting the OSD */ + unsigned duration; + /* Message priority when targeting the OSD + * > When multiple concurrent messages are sent to + * the frontend and the frontend does not have the + * capacity to display them all, messages with the + * *highest* priority value should be shown + * > There is no upper limit to a message priority + * value (within the bounds of the unsigned data type) + * > In the reference frontend (RetroArch), the same + * priority values are used for frontend-generated + * notifications, which are typically assigned values + * between 0 and 3 depending upon importance */ + unsigned priority; + /* Message logging level (info, warn, error, etc.) */ + enum retro_log_level level; + /* Message destination: OSD, logging interface or both */ + enum retro_message_target target; + /* Message 'type' when targeting the OSD + * > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a + * message should be handled in identical fashion to + * a standard frontend-generated notification + * > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that + * message is a notification that requires user attention + * or action, but that it should be displayed in a manner + * that differs from standard frontend-generated notifications. + * This would typically correspond to messages that should be + * displayed immediately (independently from any internal + * frontend message queue), and/or which should be visually + * distinguishable from frontend-generated notifications. + * For example, a core may wish to inform the user of + * information related to a disk-change event. It is + * expected that the frontend itself may provide a + * notification in this case; if the core sends a + * message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an + * uncomfortable 'double-notification' may occur. A message + * of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore + * be presented such that visual conflict with regular + * notifications does not occur + * > RETRO_MESSAGE_TYPE_STATUS: Indicates that message + * is not a standard notification. This typically + * corresponds to 'status' indicators, such as a core's + * internal FPS, which are intended to be displayed + * either permanently while a core is running, or in + * a manner that does not suggest user attention or action + * is required. 'Status' type messages should therefore be + * displayed in a different on-screen location and in a manner + * easily distinguishable from both standard frontend-generated + * notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT + * > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports + * the progress of an internal core task. For example, in cases + * where a core itself handles the loading of content from a file, + * this may correspond to the percentage of the file that has been + * read. Alternatively, an audio/video playback core may use a + * message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current + * playback position as a percentage of the runtime. 'Progress' type + * messages should therefore be displayed as a literal progress bar, + * where: + * - 'retro_message_ext.msg' is the progress bar title/label + * - 'retro_message_ext.progress' determines the length of + * the progress bar + * NOTE: Message type is a *hint*, and may be ignored + * by the frontend. If a frontend lacks support for + * displaying messages via alternate means than standard + * frontend-generated notifications, it will treat *all* + * messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */ + enum retro_message_type type; + /* Task progress when targeting the OSD and message is + * of type RETRO_MESSAGE_TYPE_PROGRESS + * > -1: Unmetered/indeterminate + * > 0-100: Current progress percentage + * NOTE: Since message type is a hint, a frontend may ignore + * progress values. Where relevant, a core should therefore + * include progress percentage within the message string, + * such that the message intent remains clear when displayed + * as a standard frontend-generated notification */ + int8_t progress; +}; + /* Describes how the libretro implementation maps a libretro input bind * to its internal input system through a human readable string. * This string can be used to better let a user configure input. */ @@ -2106,17 +2671,26 @@ struct retro_system_info * Typically used for a GUI to filter * out extensions. */ - /* If true, retro_load_game() is guaranteed to provide a valid pathname - * in retro_game_info::path. - * ::data and ::size are both invalid. + /* Libretro cores that need to have direct access to their content + * files, including cores which use the path of the content files to + * determine the paths of other files, should set need_fullpath to true. * - * If false, ::data and ::size are guaranteed to be valid, but ::path - * might not be valid. + * Cores should strive for setting need_fullpath to false, + * as it allows the frontend to perform patching, etc. * - * This is typically set to true for libretro implementations that must - * load from file. - * Implementations should strive for setting this to false, as it allows - * the frontend to perform patching, etc. */ + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info::path is guaranteed to have a valid path + * - retro_game_info::data and retro_game_info::size are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - retro_game_info::path may be NULL + * - retro_game_info::data and retro_game_info::size are guaranteed + * to be valid + * + * See also: + * - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY + * - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY + */ bool need_fullpath; /* If true, the frontend is not allowed to extract any archives before @@ -2167,6 +2741,76 @@ struct retro_variable const char *value; }; +struct retro_core_option_display +{ + /* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */ + const char *key; + + /* Specifies whether variable should be displayed + * when presenting core options to the user */ + bool visible; +}; + +/* Maximum number of values permitted for a core option + * > Note: We have to set a maximum value due the limitations + * of the C language - i.e. it is not possible to create an + * array of structs each containing a variable sized array, + * so the retro_core_option_definition values array must + * have a fixed size. The size limit of 128 is a balancing + * act - it needs to be large enough to support all 'sane' + * core options, but setting it too large may impact low memory + * platforms. In practise, if a core option has more than + * 128 values then the implementation is likely flawed. + * To quote the above API reference: + * "The number of possible options should be very limited + * i.e. it should be feasible to cycle through options + * without a keyboard." + */ +#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128 + +struct retro_core_option_value +{ + /* Expected option value */ + const char *value; + + /* Human-readable value label. If NULL, value itself + * will be displayed by the frontend */ + const char *label; +}; + +struct retro_core_option_definition +{ + /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */ + const char *key; + + /* Human-readable core option description (used as menu label) */ + const char *desc; + + /* Human-readable core option information (used as menu sublabel) */ + const char *info; + + /* Array of retro_core_option_value structs, terminated by NULL */ + struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX]; + + /* Default core option value. Must match one of the values + * in the retro_core_option_value array, otherwise will be + * ignored */ + const char *default_value; +}; + +struct retro_core_options_intl +{ + /* Pointer to an array of retro_core_option_definition structs + * - US English implementation + * - Must point to a valid array */ + struct retro_core_option_definition *us; + + /* Pointer to an array of retro_core_option_definition structs + * - Implementation for current frontend language + * - May be NULL */ + struct retro_core_option_definition *local; +}; + struct retro_game_info { const char *path; /* Path to game, UTF-8 encoded. @@ -2301,7 +2945,13 @@ RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info); * will only poll input based on that particular device type. It is only a * hint to the libretro core when a core cannot automatically detect the * appropriate input device type on its own. It is also relevant when a - * core can change its behavior depending on device type. */ + * core can change its behavior depending on device type. + * + * As part of the core's implementation of retro_set_controller_port_device, + * the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the + * frontend if the descriptions for any controls have changed as a + * result of changing the device type. + */ RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device); /* Resets the current game. */ @@ -2333,7 +2983,9 @@ RETRO_API bool retro_unserialize(const void *data, size_t size); RETRO_API void retro_cheat_reset(void); RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code); -/* Loads a game. */ +/* Loads a game. + * Return true to indicate successful loading and false to indicate load failure. + */ RETRO_API bool retro_load_game(const struct retro_game_info *game); /* Loads a "special" kind of game. Should not be used, @@ -2343,7 +2995,7 @@ RETRO_API bool retro_load_game_special( const struct retro_game_info *info, size_t num_info ); -/* Unloads a currently loaded game. */ +/* Unloads the currently loaded game. Called before retro_deinit(void). */ RETRO_API void retro_unload_game(void); /* Gets region of game. */ diff --git a/link_readme.py b/link_readme.py new file mode 100755 index 0000000000..a0df5b9883 --- /dev/null +++ b/link_readme.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +import re +import time +import urllib.request +from urllib.error import HTTPError +import time +from lxml.html import parse + +footer = "" +def replace_foo(match): + first_char = match.group(1) + id = match.group(2) + replace = first_char + "[#"+id+"][]" + + url = "https://github.com/hrydgard/ppsspp/issues/"+id + title = None + while title is None: + try: + page = urllib.request.urlopen(url) + p = parse(page) + title = p.find(".//title").text.split('by')[0].split('ยท')[0].strip() + title = re.sub(r"\"", r'\\"', title) + except HTTPError: + print("Something went wrong, retrying in 10 sec...") + time.sleep(10) + pass + + global footer + addition = "[#"+id+"]: https://github.com/hrydgard/ppsspp/issues/"+id+" \""+title+"\"" + print("Done: " + addition) + footer += addition+"\n" + return replace + +f = open("README.md", "r+") +cont = f.read() +updated = re.sub(r"([^[])#(\d+)", replace_foo, cont) +f.seek(0) +f.write(updated) +f.write(footer) +f.truncate() +f.close() diff --git a/macshaders.sh b/macshaders.sh deleted file mode 100644 index 19e8a352be..0000000000 --- a/macshaders.sh +++ /dev/null @@ -1,11 +0,0 @@ -# AWFUL way to make the shaders macosx compatible! - -cd assets/shaders -for i in *.vs *.fs -do - sed -i '' s/lowp\ //g $i - sed -i '' s/highp\ //g $i - sed -i '' s/mediump\ //g $i - sed -i '' s/#version\ 140//g $i -done -cd ../.. diff --git a/ppsspp_config.h b/ppsspp_config.h index 8743e2290e..e429e629cb 100644 --- a/ppsspp_config.h +++ b/ppsspp_config.h @@ -58,10 +58,6 @@ #define PPSSPP_ARCH_ARM64 1 #define PPSSPP_ARCH_64BIT 1 #define PPSSPP_ARCH_ARM_NEON 1 - //TODO: Remove this compat define - #ifndef ARM64 - #define ARM64 1 - #endif #endif #if defined(__mips64__) @@ -127,10 +123,7 @@ #if PPSSPP_PLATFORM(WINDOWS) #if !PPSSPP_PLATFORM(UWP) #define PPSSPP_API_D3D9 1 - -// Comment this and uncomment PPSSPP_API_D3DX9 if D3DX9 is prefered. -#define PPSSPP_API_D3D9_D3DCOMPILER 1 -// #define PPSSPP_API_D3DX9 1 #endif #define PPSSPP_API_D3D11 1 #endif + diff --git a/pspautotests b/pspautotests index 2970fbcc23..328b839c72 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 2970fbcc23c258ebc03bba922926003fe37555e5 +Subproject commit 328b839c7243e7f733f9eae88d059485e3d808e7 diff --git a/unittest/JitHarness.cpp b/unittest/JitHarness.cpp index 1569048b18..7ff7f589ad 100644 --- a/unittest/JitHarness.cpp +++ b/unittest/JitHarness.cpp @@ -17,8 +17,11 @@ #include -#include "base/timeutil.h" -#include "base/NativeApp.h" +#include "ppsspp_config.h" + +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/TimeUtil.h" #include "Core/ConfigValues.h" #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" @@ -54,7 +57,7 @@ HLEFunction UnitTestFakeSyscalls[] = { double ExecCPUTest() { int blockTicks = 1000000; int total = 0; - double st = real_time_now(); + double st = time_now_d(); do { for (int j = 0; j < 1000; ++j) { currentMIPS->pc = PSP_GetUserMemoryBase(); @@ -66,8 +69,8 @@ double ExecCPUTest() { ++total; } } - while (real_time_now() - st < 0.5); - double elapsed = real_time_now() - st; + while (time_now_d() - st < 0.5); + double elapsed = time_now_d() - st; return total / elapsed; } @@ -172,9 +175,9 @@ bool TestJit() { // Disassemble JitBlockCache *cache = MIPSComp::jit->GetBlockCache(); JitBlock *block = cache->GetBlock(0); // Should only be one block. -#if defined(ARM) +#if PPSSPP_ARCH(ARM) std::vector lines = DisassembleArm2(block->normalEntry, block->codeSize); -#elif defined(ARM64) +#elif PPSSPP_ARCH(ARM64) std::vector lines = DisassembleArm64(block->normalEntry, block->codeSize); #else std::vector lines = DisassembleX86(block->normalEntry, block->codeSize); diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp index 75e5985888..965fcee639 100644 --- a/unittest/TestVertexJit.cpp +++ b/unittest/TestVertexJit.cpp @@ -15,8 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "base/timeutil.h" #include "Common/Common.h" +#include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "GPU/Common/VertexDecoderCommon.h" @@ -86,14 +86,14 @@ public: SetupExecute(vtype, useJit); int total = 0; - double st = real_time_now(); + double st = time_now_d(); do { for (int j = 0; j < ROUNDS; ++j) { dec_->DecodeVerts(dst_, src_, indexLowerBound_, indexUpperBound); ++total; } - } while (real_time_now() - st < 0.5); - double elapsed = real_time_now() - st; + } while (time_now_d() - st < 0.5); + double elapsed = time_now_d() - st; return total / elapsed; } diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index e2b94af96a..edb5939cba 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -24,23 +24,27 @@ // TODO: Make a test of nice unittest asserts and count successes etc. // Or just integrate with an existing testing framework. - #include #include #include #include #include +#if defined(ANDROID) +#include +#endif -#include "base/NativeApp.h" -#include "base/logging.h" -#include "input/input_state.h" +#include "ppsspp_config.h" +#include "Common/System/NativeApp.h" +#include "Common/System/System.h" +#include "Common/Input/InputState.h" #include "ext/disarm.h" -#include "math/math_util.h" -#include "util/text/parsers.h" +#include "Common/Math/math_util.h" +#include "Common/Data/Text/Parsers.h" #include "Common/ArmEmitter.h" #include "Common/BitScan.h" #include "Common/CPUDetect.h" +#include "Common/Log.h" #include "Core/Config.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/MemMap.h" @@ -62,6 +66,16 @@ bool System_GetPropertyBool(SystemProperty prop) { return false; } +#if defined(ANDROID) +JNIEnv *getEnv() { + return nullptr; +} + +jclass findClass(const char *name) { + return nullptr; +} +#endif + #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 #endif @@ -326,7 +340,7 @@ bool TestMatrixTranspose() { } void TestGetMatrix(int matrix, MatrixSize sz) { - ILOG("Testing matrix %s", GetMatrixNotation(matrix, sz)); + INFO_LOG(SYSTEM, "Testing matrix %s", GetMatrixNotation(matrix, sz)); u8 fullMatrix[16]; u8 cols[4]; @@ -344,8 +358,8 @@ void TestGetMatrix(int matrix, MatrixSize sz) { // int rowName = GetRowName(matrix, sz, i, 0); int colName = cols[i]; int rowName = rows[i]; - ILOG("Column %i: %s", i, GetVectorNotation(colName, vsz)); - ILOG("Row %i: %s", i, GetVectorNotation(rowName, vsz)); + INFO_LOG(SYSTEM, "Column %i: %s", i, GetVectorNotation(colName, vsz)); + INFO_LOG(SYSTEM, "Row %i: %s", i, GetVectorNotation(rowName, vsz)); u8 colRegs[4]; u8 rowRegs[4]; @@ -366,12 +380,12 @@ void TestGetMatrix(int matrix, MatrixSize sz) { c << (int)fullMatrix[j * 4 + i] << " "; d << (int)rowRegs[j] << " "; } - ILOG("Col: %s vs %s", a.str().c_str(), b.str().c_str()); + INFO_LOG(SYSTEM, "Col: %s vs %s", a.str().c_str(), b.str().c_str()); if (a.str() != b.str()) - ILOG("WRONG!"); - ILOG("Row: %s vs %s", c.str().c_str(), d.str().c_str()); + INFO_LOG(SYSTEM, "WRONG!"); + INFO_LOG(SYSTEM, "Row: %s vs %s", c.str().c_str(), d.str().c_str()); if (c.str() != d.str()) - ILOG("WRONG!"); + INFO_LOG(SYSTEM, "WRONG!"); } } @@ -547,13 +561,13 @@ bool TestArm64Emitter(); bool TestX64Emitter(); TestItem availableTests[] = { -#if defined(ARM64) || defined(_M_X64) || defined(_M_IX86) +#if PPSSPP_ARCH(ARM64) || PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) TEST_ITEM(Arm64Emitter), #endif -#if defined(ARM) || defined(_M_X64) || defined(_M_IX86) +#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) TEST_ITEM(ArmEmitter), #endif -#if defined(_M_X64) || defined(_M_IX86) +#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) TEST_ITEM(X64Emitter), #endif TEST_ITEM(VertexJit), diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj index 86caf65925..a401a081b7 100644 --- a/unittest/UnitTests.vcxproj +++ b/unittest/UnitTests.vcxproj @@ -169,7 +169,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/x86/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86/include;../ext;../common;..;../ext/glew;../ext/zlib true false false @@ -191,7 +191,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/x86_64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86_64/include;../ext;../common;..;../ext/glew;../ext/zlib true false false @@ -214,7 +214,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/aarch64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/aarch64/include;../ext;../common;..;../ext/glew;../ext/zlib true false false @@ -237,7 +237,7 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/arm/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/arm/include;../ext;../common;..;../ext/glew;../ext/zlib true false false @@ -264,7 +264,7 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/x86/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86/include;../ext;../common;..;../ext/glew;../ext/zlib false Size true @@ -291,7 +291,7 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/x86_64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/x86_64/include;../ext;../common;..;../ext/glew;../ext/zlib false true false @@ -320,7 +320,7 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/aarch64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/aarch64/include;../ext;../common;..;../ext/glew;../ext/zlib false true false @@ -349,7 +349,7 @@ true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ffmpeg/Windows/arm/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib + ../ffmpeg/Windows/arm/include;../ext;../common;..;../ext/glew;../ext/zlib false true false @@ -414,9 +414,6 @@ {457f45d2-556f-47bc-a31d-aff0d15beaed} - - {c4df647e-80ea-4111-a0a8-218b1b711e18} - {004b8d11-2be3-4bd9-ab40-2be04cf2096f} @@ -429,4 +426,4 @@ - \ No newline at end of file +