mirror of
https://github.com/SSimco/Cemu.git
synced 2024-11-26 23:00:29 +00:00
Merge branch 'main' into android
This commit is contained in:
commit
25ea6ddf47
20
.github/workflows/build.yml
vendored
20
.github/workflows/build.yml
vendored
@ -176,7 +176,7 @@ jobs:
|
||||
path: ./bin/Cemu.exe
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-12
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v4
|
||||
@ -198,17 +198,14 @@ jobs:
|
||||
- name: "Install system dependencies"
|
||||
run: |
|
||||
brew update
|
||||
brew install llvm@15 ninja nasm automake libtool
|
||||
brew install cmake ninja
|
||||
brew install ninja nasm automake libtool
|
||||
|
||||
- name: "Build and install molten-vk"
|
||||
- name: "Install molten-vk"
|
||||
run: |
|
||||
git clone https://github.com/KhronosGroup/MoltenVK.git
|
||||
cd MoltenVK
|
||||
git checkout bf097edc74ec3b6dfafdcd5a38d3ce14b11952d6
|
||||
./fetchDependencies --macos
|
||||
make macos
|
||||
make install
|
||||
curl -L -O https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.9/MoltenVK-macos.tar
|
||||
tar xf MoltenVK-macos.tar
|
||||
sudo mkdir -p /usr/local/lib
|
||||
sudo cp MoltenVK/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib /usr/local/lib
|
||||
|
||||
- name: "Setup cmake"
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
@ -239,9 +236,8 @@ jobs:
|
||||
cd build
|
||||
cmake .. ${{ env.BUILD_FLAGS }} \
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DMACOS_BUNDLE=ON \
|
||||
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@15/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@15/bin/clang++ \
|
||||
-G Ninja
|
||||
|
||||
- name: "Build Cemu"
|
||||
|
50
BUILD.md
50
BUILD.md
@ -16,11 +16,11 @@
|
||||
- [Compiling Errors](#compiling-errors)
|
||||
- [Building Errors](#building-errors)
|
||||
- [macOS](#macos)
|
||||
- [On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used](#on-apple-silicon-macs-rosetta-2-and-the-x86_64-version-of-homebrew-must-be-used)
|
||||
- [Installing brew](#installing-brew)
|
||||
- [Installing Dependencies](#installing-dependencies)
|
||||
- [Build Cemu using CMake and Clang](#build-cemu-using-cmake-and-clang)
|
||||
- [Updating Cemu and source code](#updating-cemu-and-source-code)
|
||||
- [Installing Tool Dependencies](#installing-tool-dependencies)
|
||||
- [Installing Library Dependencies](#installing-library-dependencies)
|
||||
- [Build Cemu using CMake](#build-cemu-using-cmake)
|
||||
- [Updating Cemu and source code](#updating-cemu-and-source-code)
|
||||
|
||||
## Windows
|
||||
|
||||
@ -141,31 +141,41 @@ If you are getting a different error than any of the errors listed above, you ma
|
||||
|
||||
## macOS
|
||||
|
||||
To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and
|
||||
below, built in LLVM, and Xcode LLVM don't support the C++20 feature set required. The OpenGL graphics
|
||||
API isn't support on macOS, Vulkan must be used. Additionally Vulkan must be used through the
|
||||
Molten-VK compatibility layer
|
||||
|
||||
### On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used
|
||||
|
||||
You can skip this section if you have an Intel Mac. Every time you compile, you need to perform steps 2.
|
||||
|
||||
1. `softwareupdate --install-rosetta` # Install Rosetta 2 if you don't have it. This only has to be done once
|
||||
2. `arch -x86_64 zsh` # run an x64 shell
|
||||
To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and below
|
||||
don't support the C++20 feature set required, so either install LLVM from Homebrew or make sure that
|
||||
you have a recent enough version of Xcode. Xcode 15 is known to work. The OpenGL graphics API isn't
|
||||
supported on macOS, so Vulkan must be used through the Molten-VK compatibility layer.
|
||||
|
||||
### Installing brew
|
||||
|
||||
1. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
|
||||
2. `eval "$(/usr/local/Homebrew/bin/brew shellenv)"` # set x86_64 brew env
|
||||
2. Set up the Homebrew shell environment:
|
||||
1. **On an Intel Mac:** `eval "$(/usr/local/Homebrew/bin/brew shellenv)"`
|
||||
2. **On an Apple Silicon Mac:** eval `"$(/opt/homebrew/bin/brew shellenv)"`
|
||||
|
||||
### Installing Dependencies
|
||||
### Installing Tool Dependencies
|
||||
|
||||
`brew install boost git cmake llvm ninja nasm molten-vk automake libtool`
|
||||
The native versions of these can be used regardless of what type of Mac you have.
|
||||
|
||||
`brew install git cmake ninja nasm automake libtool`
|
||||
|
||||
### Installing Library Dependencies
|
||||
|
||||
**On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used to install these dependencies:**
|
||||
1. `softwareupdate --install-rosetta` # Install Rosetta 2 if you don't have it. This only has to be done once
|
||||
2. `arch -x86_64 zsh` # run an x64 shell
|
||||
3. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
|
||||
4. `eval "$(/usr/local/Homebrew/bin/brew shellenv)"`
|
||||
|
||||
Then install the dependencies:
|
||||
|
||||
`brew install boost molten-vk`
|
||||
|
||||
### Build Cemu using CMake
|
||||
|
||||
### Build Cemu using CMake and Clang
|
||||
1. `git clone --recursive https://github.com/cemu-project/Cemu`
|
||||
2. `cd Cemu`
|
||||
3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ -G Ninja`
|
||||
3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_OSX_ARCHITECTURES=x86_64 -G Ninja`
|
||||
4. `cmake --build build`
|
||||
5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`.
|
||||
|
||||
|
@ -101,6 +101,7 @@ endif()
|
||||
|
||||
if (APPLE)
|
||||
enable_language(OBJC OBJCXX)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
@ -236,7 +237,7 @@ if (ENABLE_CUBEB)
|
||||
option(BUILD_TOOLS "" OFF)
|
||||
option(BUNDLE_SPEEX "" OFF)
|
||||
set(USE_WINMM OFF CACHE BOOL "")
|
||||
add_subdirectory("dependencies/cubeb" EXCLUDE_FROM_ALL)
|
||||
add_subdirectory("dependencies/cubeb" EXCLUDE_FROM_ALL SYSTEM)
|
||||
set_property(TARGET cubeb PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
add_library(cubeb::cubeb ALIAS cubeb)
|
||||
endif()
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
12
dependencies/ih264d/CMakeLists.txt
vendored
12
dependencies/ih264d/CMakeLists.txt
vendored
@ -117,7 +117,13 @@ add_library (ih264d
|
||||
"decoder/ivd.h"
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
||||
if (CMAKE_OSX_ARCHITECTURES)
|
||||
set(IH264D_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES})
|
||||
else()
|
||||
set(IH264D_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
|
||||
if (IH264D_ARCHITECTURE STREQUAL "x86_64" OR IH264D_ARCHITECTURE STREQUAL "amd64" OR IH264D_ARCHITECTURE STREQUAL "AMD64")
|
||||
set(LIBAVCDEC_X86_INCLUDES "common/x86" "decoder/x86")
|
||||
include_directories("common/" "decoder/" ${LIBAVCDEC_X86_INCLUDES})
|
||||
target_sources(ih264d PRIVATE
|
||||
@ -140,7 +146,7 @@ target_sources(ih264d PRIVATE
|
||||
"decoder/x86/ih264d_function_selector_sse42.c"
|
||||
"decoder/x86/ih264d_function_selector_ssse3.c"
|
||||
)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
elseif(IH264D_ARCHITECTURE STREQUAL "aarch64" OR IH264D_ARCHITECTURE STREQUAL "arm64")
|
||||
enable_language( C CXX ASM )
|
||||
set(LIBAVCDEC_ARM_INCLUDES "common/armv8" "decoder/arm")
|
||||
include_directories("common/" "decoder/" ${LIBAVCDEC_ARM_INCLUDES})
|
||||
@ -178,7 +184,7 @@ target_sources(ih264d PRIVATE
|
||||
)
|
||||
target_compile_options(ih264d PRIVATE -DARMV8)
|
||||
else()
|
||||
message(FATAL_ERROR "ih264d unknown architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
message(FATAL_ERROR "ih264d unknown architecture: ${IH264D_ARCHITECTURE}")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
1
dist/linux/appimage.sh
vendored
1
dist/linux/appimage.sh
vendored
@ -50,7 +50,6 @@ fi
|
||||
echo "Cemu Version Cemu-${GITVERSION}"
|
||||
|
||||
rm AppDir/usr/lib/libwayland-client.so.0
|
||||
cp /lib/x86_64-linux-gnu/libstdc++.so.6 AppDir/usr/lib/
|
||||
echo -e "export LC_ALL=C\nexport FONTCONFIG_PATH=/etc/fonts" >> AppDir/apprun-hooks/linuxdeploy-plugin-gtk.sh
|
||||
VERSION="${GITVERSION}" ./mkappimage.AppImage --appimage-extract-and-run "${GITHUB_WORKSPACE}"/AppDir
|
||||
|
||||
|
@ -146,8 +146,17 @@ void SwapchainInfoVk::Create()
|
||||
UnrecoverableError("Failed to create semaphore for swapchain acquire");
|
||||
}
|
||||
|
||||
VkFenceCreateInfo fenceInfo = {};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
result = vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create fence for swapchain");
|
||||
|
||||
m_acquireIndex = 0;
|
||||
hasDefinedSwapchainImage = false;
|
||||
|
||||
m_queueDepth = 0;
|
||||
}
|
||||
|
||||
void SwapchainInfoVk::Cleanup()
|
||||
@ -177,6 +186,12 @@ void SwapchainInfoVk::Cleanup()
|
||||
m_swapchainFramebuffers.clear();
|
||||
|
||||
|
||||
if (m_imageAvailableFence)
|
||||
{
|
||||
WaitAvailableFence();
|
||||
vkDestroyFence(m_logicalDevice, m_imageAvailableFence, nullptr);
|
||||
m_imageAvailableFence = nullptr;
|
||||
}
|
||||
if (m_swapchain)
|
||||
{
|
||||
vkDestroySwapchainKHR(m_logicalDevice, m_swapchain, nullptr);
|
||||
@ -189,6 +204,18 @@ bool SwapchainInfoVk::IsValid() const
|
||||
return m_swapchain && !m_acquireSemaphores.empty();
|
||||
}
|
||||
|
||||
void SwapchainInfoVk::WaitAvailableFence()
|
||||
{
|
||||
if(m_awaitableFence != VK_NULL_HANDLE)
|
||||
vkWaitForFences(m_logicalDevice, 1, &m_awaitableFence, VK_TRUE, UINT64_MAX);
|
||||
m_awaitableFence = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void SwapchainInfoVk::ResetAvailableFence() const
|
||||
{
|
||||
vkResetFences(m_logicalDevice, 1, &m_imageAvailableFence);
|
||||
}
|
||||
|
||||
VkSemaphore SwapchainInfoVk::ConsumeAcquireSemaphore()
|
||||
{
|
||||
VkSemaphore ret = m_currentSemaphore;
|
||||
@ -198,8 +225,10 @@ VkSemaphore SwapchainInfoVk::ConsumeAcquireSemaphore()
|
||||
|
||||
bool SwapchainInfoVk::AcquireImage()
|
||||
{
|
||||
ResetAvailableFence();
|
||||
|
||||
VkSemaphore acquireSemaphore = m_acquireSemaphores[m_acquireIndex];
|
||||
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, 1'000'000'000, acquireSemaphore, nullptr, &swapchainImageIndex);
|
||||
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, 1'000'000'000, acquireSemaphore, m_imageAvailableFence, &swapchainImageIndex);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
m_shouldRecreate = true;
|
||||
if (result == VK_TIMEOUT)
|
||||
@ -216,6 +245,7 @@ bool SwapchainInfoVk::AcquireImage()
|
||||
return false;
|
||||
}
|
||||
m_currentSemaphore = acquireSemaphore;
|
||||
m_awaitableFence = m_imageAvailableFence;
|
||||
m_acquireIndex = (m_acquireIndex + 1) % m_swapchainImages.size();
|
||||
|
||||
return true;
|
||||
@ -319,6 +349,7 @@ VkExtent2D SwapchainInfoVk::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& cap
|
||||
|
||||
VkPresentModeKHR SwapchainInfoVk::ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes)
|
||||
{
|
||||
m_maxQueued = 0;
|
||||
const auto vsyncState = (VSync)GetConfig().vsync.GetValue();
|
||||
if (vsyncState == VSync::MAILBOX)
|
||||
{
|
||||
@ -345,6 +376,7 @@ VkPresentModeKHR SwapchainInfoVk::ChoosePresentMode(const std::vector<VkPresentM
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
m_maxQueued = 1;
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,9 @@ struct SwapchainInfoVk
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
void WaitAvailableFence();
|
||||
void ResetAvailableFence() const;
|
||||
|
||||
bool AcquireImage();
|
||||
// retrieve semaphore of last acquire for submitting a wait operation
|
||||
// only one wait operation must be submitted per acquire (which submits a single signal operation)
|
||||
@ -67,6 +70,9 @@ struct SwapchainInfoVk
|
||||
VkSwapchainKHR m_swapchain{};
|
||||
Vector2i m_desiredExtent{};
|
||||
uint32 swapchainImageIndex = (uint32)-1;
|
||||
uint64 m_presentId = 1;
|
||||
uint64 m_queueDepth = 0; // number of frames with pending presentation requests
|
||||
uint64 m_maxQueued = 0; // the maximum number of frames with presentation requests.
|
||||
|
||||
|
||||
// swapchain image ringbuffer (indexed by swapchainImageIndex)
|
||||
@ -80,6 +86,8 @@ struct SwapchainInfoVk
|
||||
private:
|
||||
uint32 m_acquireIndex = 0;
|
||||
std::vector<VkSemaphore> m_acquireSemaphores; // indexed by m_acquireIndex
|
||||
VkFence m_imageAvailableFence{};
|
||||
VkFence m_awaitableFence = VK_NULL_HANDLE;
|
||||
VkSemaphore m_currentSemaphore = VK_NULL_HANDLE;
|
||||
|
||||
std::array<uint32, 2> m_swapchainQueueFamilyIndices;
|
||||
|
@ -192,6 +192,9 @@ VKFUNC_DEVICE(vkCmdPipelineBarrier2KHR);
|
||||
VKFUNC_DEVICE(vkCmdBeginRenderingKHR);
|
||||
VKFUNC_DEVICE(vkCmdEndRenderingKHR);
|
||||
|
||||
// khr_present_wait
|
||||
VKFUNC_DEVICE(vkWaitForPresentKHR);
|
||||
|
||||
// transform feedback extension
|
||||
VKFUNC_DEVICE(vkCmdBindTransformFeedbackBuffersEXT);
|
||||
VKFUNC_DEVICE(vkCmdBeginTransformFeedbackEXT);
|
||||
|
@ -44,7 +44,9 @@ const std::vector<const char*> kOptionalDeviceExtensions =
|
||||
VK_EXT_FILTER_CUBIC_EXTENSION_NAME, // not supported by any device yet
|
||||
VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
|
||||
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
|
||||
VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME
|
||||
VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
|
||||
VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
|
||||
VK_KHR_PRESENT_ID_EXTENSION_NAME
|
||||
};
|
||||
|
||||
const std::vector<const char*> kRequiredDeviceExtensions =
|
||||
@ -255,11 +257,23 @@ void VulkanRenderer::GetDeviceFeatures()
|
||||
pcc.pNext = prevStruct;
|
||||
prevStruct = &pcc;
|
||||
|
||||
VkPhysicalDevicePresentIdFeaturesKHR pidf{};
|
||||
pidf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR;
|
||||
pidf.pNext = prevStruct;
|
||||
prevStruct = &pidf;
|
||||
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR pwf{};
|
||||
pwf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR;
|
||||
pwf.pNext = prevStruct;
|
||||
prevStruct = &pwf;
|
||||
|
||||
VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{};
|
||||
physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
physicalDeviceFeatures2.pNext = prevStruct;
|
||||
|
||||
vkGetPhysicalDeviceFeatures2(m_physicalDevice, &physicalDeviceFeatures2);
|
||||
|
||||
cemuLog_log(LogType::Force, "Vulkan: present_wait extension: {}", (pwf.presentWait && pidf.presentId) ? "supported" : "unsupported");
|
||||
m_featureControl.deviceFeatures.geometry_shader = physicalDeviceFeatures2.features.geometryShader;
|
||||
m_featureControl.deviceFeatures.logic_op = physicalDeviceFeatures2.features.logicOp;
|
||||
|
||||
@ -489,6 +503,24 @@ VulkanRenderer::VulkanRenderer()
|
||||
customBorderColorFeature.customBorderColors = VK_TRUE;
|
||||
customBorderColorFeature.customBorderColorWithoutFormat = VK_TRUE;
|
||||
}
|
||||
// enable VK_KHR_present_id
|
||||
VkPhysicalDevicePresentIdFeaturesKHR presentIdFeature{};
|
||||
if(m_featureControl.deviceExtensions.present_wait)
|
||||
{
|
||||
presentIdFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR;
|
||||
presentIdFeature.pNext = deviceExtensionFeatures;
|
||||
deviceExtensionFeatures = &presentIdFeature;
|
||||
presentIdFeature.presentId = VK_TRUE;
|
||||
}
|
||||
// enable VK_KHR_present_wait
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeature{};
|
||||
if(m_featureControl.deviceExtensions.present_wait)
|
||||
{
|
||||
presentWaitFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR;
|
||||
presentWaitFeature.pNext = deviceExtensionFeatures;
|
||||
deviceExtensionFeatures = &presentWaitFeature;
|
||||
presentWaitFeature.presentWait = VK_TRUE;
|
||||
}
|
||||
|
||||
std::vector<const char*> used_extensions;
|
||||
VkDeviceCreateInfo createInfo = CreateDeviceCreateInfo(queueCreateInfos, deviceFeatures, deviceExtensionFeatures, used_extensions);
|
||||
@ -1048,6 +1080,10 @@ VkDeviceCreateInfo VulkanRenderer::CreateDeviceCreateInfo(const std::vector<VkDe
|
||||
used_extensions.emplace_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
||||
if (m_featureControl.deviceExtensions.shader_float_controls)
|
||||
used_extensions.emplace_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
||||
if (m_featureControl.deviceExtensions.present_wait)
|
||||
used_extensions.emplace_back(VK_KHR_PRESENT_ID_EXTENSION_NAME);
|
||||
if (m_featureControl.deviceExtensions.present_wait)
|
||||
used_extensions.emplace_back(VK_KHR_PRESENT_WAIT_EXTENSION_NAME);
|
||||
|
||||
VkDeviceCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
@ -1145,6 +1181,7 @@ bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device,
|
||||
info.deviceExtensions.shader_float_controls = isExtensionAvailable(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
||||
info.deviceExtensions.dynamic_rendering = false; // isExtensionAvailable(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
||||
// dynamic rendering doesn't provide any benefits for us right now. Driver implementations are very unoptimized as of Feb 2022
|
||||
info.deviceExtensions.present_wait = isExtensionAvailable(VK_KHR_PRESENT_WAIT_EXTENSION_NAME) && isExtensionAvailable(VK_KHR_PRESENT_ID_EXTENSION_NAME);
|
||||
|
||||
// check for framedebuggers
|
||||
info.debugMarkersSupported = false;
|
||||
@ -2723,11 +2760,21 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
|
||||
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
const size_t currentFrameCmdBufferID = GetCurrentCommandBufferId();
|
||||
|
||||
VkSemaphore presentSemaphore = chainInfo.m_presentSemaphores[chainInfo.swapchainImageIndex];
|
||||
SubmitCommandBuffer(presentSemaphore); // submit all command and signal semaphore
|
||||
|
||||
cemu_assert_debug(m_numSubmittedCmdBuffers > 0);
|
||||
|
||||
// wait for the previous frame to finish rendering
|
||||
WaitCommandBufferFinished(m_commandBufferIDOfPrevFrame);
|
||||
m_commandBufferIDOfPrevFrame = currentFrameCmdBufferID;
|
||||
|
||||
chainInfo.WaitAvailableFence();
|
||||
|
||||
VkPresentIdKHR presentId = {};
|
||||
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.swapchainCount = 1;
|
||||
@ -2737,6 +2784,24 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
presentInfo.pWaitSemaphores = &presentSemaphore;
|
||||
|
||||
// if present_wait is available and enabled, add frame markers to present requests
|
||||
// and limit the number of queued present operations
|
||||
if (m_featureControl.deviceExtensions.present_wait && chainInfo.m_maxQueued > 0)
|
||||
{
|
||||
presentId.sType = VK_STRUCTURE_TYPE_PRESENT_ID_KHR;
|
||||
presentId.swapchainCount = 1;
|
||||
presentId.pPresentIds = &chainInfo.m_presentId;
|
||||
|
||||
presentInfo.pNext = &presentId;
|
||||
|
||||
if(chainInfo.m_queueDepth >= chainInfo.m_maxQueued)
|
||||
{
|
||||
uint64 waitFrameId = chainInfo.m_presentId - chainInfo.m_queueDepth;
|
||||
vkWaitForPresentKHR(m_logicalDevice, chainInfo.m_swapchain, waitFrameId, 40'000'000);
|
||||
chainInfo.m_queueDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo);
|
||||
if (result < 0 && result != VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
@ -2745,6 +2810,12 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
|
||||
if(result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
chainInfo.m_shouldRecreate = true;
|
||||
|
||||
if(result >= 0)
|
||||
{
|
||||
chainInfo.m_queueDepth++;
|
||||
chainInfo.m_presentId++;
|
||||
}
|
||||
|
||||
#if !__ANDROID__
|
||||
if(result == VK_SUBOPTIMAL_KHR)
|
||||
chainInfo.m_shouldRecreate = true;
|
||||
|
@ -455,6 +455,7 @@ private:
|
||||
bool synchronization2 = false; // VK_KHR_synchronization2
|
||||
bool dynamic_rendering = false; // VK_KHR_dynamic_rendering
|
||||
bool shader_float_controls = false; // VK_KHR_shader_float_controls
|
||||
bool present_wait = false; // VK_KHR_present_wait
|
||||
}deviceExtensions;
|
||||
|
||||
struct
|
||||
@ -468,7 +469,7 @@ private:
|
||||
bool shaderRoundingModeRTEFloat32{ false };
|
||||
}shaderFloatControls; // from VK_KHR_shader_float_controls
|
||||
|
||||
struct
|
||||
struct
|
||||
{
|
||||
bool debug_utils = false; // VK_EXT_DEBUG_UTILS
|
||||
}instanceExtensions;
|
||||
@ -646,6 +647,7 @@ private:
|
||||
|
||||
size_t m_commandBufferIndex = 0; // current buffer being filled
|
||||
size_t m_commandBufferSyncIndex = 0; // latest buffer that finished execution (updated on submit)
|
||||
size_t m_commandBufferIDOfPrevFrame = 0;
|
||||
std::array<VkFence, kCommandBufferPoolSize> m_cmd_buffer_fences;
|
||||
std::array<VkCommandBuffer, kCommandBufferPoolSize> m_commandBuffers;
|
||||
std::array<VkSemaphore, kCommandBufferPoolSize> m_commandBufferSemaphores;
|
||||
|
@ -137,6 +137,10 @@ namespace iosu
|
||||
this->task_settings.taskType = settings->taskType;
|
||||
|
||||
curl = std::shared_ptr<CURL>(curl_easy_init(), curl_easy_cleanup);
|
||||
if(GetConfig().proxy_server.GetValue() != "")
|
||||
{
|
||||
curl_easy_setopt(curl.get(), CURLOPT_PROXY, GetConfig().proxy_server.GetValue().c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -112,7 +112,7 @@ namespace nn
|
||||
|
||||
nnResult _Async_OfflineDB_DownloadPostDataListParam_DownloadPostDataList(coreinit::OSEvent* event, DownloadedTopicData* downloadedTopicData, DownloadedPostData* downloadedPostData, uint32be* postCountOut, uint32 maxCount, DownloadPostDataListParam* param)
|
||||
{
|
||||
scope_exit _se([&](){coreinit::OSSignalEvent(event);});
|
||||
stdx::scope_exit _se([&](){coreinit::OSSignalEvent(event);});
|
||||
|
||||
uint64 titleId = CafeSystem::GetForegroundTitleId();
|
||||
|
||||
@ -184,7 +184,7 @@ namespace nn
|
||||
|
||||
nnResult _Async_OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(coreinit::OSEvent* event, DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize)
|
||||
{
|
||||
scope_exit _se([&](){coreinit::OSSignalEvent(event);});
|
||||
stdx::scope_exit _se([&](){coreinit::OSSignalEvent(event);});
|
||||
|
||||
if (!_this->TestFlags(_this, DownloadedDataBase::FLAGS::HAS_EXTERNAL_IMAGE))
|
||||
return OLV_RESULT_MISSING_DATA;
|
||||
|
@ -1017,11 +1017,7 @@ namespace nsyshid
|
||||
std::array<uint8, 16> InfinityUSB::GenerateInfinityFigureKey(const std::vector<uint8>& sha1Data)
|
||||
{
|
||||
std::array<uint8, 20> digest = {};
|
||||
SHA_CTX ctx;
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, sha1Data.data(), sha1Data.size());
|
||||
SHA1_Final(digest.data(), &ctx);
|
||||
OPENSSL_cleanse(&ctx, sizeof(ctx));
|
||||
SHA1(sha1Data.data(), sha1Data.size(), digest.data());
|
||||
// Infinity AES keys are the first 16 bytes of the SHA1 Digest, every set of 4 bytes need to be
|
||||
// reversed due to endianness
|
||||
std::array<uint8, 16> key = {};
|
||||
|
@ -1210,6 +1210,14 @@ void nsysnetExport_select(PPCInterpreter_t* hCPU)
|
||||
|
||||
timeval tv = { 0 };
|
||||
|
||||
if (timeOut == NULL)
|
||||
{
|
||||
// return immediately
|
||||
cemuLog_log(LogType::Socket, "select returned immediately because of null timeout");
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 msTimeout = (_swapEndianU32(timeOut->tv_usec) / 1000) + (_swapEndianU32(timeOut->tv_sec) * 1000);
|
||||
uint32 startTime = GetTickCount();
|
||||
while (true)
|
||||
|
@ -509,7 +509,7 @@ namespace ntag
|
||||
noftHeader->writeCount = _swapEndianU16(_swapEndianU16(noftHeader->writeCount) + 1);
|
||||
}
|
||||
|
||||
memcpy(decryptedBuffer + 0x20, noftHeader, sizeof(noftHeader));
|
||||
memcpy(decryptedBuffer + 0x20, noftHeader, sizeof(NTAGNoftHeader));
|
||||
memcpy(decryptedBuffer + _swapEndianU16(rwHeader->offset), data, dataSize);
|
||||
|
||||
// Encrypt
|
||||
|
@ -522,10 +522,10 @@ namespace snd_core
|
||||
// called periodically to check for AX updates
|
||||
void AXOut_update()
|
||||
{
|
||||
constexpr auto kTimeout = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(((IAudioAPI::kBlockCount * 3) / 4) * (AX_FRAMES_PER_GROUP * 3)));
|
||||
constexpr auto kWaitDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(3));
|
||||
constexpr auto kWaitDurationFast = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::microseconds(2900));
|
||||
constexpr auto kWaitDurationMinimum = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::microseconds(1700));
|
||||
constexpr static auto kTimeout = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(((IAudioAPI::kBlockCount * 3) / 4) * (AX_FRAMES_PER_GROUP * 3)));
|
||||
constexpr static auto kWaitDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(3));
|
||||
constexpr static auto kWaitDurationFast = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::microseconds(2900));
|
||||
constexpr static auto kWaitDurationMinimum = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::microseconds(1700));
|
||||
|
||||
// if we haven't buffered any blocks, we will wait less time than usual
|
||||
bool additional_blocks_required = false;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
using MPTR = uint32; // generic address in PowerPC memory space
|
||||
|
||||
#define MPTR_NULL (0)
|
||||
#define MPTR_NULL (0)
|
||||
|
||||
using VAddr = uint32; // virtual address
|
||||
using PAddr = uint32; // physical address
|
||||
@ -14,137 +14,175 @@ extern uint8* PPCInterpreterGetStackPointer();
|
||||
extern uint8* PPCInterpreter_PushAndReturnStackPointer(sint32 offset);
|
||||
extern void PPCInterpreterModifyStackPointer(sint32 offset);
|
||||
|
||||
class MEMPTRBase {};
|
||||
class MEMPTRBase
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
class MEMPTR : MEMPTRBase
|
||||
{
|
||||
public:
|
||||
constexpr MEMPTR()
|
||||
: m_value(0) { }
|
||||
public:
|
||||
constexpr MEMPTR() noexcept
|
||||
: m_value(0) {}
|
||||
|
||||
explicit constexpr MEMPTR(uint32 offset)
|
||||
: m_value(offset) { }
|
||||
explicit constexpr MEMPTR(uint32 offset) noexcept
|
||||
: m_value(offset) {}
|
||||
|
||||
explicit constexpr MEMPTR(const uint32be& offset)
|
||||
: m_value(offset) { }
|
||||
explicit constexpr MEMPTR(const uint32be& offset) noexcept
|
||||
: m_value(offset) {}
|
||||
|
||||
constexpr MEMPTR(std::nullptr_t)
|
||||
: m_value(0) { }
|
||||
constexpr MEMPTR(std::nullptr_t) noexcept
|
||||
: m_value(0) {}
|
||||
|
||||
MEMPTR(T* ptr)
|
||||
MEMPTR(T* ptr) noexcept
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
m_value = 0;
|
||||
else
|
||||
{
|
||||
cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);
|
||||
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);
|
||||
}
|
||||
{
|
||||
cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);
|
||||
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr MEMPTR(const MEMPTR& memptr)
|
||||
: m_value(memptr.m_value) { }
|
||||
constexpr MEMPTR(const MEMPTR&) noexcept = default;
|
||||
|
||||
constexpr MEMPTR& operator=(const MEMPTR& memptr)
|
||||
{
|
||||
m_value = memptr.m_value;
|
||||
return *this;
|
||||
}
|
||||
constexpr MEMPTR& operator=(const MEMPTR&) noexcept = default;
|
||||
|
||||
constexpr MEMPTR& operator=(const uint32& offset)
|
||||
constexpr MEMPTR& operator=(const uint32& offset) noexcept
|
||||
{
|
||||
m_value = offset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr MEMPTR& operator=(const std::nullptr_t rhs)
|
||||
constexpr MEMPTR& operator=(std::nullptr_t) noexcept
|
||||
{
|
||||
m_value = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MEMPTR& operator=(T* ptr)
|
||||
MEMPTR& operator=(T* ptr) noexcept
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
if (ptr == nullptr)
|
||||
m_value = 0;
|
||||
else
|
||||
{
|
||||
cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);
|
||||
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);
|
||||
}
|
||||
{
|
||||
cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);
|
||||
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool atomic_compare_exchange(T* comparePtr, T* newPtr)
|
||||
bool atomic_compare_exchange(T* comparePtr, T* newPtr) noexcept
|
||||
{
|
||||
MEMPTR<T> mp_compare = comparePtr;
|
||||
MEMPTR<T> mp_new = newPtr;
|
||||
std::atomic<uint32be>* thisValueAtomic = (std::atomic<uint32be>*)&m_value;
|
||||
auto* thisValueAtomic = reinterpret_cast<std::atomic<uint32be>*>(&m_value);
|
||||
return thisValueAtomic->compare_exchange_strong(mp_compare.m_value, mp_new.m_value);
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const noexcept { return m_value != 0; }
|
||||
|
||||
constexpr operator T*() const noexcept { return GetPtr(); } // allow implicit cast to wrapped pointer type
|
||||
explicit constexpr operator bool() const noexcept
|
||||
{
|
||||
return m_value != 0;
|
||||
}
|
||||
|
||||
// allow implicit cast to wrapped pointer type
|
||||
constexpr operator T*() const noexcept
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
template <typename X>
|
||||
explicit operator MEMPTR<X>() const { return MEMPTR<X>(this->m_value); }
|
||||
template<typename X>
|
||||
explicit operator MEMPTR<X>() const noexcept
|
||||
{
|
||||
return MEMPTR<X>(this->m_value);
|
||||
}
|
||||
|
||||
MEMPTR operator+(const MEMPTR& ptr) { return MEMPTR(this->GetMPTR() + ptr.GetMPTR()); }
|
||||
MEMPTR operator-(const MEMPTR& ptr) { return MEMPTR(this->GetMPTR() - ptr.GetMPTR()); }
|
||||
MEMPTR operator+(const MEMPTR& ptr) noexcept
|
||||
{
|
||||
return MEMPTR(this->GetMPTR() + ptr.GetMPTR());
|
||||
}
|
||||
MEMPTR operator-(const MEMPTR& ptr) noexcept
|
||||
{
|
||||
return MEMPTR(this->GetMPTR() - ptr.GetMPTR());
|
||||
}
|
||||
|
||||
MEMPTR operator+(sint32 v)
|
||||
MEMPTR operator+(sint32 v) noexcept
|
||||
{
|
||||
// pointer arithmetic
|
||||
return MEMPTR(this->GetMPTR() + v * 4);
|
||||
}
|
||||
|
||||
MEMPTR operator-(sint32 v)
|
||||
MEMPTR operator-(sint32 v) noexcept
|
||||
{
|
||||
// pointer arithmetic
|
||||
return MEMPTR(this->GetMPTR() - v * 4);
|
||||
}
|
||||
|
||||
MEMPTR& operator+=(sint32 v)
|
||||
MEMPTR& operator+=(sint32 v) noexcept
|
||||
{
|
||||
m_value += v * sizeof(T);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Q = T>
|
||||
typename std::enable_if<!std::is_same<Q, void>::value, Q>::type&
|
||||
operator*() const { return *GetPtr(); }
|
||||
template<typename Q = T>
|
||||
std::enable_if_t<!std::is_same_v<Q, void>, Q>& operator*() const noexcept
|
||||
{
|
||||
return *GetPtr();
|
||||
}
|
||||
|
||||
T* operator->() const { return GetPtr(); }
|
||||
constexpr T* operator->() const noexcept
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
template <class Q = T>
|
||||
typename std::enable_if<!std::is_same<Q, void>::value, Q>::type&
|
||||
operator[](int index) { return GetPtr()[index]; }
|
||||
template<typename Q = T>
|
||||
std::enable_if_t<!std::is_same_v<Q, void>, Q>& operator[](int index) noexcept
|
||||
{
|
||||
return GetPtr()[index];
|
||||
}
|
||||
|
||||
T* GetPtr() const { return (T*)(m_value == 0 ? nullptr : memory_base + (uint32)m_value); }
|
||||
T* GetPtr() const noexcept
|
||||
{
|
||||
return (T*)(m_value == 0 ? nullptr : memory_base + (uint32)m_value);
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
C* GetPtr() const { return (C*)(GetPtr()); }
|
||||
template<typename C>
|
||||
C* GetPtr() const noexcept
|
||||
{
|
||||
return static_cast<C*>(GetPtr());
|
||||
}
|
||||
|
||||
constexpr uint32 GetMPTR() const { return m_value.value(); }
|
||||
constexpr const uint32be& GetBEValue() const { return m_value; }
|
||||
[[nodiscard]] constexpr uint32 GetMPTR() const noexcept
|
||||
{
|
||||
return m_value.value();
|
||||
}
|
||||
[[nodiscard]] constexpr const uint32be& GetBEValue() const noexcept
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
constexpr bool IsNull() const { return m_value == 0; }
|
||||
[[nodiscard]] constexpr bool IsNull() const noexcept
|
||||
{
|
||||
return m_value == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
uint32be m_value;
|
||||
};
|
||||
|
||||
static_assert(sizeof(MEMPTR<void*>) == sizeof(uint32be));
|
||||
static_assert(std::is_trivially_copyable_v<MEMPTR<void*>>);
|
||||
|
||||
#include "StackAllocator.h"
|
||||
#include "SysAllocator.h"
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct fmt::formatter<MEMPTR<T>> : formatter<string_view>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
auto format(const MEMPTR<T>& v, FormatContext& ctx) const -> format_context::iterator { return fmt::format_to(ctx.out(), "{:#x}", v.GetMPTR()); }
|
||||
template<typename FormatContext>
|
||||
auto format(const MEMPTR<T>& v, FormatContext& ctx) const -> format_context::iterator
|
||||
{
|
||||
return fmt::format_to(ctx.out(), "{:#x}", v.GetMPTR());
|
||||
}
|
||||
};
|
||||
|
@ -436,16 +436,10 @@ void vectorRemoveByIndex(std::vector<T>& vec, const size_t index)
|
||||
vec.erase(vec.begin() + index);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
int match_any_of(T1 value, T2 compareTo)
|
||||
template<typename T1, typename... Types>
|
||||
bool match_any_of(T1&& value, Types&&... others)
|
||||
{
|
||||
return value == compareTo;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename... Types>
|
||||
bool match_any_of(T1 value, T2 compareTo, Types&&... others)
|
||||
{
|
||||
return value == compareTo || match_any_of(value, others...);
|
||||
return ((value == others) || ...);
|
||||
}
|
||||
|
||||
// we cache the frequency in a static variable
|
||||
@ -551,13 +545,6 @@ bool future_is_ready(std::future<T>& f)
|
||||
#endif
|
||||
}
|
||||
|
||||
// replace with std::scope_exit once available
|
||||
struct scope_exit
|
||||
{
|
||||
std::function<void()> f_;
|
||||
explicit scope_exit(std::function<void()> f) noexcept : f_(std::move(f)) {}
|
||||
~scope_exit() { if (f_) f_(); }
|
||||
};
|
||||
|
||||
// helper function to cast raw pointers to std::atomic
|
||||
// this is technically not legal but works on most platforms as long as alignment restrictions are met and the implementation of atomic doesnt come with additional members
|
||||
@ -565,6 +552,8 @@ struct scope_exit
|
||||
template<typename T>
|
||||
std::atomic<T>* _rawPtrToAtomic(T* ptr)
|
||||
{
|
||||
static_assert(sizeof(T) == sizeof(std::atomic<T>));
|
||||
cemu_assert_debug((reinterpret_cast<std::uintptr_t>(ptr) % alignof(std::atomic<T>)) == 0);
|
||||
return reinterpret_cast<std::atomic<T>*>(ptr);
|
||||
}
|
||||
|
||||
@ -628,13 +617,34 @@ struct fmt::formatter<betype<T>> : fmt::formatter<T>
|
||||
}
|
||||
};
|
||||
|
||||
// useful C++23 stuff that isn't yet widely supported
|
||||
|
||||
// std::to_underlying
|
||||
// useful future C++ stuff
|
||||
namespace stdx
|
||||
{
|
||||
// std::to_underlying
|
||||
template <typename EnumT, typename = std::enable_if_t < std::is_enum<EnumT>{} >>
|
||||
constexpr std::underlying_type_t<EnumT> to_underlying(EnumT e) noexcept {
|
||||
return static_cast<std::underlying_type_t<EnumT>>(e);
|
||||
};
|
||||
|
||||
// std::scope_exit
|
||||
template <typename Fn>
|
||||
class scope_exit
|
||||
{
|
||||
Fn m_func;
|
||||
bool m_released = false;
|
||||
public:
|
||||
explicit scope_exit(Fn&& f) noexcept
|
||||
: m_func(std::forward<Fn>(f))
|
||||
{}
|
||||
~scope_exit()
|
||||
{
|
||||
if (!m_released) m_func();
|
||||
}
|
||||
scope_exit(scope_exit&& other) noexcept
|
||||
: m_func(std::move(other.m_func)), m_released(std::exchange(other.m_released, true))
|
||||
{}
|
||||
scope_exit(const scope_exit&) = delete;
|
||||
scope_exit& operator=(scope_exit) = delete;
|
||||
void release() { m_released = true;}
|
||||
};
|
||||
}
|
@ -1,6 +1,12 @@
|
||||
project(CemuAsm C)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
|
||||
if (CMAKE_OSX_ARCHITECTURES)
|
||||
set(CEMU_ASM_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES})
|
||||
else()
|
||||
set(CEMU_ASM_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
|
||||
if (CEMU_ASM_ARCHITECTURE MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
|
||||
|
||||
if (WIN32)
|
||||
|
||||
@ -42,9 +48,9 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
|
||||
|
||||
endif()
|
||||
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)")
|
||||
elseif(CEMU_ASM_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)")
|
||||
enable_language(C ASM)
|
||||
add_library(CemuAsm aarch64util.s)
|
||||
else()
|
||||
message(STATUS "CemuAsm - Unsupported arch: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
message(STATUS "CemuAsm - Unsupported arch: ${CEMU_ASM_ARCHITECTURE}")
|
||||
endif()
|
||||
|
@ -15,6 +15,9 @@
|
||||
#if BOOST_OS_LINUX && HAS_WAYLAND
|
||||
#include "helpers/wxWayland.h"
|
||||
#endif
|
||||
#if __WXGTK__
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
#include <wx/image.h>
|
||||
#include <wx/filename.h>
|
||||
|
@ -932,6 +932,7 @@ void GeneralSettings2::StoreConfig()
|
||||
config.fullscreen_menubar = m_fullscreen_menubar->IsChecked();
|
||||
config.check_update = m_auto_update->IsChecked();
|
||||
config.save_screenshot = m_save_screenshot->IsChecked();
|
||||
config.receive_untested_updates = m_receive_untested_releases->IsChecked();
|
||||
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||
config.feral_gamemode = m_feral_gamemode->IsChecked();
|
||||
#endif
|
||||
|
@ -50,7 +50,6 @@ add_library(CemuUtil
|
||||
MemMapper/MemMapper.h
|
||||
SystemInfo/SystemInfo.cpp
|
||||
SystemInfo/SystemInfo.h
|
||||
ThreadPool/ThreadPool.cpp
|
||||
ThreadPool/ThreadPool.h
|
||||
tinyxml2/tinyxml2.cpp
|
||||
tinyxml2/tinyxml2.h
|
||||
|
@ -194,7 +194,7 @@ namespace robin_hood {
|
||||
|
||||
// workaround missing "is_trivially_copyable" in g++ < 5.0
|
||||
// See https://stackoverflow.com/a/31798726/48181
|
||||
#if defined(__GNUC__) && __GNUC__ < 5
|
||||
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
|
||||
# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
|
||||
#else
|
||||
# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
|
||||
|
@ -1,29 +1,6 @@
|
||||
#include "crc32.h"
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define __LITTLE_ENDIAN 1234
|
||||
#define __BIG_ENDIAN 4321
|
||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
|
||||
#include <xmmintrin.h>
|
||||
#ifdef __MINGW32__
|
||||
#define PREFETCH(location) __builtin_prefetch(location)
|
||||
#else
|
||||
#define PREFETCH(location) _mm_prefetch(location, _MM_HINT_T0)
|
||||
#endif
|
||||
#else
|
||||
// defines __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PREFETCH(location) __builtin_prefetch(location)
|
||||
#else
|
||||
// no prefetching
|
||||
#define PREFETCH(location) ;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
unsigned int Crc32Lookup[8][256] =
|
||||
constexpr uint32 Crc32Lookup[8][256] =
|
||||
{
|
||||
{
|
||||
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,
|
||||
@ -301,20 +278,7 @@ unsigned int Crc32Lookup[8][256] =
|
||||
}
|
||||
};
|
||||
|
||||
/// swap endianess
|
||||
static inline uint32_t swap(uint32_t x)
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_bswap32(x);
|
||||
#else
|
||||
return (x >> 24) |
|
||||
((x >> 8) & 0x0000FF00) |
|
||||
((x << 8) & 0x00FF0000) |
|
||||
(x << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data, int length)
|
||||
uint32 crc32_calc_slice_by_8(uint32 previousCrc32, const void* data, size_t length)
|
||||
{
|
||||
uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF
|
||||
const uint32_t* current = (const uint32_t*)data;
|
||||
@ -323,7 +287,7 @@ unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data,
|
||||
while (length >= 8)
|
||||
{
|
||||
if constexpr (std::endian::native == std::endian::big){
|
||||
uint32_t one = *current++ ^ swap(crc);
|
||||
uint32_t one = *current++ ^ _swapEndianU32(crc);
|
||||
uint32_t two = *current++;
|
||||
crc = Crc32Lookup[0][two & 0xFF] ^
|
||||
Crc32Lookup[1][(two >> 8) & 0xFF] ^
|
||||
@ -348,13 +312,14 @@ unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data,
|
||||
Crc32Lookup[7][one & 0xFF];
|
||||
}
|
||||
else {
|
||||
cemu_assert(false);
|
||||
static_assert(std::endian::native == std::endian::big || std::endian::native == std::endian::little,
|
||||
"Platform byte-order is unsupported");
|
||||
}
|
||||
|
||||
length -= 8;
|
||||
}
|
||||
|
||||
const uint8_t* currentChar = (const uint8_t*)current;
|
||||
const uint8* currentChar = (const uint8*)current;
|
||||
// remaining 1 to 7 bytes (standard algorithm)
|
||||
while (length-- != 0)
|
||||
crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++];
|
||||
@ -362,20 +327,20 @@ unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data,
|
||||
return ~crc; // same as crc ^ 0xFFFFFFFF
|
||||
}
|
||||
|
||||
unsigned int crc32_calc(unsigned int c, const void* data, int length)
|
||||
uint32 crc32_calc(uint32 c, const void* data, size_t length)
|
||||
{
|
||||
if (length >= 16)
|
||||
{
|
||||
return crc32_calc_slice_by_8(c, data, length);
|
||||
}
|
||||
unsigned char* p = (unsigned char*)data;
|
||||
const uint8* p = (const uint8*)data;
|
||||
if (length == 0)
|
||||
return c;
|
||||
c ^= 0xFFFFFFFF;
|
||||
while (length)
|
||||
{
|
||||
unsigned char temp = *p;
|
||||
temp ^= (unsigned char)c;
|
||||
uint8 temp = *p;
|
||||
temp ^= (uint8)c;
|
||||
c = (c >> 8) ^ Crc32Lookup[0][temp];
|
||||
// next
|
||||
length--;
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
unsigned int crc32_calc(unsigned int c, const void* data, int length);
|
||||
uint32 crc32_calc(uint32 c, const void* data, size_t length);
|
||||
|
||||
inline unsigned int crc32_calc(const void* data, int length)
|
||||
inline uint32 crc32_calc(const void* data, size_t length)
|
||||
{
|
||||
return crc32_calc(0, data, length);
|
||||
}
|
Loading…
Reference in New Issue
Block a user