diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index b24b1f2e..80309140 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -338,7 +338,7 @@ void LatteShaderCache_load() if (g_renderer->GetType() == RendererAPI::Vulkan) LatteShaderCache_loadVulkanPipelineCache(cacheTitleId); - +#if !__ANDROID__ g_renderer->BeginFrame(true); if (g_renderer->ImguiBegin(true)) { @@ -351,7 +351,7 @@ void LatteShaderCache_load() LatteShaderCache_drawBackgroundImage(g_shaderCacheLoaderState.textureDRCId, 854, 480); g_renderer->ImguiEnd(); } - +#endif // __ANDROID__ g_renderer->SwapBuffers(true, true); if (g_shaderCacheLoaderState.textureTVId) diff --git a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp index ae528944..70f5052d 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp +++ b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp @@ -302,16 +302,16 @@ std::string RendererOutputShader::GetVulkanVertexSource(bool render_upside_down) { // vertex shader std::ostringstream vertex_source; - vertex_source << - R"(#version 450 + vertex_source << R"(#version 450 layout(location = 0) out vec2 passUV; - out gl_PerVertex { vec4 gl_Position; -}; - -void main(){ +};)"; +#if __ANDROID__ + vertex_source << "layout (push_constant) uniform PushConstants { mat2 preRotate; } pushConstants;\n"; +#endif // __ANDROID__ + vertex_source << R"(void main(){ vec2 vPos; vec2 vUV; int vID = gl_VertexIndex; @@ -340,12 +340,13 @@ void main(){ )"; } - vertex_source << - R"( passUV = vUV; - gl_Position = vec4(vPos, 0.0, 1.0); -} -)"; - return vertex_source.str(); + vertex_source << "passUV = vUV;\n"; +#if __ANDROID__ + vertex_source << "gl_Position = vec4(pushConstants.preRotate * vPos, 0.0, 1.0);}"; +#else + vertex_source << "gl_Position = vec4(vPos, 0.0, 1.0);}"; +#endif // __ANDROID__ + return vertex_source.str(); } void RendererOutputShader::InitializeStatic() { diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp index 14b7a17c..1bed55ea 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp @@ -12,6 +12,9 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe const auto details = QuerySwapchainSupport(surface, physicalDevice); m_surfaceFormat = ChooseSurfaceFormat(details.formats); m_actualExtent = ChooseSwapExtent(details.capabilities); +#if __ANDROID__ + m_preTransform = details.capabilities.currentTransform; +#endif // __ANDROID__ // use at least two swapchain images. fewer than that causes problems on some drivers uint32_t image_count = std::max(2u, details.capabilities.minImageCount); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h index 26dbc7d1..e992302e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h @@ -76,7 +76,9 @@ struct SwapchainInfoVk bool m_usesSRGB = false; VSync m_vsyncState = VSync::Immediate; bool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state - +#if __ANDROID__ + VkSurfaceTransformFlagBitsKHR m_preTransform{}; +#endif // __ANDROID__ VkPhysicalDevice m_physicalDevice{}; VkDevice m_logicalDevice{}; VkSurfaceKHR surface{}; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index e8bb7a90..885a6f88 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -2923,7 +2923,25 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu auto descriptSet = backbufferBlit_createDescriptorSet(m_swapchainDescriptorSetLayout, texViewVk, useLinearTexFilter); vkCmdBeginRenderPass(m_state.currentCommandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - +#if __ANDROID__ + float radians = 0.0f; + switch (chainInfo.m_preTransform) + { + case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: + radians = glm::radians(90.0f); + break; + case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: + radians = glm::radians(180.0f); + break; + case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: + radians = glm::radians(270.0f); + break; + default: + break; + } + const glm::mat2 preRotate = glm::rotate(glm::mat4(1.0), radians, glm::vec3(0.0F, 0.0F, 1.0F)); + vkCmdPushConstants(m_state.currentCommandBuffer, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(preRotate), &preRotate); +#endif // __ANDROID__ vkCmdBindPipeline(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); m_state.currentPipeline = pipeline; diff --git a/src/android/app/src/main/cpp/native-lib.cpp b/src/android/app/src/main/cpp/native-lib.cpp index 1a79da85..4133aff4 100644 --- a/src/android/app/src/main/cpp/native-lib.cpp +++ b/src/android/app/src/main/cpp/native-lib.cpp @@ -113,6 +113,7 @@ public: reinterpret_cast(iconData.m_image)); env->CallVoidMethod(*m_gameTitleLoadedCallbackObj, m_onGameIconLoadedMID, jTitleId, jIconData, iconData.m_width, iconData.m_height); + env->DeleteLocalRef(jIconData); } }; @@ -179,5 +180,10 @@ Java_info_cemu_Cemu_NativeLibrary_initializeRendererSurface(JNIEnv *env, jclass VulkanRenderer::GetInstance()->InitializeSurface( {width, height}, is_main_canvas); - -} \ No newline at end of file +} +extern "C" +JNIEXPORT void JNICALL +Java_info_cemu_Cemu_NativeLibrary_setDPI(JNIEnv *env, jclass clazz, jfloat dpi) { + auto& windowInfo = gui_getWindowInfo(); + windowInfo.dpi_scale = windowInfo.pad_dpi_scale = dpi; +} diff --git a/src/android/app/src/main/java/info/cemu/Cemu/CemuApplication.java b/src/android/app/src/main/java/info/cemu/Cemu/CemuApplication.java index 98c37110..6b9f132e 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/CemuApplication.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/CemuApplication.java @@ -1,11 +1,14 @@ package info.cemu.Cemu; import android.app.Application; +import android.util.DisplayMetrics; public class CemuApplication extends Application { @Override public void onCreate() { super.onCreate(); + DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); + NativeLibrary.setDPI(displayMetrics.density); NativeLibrary.initializeActiveSettings(getExternalFilesDir(null).getAbsoluteFile().toString(), getCacheDir().toString()); NativeLibrary.initializeEmulation(); } diff --git a/src/android/app/src/main/java/info/cemu/Cemu/NativeLibrary.java b/src/android/app/src/main/java/info/cemu/Cemu/NativeLibrary.java index 44dd98a8..4251faf2 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/NativeLibrary.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/NativeLibrary.java @@ -7,6 +7,8 @@ public class NativeLibrary { System.loadLibrary("CemuAndroid"); } + public static native void setDPI(float dpi); + public static native void setSurface(Surface surface, boolean isMainCanvas); public static native void setSurfaceSize(int width, int height, boolean isMainCanvas); diff --git a/src/config/ActiveSettings.cpp b/src/config/ActiveSettings.cpp index 9ad459ca..3352d58b 100644 --- a/src/config/ActiveSettings.cpp +++ b/src/config/ActiveSettings.cpp @@ -65,7 +65,7 @@ bool ActiveSettings::FullscreenEnabled() CPUMode ActiveSettings::GetCPUMode() { -#if !ARCH_X86_64 +#ifndef ARCH_X86_64 return CPUMode::SinglecoreInterpreter; #else auto mode = g_current_game_profile->GetCPUMode().value_or(CPUMode::Auto); diff --git a/src/gui/AndroidGui/AndroidGuiWrapper.cpp b/src/gui/AndroidGui/AndroidGuiWrapper.cpp index 79596205..8664525d 100644 --- a/src/gui/AndroidGui/AndroidGuiWrapper.cpp +++ b/src/gui/AndroidGui/AndroidGuiWrapper.cpp @@ -72,11 +72,11 @@ void gui_getPadWindowPhysSize(int& w, int& h) } double gui_getWindowDPIScale() { - return 1.0; + return gui_getWindowInfo().dpi_scale; } double gui_getPadDPIScale() { - return 1.0; + return gui_getWindowInfo().pad_dpi_scale; } bool gui_isPadWindowOpen() {