mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Merge branch 'main' into android
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
+2
-1
@@ -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.
Vendored
+9
-3
@@ -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)
|
||||
|
||||
Vendored
-1
@@ -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;
|
||||
|
||||
+99
-61
@@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user