From be23c47cac762bb59e5355fdb971cd814f1ba5a7 Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Sat, 21 Sep 2024 21:48:37 +0300 Subject: [PATCH] Pass c++ exception to java for renderer functions --- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 8 ++-- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 6 +++ src/android/app/src/main/AndroidManifest.xml | 5 +++ src/android/app/src/main/cpp/JNIUtils.cpp | 16 ++++++++ src/android/app/src/main/cpp/JNIUtils.h | 2 + src/android/app/src/main/cpp/native-lib.cpp | 8 +++- .../Cemu/emulation/EmulationFragment.java | 41 +++++++++++-------- .../Cemu/nativeinterface/NativeException.java | 8 ++++ .../app/src/main/res/values/strings.xml | 2 + 9 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeException.java diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 2b485d9..c440a58 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -260,6 +260,8 @@ void VulkanRenderer::GetDeviceFeatures() physicalDeviceFeatures2.pNext = prevStruct; vkGetPhysicalDeviceFeatures2(m_physicalDevice, &physicalDeviceFeatures2); + m_featureControl.deviceFeatures.geometry_shader = physicalDeviceFeatures2.features.geometryShader; + m_featureControl.deviceFeatures.logic_op = physicalDeviceFeatures2.features.logicOp; /* Get Vulkan device properties and limits */ VkPhysicalDeviceFloatControlsPropertiesKHR pfcp{}; @@ -451,10 +453,8 @@ VulkanRenderer::VulkanRenderer() deviceFeatures.independentBlend = VK_TRUE; deviceFeatures.samplerAnisotropy = VK_TRUE; deviceFeatures.imageCubeArray = VK_TRUE; -#if !BOOST_OS_MACOS - deviceFeatures.geometryShader = VK_TRUE; -// deviceFeatures.logicOp = VK_TRUE; -#endif + deviceFeatures.geometryShader = m_featureControl.deviceFeatures.geometry_shader; + deviceFeatures.logicOp = m_featureControl.deviceFeatures.logic_op; deviceFeatures.occlusionQueryPrecise = VK_TRUE; deviceFeatures.depthClamp = VK_TRUE; deviceFeatures.depthBiasClamp = VK_TRUE; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index 162dc85..e318c91 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -457,6 +457,12 @@ private: bool shader_float_controls = false; // VK_KHR_shader_float_controls }deviceExtensions; + struct + { + bool geometry_shader; + bool logic_op; + } deviceFeatures; + struct { bool shaderRoundingModeRTEFloat32{ false }; diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index d83049f..814563c 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -6,6 +6,11 @@ + + & fn) +{ + try + { + fn(); + } catch (const std::exception& exception) + { + jclass exceptionClass = env->FindClass("info/cemu/Cemu/nativeinterface/NativeException"); + env->ThrowNew(exceptionClass, exception.what()); + } catch (...) + { + jclass exceptionClass = env->FindClass("info/cemu/Cemu/nativeinterface/NativeException"); + env->ThrowNew(exceptionClass, "Unknown native exception"); + } +} + jobject JNIUtils::createJavaStringArrayList(JNIEnv* env, const std::vector& strings) { jclass arrayListClass = env->FindClass("java/util/ArrayList"); diff --git a/src/android/app/src/main/cpp/JNIUtils.h b/src/android/app/src/main/cpp/JNIUtils.h index 05cb533..4c96697 100644 --- a/src/android/app/src/main/cpp/JNIUtils.h +++ b/src/android/app/src/main/cpp/JNIUtils.h @@ -13,6 +13,8 @@ namespace JNIUtils jobject createJavaStringArrayList(JNIEnv* env, const std::vector& stringList); + void handleNativeException(JNIEnv* env, const std::function& fn); + class ScopedJNIENV { public: diff --git a/src/android/app/src/main/cpp/native-lib.cpp b/src/android/app/src/main/cpp/native-lib.cpp index 8b69978..cf5afd6 100644 --- a/src/android/app/src/main/cpp/native-lib.cpp +++ b/src/android/app/src/main/cpp/native-lib.cpp @@ -16,7 +16,9 @@ extern "C" [[maybe_unused]] JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, [[mayb extern "C" [[maybe_unused]] JNIEXPORT void JNICALL Java_info_cemu_Cemu_NativeLibrary_setSurface(JNIEnv* env, [[maybe_unused]] jclass clazz, jobject surface, jboolean is_main_canvas) { - s_emulationState.setSurface(env, surface, is_main_canvas); + JNIUtils::handleNativeException(env, [&]() { + s_emulationState.setSurface(env, surface, is_main_canvas); + }); } extern "C" [[maybe_unused]] JNIEXPORT void JNICALL @@ -86,7 +88,9 @@ Java_info_cemu_Cemu_NativeLibrary_initializeEmulation([[maybe_unused]] JNIEnv* e extern "C" [[maybe_unused]] JNIEXPORT void JNICALL Java_info_cemu_Cemu_NativeLibrary_initializerRenderer(JNIEnv* env, [[maybe_unused]] jclass clazz, jobject testSurface) { - s_emulationState.initializeRenderer(env, testSurface); + JNIUtils::handleNativeException(env, [&]() { + s_emulationState.initializeRenderer(env, testSurface); + }); } extern "C" [[maybe_unused]] JNIEXPORT void JNICALL diff --git a/src/android/app/src/main/java/info/cemu/Cemu/emulation/EmulationFragment.java b/src/android/app/src/main/java/info/cemu/Cemu/emulation/EmulationFragment.java index 29657d4..4b79e57 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/emulation/EmulationFragment.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/emulation/EmulationFragment.java @@ -1,7 +1,5 @@ package info.cemu.Cemu.emulation; -import static androidx.core.app.ActivityCompat.finishAffinity; - import android.annotation.SuppressLint; import android.content.res.Configuration; import android.graphics.SurfaceTexture; @@ -24,14 +22,13 @@ import androidx.appcompat.widget.PopupMenu; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - import info.cemu.Cemu.NativeLibrary; import info.cemu.Cemu.R; import info.cemu.Cemu.databinding.FragmentEmulationBinding; import info.cemu.Cemu.input.SensorManager; import info.cemu.Cemu.inputoverlay.InputOverlaySettingsProvider; import info.cemu.Cemu.inputoverlay.InputOverlaySurfaceView; +import info.cemu.Cemu.nativeinterface.NativeException; @SuppressLint("ClickableViewAccessibility") public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemClickListener { @@ -71,7 +68,7 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC } } - private static class SurfaceHolderCallback implements SurfaceHolder.Callback { + private class SurfaceHolderCallback implements SurfaceHolder.Callback { final boolean isMainCanvas; boolean surfaceSet; @@ -85,12 +82,16 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC @Override public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int format, int width, int height) { - NativeLibrary.setSurfaceSize(width, height, isMainCanvas); - if (surfaceSet) { - return; + try { + NativeLibrary.setSurfaceSize(width, height, isMainCanvas); + if (surfaceSet) { + return; + } + NativeLibrary.setSurface(surfaceHolder.getSurface(), isMainCanvas); + surfaceSet = true; + } catch (NativeException exception) { + onEmulationError(getString(R.string.failed_create_surface_error, exception.getMessage())); } - surfaceSet = true; - NativeLibrary.setSurface(surfaceHolder.getSurface(), isMainCanvas); } @Override @@ -112,6 +113,7 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC private InputOverlaySurfaceView inputOverlaySurfaceView; private SensorManager sensorManager; private EmulationViewModel viewModel; + private boolean hasEmulationError; public EmulationFragment(String launchPath) { this.launchPath = launchPath; @@ -229,14 +231,10 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC return false; } - @Override - public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - viewModel = new ViewModelProvider(requireActivity()).get(EmulationViewModel.class); - } - @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + viewModel = new ViewModelProvider(requireActivity()).get(EmulationViewModel.class); + binding = FragmentEmulationBinding.inflate(inflater, container, false); inputOverlaySurfaceView = binding.inputOverlay; @@ -271,8 +269,12 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC inputOverlaySurfaceView.setVisibility(View.GONE); } SurfaceView mainCanvas = binding.mainCanvas; - - NativeLibrary.initializerRenderer(testSurface); + try { + NativeLibrary.initializerRenderer(testSurface); + } catch (NativeException exception) { + onEmulationError(getString(R.string.failed_initialize_renderer_error, exception.getMessage())); + return binding.getRoot(); + } var mainCanvasHolder = mainCanvas.getHolder(); mainCanvasHolder.addCallback(new SurfaceHolderCallback(true)); @@ -283,6 +285,8 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC @Override public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + if (hasEmulationError) + return; if (!isGameRunning) { isGameRunning = true; startGame(); @@ -312,6 +316,7 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC } private void onEmulationError(String errorMessage) { + hasEmulationError = true; if (viewModel == null) return; viewModel.setEmulationError(new EmulationError(errorMessage)); diff --git a/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeException.java b/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeException.java new file mode 100644 index 0000000..483c845 --- /dev/null +++ b/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeException.java @@ -0,0 +1,8 @@ +package info.cemu.Cemu.nativeinterface; + +@SuppressWarnings("unused") +public final class NativeException extends RuntimeException { + public NativeException(String message) { + super(message); + } +} diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 20d4b87..d0fa069 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -174,4 +174,6 @@ Could not decrypt title. Make sure that keys.txt contains the correct disc key for this title. Could not decrypt title because title.tik is missing. Unable to launch game because the base files were not found. + Failed creating surface: %1$s + Failed to initialize renderer: %1$s \ No newline at end of file