From fc0371273fe2ca5ec6bfdae31ad9e8a002baba68 Mon Sep 17 00:00:00 2001 From: iota97 Date: Sun, 13 Mar 2022 08:07:14 +0100 Subject: [PATCH 001/715] Fix grid align --- UI/TouchControlLayoutScreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index b52b09f7a8..f681e3399c 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -401,8 +401,8 @@ void ControlLayoutView::Touch(const TouchInput &touch) { newPos.x = startObjectX_ + (touch.x - startDragX_); newPos.y = startObjectY_ + (touch.y - startDragY_); if (g_Config.bTouchSnapToGrid) { - newPos.x -= fmod(newPos.x - controlBounds.w, g_Config.iTouchSnapGridSize); - newPos.y -= fmod(newPos.y - controlBounds.h, g_Config.iTouchSnapGridSize); + newPos.x -= fmod(newPos.x, g_Config.iTouchSnapGridSize); + newPos.y -= fmod(newPos.y, g_Config.iTouchSnapGridSize); } newPos = ClampTo(newPos, validRange); From fea2ace548a3b6386e8a00527bbde2f67f7dd83d Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 13 Sep 2022 01:39:44 +0200 Subject: [PATCH 002/715] OpenXR - Initial work on Vulkan support --- Common/GPU/Vulkan/VulkanLoader.cpp | 6 ---- Common/VR/PPSSPPVR.cpp | 4 ++- Common/VR/VRBase.cpp | 57 ++++++++++++++++++----------- Common/VR/VRBase.h | 4 ++- Common/VR/VRFramebuffer.cpp | 26 ++++++++++++-- Common/VR/VRFramebuffer.h | 1 + Common/VR/VRRenderer.cpp | 58 +++++++----------------------- 7 files changed, 80 insertions(+), 76 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index b0c2ab370b..2ead5cb95d 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -23,7 +23,6 @@ #include "Common/GPU/Vulkan/VulkanLoader.h" #include "Common/Log.h" #include "Common/System/System.h" -#include "Common/VR/PPSSPPVR.h" #if !PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(SWITCH) #include @@ -309,11 +308,6 @@ void VulkanSetAvailable(bool available) { bool VulkanMayBeAvailable() { - //unsupported in VR at the moment - if (IsVRBuild()) { - return false; - } - if (g_vulkanAvailabilityChecked) { return g_vulkanMayBeAvailable; } diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 71b4919bf1..23712db954 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -97,12 +97,14 @@ bool IsVRBuild() { } void InitVROnAndroid(void* vm, void* activity, int version, const char* name) { + bool useVulkan = (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN; + ovrJava java; java.Vm = (JavaVM*)vm; java.ActivityObject = (jobject)activity; java.AppVersion = version; strcpy(java.AppName, name); - VR_Init(java); + VR_Init(java, useVulkan); __DisplaySetFramerate(72); } diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 9932d09553..bedc6b1e0c 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -4,21 +4,12 @@ #include #include #include +#include static engine_t vr_engine; int vr_initialized = 0; -const char* const requiredExtensionNames[] = { - XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME, -#ifdef OPENXR_HAS_PERFORMANCE_EXTENSION - XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME, - XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME, -#endif - XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME}; -const uint32_t numRequiredExtensions = - sizeof(requiredExtensionNames) / sizeof(requiredExtensionNames[0]); - -void VR_Init( ovrJava java ) { +void VR_Init( ovrJava java, bool useVulkan ) { if (vr_initialized) return; @@ -37,6 +28,18 @@ void VR_Init( ovrJava java ) { xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid); } + std::vector extensions; + if (useVulkan) { + extensions.push_back(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME); + } else { + extensions.push_back(XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME); + } + extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME); +#ifdef OPENXR_HAS_PERFORMANCE_EXTENSION + extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); + extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); +#endif + // Create the OpenXR instance. XrApplicationInfo appInfo; memset(&appInfo, 0, sizeof(appInfo)); @@ -54,8 +57,8 @@ void VR_Init( ovrJava java ) { instanceCreateInfo.applicationInfo = appInfo; instanceCreateInfo.enabledApiLayerCount = 0; instanceCreateInfo.enabledApiLayerNames = NULL; - instanceCreateInfo.enabledExtensionCount = numRequiredExtensions; - instanceCreateInfo.enabledExtensionNames = requiredExtensionNames; + instanceCreateInfo.enabledExtensionCount = extensions.size(); + instanceCreateInfo.enabledExtensionNames = extensions.data(); XrResult initResult; OXR(initResult = xrCreateInstance(&instanceCreateInfo, &vr_engine.appState.Instance)); @@ -89,15 +92,27 @@ void VR_Init( ovrJava java ) { } // Get the graphics requirements. - PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL; - OXR(xrGetInstanceProcAddr( - vr_engine.appState.Instance, - "xrGetOpenGLESGraphicsRequirementsKHR", - (PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR))); + if (useVulkan) { + PFN_xrGetVulkanGraphicsRequirementsKHR pfnGetVulkanGraphicsRequirementsKHR = NULL; + OXR(xrGetInstanceProcAddr( + vr_engine.appState.Instance, + "xrGetVulkanGraphicsRequirementsKHR", + (PFN_xrVoidFunction*)(&pfnGetVulkanGraphicsRequirementsKHR))); - XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {}; - graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR; - OXR(pfnGetOpenGLESGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); + XrGraphicsRequirementsVulkanKHR graphicsRequirements = {}; + graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR; + OXR(pfnGetVulkanGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); + } else { + PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL; + OXR(xrGetInstanceProcAddr( + vr_engine.appState.Instance, + "xrGetOpenGLESGraphicsRequirementsKHR", + (PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR))); + + XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {}; + graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR; + OXR(pfnGetOpenGLESGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); + } vr_engine.appState.MainThreadTid = gettid(); vr_engine.appState.SystemId = systemId; diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index fffd234868..4d5138e40f 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -12,10 +12,12 @@ //OpenXR #define XR_USE_PLATFORM_ANDROID 1 #define XR_USE_GRAPHICS_API_OPENGL_ES 1 +#define XR_USE_GRAPHICS_API_VULKAN 1 #include #include #include #include +#include #include #include #include @@ -146,7 +148,7 @@ typedef struct { float predictedDisplayTime; } engine_t; -void VR_Init( ovrJava java ); +void VR_Init( ovrJava java, bool useVulkan ); void VR_Destroy( engine_t* engine ); void VR_EnterVR( engine_t* engine ); void VR_LeaveVR( engine_t* engine ); diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 70f2ad02aa..007a21cee8 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -9,8 +9,6 @@ #include #include #include -#include -#include double FromXrTime(const XrTime time) { return (time * 1e-9); @@ -178,6 +176,15 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { waitInfo.timeout * (1E-9)); } frameBuffer->Acquired = res == XR_SUCCESS; + + ovrFramebuffer_SetCurrent(frameBuffer); + GL(glEnable( GL_SCISSOR_TEST )); + GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); + GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); + GL(glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height )); + GL(glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )); + GL(glScissor( 0, 0, 0, 0 )); + GL(glDisable( GL_SCISSOR_TEST )); } void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { @@ -185,6 +192,12 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL}; OXR(xrReleaseSwapchainImage(frameBuffer->ColorSwapChain.Handle, &releaseInfo)); frameBuffer->Acquired = false; + + // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully + GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); + GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); + GL(glClear(GL_COLOR_BUFFER_BIT)); + GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)); } } @@ -217,6 +230,15 @@ void ovrRenderer_Destroy(ovrRenderer* renderer) { } } +void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { + GL(glEnable(GL_SCISSOR_TEST)); + GL(glScissor(x, y, size, size)); + GL(glViewport(x, y, size, size)); + GL(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); + GL(glClear(GL_COLOR_BUFFER_BIT)); + GL(glDisable(GL_SCISSOR_TEST)); +} + /* ================================================================================ diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index dcedad580f..20b9004190 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -14,3 +14,4 @@ void ovrFramebuffer_SetNone(); void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview); void ovrRenderer_Destroy(ovrRenderer* renderer); +void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 79e6114a61..1d421c2fa3 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -6,14 +6,11 @@ #include #include -#include -#include - XrView* projections; XrPosef invViewTransform[2]; XrFrameState frameState = {}; -GLboolean initialized = GL_FALSE; -GLboolean stageSupported = GL_FALSE; +bool initialized = false; +bool stageSupported = false; int vrConfig[VR_CONFIG_MAX] = {}; XrVector3f hmdorientation; @@ -194,7 +191,7 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { for (uint32_t i = 0; i < numOutputSpaces; i++) { if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) { - stageSupported = GL_TRUE; + stageSupported = true; break; } } @@ -213,40 +210,27 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { engine->appState.ViewConfigurationView[0].recommendedImageRectWidth, engine->appState.ViewConfigurationView[0].recommendedImageRectHeight, multiview); - initialized = GL_TRUE; + initialized = true; } void VR_DestroyRenderer( engine_t* engine ) { ovrRenderer_Destroy(&engine->appState.Renderer); free(projections); - initialized = GL_FALSE; -} - -void VR_ClearFrameBuffer( int width, int height) { - glEnable( GL_SCISSOR_TEST ); - glViewport( 0, 0, width, height ); - - glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - - glScissor( 0, 0, width, height ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - glScissor( 0, 0, 0, 0 ); - glDisable( GL_SCISSOR_TEST ); + initialized = false; } bool VR_InitFrame( engine_t* engine ) { - GLboolean stageBoundsDirty = GL_TRUE; + bool stageBoundsDirty = true; if (ovrApp_HandleXrEvents(&engine->appState)) { VR_Recenter(engine); } - if (engine->appState.SessionActive == GL_FALSE) { + if (engine->appState.SessionActive == false) { return false; } if (stageBoundsDirty) { VR_UpdateStageBounds(&engine->appState); - stageBoundsDirty = GL_FALSE; + stageBoundsDirty = false; } // NOTE: OpenXR does not use the concept of frame indices. Instead, @@ -309,32 +293,19 @@ bool VR_InitFrame( engine_t* engine ) { void VR_BeginFrame( engine_t* engine, int fboIndex ) { vrConfig[VR_CONFIG_CURRENT_FBO] = fboIndex; - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; - ovrFramebuffer_Acquire(frameBuffer); - ovrFramebuffer_SetCurrent(frameBuffer); - VR_ClearFrameBuffer(frameBuffer->ColorSwapChain.Width, frameBuffer->ColorSwapChain.Height); + ovrFramebuffer_Acquire(&engine->appState.Renderer.FrameBuffer[fboIndex]); } void VR_EndFrame( engine_t* engine ) { - int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; - - // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully VR_BindFramebuffer(engine); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Show mouse cursor int size = vrConfig[VR_CONFIG_MOUSE_SIZE]; if ((vrConfig[VR_CONFIG_MODE] == VR_MODE_FLAT_SCREEN) && (size > 0)) { - glEnable(GL_SCISSOR_TEST); - glScissor(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size); - glViewport(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size); - glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_SCISSOR_TEST); + int x = vrConfig[VR_CONFIG_MOUSE_X]; + int y = vrConfig[VR_CONFIG_MOUSE_Y]; + ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, size); } ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; @@ -454,10 +425,7 @@ void VR_SetConfig( VRConfig config, int value) { void VR_BindFramebuffer(engine_t *engine) { if (!initialized) return; int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; - unsigned int swapchainIndex = frameBuffer->TextureSwapChainIndex; - unsigned int glFramebuffer = frameBuffer->FrameBuffers[swapchainIndex]; - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, glFramebuffer)); + ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]); } ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) { From d8fbc7ce56e426d7bdd65318d4a3f009e8c55974 Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 14 Sep 2022 19:53:55 +0200 Subject: [PATCH 003/715] OpenXR - Vulkan support in progress --- Common/VR/PPSSPPVR.cpp | 22 ++++- Common/VR/PPSSPPVR.h | 4 +- Common/VR/VRBase.cpp | 22 +++-- Common/VR/VRBase.h | 23 ++++- Common/VR/VRFramebuffer.cpp | 181 ++++++++++++++++++++++++++++-------- Common/VR/VRFramebuffer.h | 4 +- Common/VR/VRRenderer.cpp | 12 ++- android/jni/app-android.cpp | 2 +- 8 files changed, 204 insertions(+), 66 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 23712db954..ef0d6f7c03 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -1,3 +1,4 @@ +#include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/VR/PPSSPPVR.h" #include "Common/VR/VRBase.h" #include "Common/VR/VRInput.h" @@ -109,10 +110,25 @@ void InitVROnAndroid(void* vm, void* activity, int version, const char* name) { __DisplaySetFramerate(72); } -void EnterVR(bool firstStart) { +void EnterVR(bool firstStart, void* vulkanContext) { if (firstStart) { - VR_EnterVR(VR_GetEngine()); - IN_VRInit(VR_GetEngine()); + engine_t* engine = VR_GetEngine(); + bool useVulkan = (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN; + if (useVulkan) { + auto* context = (VulkanContext*)vulkanContext; + engine->graphicsBindingVulkan = {}; + engine->graphicsBindingVulkan.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR; + engine->graphicsBindingVulkan.next = NULL; + engine->graphicsBindingVulkan.device = context->GetDevice(); + engine->graphicsBindingVulkan.instance = context->GetInstance(); + engine->graphicsBindingVulkan.physicalDevice = context->GetCurrentPhysicalDevice(); + engine->graphicsBindingVulkan.queueFamilyIndex = context->GetGraphicsQueueFamilyIndex(); + engine->graphicsBindingVulkan.queueIndex = 0; + VR_EnterVR(engine, &engine->graphicsBindingVulkan); + } else { + VR_EnterVR(engine, nullptr); + } + IN_VRInit(engine); } VR_SetConfig(VR_CONFIG_VIEWPORT_VALID, false); } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index e7151130ea..7ff1338eea 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -8,7 +8,7 @@ // VR app flow integration bool IsVRBuild(); void InitVROnAndroid(void* vm, void* activity, int version, const char* name); -void EnterVR(bool firstStart); +void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); void UpdateVRScreenKey(const KeyInput &key); @@ -31,7 +31,7 @@ void UpdateVRView(float* leftEye, float* rightEye); // VR app flow integration inline bool IsVRBuild() { return false; } inline void InitVROnAndroid(void* vm, void* activity, int version, const char* name) {} -inline void EnterVR(bool firstTime) {} +inline void EnterVR(bool firstTime, void* vulkanContext) {} inline void GetVRResolutionPerEye(int* width, int* height) {} inline void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {} inline void UpdateVRScreenKey(const KeyInput &key) {} diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index bedc6b1e0c..e146967b42 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -118,6 +118,7 @@ void VR_Init( ovrJava java, bool useVulkan ) { vr_engine.appState.SystemId = systemId; vr_engine.java = java; + vr_engine.useVulkan = useVulkan; vr_initialized = 1; } @@ -128,7 +129,7 @@ void VR_Destroy( engine_t* engine ) { } } -void VR_EnterVR( engine_t* engine ) { +void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ) { if (engine->appState.Session) { ALOGE("VR_EnterVR called with existing session"); @@ -136,17 +137,20 @@ void VR_EnterVR( engine_t* engine ) { } // Create the OpenXR Session. - XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingAndroidGLES = {}; - graphicsBindingAndroidGLES.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; - graphicsBindingAndroidGLES.next = NULL; - graphicsBindingAndroidGLES.display = eglGetCurrentDisplay(); - graphicsBindingAndroidGLES.config = eglGetCurrentSurface(EGL_DRAW); - graphicsBindingAndroidGLES.context = eglGetCurrentContext(); - XrSessionCreateInfo sessionCreateInfo = {}; + XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingAndroidGLES = {}; memset(&sessionCreateInfo, 0, sizeof(sessionCreateInfo)); + if (engine->useVulkan) { + sessionCreateInfo.next = graphicsBindingVulkan; + } else { + graphicsBindingAndroidGLES.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; + graphicsBindingAndroidGLES.next = NULL; + graphicsBindingAndroidGLES.display = eglGetCurrentDisplay(); + graphicsBindingAndroidGLES.config = eglGetCurrentSurface(EGL_DRAW); + graphicsBindingAndroidGLES.context = eglGetCurrentContext(); + sessionCreateInfo.next = &graphicsBindingAndroidGLES; + } sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO; - sessionCreateInfo.next = &graphicsBindingAndroidGLES; sessionCreateInfo.createFlags = 0; sessionCreateInfo.systemId = engine->appState.SystemId; diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 4d5138e40f..89bec2b3dd 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -9,6 +9,14 @@ #define ALOGV(...) printf(__VA_ARGS__) #endif +//Vulkan +#ifdef VK_USE_NATIVE_LIB +#include +#else +#include "Common/GPU/Vulkan/VulkanLoader.h" +using namespace PPSSPP_VK; +#endif + //OpenXR #define XR_USE_PLATFORM_ANDROID 1 #define XR_USE_GRAPHICS_API_OPENGL_ES 1 @@ -17,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -98,10 +105,14 @@ typedef struct { uint32_t TextureSwapChainIndex; ovrSwapChain ColorSwapChain; ovrSwapChain DepthSwapChain; - XrSwapchainImageOpenGLESKHR* ColorSwapChainImage; - XrSwapchainImageOpenGLESKHR* DepthSwapChainImage; - unsigned int* FrameBuffers; + void* ColorSwapChainImage; + void* DepthSwapChainImage; + unsigned int* GLFrameBuffers; + VkFramebuffer* VKFrameBuffers; + bool Acquired; + bool UseVulkan; + XrGraphicsBindingVulkanKHR* VKContext; } ovrFramebuffer; typedef struct { @@ -146,11 +157,13 @@ typedef struct { ovrApp appState; ovrJava java; float predictedDisplayTime; + bool useVulkan; + XrGraphicsBindingVulkanKHR graphicsBindingVulkan; } engine_t; void VR_Init( ovrJava java, bool useVulkan ); void VR_Destroy( engine_t* engine ); -void VR_EnterVR( engine_t* engine ); +void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ); void VR_LeaveVR( engine_t* engine ); engine_t* VR_GetEngine( void ); diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 007a21cee8..4a71cb5cd8 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -37,14 +37,15 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) { frameBuffer->DepthSwapChain.Height = 0; frameBuffer->DepthSwapChainImage = NULL; - frameBuffer->FrameBuffers = NULL; + frameBuffer->GLFrameBuffers = NULL; frameBuffer->Acquired = false; } -bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { +bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { frameBuffer->Width = width; frameBuffer->Height = height; + frameBuffer->UseVulkan = false; if (strstr((const char*)glGetString(GL_EXTENSIONS), "GL_OVR_multiview2") == nullptr) { @@ -78,20 +79,20 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->ColorSwapChain.Handle)); OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL)); - frameBuffer->ColorSwapChainImage = (XrSwapchainImageOpenGLESKHR*)malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); + frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); // Create the depth swapchain. swapChainCreateInfo.format = GL_DEPTH24_STENCIL8; swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle)); - frameBuffer->DepthSwapChainImage = (XrSwapchainImageOpenGLESKHR*)malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); + frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); // Populate the swapchain image array. for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { - frameBuffer->ColorSwapChainImage[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; - frameBuffer->ColorSwapChainImage[i].next = NULL; - frameBuffer->DepthSwapChainImage[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; - frameBuffer->DepthSwapChainImage[i].next = NULL; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL; } OXR(xrEnumerateSwapchainImages( frameBuffer->ColorSwapChain.Handle, @@ -104,14 +105,14 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w &frameBuffer->TextureSwapChainLength, (XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage)); - frameBuffer->FrameBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint)); + frameBuffer->GLFrameBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint)); for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { - const GLuint colorTexture = frameBuffer->ColorSwapChainImage[i].image; - const GLuint depthTexture = frameBuffer->DepthSwapChainImage[i].image; + const GLuint colorTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].image; + const GLuint depthTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].image; // Create the frame buffer. - GL(glGenFramebuffers(1, &frameBuffer->FrameBuffers[i])); - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[i])); + GL(glGenFramebuffers(1, &frameBuffer->GLFrameBuffers[i])); + GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[i])); if (multiview) { GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexture, 0, 0, 2)); GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0, 2)); @@ -132,29 +133,114 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w return true; } +bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, + bool multiview, void* context) { + + frameBuffer->Width = width; + frameBuffer->Height = height; + frameBuffer->UseVulkan = true; + frameBuffer->VKContext = (XrGraphicsBindingVulkanKHR*)context; + + XrSwapchainCreateInfo swapChainCreateInfo; + memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo)); + swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO; + swapChainCreateInfo.sampleCount = 1; + swapChainCreateInfo.width = width; + swapChainCreateInfo.height = height; + swapChainCreateInfo.faceCount = 1; + swapChainCreateInfo.mipCount = 1; + swapChainCreateInfo.arraySize = multiview ? 2 : 1; + + frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width; + frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height; + frameBuffer->DepthSwapChain.Width = swapChainCreateInfo.width; + frameBuffer->DepthSwapChain.Height = swapChainCreateInfo.height; + + // Create the color swapchain. + swapChainCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; + OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->ColorSwapChain.Handle)); + OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL)); + frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR)); + + // Create the depth swapchain. + swapChainCreateInfo.format = VK_FORMAT_D24_UNORM_S8_UINT; + swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle)); + frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR)); + + // Populate the swapchain image array. + for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { + ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; + ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL; + ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; + ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL; + } + OXR(xrEnumerateSwapchainImages( + frameBuffer->ColorSwapChain.Handle, + frameBuffer->TextureSwapChainLength, + &frameBuffer->TextureSwapChainLength, + (XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage)); + OXR(xrEnumerateSwapchainImages( + frameBuffer->DepthSwapChain.Handle, + frameBuffer->TextureSwapChainLength, + &frameBuffer->TextureSwapChainLength, + (XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage)); + + frameBuffer->VKFrameBuffers = (VkFramebuffer*)malloc(frameBuffer->TextureSwapChainLength * sizeof(VkFramebuffer)); + for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { + VkImage colorTexture = ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].image; + VkImage depthTexture = ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].image; + + // Create the frame buffer. + //TODO:implement framebuffer creation + } + + return true; +} + void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { - GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->FrameBuffers)); + if (frameBuffer->UseVulkan) { + for (int i = 0; i < frameBuffer->TextureSwapChainLength; i++) { + vkDestroyFramebuffer(frameBuffer->VKContext->device, frameBuffer->VKFrameBuffers[i], nullptr); + } + free(frameBuffer->VKFrameBuffers); + } else { + GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); + free(frameBuffer->GLFrameBuffers); + } OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle)); OXR(xrDestroySwapchain(frameBuffer->DepthSwapChain.Handle)); free(frameBuffer->ColorSwapChainImage); free(frameBuffer->DepthSwapChainImage); - free(frameBuffer->FrameBuffers); ovrFramebuffer_Clear(frameBuffer); } void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->TextureSwapChainIndex])); + if (frameBuffer->UseVulkan) { + //TODO:bind framebuffer + } else { + GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); + } } -void ovrFramebuffer_SetNone() { - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); +void ovrFramebuffer_SetNone(ovrFramebuffer* frameBuffer) { + if (frameBuffer->UseVulkan) { + //TODO:unbind framebuffer + } else { + GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + } } void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer) { // Discard the depth buffer, so the tiler won't need to write it back out to memory. - const GLenum depthAttachment[1] = {GL_DEPTH_ATTACHMENT}; - glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, depthAttachment); + if (frameBuffer->UseVulkan) { + //TODO:implement + } else { + const GLenum depthAttachment[1] = {GL_DEPTH_ATTACHMENT}; + glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, depthAttachment); + } } void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { @@ -178,13 +264,18 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = res == XR_SUCCESS; ovrFramebuffer_SetCurrent(frameBuffer); - GL(glEnable( GL_SCISSOR_TEST )); - GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); - GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); - GL(glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height )); - GL(glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )); - GL(glScissor( 0, 0, 0, 0 )); - GL(glDisable( GL_SCISSOR_TEST )); + + if (frameBuffer->UseVulkan) { + //TODO:implement + } else { + GL(glEnable( GL_SCISSOR_TEST )); + GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); + GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); + GL(glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height )); + GL(glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )); + GL(glScissor( 0, 0, 0, 0 )); + GL(glDisable( GL_SCISSOR_TEST )); + } } void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { @@ -194,10 +285,14 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = false; // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully - GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); - GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); - GL(glClear(GL_COLOR_BUFFER_BIT)); - GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)); + if (frameBuffer->UseVulkan) { + //TODO:implement + } else { + GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); + GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); + GL(glClear(GL_COLOR_BUFFER_BIT)); + GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)); + } } } @@ -215,11 +310,15 @@ void ovrRenderer_Clear(ovrRenderer* renderer) { } } -void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview) { +void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext) { renderer->Multiview = multiview; int instances = renderer->Multiview ? 1 : ovrMaxNumEyes; for (int i = 0; i < instances; i++) { - ovrFramebuffer_Create(session, &renderer->FrameBuffer[i], width, height, multiview); + if (vulkanContext) { + ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, multiview, vulkanContext); + } else { + ovrFramebuffer_CreateGL(session, &renderer->FrameBuffer[i], width, height, multiview); + } } } @@ -231,12 +330,16 @@ void ovrRenderer_Destroy(ovrRenderer* renderer) { } void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { - GL(glEnable(GL_SCISSOR_TEST)); - GL(glScissor(x, y, size, size)); - GL(glViewport(x, y, size, size)); - GL(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); - GL(glClear(GL_COLOR_BUFFER_BIT)); - GL(glDisable(GL_SCISSOR_TEST)); + if (renderer->FrameBuffer[0].UseVulkan) { + //TODO:implement + } else { + GL(glEnable(GL_SCISSOR_TEST)); + GL(glScissor(x, y, size, size)); + GL(glViewport(x, y, size, size)); + GL(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); + GL(glClear(GL_COLOR_BUFFER_BIT)); + GL(glDisable(GL_SCISSOR_TEST)); + } } /* diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index 20b9004190..12eb162980 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -10,8 +10,8 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer); void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer); void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer); void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer); -void ovrFramebuffer_SetNone(); +void ovrFramebuffer_SetNone(ovrFramebuffer* frameBuffer); -void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview); +void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext); void ovrRenderer_Destroy(ovrRenderer* renderer); void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 1d421c2fa3..f9a8e5ce53 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -204,12 +204,14 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView))); - ovrRenderer_Create( - engine->appState.Session, - &engine->appState.Renderer, + void* vulkanContext = nullptr; + if (engine->useVulkan) { + vulkanContext = &engine->graphicsBindingVulkan; + } + ovrRenderer_Create(engine->appState.Session, &engine->appState.Renderer, engine->appState.ViewConfigurationView[0].recommendedImageRectWidth, engine->appState.ViewConfigurationView[0].recommendedImageRectHeight, - multiview); + multiview, vulkanContext); initialized = true; } @@ -311,7 +313,7 @@ void VR_EndFrame( engine_t* engine ) { ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; //ovrFramebuffer_Resolve(frameBuffer); ovrFramebuffer_Release(frameBuffer); - ovrFramebuffer_SetNone(); + ovrFramebuffer_SetNone(frameBuffer); } void VR_FinishFrame( engine_t* engine ) { diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 482b864ea5..d430322afc 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -940,7 +940,7 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, NativeMessageReceived("recreateviews", ""); if (IsVRBuild()) { - EnterVR(firstStart); + EnterVR(firstStart, graphicsContext->GetAPIContext()); } return true; From 896f753e86fe4a691fca5fbd15ad5d2dd209bae9 Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Sun, 2 Oct 2022 17:40:30 +0200 Subject: [PATCH 004/715] assets/lang: translate more stuff in settings screen --- assets/lang/pl_PL.ini | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index e963535aee..c128098a46 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -1,5 +1,5 @@ [Audio] -Alternate speed volume = Alternate speed volume +Alternate speed volume = Alternatywna prędkość emulacji Audio backend = Sterownik dźwięku (wymagany restart) Audio Error = Błąd Audio AudioBufferingForBluetooth = Bufory dźwięku dost. do Bluetooth (wolniejsze) @@ -57,7 +57,7 @@ Gesture = Gesty Gesture mapping = Konfiguracja gestów Glowing borders = Świecące krawędzie HapticFeedback = Wibracje -Hide touch analog stick background circle = Hide touch analog stick background circle +Hide touch analog stick background circle = Ukryj obszar zasięgu Gałki Analogowej Icon = Ikona Ignore gamepads when not focused = Ignoruj przyciski pada gdy okno nieaktywne Ignore Windows Key = Ignoruj klawisz Windows @@ -472,11 +472,11 @@ Bicubic = Bicubic (Dwusześcienne) BlockTransfer Tip = Niektóre gry wymagają włączenia tej opcji do poprawnego działania. BlockTransferRequired = Uwaga: Ta gra wymaga włączonej opcji "Symuluj efekty transferu bloków". Both = Oba -Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) +Buffer graphics commands (faster, input lag) = Bufor komand grafiki (szybsze, może powodować lagi sterowania) Buffered Rendering = Renderowanie buforowe BufferedRenderingRequired = Uwaga: Ta gra wymaga włączonej opcji "Renderowanie buforowe". -Camera = Camera -Camera Device = Camera device +Camera = Kamera +Camera Device = Kamera Cardboard Screen Size = Rozmiar ekranu (% widocznego obszaru) Cardboard Screen X Shift = Przesunięcie X (% pustej przestrzeni) Cardboard Screen Y Shift = Przesunięcie Y (% pustej przestrzeni) @@ -494,7 +494,7 @@ Disabled = Wył. Display layout editor = Edytor położenia obrazu Display Resolution (HW scaler) = Rozdzielczość ekranu (skaler sprz.) Dump next frame to log = Zrzuć następną klatkę do dziennika zdarzeń -Enable Cardboard VR = Enable Cardboard VR +Enable Cardboard VR = Aktywuj Cardboard VR FPS = Tylko FPS Frame Rate Control = Kontrola klatek na sekundę Frame Skipping = Pomijanie klatek @@ -537,7 +537,7 @@ Performance = Wydajność Postprocessing effect = Postprocessing effects Postprocessing Shader = Efekty wizualne shaderów Recreate Activity = Recreate activity -Render duplicate frames to 60hz = Render duplicate frames to 60 Hz +Render duplicate frames to 60hz = Renderuj duplikowane klatki w 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Tryb renderowania Rendering Resolution = Rozdzielczość renderowania @@ -759,38 +759,38 @@ Change proAdhocServer Address = Zmień adres IP serwera PRO dla trybu ad hoc (lo ChangeMacSaveConfirm = Generate a new MAC address? ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Chat -Chat Button Position = Chat button position -Chat Here = Chat here -Chat message = Chat message -Chat Screen Position = Chat screen position -Disconnected from AdhocServer = Disconnected from ad hoc server +Chat Button Position = Pozycja przycisku chatu +Chat Here = Napisz wiadomość +Chat message = Wiadomość +Chat Screen Position = Pozycja ekranu chatu +Disconnected from AdhocServer = Rozłączono z ad hoc serwerem DNS Error Resolving = DNS error resolving Enable built-in PRO Adhoc Server = Włącz wbudowany serwer PRO dla trybu ad hoc -Enable network chat = Enable network chat +Enable network chat = Uruchom chat Enable networking = Włącz sieć/WLAN (beta, może powodować błędy) -Enable UPnP = Enable UPnP (need a few seconds to detect) -EnableQuickChat = Enable quick chat +Enable UPnP = Uruchom UPnP (potrzebuje kilka sekund na wykrycie) +EnableQuickChat = Uruchom szybki chat Enter a new PSP nickname = Enter a new PSP nickname -Enter Quick Chat 1 = Enter quick chat 1 -Enter Quick Chat 2 = Enter quick chat 2 -Enter Quick Chat 3 = Enter quick chat 3 -Enter Quick Chat 4 = Enter quick chat 4 -Enter Quick Chat 5 = Enter quick chat 5 -Error = Error +Enter Quick Chat 1 = Wejdź na szybki chat 1 +Enter Quick Chat 2 = Wejdź na szybki chat 2 +Enter Quick Chat 3 = Wejdź na szybki chat 3 +Enter Quick Chat 4 = Wejdź na szybki chat 4 +Enter Quick Chat 5 = Wejdź na szybki chat 5 +Error = Błąd Failed to Bind Localhost IP = Failed to bind localhost IP Failed to Bind Port = Failed to bind port Failed to connect to Adhoc Server = Failed to connect to ad hoc server -Forced First Connect = Forced first connect (faster connect) +Forced First Connect = Wymuszenie pierwszego połączenie (szybsze łączenie) GM: Data from Unknown Port = GM: Data from Unknown Port Hostname = Hostname Invalid IP or hostname = Invalid IP or hostname -Minimum Timeout = Minimum timeout (override in ms, 0 = default) -Misc = Miscellaneous (default = PSP compatibility) +Minimum Timeout = Minimalny czas oczekiwania (podaj w ms, domyślnie 0) +Misc = Inne (domyślnie = Kompatybilność z PSP) Network Initialized = Sieć została zainicjowana None = None Please change your Port Offset = Please change your port offset Port offset = Zmień port (0 = zgodne z PSP) -Open PPSSPP Multiplayer Wiki Page = Open PPSSPP Multiplayer Wiki Page +Open PPSSPP Multiplayer Wiki Page = Przejdź do strony PPSSPP pomocy dla wielu graczy. proAdhocServer Address: = Ad hoc server address: Quick Chat 1 = Quick chat 1 Quick Chat 2 = Quick chat 2 @@ -808,7 +808,7 @@ UPnP (port-forwarding) = UPnP (port forwarding) UPnP need to be reinitialized = UPnP need to be reinitialized UPnP use original port = UPnP use original port (enabled = PSP compatibility) Validating address... = Validating address... -WLAN Channel = WLAN channel +WLAN Channel = Kanał WLAN You're in Offline Mode, go to lobby or online hall = You're in offline mode, go to lobby or online hall [Pause] @@ -1008,11 +1008,11 @@ State load undone = State load undone Untitled PSP game = Untitled PSP game [Search] -Clear filter = Clear filter -Filter = Filter -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -No settings matched '%1' = No settings matched '%1' +Clear filter = Wyczyść frazę +Filter = Szukaj +Filtering settings by '%1' = Wyszukiwanie ustawień '%1' +Find settings = Szukaj ustawień +No settings matched '%1' = Brak wyników dla '%1' [Store] Already Installed = Zainstalowane @@ -1181,7 +1181,7 @@ Theme = Motyw Time Format = Format czasu UI = Interfejs użytkownika UI background animation = Animacja tła -UI Sound = UI sound +UI Sound = Dźwięki interfejsu użydkownika undo %c = backup %c USB = USB Use Lossless Video Codec (FFV1) = Używaj stratnego kodeka wideo (FFV1) From 80448c557033eb32dc335a0a0770331f0d6b4ac0 Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Sun, 2 Oct 2022 17:45:38 +0200 Subject: [PATCH 005/715] assets/lang pl_PL: edit some translations on game pause screen I've decided to edit some translations on the game-pause screen as I think they sounds better now --- assets/lang/pl_PL.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index c128098a46..036a5a7b72 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -816,15 +816,15 @@ Cheats = Kody Continue = Kontynuuj Create Game Config = Utwórz konfigurację gry Delete Game Config = Usuń konfigurację gry -Exit to menu = Wyjdź do menu +Exit to menu = Wróć do menu Game Settings = Ustawienia gry Load State = Wczytaj stan Rewind = Przewiń do tyłu Save State = Zapisz stan Settings = Ustawienia Switch UMD = Podmień UMD -Undo last load = Undo last load -Undo last save = Undo last save +Undo last load = Cofnij ostatnio wczytane +Undo last save = Cofnij ostatni zapis [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) @@ -951,8 +951,8 @@ Perfect = Perfekcyjnie Perfect Description = Bezbłędna emulacja w całej grze - super! Plays = Działa Plays Description = Całkowicie grywalna, jednak można napotkać niewielkie błędy -ReportButton = Raportuj -Show disc CRC = Show disc CRC +ReportButton = Zgłoś błąd +Show disc CRC = Pokaż sumę kontrolną (CRC) dysku Speed = Szybkość Submit Feedback = Wyślij raport SuggestionConfig = Sprawdź dobre konfiguracje w raportach na stronie. From f97b8f9e59d53048a0bfa61c26c19cf47798ca40 Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Sun, 2 Oct 2022 18:30:31 +0200 Subject: [PATCH 006/715] lang/pl: translate errors section --- assets/lang/pl_PL.ini | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 036a5a7b72..f5a1bf70ea 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -364,30 +364,30 @@ Disk full while writing data = Dysk zapełniony. ELF file truncated - can't load = ELF file truncated - can't load Error loading file = Wystąpił błąd: Error reading file = Błąd podczas odczytywania pliku. -Failed initializing CPU/Memory = Failed initializing CPU or memory -Failed to load executable: = Failed to load executable: +Failed initializing CPU/Memory = Nie można zainicjować CPU lub pamięci +Failed to load executable: = Nie udało się uruchomić pliku wykonywalnego: File corrupt = Uszkodzony plik Game disc read error - ISO corrupt = Nie można odczytać danych z dysku - plik ISO uszkodzony. -GenericAllStartupError = PPSSPP failed to start up with any graphics backend. Try upgrading your graphics and other drivers. -GenericBackendSwitchCrash = PPSSPP crashed while starting.\n\nThis usually means a graphics driver problem. Try upgrading your graphics drivers.\n\nGraphics backend has been switched: +GenericAllStartupError = PPSSPP nie może uruchomić żadnego trybu grafiki. Sprubuj zaktualizować swoje sterowniki do karty graficznej (oraz pozostałe). +GenericBackendSwitchCrash = PPSSPP - wystąpił błąd podczas uruchamiania emulatora.\n\nMoże to oznaczać problem ze sterownikiem do karty graficznej. Sprubuj go zaktualizować.\n\nSilnik graficzny został zmieniony: GenericDirect3D9Error = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej i biblioteki DirectX9.\n\nCzy chcesz zmienić sterownik na OpenGL?\n\nKomunikat błędu: GenericGraphicsError = Błąd grafiki GenericOpenGLError = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej.\n\nCzy chcesz zmienić sterownik na DirectX 9?\n\nKomunikat błędu: GenericVulkanError = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej.\n\nCzy chcesz zmienić sterownik na OpenGL?\n\nKomunikat błędu: InsufficientOpenGLDriver = Wykryto brak obsługi wystarczająco nowej wersji OpenGL!\n\nTwoja karta graficzna zgłasza, że nie obsługuje OpenGL 2.0, który jest aktualnie wymagany do uruchomienia PPSSPP.\n\nSprawdź, czy Twoja karta graficzna jest zgodna z OpenGL 2.0. Jeśli jest, musisz zainstalować nowe sterowniki ze strony producenta.\n\nOdwiedź forum https://forums.ppsspp.org, aby uzyskać więcej informacji. Just a directory. = Tylko katalog. -Missing key = Missing key -MsgErrorCode = Error code: -MsgErrorSavedataDataBroken = Save data was corrupt. -MsgErrorSavedataMSFull = Memory Stick full. Check your storage space. -MsgErrorSavedataNoData = Warning: no save data was found. -MsgErrorSavedataNoMS = Memory Stick not inserted. +Missing key = Brak klucza +MsgErrorCode = Kod błędu: +MsgErrorSavedataDataBroken = Uszkodzone dane zapisu. +MsgErrorSavedataMSFull = Karta pamięci pełna. Sprawdź miejsce na dysku. +MsgErrorSavedataNoData = Uwaga: nie znaleziono danych zapisu. +MsgErrorSavedataNoMS = Brak Karty Pamięci. No EBOOT.PBP, misidentified game = Brak EBOOT.PBP, gra nierozpoznana. Not a valid disc image. = Nieprawidłowy obraz nośnika. OpenGLDriverError = Błąd sterownika OpenGL. PPSSPP doesn't support UMD Music. = PPSSPP nie wspiera UMD Music. PPSSPP doesn't support UMD Video. = PPSSPP nie wspiera UMD Video. -PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP plays PSP games, not PlayStation 1 or 2 games. +PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP odtwarza gry na PSP, nie na PlayStation 1/2 PPSSPPDoesNotSupportInternet = PPSSPP aktualnie nie obsługuje połączenia z Internetem dla DLC, PSN oraz aktualizacji gier. PS1 EBOOTs are not supported by PPSSPP. = Pliki EBOOT PS1 nie są obsługiwane przez PPSSPP. PSX game image detected. = Plik jest obrazem MODE2. PPSSPP nie obsługuje gier z PS1. @@ -400,7 +400,7 @@ textures.ini filenames may not be cross-platform = Nazwy plików w "textures.ini This is a saved state, not a game. = To jest zapis stanu, a nie gra. This is save data, not a game. = To jest zapis gry, a nie gra. Unable to create cheat file, disk may be full = Nie można utworzyć pliku kodów, dysk może być już zapełniony. -Unable to initialize rendering engine. = Unable to initialize rendering engine. +Unable to initialize rendering engine. = Nie można zainicjować silnika renderowania. Unable to write savedata, disk may be full = Nie można zapisać danych zapisu gry, dysk może być już zapełniony. Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = Ostrzeżenie: Pamięć wideo jest PEŁNA, nastąpi zmniejszenie rozdzielczości i zmiana na powolne buforowanie. Warning: Video memory FULL, switching to slow caching mode = Ostrzeżenie: Pamięć wideo jest PEŁNA, nastąpi zmiana na powolne buforowanie. From 64c5b5e55d06b8989278bbfbb44f29f41a1f2cf6 Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Sun, 2 Oct 2022 20:11:30 +0200 Subject: [PATCH 007/715] lang/pl_PL: translate controlls section mostly done, I don't have idea how to translate some parts, so I leave them as is (don't want to copy-paste from translator) --- assets/lang/pl_PL.ini | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index f5a1bf70ea..6a8b45a191 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -18,20 +18,20 @@ Use global volume = Używaj głośności globalnej WASAPI (fast) = WASAPI (szybki) [Controls] -Analog Binding = Analog Binding -Analog Limiter = Ogranicznik analoga -Analog Settings = Analog Settings +Analog Binding = Połączenie Gałki Analogowej +Analog Limiter = Ogranicznik Gałki Analogowej +Analog Settings = Ustawienia Gałki Analogowej Analog Stick = Gałka analogowa -Analog Style = Analog Style -AnalogLimiter Tip = Jeśli "ogranicznik analoga" jest aktywny +Analog Style = Styl Gałki Analogowej +AnalogLimiter Tip = Jeśli "ogranicznik Gałki Analogowej" jest aktywny Auto = Automatyczny Auto-centering analog stick = Autocentrowanie gałki analogowej Auto-hide buttons after seconds = Automatyczne ukrywanie przycisków po: Auto-rotation speed = Prędkość automatycznego obracania Auto-switch = Auto-switch -Base tilt position = Base tilt position -Binds = Binds -Button Binding = Button Binding +Base tilt position = Domyślna pozycja tytułu +Binds = Powiązania +Button Binding = Konfiguracja przycisków Button Opacity = Przeźroczystość przycisków Button style = Styl przycisków Calibrate Analog Stick = Kalibracja Gałki Analogowej @@ -81,8 +81,8 @@ OnScreen = Przyciski ekranowe Portrait = Pionowo Portrait Reversed = Odwrócone pionowo PSP Action Buttons = Klawisze akcji PSP -Raw input = Raw input -Repeat mode = Repeat mode +Raw input = Zwykłe wejście +Repeat mode = Tryb powtarzania Reset to defaults = Domyślne Screen aligned to ground = Screen aligned to ground Screen at right angle to ground = Screen at right angle to ground @@ -106,7 +106,7 @@ Touch Control Visibility = Kontroler dotykowy (widoczny) Use custom right analog = Use custom right analog Use Mouse Control = Włącz kontrolę myszką Visibility = Widoczność -Visible = Visible +Visible = WIdoczny X = X Y = Y From acdaaae7a4b0af0efe93eb6f3760b2cd85fe6a5f Mon Sep 17 00:00:00 2001 From: Nemoumbra Date: Wed, 12 Oct 2022 11:55:01 +0300 Subject: [PATCH 008/715] Added optional parameter to hle.func.scan, improved code of hle.func.removeRange --- Core/Debugger/WebSocket/HLESubscriber.cpp | 92 ++++++++++++++++------- 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/Core/Debugger/WebSocket/HLESubscriber.cpp b/Core/Debugger/WebSocket/HLESubscriber.cpp index 2a90ca619d..50ef77163d 100644 --- a/Core/Debugger/WebSocket/HLESubscriber.cpp +++ b/Core/Debugger/WebSocket/HLESubscriber.cpp @@ -362,6 +362,41 @@ void WebSocketHLEFuncRemove(DebuggerRequest &req) { json.writeUint("size", funcSize); } +static u32 RemoveFuncSymbolsInRange(u32 addr, u32 size) { + // Note: this makes no checks whether the range is valid + + u32 func_address = g_symbolMap->GetFunctionStart(addr); + if (func_address == SymbolMap::INVALID_ADDRESS) { + func_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION); + } + + u32 counter = 0; + while (func_address < addr + size && func_address != SymbolMap::INVALID_ADDRESS) { + g_symbolMap->RemoveFunction(func_address, true); + ++counter; + func_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION); + } + + if (counter) { + MIPSAnalyst::ForgetFunctions(addr, addr + size - 1); + + // The following was copied from hle.func.remove: + g_symbolMap->SortSymbols(); + + MIPSAnalyst::UpdateHashMap(); + MIPSAnalyst::ApplyHashMap(); + + if (g_Config.bFuncReplacements) { + MIPSAnalyst::ReplaceFunctions(); + } + + // Clear cache for branch lines and such. + DisassemblyManager manager; + manager.clear(); + } + return counter; +} + // Remove function symbols in range (hle.func.removeRange) // // Parameters: @@ -386,34 +421,10 @@ void WebSocketHLEFuncRemoveRange(DebuggerRequest &req) { if (!Memory::IsValidRange(addr, size)) return req.Fail("Address or size outside valid memory"); - u32 first_address = g_symbolMap->GetFunctionStart(addr); - if (first_address == SymbolMap::INVALID_ADDRESS) { - first_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION); - } - - u32 counter = 0; - for (u32 current_addr = first_address; (current_addr < addr + size) && current_addr != SymbolMap::INVALID_ADDRESS; current_addr = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION)) { - g_symbolMap->RemoveFunction(current_addr, true); - ++counter; - } - MIPSAnalyst::ForgetFunctions(addr, addr + size - 1); - - // The following was copied from hle.func.remove: - g_symbolMap->SortSymbols(); - - MIPSAnalyst::UpdateHashMap(); - MIPSAnalyst::ApplyHashMap(); - - if (g_Config.bFuncReplacements) { - MIPSAnalyst::ReplaceFunctions(); - } - - // Clear cache for branch lines and such. - DisassemblyManager manager; - manager.clear(); + u32 count = RemoveFuncSymbolsInRange(addr, size); JsonWriter &json = req.Respond(); - json.writeUint("count", counter); + json.writeUint("count", count); } // Rename a function symbol (hle.func.rename) @@ -480,9 +491,38 @@ void WebSocketHLEFuncScan(DebuggerRequest &req) { if (!req.ParamU32("size", &size)) return; + bool has_recreate = req.HasParam("recreate"); + bool recreate; + if (has_recreate) { + if (!req.ParamBool("recreate", &recreate)) { + return; + } + } + if (!Memory::IsValidRange(addr, size)) return req.Fail("Address or size outside valid memory"); + if (recreate) { + // let's see if the last function is partially inside our range + + u32 last_func_start = g_symbolMap->GetFunctionStart(addr + size - 1); + if (last_func_start != SymbolMap::INVALID_ADDRESS) { + // there is a function + // u32 end = last_func_start + g_symbolMap->GetFunctionSize(last_func_start); + if (last_func_start + g_symbolMap->GetFunctionSize(last_func_start) != addr + size) { + size = last_func_start - addr; + } + } + // let's see if the first function is partially inside our range + u32 start = g_symbolMap->GetFunctionStart(addr); + + if (start != SymbolMap::INVALID_ADDRESS && start != addr) { + // skip to a byte after end + addr = start + g_symbolMap->GetFunctionSize(start); + } + RemoveFuncSymbolsInRange(addr, size); + } + bool insertSymbols = MIPSAnalyst::ScanForFunctions(addr, addr + size - 1, true); MIPSAnalyst::FinalizeScan(insertSymbols); From a772e87072731376340c841120090b1f619be642 Mon Sep 17 00:00:00 2001 From: Nemoumbra Date: Wed, 12 Oct 2022 12:09:05 +0300 Subject: [PATCH 009/715] Comments updated, default value for parameter "recreate" set to false --- Core/Debugger/WebSocket/HLESubscriber.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/Debugger/WebSocket/HLESubscriber.cpp b/Core/Debugger/WebSocket/HLESubscriber.cpp index 50ef77163d..8c8bfe50dd 100644 --- a/Core/Debugger/WebSocket/HLESubscriber.cpp +++ b/Core/Debugger/WebSocket/HLESubscriber.cpp @@ -476,6 +476,7 @@ void WebSocketHLEFuncRename(DebuggerRequest &req) { // Parameters: // - address: unsigned integer address for the start of the range. // - size: unsigned integer size in bytes for scan. +// - recreate: optional bool indicating whether functions that lie inside the range must be removed before scanning // // Response (same event name) with no extra data. void WebSocketHLEFuncScan(DebuggerRequest &req) { @@ -492,7 +493,7 @@ void WebSocketHLEFuncScan(DebuggerRequest &req) { return; bool has_recreate = req.HasParam("recreate"); - bool recreate; + bool recreate = false; if (has_recreate) { if (!req.ParamBool("recreate", &recreate)) { return; @@ -510,7 +511,7 @@ void WebSocketHLEFuncScan(DebuggerRequest &req) { // there is a function // u32 end = last_func_start + g_symbolMap->GetFunctionSize(last_func_start); if (last_func_start + g_symbolMap->GetFunctionSize(last_func_start) != addr + size) { - size = last_func_start - addr; + size = last_func_start - addr; // decrease the size parameter } } // let's see if the first function is partially inside our range From ade606bc3c7a13f7a13b01f664aa1f0bf17313eb Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 12 Oct 2022 16:21:54 +0200 Subject: [PATCH 010/715] OpenXR - Hookup VR API into Vulkan --- Common/GPU/OpenGL/GLQueueRunner.cpp | 7 +++---- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 18 ++++++++++++------ Common/GPU/Vulkan/VulkanQueueRunner.h | 2 +- Common/GPU/Vulkan/VulkanRenderManager.cpp | 17 ++++++++++++++++- Common/UI/UIScreen.cpp | 5 ----- Common/VR/PPSSPPVR.cpp | 4 ++-- Common/VR/PPSSPPVR.h | 4 ++-- Common/VR/VRFramebuffer.cpp | 23 +++-------------------- Common/VR/VRFramebuffer.h | 4 +--- Common/VR/VRRenderer.cpp | 11 ++++------- Common/VR/VRRenderer.h | 2 +- 11 files changed, 45 insertions(+), 52 deletions(-) diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 80222bbfbf..e5a7b74eb8 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -1589,6 +1589,9 @@ void GLQueueRunner::PerformBindFramebufferAsRenderTarget(const GLRStep &pass) { fbo_bind_fb_target(false, curFB_->handle); } else { fbo_unbind(); + if (IsVRBuild()) { + BindVRFramebuffer(); + } // Backbuffer is now bound. } CHECK_GL_ERROR_IF_DEBUG(); @@ -1741,10 +1744,6 @@ void GLQueueRunner::fbo_unbind() { bindDefaultFBO(); #endif - if (IsVRBuild()) { - BindVRFramebuffer(); - } - currentDrawHandle_ = 0; currentReadHandle_ = 0; CHECK_GL_ERROR_IF_DEBUG(); diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 69d81b5391..161c2942b9 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -3,6 +3,7 @@ #include "Common/GPU/DataFormat.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" #include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/Log.h" #include "Common/TimeUtil.h" @@ -544,7 +545,7 @@ void VulkanQueueRunner::PreprocessSteps(std::vector &steps) { } } -void VulkanQueueRunner::RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared) { +void VulkanQueueRunner::RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared, bool keepSteps) { QueueProfileContext *profile = frameData.profilingEnabled_ ? &frameData.profile : nullptr; if (profile) @@ -622,12 +623,13 @@ void VulkanQueueRunner::RunSteps(std::vector &steps, FrameData &frame // Deleting all in one go should be easier on the instruction cache than deleting // them as we go - and easier to debug because we can look backwards in the frame. - for (auto step : steps) { - delete step; + if (!keepSteps) { + for (auto step : steps) { + delete step; + } + steps.clear(); } - steps.clear(); - if (profile) profile->cpuEndTime = time_now_d(); } @@ -1652,7 +1654,11 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR }; renderPass = GetRenderPass(key); - framebuf = backbuffer_; + if (IsVRBuild()) { + framebuf = (VkFramebuffer)BindVRFramebuffer(); + } else { + framebuf = backbuffer_; + } // Raw, rotated backbuffer size. w = vulkan_->GetBackbufferWidth(); diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 7036029149..63dcd66b23 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -278,7 +278,7 @@ public: } void PreprocessSteps(std::vector &steps); - void RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared); + void RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared, bool keepSteps = false); void LogSteps(const std::vector &steps, bool verbose); std::string StepToString(const VKRStep &step) const; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 3343bd889f..9d48914e94 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -12,6 +12,9 @@ #include "Common/GPU/Vulkan/VulkanRenderManager.h" #include "Common/Thread/ThreadUtil.h" +#include "Common/VR/PPSSPPVR.h" + +#include "Core/Config.h" #if 0 // def _DEBUG #define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__) @@ -1262,7 +1265,19 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { if (task.steps.empty() && !frameData.hasAcquired) frameData.skipSwap = true; //queueRunner_.LogSteps(stepsOnThread, false); - queueRunner_.RunSteps(task.steps, frameData, frameDataShared_); + if (IsVRBuild()) { + int passes = 1; + if (!IsMultiviewSupported() && g_Config.bEnableStereo) { + passes = 2; + } + for (int i = 0; i < passes; i++) { + PreVRFrameRender(i); + queueRunner_.RunSteps(task.steps, frameData, frameDataShared_, i < passes - 1); + PostVRFrameRender(); + } + } else { + queueRunner_.RunSteps(task.steps, frameData, frameDataShared_); + } switch (task.runType) { case VKRRunType::PRESENT: diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index ecebae3a81..41ec1bb76d 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -12,7 +12,6 @@ #include "Common/UI/Root.h" #include "Common/Data/Text/I18n.h" #include "Common/Render/DrawBuffer.h" -#include "Common/VR/PPSSPPVR.h" #include "Common/Log.h" #include "Common/StringUtils.h" @@ -89,10 +88,6 @@ void UIScreen::preRender() { draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); screenManager()->getUIContext()->BeginFrame(); - if (IsVRBuild()) { - BindVRFramebuffer(); - } - Draw::Viewport viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 18b9f00e3c..31c6a20fce 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -290,8 +290,8 @@ VR rendering integration ================================================================================ */ -void BindVRFramebuffer() { - VR_BindFramebuffer(VR_GetEngine()); +void* BindVRFramebuffer() { + return VR_BindFramebuffer(VR_GetEngine()); } bool StartVRRender() { diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 6fbe2f00fb..a7b5d8420d 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -32,7 +32,7 @@ void PreprocessStepVR(void* step); void SetVRCompat(VRCompatFlag flag, long value); // VR rendering integration -void BindVRFramebuffer(); +void* BindVRFramebuffer(); bool StartVRRender(); void FinishVRRender(); void PreVRFrameRender(int fboIndex); @@ -59,7 +59,7 @@ inline void PreprocessStepVR(void* step) {} inline void SetVRCompat(VRCompatFlag flag, long value) {} // VR rendering integration -inline void BindVRFramebuffer() {} +inline void* BindVRFramebuffer() { return nullptr; } inline bool StartVRRender() { return false; } inline void FinishVRRender() {} inline void PreVRFrameRender(int fboIndex) {} diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 1a62417c3e..b8dbe5671b 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -217,29 +217,12 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { ovrFramebuffer_Clear(frameBuffer); } -void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { +void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { - //TODO:bind framebuffer + return frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); - } -} - -void ovrFramebuffer_SetNone(ovrFramebuffer* frameBuffer) { - if (frameBuffer->UseVulkan) { - //TODO:unbind framebuffer - } else { - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); - } -} - -void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer) { - // Discard the depth buffer, so the tiler won't need to write it back out to memory. - if (frameBuffer->UseVulkan) { - //TODO:implement - } else { - const GLenum depthAttachment[1] = {GL_DEPTH_ATTACHMENT}; - glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, depthAttachment); + return nullptr; } } diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index 12eb162980..644a28fe4c 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -7,10 +7,8 @@ void ovrApp_Destroy(ovrApp* app); int ovrApp_HandleXrEvents(ovrApp* app); void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer); -void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer); void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer); -void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer); -void ovrFramebuffer_SetNone(ovrFramebuffer* frameBuffer); +void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer); void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext); void ovrRenderer_Destroy(ovrRenderer* renderer); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 4d41d09bcd..77e80ca9aa 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -372,10 +372,7 @@ void VR_EndFrame( engine_t* engine ) { ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, size); } - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; - //ovrFramebuffer_Resolve(frameBuffer); - ovrFramebuffer_Release(frameBuffer); - ovrFramebuffer_SetNone(frameBuffer); + ovrFramebuffer_Release(&engine->appState.Renderer.FrameBuffer[fboIndex]); } void VR_FinishFrame( engine_t* engine ) { @@ -487,10 +484,10 @@ void VR_SetConfig( VRConfig config, int value) { vrConfig[config] = value; } -void VR_BindFramebuffer(engine_t *engine) { - if (!initialized) return; +void* VR_BindFramebuffer(engine_t *engine) { + if (!initialized) return nullptr; int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; - ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]); + return ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]); } ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) { diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index e19a0e82a5..fe7a4671f1 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -51,5 +51,5 @@ void VR_FinishFrame( engine_t* engine ); int VR_GetConfig( VRConfig config ); void VR_SetConfig( VRConfig config, int value); -void VR_BindFramebuffer(engine_t *engine); +void* VR_BindFramebuffer(engine_t *engine); ovrMatrix4f VR_GetMatrix( VRMatrix matrix ); From d0431e494ad281aac0a3187c95274441bd86a667 Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 12 Oct 2022 19:16:17 +0200 Subject: [PATCH 011/715] OpenXR - Create VR framebuffer for Vulkan --- Common/VR/VRBase.h | 2 ++ Common/VR/VRFramebuffer.cpp | 52 +++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index c05e4739a9..08ae4708f2 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -111,6 +111,8 @@ typedef struct { void* DepthSwapChainImage; unsigned int* GLFrameBuffers; VkFramebuffer* VKFrameBuffers; + VkImageView* VKColorImages; + VkImageView* VKDepthImages; bool Acquired; bool UseVulkan; diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index b8dbe5671b..1e948ea90c 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -187,13 +187,51 @@ bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int &frameBuffer->TextureSwapChainLength, (XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage)); - frameBuffer->VKFrameBuffers = (VkFramebuffer*)malloc(frameBuffer->TextureSwapChainLength * sizeof(VkFramebuffer)); + frameBuffer->VKColorImages = new VkImageView[frameBuffer->TextureSwapChainLength]; + frameBuffer->VKDepthImages = new VkImageView[frameBuffer->TextureSwapChainLength]; + frameBuffer->VKFrameBuffers = new VkFramebuffer[frameBuffer->TextureSwapChainLength]; for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { - VkImage colorTexture = ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].image; - VkImage depthTexture = ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].image; + VkImageViewCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].image; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = swapChainCreateInfo.arraySize; + if (vkCreateImageView(frameBuffer->VKContext->device, &createInfo, nullptr, &frameBuffer->VKColorImages[i]) != VK_SUCCESS) { + ALOGE("failed to create color image view!"); + return false; + } + + createInfo.image = ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].image; + createInfo.format = VK_FORMAT_D24_UNORM_S8_UINT; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (vkCreateImageView(frameBuffer->VKContext->device, &createInfo, nullptr, &frameBuffer->VKDepthImages[i]) != VK_SUCCESS) { + ALOGE("failed to create depth image view!"); + return false; + } // Create the frame buffer. - //TODO:implement framebuffer creation + VkImageView attachments[] = { frameBuffer->VKColorImages[i], frameBuffer->VKDepthImages[i] }; + VkFramebufferCreateInfo framebufferInfo{}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = VK_NULL_HANDLE; + framebufferInfo.attachmentCount = 2; + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = width; + framebufferInfo.height = height; + framebufferInfo.layers = swapChainCreateInfo.arraySize; + if (vkCreateFramebuffer(frameBuffer->VKContext->device, &framebufferInfo, nullptr, &frameBuffer->VKFrameBuffers[i]) != VK_SUCCESS) { + ALOGE("failed to create framebuffer!"); + return false; + } } return true; @@ -202,9 +240,13 @@ bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { for (int i = 0; i < frameBuffer->TextureSwapChainLength; i++) { + vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKColorImages[i], nullptr); + vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKDepthImages[i], nullptr); vkDestroyFramebuffer(frameBuffer->VKContext->device, frameBuffer->VKFrameBuffers[i], nullptr); } - free(frameBuffer->VKFrameBuffers); + delete[] frameBuffer->VKColorImages; + delete[] frameBuffer->VKDepthImages; + delete[] frameBuffer->VKFrameBuffers; } else { GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); free(frameBuffer->GLFrameBuffers); From de416503184a2e1b28f4eb9818dc5c97133373e9 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 14 Oct 2022 16:47:54 +0200 Subject: [PATCH 012/715] OpenXR - Disable VUlkan for now --- Common/GPU/Vulkan/VulkanLoader.cpp | 6 ++++++ Common/VR/VRFramebuffer.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index 2ead5cb95d..b0c2ab370b 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -23,6 +23,7 @@ #include "Common/GPU/Vulkan/VulkanLoader.h" #include "Common/Log.h" #include "Common/System/System.h" +#include "Common/VR/PPSSPPVR.h" #if !PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(SWITCH) #include @@ -308,6 +309,11 @@ void VulkanSetAvailable(bool available) { bool VulkanMayBeAvailable() { + //unsupported in VR at the moment + if (IsVRBuild()) { + return false; + } + if (g_vulkanAvailabilityChecked) { return g_vulkanMayBeAvailable; } diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 1e948ea90c..742e9457c6 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -222,7 +222,7 @@ bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int VkImageView attachments[] = { frameBuffer->VKColorImages[i], frameBuffer->VKDepthImages[i] }; VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = VK_NULL_HANDLE; + framebufferInfo.renderPass = VK_NULL_HANDLE; //TODO:This is probably wrong framebufferInfo.attachmentCount = 2; framebufferInfo.pAttachments = attachments; framebufferInfo.width = width; From 4a967966ef6f09b4d1e9fb3c74c06d919d7f08fd Mon Sep 17 00:00:00 2001 From: Nemoumbra Date: Sat, 15 Oct 2022 16:01:12 +0300 Subject: [PATCH 013/715] Removed the bugged part of hle.func.scan + new comments --- Core/Debugger/WebSocket/HLESubscriber.cpp | 41 +++++++++++++---------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/Core/Debugger/WebSocket/HLESubscriber.cpp b/Core/Debugger/WebSocket/HLESubscriber.cpp index 8c8bfe50dd..09b67624d1 100644 --- a/Core/Debugger/WebSocket/HLESubscriber.cpp +++ b/Core/Debugger/WebSocket/HLESubscriber.cpp @@ -362,9 +362,10 @@ void WebSocketHLEFuncRemove(DebuggerRequest &req) { json.writeUint("size", funcSize); } +// This function removes function symbols that intersect or lie inside the range +// (Note: this makes no checks whether the range is valid) +// Returns the number of removed functions static u32 RemoveFuncSymbolsInRange(u32 addr, u32 size) { - // Note: this makes no checks whether the range is valid - u32 func_address = g_symbolMap->GetFunctionStart(addr); if (func_address == SymbolMap::INVALID_ADDRESS) { func_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION); @@ -476,7 +477,7 @@ void WebSocketHLEFuncRename(DebuggerRequest &req) { // Parameters: // - address: unsigned integer address for the start of the range. // - size: unsigned integer size in bytes for scan. -// - recreate: optional bool indicating whether functions that lie inside the range must be removed before scanning +// - recreate: optional bool indicating whether functions that intersect or inside lie inside the range must be removed before scanning // // Response (same event name) with no extra data. void WebSocketHLEFuncScan(DebuggerRequest &req) { @@ -504,23 +505,27 @@ void WebSocketHLEFuncScan(DebuggerRequest &req) { return req.Fail("Address or size outside valid memory"); if (recreate) { - // let's see if the last function is partially inside our range + // The following code doesn't do what I wanted it to do AND it's debatable whether it's needed at all + // In short, I wanted to shift the start and the end of the range before removal - u32 last_func_start = g_symbolMap->GetFunctionStart(addr + size - 1); - if (last_func_start != SymbolMap::INVALID_ADDRESS) { - // there is a function - // u32 end = last_func_start + g_symbolMap->GetFunctionSize(last_func_start); - if (last_func_start + g_symbolMap->GetFunctionSize(last_func_start) != addr + size) { - size = last_func_start - addr; // decrease the size parameter - } - } - // let's see if the first function is partially inside our range - u32 start = g_symbolMap->GetFunctionStart(addr); + //// let's see if the last function is partially inside our range + + //u32 last_func_start = g_symbolMap->GetFunctionStart(addr + size - 1); + //if (last_func_start != SymbolMap::INVALID_ADDRESS) { + // // there is a function + // // u32 end = last_func_start + g_symbolMap->GetFunctionSize(last_func_start); + // if (last_func_start + g_symbolMap->GetFunctionSize(last_func_start) != addr + size) { + // size = last_func_start - addr; // decrease the size parameter + // } + //} + //// let's see if the first function is partially inside our range + //u32 start = g_symbolMap->GetFunctionStart(addr); + + //if (start != SymbolMap::INVALID_ADDRESS && start != addr) { + // // skip to a byte after end + // addr = start + g_symbolMap->GetFunctionSize(start); + //} - if (start != SymbolMap::INVALID_ADDRESS && start != addr) { - // skip to a byte after end - addr = start + g_symbolMap->GetFunctionSize(start); - } RemoveFuncSymbolsInRange(addr, size); } From c4bf2cb5c0fa00c61c88f2c1036ce779dd7f161f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 15 Oct 2022 18:27:52 -0700 Subject: [PATCH 014/715] jit: Ignore zero byte icache invalidates. These were getting marked pending and were clearing all cache, causing performance concerns in for example LittleBigPlanet. --- Core/HLE/ReplaceTables.cpp | 7 ++++--- Core/HLE/sceDmac.cpp | 2 +- Core/HLE/sceKernel.cpp | 3 ++- Core/HLE/sceKernelInterrupt.cpp | 3 ++- Core/MIPS/MIPS.cpp | 17 +++++++++-------- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 5e8c093671..85817a49e3 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -233,8 +233,9 @@ static int Replace_memcpy16() { bool skip = false; // Some games use memcpy on executable code. We need to flush emuhack ops. - currentMIPS->InvalidateICache(srcPtr, bytes); - if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMCPY) == 0) { + if (bytes != 0) + currentMIPS->InvalidateICache(srcPtr, bytes); + if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMCPY) == 0 && bytes != 0) { if (Memory::IsVRAMAddress(destPtr) || Memory::IsVRAMAddress(srcPtr)) { skip = gpu->PerformMemoryCopy(destPtr, srcPtr, bytes); } @@ -305,7 +306,7 @@ static int Replace_memmove() { bool skip = false; // Some games use memcpy on executable code. We need to flush emuhack ops. - if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMMOVE) == 0) { + if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMMOVE) == 0 && bytes != 0) { currentMIPS->InvalidateICache(srcPtr, bytes); if (Memory::IsVRAMAddress(destPtr) || Memory::IsVRAMAddress(srcPtr)) { skip = gpu->PerformMemoryCopy(destPtr, srcPtr, bytes); diff --git a/Core/HLE/sceDmac.cpp b/Core/HLE/sceDmac.cpp index 5fba8f9b94..3735eb2a84 100644 --- a/Core/HLE/sceDmac.cpp +++ b/Core/HLE/sceDmac.cpp @@ -49,7 +49,7 @@ static int __DmacMemcpy(u32 dst, u32 src, u32 size) { if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) { skip = gpu->PerformMemoryCopy(dst, src, size); } - if (!skip) { + if (!skip && size != 0) { currentMIPS->InvalidateICache(src, size); if (MemBlockInfoDetailed(size)) { const std::string tag = GetMemWriteTagAt("DmacMemcpy/", src, size); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index b9d1028b48..6f18a5768e 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -392,7 +392,8 @@ int sceKernelDcacheInvalidateRange(u32 addr, int size) int sceKernelIcacheInvalidateRange(u32 addr, int size) { DEBUG_LOG(CPU, "sceKernelIcacheInvalidateRange(%08x, %i)", addr, size); - currentMIPS->InvalidateICache(addr, size); + if (size != 0) + currentMIPS->InvalidateICache(addr, size); return 0; } diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 4c91ffe529..3dadc4dc77 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -624,7 +624,8 @@ static u32 sceKernelMemcpy(u32 dst, u32 src, u32 size) DEBUG_LOG(SCEKERNEL, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); // Some games copy from executable code. We need to flush emuhack ops. - currentMIPS->InvalidateICache(src, size); + if (size != 0) + currentMIPS->InvalidateICache(src, size); bool skip = false; if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) { diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 5aeeacbbf8..9a472b08c5 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -366,14 +366,15 @@ void MIPSState::ProcessPendingClears() { void MIPSState::InvalidateICache(u32 address, int length) { // Only really applies to jit. std::lock_guard guard(MIPSComp::jitLock); - if (MIPSComp::jit) { - if (coreState == CORE_RUNNING || insideJit) { - pendingClears.emplace_back(address, length); - hasPendingClears = true; - CoreTiming::ForceCheck(); - } else { - MIPSComp::jit->InvalidateCacheAt(address, length); - } + if (!MIPSComp::jit || length == 0) + return; + + if (coreState == CORE_RUNNING || insideJit) { + pendingClears.emplace_back(address, length); + hasPendingClears = true; + CoreTiming::ForceCheck(); + } else { + MIPSComp::jit->InvalidateCacheAt(address, length); } } From fa5f9d5e74b54e1abbfa1a4e2eacc527f5638e46 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 15 Oct 2022 18:30:13 -0700 Subject: [PATCH 015/715] jit: Consistently check range on invalidate. We did this on x86, we should do it everywhere or nowhere. --- Core/MIPS/ARM/ArmJit.cpp | 7 ++++--- Core/MIPS/ARM64/Arm64Jit.cpp | 4 +++- Core/MIPS/MIPS/MipsJit.cpp | 7 ++++--- Core/MIPS/fake/FakeJit.cpp | 7 ++++--- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 0f138c6092..74675a6ae4 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -182,9 +182,10 @@ void ArmJit::ClearCache() GenerateFixedCode(); } -void ArmJit::InvalidateCacheAt(u32 em_address, int length) -{ - blocks.InvalidateICache(em_address, length); +void ArmJit::InvalidateCacheAt(u32 em_address, int length) { + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void ArmJit::EatInstruction(MIPSOpcode op) { diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 8fb4c512d8..b111784c1a 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -180,7 +180,9 @@ void Arm64Jit::ClearCache() { } void Arm64Jit::InvalidateCacheAt(u32 em_address, int length) { - blocks.InvalidateICache(em_address, length); + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void Arm64Jit::EatInstruction(MIPSOpcode op) { diff --git a/Core/MIPS/MIPS/MipsJit.cpp b/Core/MIPS/MIPS/MipsJit.cpp index 2a096759c4..2b263773c8 100644 --- a/Core/MIPS/MIPS/MipsJit.cpp +++ b/Core/MIPS/MIPS/MipsJit.cpp @@ -97,9 +97,10 @@ void MipsJit::ClearCache() //GenerateFixedCode(); } -void MipsJit::InvalidateCacheAt(u32 em_address, int length) -{ - blocks.InvalidateICache(em_address, length); +void MipsJit::InvalidateCacheAt(u32 em_address, int length) { + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void MipsJit::EatInstruction(MIPSOpcode op) { diff --git a/Core/MIPS/fake/FakeJit.cpp b/Core/MIPS/fake/FakeJit.cpp index 8150e26118..d8fb86d07d 100644 --- a/Core/MIPS/fake/FakeJit.cpp +++ b/Core/MIPS/fake/FakeJit.cpp @@ -98,9 +98,10 @@ void FakeJit::ClearCache() //GenerateFixedCode(); } -void FakeJit::InvalidateCacheAt(u32 em_address, int length) -{ - blocks.InvalidateICache(em_address, length); +void FakeJit::InvalidateCacheAt(u32 em_address, int length) { + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void FakeJit::EatInstruction(MIPSOpcode op) { From 0226d950006c86c2b925d44fd22584cb72ca0999 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 15 Oct 2022 18:44:21 -0700 Subject: [PATCH 016/715] jit: Run invalidates immediately. Previously, I thought we might clear native code when invalidating - we don't. We only do that when clearing. --- Core/MIPS/MIPS.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 5aeeacbbf8..6700e5bfb3 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -365,15 +365,10 @@ void MIPSState::ProcessPendingClears() { void MIPSState::InvalidateICache(u32 address, int length) { // Only really applies to jit. + // Note that the backend is responsible for ensuring native code can still be returned to. std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) { - if (coreState == CORE_RUNNING || insideJit) { - pendingClears.emplace_back(address, length); - hasPendingClears = true; - CoreTiming::ForceCheck(); - } else { - MIPSComp::jit->InvalidateCacheAt(address, length); - } + MIPSComp::jit->InvalidateCacheAt(address, length); } } From 8fa24045b1501e310fada3f0468f976cd66004ef Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 15 Oct 2022 20:55:26 -0700 Subject: [PATCH 017/715] Io: Fail open earlier from ms0: w/ no access flags. The PSP returns this error code if you use 0 for the open flags on ms0:/. --- Core/FileSystems/DirectoryFileSystem.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index af8ea370a4..b2ae2fabb7 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -115,6 +115,11 @@ Path DirectoryFileSystem::GetLocalPath(std::string internalPath) const { bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, FileAccess access, u32 &error) { error = 0; + if (access == FILEACCESS_NONE) { + error = SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; + return false; + } + #if HOST_IS_CASE_SENSITIVE if (access & (FILEACCESS_APPEND | FILEACCESS_CREATE | FILEACCESS_WRITE)) { DEBUG_LOG(FILESYS, "Checking case for path %s", fileName.c_str()); From 1b5e5e2556e41e82a4c20b8d47cbaa937041e66c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 15 Oct 2022 21:23:49 -0700 Subject: [PATCH 018/715] Windows: Improve reporting of WASAPI errors. --- Windows/WASAPIStream.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp index a80155cb0d..3481e42d69 100644 --- a/Windows/WASAPIStream.cpp +++ b/Windows/WASAPIStream.cpp @@ -366,13 +366,16 @@ bool WASAPIAudioThread::DetectFormat() { CoTaskMemFree(deviceFormat_); deviceFormat_ = closest; } else { - ERROR_LOG_REPORT_ONCE(badfallbackclosest, SCEAUDIO, "WASAPI fallback and closest unsupported"); + wchar_t guid[256]{}; + StringFromGUID2(closest->SubFormat, guid, 256); + ERROR_LOG_REPORT_ONCE(badfallbackclosest, SCEAUDIO, "WASAPI fallback and closest unsupported (fmt=%04x/%s)", closest->Format.wFormatTag, guid); CoTaskMemFree(closest); return false; } } else { CoTaskMemFree(closest); - ERROR_LOG_REPORT_ONCE(badfallback, SCEAUDIO, "WASAPI fallback format was unsupported"); + if (hr != AUDCLNT_E_DEVICE_INVALIDATED && hr != AUDCLNT_E_SERVICE_NOT_RUNNING) + ERROR_LOG_REPORT_ONCE(badfallback, SCEAUDIO, "WASAPI fallback format was unsupported (%08x)", hr); return false; } } @@ -390,7 +393,9 @@ bool WASAPIAudioThread::ValidateFormat(const WAVEFORMATEXTENSIBLE *fmt) { if (fmt->Format.nChannels >= 1) format_ = Format::IEEE_FLOAT; } else { - ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format, expected float!"); + wchar_t guid[256]{}; + StringFromGUID2(fmt->SubFormat, guid, 256); + ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format (%S), expected float!", guid); if (fmt->Format.wBitsPerSample == 16 && fmt->Format.nChannels == 2) { format_ = Format::PCM16; } From 770fdbeece3a38976685fd257eebca9e4c10012d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 15 Oct 2022 21:38:08 -0700 Subject: [PATCH 019/715] Kernel: Add reason to reported stop error. --- Core/HLE/sceKernelThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index f717cd5a3e..e3fcf2e442 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1644,7 +1644,7 @@ void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason) t->nt.waitType = WAITTYPE_NONE; t->nt.waitID = 0; } else { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelStopThread: thread %d does not exist", threadID); + ERROR_LOG_REPORT(SCEKERNEL, "__KernelStopThread: thread %d does not exist (%s)", threadID, reason ? reason : "?"); } } From 0d86eafe2fe15899b13536c42d335e2c4408b02d Mon Sep 17 00:00:00 2001 From: sum2012 Date: Sun, 16 Oct 2022 13:13:40 +0800 Subject: [PATCH 020/715] Add draft mp4msv module Meruru no Atelier Plus - Arland no Renkinjutsushi 3 - Official PlayView use it --- Core/HLE/sceMp4.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceMp4.cpp b/Core/HLE/sceMp4.cpp index 3dac7acacd..f09bc06357 100644 --- a/Core/HLE/sceMp4.cpp +++ b/Core/HLE/sceMp4.cpp @@ -395,6 +395,16 @@ static u32 sceAacResetPlayPosition(u32 id) return ctx->AuResetPlayPosition(); } +static u32 mp4msv_3C2183C7(u32 unknown1, u32 unknown2) { + ERROR_LOG(ME, "UNIMPL mp4msv_3C2183C7(%d, %x)", unknown1, unknown2); + return 0; +} + +static u32 mp4msv_9CA13D1A(u32 unknown1, u32 unknown2) { + ERROR_LOG(ME, "UNIMPL mp4msv_9CA13D1A(%d, %x)", unknown1, unknown2); + return 0; +} + const HLEFunction sceMp4[] = { {0X68651CBC, &WrapU_V, "sceMp4Init", 'x', "" }, @@ -455,8 +465,15 @@ const HLEFunction sceAac[] = { {0XD2DA2BBA, &WrapU_U, "sceAacResetPlayPosition", 'x', "x" }, }; +const HLEFunction mp4msv[] = { + {0x3C2183C7, &WrapU_UU, "mp4msv_3C2183C7", 'x', "xx" }, + {0x9CA13D1A, &WrapU_UU, "mp4msv_9CA13D1A", 'x', "xx" }, + +}; + void Register_sceMp4() { RegisterModule("sceMp4", ARRAY_SIZE(sceMp4), sceMp4); RegisterModule("sceAac", ARRAY_SIZE(sceAac), sceAac); -} + RegisterModule("mp4msv", ARRAY_SIZE(mp4msv), mp4msv); +} \ No newline at end of file From 620c515704ffcbf51a175b992cea7f9a44c8c97e Mon Sep 17 00:00:00 2001 From: sum2012 Date: Sun, 16 Oct 2022 13:51:08 +0800 Subject: [PATCH 021/715] know unknown in sceMp4Create It is callbacks --- Core/HLE/sceMp4.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceMp4.cpp b/Core/HLE/sceMp4.cpp index f09bc06357..03ae4214d9 100644 --- a/Core/HLE/sceMp4.cpp +++ b/Core/HLE/sceMp4.cpp @@ -60,9 +60,9 @@ static u32 sceMp4Finish() return 0; } -static u32 sceMp4Create(u32 mp4, u32 unknown2, u32 readBufferAddr, u32 readBufferSize) +static u32 sceMp4Create(u32 mp4, u32 callbacks, u32 readBufferAddr, u32 readBufferSize) { - ERROR_LOG_REPORT(ME, "UNIMPL sceMp4Create(mp4 %i,unknown2 %08x,readBufferAddr %08x,readBufferSize %i)", mp4, unknown2, readBufferAddr, readBufferSize); + ERROR_LOG_REPORT(ME, "UNIMPL sceMp4Create(mp4 %i,unknown2 %08x,readBufferAddr %08x,readBufferSize %i)", mp4, callbacks, readBufferAddr, readBufferSize); return 0; } From 266872bf152d0ab71baa78d082cd87d2df7f58f2 Mon Sep 17 00:00:00 2001 From: sum2012 Date: Sun, 16 Oct 2022 14:09:52 +0800 Subject: [PATCH 022/715] OOP --- Core/HLE/sceMp4.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceMp4.cpp b/Core/HLE/sceMp4.cpp index 03ae4214d9..f039f82c66 100644 --- a/Core/HLE/sceMp4.cpp +++ b/Core/HLE/sceMp4.cpp @@ -62,7 +62,7 @@ static u32 sceMp4Finish() static u32 sceMp4Create(u32 mp4, u32 callbacks, u32 readBufferAddr, u32 readBufferSize) { - ERROR_LOG_REPORT(ME, "UNIMPL sceMp4Create(mp4 %i,unknown2 %08x,readBufferAddr %08x,readBufferSize %i)", mp4, callbacks, readBufferAddr, readBufferSize); + ERROR_LOG_REPORT(ME, "UNIMPL sceMp4Create(mp4 %i,callbacks %08x,readBufferAddr %08x,readBufferSize %i)", mp4, callbacks, readBufferAddr, readBufferSize); return 0; } From 4764c54803fb376425f2afd1bca7ce8e1d400276 Mon Sep 17 00:00:00 2001 From: sum2012 Date: Sun, 16 Oct 2022 15:23:33 +0800 Subject: [PATCH 023/715] Fix save states --- Core/HLE/HLETables.cpp | 1 + Core/HLE/sceMp4.cpp | 8 ++++++-- Core/HLE/sceMp4.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index cb775c7ebf..016a19e5c1 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -305,6 +305,7 @@ void RegisterAllModules() { Register_sceOpenPSID_driver(); Register_semaphore(); Register_sceDdrdb(); + Register_mp4msv(); // add new modules here. } diff --git a/Core/HLE/sceMp4.cpp b/Core/HLE/sceMp4.cpp index f039f82c66..38c288e950 100644 --- a/Core/HLE/sceMp4.cpp +++ b/Core/HLE/sceMp4.cpp @@ -474,6 +474,10 @@ const HLEFunction mp4msv[] = { void Register_sceMp4() { RegisterModule("sceMp4", ARRAY_SIZE(sceMp4), sceMp4); - RegisterModule("sceAac", ARRAY_SIZE(sceAac), sceAac); + RegisterModule("sceAac", ARRAY_SIZE(sceAac), sceAac); +} + +void Register_mp4msv() +{ RegisterModule("mp4msv", ARRAY_SIZE(mp4msv), mp4msv); -} \ No newline at end of file +} diff --git a/Core/HLE/sceMp4.h b/Core/HLE/sceMp4.h index b6870b90e2..9df50ed96f 100644 --- a/Core/HLE/sceMp4.h +++ b/Core/HLE/sceMp4.h @@ -25,3 +25,4 @@ enum { void Register_sceMp4(); void __AACShutdown(); void __AACDoState(PointerWrap &p); +void Register_mp4msv(); From 73e5791b08723780fa38991a53027152b4871453 Mon Sep 17 00:00:00 2001 From: Nemoumbra Date: Sun, 16 Oct 2022 14:43:56 +0300 Subject: [PATCH 024/715] Code cleanup, optional param renamed: "recreate" -> "remove" --- Core/Debugger/WebSocket/HLESubscriber.cpp | 35 ++++------------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/Core/Debugger/WebSocket/HLESubscriber.cpp b/Core/Debugger/WebSocket/HLESubscriber.cpp index 09b67624d1..0efe01b222 100644 --- a/Core/Debugger/WebSocket/HLESubscriber.cpp +++ b/Core/Debugger/WebSocket/HLESubscriber.cpp @@ -477,7 +477,7 @@ void WebSocketHLEFuncRename(DebuggerRequest &req) { // Parameters: // - address: unsigned integer address for the start of the range. // - size: unsigned integer size in bytes for scan. -// - recreate: optional bool indicating whether functions that intersect or inside lie inside the range must be removed before scanning +// - remove: optional bool indicating whether functions that intersect or inside lie inside the range must be removed before scanning // // Response (same event name) with no extra data. void WebSocketHLEFuncScan(DebuggerRequest &req) { @@ -493,39 +493,14 @@ void WebSocketHLEFuncScan(DebuggerRequest &req) { if (!req.ParamU32("size", &size)) return; - bool has_recreate = req.HasParam("recreate"); - bool recreate = false; - if (has_recreate) { - if (!req.ParamBool("recreate", &recreate)) { - return; - } - } + bool remove = false; + if (!req.ParamBool("remove", &remove, DebuggerParamType::OPTIONAL)) + return; if (!Memory::IsValidRange(addr, size)) return req.Fail("Address or size outside valid memory"); - if (recreate) { - // The following code doesn't do what I wanted it to do AND it's debatable whether it's needed at all - // In short, I wanted to shift the start and the end of the range before removal - - //// let's see if the last function is partially inside our range - - //u32 last_func_start = g_symbolMap->GetFunctionStart(addr + size - 1); - //if (last_func_start != SymbolMap::INVALID_ADDRESS) { - // // there is a function - // // u32 end = last_func_start + g_symbolMap->GetFunctionSize(last_func_start); - // if (last_func_start + g_symbolMap->GetFunctionSize(last_func_start) != addr + size) { - // size = last_func_start - addr; // decrease the size parameter - // } - //} - //// let's see if the first function is partially inside our range - //u32 start = g_symbolMap->GetFunctionStart(addr); - - //if (start != SymbolMap::INVALID_ADDRESS && start != addr) { - // // skip to a byte after end - // addr = start + g_symbolMap->GetFunctionSize(start); - //} - + if (remove) { RemoveFuncSymbolsInRange(addr, size); } From a000c32820c603b255e96d33dcf1aa69eaf31354 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 08:40:01 -0700 Subject: [PATCH 025/715] Kernel: Stop reporting invalid mutex names. We know this behavior is correct, let's just make it logging. --- Core/HLE/sceKernel.cpp | 2 +- Core/HLE/sceKernelMutex.cpp | 31 ++++++++++--------------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 6f18a5768e..ec737dd1ad 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -735,7 +735,7 @@ const HLEFunction ThreadManForUser[] = {0XB011B11F, &WrapI_IIU, "sceKernelLockMutex", 'i', "iix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, {0X5BF4DD27, &WrapI_IIU, "sceKernelLockMutexCB", 'i', "iix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, {0X6B30100F, &WrapI_II, "sceKernelUnlockMutex", 'i', "ii" }, - {0XB7D098C6, &WrapI_CUIU, "sceKernelCreateMutex", 'i', "sxix" }, + {0XB7D098C6, &WrapI_CUIU, "sceKernelCreateMutex", 'i', "sxip" }, {0X0DDCD2C9, &WrapI_II, "sceKernelTryLockMutex", 'i', "ii" }, {0XA9C2CB9A, &WrapI_IU, "sceKernelReferMutexStatus", 'i', "ip" }, {0X87D9223C, &WrapI_IIU, "sceKernelCancelMutex", 'i', "iix" }, diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 6921ffdf26..1885552ce1 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -305,23 +305,16 @@ void __KernelMutexEndCallback(SceUID threadID, SceUID prevCallbackId) DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB: Resuming lock wait for callback"); } -int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) -{ +int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!name) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateMutex(): invalid name", SCE_KERNEL_ERROR_ERROR); - return SCE_KERNEL_ERROR_ERROR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (attr & ~0xBFF) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); - return SCE_KERNEL_ERROR_ILLEGAL_ATTR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); if (initialCount < 0) - return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal initial count"); if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) - return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal non-recursive count"); PSPMutex *mutex = new PSPMutex(); SceUID id = kernelObjects.Create(mutex); @@ -331,18 +324,14 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; mutex->nm.attr = attr; mutex->nm.initialCount = initialCount; - if (initialCount == 0) - { + if (initialCount == 0) { mutex->nm.lockLevel = 0; mutex->nm.lockThread = -1; - } - else + } else { __KernelMutexAcquireLock(mutex, initialCount); + } - DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateMutex(%s, %08x, %d, %08x)", id, name, attr, initialCount, optionsPtr); - - if (optionsPtr != 0) - { + if (optionsPtr != 0) { u32 size = Memory::Read_U32(optionsPtr); if (size > 4) WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMutex(%s) unsupported options parameter, size = %d", name, size); @@ -350,7 +339,7 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0) WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr); - return id; + return hleLogSuccessX(SCEKERNEL, id); } int sceKernelDeleteMutex(SceUID id) From 91bfa3ee4909d11a92ede9f7df702574c4890064 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 08:48:15 -0700 Subject: [PATCH 026/715] Kernel: Stop reporting invalid semaphore names. --- Core/HLE/sceKernel.cpp | 4 ++-- Core/HLE/sceKernelSemaphore.cpp | 28 ++++++++++------------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index ec737dd1ad..a7f5b7cb82 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -713,7 +713,7 @@ const HLEFunction ThreadManForUser[] = {0XA66B0120, &WrapU_IU, "sceKernelReferEventFlagStatus", 'x', "ix" }, {0X8FFDF9A2, &WrapI_IIU, "sceKernelCancelSema", 'i', "iix" }, - {0XD6DA4BA1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiix" }, + {0XD6DA4BA1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiip" }, {0X28B6489C, &WrapI_I, "sceKernelDeleteSema", 'i', "i" }, {0X58B1F937, &WrapI_II, "sceKernelPollSema", 'i', "ii" }, {0XBC6FEBC5, &WrapI_IU, "sceKernelReferSemaStatus", 'i', "ip" }, @@ -899,7 +899,7 @@ const HLEFunction ThreadManForKernel[] = {0X75156E8F, &WrapI_I, "sceKernelResumeThread", 'i', "i", HLE_KERNEL_SYSCALL }, {0X94416130, &WrapU_UUUU, "sceKernelGetThreadmanIdList", 'x', "xxxx", HLE_KERNEL_SYSCALL }, {0x278c0df5, &WrapI_IU, "sceKernelWaitThreadEnd", 'i', "ix", HLE_KERNEL_SYSCALL }, - {0xd6da4ba1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiix", HLE_KERNEL_SYSCALL }, + {0xd6da4ba1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiip", HLE_KERNEL_SYSCALL }, {0x28b6489c, &WrapI_I, "sceKernelDeleteSema", 'i', "i", HLE_KERNEL_SYSCALL }, {0x3f53e640, &WrapI_II, "sceKernelSignalSema", 'i', "ii", HLE_KERNEL_SYSCALL }, {0x4e3a1105, &WrapI_IIU, "sceKernelWaitSema", 'i', "iix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED | HLE_KERNEL_SYSCALL}, diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index fffb16c20f..b6a759cb76 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -203,18 +203,11 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) } } -int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) -{ +int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) { if (!name) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateSema(): invalid name", SCE_KERNEL_ERROR_ERROR); - return SCE_KERNEL_ERROR_ERROR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (attr >= 0x200) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateSema(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); - return SCE_KERNEL_ERROR_ILLEGAL_ATTR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); PSPSemaphore *s = new PSPSemaphore(); SceUID id = kernelObjects.Create(s); @@ -228,18 +221,17 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 s->ns.maxCount = maxVal; s->ns.numWaitThreads = 0; - DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr); - - if (optionPtr != 0) - { - u32 size = Memory::Read_U32(optionPtr); - if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateSema(%s) unsupported options parameter, size = %d", name, size); + // Many games pass garbage into optionPtr, it doesn't have any options. + if (optionPtr != 0) { + if (!Memory::IsValidRange(optionPtr, 4)) + hleLogWarning(SCEKERNEL, id, "invalid options parameter"); + else if (Memory::Read_U32(optionPtr) > 4) + hleLogDebug(SCEKERNEL, id, "invalid options parameter size"); } if ((attr & ~PSP_SEMA_ATTR_PRIORITY) != 0) WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateSema(%s) unsupported attr parameter: %08x", name, attr); - return id; + return hleLogSuccessX(SCEKERNEL, id); } int sceKernelDeleteSema(SceUID id) From 29e7a53b5d5e66e594fc275372bd5674164909b8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 08:14:48 -0700 Subject: [PATCH 027/715] Savedata: Update filelist on file erasure. Also stop reporting as "not coded." --- Core/Dialog/PSPSaveDialog.cpp | 4 ++++ Core/Dialog/SavedataParam.cpp | 43 +++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 91994d3f36..ea600d5669 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -70,6 +70,8 @@ static bool IsNotVisibleAction(SceUtilitySavedataType type) { case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA: case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_READDATA: + case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE: + case SCE_UTILITY_SAVEDATA_TYPE_ERASE: case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: return true; @@ -222,6 +224,8 @@ int PSPSaveDialog::Init(int paramAddr) case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA: case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_READDATA: + case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE: + case SCE_UTILITY_SAVEDATA_TYPE_ERASE: case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: display = DS_NONE; break; diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 53d6d819a3..3c6c545baa 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include +#include #include "Common/Log.h" #include "Common/Data/Text/I18n.h" #include "Common/Data/Format/ZIMLoad.h" @@ -36,14 +38,15 @@ #include "Core/HW/MemoryStick.h" #include "Core/Util/PPGeDraw.h" -#include - static const std::string ICON0_FILENAME = "ICON0.PNG"; static const std::string ICON1_FILENAME = "ICON1.PMF"; static const std::string PIC1_FILENAME = "PIC1.PNG"; static const std::string SND0_FILENAME = "SND0.AT3"; static const std::string SFO_FILENAME = "PARAM.SFO"; +static const int FILE_LIST_COUNT_MAX = 99; +static const u32 FILE_LIST_TOTAL_SIZE = sizeof(SaveSFOFileListEntry) * FILE_LIST_COUNT_MAX; + static const std::string savePath = "ms0:/PSP/SAVEDATA/"; namespace @@ -382,6 +385,39 @@ int SavedataParam::DeleteData(SceUtilitySavedataParam* param) { ClearCaches(); pspFileSystem.RemoveFile(filePath); + // Update PARAM.SFO to remove the file, if it was in the list. + std::shared_ptr sfoFile = LoadCachedSFO(sfoPath); + if (sfoFile) { + // Note: do not update values such as TITLE in this operation. + u32 fileListSize = 0; + SaveSFOFileListEntry *fileList = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &fileListSize); + size_t fileListCount = fileListSize / sizeof(SaveSFOFileListEntry); + bool changed = false; + for (size_t i = 0; i < fileListCount; ++i) { + if (strncmp(fileList[i].filename, fileName.c_str(), sizeof(fileList[i].filename)) != 0) + continue; + + memset(fileList[i].filename, 0, sizeof(fileList[i].filename)); + memset(fileList[i].hash, 0, sizeof(fileList[i].hash)); + changed = true; + break; + } + + if (changed) { + std::unique_ptr updatedList(new u8[fileListSize]); + memcpy(updatedList.get(), fileList, fileListSize); + sfoFile->SetValue("SAVEDATA_FILE_LIST", updatedList.get(), fileListSize, (int)FILE_LIST_TOTAL_SIZE); + + u8 *sfoData; + size_t sfoSize; + sfoFile->WriteSFO(&sfoData, &sfoSize); + + ClearCaches(); + WritePSPFile(sfoPath, sfoData, (SceSize)sfoSize); + delete[] sfoData; + } + } + return 0; } @@ -470,8 +506,6 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD // Always write and update the file list. // For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding - const int FILE_LIST_COUNT_MAX = 99; - const u32 FILE_LIST_TOTAL_SIZE = sizeof(SaveSFOFileListEntry) * FILE_LIST_COUNT_MAX; u32 tmpDataSize = 0; SaveSFOFileListEntry *tmpDataOrig = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize); SaveSFOFileListEntry *updatedList = new SaveSFOFileListEntry[FILE_LIST_COUNT_MAX]; @@ -825,7 +859,6 @@ std::vector SavedataParam::GetSFOEntries(const std::string return result; } - const int FILE_LIST_COUNT_MAX = 99; u32 sfoFileListSize = 0; SaveSFOFileListEntry *sfoFileList = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &sfoFileListSize); const u32 count = std::min((u32)FILE_LIST_COUNT_MAX, sfoFileListSize / (u32)sizeof(SaveSFOFileListEntry)); From e90a7de3e4b09e0a74560a988949f16eeeb34ea8 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 16 Oct 2022 20:28:45 +0200 Subject: [PATCH 028/715] OpenXR - Add VR mode for stereo flat screen rendering --- Common/VR/PPSSPPVR.cpp | 5 ++-- Common/VR/VRBase.h | 2 +- Common/VR/VRRenderer.cpp | 53 ++++++++++++++++++++++++++-------------- Common/VR/VRRenderer.h | 7 +++--- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 31c6a20fce..7bbda32cde 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -307,7 +307,7 @@ bool StartVRRender() { bool stereo = VR_GetConfig(VR_CONFIG_6DOF_PRECISE) && g_Config.bEnableStereo; VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); } else { - VR_SetConfig(VR_CONFIG_MODE, VR_MODE_FLAT_SCREEN); + VR_SetConfig(VR_CONFIG_MODE, g_Config.bEnableStereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); } VR_SetConfig(VR_CONFIG_3D_GEOMETRY_COUNT, VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) / 2); @@ -345,7 +345,8 @@ bool IsMultiviewSupported() { } bool IsFlatVRScene() { - return VR_GetConfig(VR_CONFIG_MODE) == VR_MODE_FLAT_SCREEN; + int vrMode = VR_GetConfig(VR_CONFIG_MODE); + return (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN); } bool Is2DVRObject(float* projMatrix, bool ortho) { diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 08ae4708f2..5f9016d7cd 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -86,7 +86,7 @@ static void OXR_CheckErrors(XrInstance instance, XrResult result, const char* fu #define OPENXR_HAS_PERFORMANCE_EXTENSION #endif -enum { ovrMaxLayerCount = 1 }; +enum { ovrMaxLayerCount = 2 }; enum { ovrMaxNumEyes = 2 }; typedef union { diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 77e80ca9aa..64c388df07 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -366,7 +366,9 @@ void VR_EndFrame( engine_t* engine ) { // Show mouse cursor int size = vrConfig[VR_CONFIG_MOUSE_SIZE]; - if ((vrConfig[VR_CONFIG_MODE] == VR_MODE_FLAT_SCREEN) && (size > 0)) { + int vrMode = vrConfig[VR_CONFIG_MODE]; + bool screenMode = (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN); + if (screenMode && (size > 0)) { int x = vrConfig[VR_CONFIG_MOUSE_X]; int y = vrConfig[VR_CONFIG_MOUSE_Y]; ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, size); @@ -416,23 +418,9 @@ void VR_FinishFrame( engine_t* engine ) { projection_layer.views = projection_layer_elements; engine->appState.Layers[engine->appState.LayerCount++].Projection = projection_layer; - } else if (vrMode == VR_MODE_FLAT_SCREEN) { + } else if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { - // Build the cylinder layer - int width = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Width; - int height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height; - XrCompositionLayerCylinderKHR cylinder_layer = {}; - cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR; - cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; - cylinder_layer.space = engine->appState.CurrentSpace; - cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; - memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage)); - cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Handle; - cylinder_layer.subImage.imageRect.offset.x = 0; - cylinder_layer.subImage.imageRect.offset.y = 0; - cylinder_layer.subImage.imageRect.extent.width = width; - cylinder_layer.subImage.imageRect.extent.height = height; - cylinder_layer.subImage.imageArrayIndex = 0; + // Flat screen pose float distance = (float)vrConfig[VR_CONFIG_CANVAS_DISTANCE]; float menuPitch = ToRadians((float)vrConfig[VR_CONFIG_MENU_PITCH]); float menuYaw = ToRadians((float)vrConfig[VR_CONFIG_MENU_YAW]); @@ -443,13 +431,42 @@ void VR_FinishFrame( engine_t* engine ) { }; XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, -menuPitch); XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, menuYaw); + + // Setup the cylinder layer + XrCompositionLayerCylinderKHR cylinder_layer = {}; + cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR; + cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; + cylinder_layer.space = engine->appState.CurrentSpace; + memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage)); + cylinder_layer.subImage.imageRect.offset.x = 0; + cylinder_layer.subImage.imageRect.offset.y = 0; + cylinder_layer.subImage.imageRect.extent.width = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Width; + cylinder_layer.subImage.imageRect.extent.height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height; + cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Handle; + cylinder_layer.subImage.imageArrayIndex = 0; cylinder_layer.pose.orientation = XrQuaternionf_Multiply(pitch, yaw); cylinder_layer.pose.position = pos; cylinder_layer.radius = 12.0f; cylinder_layer.centralAngle = M_PI * 0.5f; cylinder_layer.aspectRatio = 1; - engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + // Build the cylinder layer + if (vrMode == VR_MODE_MONO_SCREEN) { + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + } else if (engine->appState.Renderer.Multiview) { + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT; + cylinder_layer.subImage.imageArrayIndex = 1; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + } else { + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT; + cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[1].ColorSwapChain.Handle; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + } } else { assert(false); } diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index fe7a4671f1..7a86adf6b2 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -34,9 +34,10 @@ enum VRMatrix { }; enum VRMode { - VR_MODE_FLAT_SCREEN = 0, - VR_MODE_MONO_6DOF = 1, - VR_MODE_STEREO_6DOF = 2 + VR_MODE_MONO_SCREEN, + VR_MODE_STEREO_SCREEN, + VR_MODE_MONO_6DOF, + VR_MODE_STEREO_6DOF }; void VR_GetResolution( engine_t* engine, int *pWidth, int *pHeight ); From 1931fa2f5fea2dc1158f6a9f8d948a73599c79ac Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 16:01:09 -0700 Subject: [PATCH 029/715] softgpu: Make triangle fan rect detection generic. --- GPU/Software/RasterizerRectangle.cpp | 63 ++++++++++++++++------------ GPU/Software/RasterizerRectangle.h | 2 +- GPU/Software/TransformUnit.cpp | 2 +- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 5cc40566d6..8d39a2426a 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -483,40 +483,51 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData return false; } -bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex) { +bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex) { // Color and Z must be flat. - for (int i = 1; i < c; ++i) { + int tl = 0, br = 0; + for (int i = 1; i < 4; ++i) { if (!AreCoordsRectangleCompatible(state, data[i], data[0])) return false; + + if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) + tl = i; + if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y >= data[br].v.screenpos.y) + br = i; } - // Check for the common case: a single TL-TR-BR-BL. - if (c == 4) { - const auto &pos0 = data[0].v.screenpos, &pos1 = data[1].v.screenpos; - const auto &pos2 = data[2].v.screenpos, &pos3 = data[3].v.screenpos; - if (pos0.x == pos3.x && pos1.x == pos2.x && pos0.y == pos1.y && pos3.y == pos2.y) { - // Looking like yes. Set TL/BR based on y order first... - *tlIndex = pos0.y > pos3.y ? 2 : 0; - *brIndex = pos0.y > pos3.y ? 0 : 2; - // And if it's horizontally flipped, trade to the actual TL/BR. - if (pos0.x > pos1.x) { - *tlIndex ^= 1; - *brIndex ^= 1; - } + *tlIndex = tl; + *brIndex = br; - // Do we need to think about rotation? - if (!state.enableTextures) - return true; + int tr = 1, bl = 1; + for (int i = 0; i < 4; ++i) { + if (i == tl || i == br) + continue; - const auto &textl = data[*tlIndex].v.texturecoords, &textr = data[*tlIndex ^ 1].v.texturecoords; - const auto &texbl = data[*brIndex ^ 1].v.texturecoords, &texbr = data[*brIndex].v.texturecoords; + if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y >= data[tl].v.screenpos.y) + bl = i; + if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y <= data[br].v.screenpos.y) + tr = i; + } - if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) { - // Okay, the texture is also good, but let's avoid rotation issues. - const auto &postl = data[*tlIndex].v.screenpos; - const auto &posbr = data[*brIndex].v.screenpos; - return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x; - } + // Must have found each of the coordinates. + if (tl + tr + bl + br != 6) + return false; + + // Note the common case is a single TL-TR-BR-BL. + const auto &postl = data[tl].v.screenpos, &postr = data[tr].v.screenpos; + const auto &posbr = data[br].v.screenpos, &posbl = data[bl].v.screenpos; + if (postl.x == posbl.x && postr.x == posbr.x && postl.y == postr.y && posbl.y == posbr.y) { + // Do we need to think about rotation? + if (!state.enableTextures) + return true; + + const auto &textl = data[tl].v.texturecoords, &textr = data[tr].v.texturecoords; + const auto &texbl = data[bl].v.texturecoords, &texbr = data[br].v.texturecoords; + + if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) { + // Okay, the texture is also good, but let's avoid rotation issues. + return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x; } } diff --git a/GPU/Software/RasterizerRectangle.h b/GPU/Software/RasterizerRectangle.h index 19e4b42b48..49f2e61c93 100644 --- a/GPU/Software/RasterizerRectangle.h +++ b/GPU/Software/RasterizerRectangle.h @@ -21,7 +21,7 @@ namespace Rasterizer { void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state); bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData data[4], int *tlIndex, int *brIndex); - bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex); + bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex); bool DetectRectangleFromPair(const RasterizerState &state, const ClipVertexData data[6], int *tlIndex, int *brIndex); bool DetectRectangleThroughModeSlices(const RasterizerState &state, const ClipVertexData data[4]); } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 7d1d28d07d..fbbdcd3919 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -793,7 +793,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G } int tl = -1, br = -1; - if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, vertex_count, &tl, &br)) { + if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, &tl, &br)) { Clipper::ProcessRect(data_[tl], data_[br], *binner_); break; } From 9d6de98ed95615dd0bd0f7ca16683f01e95026b3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 18:46:38 -0700 Subject: [PATCH 030/715] softgpu: Correct drawing outside TL of rectangle. If the start coordinate was something like 51.75, we were incorrectly drawing to 51. This can be seen in the Metal Slug intro (#15755.) --- GPU/Software/Rasterizer.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index d59c1fb0cf..2a24ee348a 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -796,11 +796,18 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & int entireY1 = std::min(v0.screenpos.y, v1.screenpos.y); int entireX2 = std::max(v0.screenpos.x, v1.screenpos.x) - 1; int entireY2 = std::max(v0.screenpos.y, v1.screenpos.y) - 1; - int minX = std::max(entireX1, range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); - int minY = std::max(entireY1, range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minX = std::max(entireX1 & ~(SCREEN_SCALE_FACTOR - 1), range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minY = std::max(entireY1 & ~(SCREEN_SCALE_FACTOR - 1), range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); int maxX = std::min(entireX2, range.x2); int maxY = std::min(entireY2, range.y2); + // If TL x or y was after the half, we don't draw the pixel. + // TODO: Verify what center is used, allowing slight offset makes gpu/primitives/trianglefan pass. + if (minX < entireX1 - 1) + minX += SCREEN_SCALE_FACTOR; + if (minY < entireY1 - 1) + minY += SCREEN_SCALE_FACTOR; + RasterizerState state = OptimizeFlatRasterizerState(rastState, v1); Vec2f rowST(0.0f, 0.0f); @@ -1043,10 +1050,17 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const BinCoords int entireY1 = std::min(v0.screenpos.y, v1.screenpos.y); int entireX2 = std::max(v0.screenpos.x, v1.screenpos.x) - 1; int entireY2 = std::max(v0.screenpos.y, v1.screenpos.y) - 1; - int minX = std::max(entireX1, range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); - int minY = std::max(entireY1, range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minX = std::max(entireX1 & ~(SCREEN_SCALE_FACTOR - 1), range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minY = std::max(entireY1 & ~(SCREEN_SCALE_FACTOR - 1), range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); int maxX = std::min(entireX2, range.x2); int maxY = std::min(entireY2, range.y2); + + // If TL x or y was after the half, we don't draw the pixel. + if (minX < entireX1 - 1) + minX += SCREEN_SCALE_FACTOR; + if (minY < entireY1 - 1) + minY += SCREEN_SCALE_FACTOR; + const DrawingCoords pprime = TransformUnit::ScreenToDrawing(minX, minY); const DrawingCoords pend = TransformUnit::ScreenToDrawing(maxX, maxY); auto &pixelID = state.pixelID; From 7eb7bd51417beff7c0d2abc3acca8ee6c4785e4a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 18:49:37 -0700 Subject: [PATCH 031/715] softgpu: Correct linear interp for uneven positions. Can't round to the pixel when calculating the S/T deltas. This fixes issues in Wipeout (#16131) and Call of Duty bloom. --- GPU/Software/Rasterizer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 2a24ee348a..d75f7f9476 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -826,8 +826,8 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & tc1.t() *= 1.0f / (float)(1 << state.samplerID.height0Shift); } - int diffX = (entireX2 - entireX1 + 1) / SCREEN_SCALE_FACTOR; - int diffY = (entireY2 - entireY1 + 1) / SCREEN_SCALE_FACTOR; + float diffX = (entireX2 - entireX1 + 1) / (float)SCREEN_SCALE_FACTOR; + float diffY = (entireY2 - entireY1 + 1) / (float)SCREEN_SCALE_FACTOR; float diffS = tc1.s() - tc0.s(); float diffT = tc1.t() - tc0.t(); @@ -860,8 +860,8 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & } // Okay, now move ST to the minX, minY position. - rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1); - rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1); + rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1 + 1); + rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1 + 1); } // And now what we add to spread out to 4 values. From 162b27e13677242eb720adc96b790512db87c26a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 22:24:43 -0700 Subject: [PATCH 032/715] GPU: Replace logic ops with blend for simple cases. So that alpha/stencil are handled correctly. --- GPU/Common/GPUStateUtils.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2b8bb84dc1..1b3e348738 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -858,9 +858,12 @@ static inline bool blendColorSimilar(uint32_t a, uint32_t b, int margin = 25) { // The shader might also need modification, the below function SimulateLogicOpShaderTypeIfNeeded // takes care of that. static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) { + if (!gstate.isLogicOpEnabled()) + return false; + // Note: our shader solution applies logic ops BEFORE blending, not correctly after. // This is however fine for the most common ones, like CLEAR/NOOP/SET, etc. - if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP) && gstate.isLogicOpEnabled()) { + if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { switch (gstate.getLogicOp()) { case GE_LOGIC_CLEAR: srcBlend = BlendFactor::ZERO; @@ -916,6 +919,25 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp()); return true; } + } else { + // Even if we support hardware logic ops, alpha is handled wrong. + // It's better to override blending for the simple cases. + switch (gstate.getLogicOp()) { + case GE_LOGIC_CLEAR: + srcBlend = BlendFactor::ZERO; + dstBlend = BlendFactor::ZERO; + blendEq = BlendEq::ADD; + return true; + case GE_LOGIC_NOOP: + srcBlend = BlendFactor::ZERO; + dstBlend = BlendFactor::ONE; + blendEq = BlendEq::ADD; + return true; + + default: + // Let's hope hardware gets it right. + return false; + } } return false; } @@ -1598,5 +1620,7 @@ void GenericLogicState::ApplyToBlendState(GenericBlendState &blendState) { blendState.dstAlpha = BlendFactor::ZERO; blendState.eqAlpha = BlendEq::ADD; } + logicOpEnabled = false; + logicOp = GE_LOGIC_COPY; } } From daca0b2109aa0bfb7a0574766ed3a9f5fe1e4a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 08:27:49 +0200 Subject: [PATCH 033/715] Rename gstate_c.Supports to gstate_c.Use --- GPU/Common/DrawEngineCommon.cpp | 2 +- GPU/Common/FragmentShaderGenerator.cpp | 16 ++++++------- GPU/Common/FramebufferManagerCommon.cpp | 2 +- GPU/Common/GPUStateUtils.cpp | 30 ++++++++++++------------- GPU/Common/GeometryShaderGenerator.cpp | 12 +++++----- GPU/Common/ShaderId.cpp | 8 +++---- GPU/Common/SoftwareTransformCommon.cpp | 2 +- GPU/Common/TextureCacheCommon.cpp | 12 +++++----- GPU/Common/VertexShaderGenerator.cpp | 18 +++++++-------- GPU/D3D11/DrawEngineD3D11.cpp | 2 +- GPU/D3D11/GPU_D3D11.cpp | 4 ++-- GPU/D3D11/StateMappingD3D11.cpp | 4 ++-- GPU/D3D11/TextureCacheD3D11.cpp | 2 +- GPU/Directx9/DrawEngineDX9.cpp | 2 +- GPU/Directx9/GPU_DX9.cpp | 4 ++-- GPU/Directx9/TextureCacheDX9.cpp | 2 +- GPU/GLES/DepthBufferGLES.cpp | 2 +- GPU/GLES/DrawEngineGLES.cpp | 4 ++-- GPU/GLES/GPU_GLES.cpp | 4 ++-- GPU/GLES/ShaderManagerGLES.cpp | 18 +++++++-------- GPU/GLES/StateMappingGLES.cpp | 6 ++--- GPU/GLES/TextureCacheGLES.cpp | 4 ++-- GPU/GPUCommon.cpp | 4 ++-- GPU/GPUState.h | 7 +++--- GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++-- GPU/Vulkan/GPU_Vulkan.cpp | 6 ++--- GPU/Vulkan/ShaderManagerVulkan.cpp | 6 ++--- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- GPU/Vulkan/TextureCacheVulkan.cpp | 4 ++-- 29 files changed, 97 insertions(+), 96 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index f884486c65..249bcf48ef 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -537,7 +537,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, } void DrawEngineCommon::ApplyFramebufferRead(FBOTexState *fboTexState) { - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { + if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { *fboTexState = FBO_TEX_READ_FRAMEBUFFER; } else { gpuStats.numCopiesForShaderBlend++; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index efd7c5a229..783afaa5b7 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -45,7 +45,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool highpFog = false; bool highpTexcoord = false; - bool enableFragmentTestCache = gstate_c.Supports(GPU_USE_FRAGMENT_TEST_CACHE); + bool enableFragmentTestCache = gstate_c.Use(GPU_USE_FRAGMENT_TEST_CACHE); if (compat.gles) { // PowerVR needs highp to do the fog in MHU correctly. @@ -137,11 +137,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool needFramebufferRead = replaceBlend == REPLACE_BLEND_READ_FRAMEBUFFER || colorWriteMask || replaceLogicOp; - bool fetchFramebuffer = needFramebufferRead && gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); - bool readFramebufferTex = needFramebufferRead && !gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); + bool fetchFramebuffer = needFramebufferRead && gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); + bool readFramebufferTex = needFramebufferRead && !gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); - bool needFragCoord = readFramebufferTex || gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); - bool writeDepth = gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); + bool needFragCoord = readFramebufferTex || gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); + bool writeDepth = gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); if (shaderDepalMode != ShaderDepalMode::OFF && !doTexture) { *errorString = "depal requires a texture"; @@ -149,7 +149,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN) { - if (useDiscardStencilBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { + if (useDiscardStencilBugWorkaround && !gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } @@ -1173,11 +1173,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " %s = vec4(0.0, 0.0, 0.0, %s.z); // blue to alpha\n", compat.fragColor0, compat.fragColor0); } - if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { + if (gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { const double scale = DepthSliceFactor() * 65535.0; WRITE(p, " highp float z = gl_FragCoord.z;\n"); - if (gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { // We center the depth with an offset, but only its fraction matters. // When (DepthSliceFactor() - 1) is odd, it will be 0.5, otherwise 0. if (((int)(DepthSliceFactor() - 1.0f) & 1) == 1) { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 7195c9fc6e..295910c4fc 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2532,7 +2532,7 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 } bool flipY = (GetGPUBackend() == GPUBackend::OPENGL && !useBufferedRendering_) ? true : false; - if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT_DIV_256, flipY); } else { buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT, flipY); diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 1b3e348738..0adf0ea5d0 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -183,7 +183,7 @@ ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend) { if (nonAlphaSrcFactors[gstate.getBlendFuncA()] && nonAlphaDestFactors[gstate.getBlendFuncB()]) { return REPLACE_ALPHA_YES; } else { - if (gstate_c.Supports(GPU_SUPPORTS_DUALSOURCE_BLEND)) { + if (gstate_c.Use(GPU_SUPPORTS_DUALSOURCE_BLEND)) { return REPLACE_ALPHA_DUALSOURCE; } else { return REPLACE_ALPHA_NO; @@ -275,7 +275,7 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_BLENDMODE_MIN: case GE_BLENDMODE_MAX: - if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) { + if (gstate_c.Use(GPU_SUPPORTS_BLEND_MINMAX)) { return REPLACE_BLEND_STANDARD; } else { return REPLACE_BLEND_READ_FRAMEBUFFER; @@ -312,7 +312,7 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: // We can't technically do this correctly (due to clamping) without reading the dst color. // Using a copy isn't accurate either, though, when there's overlap. - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; @@ -454,14 +454,14 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: if (funcA == GE_SRCBLEND_SRCALPHA || funcA == GE_SRCBLEND_INVSRCALPHA) { // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; } else { // This means dst alpha/color is used in the src factor. // Unfortunately, copying here causes overlap problems in Silent Hill games (it seems?) // We will just hope that doubling alpha for the dst factor will not clamp too badly. - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_2X_ALPHA; } @@ -494,10 +494,10 @@ static const float DEPTH_SLICE_FACTOR_HIGH = 4.0f; static const float DEPTH_SLICE_FACTOR_16BIT = 256.0f; float DepthSliceFactor() { - if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { return DEPTH_SLICE_FACTOR_16BIT; } - if (gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP)) { + if (gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP)) { return 1.0f; } return DEPTH_SLICE_FACTOR_HIGH; @@ -505,12 +505,12 @@ float DepthSliceFactor() { // This is used for float values which might not be integers, but are in the integer scale of 65535. float ToScaledDepthFromIntegerScale(float z) { - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { return z * (1.0f / 65535.0f); } const float depthSliceFactor = DepthSliceFactor(); - if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { const double doffset = 0.5 * (depthSliceFactor - 1.0) * (1.0 / depthSliceFactor); // Use one bit for each value, rather than 1.0 / (25535.0 * 256.0). return (float)((double)z * (1.0 / 16777215.0) + doffset); @@ -523,7 +523,7 @@ float ToScaledDepthFromIntegerScale(float z) { // See struct DepthScaleFactors for how to apply. DepthScaleFactors GetDepthScaleFactors() { DepthScaleFactors factors; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { factors.offset = 0; factors.scale = 65535.0f; return factors; @@ -728,7 +728,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo // This adjusts the center from halfActualZRange to vpZCenter. out.zOffset = halfActualZRange < std::numeric_limits::epsilon() ? 0.0f : (vpZCenter - (minz + halfActualZRange)) / halfActualZRange; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { out.depthScale = 1.0f; out.zOffset = 0.0f; out.depthRangeMin = ToScaledDepthFromIntegerScale(vpZCenter - vpZScale); @@ -863,7 +863,7 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend // Note: our shader solution applies logic ops BEFORE blending, not correctly after. // This is however fine for the most common ones, like CLEAR/NOOP/SET, etc. - if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { + if (!gstate_c.Use(GPU_SUPPORTS_LOGIC_OP)) { switch (gstate.getLogicOp()) { case GE_LOGIC_CLEAR: srcBlend = BlendFactor::ZERO; @@ -944,7 +944,7 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend // Choose the shader part of the above logic op fallback simulation. SimulateLogicOpType SimulateLogicOpShaderTypeIfNeeded() { - if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP) && gstate.isLogicOpEnabled()) { + if (!gstate_c.Use(GPU_SUPPORTS_LOGIC_OP) && gstate.isLogicOpEnabled()) { switch (gstate.getLogicOp()) { case GE_LOGIC_COPY_INVERTED: case GE_LOGIC_AND_INVERTED: @@ -1275,7 +1275,7 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow. BlendEq colorEq; - if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) { + if (gstate_c.Use(GPU_SUPPORTS_BLEND_MINMAX)) { colorEq = eqLookup[blendFuncEq]; } else { colorEq = eqLookupNoMinMax[blendFuncEq]; @@ -1597,7 +1597,7 @@ void ComputedPipelineState::Convert(bool shaderBitOpsSuppported) { // Passing on the previous applyFramebufferRead as forceFrameBuffer read in the next one, // thus propagating forward. ConvertMaskState(maskState, shaderBitOpsSuppported); - ConvertLogicOpState(logicState, gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP), shaderBitOpsSuppported, maskState.applyFramebufferRead); + ConvertLogicOpState(logicState, gstate_c.Use(GPU_SUPPORTS_LOGIC_OP), shaderBitOpsSuppported, maskState.applyFramebufferRead); ConvertBlendState(blendState, logicState.applyFramebufferRead); // Note: If the blend state decided it had to use framebuffer reads, diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index a814a345da..67a13e889b 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -46,11 +46,11 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu } } bool vertexRangeCulling = !id.Bit(GS_BIT_CURVE); - bool clipClampedDepth = gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + bool clipClampedDepth = gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts.data(), gl_exts.size()); p.C("layout(triangles) in;\n"); - if (clipClampedDepth && vertexRangeCulling && !gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { p.C("layout(triangle_strip, max_vertices = 12) out;\n"); } else { p.C("layout(triangle_strip, max_vertices = 6) out;\n"); @@ -85,7 +85,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" bool anyInside = false;\n"); } // And apply manual clipping if necessary. - if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { p.C(" float clip0[3];\n"); if (clipClampedDepth) { p.C(" float clip1[3];\n"); @@ -117,7 +117,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" }\n"); } - if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { // This is basically the same value as gl_ClipDistance would take, z + w. if (vertexRangeCulling) { p.C(" clip0[i] = projZ * outPos.w + outPos.w;\n"); @@ -156,7 +156,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" }\n"); } - if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { // Clipping against one half-space cuts a triangle (17/27), culls (7/27), or creates two triangles (3/27). // We clip against two, so we can generate up to 4 triangles, a polygon with 6 points. p.C(" int indices[6];\n"); @@ -290,7 +290,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix0); } p.C(" gl_Position = outPos;\n"); - if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { } for (size_t i = 0; i < varyings.size(); i++) { diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 43fcbab8ab..e0c14945e1 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -83,7 +83,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, } bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough && !gstate.isModeClear(); - bool vertexRangeCulling = gstate_c.Supports(GPU_SUPPORTS_VS_RANGE_CULLING) && + bool vertexRangeCulling = gstate_c.Use(GPU_SUPPORTS_VS_RANGE_CULLING) && !isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692 VShaderID id; @@ -124,7 +124,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, if (gstate.isLightingEnabled()) { // doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping. id.SetBit(VS_BIT_LIGHTING_ENABLE); - if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { + if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) { id.SetBit(VS_BIT_LIGHT_UBERSHADER); } else { id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate()); @@ -390,11 +390,11 @@ void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim bool isTriangle = prim == GE_PRIM_TRIANGLES || prim == GE_PRIM_TRIANGLE_FAN || prim == GE_PRIM_TRIANGLE_STRIP; bool vertexRangeCulling = !isCurve; - bool clipClampedDepth = gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP) && !gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipClampedDepth = gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP) && !gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE); // If we're not using GS culling, return a zero ID. // Also, only use this for triangle primitives. - if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle || !gstate_c.Supports(GPU_SUPPORTS_GS_CULLING)) { + if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle || !gstate_c.Use(GPU_SUPPORTS_GS_CULLING)) { *id_out = id; return; } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 5e3c0c5850..418868e219 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -639,7 +639,7 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy result->drawIndexed = true; // If we don't support custom cull in the shader, process it here. - if (!gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE) && vertexCount > 0 && !throughmode) { + if (!gstate_c.Use(GPU_SUPPORTS_CULL_DISTANCE) && vertexCount > 0 && !throughmode) { const u16 *indsIn = (const u16 *)inds; u16 *newInds = inds + vertexCount; u16 *indsOut = newInds; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 32b234b49a..d1df05f809 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -197,7 +197,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.maxLevel = maxLevel * 256; key.minLevel = 0; key.lodBias = (int)(lodBias * 256.0f); - if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + if (gstate_c.Use(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { key.aniso = true; } break; @@ -281,7 +281,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.mipFilt = 1; key.maxLevel = 9 * 256; key.lodBias = 0.0f; - if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + if (gstate_c.Use(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { key.aniso = true; } break; @@ -1103,7 +1103,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) gstate_c.SetNeedShaderTexclamp(true); } - if (channel == RASTER_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) { + if (channel == RASTER_DEPTH && !gstate_c.Use(GPU_SUPPORTS_DEPTH_TEXTURE)) { WARN_LOG_ONCE(ndepthtex, G3D, "Depth textures not supported, not binding"); // Flag to bind a null texture if we can't support depth textures. // Should only happen on old OpenGL. @@ -1202,7 +1202,7 @@ bool TextureCacheCommon::GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffe void TextureCacheCommon::NotifyConfigChanged() { int scaleFactor = g_Config.iTexScalingLevel; - if (!gstate_c.Supports(GPU_SUPPORTS_TEXTURE_NPOT)) { + if (!gstate_c.Use(GPU_SUPPORTS_TEXTURE_NPOT)) { // Reduce the scale factor to a power of two (e.g. 2 or 4) if textures must be a power of two. // TODO: In addition we should probably remove these options from the UI in this case. while ((scaleFactor & (scaleFactor - 1)) != 0) { @@ -2581,7 +2581,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt int lastW = gstate.getTextureWidth(i - 1); int lastH = gstate.getTextureHeight(i - 1); - if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (gstate_c.Use(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { if (tw != 1 && tw != (lastW >> 1)) plan.badMipSizes = true; else if (th != 1 && th != (lastH >> 1)) @@ -2782,7 +2782,7 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, i decPitch = stride; } - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) { + if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) { texDecFlags |= TexDecodeFlags::EXPAND32; } if (entry.status & TexCacheEntry::STATUS_CLUT_GPU) { diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 24f118603f..601be62a0c 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -139,7 +139,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (gl_extensions.EXT_gpu_shader4) { gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); } - bool useClamp = gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH); + bool useClamp = gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH); if (gl_extensions.EXT_clip_cull_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) { gl_exts.push_back("#extension GL_EXT_clip_cull_distance : enable"); } @@ -230,7 +230,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool texCoordInVec3 = false; bool vertexRangeCulling = id.Bit(VS_BIT_VERTEX_RANGE_CULLING) && !isModeThrough; - bool clipClampedDepth = !isModeThrough && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipClampedDepth = !isModeThrough && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP) && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE); const char *clipClampedDepthSuffix = "[0]"; const char *vertexRangeClipSuffix = clipClampedDepth ? "[1]" : "[0]"; @@ -416,7 +416,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 gl_Position : POSITION;\n"); } else { WRITE(p, " vec4 gl_Position : SV_Position;\n"); - bool clipRange = vertexRangeCulling && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipRange = vertexRangeCulling && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE); if (clipClampedDepth && clipRange) { WRITE(p, " float2 gl_ClipDistance : SV_ClipDistance;\n"); clipClampedDepthSuffix = ".x"; @@ -426,7 +426,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag clipClampedDepthSuffix = ""; vertexRangeClipSuffix = ""; } - if (vertexRangeCulling && gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE)) { + if (vertexRangeCulling && gstate_c.Use(GPU_SUPPORTS_CULL_DISTANCE)) { WRITE(p, " float2 gl_CullDistance : SV_CullDistance0;\n"); } } @@ -597,7 +597,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } // See comment above this function (GenerateVertexShader). - if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + if (!isModeThrough && gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { // Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection. WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n"); WRITE(p, " float z = v.z / v.w;\n"); @@ -847,7 +847,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } // The viewport is used in this case, so need to compensate for that. - if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { WRITE(p, " vec4 outPos = depthRoundZVP(pos);\n"); } else { WRITE(p, " vec4 outPos = pos;\n"); @@ -927,7 +927,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 viewPos = vec4(mul(vec4(worldpos, 1.0), u_view%s).xyz, 1.0);\n", matrixPostfix.c_str()); // Final view and projection transforms. - if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { if (IsVRBuild()) { WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj_lens%s, viewPos));\n", matrixPostfix.c_str()); WRITE(p, " vec4 orgPos = depthRoundZVP(mul(u_proj, viewPos));\n"); @@ -1306,11 +1306,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag const char *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]"; const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]"; - if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { // TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z. WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", compat.vsOutPrefix, vertexRangeClipSuffix); } - if (gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE)) { + if (gstate_c.Use(GPU_SUPPORTS_CULL_DISTANCE)) { // Cull any triangle fully outside in the same direction when depth clamp enabled. WRITE(p, " if (u_cullRangeMin.w > 0.0) {\n"); WRITE(p, " %sgl_CullDistance%s = projPos.z - u_cullRangeMin.z;\n", compat.vsOutPrefix, cull0); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index eff16b543b..c5c4669ba9 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -701,7 +701,7 @@ rotateVBO: uint8_t clearStencil = clearColor >> 24; draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil); - if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { + if ((gstate_c.useFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index bfbd12f190..59e3a5a4ed 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -82,7 +82,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // No need to flush before the tex scale/offset commands if we are baking // the tex scale/offset into the vertices anyway. UpdateCmdInfo(); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); BuildReportingInfo(); @@ -174,7 +174,7 @@ void GPU_D3D11::BeginHostFrame() { GPUCommon::BeginHostFrame(); UpdateCmdInfo(); if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); framebufferManager_->Resized(); drawEngine_.Resized(); textureCache_->NotifyConfigChanged(); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 6f113f23d0..6a839e3d66 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -202,7 +202,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { dynState_.useBlendColor = false; } - if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { + if (gstate_c.Use(GPU_SUPPORTS_LOGIC_OP)) { // Logic Ops if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) { keys_.blend.blendEnable = false; // Can't have both blend & logic op - although I think the PSP can! @@ -229,7 +229,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - keys_.raster.depthClipEnable = !gstate.isDepthClampEnabled() || !gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + keys_.raster.depthClipEnable = !gstate.isDepthClampEnabled() || !gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. keys_.raster.depthClipEnable = 1; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 2dac7b0749..a69dd20cd5 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -428,7 +428,7 @@ DXGI_FORMAT GetClutDestFormatD3D11(GEPaletteFormat format) { } DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS)) { + if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS)) { return DXGI_FORMAT_B8G8R8A8_UNORM; } diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index b8d4bfa0fb..8d0bac74ea 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -645,7 +645,7 @@ rotateVBO: device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); - if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 075d89e460..7a69f7410d 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -81,7 +81,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // No need to flush before the tex scale/offset commands if we are baking // the tex scale/offset into the vertices anyway. UpdateCmdInfo(); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); BuildReportingInfo(); @@ -163,7 +163,7 @@ void GPU_DX9::BeginHostFrame() { GPUCommon::BeginHostFrame(); UpdateCmdInfo(); if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); framebufferManager_->Resized(); drawEngine_.Resized(); shaderManagerDX9_->DirtyShader(); diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index dedbb55660..4179c8b39d 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -170,7 +170,7 @@ void TextureCacheDX9::StartFrame() { Decimate(); } - if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY)) { + if (gstate_c.Use(GPU_SUPPORTS_ANISOTROPY)) { DWORD aniso = 1 << g_Config.iAnisotropyLevel; DWORD anisotropyLevel = aniso > maxAnisotropyLevel ? maxAnisotropyLevel : aniso; device_->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, anisotropyLevel); diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 5283612f51..e82f055424 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -217,7 +217,7 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int DepthUB ub{}; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { // Don't scale anything, since we're not using factors outside accurate mode. ub.u_depthFactor[0] = 0.0f; ub.u_depthFactor[1] = 1.0f; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 2102e46095..2e981d0474 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -437,7 +437,7 @@ void DrawEngineGLES::DoFlush() { render_->Clear(clearColor, clearDepth, clearColor >> 24, target, rgbaMask, vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH); framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate_c.framebufFormat == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; @@ -476,7 +476,7 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { bool DrawEngineGLES::SupportsHWTessellation() const { bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; - return hasTexelFetch && gstate_c.SupportsAll(GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT | GPU_SUPPORTS_INSTANCE_RENDERING); + return hasTexelFetch && gstate_c.UseAll(GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT | GPU_SUPPORTS_INSTANCE_RENDERING); } bool DrawEngineGLES::UpdateUseHWTessellation(bool enable) { diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 65dd71a539..39b9e59eb4 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -54,7 +54,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), drawEngine_(draw), fragmentTestCache_(draw) { UpdateVsyncInterval(true); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); shaderManagerGL_ = new ShaderManagerGLES(draw); framebufferManagerGL_ = new FramebufferManagerGLES(draw); @@ -281,7 +281,7 @@ void GPU_GLES::BeginHostFrame() { GPUCommon::BeginHostFrame(); UpdateCmdInfo(); if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); framebufferManager_->Resized(); drawEngine_.Resized(); shaderManagerGL_->DirtyShader(); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 70295fdfdf..7d38e8df36 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -196,12 +196,12 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, initialize.push_back({ &u_tess_weights_v, 0, TEX_SLOT_SPLINE_WEIGHTS_V }); GLRProgramFlags flags{}; - flags.supportDualSource = (gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) != 0; - if (!VSID.Bit(VS_BIT_IS_THROUGH) && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP)) { + flags.supportDualSource = (gstate_c.useFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) != 0; + if (!VSID.Bit(VS_BIT_IS_THROUGH) && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP)) { flags.useClipDistance0 = true; - if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) + if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) flags.useClipDistance1 = true; - } else if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + } else if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { flags.useClipDistance0 = true; } @@ -323,7 +323,7 @@ static inline void FlipProjMatrix(Matrix4x4 &in, bool useBufferedRendering) { // In Phantasy Star Portable 2, depth range sometimes goes negative and is clamped by glDepthRange to 0, // causing graphics clipping glitch (issue #1788). This hack modifies the projection matrix to work around it. - if (gstate_c.Supports(GPU_USE_DEPTH_RANGE_HACK)) { + if (gstate_c.Use(GPU_USE_DEPTH_RANGE_HACK)) { float zScale = gstate.getViewportZScale() / 65535.0f; float zCenter = gstate.getViewportZCenter() / 65535.0f; @@ -564,7 +564,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu float viewZScale = halfActualZRange; float viewZCenter = minz + halfActualZRange; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { viewZScale = vpZScale; viewZCenter = vpZCenter; } @@ -940,7 +940,7 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT struct CacheHeader { uint32_t magic; uint32_t version; - uint32_t featureFlags; + uint32_t useFlags; uint32_t reserved; int numVertexShaders; int numFragmentShaders; @@ -957,7 +957,7 @@ void ShaderManagerGLES::Load(const Path &filename) { if (!f.ReadArray(&header, 1)) { return; } - if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.featureFlags != gstate_c.featureFlags) { + if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.useFlags != gstate_c.useFlags) { return; } diskCachePending_.start = time_now_d(); @@ -1113,7 +1113,7 @@ void ShaderManagerGLES::Save(const Path &filename) { header.magic = CACHE_HEADER_MAGIC; header.version = CACHE_VERSION; header.reserved = 0; - header.featureFlags = gstate_c.featureFlags; + header.useFlags = gstate_c.useFlags; header.numVertexShaders = GetNumVertexShaders(); header.numFragmentShaders = GetNumFragmentShaders(); header.numLinkedPrograms = GetNumPrograms(); diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 5485db3c4e..cbbfb72a95 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -209,7 +209,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { // TODO: Get rid of the ifdef #ifndef USING_GLES2 - if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { + if (gstate_c.Use(GPU_SUPPORTS_LOGIC_OP)) { renderManager->SetLogicOp(logicState.logicOpEnabled, logicOps[(int)logicState.logicOp]); } #endif @@ -232,7 +232,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. depthClampEnable = false; @@ -304,7 +304,7 @@ void DrawEngineGLES::ApplyDrawStateLate(bool setStencilValue, int stencilValue) // At this point, we know if the vertices are full alpha or not. // TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)? - if (!gstate.isModeClear() && gstate_c.Supports(GPU_USE_FRAGMENT_TEST_CACHE)) { + if (!gstate.isModeClear() && gstate_c.Use(GPU_USE_FRAGMENT_TEST_CACHE)) { // Apply last, once we know the alpha params of the texture. if (gstate.isAlphaTestEnabled() || gstate.isColorTestEnabled()) { fragmentTestCache_->BindTestTexture(TEX_SLOT_ALPHATEST); diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index bbb7c9838b..56b7f0d3b3 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -105,7 +105,7 @@ static const GLuint MagFiltGL[2] = { }; void TextureCacheGLES::ApplySamplingParams(const SamplerCacheKey &key) { - if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (gstate_c.Use(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { float minLod = (float)key.minLevel / 256.0f; float maxLod = (float)key.maxLevel / 256.0f; float lodBias = (float)key.lodBias / 256.0f; @@ -286,7 +286,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { } } - if (!gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (!gstate_c.Use(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { // If the mip chain is not full.. if (plan.levelsToCreate != plan.maxPossibleLevels) { // We need to avoid creating mips at all, or generate them all - can't be incomplete diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 80f2eefefc..5cdfd9a434 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -454,7 +454,7 @@ void GPUCommon::UpdateCmdInfo() { // Reconfigure for light ubershader or not. for (int i = 0; i < 4; i++) { - if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { + if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) { cmdInfo_[GE_CMD_LIGHTENABLE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE); cmdInfo_[GE_CMD_LIGHTENABLE0 + i].AddDirty(DIRTY_LIGHT_CONTROL); cmdInfo_[GE_CMD_LIGHTTYPE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE); @@ -467,7 +467,7 @@ void GPUCommon::UpdateCmdInfo() { } } - if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { + if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) { cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_VERTEXSHADER_STATE); cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_LIGHT_CONTROL); } else { diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 15b837e5ba..052554b287 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -519,8 +519,9 @@ enum class SubmitType { }; struct GPUStateCache { - bool Supports(u32 flags) { return (featureFlags & flags) != 0; } // Return true if ANY of flags are true. - bool SupportsAll(u32 flags) { return (featureFlags & flags) == flags; } // Return true if ALL flags are true. + bool Use(u32 flags) { return (useFlags & flags) != 0; } // Return true if ANY of flags are true. + bool UseAll(u32 flags) { return (useFlags & flags) == flags; } // Return true if ALL flags are true. + uint64_t GetDirtyUniforms() { return dirty & DIRTY_ALL_UNIFORMS; } void Dirty(u64 what) { dirty |= what; @@ -561,7 +562,7 @@ struct GPUStateCache { } } - u32 featureFlags; + u32 useFlags; u32 vertexAddr; u32 indexAddr; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index b0e88aa0f2..f46b73de41 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -112,7 +112,7 @@ void DrawEngineVulkan::InitDeviceObjects() { bindings[3].descriptorCount = 1; bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; bindings[3].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - if (gstate_c.Supports(GPU_SUPPORTS_GS_CULLING)) + if (gstate_c.Use(GPU_SUPPORTS_GS_CULLING)) bindings[3].stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT; bindings[3].binding = DRAW_BINDING_DYNUBO_BASE; bindings[4].descriptorCount = 1; @@ -973,7 +973,7 @@ void DrawEngineVulkan::DoFlush() { // If non-buffered though, it'll just do a plain clear. framebufferManager_->NotifyClear(gstate.isClearModeColorMask(), gstate.isClearModeAlphaMask(), gstate.isClearModeDepthMask(), result.color, result.depth); - if (gstate_c.Supports(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 64f69a861b..2ac1188824 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -52,7 +52,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), drawEngine_(draw) { - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); drawEngine_.InitDeviceObjects(); VulkanContext *vulkan = (VulkanContext *)gfxCtx->GetAPIContext(); @@ -276,7 +276,7 @@ void GPU_Vulkan::BeginHostFrame() { UpdateCmdInfo(); if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); // In case the GPU changed. BuildReportingInfo(); framebufferManager_->Resized(); @@ -515,7 +515,7 @@ void GPU_Vulkan::DeviceRestore() { GPUCommon::DeviceRestore(); InitDeviceObjects(); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.useFlags = CheckGPUFeatures(); BuildReportingInfo(); UpdateCmdInfo(); diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index c7724da670..97eb00c490 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -486,7 +486,7 @@ VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderM struct VulkanCacheHeader { uint32_t magic; uint32_t version; - uint32_t featureFlags; + uint32_t useFlags; uint32_t reserved; int numVertexShaders; int numFragmentShaders; @@ -500,7 +500,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { return false; if (header.version != CACHE_VERSION) return false; - if (header.featureFlags != gstate_c.featureFlags) + if (header.useFlags != gstate_c.useFlags) return false; VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); @@ -563,7 +563,7 @@ void ShaderManagerVulkan::SaveCache(FILE *f) { VulkanCacheHeader header{}; header.magic = CACHE_HEADER_MAGIC; header.version = CACHE_VERSION; - header.featureFlags = gstate_c.featureFlags; + header.useFlags = gstate_c.useFlags; header.reserved = 0; header.numVertexShaders = (int)vsCache_.size(); header.numFragmentShaders = (int)fsCache_.size(); diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 4a81988a7f..62ef19d868 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -232,7 +232,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. key.depthClampEnable = false; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 1a910bc5a1..f063dfa44a 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -685,7 +685,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS)) { + if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS)) { return VK_FORMAT_R8G8B8A8_UNORM; } switch (format) { @@ -726,7 +726,7 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt int decPitch; TexDecodeFlags texDecFlags{}; - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) { + if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) { texDecFlags |= TexDecodeFlags::EXPAND32; } if (entry.status & TexCacheEntry::STATUS_CLUT_GPU) { From 9b8a5d1db30952de01bd760727591c1f7671a9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 08:30:27 +0200 Subject: [PATCH 034/715] Rename GPU_SUPPORTS_ to GPU_USE_ --- GPU/Common/DrawEngineCommon.cpp | 2 +- GPU/Common/FragmentShaderGenerator.cpp | 6 ++--- GPU/Common/GPUStateUtils.cpp | 26 +++++++++---------- GPU/Common/GeometryShaderGenerator.cpp | 12 ++++----- GPU/Common/ShaderId.cpp | 6 ++--- GPU/Common/SoftwareTransformCommon.cpp | 2 +- GPU/Common/TextureCacheCommon.cpp | 12 ++++----- GPU/Common/VertexShaderGenerator.cpp | 12 ++++----- GPU/D3D11/GPU_D3D11.cpp | 16 ++++++------ GPU/D3D11/StateMappingD3D11.cpp | 4 +-- GPU/D3D11/TextureCacheD3D11.cpp | 2 +- GPU/Directx9/GPU_DX9.cpp | 6 ++--- GPU/Directx9/TextureCacheDX9.cpp | 2 +- GPU/GLES/DepthBufferGLES.cpp | 2 +- GPU/GLES/DrawEngineGLES.cpp | 2 +- GPU/GLES/GPU_GLES.cpp | 18 ++++++------- GPU/GLES/ShaderManagerGLES.cpp | 10 +++---- GPU/GLES/StateMappingGLES.cpp | 4 +-- GPU/GLES/TextureCacheGLES.cpp | 4 +-- GPU/GPUCommon.cpp | 20 +++++++------- GPU/GPUState.h | 36 +++++++++++++------------- GPU/Vulkan/DrawEngineVulkan.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 30 ++++++++++----------- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- GPU/Vulkan/TextureCacheVulkan.cpp | 4 +-- 25 files changed, 121 insertions(+), 121 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 249bcf48ef..155589641a 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -537,7 +537,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, } void DrawEngineCommon::ApplyFramebufferRead(FBOTexState *fboTexState) { - if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { + if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) { *fboTexState = FBO_TEX_READ_FRAMEBUFFER; } else { gpuStats.numCopiesForShaderBlend++; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 783afaa5b7..e465e37ad1 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -137,8 +137,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool needFramebufferRead = replaceBlend == REPLACE_BLEND_READ_FRAMEBUFFER || colorWriteMask || replaceLogicOp; - bool fetchFramebuffer = needFramebufferRead && gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); - bool readFramebufferTex = needFramebufferRead && !gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); + bool fetchFramebuffer = needFramebufferRead && gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH); + bool readFramebufferTex = needFramebufferRead && !gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH); bool needFragCoord = readFramebufferTex || gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); bool writeDepth = gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); @@ -1177,7 +1177,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu const double scale = DepthSliceFactor() * 65535.0; WRITE(p, " highp float z = gl_FragCoord.z;\n"); - if (gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { // We center the depth with an offset, but only its fraction matters. // When (DepthSliceFactor() - 1) is odd, it will be 0.5, otherwise 0. if (((int)(DepthSliceFactor() - 1.0f) & 1) == 1) { diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 0adf0ea5d0..1d2ceaaca0 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -183,7 +183,7 @@ ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend) { if (nonAlphaSrcFactors[gstate.getBlendFuncA()] && nonAlphaDestFactors[gstate.getBlendFuncB()]) { return REPLACE_ALPHA_YES; } else { - if (gstate_c.Use(GPU_SUPPORTS_DUALSOURCE_BLEND)) { + if (gstate_c.Use(GPU_USE_DUALSOURCE_BLEND)) { return REPLACE_ALPHA_DUALSOURCE; } else { return REPLACE_ALPHA_NO; @@ -275,7 +275,7 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_BLENDMODE_MIN: case GE_BLENDMODE_MAX: - if (gstate_c.Use(GPU_SUPPORTS_BLEND_MINMAX)) { + if (gstate_c.Use(GPU_USE_BLEND_MINMAX)) { return REPLACE_BLEND_STANDARD; } else { return REPLACE_BLEND_READ_FRAMEBUFFER; @@ -312,7 +312,7 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: // We can't technically do this correctly (due to clamping) without reading the dst color. // Using a copy isn't accurate either, though, when there's overlap. - if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; @@ -454,14 +454,14 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: if (funcA == GE_SRCBLEND_SRCALPHA || funcA == GE_SRCBLEND_INVSRCALPHA) { // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. - if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; } else { // This means dst alpha/color is used in the src factor. // Unfortunately, copying here causes overlap problems in Silent Hill games (it seems?) // We will just hope that doubling alpha for the dst factor will not clamp too badly. - if (gstate_c.Use(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_2X_ALPHA; } @@ -497,7 +497,7 @@ float DepthSliceFactor() { if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { return DEPTH_SLICE_FACTOR_16BIT; } - if (gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP)) { + if (gstate_c.Use(GPU_USE_DEPTH_CLAMP)) { return 1.0f; } return DEPTH_SLICE_FACTOR_HIGH; @@ -505,7 +505,7 @@ float DepthSliceFactor() { // This is used for float values which might not be integers, but are in the integer scale of 65535. float ToScaledDepthFromIntegerScale(float z) { - if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { return z * (1.0f / 65535.0f); } @@ -523,7 +523,7 @@ float ToScaledDepthFromIntegerScale(float z) { // See struct DepthScaleFactors for how to apply. DepthScaleFactors GetDepthScaleFactors() { DepthScaleFactors factors; - if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { factors.offset = 0; factors.scale = 65535.0f; return factors; @@ -728,7 +728,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo // This adjusts the center from halfActualZRange to vpZCenter. out.zOffset = halfActualZRange < std::numeric_limits::epsilon() ? 0.0f : (vpZCenter - (minz + halfActualZRange)) / halfActualZRange; - if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { out.depthScale = 1.0f; out.zOffset = 0.0f; out.depthRangeMin = ToScaledDepthFromIntegerScale(vpZCenter - vpZScale); @@ -863,7 +863,7 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend // Note: our shader solution applies logic ops BEFORE blending, not correctly after. // This is however fine for the most common ones, like CLEAR/NOOP/SET, etc. - if (!gstate_c.Use(GPU_SUPPORTS_LOGIC_OP)) { + if (!gstate_c.Use(GPU_USE_LOGIC_OP)) { switch (gstate.getLogicOp()) { case GE_LOGIC_CLEAR: srcBlend = BlendFactor::ZERO; @@ -944,7 +944,7 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend // Choose the shader part of the above logic op fallback simulation. SimulateLogicOpType SimulateLogicOpShaderTypeIfNeeded() { - if (!gstate_c.Use(GPU_SUPPORTS_LOGIC_OP) && gstate.isLogicOpEnabled()) { + if (!gstate_c.Use(GPU_USE_LOGIC_OP) && gstate.isLogicOpEnabled()) { switch (gstate.getLogicOp()) { case GE_LOGIC_COPY_INVERTED: case GE_LOGIC_AND_INVERTED: @@ -1275,7 +1275,7 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow. BlendEq colorEq; - if (gstate_c.Use(GPU_SUPPORTS_BLEND_MINMAX)) { + if (gstate_c.Use(GPU_USE_BLEND_MINMAX)) { colorEq = eqLookup[blendFuncEq]; } else { colorEq = eqLookupNoMinMax[blendFuncEq]; @@ -1597,7 +1597,7 @@ void ComputedPipelineState::Convert(bool shaderBitOpsSuppported) { // Passing on the previous applyFramebufferRead as forceFrameBuffer read in the next one, // thus propagating forward. ConvertMaskState(maskState, shaderBitOpsSuppported); - ConvertLogicOpState(logicState, gstate_c.Use(GPU_SUPPORTS_LOGIC_OP), shaderBitOpsSuppported, maskState.applyFramebufferRead); + ConvertLogicOpState(logicState, gstate_c.Use(GPU_USE_LOGIC_OP), shaderBitOpsSuppported, maskState.applyFramebufferRead); ConvertBlendState(blendState, logicState.applyFramebufferRead); // Note: If the blend state decided it had to use framebuffer reads, diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index 67a13e889b..18a2bc182e 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -46,11 +46,11 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu } } bool vertexRangeCulling = !id.Bit(GS_BIT_CURVE); - bool clipClampedDepth = gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); + bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP); ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts.data(), gl_exts.size()); p.C("layout(triangles) in;\n"); - if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { p.C("layout(triangle_strip, max_vertices = 12) out;\n"); } else { p.C("layout(triangle_strip, max_vertices = 6) out;\n"); @@ -85,7 +85,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" bool anyInside = false;\n"); } // And apply manual clipping if necessary. - if (!gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { p.C(" float clip0[3];\n"); if (clipClampedDepth) { p.C(" float clip1[3];\n"); @@ -117,7 +117,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" }\n"); } - if (!gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // This is basically the same value as gl_ClipDistance would take, z + w. if (vertexRangeCulling) { p.C(" clip0[i] = projZ * outPos.w + outPos.w;\n"); @@ -156,7 +156,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" }\n"); } - if (!gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // Clipping against one half-space cuts a triangle (17/27), culls (7/27), or creates two triangles (3/27). // We clip against two, so we can generate up to 4 triangles, a polygon with 6 points. p.C(" int indices[6];\n"); @@ -290,7 +290,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix0); } p.C(" gl_Position = outPos;\n"); - if (gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { } for (size_t i = 0; i < varyings.size(); i++) { diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index e0c14945e1..78483cf8a5 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -83,7 +83,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, } bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough && !gstate.isModeClear(); - bool vertexRangeCulling = gstate_c.Use(GPU_SUPPORTS_VS_RANGE_CULLING) && + bool vertexRangeCulling = gstate_c.Use(GPU_USE_VS_RANGE_CULLING) && !isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692 VShaderID id; @@ -390,11 +390,11 @@ void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim bool isTriangle = prim == GE_PRIM_TRIANGLES || prim == GE_PRIM_TRIANGLE_FAN || prim == GE_PRIM_TRIANGLE_STRIP; bool vertexRangeCulling = !isCurve; - bool clipClampedDepth = gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP) && !gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !gstate_c.Use(GPU_USE_CLIP_DISTANCE); // If we're not using GS culling, return a zero ID. // Also, only use this for triangle primitives. - if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle || !gstate_c.Use(GPU_SUPPORTS_GS_CULLING)) { + if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle || !gstate_c.Use(GPU_USE_GS_CULLING)) { *id_out = id; return; } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 418868e219..0f841d1709 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -639,7 +639,7 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy result->drawIndexed = true; // If we don't support custom cull in the shader, process it here. - if (!gstate_c.Use(GPU_SUPPORTS_CULL_DISTANCE) && vertexCount > 0 && !throughmode) { + if (!gstate_c.Use(GPU_USE_CULL_DISTANCE) && vertexCount > 0 && !throughmode) { const u16 *indsIn = (const u16 *)inds; u16 *newInds = inds + vertexCount; u16 *indsOut = newInds; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index d1df05f809..0ee2c54b10 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -197,7 +197,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.maxLevel = maxLevel * 256; key.minLevel = 0; key.lodBias = (int)(lodBias * 256.0f); - if (gstate_c.Use(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + if (gstate_c.Use(GPU_USE_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { key.aniso = true; } break; @@ -281,7 +281,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.mipFilt = 1; key.maxLevel = 9 * 256; key.lodBias = 0.0f; - if (gstate_c.Use(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + if (gstate_c.Use(GPU_USE_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { key.aniso = true; } break; @@ -1103,7 +1103,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) gstate_c.SetNeedShaderTexclamp(true); } - if (channel == RASTER_DEPTH && !gstate_c.Use(GPU_SUPPORTS_DEPTH_TEXTURE)) { + if (channel == RASTER_DEPTH && !gstate_c.Use(GPU_USE_DEPTH_TEXTURE)) { WARN_LOG_ONCE(ndepthtex, G3D, "Depth textures not supported, not binding"); // Flag to bind a null texture if we can't support depth textures. // Should only happen on old OpenGL. @@ -1202,7 +1202,7 @@ bool TextureCacheCommon::GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffe void TextureCacheCommon::NotifyConfigChanged() { int scaleFactor = g_Config.iTexScalingLevel; - if (!gstate_c.Use(GPU_SUPPORTS_TEXTURE_NPOT)) { + if (!gstate_c.Use(GPU_USE_TEXTURE_NPOT)) { // Reduce the scale factor to a power of two (e.g. 2 or 4) if textures must be a power of two. // TODO: In addition we should probably remove these options from the UI in this case. while ((scaleFactor & (scaleFactor - 1)) != 0) { @@ -2581,7 +2581,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt int lastW = gstate.getTextureWidth(i - 1); int lastH = gstate.getTextureHeight(i - 1); - if (gstate_c.Use(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (gstate_c.Use(GPU_USE_TEXTURE_LOD_CONTROL)) { if (tw != 1 && tw != (lastW >> 1)) plan.badMipSizes = true; else if (th != 1 && th != (lastH >> 1)) @@ -2782,7 +2782,7 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, i decPitch = stride; } - if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) { texDecFlags |= TexDecodeFlags::EXPAND32; } if (entry.status & TexCacheEntry::STATUS_CLUT_GPU) { diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 601be62a0c..45433a72d7 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -139,7 +139,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (gl_extensions.EXT_gpu_shader4) { gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); } - bool useClamp = gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH); + bool useClamp = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH); if (gl_extensions.EXT_clip_cull_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) { gl_exts.push_back("#extension GL_EXT_clip_cull_distance : enable"); } @@ -230,7 +230,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool texCoordInVec3 = false; bool vertexRangeCulling = id.Bit(VS_BIT_VERTEX_RANGE_CULLING) && !isModeThrough; - bool clipClampedDepth = !isModeThrough && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP) && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipClampedDepth = !isModeThrough && gstate_c.Use(GPU_USE_DEPTH_CLAMP) && gstate_c.Use(GPU_USE_CLIP_DISTANCE); const char *clipClampedDepthSuffix = "[0]"; const char *vertexRangeClipSuffix = clipClampedDepth ? "[1]" : "[0]"; @@ -416,7 +416,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 gl_Position : POSITION;\n"); } else { WRITE(p, " vec4 gl_Position : SV_Position;\n"); - bool clipRange = vertexRangeCulling && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipRange = vertexRangeCulling && gstate_c.Use(GPU_USE_CLIP_DISTANCE); if (clipClampedDepth && clipRange) { WRITE(p, " float2 gl_ClipDistance : SV_ClipDistance;\n"); clipClampedDepthSuffix = ".x"; @@ -426,7 +426,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag clipClampedDepthSuffix = ""; vertexRangeClipSuffix = ""; } - if (vertexRangeCulling && gstate_c.Use(GPU_SUPPORTS_CULL_DISTANCE)) { + if (vertexRangeCulling && gstate_c.Use(GPU_USE_CULL_DISTANCE)) { WRITE(p, " float2 gl_CullDistance : SV_CullDistance0;\n"); } } @@ -1306,11 +1306,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag const char *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]"; const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]"; - if (gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z. WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", compat.vsOutPrefix, vertexRangeClipSuffix); } - if (gstate_c.Use(GPU_SUPPORTS_CULL_DISTANCE)) { + if (gstate_c.Use(GPU_USE_CULL_DISTANCE)) { // Cull any triangle fully outside in the same direction when depth clamp enabled. WRITE(p, " if (u_cullRangeMin.w > 0.0) {\n"); WRITE(p, " %sgl_CullDistance%s = projPos.z - u_cullRangeMin.z;\n", compat.vsOutPrefix, cull0); diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 59e3a5a4ed..19155b0df5 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -106,23 +106,23 @@ u32 GPU_D3D11::CheckGPUFeatures() const { // Accurate depth is required because the Direct3D API does not support inverse Z. // So we cannot incorrectly use the viewport transform as the depth range on Direct3D. // TODO: Breaks text in PaRappa for some reason? - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; if (draw_->GetDeviceCaps().depthClampSupported) - features |= GPU_SUPPORTS_DEPTH_CLAMP; + features |= GPU_USE_DEPTH_CLAMP; - features |= GPU_SUPPORTS_TEXTURE_FLOAT; - features |= GPU_SUPPORTS_INSTANCE_RENDERING; - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_USE_TEXTURE_FLOAT; + features |= GPU_USE_INSTANCE_RENDERING; + features |= GPU_USE_TEXTURE_LOD_CONTROL; uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16); uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16); uint32_t fmt565 = draw_->GetDataFormatSupport(Draw::DataFormat::R5G6B5_UNORM_PACK16); if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) { - features |= GPU_SUPPORTS_16BIT_FORMATS; + features |= GPU_USE_16BIT_FORMATS; } - if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { + if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { // Use fragment rounding on desktop and GLES3, most accurate. @@ -132,7 +132,7 @@ u32 GPU_D3D11::CheckGPUFeatures() const { } // The Phantasy Star hack :( - if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_SUPPORTS_ACCURATE_DEPTH) == 0) { + if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_USE_ACCURATE_DEPTH) == 0) { features |= GPU_USE_DEPTH_RANGE_HACK; } diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 6a839e3d66..a902401122 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -202,7 +202,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { dynState_.useBlendColor = false; } - if (gstate_c.Use(GPU_SUPPORTS_LOGIC_OP)) { + if (gstate_c.Use(GPU_USE_LOGIC_OP)) { // Logic Ops if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) { keys_.blend.blendEnable = false; // Can't have both blend & logic op - although I think the PSP can! @@ -229,7 +229,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - keys_.raster.depthClipEnable = !gstate.isDepthClampEnabled() || !gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); + keys_.raster.depthClipEnable = !gstate.isDepthClampEnabled() || !gstate_c.Use(GPU_USE_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. keys_.raster.depthClipEnable = 1; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index a69dd20cd5..83c2c4869c 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -428,7 +428,7 @@ DXGI_FORMAT GetClutDestFormatD3D11(GEPaletteFormat format) { } DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { - if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS)) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS)) { return DXGI_FORMAT_B8G8R8A8_UNORM; } diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 7a69f7410d..32d9d248c4 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -100,13 +100,13 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) u32 GPU_DX9::CheckGPUFeatures() const { u32 features = GPUCommon::CheckGPUFeatures(); - features |= GPU_SUPPORTS_16BIT_FORMATS; - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_USE_16BIT_FORMATS; + features |= GPU_USE_TEXTURE_LOD_CONTROL; // Accurate depth is required because the Direct3D API does not support inverse Z. // So we cannot incorrectly use the viewport transform as the depth range on Direct3D. // TODO: Breaks text in PaRappa for some reason? - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; auto vendor = draw_->GetDeviceCaps().vendor; diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 4179c8b39d..a280c7c590 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -170,7 +170,7 @@ void TextureCacheDX9::StartFrame() { Decimate(); } - if (gstate_c.Use(GPU_SUPPORTS_ANISOTROPY)) { + if (gstate_c.Use(GPU_USE_ANISOTROPY)) { DWORD aniso = 1 << g_Config.iAnisotropyLevel; DWORD anisotropyLevel = aniso > maxAnisotropyLevel ? maxAnisotropyLevel : aniso; device_->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, anisotropyLevel); diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index e82f055424..7be1adf9d3 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -217,7 +217,7 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int DepthUB ub{}; - if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { // Don't scale anything, since we're not using factors outside accurate mode. ub.u_depthFactor[0] = 0.0f; ub.u_depthFactor[1] = 1.0f; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 2e981d0474..8bd39eadb4 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -476,7 +476,7 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { bool DrawEngineGLES::SupportsHWTessellation() const { bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; - return hasTexelFetch && gstate_c.UseAll(GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT | GPU_SUPPORTS_INSTANCE_RENDERING); + return hasTexelFetch && gstate_c.UseAll(GPU_USE_VERTEX_TEXTURE_FETCH | GPU_USE_TEXTURE_FLOAT | GPU_USE_INSTANCE_RENDERING); } bool DrawEngineGLES::UpdateUseHWTessellation(bool enable) { diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 39b9e59eb4..e71557c7ee 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -151,29 +151,29 @@ GPU_GLES::~GPU_GLES() { u32 GPU_GLES::CheckGPUFeatures() const { u32 features = GPUCommon::CheckGPUFeatures(); - features |= GPU_SUPPORTS_16BIT_FORMATS; + features |= GPU_USE_16BIT_FORMATS; if ((gl_extensions.gpuVendor == GPU_VENDOR_NVIDIA) || (gl_extensions.gpuVendor == GPU_VENDOR_AMD)) features |= GPU_PREFER_REVERSE_COLOR_ORDER; if (gl_extensions.GLES3 || !gl_extensions.IsGLES) - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_USE_TEXTURE_LOD_CONTROL; bool canUseInstanceID = gl_extensions.EXT_draw_instanced || gl_extensions.ARB_draw_instanced; bool canDefInstanceID = gl_extensions.IsGLES || gl_extensions.EXT_gpu_shader4 || gl_extensions.VersionGEThan(3, 1); bool instanceRendering = gl_extensions.GLES3 || (canUseInstanceID && canDefInstanceID); if (instanceRendering) - features |= GPU_SUPPORTS_INSTANCE_RENDERING; + features |= GPU_USE_INSTANCE_RENDERING; int maxVertexTextureImageUnits = gl_extensions.maxVertexTextureUnits; if (maxVertexTextureImageUnits >= 3) // At least 3 for hardware tessellation - features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; + features |= GPU_USE_VERTEX_TEXTURE_FETCH; if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float) - features |= GPU_SUPPORTS_TEXTURE_FLOAT; + features |= GPU_USE_TEXTURE_FLOAT; if (draw_->GetDeviceCaps().depthClampSupported) { - features |= GPU_SUPPORTS_DEPTH_CLAMP | GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH; // Our implementation of depth texturing needs simple Z range, so can't // use the extension hacks (yet). } @@ -181,13 +181,13 @@ u32 GPU_GLES::CheckGPUFeatures() const { // If we already have a 16-bit depth buffer, we don't need to round. bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; if (prefer24) { - if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { + if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { if (!gl_extensions.IsGLES || gl_extensions.GLES3) { // Use fragment rounding on desktop and GLES3, most accurate. features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } else if (prefer24 && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { + } else if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { // Here we can simulate a 16 bit depth buffer by scaling. // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; @@ -201,7 +201,7 @@ u32 GPU_GLES::CheckGPUFeatures() const { } // The Phantasy Star hack :( - if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_SUPPORTS_ACCURATE_DEPTH) == 0) { + if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_USE_ACCURATE_DEPTH) == 0) { features |= GPU_USE_DEPTH_RANGE_HACK; } diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 7d38e8df36..2148efa5fd 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -196,12 +196,12 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, initialize.push_back({ &u_tess_weights_v, 0, TEX_SLOT_SPLINE_WEIGHTS_V }); GLRProgramFlags flags{}; - flags.supportDualSource = (gstate_c.useFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) != 0; - if (!VSID.Bit(VS_BIT_IS_THROUGH) && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP)) { + flags.supportDualSource = (gstate_c.useFlags & GPU_USE_DUALSOURCE_BLEND) != 0; + if (!VSID.Bit(VS_BIT_IS_THROUGH) && gstate_c.Use(GPU_USE_DEPTH_CLAMP)) { flags.useClipDistance0 = true; - if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) + if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_USE_CLIP_DISTANCE)) flags.useClipDistance1 = true; - } else if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_SUPPORTS_CLIP_DISTANCE)) { + } else if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { flags.useClipDistance0 = true; } @@ -564,7 +564,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu float viewZScale = halfActualZRange; float viewZCenter = minz + halfActualZRange; - if (!gstate_c.Use(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { viewZScale = vpZScale; viewZCenter = vpZCenter; } diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index cbbfb72a95..0b8f45c3c6 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -209,7 +209,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { // TODO: Get rid of the ifdef #ifndef USING_GLES2 - if (gstate_c.Use(GPU_SUPPORTS_LOGIC_OP)) { + if (gstate_c.Use(GPU_USE_LOGIC_OP)) { renderManager->SetLogicOp(logicState.logicOpEnabled, logicOps[(int)logicState.logicOp]); } #endif @@ -232,7 +232,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); + depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_USE_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. depthClampEnable = false; diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 56b7f0d3b3..9584955d34 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -105,7 +105,7 @@ static const GLuint MagFiltGL[2] = { }; void TextureCacheGLES::ApplySamplingParams(const SamplerCacheKey &key) { - if (gstate_c.Use(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (gstate_c.Use(GPU_USE_TEXTURE_LOD_CONTROL)) { float minLod = (float)key.minLevel / 256.0f; float maxLod = (float)key.maxLevel / 256.0f; float lodBias = (float)key.lodBias / 256.0f; @@ -286,7 +286,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { } } - if (!gstate_c.Use(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (!gstate_c.Use(GPU_USE_TEXTURE_LOD_CONTROL)) { // If the mip chain is not full.. if (plan.levelsToCreate != plan.maxPossibleLevels) { // We need to avoid creating mips at all, or generate them all - can't be incomplete diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 5cdfd9a434..49cf93d712 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3285,44 +3285,44 @@ size_t GPUCommon::FormatGPUStatsCommon(char *buffer, size_t size) { u32 GPUCommon::CheckGPUFeatures() const { u32 features = 0; if (draw_->GetDeviceCaps().logicOpSupported) { - features |= GPU_SUPPORTS_LOGIC_OP; + features |= GPU_USE_LOGIC_OP; } if (draw_->GetDeviceCaps().anisoSupported) { - features |= GPU_SUPPORTS_ANISOTROPY; + features |= GPU_USE_ANISOTROPY; } if (draw_->GetDeviceCaps().textureNPOTFullySupported) { - features |= GPU_SUPPORTS_TEXTURE_NPOT; + features |= GPU_USE_TEXTURE_NPOT; } if (draw_->GetDeviceCaps().dualSourceBlend) { if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) { - features |= GPU_SUPPORTS_DUALSOURCE_BLEND; + features |= GPU_USE_DUALSOURCE_BLEND; } } if (draw_->GetDeviceCaps().blendMinMaxSupported) { - features |= GPU_SUPPORTS_BLEND_MINMAX; + features |= GPU_USE_BLEND_MINMAX; } if (draw_->GetDeviceCaps().clipDistanceSupported) { - features |= GPU_SUPPORTS_CLIP_DISTANCE; + features |= GPU_USE_CLIP_DISTANCE; } if (draw_->GetDeviceCaps().cullDistanceSupported) { - features |= GPU_SUPPORTS_CULL_DISTANCE; + features |= GPU_USE_CULL_DISTANCE; } if (draw_->GetDeviceCaps().textureDepthSupported) { - features |= GPU_SUPPORTS_DEPTH_TEXTURE; + features |= GPU_USE_DEPTH_TEXTURE; } bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported; bool canDiscardVertex = draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL); if (canClipOrCull || canDiscardVertex) { // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible. - features |= GPU_SUPPORTS_VS_RANGE_CULLING; + features |= GPU_USE_VS_RANGE_CULLING; } if (draw_->GetDeviceCaps().framebufferFetchSupported) { - features |= GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH; + features |= GPU_USE_ANY_FRAMEBUFFER_FETCH; } if (draw_->GetShaderLanguageDesc().bitwiseOps) { diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 052554b287..881c7b3c69 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -471,35 +471,35 @@ struct UVScale { // to centralize into flags like this. They're also fast to check since the cache line // will be hot. enum { - GPU_SUPPORTS_DUALSOURCE_BLEND = FLAG_BIT(0), + GPU_USE_DUALSOURCE_BLEND = FLAG_BIT(0), GPU_USE_LIGHT_UBERSHADER = FLAG_BIT(1), GPU_USE_FRAGMENT_TEST_CACHE = FLAG_BIT(2), - GPU_SUPPORTS_VS_RANGE_CULLING = FLAG_BIT(3), - GPU_SUPPORTS_BLEND_MINMAX = FLAG_BIT(4), - GPU_SUPPORTS_LOGIC_OP = FLAG_BIT(5), + GPU_USE_VS_RANGE_CULLING = FLAG_BIT(3), + GPU_USE_BLEND_MINMAX = FLAG_BIT(4), + GPU_USE_LOGIC_OP = FLAG_BIT(5), GPU_USE_DEPTH_RANGE_HACK = FLAG_BIT(6), // Free bit: 7 - GPU_SUPPORTS_ANISOTROPY = FLAG_BIT(8), + GPU_USE_ANISOTROPY = FLAG_BIT(8), GPU_USE_CLEAR_RAM_HACK = FLAG_BIT(9), - GPU_SUPPORTS_INSTANCE_RENDERING = FLAG_BIT(10), - GPU_SUPPORTS_VERTEX_TEXTURE_FETCH = FLAG_BIT(11), - GPU_SUPPORTS_TEXTURE_FLOAT = FLAG_BIT(12), - GPU_SUPPORTS_16BIT_FORMATS = FLAG_BIT(13), - GPU_SUPPORTS_DEPTH_CLAMP = FLAG_BIT(14), + GPU_USE_INSTANCE_RENDERING = FLAG_BIT(10), + GPU_USE_VERTEX_TEXTURE_FETCH = FLAG_BIT(11), + GPU_USE_TEXTURE_FLOAT = FLAG_BIT(12), + GPU_USE_16BIT_FORMATS = FLAG_BIT(13), + GPU_USE_DEPTH_CLAMP = FLAG_BIT(14), // Free bit: 15 - GPU_SUPPORTS_DEPTH_TEXTURE = FLAG_BIT(16), - GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17), - GPU_SUPPORTS_GS_CULLING = FLAG_BIT(18), // Geometry shader + GPU_USE_DEPTH_TEXTURE = FLAG_BIT(16), + GPU_USE_ACCURATE_DEPTH = FLAG_BIT(17), + GPU_USE_GS_CULLING = FLAG_BIT(18), // Geometry shader // Free bit: 19 - GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20), + GPU_USE_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20), GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer - GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24), + GPU_USE_TEXTURE_LOD_CONTROL = FLAG_BIT(24), // Free bits: 25-27 - GPU_SUPPORTS_TEXTURE_NPOT = FLAG_BIT(28), - GPU_SUPPORTS_CLIP_DISTANCE = FLAG_BIT(29), - GPU_SUPPORTS_CULL_DISTANCE = FLAG_BIT(30), + GPU_USE_TEXTURE_NPOT = FLAG_BIT(28), + GPU_USE_CLIP_DISTANCE = FLAG_BIT(29), + GPU_USE_CULL_DISTANCE = FLAG_BIT(30), GPU_PREFER_REVERSE_COLOR_ORDER = FLAG_BIT(31), }; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index f46b73de41..b24e4b0021 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -112,7 +112,7 @@ void DrawEngineVulkan::InitDeviceObjects() { bindings[3].descriptorCount = 1; bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; bindings[3].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - if (gstate_c.Use(GPU_SUPPORTS_GS_CULLING)) + if (gstate_c.Use(GPU_USE_GS_CULLING)) bindings[3].stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT; bindings[3].binding = DRAW_BINDING_DYNUBO_BASE; bindings[4].descriptorCount = 1; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 2ac1188824..fbc31a90e3 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -190,11 +190,11 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { switch (vulkan->GetPhysicalDeviceProperties().properties.vendorID) { case VULKAN_VENDOR_AMD: // Accurate depth is required on AMD (due to reverse-Z driver bug) so we ignore the compat flag to disable it on those. See #9545 - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; break; case VULKAN_VENDOR_QUALCOMM: // Accurate depth is required on Adreno too (seems to also have a reverse-Z driver bug). - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; break; case VULKAN_VENDOR_ARM: { @@ -206,40 +206,40 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { || VK_VERSION_MAJOR(vulkan->GetPhysicalDeviceProperties().properties.driverVersion) < 14; if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || driverTooOld) { - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; } break; } default: if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; } break; } // Might enable this later - in the first round we are mostly looking at depth/stencil/discard. // if (!g_Config.bEnableVendorBugChecks) - // features |= GPU_SUPPORTS_ACCURATE_DEPTH; + // features |= GPU_USE_ACCURATE_DEPTH; // Mandatory features on Vulkan, which may be checked in "centralized" code - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - features |= GPU_SUPPORTS_INSTANCE_RENDERING; - features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; - features |= GPU_SUPPORTS_TEXTURE_FLOAT; + features |= GPU_USE_TEXTURE_LOD_CONTROL; + features |= GPU_USE_INSTANCE_RENDERING; + features |= GPU_USE_VERTEX_TEXTURE_FETCH; + features |= GPU_USE_TEXTURE_FLOAT; auto &enabledFeatures = vulkan->GetDeviceFeatures().enabled; if (enabledFeatures.depthClamp) { - features |= GPU_SUPPORTS_DEPTH_CLAMP; + features |= GPU_USE_DEPTH_CLAMP; } // Fall back to geometry shader culling if we can't do vertex range culling. if (enabledFeatures.geometryShader) { const bool useGeometry = g_Config.bUseGeometryShader && !draw_->GetBugs().Has(Draw::Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN); const bool vertexSupported = draw_->GetDeviceCaps().clipDistanceSupported && draw_->GetDeviceCaps().cullDistanceSupported; - if (useGeometry && (!vertexSupported || (features & GPU_SUPPORTS_VS_RANGE_CULLING) == 0)) { + if (useGeometry && (!vertexSupported || (features & GPU_USE_VS_RANGE_CULLING) == 0)) { // Switch to culling via the geometry shader if not fully supported in vertex. - features |= GPU_SUPPORTS_GS_CULLING; - features &= ~GPU_SUPPORTS_VS_RANGE_CULLING; + features |= GPU_USE_GS_CULLING; + features &= ~GPU_USE_VS_RANGE_CULLING; } } @@ -252,12 +252,12 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { // if it's not available, for simplicity. uint32_t fmt565 = draw_->GetDataFormatSupport(Draw::DataFormat::B5G6R5_UNORM_PACK16); if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) { - features |= GPU_SUPPORTS_16BIT_FORMATS; + features |= GPU_USE_16BIT_FORMATS; } else { INFO_LOG(G3D, "Deficient texture format support: 4444: %d 1555: %d 565: %d", fmt4444, fmt1555, fmt565); } - if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { + if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 62ef19d868..c29d2317d9 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -232,7 +232,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_SUPPORTS_DEPTH_CLAMP); + key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_USE_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. key.depthClampEnable = false; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index f063dfa44a..c465aa31c2 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -685,7 +685,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { - if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS)) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS)) { return VK_FORMAT_R8G8B8A8_UNORM; } switch (format) { @@ -726,7 +726,7 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt int decPitch; TexDecodeFlags texDecFlags{}; - if (!gstate_c.Use(GPU_SUPPORTS_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) { texDecFlags |= TexDecodeFlags::EXPAND32; } if (entry.status & TexCacheEntry::STATUS_CLUT_GPU) { From 30aa07b1560ba7fa9af292974ef0d1a5887b937a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 08:34:03 +0200 Subject: [PATCH 035/715] Two more renames to make things read better --- GPU/Common/DrawEngineCommon.cpp | 2 +- GPU/Common/FragmentShaderGenerator.cpp | 4 ++-- GPU/Common/GPUStateUtils.cpp | 6 +++--- GPU/GLES/GPU_GLES.cpp | 2 +- GPU/GPUCommon.cpp | 2 +- GPU/GPUState.h | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 155589641a..495b206515 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -537,7 +537,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, } void DrawEngineCommon::ApplyFramebufferRead(FBOTexState *fboTexState) { - if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) { + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) { *fboTexState = FBO_TEX_READ_FRAMEBUFFER; } else { gpuStats.numCopiesForShaderBlend++; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index e465e37ad1..5fe27b19c0 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -137,8 +137,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool needFramebufferRead = replaceBlend == REPLACE_BLEND_READ_FRAMEBUFFER || colorWriteMask || replaceLogicOp; - bool fetchFramebuffer = needFramebufferRead && gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH); - bool readFramebufferTex = needFramebufferRead && !gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH); + bool fetchFramebuffer = needFramebufferRead && gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH); + bool readFramebufferTex = needFramebufferRead && !gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH); bool needFragCoord = readFramebufferTex || gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); bool writeDepth = gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 1d2ceaaca0..47d11afb4a 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -312,7 +312,7 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: // We can't technically do this correctly (due to clamping) without reading the dst color. // Using a copy isn't accurate either, though, when there's overlap. - if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; @@ -454,14 +454,14 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: if (funcA == GE_SRCBLEND_SRCALPHA || funcA == GE_SRCBLEND_INVSRCALPHA) { // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. - if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; } else { // This means dst alpha/color is used in the src factor. // Unfortunately, copying here causes overlap problems in Silent Hill games (it seems?) // We will just hope that doubling alpha for the dst factor will not clamp too badly. - if (gstate_c.Use(GPU_USE_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_2X_ALPHA; } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index e71557c7ee..c2740460db 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -154,7 +154,7 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_USE_16BIT_FORMATS; if ((gl_extensions.gpuVendor == GPU_VENDOR_NVIDIA) || (gl_extensions.gpuVendor == GPU_VENDOR_AMD)) - features |= GPU_PREFER_REVERSE_COLOR_ORDER; + features |= GPU_USE_REVERSE_COLOR_ORDER; if (gl_extensions.GLES3 || !gl_extensions.IsGLES) features |= GPU_USE_TEXTURE_LOD_CONTROL; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 49cf93d712..7a6b3fea88 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3322,7 +3322,7 @@ u32 GPUCommon::CheckGPUFeatures() const { } if (draw_->GetDeviceCaps().framebufferFetchSupported) { - features |= GPU_USE_ANY_FRAMEBUFFER_FETCH; + features |= GPU_USE_FRAMEBUFFER_FETCH; } if (draw_->GetShaderLanguageDesc().bitwiseOps) { diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 881c7b3c69..d34b824c8a 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -491,7 +491,7 @@ enum { GPU_USE_ACCURATE_DEPTH = FLAG_BIT(17), GPU_USE_GS_CULLING = FLAG_BIT(18), // Geometry shader // Free bit: 19 - GPU_USE_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20), + GPU_USE_FRAMEBUFFER_FETCH = FLAG_BIT(20), GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer @@ -500,7 +500,7 @@ enum { GPU_USE_TEXTURE_NPOT = FLAG_BIT(28), GPU_USE_CLIP_DISTANCE = FLAG_BIT(29), GPU_USE_CULL_DISTANCE = FLAG_BIT(30), - GPU_PREFER_REVERSE_COLOR_ORDER = FLAG_BIT(31), + GPU_USE_REVERSE_COLOR_ORDER = FLAG_BIT(31), }; struct KnownVertexBounds { From d5c9d15ec3931a0b00f4d6b7b09920bce8f9c3e8 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 17 Oct 2022 18:31:01 +0200 Subject: [PATCH 036/715] OpenXR - Move matrix composing out of VR tweaks --- Common/VR/PPSSPPVR.cpp | 57 ++++++++++++++++++++++++++++++++++++++---- Common/VR/VRTweaks.cpp | 50 +----------------------------------- Common/VR/VRTweaks.h | 5 ---- 3 files changed, 53 insertions(+), 59 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 7bbda32cde..b55d5d011c 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -362,9 +362,43 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { } void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { - VR_TweakProjection(projMatrix, leftEye, VR_PROJECTION_MATRIX_LEFT_EYE); - VR_TweakProjection(projMatrix, rightEye, VR_PROJECTION_MATRIX_RIGHT_EYE); - VR_TweakMirroring(projMatrix); + + // Update project matrices + float* dst[] = {leftEye, rightEye}; + VRMatrix enums[] = {VR_PROJECTION_MATRIX_LEFT_EYE, VR_PROJECTION_MATRIX_RIGHT_EYE}; + for (int index = 0; index < 2; index++) { + ovrMatrix4f hmdProjection = VR_GetMatrix(enums[index]); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if ((hmdProjection.M[i][j] > 0) != (projMatrix[i * 4 + j] > 0)) { + hmdProjection.M[i][j] *= -1.0f; + } + } + } + memcpy(dst[index], hmdProjection.M, 16 * sizeof(float)); + } + + // Set mirroring of axes + VR_SetConfig(VR_CONFIG_MIRROR_AXIS_X, projMatrix[0] < 0); + VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Y, projMatrix[5] < 0); + VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Z, projMatrix[10] > 0); + if ((projMatrix[0] < 0) && (projMatrix[10] < 0)) { //e.g. Dante's inferno + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + } else if (projMatrix[10] < 0) { //e.g. GTA - Liberty city + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, false); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + } else if (projMatrix[5] < 0) { //e.g. PES 2014 + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + } else { //e.g. Lego Pirates + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, true); + } // Set 6DoF scale float scale = pow(fabs(projMatrix[14]), 1.15f); @@ -378,6 +412,19 @@ void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { } void UpdateVRView(float* leftEye, float* rightEye) { - VR_TweakView(leftEye, VR_VIEW_MATRIX_LEFT_EYE); - VR_TweakView(rightEye, VR_VIEW_MATRIX_RIGHT_EYE); + float* dst[] = {leftEye, rightEye}; + VRMatrix enums[] = {VR_VIEW_MATRIX_LEFT_EYE, VR_VIEW_MATRIX_RIGHT_EYE}; + for (int index = 0; index < 2; index++) { + + // Get view matrix from the game + ovrMatrix4f gameView; + memcpy(gameView.M, dst[index], 16 * sizeof(float)); + + // Get view matrix from the headset + ovrMatrix4f hmdView = VR_GetMatrix(enums[index]); + + // Combine the matrices + ovrMatrix4f renderView = ovrMatrix4f_Multiply(&hmdView, &gameView); + memcpy(dst[index], renderView.M, 16 * sizeof(float)); + } } diff --git a/Common/VR/VRTweaks.cpp b/Common/VR/VRTweaks.cpp index 209ef56b6d..050e3c3b84 100644 --- a/Common/VR/VRTweaks.cpp +++ b/Common/VR/VRTweaks.cpp @@ -1,5 +1,5 @@ +#include "VRMath.h" #include "VRTweaks.h" -#include bool VR_TweakIsMatrixBigScale(float* matrix) { for (int i = 0; i < 2; i++) { @@ -43,51 +43,3 @@ bool VR_TweakIsMatrixOneTransform(float* matrix) { } return true; } - -void VR_TweakMirroring(float* projMatrix) { - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_X, projMatrix[0] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Y, projMatrix[5] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Z, projMatrix[10] > 0); - if ((projMatrix[0] < 0) && (projMatrix[10] < 0)) { //e.g. Dante's inferno - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else if (projMatrix[10] < 0) { //e.g. GTA - Liberty city - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, false); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else if (projMatrix[5] < 0) { //e.g. PES 2014 - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else { //e.g. Lego Pirates - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, true); - } -} - -void VR_TweakProjection(float* src, float* dst, VRMatrix matrix) { - ovrMatrix4f hmdProjection = VR_GetMatrix(matrix); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - if ((hmdProjection.M[i][j] > 0) != (src[i * 4 + j] > 0)) { - hmdProjection.M[i][j] *= -1.0f; - } - } - } - memcpy(dst, hmdProjection.M, 16 * sizeof(float)); -} - -void VR_TweakView(float* view, VRMatrix matrix) { - // Get view matrix from the game - ovrMatrix4f gameView; - memcpy(gameView.M, view, 16 * sizeof(float)); - - // Get view matrix from the headset - ovrMatrix4f hmdView = VR_GetMatrix(matrix); - - // Combine the matrices - ovrMatrix4f renderView = ovrMatrix4f_Multiply(&hmdView, &gameView); - memcpy(view, renderView.M, 16 * sizeof(float)); -} diff --git a/Common/VR/VRTweaks.h b/Common/VR/VRTweaks.h index 173314a86f..1cbdfe347d 100644 --- a/Common/VR/VRTweaks.h +++ b/Common/VR/VRTweaks.h @@ -1,12 +1,7 @@ #pragma once -#include "VRRenderer.h" - bool VR_TweakIsMatrixBigScale(float* matrix); bool VR_TweakIsMatrixIdentity(float* matrix); bool VR_TweakIsMatrixOneOrtho(float* matrix); bool VR_TweakIsMatrixOneScale(float* matrix); bool VR_TweakIsMatrixOneTransform(float* matrix); -void VR_TweakMirroring(float* projMatrix); -void VR_TweakProjection(float* src, float* dst, VRMatrix matrix); -void VR_TweakView(float* view, VRMatrix matrix); From 468a193d6dadc4f758fe5ac428af5dc952c56387 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 17 Oct 2022 18:52:03 +0200 Subject: [PATCH 037/715] OpenXR - Get rid of VR tweaks --- CMakeLists.txt | 2 -- Common/VR/PPSSPPVR.cpp | 23 ++++++++++++++++----- Common/VR/VRTweaks.cpp | 45 ------------------------------------------ Common/VR/VRTweaks.h | 7 ------- 4 files changed, 18 insertions(+), 59 deletions(-) delete mode 100644 Common/VR/VRTweaks.cpp delete mode 100644 Common/VR/VRTweaks.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ce455b8a..f0577780a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1106,8 +1106,6 @@ if(ANDROID) Common/VR/VRMath.h Common/VR/VRRenderer.cpp Common/VR/VRRenderer.h - Common/VR/VRTweaks.cpp - Common/VR/VRTweaks.h ) set(nativeExtraLibs ${nativeExtraLibs} openxr) endif() diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index b55d5d011c..c29a8909f8 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -350,11 +350,24 @@ bool IsFlatVRScene() { } bool Is2DVRObject(float* projMatrix, bool ortho) { - bool is2D = VR_TweakIsMatrixBigScale(projMatrix) || - VR_TweakIsMatrixIdentity(projMatrix) || - VR_TweakIsMatrixOneOrtho(projMatrix) || - VR_TweakIsMatrixOneScale(projMatrix) || - VR_TweakIsMatrixOneTransform(projMatrix); + bool isOneTransform = (fabs(fabs(projMatrix[12]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[13]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[14]) - 1.0f) < EPSILON);; + bool isOneScale = (fabs(projMatrix[0] - 1) < EPSILON) && (fabs(projMatrix[5] - 1) < EPSILON); + bool isBigScale = (fabs(projMatrix[0]) > 10.0f) && (fabs(projMatrix[5]) > 10.0f); + bool isOrtho = fabs(projMatrix[15] - 1) < EPSILON; + + bool identity = true; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + float value = projMatrix[i * 4 + j]; + + // Other number than zero on non-diagonale + if ((i != j) && (fabs(value) > EPSILON)) identity = false; + // Other number than one on diagonale + if ((i == j) && (fabs(value - 1.0f) > EPSILON)) identity = false; + } + } + + bool is2D = isBigScale || identity || isOrtho || isOneScale || isOneTransform; if (!is2D && !ortho) { VR_SetConfig(VR_CONFIG_3D_GEOMETRY_COUNT, VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) + 1); } diff --git a/Common/VR/VRTweaks.cpp b/Common/VR/VRTweaks.cpp deleted file mode 100644 index 050e3c3b84..0000000000 --- a/Common/VR/VRTweaks.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "VRMath.h" -#include "VRTweaks.h" - -bool VR_TweakIsMatrixBigScale(float* matrix) { - for (int i = 0; i < 2; i++) { - float value = matrix[i * 4 + i]; - if (fabs(value) < 10.0f) return false; - } - return true; -} - -bool VR_TweakIsMatrixIdentity(float* matrix) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - float value = matrix[i * 4 + j]; - - // Other number than zero on non-diagonale - if ((i != j) && (fabs(value) > EPSILON)) return false; - // Other number than one on diagonale - if ((i == j) && (fabs(value - 1.0f) > EPSILON)) return false; - } - } - return true; -} - -bool VR_TweakIsMatrixOneOrtho(float* matrix) { - float value = matrix[15]; - return fabs(value - 1) < EPSILON; -} - -bool VR_TweakIsMatrixOneScale(float* matrix) { - for (int i = 0; i < 2; i++) { - float value = matrix[i * 4 + i]; - if (fabs(value - 1) > EPSILON) return false; - } - return true; -} - -bool VR_TweakIsMatrixOneTransform(float* matrix) { - for (int j = 0; j < 4; j++) { - float value = matrix[12 + j]; - if (fabs(fabs(value) - 1.0f) > EPSILON) return false; - } - return true; -} diff --git a/Common/VR/VRTweaks.h b/Common/VR/VRTweaks.h deleted file mode 100644 index 1cbdfe347d..0000000000 --- a/Common/VR/VRTweaks.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -bool VR_TweakIsMatrixBigScale(float* matrix); -bool VR_TweakIsMatrixIdentity(float* matrix); -bool VR_TweakIsMatrixOneOrtho(float* matrix); -bool VR_TweakIsMatrixOneScale(float* matrix); -bool VR_TweakIsMatrixOneTransform(float* matrix); From 8ed105ff83b63dbcf684767d6ebe5150fab18da6 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 17 Oct 2022 18:57:47 +0200 Subject: [PATCH 038/715] OpenXR - Simplify projection matrix analyze --- Common/VR/PPSSPPVR.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index c29a8909f8..80bbc9a81b 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -6,7 +6,6 @@ #include "Common/VR/VRInput.h" #include "Common/VR/VRMath.h" #include "Common/VR/VRRenderer.h" -#include "Common/VR/VRTweaks.h" #include "Core/HLE/sceDisplay.h" #include "Core/Config.h" @@ -350,11 +349,19 @@ bool IsFlatVRScene() { } bool Is2DVRObject(float* projMatrix, bool ortho) { - bool isOneTransform = (fabs(fabs(projMatrix[12]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[13]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[14]) - 1.0f) < EPSILON);; - bool isOneScale = (fabs(projMatrix[0] - 1) < EPSILON) && (fabs(projMatrix[5] - 1) < EPSILON); - bool isBigScale = (fabs(projMatrix[0]) > 10.0f) && (fabs(projMatrix[5]) > 10.0f); - bool isOrtho = fabs(projMatrix[15] - 1) < EPSILON; + // Quick analyze if the object is in 2D + if ((fabs(fabs(projMatrix[12]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[13]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[14]) - 1.0f) < EPSILON)) { + return true; + } else if ((fabs(projMatrix[0] - 1) < EPSILON) && (fabs(projMatrix[5] - 1) < EPSILON)) { + return true; + } else if ((fabs(projMatrix[0]) > 10.0f) && (fabs(projMatrix[5]) > 10.0f)) { + return true; + } else if (fabs(projMatrix[15] - 1) < EPSILON) { + return true; + } + + // Chceck if the projection matrix is identity bool identity = true; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -367,11 +374,11 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { } } - bool is2D = isBigScale || identity || isOrtho || isOneScale || isOneTransform; - if (!is2D && !ortho) { + // Update 3D geometry count + if (!identity && !ortho) { VR_SetConfig(VR_CONFIG_3D_GEOMETRY_COUNT, VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) + 1); } - return is2D; + return identity; } void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { From 1a6180583e8d801e67562e0136707de1b2e4dad8 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 17 Oct 2022 19:00:38 +0200 Subject: [PATCH 039/715] OpenXR - Reduce uniform calls --- GPU/GLES/ShaderManagerGLES.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 2148efa5fd..1c7bd4296b 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -363,10 +363,6 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu u64 dirty = dirtyUniforms & availableUniforms; dirtyUniforms = 0; - if (IsVRBuild()) { - dirty |= DIRTY_VIEWMATRIX; - SetVRCompat(VR_COMPAT_FOG_COLOR, gstate.fogcolor); - } if (!dirty) return; @@ -459,6 +455,9 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } if (dirty & DIRTY_FOGCOLOR) { SetColorUniform3(render_, &u_fogcolor, gstate.fogcolor); + if (IsVRBuild()) { + SetVRCompat(VR_COMPAT_FOG_COLOR, gstate.fogcolor); + } } if (dirty & DIRTY_FOGCOEF) { float fogcoef[2] = { From be2613d495dd903eea8c0e7e480bb03d63702f71 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 17 Oct 2022 19:07:27 +0200 Subject: [PATCH 040/715] OpenXR - Move VR passes count calculation --- Common/GPU/OpenGL/GLRenderManager.cpp | 7 +------ Common/GPU/Vulkan/VulkanRenderManager.cpp | 7 +------ Common/VR/PPSSPPVR.cpp | 8 ++++++++ Common/VR/PPSSPPVR.h | 2 ++ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index 01cccb8874..bca19e274f 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -5,8 +5,6 @@ #include "Common/Thread/ThreadUtil.h" #include "Common/VR/PPSSPPVR.h" -#include "Core/Config.h" - #include "Common/Log.h" #include "Common/MemoryUtil.h" #include "Common/Math/math_util.h" @@ -580,10 +578,7 @@ void GLRenderManager::Run(int frame) { } if (IsVRBuild()) { - int passes = 1; - if (!IsMultiviewSupported() && g_Config.bEnableStereo) { - passes = 2; - } + int passes = GetVRPassesCount(); for (int i = 0; i < passes; i++) { PreVRFrameRender(i); queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, i < passes - 1); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 4e248a0077..66f3e287e9 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -14,8 +14,6 @@ #include "Common/Thread/ThreadUtil.h" #include "Common/VR/PPSSPPVR.h" -#include "Core/Config.h" - #if 0 // def _DEBUG #define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__) #else @@ -1282,10 +1280,7 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { frameData.skipSwap = true; //queueRunner_.LogSteps(stepsOnThread, false); if (IsVRBuild()) { - int passes = 1; - if (!IsMultiviewSupported() && g_Config.bEnableStereo) { - passes = 2; - } + int passes = GetVRPassesCount(); for (int i = 0; i < passes; i++) { PreVRFrameRender(i); queueRunner_.RunSteps(task.steps, frameData, frameDataShared_, i < passes - 1); diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 80bbc9a81b..a0807b049a 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -339,6 +339,14 @@ int GetVRFBOIndex() { return VR_GetConfig(VR_CONFIG_CURRENT_FBO); } +int GetVRPassesCount() { + if (!IsMultiviewSupported() && g_Config.bEnableStereo) { + return 2; + } else { + return 1; + } +} + bool IsMultiviewSupported() { return false; } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index a7b5d8420d..91f5862ff0 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -38,6 +38,7 @@ void FinishVRRender(); void PreVRFrameRender(int fboIndex); void PostVRFrameRender(); int GetVRFBOIndex(); +int GetVRPassesCount(); bool IsMultiviewSupported(); bool IsFlatVRScene(); bool Is2DVRObject(float* projMatrix, bool ortho); @@ -65,6 +66,7 @@ inline void FinishVRRender() {} inline void PreVRFrameRender(int fboIndex) {} inline void PostVRFrameRender() {} inline int GetVRFBOIndex() { return 0; } +inline int GetVRPassesCount() { return 1; } inline bool IsMultiviewSupported() { return false; } inline bool IsFlatVRScene() { return true; } inline bool Is2DVRObject(float* projMatrix, bool ortho) { return false; } From 7c5fc3ccb50cbf0cf17dd19d39d4462e8b82000f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 09:34:26 +0200 Subject: [PATCH 041/715] Reorder the GPU USE flags a bit --- GPU/GLES/DrawEngineGLES.cpp | 1 + GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/GPUState.h | 14 +++++--------- GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 8bd39eadb4..dd3395abd2 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -474,6 +474,7 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } +// TODO: Refactor this to a single USE flag. bool DrawEngineGLES::SupportsHWTessellation() const { bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; return hasTexelFetch && gstate_c.UseAll(GPU_USE_VERTEX_TEXTURE_FETCH | GPU_USE_TEXTURE_FLOAT | GPU_USE_INSTANCE_RENDERING); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 1c7bd4296b..055d626b28 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -935,7 +935,7 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT // as sometimes these features might have an effect on the ID bits. #define CACHE_HEADER_MAGIC 0x83277592 -#define CACHE_VERSION 15 +#define CACHE_VERSION 16 struct CacheHeader { uint32_t magic; uint32_t version; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index d34b824c8a..272b39d70e 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -478,7 +478,7 @@ enum { GPU_USE_BLEND_MINMAX = FLAG_BIT(4), GPU_USE_LOGIC_OP = FLAG_BIT(5), GPU_USE_DEPTH_RANGE_HACK = FLAG_BIT(6), - // Free bit: 7 + GPU_USE_TEXTURE_NPOT = FLAG_BIT(7), GPU_USE_ANISOTROPY = FLAG_BIT(8), GPU_USE_CLEAR_RAM_HACK = FLAG_BIT(9), GPU_USE_INSTANCE_RENDERING = FLAG_BIT(10), @@ -486,21 +486,17 @@ enum { GPU_USE_TEXTURE_FLOAT = FLAG_BIT(12), GPU_USE_16BIT_FORMATS = FLAG_BIT(13), GPU_USE_DEPTH_CLAMP = FLAG_BIT(14), - // Free bit: 15 + GPU_USE_TEXTURE_LOD_CONTROL = FLAG_BIT(15), GPU_USE_DEPTH_TEXTURE = FLAG_BIT(16), GPU_USE_ACCURATE_DEPTH = FLAG_BIT(17), GPU_USE_GS_CULLING = FLAG_BIT(18), // Geometry shader - // Free bit: 19 + GPU_USE_REVERSE_COLOR_ORDER = FLAG_BIT(19), GPU_USE_FRAMEBUFFER_FETCH = FLAG_BIT(20), GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer - GPU_USE_TEXTURE_LOD_CONTROL = FLAG_BIT(24), - // Free bits: 25-27 - GPU_USE_TEXTURE_NPOT = FLAG_BIT(28), - GPU_USE_CLIP_DISTANCE = FLAG_BIT(29), - GPU_USE_CULL_DISTANCE = FLAG_BIT(30), - GPU_USE_REVERSE_COLOR_ORDER = FLAG_BIT(31), + GPU_USE_CLIP_DISTANCE = FLAG_BIT(24), + GPU_USE_CULL_DISTANCE = FLAG_BIT(25), }; struct KnownVertexBounds { diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 97eb00c490..72a20476c0 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -482,7 +482,7 @@ VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 29 +#define CACHE_VERSION 30 struct VulkanCacheHeader { uint32_t magic; uint32_t version; From aa51bfd1eff73f8a8c022aafbd6d84d859600513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 18:36:54 +0200 Subject: [PATCH 042/715] Use GPU "use" flags to replace IsVRBuild in the renderer. It remains elsewhere. --- Common/Common.vcxproj | 77 +++++++++++++++++++++++++++ Common/Common.vcxproj.filters | 45 ++++++++++++++++ Common/GPU/OpenGL/GLQueueRunner.cpp | 2 +- Common/GPU/OpenGL/GLQueueRunner.h | 2 +- Common/GPU/OpenGL/GLRenderManager.cpp | 4 +- Common/GPU/Vulkan/VulkanLoader.cpp | 3 +- GPU/Common/PresentationCommon.cpp | 16 +++--- GPU/Common/VertexShaderGenerator.cpp | 26 ++++----- GPU/GLES/GPU_GLES.cpp | 8 +++ GPU/GLES/ShaderManagerGLES.cpp | 13 +++-- GPU/GPUState.h | 5 ++ UI/NativeApp.cpp | 1 - 12 files changed, 168 insertions(+), 34 deletions(-) diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index aa0f9bb1e7..e5e6a5530a 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -557,6 +557,13 @@ + + + + + + + @@ -989,6 +996,76 @@ + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 0cb9e79423..e04ecff0c8 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -425,6 +425,27 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + @@ -803,6 +824,27 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + @@ -907,6 +949,9 @@ {7b17065c-729c-47c3-a02d-66dc383529dd} + + {9d1c29fd-8ac7-4475-8ea6-c8c759b695fe} + diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 47874252e3..84f1b1a375 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -648,7 +648,7 @@ retry_depth: currentReadHandle_ = fbo->handle; } -void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps) { +void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps, bool useVR) { if (skipGLCalls) { if (keepSteps) { return; diff --git a/Common/GPU/OpenGL/GLQueueRunner.h b/Common/GPU/OpenGL/GLQueueRunner.h index 1e009787ae..e9ad214eb4 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.h +++ b/Common/GPU/OpenGL/GLQueueRunner.h @@ -363,7 +363,7 @@ public: void RunInitSteps(const std::vector &steps, bool skipGLCalls); - void RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps = false); + void RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps, bool useVR); void LogSteps(const std::vector &steps); void CreateDeviceObjects(); diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index bca19e274f..c3d14bb4a7 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -581,11 +581,11 @@ void GLRenderManager::Run(int frame) { int passes = GetVRPassesCount(); for (int i = 0; i < passes; i++) { PreVRFrameRender(i); - queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, i < passes - 1); + queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, i < passes - 1, true); PostVRFrameRender(); } } else { - queueRunner_.RunSteps(stepsOnThread, skipGLCalls_); + queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, false, false); } stepsOnThread.clear(); diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index b0c2ab370b..52ece65731 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -308,8 +308,7 @@ void VulkanSetAvailable(bool available) { } bool VulkanMayBeAvailable() { - - //unsupported in VR at the moment + // Unsupported in VR at the moment if (IsVRBuild()) { return false; } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index e430374079..b771342e49 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -74,19 +74,21 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f bool rotated = rotation == ROTATION_LOCKED_VERTICAL || rotation == ROTATION_LOCKED_VERTICAL180; + SmallDisplayZoom zoomType = (SmallDisplayZoom)g_Config.iSmallDisplayZoomType; + if (IsVRBuild()) { if (IsFlatVRScene()) { - g_Config.iSmallDisplayZoomType = (int)SmallDisplayZoom::AUTO; + zoomType = SmallDisplayZoom::AUTO; } else { - g_Config.iSmallDisplayZoomType = (int)SmallDisplayZoom::STRETCH; + zoomType = SmallDisplayZoom::STRETCH; } } - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::STRETCH) { + if (zoomType == SmallDisplayZoom::STRETCH) { outW = frame.w; outH = frame.h; } else { - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::MANUAL) { + if (zoomType == SmallDisplayZoom::MANUAL) { float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frame.w + frame.x; float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frame.h + frame.y; // Have to invert Y for GL @@ -109,7 +111,7 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f rc->h = floorf(smallDisplayW); return; } - } else if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { + } else if (zoomType == SmallDisplayZoom::AUTO) { // Stretch to 1080 for 272*4. But don't distort if not widescreen (i.e. ultrawide of halfwide.) float pixelCrop = frame.h / 270.0f; float resCommonWidescreen = pixelCrop - floor(pixelCrop); @@ -130,13 +132,13 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f outW = frame.w; outH = frame.w / origRatio; // Stretch a little bit - if (!rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) + if (!rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH) outH = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 } else { // Image is taller than frame. Center horizontally. outW = frame.h * origRatio; outH = frame.h; - if (rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) + if (rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH) outW = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 } } diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 45433a72d7..64258d1103 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -23,7 +23,6 @@ #include "Common/GPU/OpenGL/GLFeatures.h" #include "Common/GPU/ShaderWriter.h" #include "Common/GPU/thin3d.h" -#include "Common/VR/PPSSPPVR.h" #include "Core/Config.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -149,10 +148,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (gl_extensions.ARB_cull_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) { gl_exts.push_back("#extension GL_ARB_cull_distance : enable"); } + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + gl_exts.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;"); + } } - if (IsVRBuild() && IsMultiviewSupported()) { - gl_exts.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;"); - } + ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts.data(), gl_exts.size()); bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); @@ -480,8 +480,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "uniform mat4 u_proj_through;\n"); *uniformMask |= DIRTY_PROJTHROUGHMATRIX; } else if (useHWTransform) { - if (IsVRBuild()) { - if (IsMultiviewSupported()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { WRITE(p, "layout(shared) uniform ProjectionMatrix { uniform mat4 u_proj_lens[2]; };\n"); } else { WRITE(p, "uniform mat4 u_proj_lens;\n"); @@ -495,7 +495,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // When transforming by hardware, we need a great deal more uniforms... // TODO: Use 4x3 matrices where possible. Though probably doesn't matter much. WRITE(p, "uniform mat4 u_world;\n"); - if (IsVRBuild() && IsMultiviewSupported()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { WRITE(p, "layout(shared) uniform ViewMatrices { uniform mat4 u_view[2]; };\n"); } else { WRITE(p, "uniform mat4 u_view;\n"); @@ -560,7 +560,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "uniform lowp float u_rotation;\n"); } - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, "uniform lowp float u_scaleX;\n"); WRITE(p, "uniform lowp float u_scaleY;\n"); } @@ -920,7 +920,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } std::string matrixPostfix; - if (IsVRBuild() && IsMultiviewSupported()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { matrixPostfix = "[gl_ViewID_OVR]"; } @@ -928,14 +928,14 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // Final view and projection transforms. if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj_lens%s, viewPos));\n", matrixPostfix.c_str()); WRITE(p, " vec4 orgPos = depthRoundZVP(mul(u_proj, viewPos));\n"); } else { WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj, viewPos));\n"); } } else { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, " vec4 outPos = mul(u_proj_lens%s, viewPos);\n", matrixPostfix.c_str()); WRITE(p, " vec4 orgPos = mul(u_proj, viewPos);\n"); } else { @@ -1284,7 +1284,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " }\n"); } - if (vertexRangeCulling && !IsVRBuild()) { + if (vertexRangeCulling && !gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n"); WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n"); @@ -1325,7 +1325,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // We've named the output gl_Position in HLSL as well. WRITE(p, " %sgl_Position = outPos;\n", compat.vsOutPrefix); - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { // Z correction for the depth buffer if (useHWTransform) { WRITE(p, " %sgl_Position.z = orgPos.z / abs(orgPos.w) * abs(outPos.w);\n", compat.vsOutPrefix); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index c2740460db..b6b2b6a661 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -22,6 +22,7 @@ #include "Common/Serialize/Serializer.h" #include "Common/File/FileUtil.h" #include "Common/GraphicsContext.h" +#include "Common/VR/PPSSPPVR.h" #include "Core/Config.h" #include "Core/Debugger/Breakpoints.h" @@ -209,6 +210,13 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_USE_FRAGMENT_TEST_CACHE; } + if (IsVRBuild()) { + features |= GPU_USE_VIRTUAL_REALITY; + } + if (IsMultiviewSupported()) { + features |= GPU_USE_SINGLE_PASS_STEREO; + } + return features; } diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 055d626b28..db721ab475 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -130,10 +130,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_cullRangeMax, "u_cullRangeMax" }); queries.push_back({ &u_rotation, "u_rotation" }); - if (IsVRBuild()) { - queries.push_back({ &u_scaleX, "u_scaleX" }); - queries.push_back({ &u_scaleY, "u_scaleY" }); - } + // These two are only used for VR, but let's always query them for simplicity. + queries.push_back({ &u_scaleX, "u_scaleX" }); + queries.push_back({ &u_scaleY, "u_scaleY" }); #ifdef USE_BONE_ARRAY queries.push_back({ &u_bone, "u_bone" }); @@ -378,7 +377,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } bool is2D, flatScreen; - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { // Analyze scene is2D = Is2DVRObject(gstate.projMatrix, gstate.isModeThrough()); flatScreen = IsFlatVRScene(); @@ -402,7 +401,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu // Update any dirty uniforms before we draw if (dirty & DIRTY_PROJMATRIX) { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { Matrix4x4 leftEyeMatrix, rightEyeMatrix; if (flatScreen || is2D) { memcpy(&leftEyeMatrix, gstate.projMatrix, 16 * sizeof(float)); @@ -536,7 +535,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu SetMatrix4x3(render_, &u_world, gstate.worldMatrix); } if (dirty & DIRTY_VIEWMATRIX) { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { float leftEyeView[16]; float rightEyeView[16]; ConvertMatrix4x3To4x4Transposed(leftEyeView, gstate.viewMatrix); diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 272b39d70e..e7a15e9536 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -497,6 +497,11 @@ enum { GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer GPU_USE_CLIP_DISTANCE = FLAG_BIT(24), GPU_USE_CULL_DISTANCE = FLAG_BIT(25), + + // VR flags (reserved or in-use) + GPU_USE_VIRTUAL_REALITY = FLAG_BIT(29), + GPU_USE_SINGLE_PASS_STEREO = FLAG_BIT(30), + GPU_USE_SIMPLE_STEREO_PERSPECTIVE = FLAG_BIT(31), }; struct KnownVertexBounds { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 93b11fd53e..36ce962ea4 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1296,7 +1296,6 @@ bool NativeTouch(const TouchInput &touch) { } bool NativeKey(const KeyInput &key) { - // Hack to quickly enable 2D mode in VR game mode. if (IsVRBuild()) { UpdateVRScreenKey(key); From 70488be450eb9eb6a4b4edfcee6cef6f60595936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 18:39:02 +0200 Subject: [PATCH 043/715] Make as much as possible of the VR code build on all platforms --- CMakeLists.txt | 29 +++++------ Common/Common.vcxproj | 95 ++++++----------------------------- Common/Common.vcxproj.filters | 8 +-- Common/VR/PPSSPPVR.cpp | 6 +++ Common/VR/VRBase.cpp | 7 ++- Common/VR/VRBase.h | 32 +++++++++++- Common/VR/VRFramebuffer.cpp | 33 +++++++++--- Common/VR/VRFramebuffer.h | 2 +- Common/VR/VRInput.cpp | 23 +++------ Common/VR/VRMath.cpp | 5 ++ Common/VR/VRRenderer.cpp | 12 +++-- android/jni/Android.mk | 9 ++++ libretro/Makefile.common | 8 +++ 13 files changed, 136 insertions(+), 133 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0577780a6..b8b323d4ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1092,21 +1092,22 @@ if(ANDROID) android/jni/OpenSLContext.h ) + set(nativeExtra ${nativeExtra} + Common/VR/PPSSPPVR.cpp + Common/VR/PPSSPPVR.h + Common/VR/VRBase.cpp + Common/VR/VRBase.h + Common/VR/VRFramebuffer.cpp + Common/VR/VRFramebuffer.h + Common/VR/VRInput.cpp + Common/VR/VRInput.h + Common/VR/VRMath.cpp + Common/VR/VRMath.h + Common/VR/VRRenderer.cpp + Common/VR/VRRenderer.h + ) + if (OPENXR) - set(nativeExtra ${nativeExtra} - Common/VR/PPSSPPVR.cpp - Common/VR/PPSSPPVR.h - Common/VR/VRBase.cpp - Common/VR/VRBase.h - Common/VR/VRFramebuffer.cpp - Common/VR/VRFramebuffer.h - Common/VR/VRInput.cpp - Common/VR/VRInput.h - Common/VR/VRMath.cpp - Common/VR/VRMath.h - Common/VR/VRRenderer.cpp - Common/VR/VRRenderer.h - ) set(nativeExtraLibs ${nativeExtraLibs} openxr) endif() # No target diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index e5e6a5530a..5c085bd0ed 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -136,7 +136,7 @@ _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) Common/DbgNew.h MultiThreadedDebug - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib StreamingSIMDExtensions2 Precise true @@ -162,7 +162,7 @@ Common/DbgNew.h MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib NotSet Precise false @@ -189,7 +189,7 @@ Common/DbgNew.h MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib NotSet Precise false @@ -217,7 +217,7 @@ MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib NotSet Precise false @@ -250,7 +250,7 @@ false StreamingSIMDExtensions2 Precise - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib Speed true false @@ -280,7 +280,7 @@ USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib false NotSet Precise @@ -315,7 +315,7 @@ USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib false NotSet Precise @@ -350,7 +350,7 @@ USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib false NotSet Precise @@ -563,7 +563,6 @@ - @@ -996,76 +995,12 @@ - - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - + + + + + + @@ -1080,4 +1015,4 @@ - \ No newline at end of file + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index e04ecff0c8..5c58a6453f 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -443,9 +443,6 @@ VR - - VR - @@ -842,9 +839,6 @@ VR - - VR - @@ -958,4 +952,4 @@ ext\libpng17 - \ No newline at end of file + diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index a0807b049a..abbd78cfdf 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -12,6 +12,8 @@ #include "Core/KeyMap.h" #include "Core/System.h" +#ifdef OPENXR + static long vrCompat[VR_COMPAT_MAX]; /* @@ -99,6 +101,7 @@ bool IsVRBuild() { return true; } +#if PPSSPP_PLATFORM(ANDROID) void InitVROnAndroid(void* vm, void* activity, int version, const char* name) { bool useVulkan = (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN; @@ -111,6 +114,7 @@ void InitVROnAndroid(void* vm, void* activity, int version, const char* name) { __DisplaySetFramerate(72); } +#endif void EnterVR(bool firstStart, void* vulkanContext) { if (firstStart) { @@ -456,3 +460,5 @@ void UpdateVRView(float* leftEye, float* rightEye) { memcpy(dst[index], renderView.M, 16 * sizeof(float)); } } + +#endif diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index abbad01d78..687506aeb5 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -3,9 +3,12 @@ #include #include #include -#include #include +#if PPSSPP_PLATFORM(ANDROID) + +#include + #ifdef OPENXR_PLATFORM_PICO enum ConfigsSetEXT { UNREAL_VERSION = 0, @@ -248,3 +251,5 @@ void VR_LeaveVR( engine_t* engine ) { engine_t* VR_GetEngine( void ) { return &vr_engine; } + +#endif diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 5f9016d7cd..4caa9417ba 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -1,10 +1,14 @@ #pragma once -#ifdef ANDROID +#include "ppsspp_config.h" + +// TODO: Switch to PPSSPP logging +#if PPSSPP_PLATFORM(ANDROID) #include #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "OpenXR", __VA_ARGS__); #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "OpenXR", __VA_ARGS__); #else +#include #define ALOGE(...) printf(__VA_ARGS__) #define ALOGV(...) printf(__VA_ARGS__) #endif @@ -17,6 +21,7 @@ using namespace PPSSPP_VK; #endif +#if PPSSPP_PLATFORM(ANDROID) //OpenXR #define XR_USE_PLATFORM_ANDROID 1 #define XR_USE_GRAPHICS_API_OPENGL_ES 1 @@ -24,13 +29,29 @@ using namespace PPSSPP_VK; #include #include #include +#elif PPSSPP_PLATFORM(WINDOWS) +#include "Common/CommonWindows.h" +#include +#define XR_USE_PLATFORM_WIN32 1 +#define XR_USE_GRAPHICS_API_OPENGL_ES 1 +#define XR_USE_GRAPHICS_API_VULKAN 1 +#else +#define XR_USE_GRAPHICS_API_OPENGL_ES 1 +#define XR_USE_GRAPHICS_API_VULKAN 1 +#endif + #include #include #include + +#if PPSSPP_PLATFORM(ANDROID) + #include #include -#ifdef _DEBUG +#endif + +#if defined(_DEBUG) && PPSSPP_PLATFORM(ANDROID) static const char* GlErrorString(GLenum error) { switch (error) { case GL_NO_ERROR: @@ -148,6 +169,7 @@ typedef struct { ovrRenderer Renderer; } ovrApp; +#if PPSSPP_PLATFORM(ANDROID) typedef struct { JavaVM* Vm; jobject ActivityObject; @@ -155,17 +177,23 @@ typedef struct { char AppName[64]; int AppVersion; } ovrJava; +#endif typedef struct { uint64_t frameIndex; ovrApp appState; +#if PPSSPP_PLATFORM(ANDROID) ovrJava java; +#endif float predictedDisplayTime; bool useVulkan; XrGraphicsBindingVulkanKHR graphicsBindingVulkan; } engine_t; +#if PPSSPP_PLATFORM(ANDROID) void VR_Init( ovrJava java, bool useVulkan ); +#endif + void VR_Destroy( engine_t* engine ); void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ); void VR_LeaveVR( engine_t* engine ); diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 742e9457c6..8e7828ded8 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -1,14 +1,17 @@ #include "VRFramebuffer.h" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include + +#if PPSSPP_PLATFORM(ANDROID) #include #include -#include +#endif double FromXrTime(const XrTime time) { return (time * 1e-9); @@ -41,6 +44,8 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = false; } +#if PPSSPP_PLATFORM(ANDROID) + bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { frameBuffer->Width = width; @@ -133,6 +138,8 @@ bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int return true; } +#endif + bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview, void* context) { @@ -248,8 +255,10 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { delete[] frameBuffer->VKDepthImages; delete[] frameBuffer->VKFrameBuffers; } else { +#if PPSSPP_PLATFORM(ANDROID) GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); free(frameBuffer->GLFrameBuffers); +#endif } OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle)); OXR(xrDestroySwapchain(frameBuffer->DepthSwapChain.Handle)); @@ -263,7 +272,9 @@ void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { return frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { +#if PPSSPP_PLATFORM(ANDROID) GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); +#endif return nullptr; } } @@ -293,6 +304,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { //TODO:implement } else { +#if PPSSPP_PLATFORM(ANDROID) GL(glEnable( GL_SCISSOR_TEST )); GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); @@ -300,6 +312,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { GL(glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )); GL(glScissor( 0, 0, 0, 0 )); GL(glDisable( GL_SCISSOR_TEST )); +#endif } } @@ -313,10 +326,12 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { //TODO:implement } else { +#if PPSSPP_PLATFORM(ANDROID) GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL(glClear(GL_COLOR_BUFFER_BIT)); GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)); +#endif } } } @@ -342,7 +357,9 @@ void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int if (vulkanContext) { ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, multiview, vulkanContext); } else { +#if PPSSPP_PLATFORM(ANDROID) ovrFramebuffer_CreateGL(session, &renderer->FrameBuffer[i], width, height, multiview); +#endif } } } @@ -358,12 +375,14 @@ void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { if (renderer->FrameBuffer[0].UseVulkan) { //TODO:implement } else { +#if PPSSPP_PLATFORM(ANDROID) GL(glEnable(GL_SCISSOR_TEST)); GL(glScissor(x, y, size, size)); GL(glViewport(x, y, size, size)); GL(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); GL(glClear(GL_COLOR_BUFFER_BIT)); GL(glDisable(GL_SCISSOR_TEST)); +#endif } } diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index 644a28fe4c..5dd455fd16 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -1,6 +1,6 @@ #pragma once -#include "VR/VRBase.h" +#include "Common/VR/VRBase.h" void ovrApp_Clear(ovrApp* app); void ovrApp_Destroy(ovrApp* app); diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index 2fc8816f61..e07c44fcda 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -1,6 +1,7 @@ #include "VRInput.h" #include -#include + +#include //OpenXR XrPath leftHandPath; @@ -41,20 +42,11 @@ float vibration_channel_intensity[2] = {0.0f, 0.0f}; unsigned long sys_timeBase = 0; int milliseconds(void) { - struct timeval tp; - - gettimeofday(&tp, NULL); - - if (!sys_timeBase) { - sys_timeBase = tp.tv_sec; - return tp.tv_usec/1000; - } - - return (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000; + return (int)(1000.0 * time_now_d()); } XrTime ToXrTime(const double timeInSeconds) { - return (timeInSeconds * 1e9); + return (XrTime)(timeInSeconds * 1e9); } void INVR_Vibrate( int duration, int chan, float intensity ) { @@ -67,16 +59,15 @@ void INVR_Vibrate( int duration, int chan, float intensity ) { if (vibration_channel_duration[channel] == -1.0f && duration != 0.0f) return; - vibration_channel_duration[channel] = duration; + vibration_channel_duration[channel] = (float)duration; vibration_channel_intensity[channel] = intensity; } } } - void VR_processHaptics() { float lastFrameTime = 0.0f; - float timestamp = (float)(milliseconds( )); + float timestamp = (float)(milliseconds()); float frametime = timestamp - lastFrameTime; lastFrameTime = timestamp; @@ -438,6 +429,6 @@ XrPosef IN_VRGetPose( int controllerIndex ) { XrSpaceLocation loc = {}; loc.type = XR_TYPE_SPACE_LOCATION; XrSpace aimSpace[] = { leftControllerAimSpace, rightControllerAimSpace }; - xrLocateSpace(aimSpace[controllerIndex], engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc); + xrLocateSpace(aimSpace[controllerIndex], engine->appState.CurrentSpace, (XrTime)(engine->predictedDisplayTime), &loc); return loc.pose; } diff --git a/Common/VR/VRMath.cpp b/Common/VR/VRMath.cpp index 204e591fad..df9512d186 100644 --- a/Common/VR/VRMath.cpp +++ b/Common/VR/VRMath.cpp @@ -1,5 +1,10 @@ +#include + #include "VRMath.h" +#include "Common/Math/math_util.h" + + float ToDegrees(float rad) { return (float)(rad / M_PI * 180.0f); } diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 64c388df07..08f44749e4 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -2,9 +2,11 @@ #include "VRInput.h" #include "VRRenderer.h" -#include -#include -#include +#include "Common/Math/math_util.h" + +#include +#include +#include XrFovf fov; XrView* projections; @@ -301,8 +303,8 @@ bool VR_InitFrame( engine_t* engine ) { // Update matrices for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) { - float near = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f; - vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, near, 0.0f ); + float nearPlane = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f; + vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, nearPlane, 0.0f ); } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { XrPosef invView = invViewTransform[0]; diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 305caf67a5..333733382e 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -71,6 +71,14 @@ SPIRV_CROSS_FILES := \ $(SRC)/ext/SPIRV-Cross/spirv_parser.cpp \ $(SRC)/ext/SPIRV-Cross/spirv_cross_parsed_ir.cpp +VR_FILES := \ + $(SRC)/Common/VR/PPSSPPVR.cpp \ + $(SRC)/Common/VR/VRBase.cpp \ + $(SRC)/Common/VR/VRFramebuffer.cpp \ + $(SRC)/Common/VR/VRInput.cpp \ + $(SRC)/Common/VR/VRMath.cpp \ + $(SRC)/Common/VR/VRRenderer.cpp + EXT_FILES := \ $(SRC)/ext/cityhash/city.cpp \ $(SRC)/ext/libpng17/png.c \ @@ -115,6 +123,7 @@ EXEC_AND_LIB_FILES := \ $(ARCH_FILES) \ $(EGL_FILES) \ $(VULKAN_FILES) \ + $(VR_FILES) \ $(VMA_FILES) \ $(SPIRV_CROSS_FILES) \ $(EXT_FILES) \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 375792b296..014579eec4 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -314,6 +314,14 @@ SOURCES_CXX += \ $(COMMONDIR)/StringUtils.cpp \ $(COMMONDIR)/TimeUtil.cpp +SOURCES_CXX += \ + $(COMMONDIR)/VRBase.cpp \ + $(COMMONDIR)/VRMath.cpp \ + $(COMMONDIR)/VRFramebuffer.cpp \ + $(COMMONDIR)/VRInput.cpp \ + $(COMMONDIR)/VRMath.cpp \ + $(COMMONDIR)/VRRenderer.cpp + SOURCES_C +=\ $(COMMONDIR)/GPU/OpenGL/gl3stub.c \ $(COMMONDIR)/Math/fast/fast_matrix.c From 2ac0b6d8c1120f393b17afdad9592f2fbdff1e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 19:25:55 +0200 Subject: [PATCH 044/715] CMakeLists.txt fix --- CMakeLists.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8b323d4ee..b9084bea3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,7 +119,6 @@ add_definitions(-DASSETS_DIR="${CMAKE_INSTALL_FULL_DATADIR}/ppsspp/assets/") if(OPENXR) add_definitions(-DOPENXR) add_library(openxr SHARED IMPORTED) - include_directories(ext/openxr) if(OPENXR_PLATFORM_PICO) add_definitions(-DOPENXR_PLATFORM_PICO) set_property(TARGET openxr PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so") @@ -507,6 +506,22 @@ if(WIN32) ) endif() +set(CommonVR + Common/VR/PPSSPPVR.cpp + Common/VR/PPSSPPVR.h + Common/VR/VRBase.cpp + Common/VR/VRBase.h + Common/VR/VRFramebuffer.cpp + Common/VR/VRFramebuffer.h + Common/VR/VRInput.cpp + Common/VR/VRInput.h + Common/VR/VRMath.cpp + Common/VR/VRMath.h + Common/VR/VRRenderer.cpp + Common/VR/VRRenderer.h +) +include_directories(ext/openxr) + add_library(Common STATIC ${CommonX86} ${CommonARM} @@ -514,6 +529,7 @@ add_library(Common STATIC ${CommonMIPS} ${CommonRISCV64} ${CommonD3D} + ${CommonVR} Common/Serialize/Serializer.cpp Common/Serialize/Serializer.h Common/Serialize/SerializeDeque.h @@ -1091,22 +1107,6 @@ if(ANDROID) android/jni/OpenSLContext.cpp android/jni/OpenSLContext.h ) - - set(nativeExtra ${nativeExtra} - Common/VR/PPSSPPVR.cpp - Common/VR/PPSSPPVR.h - Common/VR/VRBase.cpp - Common/VR/VRBase.h - Common/VR/VRFramebuffer.cpp - Common/VR/VRFramebuffer.h - Common/VR/VRInput.cpp - Common/VR/VRInput.h - Common/VR/VRMath.cpp - Common/VR/VRMath.h - Common/VR/VRRenderer.cpp - Common/VR/VRRenderer.h - ) - if (OPENXR) set(nativeExtraLibs ${nativeExtraLibs} openxr) endif() From 8df6efa712d1ede8e77f6821ef18a6474ab9b64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 19:27:39 +0200 Subject: [PATCH 045/715] Android non-gradle buildfix --- android/jni/Locals.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/android/jni/Locals.mk b/android/jni/Locals.mk index ef0d118462..beed008585 100644 --- a/android/jni/Locals.mk +++ b/android/jni/Locals.mk @@ -15,6 +15,7 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../../ext/miniupnp-build \ $(LOCAL_PATH)/../../ext/libpng17 \ $(LOCAL_PATH)/../../ext/libzip \ + $(LOCAL_PATH)/../../ext/openxr \ $(LOCAL_PATH)/../../ext/zstd/lib \ $(LOCAL_PATH)/../../ext/armips \ $(LOCAL_PATH)/../../ext/armips/ext/filesystem/include \ From ba0a4e4ff17a657818fa8f03ee21dceb10a69652 Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Mon, 17 Oct 2022 20:27:17 +0200 Subject: [PATCH 046/715] lang/pl_PL: add more translations --- assets/lang/pl_PL.ini | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 6a8b45a191..7c125af989 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -5,7 +5,7 @@ Audio Error = Błąd Audio AudioBufferingForBluetooth = Bufory dźwięku dost. do Bluetooth (wolniejsze) Auto = Automatyczny Device = Urządzenie -Disabled = Wyłączone +Disabled = Wył. DSound (compatible) = DSound (kompatybilny) Enable Sound = Włącz dźwięk Global volume = Głośność globalna @@ -124,7 +124,7 @@ Refresh Rate = Szybkość odświeżania #Font = Trebuchet MS About PPSSPP... = O PPSSPP... Auto = Automatycznie -Auto Max Quality = Auto Max &Quality +Auto Max Quality = Automatyczna maksymalna &Jakość Backend = &Sterownik obrazu (Restartuje PPSSPP) Bicubic = Bicubic (Dwusześcienne) Break = Zatrzymaj @@ -154,7 +154,7 @@ Game Settings = &Ustawienia gry GE Debugger... = Debugger GE... GitHub = Git&Hub Hardware Transform = &Transformacja sprzętowa -Help = Pomo&c +Help = Pomoc Hybrid = Hybrydowe Hybrid + Bicubic = Hybrydowe + Bicubic Ignore Illegal Reads/Writes = Ignoruj nieprawidłowe odczyty/zapisy @@ -225,14 +225,14 @@ Allow remote debugger = Zezwól na zdalne debugowanie Backspace = Backspace Block address = Adres bloku By Address = Po adresie -Copy savestates to memstick root = Copy save states to Memory Stick root +Copy savestates to memstick root = Skopjuj zapisane stany do folderu głównego Karty Pamięci Create/Open textures.ini file for current game = Stwórz/otwórz plik textures.ini z bieżącej gry Current = Obecny Dev Tools = Narzędzia Developerskie DevMenu = DevMenu Disabled JIT functionality = Wyłącz funkcje JIT Draw Frametimes Graph = Draw frametimes graph -Dump Decrypted Eboot = Zachowuj odszyfrowany EBOOT.BIN przy starcie +Dump Decrypted Eboot = Zachowuj odszyfrowany EBOOT.BIN przy starcieSkopjuj zapisane stany do folderu głównego Karty Pamięci Dump Frame GPU Commands = Zrzuć klatkę komend GPU Enable driver bug workarounds = Uruchom obejścia błędów sterownika Enable Logging = Włącz dziennik zdarzeń debugera @@ -427,7 +427,7 @@ Korea = Korea MB = MB One moment please... = Chwileczkę... Play = Graj -Remove From Recent = Usuń z "Ostatnio granych" +Remove From Recent = Usuń z "Ostatnio uruchamianych tytułów" SaveData = Zapisy gier Setting Background = Ustawianie tła Show In Folder = Pokaż w folderze @@ -615,7 +615,7 @@ Load = Otwórz... Loading... = Loading... PinPath = Przypnij PPSSPP can't load games or save right now = PPSSPP nie może teraz załadować gier ani zapisywać stanów -Recent = Ostatnio grane +Recent = Ostatnio grywane SavesAreTemporary = PPSSPP zapisuje do pamięci tymczasowej SavesAreTemporaryGuidance = Wypakuj PPSSPP, by móc trwale zapisywać SavesAreTemporaryIgnore = Ignoruj @@ -723,13 +723,13 @@ DataCanBeShared = Data can be shared between PPSSPP regular/Gold DataCannotBeShared = Data CANNOT be shared between PPSSPP regular/Gold! DataWillBeLostOnUninstall = Warning! Data will be lost when you uninstall PPSSPP! DataWillStay = Data will stay even if you uninstall PPSSPP. -Done! = Done! -EasyUSBAccess = Easy USB access +Done! = Ukończono! +EasyUSBAccess = Łatwy dostęþ do USB Failed to move some files! = Nie udało się przenieść niektórych plików! -Failed to save config = Failed to save config -Free space = Free space -Manually specify PSP folder = Manually specify PSP folder -MemoryStickDescription = Choose where to keep PSP data (Memory Stick) +Failed to save config = Nie udało się zapisać ustawień +Free space = Wolne miejsce +Manually specify PSP folder = Ustaw folder PSP ręcznie +MemoryStickDescription = Wybierz, gdzie chcesz umieścić dane PSP (Karta Pamięci) Move Data = Move Data Selected PSP Data Folder = Selected PSP Data Folder No data will be changed = No data will be changed @@ -803,11 +803,11 @@ Send Discord Presence information = Transmituj informacje Discord Rich Presence Top Center = Top center Top Left = Top left Top Right = Top right -Unable to find UPnP device = Unable to find UPnP device +Unable to find UPnP device = Nie udało się zlokalizować urządzenia UPnP UPnP (port-forwarding) = UPnP (port forwarding) UPnP need to be reinitialized = UPnP need to be reinitialized -UPnP use original port = UPnP use original port (enabled = PSP compatibility) -Validating address... = Validating address... +UPnP use original port = UPnP używa oryginalnego portu (włączone = kompatybilność z PSP) +Validating address... = Uwierzytelnianie addresu... WLAN Channel = Kanał WLAN You're in Offline Mode, go to lobby or online hall = You're in offline mode, go to lobby or online hall @@ -1098,15 +1098,15 @@ Color Saturation = Color Saturation Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. -Floating symbols = Floating symbols +Floating symbols = Przepływ symboli Memory Stick folder = Zmień folder Karty Pamięci Memory Stick size = Rozmiar Karty Pamięci Change Nickname = Zmień pseudonim ChangingMemstickPath = Zapisy gier, zapisy stanu i inne dane nie zostaną skopiowane do tego folderu.\n\nZmienić ścieżkę do folderu Karty Pamięci? ChangingMemstickPathInvalid = Ta ścieżka nie może zostać użyta do zapisu plików Karty Pamięci. Cheats = Kody -Clear Recent = Clear "Recent" -Clear Recent Games List = Wyczyść listę ostatnio granych +Clear Recent = Wyczyść "Ostatni grywanych" +Clear Recent Games List = Wyczyść listę ostatnio grywanych Clear UI background = Przywróć tło interfejsu Confirmation Button = Przycisk potwierdzenia Date Format = Format daty @@ -1117,7 +1117,7 @@ Developer Tools = Narzędzia programistyczne Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid Display Homebrew on a grid = Display "Homebrew && Demos" on a grid -Display Recent on a grid = Display "Recent" on a grid +Display Recent on a grid = Wyświetlaj "Ostatnio Grywane" w projekcji siatki Dynarec (JIT) = Dynarec (JIT) Emulation = Emulacja Enable Cheats = Włącz kody @@ -1149,12 +1149,12 @@ Not a PSP game = To nie jest gra PSP Off = Wył. Oldest Save = Najstarszy zapis Path does not exist! = Path does not exist! -PSP Memory Stick = PSP Memory Stick +PSP Memory Stick = Karta Pamięci PSP PSP Model = Model PSP PSP Settings = Ustawienia PSP PSP-1000 = PSP-1000 PSP-2000/3000 = PSP-2000/3000 -Recent games = Recent games +Recent games = Ostatnio uruchamiane tytuły Record Audio = Nagrywaj dźwięk Record Display = Nagrywaj obraz Reset Recording on Save/Load State = Resetuj nagrywanie przy zapisie/wczytaniu stanu @@ -1167,7 +1167,7 @@ Savestate slot backups = Kopie zapasowe slota zapisu stanu Screenshots as PNG = Zapisuj zrzuty ekranu jako PNG Set UI background... = Zmień tło interfejsu... Show ID = Show ID -Show Memory Stick folder = Show Memory Stick folder +Show Memory Stick folder = Pokaż folder Karty Pamięci Show region flag = Show region flag Simulate UMD delays = Symuluj opóźnienia UMD Slot 1 = Slot 1 From 0a222345c1225508a5be8ee527f911619a6dda42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 20:43:58 +0200 Subject: [PATCH 047/715] Buildfixes --- Common/VR/VRBase.cpp | 2 +- Common/VR/VRFramebuffer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 687506aeb5..c30003624b 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -61,7 +61,7 @@ void VR_Init( ovrJava java, bool useVulkan ) { xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid); } - std::vector extensions; + std::vector extensions; if (useVulkan) { extensions.push_back(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME); } else { diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 8e7828ded8..e917006b51 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -270,7 +270,7 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { - return frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; + return (void *)frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { #if PPSSPP_PLATFORM(ANDROID) GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); From 0251f33ec3b1db377c180e9242372c901d5d31f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Oct 2022 23:13:18 +0200 Subject: [PATCH 048/715] Don't use PPSSPP-specific stuff in Common/VR for now. --- Common/File/DirListing.cpp | 2 +- Common/VR/PPSSPPVR.cpp | 4 +-- Common/VR/VRBase.cpp | 2 +- Common/VR/VRBase.h | 18 +++++------- Common/VR/VRFramebuffer.cpp | 20 ++++++------- Common/VR/VRInput.cpp | 4 +++ Common/VR/VRRenderer.cpp | 4 +++ UWP/CommonUWP/CommonUWP.vcxproj | 36 +++++++++++++++-------- UWP/CommonUWP/CommonUWP.vcxproj.filters | 39 +++++++++++++++++++++++++ UWP/Package.appxmanifest | 29 +++++++++++++++--- 10 files changed, 118 insertions(+), 40 deletions(-) diff --git a/Common/File/DirListing.cpp b/Common/File/DirListing.cpp index d17a4f2241..b793e85057 100644 --- a/Common/File/DirListing.cpp +++ b/Common/File/DirListing.cpp @@ -317,7 +317,7 @@ std::vector GetWindowsDrives() { if (logicaldrives & (1 << i)) { - CHAR driveName[] = { TEXT('A') + i, TEXT(':'), TEXT('\\'), TEXT('\0') }; + CHAR driveName[] = { (CHAR)(TEXT('A') + i), TEXT(':'), TEXT('\\'), TEXT('\0') }; std::string str(driveName); drives.push_back(driveName); } diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index abbd78cfdf..384be0b031 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -1,3 +1,5 @@ +#ifdef OPENXR + #include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/GPU/Vulkan/VulkanContext.h" @@ -12,8 +14,6 @@ #include "Core/KeyMap.h" #include "Core/System.h" -#ifdef OPENXR - static long vrCompat[VR_COMPAT_MAX]; /* diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index c30003624b..e0301bb6e6 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -5,7 +5,7 @@ #include #include -#if PPSSPP_PLATFORM(ANDROID) +#if defined(ANDROID) && defined(OPENXR) #include diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 4caa9417ba..b0d7b09f81 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -1,9 +1,7 @@ #pragma once -#include "ppsspp_config.h" - // TODO: Switch to PPSSPP logging -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID #include #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "OpenXR", __VA_ARGS__); #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "OpenXR", __VA_ARGS__); @@ -21,7 +19,7 @@ using namespace PPSSPP_VK; #endif -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID //OpenXR #define XR_USE_PLATFORM_ANDROID 1 #define XR_USE_GRAPHICS_API_OPENGL_ES 1 @@ -29,7 +27,7 @@ using namespace PPSSPP_VK; #include #include #include -#elif PPSSPP_PLATFORM(WINDOWS) +#elif defined(_WIN32) #include "Common/CommonWindows.h" #include #define XR_USE_PLATFORM_WIN32 1 @@ -44,14 +42,14 @@ using namespace PPSSPP_VK; #include #include -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID #include #include #endif -#if defined(_DEBUG) && PPSSPP_PLATFORM(ANDROID) +#if defined(_DEBUG) && defined(ANDROID) static const char* GlErrorString(GLenum error) { switch (error) { case GL_NO_ERROR: @@ -169,7 +167,7 @@ typedef struct { ovrRenderer Renderer; } ovrApp; -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID typedef struct { JavaVM* Vm; jobject ActivityObject; @@ -182,7 +180,7 @@ typedef struct { typedef struct { uint64_t frameIndex; ovrApp appState; -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID ovrJava java; #endif float predictedDisplayTime; @@ -190,7 +188,7 @@ typedef struct { XrGraphicsBindingVulkanKHR graphicsBindingVulkan; } engine_t; -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID void VR_Init( ovrJava java, bool useVulkan ); #endif diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index e917006b51..2d9db6c3fc 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -8,7 +8,7 @@ #include #include -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID #include #include #endif @@ -44,7 +44,7 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = false; } -#if PPSSPP_PLATFORM(ANDROID) +#ifdef OPENXR bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { @@ -138,8 +138,6 @@ bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int return true; } -#endif - bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview, void* context) { @@ -255,7 +253,7 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { delete[] frameBuffer->VKDepthImages; delete[] frameBuffer->VKFrameBuffers; } else { -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); free(frameBuffer->GLFrameBuffers); #endif @@ -272,7 +270,7 @@ void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { return (void *)frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); #endif return nullptr; @@ -304,7 +302,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { //TODO:implement } else { -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID GL(glEnable( GL_SCISSOR_TEST )); GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); @@ -326,7 +324,7 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { //TODO:implement } else { -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL(glClear(GL_COLOR_BUFFER_BIT)); @@ -357,7 +355,7 @@ void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int if (vulkanContext) { ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, multiview, vulkanContext); } else { -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID ovrFramebuffer_CreateGL(session, &renderer->FrameBuffer[i], width, height, multiview); #endif } @@ -375,7 +373,7 @@ void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { if (renderer->FrameBuffer[0].UseVulkan) { //TODO:implement } else { -#if PPSSPP_PLATFORM(ANDROID) +#ifdef ANDROID GL(glEnable(GL_SCISSOR_TEST)); GL(glScissor(x, y, size, size)); GL(glViewport(x, y, size, size)); @@ -547,3 +545,5 @@ int ovrApp_HandleXrEvents(ovrApp* app) { } return recenter; } + +#endif diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index e07c44fcda..313f9f1d9b 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -3,6 +3,8 @@ #include +#ifdef OPENXR + //OpenXR XrPath leftHandPath; XrPath rightHandPath; @@ -432,3 +434,5 @@ XrPosef IN_VRGetPose( int controllerIndex ) { xrLocateSpace(aimSpace[controllerIndex], engine->appState.CurrentSpace, (XrTime)(engine->predictedDisplayTime), &loc); return loc.pose; } + +#endif diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 08f44749e4..60db7063e1 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -20,6 +20,8 @@ ovrMatrix4f vrMatrix[VR_MATRIX_COUNT]; XrVector3f hmdorientation; XrVector3f hmdposition; +#ifdef OPENXR + void VR_UpdateStageBounds(ovrApp* pappState) { XrExtent2Df stageBounds = {}; @@ -512,3 +514,5 @@ void* VR_BindFramebuffer(engine_t *engine) { ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) { return vrMatrix[matrix]; } + +#endif diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index 09e9173e41..90a1c1649c 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -203,7 +203,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) NotUsing @@ -217,7 +217,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -232,7 +232,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -248,7 +248,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) NotUsing @@ -263,7 +263,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) NotUsing @@ -277,7 +277,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -292,7 +292,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -307,7 +307,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -322,7 +322,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -338,7 +338,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) NotUsing @@ -352,7 +352,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -367,7 +367,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -502,6 +502,12 @@ + + + + + + @@ -612,6 +618,12 @@ + + + + + + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 23de400ce6..dd2f6d6fda 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -85,6 +85,9 @@ {28139b08-f8d5-41a2-a5ee-bf86cf1469c3} + + {a5bfc343-9c3a-43ff-a033-7b0406e13816} + @@ -375,6 +378,24 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + @@ -694,6 +715,24 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + diff --git a/UWP/Package.appxmanifest b/UWP/Package.appxmanifest index dc955c64bb..68b9c930d7 100644 --- a/UWP/Package.appxmanifest +++ b/UWP/Package.appxmanifest @@ -1,9 +1,11 @@  - - + + + - DUMMY - DUMMY + PPSSPP - PSP emulator + Henrik Rydgård + Assets\StoreLogo.png @@ -11,4 +13,23 @@ + + + + + + + + + + + + + + + + + + + From feb4f9477a235f6b2c6b851bffe923332e50c344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Oct 2022 10:35:42 +0200 Subject: [PATCH 049/715] Remove newly added dependencies on PPSSPP --- Common/TimeUtil.cpp | 3 --- Common/VR/VRBase.h | 1 - Common/VR/VRFramebuffer.cpp | 16 +++++++++------- Common/VR/VRFramebuffer.h | 2 +- Common/VR/VRInput.cpp | 36 +++++++++++++++++++++++++++++++----- Common/VR/VRMath.cpp | 5 ++--- Common/VR/VRRenderer.cpp | 2 -- 7 files changed, 43 insertions(+), 22 deletions(-) diff --git a/Common/TimeUtil.cpp b/Common/TimeUtil.cpp index ad00e1e9a7..ad07fbd18c 100644 --- a/Common/TimeUtil.cpp +++ b/Common/TimeUtil.cpp @@ -21,8 +21,6 @@ // TODO: https://github.com/floooh/sokol/blob/9a6237fcdf213e6da48e4f9201f144bcb2dcb46f/sokol_time.h#L229-L248 -static double curtime = 0; - #ifdef _WIN32 static LARGE_INTEGER frequency; @@ -33,7 +31,6 @@ double time_now_d() { if (frequency.QuadPart == 0) { QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&startTime); - curtime = 0.0; frequencyMult = 1.0 / static_cast(frequency.QuadPart); } LARGE_INTEGER time; diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index b0d7b09f81..40c377ec84 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -1,6 +1,5 @@ #pragma once -// TODO: Switch to PPSSPP logging #ifdef ANDROID #include #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "OpenXR", __VA_ARGS__); diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 2d9db6c3fc..3cf70642a9 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -8,7 +8,7 @@ #include #include -#ifdef ANDROID +#if !defined(_WIN32) #include #include #endif @@ -253,7 +253,7 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { delete[] frameBuffer->VKDepthImages; delete[] frameBuffer->VKFrameBuffers; } else { -#ifdef ANDROID +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); free(frameBuffer->GLFrameBuffers); #endif @@ -270,7 +270,7 @@ void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { return (void *)frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { -#ifdef ANDROID +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); #endif return nullptr; @@ -302,7 +302,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { //TODO:implement } else { -#ifdef ANDROID +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES GL(glEnable( GL_SCISSOR_TEST )); GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); @@ -324,7 +324,7 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { if (frameBuffer->UseVulkan) { //TODO:implement } else { -#ifdef ANDROID +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL(glClear(GL_COLOR_BUFFER_BIT)); @@ -355,7 +355,7 @@ void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int if (vulkanContext) { ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, multiview, vulkanContext); } else { -#ifdef ANDROID +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES ovrFramebuffer_CreateGL(session, &renderer->FrameBuffer[i], width, height, multiview); #endif } @@ -373,7 +373,7 @@ void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { if (renderer->FrameBuffer[0].UseVulkan) { //TODO:implement } else { -#ifdef ANDROID +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES GL(glEnable(GL_SCISSOR_TEST)); GL(glScissor(x, y, size, size)); GL(glViewport(x, y, size, size)); @@ -433,6 +433,8 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { app->SessionActive = (result == XR_SUCCESS); // Set session state once we have entered VR mode and have a valid session object. + + // TODO: This should be a runtime check of the extension's presence, no? #ifdef OPENXR_HAS_PERFORMANCE_EXTENSION if (app->SessionActive) { XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index 5dd455fd16..7440e49d70 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -1,6 +1,6 @@ #pragma once -#include "Common/VR/VRBase.h" +#include "VRBase.h" void ovrApp_Clear(ovrApp* app); void ovrApp_Destroy(ovrApp* app); diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index 313f9f1d9b..58571b47f1 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -1,7 +1,5 @@ #include "VRInput.h" -#include - -#include +#include #ifdef OPENXR @@ -41,11 +39,39 @@ XrActionStateVector2f moveJoystickState[2]; float vibration_channel_duration[2] = {0.0f, 0.0f}; float vibration_channel_intensity[2] = {0.0f, 0.0f}; - +#if !defined(_WIN32) unsigned long sys_timeBase = 0; int milliseconds(void) { - return (int)(1000.0 * time_now_d()); + struct timeval tp; + + gettimeofday(&tp, NULL); + + if (!sys_timeBase) { + sys_timeBase = tp.tv_sec; + return tp.tv_usec / 1000; + } + + return (tp.tv_sec - sys_timeBase) * 1000 + tp.tv_usec / 1000; } +#else + +static LARGE_INTEGER frequency; +static double frequencyMult; +static LARGE_INTEGER startTime; + +int milliseconds() { + if (frequency.QuadPart == 0) { + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&startTime); + frequencyMult = 1.0 / static_cast(frequency.QuadPart); + } + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + double elapsed = static_cast(time.QuadPart - startTime.QuadPart); + return (int)(elapsed * frequencyMult * 1000.0); +} + +#endif XrTime ToXrTime(const double timeInSeconds) { return (XrTime)(timeInSeconds * 1e9); diff --git a/Common/VR/VRMath.cpp b/Common/VR/VRMath.cpp index df9512d186..bafdff75ea 100644 --- a/Common/VR/VRMath.cpp +++ b/Common/VR/VRMath.cpp @@ -1,10 +1,9 @@ +#define _USE_MATH_DEFINES + #include #include "VRMath.h" -#include "Common/Math/math_util.h" - - float ToDegrees(float rad) { return (float)(rad / M_PI * 180.0f); } diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 60db7063e1..d4b35c596d 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -2,8 +2,6 @@ #include "VRInput.h" #include "VRRenderer.h" -#include "Common/Math/math_util.h" - #include #include #include From 269eb55c1741ee2caebabf40a8c88656b842cf79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Oct 2022 10:48:16 +0200 Subject: [PATCH 050/715] Build/warning fix --- Common/VR/VRFramebuffer.cpp | 1 - Common/VR/VRInput.cpp | 2 ++ GPU/Common/TextureCacheCommon.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 3cf70642a9..34e3a3cbb4 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -10,7 +10,6 @@ #if !defined(_WIN32) #include -#include #endif double FromXrTime(const XrTime time) { diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index 58571b47f1..7ea64f9674 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -40,6 +40,8 @@ float vibration_channel_duration[2] = {0.0f, 0.0f}; float vibration_channel_intensity[2] = {0.0f, 0.0f}; #if !defined(_WIN32) +#include + unsigned long sys_timeBase = 0; int milliseconds(void) { struct timeval tp; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 0ee2c54b10..a0c7180588 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -2045,6 +2045,7 @@ static bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferForma } break; case GE_FORMAT_CLUT8: + case GE_FORMAT_INVALID: // Shouldn't happen here. return false; } From eed75889e4e3873143d099f22b8f6f9cf06df0b0 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 18 Oct 2022 12:23:23 +0200 Subject: [PATCH 051/715] OpenXR - Ensure scene analyze is called the same way as before --- GPU/GLES/ShaderManagerGLES.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index db721ab475..3bdd9c4f86 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -362,6 +362,13 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu u64 dirty = dirtyUniforms & availableUniforms; dirtyUniforms = 0; + // Analyze scene + bool is2D, flatScreen; + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { + is2D = Is2DVRObject(gstate.projMatrix, gstate.isModeThrough()); + flatScreen = IsFlatVRScene(); + } + if (!dirty) return; @@ -376,13 +383,8 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu render_->SetUniformUI1(&u_depal_mask_shift_off_fmt, val); } - bool is2D, flatScreen; + // Set HUD mode if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - // Analyze scene - is2D = Is2DVRObject(gstate.projMatrix, gstate.isModeThrough()); - flatScreen = IsFlatVRScene(); - - // Set HUD mode bool is3D = gstate.isDepthWriteEnabled(); bool hud = is2D && !is3D && !flatScreen && gstate.isModeThrough() && //2D content requires orthographic projection From fbb1e7eda0ec38fb1e9620d6aa4911d7da46fda8 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 18 Oct 2022 12:39:42 +0200 Subject: [PATCH 052/715] OpenXR - Use only the first projection matrix in frame for mirroing detection --- Common/VR/PPSSPPVR.cpp | 42 +++++++++++++++++++++++------------------- Common/VR/VRRenderer.h | 2 +- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 384be0b031..41101cdd9a 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -321,6 +321,7 @@ bool StartVRRender() { VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.iCanvasDistance); VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.iFieldOfViewPercentage); + VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, false); return true; } return false; @@ -411,25 +412,28 @@ void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { } // Set mirroring of axes - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_X, projMatrix[0] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Y, projMatrix[5] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Z, projMatrix[10] > 0); - if ((projMatrix[0] < 0) && (projMatrix[10] < 0)) { //e.g. Dante's inferno - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else if (projMatrix[10] < 0) { //e.g. GTA - Liberty city - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, false); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else if (projMatrix[5] < 0) { //e.g. PES 2014 - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else { //e.g. Lego Pirates - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, true); + if (!VR_GetConfig(VR_CONFIG_MIRROR_UPDATED)) { + VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, true); + VR_SetConfig(VR_CONFIG_MIRROR_AXIS_X, projMatrix[0] < 0); + VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Y, projMatrix[5] < 0); + VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Z, projMatrix[10] > 0); + if ((projMatrix[0] < 0) && (projMatrix[10] < 0)) { //e.g. Dante's inferno + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + } else if (projMatrix[10] < 0) { //e.g. GTA - Liberty city + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, false); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + } else if (projMatrix[5] < 0) { //e.g. PES 2014 + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + } else { //e.g. Lego Pirates + VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); + VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); + VR_SetConfig(VR_CONFIG_MIRROR_ROLL, true); + } } // Set 6DoF scale diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 7a86adf6b2..16f70d9411 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -9,7 +9,7 @@ enum VRConfig { //camera setup VR_CONFIG_FOV_SCALE, VR_CONFIG_CANVAS_DISTANCE, //6DoF - VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, + VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, VR_CONFIG_MIRROR_PITCH, VR_CONFIG_MIRROR_YAW, VR_CONFIG_MIRROR_ROLL, //2D canvas positioning From 83fccd0835b99144298a1f2efc13c0ba8717276c Mon Sep 17 00:00:00 2001 From: catsout Date: Tue, 18 Oct 2022 20:33:58 +0800 Subject: [PATCH 053/715] SDL: fix glew on wayland by ignore glx glXGetProcAddress works on wayland if linking with x11. As long as we don't use glx related funcs, no_glx_error can be ignored. SDL should handle the no_glx_error brefore glewInit. Glew is only used to init gl funcs. related: https://github.com/nigels-com/glew/issues/172 --- SDL/SDLGLGraphicsContext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SDL/SDLGLGraphicsContext.cpp b/SDL/SDLGLGraphicsContext.cpp index 492005a1f4..945c9a950e 100644 --- a/SDL/SDLGLGraphicsContext.cpp +++ b/SDL/SDLGLGraphicsContext.cpp @@ -394,7 +394,9 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: if (gl_extensions.IsCoreContext) { glewExperimental = true; } - if (GLEW_OK != glewInit()) { + GLenum glew_err = glewInit(); + // glx is not required, igore. + if (glew_err != GLEW_OK && glew_err != GLEW_ERROR_NO_GLX_DISPLAY) { printf("Failed to initialize glew!\n"); return 1; } From f009d150785a9013387494a36ccde5ee0af7ee4e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Oct 2022 21:33:47 -0700 Subject: [PATCH 054/715] headless: Allow screenshot to not be 512x272. Ended up with a cropped screenshot for a frame dump, which just silently crashed. Could reject, but easy enough to support. --- headless/Compare.cpp | 13 ++++++++----- headless/Compare.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/headless/Compare.cpp b/headless/Compare.cpp index 76254d005a..9c42887342 100644 --- a/headless/Compare.cpp +++ b/headless/Compare.cpp @@ -399,6 +399,7 @@ double ScreenshotComparer::Compare(const Path &screenshotFilename) { if (header[0] == 'B' && header[1] == 'M') { reference_ = (u32 *)calloc(stride_ * h_, sizeof(u32)); + referenceStride_ = stride_; asBitmap_ = true; // The bitmap header is 14 + 40 bytes. We could validate it but the test would fail either way. if (reference_ && loader->ReadAt(14 + 40, sizeof(u32), stride_ * h_, reference_) != stride_ * h_) { @@ -424,6 +425,8 @@ double ScreenshotComparer::Compare(const Path &screenshotFilename) { reference_ = nullptr; return -1.0f; } + + referenceStride_ = width; } } else { error_ = "Unable to read screenshot: " + screenshotFilename.ToVisualString(); @@ -439,15 +442,15 @@ double ScreenshotComparer::Compare(const Path &screenshotFilename) { if (asBitmap_) { // The reference is flipped and BGRA by default for the common BMP compare case. for (u32 y = 0; y < h_; ++y) { - u32 yoff = y * stride_; + u32 yoff = y * referenceStride_; for (u32 x = 0; x < w_; ++x) errors += ComparePixel(pixels_[y * stride_ + x], reference_[yoff + x]); } } else { // Just convert to BGRA for simplicity. - ConvertRGBA8888ToBGRA8888(reference_, reference_, h_ * stride_); + ConvertRGBA8888ToBGRA8888(reference_, reference_, h_ * referenceStride_); for (u32 y = 0; y < h_; ++y) { - u32 yoff = (h_ - y - 1) * stride_; + u32 yoff = (h_ - y - 1) * referenceStride_; for (u32 x = 0; x < w_; ++x) errors += ComparePixel(pixels_[y * stride_ + x], reference_[yoff + x]); } @@ -486,7 +489,7 @@ bool ScreenshotComparer::SaveVisualComparisonPNG(const Path &resultFilename) { if (asBitmap_) { // The reference is flipped and BGRA by default for the common BMP compare case. for (u32 y = 0; y < h_; ++y) { - u32 yoff = y * stride_; + u32 yoff = y * referenceStride_; u32 comparisonRow = (h_ - y - 1) * 2 * w_ * 2; for (u32 x = 0; x < w_; ++x) { PlotVisualComparison(comparison.get(), comparisonRow + x * 2, pixels_[y * stride_ + x], reference_[yoff + x]); @@ -495,7 +498,7 @@ bool ScreenshotComparer::SaveVisualComparisonPNG(const Path &resultFilename) { } else { // Reference is already in BGRA either way. for (u32 y = 0; y < h_; ++y) { - u32 yoff = (h_ - y - 1) * stride_; + u32 yoff = (h_ - y - 1) * referenceStride_; u32 comparisonRow = (h_ - y - 1) * 2 * w_ * 2; for (u32 x = 0; x < w_; ++x) { PlotVisualComparison(comparison.get(), comparisonRow + x * 2, pixels_[y * stride_ + x], reference_[yoff + x]); diff --git a/headless/Compare.h b/headless/Compare.h index 0ddd702af8..2a59039cdd 100644 --- a/headless/Compare.h +++ b/headless/Compare.h @@ -58,6 +58,7 @@ protected: u32 *reference_ = nullptr; bool asBitmap_ = false; std::string error_; + u32 referenceStride_ = 0; u32 stride_; u32 w_; u32 h_; From 21573f43028ddcf079e93569556e31c83307c436 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Oct 2022 21:34:59 -0700 Subject: [PATCH 055/715] headless: Fix crash running some tests on Vulkan. If there's no frame display, tests were crashing because no backbuffer present blit happened. This allows those tests to run. --- headless/Headless.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 5b2b8adfd3..ff5c3f94b4 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -203,8 +203,9 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops); PSP_BeginHostFrame(); - if (coreParameter.graphicsContext && coreParameter.graphicsContext->GetDrawContext()) - coreParameter.graphicsContext->GetDrawContext()->BeginFrame(); + Draw::DrawContext *draw = coreParameter.graphicsContext ? coreParameter.graphicsContext->GetDrawContext() : nullptr; + if (draw) + draw->BeginFrame(); bool passed = true; double deadline = time_now_d() + opt.timeout; @@ -238,8 +239,14 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const } PSP_EndHostFrame(); - if (coreParameter.graphicsContext && coreParameter.graphicsContext->GetDrawContext()) - coreParameter.graphicsContext->GetDrawContext()->EndFrame(); + if (draw) { + draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless"); + // Vulkan may get angry if we don't do a final present. + if (gpu) + gpu->CopyDisplayToOutput(true); + + draw->EndFrame(); + } PSP_Shutdown(); From 01896a82755320eb158c6f1958e192101d0bc101 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Oct 2022 21:35:51 -0700 Subject: [PATCH 056/715] headless: Update passing tests. --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 2ae8d9237d..4bc6b25ff9 100755 --- a/test.py +++ b/test.py @@ -163,6 +163,7 @@ tests_good = [ "gpu/primitives/indices", "gpu/primitives/invalidprim", "gpu/primitives/points", + "gpu/primitives/rectangles", "gpu/primitives/trianglefan", "gpu/primitives/trianglestrip", "gpu/primitives/triangles", @@ -186,6 +187,7 @@ tests_good = [ "gpu/textures/mipmap", "gpu/textures/rotate", "gpu/vertices/colors", + "gpu/vertices/texcoords", "hash/hash", "hle/check_not_used_uids", "intr/intr", @@ -412,7 +414,6 @@ tests_next = [ "gpu/primitives/immediate", "gpu/primitives/lines", "gpu/primitives/linestrip", - "gpu/primitives/rectangles", "gpu/primitives/spline", "gpu/reflection/reflection", "gpu/rendertarget/rendertarget", @@ -426,7 +427,6 @@ tests_next = [ "gpu/texmtx/uvs", "gpu/textures/size", "gpu/triangle/triangle", - "gpu/vertices/texcoords", "intr/registersub", "intr/releasesub", "intr/waits", From 95d8b108be6feb168197ad4aca348ec9c0f65114 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Oct 2022 21:48:49 -0700 Subject: [PATCH 057/715] Kernel: Fix reported StopThread error. Was trying to delete -1, since it was never created. --- Core/HLE/HLEHelperThread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/HLEHelperThread.cpp b/Core/HLE/HLEHelperThread.cpp index 0975d1ea96..60f7efb759 100644 --- a/Core/HLE/HLEHelperThread.cpp +++ b/Core/HLE/HLEHelperThread.cpp @@ -26,7 +26,7 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/MIPS/MIPSCodeUtils.h" -HLEHelperThread::HLEHelperThread() : id_(-1), entry_(0) { +HLEHelperThread::HLEHelperThread() : id_(0), entry_(0) { } HLEHelperThread::HLEHelperThread(const char *threadName, const u32 instructions[], u32 instrCount, u32 prio, int stacksize) { @@ -52,7 +52,7 @@ HLEHelperThread::HLEHelperThread(const char *threadName, const char *module, con } HLEHelperThread::~HLEHelperThread() { - if (id_) + if (id_ > 0) __KernelDeleteThread(id_, SCE_KERNEL_ERROR_THREAD_TERMINATED, "helper deleted"); if (entry_) kernelMemory.Free(entry_); From a42064eb48745b7552282eebbc71313303fc4c08 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Oct 2022 21:52:38 -0700 Subject: [PATCH 058/715] Vulkan: Correct some enum switch warnings. Nice to log debug annotations anyway. --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 3 +++ GPU/Vulkan/ShaderManagerVulkan.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 427264b942..98bd2e7773 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1115,6 +1115,9 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { case VKRRenderCommand::PUSH_CONSTANTS: INFO_LOG(G3D, " PushConstants(%d)", cmd.push.size); break; + case VKRRenderCommand::DEBUG_ANNOTATION: + INFO_LOG(G3D, " DebugAnnotation(%s)", cmd.debugAnnotation.annotation); + break; case VKRRenderCommand::NUM_RENDER_COMMANDS: break; diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 97eb00c490..21e8f44347 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -81,6 +81,7 @@ static Promise *CompileShaderModuleAsync(VulkanContext *vulkan, case VK_SHADER_STAGE_FRAGMENT_BIT: createTag = "game_fragment"; break; case VK_SHADER_STAGE_GEOMETRY_BIT: createTag = "game_geometry"; break; case VK_SHADER_STAGE_COMPUTE_BIT: createTag = "game_compute"; break; + default: break; } } From 1e343370aed32c1ffe0ba5866228246525a0662f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Oct 2022 10:02:40 +0200 Subject: [PATCH 059/715] Libretro buildfix attempt --- libretro/Makefile.common | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 014579eec4..d205c65f17 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -315,12 +315,13 @@ SOURCES_CXX += \ $(COMMONDIR)/TimeUtil.cpp SOURCES_CXX += \ - $(COMMONDIR)/VRBase.cpp \ - $(COMMONDIR)/VRMath.cpp \ - $(COMMONDIR)/VRFramebuffer.cpp \ - $(COMMONDIR)/VRInput.cpp \ - $(COMMONDIR)/VRMath.cpp \ - $(COMMONDIR)/VRRenderer.cpp + $(COMMONDIR)/VR/PPSSPPVR.cpp \ + $(COMMONDIR)/VR/VRBase.cpp \ + $(COMMONDIR)/VR/VRMath.cpp \ + $(COMMONDIR)/VR/VRFramebuffer.cpp \ + $(COMMONDIR)/VR/VRInput.cpp \ + $(COMMONDIR)/VR/VRMath.cpp \ + $(COMMONDIR)/VR/VRRenderer.cpp SOURCES_C +=\ $(COMMONDIR)/GPU/OpenGL/gl3stub.c \ From 90d395a10dd088d52845e976f8a7c841287391ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Oct 2022 10:15:19 +0200 Subject: [PATCH 060/715] Remove "attachment" parameter from BindFramebufferAsTexture everywhere. Not actually useful since our framebuffer objects don't support multiple color images, and probably won't ever need to. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 4 ++-- Common/GPU/D3D9/thin3d_d3d9.cpp | 4 ++-- Common/GPU/OpenGL/GLRenderManager.cpp | 2 +- Common/GPU/OpenGL/GLRenderManager.h | 2 +- Common/GPU/OpenGL/thin3d_gl.cpp | 6 +++--- Common/GPU/Vulkan/VulkanRenderManager.cpp | 2 +- Common/GPU/Vulkan/VulkanRenderManager.h | 2 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 7 ++++--- Common/GPU/thin3d.h | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 8 ++++---- GPU/Common/PresentationCommon.cpp | 8 ++++---- GPU/Common/TextureCacheCommon.cpp | 8 ++++---- GPU/GLES/DepthBufferGLES.cpp | 4 ++-- 13 files changed, 30 insertions(+), 29 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 0b10980c0f..ddbdecb0aa 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -98,7 +98,7 @@ public: Framebuffer *GetCurrentRenderTarget() override { return curRenderTarget_; } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1701,7 +1701,7 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren stepId_++; } -void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) { +void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { _assert_(binding < MAX_BOUND_TEXTURES); D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; switch (channelBit) { diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 20bcc14e5d..162c8febec 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -535,7 +535,7 @@ public: Framebuffer *GetCurrentRenderTarget() override { return curRenderTarget_; } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) override; @@ -1348,7 +1348,7 @@ uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit } } -void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int color) { +void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { _assert_(binding < MAX_BOUND_TEXTURES); D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; switch (channelBit) { diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index c3d14bb4a7..23c133272d 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -356,7 +356,7 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende } } -void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment) { +void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); _dbg_assert_(binding < MAX_GL_TEXTURE_SLOTS); GLRRenderData data{ GLRRenderCommand::BIND_FB_TEXTURE }; diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 51d7e1e9eb..135f776361 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -526,7 +526,7 @@ public: void BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag); // Binds a framebuffer as a texture, for the following draws. - void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment); + void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit); bool CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); void CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index bb937379ef..91f89e7807 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -358,7 +358,7 @@ public: Framebuffer *GetCurrentRenderTarget() override { return curRenderTarget_; } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1436,7 +1436,7 @@ bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, in return true; } -void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int color) { +void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; _assert_(binding < MAX_TEXTURE_SLOTS); @@ -1453,7 +1453,7 @@ void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBCh aspect |= GL_STENCIL_BUFFER_BIT; boundTextures_[binding] = &fb->framebuffer_->z_stencil_texture; } - renderManager_.BindFramebufferAsTexture(fb->framebuffer_, binding, aspect, color); + renderManager_.BindFramebufferAsTexture(fb->framebuffer_, binding, aspect); } void OpenGLContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 66f3e287e9..a3f61976dc 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -1176,7 +1176,7 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, steps_.push_back(step); } -VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit, int attachment) { +VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit) { _dbg_assert_(curRenderStep_ != nullptr); // We don't support texturing from stencil, neither do we support texturing from depth|stencil together (nonsensical). diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index a96dd96875..074e0c1db4 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -230,7 +230,7 @@ public: // Returns an ImageView corresponding to a framebuffer. Is called BindFramebufferAsTexture to maintain a similar interface // as the other backends, even though there's no actual binding happening here. - VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits, int attachment); + VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits); void BindCurrentFramebufferAsInputAttachment0(VkImageAspectFlags aspectBits); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 7d3b0e8218..adfe90d14c 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -408,7 +408,7 @@ public: Framebuffer *GetCurrentRenderTarget() override { return (Framebuffer *)curFramebuffer_.ptr; } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; void BindCurrentFramebufferForColorInput() override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1563,7 +1563,7 @@ void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPass curFramebuffer_ = fb; } -void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) { +void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { VKFramebuffer *fb = (VKFramebuffer *)fbo; _assert_(binding < MAX_BOUND_TEXTURES); @@ -1583,8 +1583,9 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne _assert_(false); break; } + boundTextures_[binding] = nullptr; - boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment); + boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect); } void VKContext::BindCurrentFramebufferForColorInput() { diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 8c440deb04..2d9ce7f8c5 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -658,7 +658,7 @@ public: virtual Framebuffer *GetCurrentRenderTarget() = 0; // binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2). - virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) = 0; + virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) = 0; // Framebuffer fetch / input attachment support, needs to be explicit in Vulkan. virtual void BindCurrentFramebufferForColorInput() {} diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 295910c4fc..4513493c61 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1168,15 +1168,15 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF copyInfo.fbo = renderCopy; CopyFramebufferForColorTexture(©Info, framebuffer, flags); RebindFramebuffer("After BindFramebufferAsColorTexture"); - draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT); gpuStats.numCopiesForSelfTex++; } else { // Failed to get temp FBO? Weird. - draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT); } return true; } else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) { - draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT); return true; } else { ERROR_LOG_REPORT_ONCE(selfTextureFail, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); @@ -3022,7 +3022,7 @@ void FramebufferManagerCommon::BlitUsingRaster( draw_->BindTexture(0, nullptr); // This will get optimized away in case it's already bound (in VK and GL at least..) draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); - draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); + draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT); if (destX1 == 0.0f && destY1 == 0.0f && destX2 >= destW && destY2 >= destH) { // We overwrite the whole channel of the framebuffer, so we can invalidate the current contents. diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index b771342e49..3fda863d81 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -552,7 +552,7 @@ void PresentationCommon::BindSource(int binding) { if (srcTexture_) { draw_->BindTexture(binding, srcTexture_); } else if (srcFramebuffer_) { - draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT); } else { _assert_(false); } @@ -671,13 +671,13 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u PostShaderUniforms uniforms; const auto performShaderPass = [&](const ShaderInfo *shaderInfo, Draw::Framebuffer *postShaderFramebuffer, Draw::Pipeline *postShaderPipeline) { if (postShaderOutput) { - draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT); } else { BindSource(0); } BindSource(1); if (shaderInfo->usePreviousFrame) - draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT); int nextWidth, nextHeight; draw_->GetFramebufferDimensions(postShaderFramebuffer, &nextWidth, &nextHeight); @@ -765,7 +765,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u draw_->BindPipeline(pipeline); if (postShaderOutput) { - draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT); } else { BindSource(0); } diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index a0c7180588..3877b2df22 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -2197,7 +2197,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer Draw::Viewport vp{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f }; draw_->SetViewports(1, &vp); - draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT); draw_->BindTexture(1, clutTexture.texture); Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false); Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(smoothedDepal); @@ -2213,7 +2213,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer draw_->BindTexture(0, nullptr); framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT); BoundFramebufferTexture(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); @@ -2299,7 +2299,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { draw_->SetViewports(1, &vp); draw_->BindNativeTexture(0, GetNativeTextureView(entry)); - draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT); Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false); Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(false); draw_->BindSamplerStates(0, 1, &nearest); @@ -2314,7 +2314,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { draw_->BindTexture(0, nullptr); framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT); BoundFramebufferTexture(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 7be1adf9d3..5f783e48c7 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -208,7 +208,7 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }; draw_->SetViewports(1, &viewport); - draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT, 0); + draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT); draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &depthReadbackSampler_); // We must bind the program after starting the render pass. @@ -326,7 +326,7 @@ bool FramebufferManagerGLES::ReadbackStencilbufferSync(Draw::Framebuffer *fbo, i Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }; draw_->SetViewports(1, &viewport); - draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT, 0); + draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT); draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilReadbackSampler_); // We must bind the program after starting the render pass. From 2b182417638e0263260f53a0aaa764cd7d7dd427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Oct 2022 10:48:20 +0200 Subject: [PATCH 061/715] Libretro buildfix attempt again --- libretro/Makefile.common | 1 + 1 file changed, 1 insertion(+) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index d205c65f17..7a8fd74121 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -16,6 +16,7 @@ INCFLAGS += \ -I$(CORE_DIR) \ -I$(COMMONDIR) \ -I$(CORE_DIR)/libretro \ + -I$(EXTDIR)/openxr \ -I$(EXTDIR)/glslang \ -I$(EXTDIR)/native \ -I$(EXTDIR)/zlib \ From 9a01db5f422c41eaadc60e1997ee34c7ee27fa6c Mon Sep 17 00:00:00 2001 From: fp64 <106717720+fp64@users.noreply.github.com> Date: Thu, 20 Oct 2022 06:53:49 -0400 Subject: [PATCH 062/715] Change wrap_mode to clamp for bicubic upscaler It was set to wrap, even though the comment claimed otherwise. Previous implementation had clamp, as do (I think) other upscaling modes (Hybrid, etc.). Also make upscaler codestyle a little more consistent with the rest. --- GPU/Common/TextureScalerCommon.cpp | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/GPU/Common/TextureScalerCommon.cpp b/GPU/Common/TextureScalerCommon.cpp index 3c6e946c2f..94624828e6 100644 --- a/GPU/Common/TextureScalerCommon.cpp +++ b/GPU/Common/TextureScalerCommon.cpp @@ -211,10 +211,10 @@ static void load_sample(ptrdiff_t w, ptrdiff_t h, ptrdiff_t s, const u8 *pixels, // equivalent to a>=0&&a= (size_t)w||(size_t)y >= (size_t)h) { + if((size_t)x >= (size_t)w || (size_t)y >= (size_t)h) { switch(wrap_mode) { case 0: // Wrap - if(!((w&(w-1))|(h&(h-1)))) { + if(!((w & (w-1)) | (h & (h-1)))) { // Both w and h are powers of 2. x &= w-1; y &= h-1; @@ -239,7 +239,7 @@ static void load_sample(ptrdiff_t w, ptrdiff_t h, ptrdiff_t s, const u8 *pixels, break; } } - memcpy(output, pixels+s*y+4*x, 4); + memcpy(output, pixels + s*y + 4*x, 4); } #define BLOCK 8 @@ -260,7 +260,7 @@ static void init_block( float w00 = B/6.0f , w01 = -C-0.5f*B, w02 = 2.0f*C+0.5f*B , w03 = -C-B/6.0f ; float w10 = 1.0f-B/3.0f,/*w11 = 0.0f ,*/w12 = C+2.0f*B-3.0f , w13 = -C-1.5f*B+2.0f; float w20 = B/6.0f , w21 = C+0.5f*B, w22 = -2.0f*C-2.5f*B+3.0f, w23 = C+1.5f*B-2.0f; - float /*w30 = 0.0f , w31 = 0.0f ,*/w32 = -C , w33 = C+B/6.0f ; + float /*w30 = 0.0f , w31 = 0.0f ,*/w32 = -C , w33 = C+B/6.0f ; // Express the sampling position as a rational // number num/den-1 (off by one, so that num is // always positive, since the C language does @@ -269,9 +269,9 @@ static void init_block( ptrdiff_t den = 2*factor; float inv_den = 1.0f/(float)den; for(int dir = 0; dir < 2; ++dir) { - ptrdiff_t num = (dir?2*y0+1+factor:2*x0+1+factor); - ptrdiff_t *l = (dir?ly:lx), *l0 = (dir?ly0:lx0), *s = (dir?sy:sx); - float (*c)[4] = (dir?cy:cx); + ptrdiff_t num = (dir ? 2*y0+1+factor : 2*x0+1+factor); + ptrdiff_t *l = (dir ? ly : lx), *l0 = (dir ? ly0 : lx0), *s = (dir ? sy : sx); + float (*c)[4] = (dir ? cy : cx); (*l0) = num/den-2; num = num%den; for(ptrdiff_t i = 0, j = 0; i < BLOCK; ++i) { @@ -288,13 +288,13 @@ static void init_block( (*s) = l[BLOCK-1]+4; // Total sampled src pixels in {x|y} direction. } // Get a local copy of the source pixels. - if((*lx0) >=0 && (*ly0) >= 0 && *lx0+(*sx) <= w && *ly0+(*sy) <= h) { + if((*lx0) >=0 && (*ly0) >= 0 && *lx0 + (*sx) <= w && *ly0 + (*sy) <= h) { for(ptrdiff_t iy = 0; iy < (*sy); ++iy) - memcpy(src[iy], src_pixels+src_stride*((*ly0)+iy)+4*(*lx0), (size_t)(4*(*sx))); + memcpy(src[iy], src_pixels+src_stride*((*ly0) + iy) + 4*(*lx0), (size_t)(4*(*sx))); } else { for(ptrdiff_t iy = 0; iy < (*sy); ++iy) for(ptrdiff_t ix = 0; ix < (*sx); ++ix) - load_sample(w, h, src_stride, src_pixels, wrap_mode, (*lx0)+ix, (*ly0)+iy, src[iy]+4*ix); + load_sample(w, h, src_stride, src_pixels, wrap_mode, (*lx0) + ix, (*ly0) + iy, src[iy] + 4*ix); } } @@ -315,10 +315,10 @@ static void upscale_block_c( for(ptrdiff_t iy = 0; iy < sy; ++iy) for(ptrdiff_t ix = 0; ix < sx; ++ix) for(ptrdiff_t k = 0; k < 4; ++k) - buf[0][iy][ix][k] = (float)(int)src[iy][4*ix+k]; + buf[0][iy][ix][k] = (float)(int)src[iy][4*ix + k]; // Horizontal pass. for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) { - #define S(i) (buf[0][iy][lx[ix]+i][k]) + #define S(i) (buf[0][iy][lx[ix] + i][k]) float C0 = cx[ix][0], C1 = cx[ix][1], C2 = cx[ix][2], C3 = cx[ix][3]; for(ptrdiff_t iy = 0; iy < sy; ++iy) for(ptrdiff_t k = 0; k < 4; ++k) @@ -342,9 +342,9 @@ static void upscale_block_c( float C = buf[0][iy][ix][k]; if(!(C>0.0f)) C = 0.0f; if(C>255.0f) C = 255.0f; - pixel[k] = (u8)(int)(C+0.5f); + pixel[k] = (u8)(int)(C + 0.5f); } - memcpy(dst_pixels+4*(BLOCK*iy+ix), pixel, 4); + memcpy(dst_pixels + 4*(BLOCK*iy + ix), pixel, 4); } } @@ -377,7 +377,7 @@ static void upscale_block_sse2( for(ptrdiff_t iy = 0; iy < sy; ++iy) for(ptrdiff_t ix = 0; ix < sx; ++ix) { int pixel; - memcpy(&pixel, src[iy]+4*ix, 4); + memcpy(&pixel, src[iy] + 4*ix, 4); __m128i C = _mm_cvtsi32_si128(pixel); C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0)); C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0)); @@ -385,7 +385,7 @@ static void upscale_block_sse2( } // Horizontal pass. for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) { - #define S(i) (buf[0][iy][lx[ix]+i]) + #define S(i) (buf[0][iy][lx[ix] + i]) __m128 C0 = _mm_set1_ps(cx[ix][0]), C1 = _mm_set1_ps(cx[ix][1]), C2 = _mm_set1_ps(cx[ix][2]), @@ -395,12 +395,12 @@ static void upscale_block_sse2( _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2), - _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); + _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); #undef S } // Vertical pass. for(ptrdiff_t iy = 0; iy < BLOCK; ++iy) { - #define S(i) (buf[1][ly[iy]+i][ix]) + #define S(i) (buf[1][ly[iy] + i][ix]) __m128 C0 = _mm_set1_ps(cy[iy][0]), C1 = _mm_set1_ps(cy[iy][1]), C2 = _mm_set1_ps(cy[iy][2]), @@ -410,7 +410,7 @@ static void upscale_block_sse2( _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2), - _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); + _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); #undef S } // Pack destination pixels. @@ -423,7 +423,7 @@ static void upscale_block_sse2( R = _mm_packus_epi16(R, R); R = _mm_packus_epi16(R, R); int pixel = _mm_cvtsi128_si32(R); - memcpy(dst_pixels+4*(BLOCK*iy+ix), &pixel, 4); + memcpy(dst_pixels + 4*(BLOCK*iy+ix), &pixel, 4); } } #endif // defined(_M_SSE) @@ -442,7 +442,7 @@ static void upscale_cubic( upscale_block_c (width, height, src_stride_in_bytes, (const u8*)src_pixels, wrap_mode, scale, B, C, x, y, pixels); #endif for(ptrdiff_t iy = 0, ny = (y1-y < BLOCK?y1-y:BLOCK), nx = (x1-x < BLOCK?x1-x:BLOCK); iy < ny; ++iy) - memcpy((u8*)dst_pixels+dst_stride_in_bytes*(y+iy)+4*x, pixels+BLOCK*4*iy, (size_t)(4*nx)); + memcpy((u8*)dst_pixels + dst_stride_in_bytes*(y+iy) + 4*x, pixels + BLOCK*4*iy, (size_t)(4*nx)); } } @@ -450,7 +450,7 @@ static void upscale_cubic( void scaleBicubicBSpline(int factor, u32* data, u32* out, int w, int h, int l, int u) { const float B = 1.0f, C = 0.0f; - const int wrap_mode = 0; // Clamp + const int wrap_mode = 1; // Clamp upscale_cubic( w, h, w*4, data, factor*w*4, out, @@ -460,7 +460,7 @@ void scaleBicubicBSpline(int factor, u32* data, u32* out, int w, int h, int l, i void scaleBicubicMitchell(int factor, u32* data, u32* out, int w, int h, int l, int u) { const float B = 0.0f, C = 0.5f; // Actually, Catmull-Rom - const int wrap_mode = 0; // Clamp + const int wrap_mode = 1; // Clamp upscale_cubic( w, h, w*4, data, factor*w*4, out, From 2c814c568a91e30367a35b37c9c4daf43e0865f9 Mon Sep 17 00:00:00 2001 From: fp64 <106717720+fp64@users.noreply.github.com> Date: Thu, 20 Oct 2022 06:59:35 -0400 Subject: [PATCH 063/715] Some more codestyle cleanup --- GPU/Common/TextureScalerCommon.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GPU/Common/TextureScalerCommon.cpp b/GPU/Common/TextureScalerCommon.cpp index 94624828e6..257836d4f3 100644 --- a/GPU/Common/TextureScalerCommon.cpp +++ b/GPU/Common/TextureScalerCommon.cpp @@ -322,7 +322,7 @@ static void upscale_block_c( float C0 = cx[ix][0], C1 = cx[ix][1], C2 = cx[ix][2], C3 = cx[ix][3]; for(ptrdiff_t iy = 0; iy < sy; ++iy) for(ptrdiff_t k = 0; k < 4; ++k) - buf[1][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3; + buf[1][iy][ix][k] = S(0)*C0 + S(1)*C1 + S(2)*C2 + S(3)*C3; #undef S } // Vertical pass. @@ -331,7 +331,7 @@ static void upscale_block_c( float C0 = cy[iy][0], C1 = cy[iy][1], C2 = cy[iy][2], C3 = cy[iy][3]; for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) for(ptrdiff_t k = 0; k < 4; ++k) - buf[0][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3; + buf[0][iy][ix][k] = S(0)*C0 + S(1)*C1 + S(2)*C2 + S(3)*C3; #undef S } // Pack destination pixels. @@ -429,8 +429,8 @@ static void upscale_block_sse2( #endif // defined(_M_SSE) static void upscale_cubic( - ptrdiff_t width, ptrdiff_t height, ptrdiff_t src_stride_in_bytes, const void *src_pixels, - ptrdiff_t dst_stride_in_bytes, void *dst_pixels, + ptrdiff_t width, ptrdiff_t height, ptrdiff_t src_stride_in_bytes, const void *src_pixels, + ptrdiff_t dst_stride_in_bytes, void *dst_pixels, ptrdiff_t scale, float B, float C, int wrap_mode, ptrdiff_t x0, ptrdiff_t y0, ptrdiff_t x1, ptrdiff_t y1) { u8 pixels[BLOCK*BLOCK*4]; @@ -441,7 +441,7 @@ static void upscale_cubic( #else upscale_block_c (width, height, src_stride_in_bytes, (const u8*)src_pixels, wrap_mode, scale, B, C, x, y, pixels); #endif - for(ptrdiff_t iy = 0, ny = (y1-y < BLOCK?y1-y:BLOCK), nx = (x1-x < BLOCK?x1-x:BLOCK); iy < ny; ++iy) + for(ptrdiff_t iy = 0, ny = (y1-y < BLOCK ? y1-y : BLOCK), nx = (x1-x < BLOCK ? x1-x : BLOCK); iy < ny; ++iy) memcpy((u8*)dst_pixels + dst_stride_in_bytes*(y+iy) + 4*x, pixels + BLOCK*4*iy, (size_t)(4*nx)); } } From 3009c6ee1a58a26b4e101f5c4420d4eadd3652a3 Mon Sep 17 00:00:00 2001 From: xujibbs <79200793+xujibbs@users.noreply.github.com> Date: Thu, 20 Oct 2022 19:45:33 +0800 Subject: [PATCH 064/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 486a2d5230..e095a43345 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -714,6 +714,7 @@ Up = 方向键:上 Vol + = 音量+ Vol - = 音量- Wlan = 无线网络 +Analog speed = 模拟速度 [MemStick] Already contains PSP data = 已含有PSP数据 From 77f8f2f1f7b80ccb160deb09077f066e10db6689 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 20 Oct 2022 21:04:56 +0200 Subject: [PATCH 065/715] OpenXR - Rearrange VR settings --- UI/GameSettingsScreen.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 153f03d69c..a02190445a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1123,14 +1123,15 @@ void GameSettingsScreen::CreateViews() { if (deviceType == DEVICE_TYPE_VR) { LinearLayout *vrSettings = AddTab("GameSettingsVR", ms->T("VR")); vrSettings->Add(new ItemHeader(vr->T("Virtual reality"))); - vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Enable virtual reality"))); - vrSettings->Add(new PopupSliderChoice(&g_Config.iCanvasDistance, 1, 10, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1, screenManager(), "")); - CheckBox *vr6DoF = vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("Enable 6 degrees of freedom movement"))); + vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Virtual reality"))); + CheckBox *vr6DoF = vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("6DoF movement"))); vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); - PopupSliderChoice *vrFieldOfView = vrSettings->Add(new PopupSliderChoice(&g_Config.iFieldOfViewPercentage, 100, 200, vr->T("Field of view scale", "Headset's field of view scale"), 10, screenManager(), vr->T("% of native FoV"))); - vrFieldOfView->SetEnabledPtr(&g_Config.bEnableVR); - CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Enable stereoscopic vision (Experimental)"))); + CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); vrStereo->SetEnabledPtr(&g_Config.bEnableVR); + + vrSettings->Add(new ItemHeader(vr->T("VR camera"))); + vrSettings->Add(new PopupSliderChoice(&g_Config.iCanvasDistance, 1, 10, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1, screenManager(), "")); + vrSettings->Add(new PopupSliderChoice(&g_Config.iFieldOfViewPercentage, 100, 200, vr->T("Field of view scale", "Headset's field of view scale"), 10, screenManager(), vr->T("% of native FoV"))); } } From 2fd6438c0e515ca29995dbef5a07987b916f4adf Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 20 Oct 2022 21:23:27 +0200 Subject: [PATCH 066/715] OpenXR - Camera distance adjust added --- Common/VR/PPSSPPVR.cpp | 1 + Common/VR/VRRenderer.cpp | 8 ++++++++ Common/VR/VRRenderer.h | 2 +- Core/Config.cpp | 1 + Core/Config.h | 1 + UI/GameSettingsScreen.cpp | 1 + 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 41101cdd9a..edb88a3400 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -319,6 +319,7 @@ bool StartVRRender() { // Set customizations VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); + VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.iCameraDistance); VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.iCanvasDistance); VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.iFieldOfViewPercentage); VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, false); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index d4b35c596d..5a8084941b 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -338,6 +338,14 @@ bool VR_InitFrame( engine_t* engine ) { vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; } + if (abs(vrConfig[VR_CONFIG_CAMERA_DISTANCE]) > 0) { + XrVector3f forward = {0.0f, 0.0f, (float)vrConfig[VR_CONFIG_CAMERA_DISTANCE] * scale}; + forward = XrQuaternionf_Rotate(invView.orientation, forward); + forward = XrVector3f_ScalarMultiply(forward, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); + vrMatrix[matrix].M[0][3] += forward.x; + vrMatrix[matrix].M[1][3] += forward.y; + vrMatrix[matrix].M[2][3] += forward.z; + } if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 16f70d9411..1c93f98752 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -7,7 +7,7 @@ enum VRConfig { //switching between 2D and 3D VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, //camera setup - VR_CONFIG_FOV_SCALE, VR_CONFIG_CANVAS_DISTANCE, + VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_DISTANCE, VR_CONFIG_CANVAS_DISTANCE, //6DoF VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, diff --git a/Core/Config.cpp b/Core/Config.cpp index 650e1812fa..1e44ed482b 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1206,6 +1206,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VREnable", &g_Config.bEnableVR, true), ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, true), ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false), + ConfigSetting("VRCameraDistance", &g_Config.iCameraDistance, 0), ConfigSetting("VRCanvasDistance", &g_Config.iCanvasDistance, 6), ConfigSetting("VRFieldOfView", &g_Config.iFieldOfViewPercentage, 100), diff --git a/Core/Config.h b/Core/Config.h index 10748583a9..497e8266bd 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -457,6 +457,7 @@ public: bool bEnableVR; bool bEnable6DoF; bool bEnableStereo; + int iCameraDistance; int iCanvasDistance; int iFieldOfViewPercentage; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index a02190445a..158fc547d0 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1130,6 +1130,7 @@ void GameSettingsScreen::CreateViews() { vrStereo->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); + vrSettings->Add(new PopupSliderChoice(&g_Config.iCameraDistance, -10, 10, vr->T("Camera distance adjust", "Camera distance adjust"), 1, screenManager(), "")); vrSettings->Add(new PopupSliderChoice(&g_Config.iCanvasDistance, 1, 10, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1, screenManager(), "")); vrSettings->Add(new PopupSliderChoice(&g_Config.iFieldOfViewPercentage, 100, 200, vr->T("Field of view scale", "Headset's field of view scale"), 10, screenManager(), vr->T("% of native FoV"))); } From e048c5ded88d1b9e2da623ea79423d7af7cfbc1b Mon Sep 17 00:00:00 2001 From: leoxxx <5364709+leoxxx@users.noreply.github.com> Date: Fri, 21 Oct 2022 10:15:17 +0800 Subject: [PATCH 067/715] Update zh_CN.ini https://github.com/hrydgard/ppsspp/pull/15694 Translate "artifacts" to a straightaway meaning. --- assets/lang/zh_CN.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index e095a43345..9ca27412e8 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -517,7 +517,7 @@ Linear = 线性过滤 Low = 低 LowCurves = 低品质样条函数/贝塞尔曲线(提速) LowCurves Tip = 仅对部分游戏有效, 控制曲线的平滑度 -Lower resolution for effects (reduces artifacts) = 降低特效分辨率(减少失真) +Lower resolution for effects (reduces artifacts) = 降低特效分辨率(减少图像错误) Manual Scaling = 手动缩放 Medium = 中 Mode = 渲染模式 From ad06868a13e7d42afd2430f5000420f4526c6a02 Mon Sep 17 00:00:00 2001 From: leoxxx <5364709+leoxxx@users.noreply.github.com> Date: Fri, 21 Oct 2022 10:21:48 +0800 Subject: [PATCH 068/715] Update zh_TW.ini #15694 Translate "artifacts" to a straightaway meaning. Change 2 words to TC. --- assets/lang/zh_TW.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 3559284b19..6f57d92d16 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -516,12 +516,12 @@ Hybrid + Bicubic = 混合+雙立方 Ignore camera notch when centering = 居中時忽略攝像頭缺口 Internal Resolution = 內部分辨率 Lazy texture caching = 緩慢紋理快取(提升速度) -Lazy texture caching Tip = 更快,在一些游戲裏會引起文字渲染錯誤更快, 在一些游戏里引起文字渲染错误 +Lazy texture caching Tip = 更快,在一些游戲裏會引起文字渲染錯誤更快, 在一些游戏里引起文字渲染錯誤 Linear = 線性 Low = 低 LowCurves = 樣條函數/貝茲曲線品質 LowCurves Tip = 此選項將顯著提高/降低渲染樣條和貝塞爾曲線的質量 -Lower resolution for effects (reduces artifacts) = 降低效果的解析度(減少失真) +Lower resolution for effects (reduces artifacts) = 降低效果的解析度(減少圖像錯誤) Manual Scaling = 手動縮放 Medium = 中 Mode = 模式 From d6a59be012908bd7324b07a0b3beea06c896a82e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 20 Oct 2022 23:09:48 -0700 Subject: [PATCH 069/715] softgpu: Respect negate normal flag without norm. Per tests, Z is still negated even when using the previous normal value. --- GPU/Software/TransformUnit.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index fbbdcd3919..ac52ef180f 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -337,17 +337,12 @@ ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformS vertex.v.texturecoords = lastTC; } - Vec3f normal; static Vec3f lastnormal; - if (vreader.hasNormal()) { - vreader.ReadNrm(normal.AsArray()); - lastnormal = normal; - - if (state.negateNormals) - normal = -normal; - } else { - normal = lastnormal; - } + if (vreader.hasNormal()) + vreader.ReadNrm(lastnormal.AsArray()); + Vec3f normal = lastnormal; + if (state.negateNormals) + normal = -normal; if (state.readWeights) { float W[8] = { 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }; From 6945604492a1e09b05ce5de4aa2e6f67c37d39a6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 20 Oct 2022 23:10:56 -0700 Subject: [PATCH 070/715] softgpu: Multiply prev normal by world matrix. Even when it's not in the vertex data, we still must multiply by the world matrix. Fixes some lighting issues in Nayuta no Kiseki. --- GPU/Software/TransformUnit.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index ac52ef180f..043683b88c 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -411,11 +411,9 @@ ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformS vertex.v.clipw = vertex.clippos.w; Vec3 worldnormal; - if (vreader.hasNormal()) { + if (state.enableLighting || state.uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP) { worldnormal = TransformUnit::ModelToWorldNormal(normal); worldnormal.NormalizeOr001(); - } else { - worldnormal = Vec3(0.0f, 0.0f, 1.0f); } // Time to generate some texture coords. Lighting will handle shade mapping. From d23293ee72b3b8ed0af9545cf84ce2c5ecebf01d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 20 Oct 2022 23:15:25 -0700 Subject: [PATCH 071/715] GPU: Respect matrix and reverse flag w/o normals. See frame dump in #14223, which requires world matrix be applied. --- GPU/Common/VertexShaderGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 45433a72d7..a90299c57e 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -869,7 +869,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (hasNormalTess) { WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(%stess.nrm, 0.0), u_world).xyz);\n", flipNormalTess ? "-" : ""); } else { - WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); + WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormalTess ? "-" : ""); } } else { // No skinning, just standard T&L. @@ -877,7 +877,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (hasNormal) WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(%snormal, 0.0), u_world).xyz);\n", flipNormal ? "-" : ""); else - WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); + WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormal ? "-" : ""); } } else { static const char *rescale[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f}; From cafce7365b2a8c11a51af5b3fd19d4ea13bd2396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 21 Oct 2022 12:52:21 +0200 Subject: [PATCH 072/715] Vulkan: Fix frame ordering issue with postprocessing shaders Requested an init command buffer outside the frame, which is dangerous and caused validation problems with command pool resets. Would like to assert on insideFrame in GetInitCmd, but we use it from some init code where it does work correctly. Might clean that up at some point. --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 12 ++++++++++-- GPU/Common/FramebufferManagerCommon.h | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index a3f61976dc..8da78975d2 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -612,9 +612,9 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling, bool enableLogProfile // Must be after the fence - this performs deletes. VLOG("PUSH: BeginFrame %d", curFrame); + insideFrame_ = true; vulkan_->BeginFrame(enableLogProfiler ? GetInitCmd() : VK_NULL_HANDLE); - insideFrame_ = true; renderStepOffset_ = 0; frameData.profile.timestampDescriptions.clear(); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 4513493c61..07f933778f 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -108,6 +108,13 @@ bool FramebufferManagerCommon::UpdateSize() { void FramebufferManagerCommon::BeginFrame() { DecimateFBOs(); + + // Might have a new post shader - let's compile it. + if (updatePostShaders_) { + presentation_->UpdatePostShader(); + updatePostShaders_ = false; + } + currentRenderVfb_ = nullptr; } @@ -2349,8 +2356,9 @@ void FramebufferManagerCommon::Resized() { DestroyAllFBOs(); } - // Might have a new post shader - let's compile it. - presentation_->UpdatePostShader(); + // No drawing is allowed here. This includes anything that might potentially touch a command buffer, like creating images! + // So we need to defer the post processing initialization. + updatePostShaders_ = true; #ifdef _WIN32 // Seems related - if you're ok with numbers all the time, show some more :) diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index ffcab7a1ec..5a85d93541 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -544,6 +544,7 @@ protected: int pixelWidth_ = 0; int pixelHeight_ = 0; int bloomHack_ = 0; + bool updatePostShaders_ = false; Draw::DataFormat preferredPixelsFormat_ = Draw::DataFormat::R8G8B8A8_UNORM; From f2193814eeca7eeaf3c7b5cb5214f11e4123ca7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 21 Oct 2022 14:18:18 +0200 Subject: [PATCH 073/715] PresentationCommon: Use refcounts to simplify shader module management --- GPU/Common/PresentationCommon.cpp | 8 ++++---- GPU/Common/PresentationCommon.h | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 3fda863d81..bb3a6d8fad 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -307,6 +307,10 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha } }; Draw::Pipeline *pipeline = CreatePipeline({ vs, fs }, true, &postShaderDesc); + + fs->Release(); + vs->Release(); + if (!pipeline) return false; @@ -504,7 +508,6 @@ void PresentationCommon::DestroyDeviceObjects() { void PresentationCommon::DestroyPostShader() { usePostShader_ = false; - DoReleaseVector(postShaderModules_); DoReleaseVector(postShaderPipelines_); DoReleaseVector(postShaderFramebuffers_); DoReleaseVector(previousFramebuffers_); @@ -521,10 +524,7 @@ Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, S return nullptr; } } - Draw::ShaderModule *shader = draw_->CreateShaderModule(stage, lang_, (const uint8_t *)translated.c_str(), translated.size(), "postshader"); - if (shader) - postShaderModules_.push_back(shader); return shader; } diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index 7ce81117b8..ea51fb0b5c 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -129,7 +129,6 @@ protected: Draw::Buffer *vdata_ = nullptr; Draw::Buffer *idata_ = nullptr; - std::vector postShaderModules_; std::vector postShaderPipelines_; std::vector postShaderFramebuffers_; std::vector postShaderInfo_; From 6aa3e4b2424971880ef47df4a6cc2588359e22e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 21 Oct 2022 15:42:32 +0200 Subject: [PATCH 074/715] Minor refactoring in PresentationCommon Broken out from stereo work --- GPU/Common/PresentationCommon.cpp | 36 +++++++++++++++++++++---------- GPU/Common/PresentationCommon.h | 15 +++++++------ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index bb3a6d8fad..ce3e155c93 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -157,7 +157,7 @@ PresentationCommon::~PresentationCommon() { DestroyDeviceObjects(); } -void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettings) { +void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettings) const { if (!g_Config.bEnableCardboardVR) { cardboardSettings->enabled = false; return; @@ -183,7 +183,7 @@ void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettin cardboardSettings->screenHeight = cardboardScreenHeight; } -void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) { +void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) const { float u_delta = 1.0f / bufferWidth; float v_delta = 1.0f / bufferHeight; float u_pixel_delta = 1.0f / targetWidth; @@ -234,17 +234,23 @@ bool PresentationCommon::UpdatePostShader() { } DestroyPostShader(); - if (shaderInfo.empty()) + if (shaderInfo.empty()) { + usePostShader_ = false; return false; + } bool usePreviousFrame = false; bool usePreviousAtOutputResolution = false; for (size_t i = 0; i < shaderInfo.size(); ++i) { const ShaderInfo *next = i + 1 < shaderInfo.size() ? shaderInfo[i + 1] : nullptr; - if (!BuildPostShader(shaderInfo[i], next)) { + Draw::Pipeline *postPipeline = nullptr; + if (!BuildPostShader(shaderInfo[i], next, &postPipeline)) { DestroyPostShader(); return false; } + _dbg_assert_(postPipeline); + postShaderPipelines_.push_back(postPipeline); + postShaderInfo_.push_back(*shaderInfo[i]); if (shaderInfo[i]->usePreviousFrame) { usePreviousFrame = true; usePreviousAtOutputResolution = shaderInfo[i]->outputResolution; @@ -272,7 +278,7 @@ bool PresentationCommon::UpdatePostShader() { return true; } -bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next) { +bool PresentationCommon::CompilePostShader(const ShaderInfo *shaderInfo, Draw::Pipeline **outPipeline) const { std::string vsSourceGLSL = ReadShaderSrc(shaderInfo->vertexShaderFile); std::string fsSourceGLSL = ReadShaderSrc(shaderInfo->fragmentShaderFile); if (vsSourceGLSL.empty() || fsSourceGLSL.empty()) { @@ -314,6 +320,15 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha if (!pipeline) return false; + *outPipeline = pipeline; + return true; +} + +bool PresentationCommon::BuildPostShader(const ShaderInfo * shaderInfo, const ShaderInfo * next, Draw::Pipeline **outPipeline) { + if (!CompilePostShader(shaderInfo, outPipeline)) { + return false; + } + if (!shaderInfo->outputResolution || next) { int nextWidth = renderWidth_; int nextHeight = renderHeight_; @@ -341,13 +356,12 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha } if (!AllocateFramebuffer(nextWidth, nextHeight)) { - pipeline->Release(); + (*outPipeline)->Release(); + *outPipeline = nullptr; return false; } } - postShaderPipelines_.push_back(pipeline); - postShaderInfo_.push_back(*shaderInfo); return true; } @@ -416,7 +430,7 @@ void PresentationCommon::DeviceRestore(Draw::DrawContext *draw) { CreateDeviceObjects(); } -Draw::Pipeline *PresentationCommon::CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc) { +Draw::Pipeline *PresentationCommon::CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc) const { using namespace Draw; Semantic pos = SEM_POSITION; @@ -515,7 +529,7 @@ void PresentationCommon::DestroyPostShader() { postShaderFBOUsage_.clear(); } -Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) { +Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) const { std::string translated = src; if (lang != lang_) { // Gonna have to upconvert the shader. @@ -816,7 +830,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u previousUniforms_ = uniforms; } -void PresentationCommon::CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) { +void PresentationCommon::CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) const { // Check if postprocessing shader is doing upscaling as it requires native resolution std::vector shaderInfo; if (!g_Config.vPostShaderNames.empty()) { diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index ea51fb0b5c..c3faff6568 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -102,24 +102,25 @@ public: void SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidth, int bufferHeight); void CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1); - void CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa); + void CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) const; protected: void CreateDeviceObjects(); void DestroyDeviceObjects(); void DestroyPostShader(); - void ShowPostShaderError(const std::string &errorString); + static void ShowPostShaderError(const std::string &errorString); - Draw::ShaderModule *CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString); - Draw::Pipeline *CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc); - bool BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next); + Draw::ShaderModule *CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) const; + Draw::Pipeline *CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc) const; + bool CompilePostShader(const ShaderInfo *shaderInfo, Draw::Pipeline **outPipeline) const; + bool BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next, Draw::Pipeline **outPipeline); bool AllocateFramebuffer(int w, int h); void BindSource(int binding); - void GetCardboardSettings(CardboardSettings *cardboardSettings); - void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms); + void GetCardboardSettings(CardboardSettings *cardboardSettings) const; + void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) const; Draw::DrawContext *draw_; Draw::Pipeline *texColor_ = nullptr; From 6a6ccb4c68acb6c80dab8e3f188e0332a0db447d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 21 Oct 2022 18:47:28 +0200 Subject: [PATCH 075/715] Apply Kyria's updates to tr_TR (Turkish) translation --- assets/lang/tr_TR.ini | 179 +++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 90 deletions(-) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index d6c04817fd..4af52fed3c 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1,12 +1,12 @@ [Audio] -Alternate speed volume = Alternatif hız sesi +Alternate speed volume = Alternatif hız hacmi Audio backend = Ses alttabanı (Yeniden başlatma gerekir) Audio Error = Ses Hatası -AudioBufferingForBluetooth = Bluetooth-uyumlu arabellek (daha yavaş) -Auto = Auto +AudioBufferingForBluetooth = Bluetooth uyumlu arabellek (daha yavaş) +Auto = Otomatik Device = Cihaz Disabled = Devre dışı -DSound (compatible) = DSound (Uyumlu) +DSound (compatible) = DSound (uyumlu) Enable Sound = Sesi etkinleştir Global volume = Genel ses Microphone = Mikrofon @@ -15,10 +15,10 @@ Mute = Sessiz Reverb volume = Yankı sesi Use new audio devices automatically = Otomatik olarak yeni ses cihazlarını kullan Use global volume = Genel ses seviyesini kullan -WASAPI (fast) = WASAPI (Hızlı) +WASAPI (fast) = WASAPI (hızlı) [Controls] -Analog Binding = Analog Binding +Analog Binding = Analog Bağlama Analog Limiter = Analog sınırlayıcı Analog Settings = Analog Ayarları Analog Stick = Analog çubuk @@ -31,9 +31,9 @@ Auto-rotation speed = Otomatik rotasyon hızı Auto-switch = Oto-switch Base tilt position = Base tilt position Binds = Binds -Button Binding = Button Binding +Button Binding = Düğme Bağlama Button Opacity = Tuş görünürlüğü -Button style = Tuş biçimi +Button style = Tuş stili Calibrate Analog Stick = Analog Çubuğu Kalibre Et Calibrate D-Pad = D-Pad'i kalibre et Calibrated = Kalibre edildi @@ -44,7 +44,7 @@ Confine Mouse = Fareyi belirli bir pencere/görüntü alanı içinde sınırla Control Mapping = Kontrolleri Ayarla Custom Key Setting = Özel Tuş Ayarı Customize = Düzenle -Customize Touch Controls = Dokunmatik kontrol düzenini düzenle... +Customize Touch Controls = Dokunmatik kontrolleri düzenle... Customize tilt = Eğimi düzenle... D-PAD = D-Pad Deadzone radius = Ölü bölge yarıçapı @@ -70,22 +70,22 @@ L/R Trigger Buttons = L/R Tetik düğmeleri Landscape = Yatay Landscape Auto = Otomatik yatay Landscape Reversed = Ters yatay -Low end radius = Low end radius +Low end radius = Düşük uç yarıçapı Mouse = Fare ayarları Mouse sensitivity = Fare hassasiyeti Mouse smoothing = Fare yumuşatma MouseControl Tip = Fareye 'Kontrolleri Ayarlama' bölümünden 'M' simgesine basarak kontrol atayabilirsiniz. -None (Disabled) = Hiçbiri (Devre Dışı) +None (Disabled) = Hiçbiri (Devre dışı) Off = Kapalı OnScreen = Dokunmatik ekran kontrolleri Portrait = Dikey Portrait Reversed = Ters dikey PSP Action Buttons = PSP eylem tuşları -Raw input = Ham girdi -Repeat mode = Repeat mode +Raw input = Saf girdi +Repeat mode = Tekrar modu Reset to defaults = Varsayılanlara sıfırla Screen aligned to ground = Ekran yere hizalansın -Screen at right angle to ground = Screen at right angle to ground +Screen at right angle to ground = Yere dik açıda ekran Screen Rotation = Ekran rotasyonu seconds, 0 : off = saniyeler, 0 = kapalı Sensitivity (scale) = Hassasiyet (ölçek) @@ -101,7 +101,7 @@ Tilt Input Type = Eğim giriş türü Tilt Sensitivity along X axis = X ekseni boyunca eğim hassasiyeti Tilt Sensitivity along Y axis = Y ekseni boyunca eğim hassasiyeti To Calibrate = Kalibre etmek için cihazı düz bir zemine yerleştirin ve "Kalibre et" tuşuna basın. -Toggle mode = Toggle mode +Toggle mode = Geçiş modu Touch Control Visibility = Dokunmatik kontrol görünürlüğü Use custom right analog = Özel sağ analog kullan Use Mouse Control = Fareyle kontrolü etkinleştir @@ -116,7 +116,7 @@ Edit Cheat File = Hile dosyasını düzenle Enable/Disable All = Bütün hileleri Aç/Kapat Import Cheats = cheat.db'den hile al Options = Ayarlar -Refresh Rate = Yenileme hızı +Refresh Rate = Yenileme Hızı [DesktopUI] # EN: If your language does not show well with the default font, you can use Font to specify a different one. @@ -492,6 +492,7 @@ Deposterize Tip = Yeniden ölçeklenen dokulardaki görsel şerit hatalarını d Device = Cihaz Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 +Disable slower effects (speedup) = Daha yavaş efektleri kapatın (daha hızlı) Disabled = Devre dışı Display layout editor = Görüntü Düzeni Düzenleyicisi Display Resolution (HW scaler) = Görüntü Çözünürlüğü (HW scaler) @@ -602,7 +603,7 @@ You can press ESC to cancel. = İptal etmek için Esc'ye basabilirsiniz. [MainMenu] Browse = Aç... -Buy PPSSPP Gold = Buy PPSSPP Gold +Buy PPSSPP Gold = PPSSPP Gold'u Al Choose folder = Klasör seç Credits = Emeği Geçenler PPSSPP Homebrew Store = PPSSPP Bağımsız Yapım Mağazası @@ -630,7 +631,7 @@ Audio = Ses Controls = Kontroller Graphics = Grafik Networking = Ağ ayarları -Search = Search +Search = Ara System = Sistem Tools = Araçlar @@ -758,8 +759,6 @@ Center Left = Sol orta Center Right = Sağ orta Change Mac Address = MAC adresini değiştir Change proAdhocServer Address = PRO Ad Hoc Server IP adresini değiştir (localhost = çoklu örnek) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Chat Chat Button Position = Chat düğmesinin konumu Chat Here = Buraya yazın @@ -771,13 +770,13 @@ Enable built-in PRO Adhoc Server = Yerleşik PRO Ad Hoc Sunucusunu etkinleştir Enable network chat = Ağ sohbetini etkinleştir Enable networking = Ağ Oluşturma/WLAN'ı aç (Henüz Beta, oyun çökebilir.) Enable UPnP = UPnP'yi etkinleştirin (algılamak için birkaç saniye gerekir) -EnableQuickChat = Hızlı chat'i etkinleştirin +EnableQuickChat = Hızlı sohbeti etkinleştirin Enter a new PSP nickname = Yeni bir PSP kullanıcı adı girin -Enter Quick Chat 1 = Hızlı chat 1'e girin -Enter Quick Chat 2 = Hızlı chat 2'ye girin -Enter Quick Chat 3 = Hızlı chat 3'e girin -Enter Quick Chat 4 = Hızlı chat 4'e girin -Enter Quick Chat 5 = Hızlı chat 5'e girin +Enter Quick Chat 1 = Hızlı sohbet 1'e girin +Enter Quick Chat 2 = Hızlı sohbet 2'ye girin +Enter Quick Chat 3 = Hızlı sohbet 3'e girin +Enter Quick Chat 4 = Hızlı sohbet 4'e girin +Enter Quick Chat 5 = Hızlı sohbet 5'e girin Error = Hata Failed to Bind Localhost IP = Failed to bind localhost IP Failed to Bind Port = Failed to bind port @@ -794,11 +793,11 @@ Please change your Port Offset = Lütfen Port Offset'i değiştirin Port offset = Port offset(0 = PSP uyumluluğu) Open PPSSPP Multiplayer Wiki Page = PPSSPP Ad-Hoc Wiki Sayfası proAdhocServer Address: = Ad hoc sunucu adresi: -Quick Chat 1 = Hızlı chat 1 -Quick Chat 2 = Hızlı chat 2 -Quick Chat 3 = Hızlı chat 3 -Quick Chat 4 = Hızlı chat 4 -Quick Chat 5 = Hızlı chat 5 +Quick Chat 1 = Hızlı sohbet 1 +Quick Chat 2 = Hızlı sohbet 2 +Quick Chat 3 = Hızlı sohbet 3 +Quick Chat 4 = Hızlı sohbet 4 +Quick Chat 5 = Hızlı sohbet 5 QuickChat = Hızlı sohbet Send = Gönder Send Discord Presence information = Discord "Rich Presence" bilgisi gönder @@ -868,8 +867,8 @@ Vignette = Vinyet all the forum mods = Bütün forum modlarına build server = build server Buy Gold = Altın Sürümü alın -check = Ayrıca Etraftaki En İyi Wii/GC Emülatörü Olan Dolphin'e Gözatın: -CheckOutPPSSPP = Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/ +check = Ayrıca etraftaki en iyi Wii/GC emülatörü olan Dolphin'e göz atın: +CheckOutPPSSPP = PPSSPP'ye göz atın: https://www.ppsspp.org/ contributors = Yardımcılar: created = Yaratıcı Discord = Discord @@ -877,18 +876,18 @@ info1 = PPSSPP sadece eğitimsel amaçlar için tasarlandı. info2 = Lütfen oynadığınız herhangi bir oyunun haklarına sahip olduğunuzu, info3 = oyunun UMD'sini veya PSP'niz üzerinden info4 = PSN Store'dan dijital sürümünü satın alarak emin olunuz. -info5 = PSP SONY'nin tescilli markasıdır. -iOS builds = iOS builds +info5 = PSP, Sony'nin tescilli markasıdır. +iOS builds = iOS derlemeleri license = GPL 2.0+ altında bir "özgür yazılım" list = Uyumluluk Listeleri, Forumlar ve Geliştirme Bilgisi PPSSPP Forums = PPSSPP Forumları -Privacy Policy = Privacy policy +Privacy Policy = Gizlilik politikası Share PPSSPP = PPSSPP'yi Paylaş specialthanks = Özel Teşekkürler: specialthanksKeithGalocy = at NVIDIA (hardware, advice) specialthanksMaxim = for his amazing Atrac3+ decoder work -testing = testing -this translation by = Türkçe Çeviri Yapan: +testing = test +this translation by = Türkçe çeviri: title = Hızlı ve Taşınabilir PSP Emülatörü tools = Kullanılan Ücretsiz Araçlar: # Add translators or contributors who translated PPSSPP into your language here. @@ -896,12 +895,12 @@ tools = Kullanılan Ücretsiz Araçlar: # Leave extra lines blank. 4 contributors per line seems to look best. translators1 = Gravityy translators2 = mygizli04 -translators3 = kishiradarken1867 +translators3 = Kyria Crown translators4 = translators5 = translators6 = -Twitter @PPSSPP_emu = Twitter @PPSSPP_emu -website = PPSSPP.org'u Ziyaret Et +Twitter @PPSSPP_emu = Twitter +website = PPSSPP.org written = Hız ve Taşınabilirlik için C++ ile Yazıldı [RemoteISO] @@ -935,7 +934,7 @@ FeedbackIncludeCRC = Not: Batarya diskin döngüsel artıklık denetimini yollam FeedbackIncludeScreen = Ekran görüntüsü dahil et FeedbackSubmitDone = Veriniz gönderildi. FeedbackSubmitFail = Veri sunucuya gönderilemedi. PPSSPP'yi güncellemeyi deneyin. -FeedbackThanks = Geribildirimin için teşekkürler! +FeedbackThanks = Geribildiriminiz için teşekkürler! Gameplay = Oynanış Graphics = Grafikler Great = İyi @@ -958,20 +957,20 @@ Speed = Hız Submit Feedback = Geribildirimi yolla SuggestionConfig = İyi ayarlar için sitedeki ayarlara bakın. SuggestionCPUSpeed0 = Kilitlenmiş CPU hızını kapat. -SuggestionDowngrade = Daha eski bir PPSSPP sürümüne indirin ( Bu bugu rapor edin, lütfen. ) -SuggestionsFound = Diğer kullanıcılar daha iyi sonuçlar rapor etti. Daha fazla ayrıntı için "Geri dönüşü görüntüle" tuşuna basın. +SuggestionDowngrade = Daha eski bir PPSSPP sürümüne indirin (Lütfen bu hatayı raporlayın.) +SuggestionsFound = Diğer kullanıcılar daha iyi sonuçlar raporladı. Daha fazla ayrıntı için "Geribildirimi görüntüle"ye basın. SuggestionsNone = Bu oyun diğer kullanıcılar için de çalışmıyor. SuggestionsWaiting = Gönderiliyor ve diğer kullanıcıların da sonuçlarına bakılıyor... SuggestionUpgrade = Daha yeni bir PPSSPP sürümüne güncelleyin. SuggestionVerifyDisc = ISO dosyanızın doğru olduğunu kontrol edin. -Unselected Overall Description = Bu oyun nasıl simule ediliyor? +Unselected Overall Description = Bu oyun nasıl simüle ediliyor? View Feedback = Bütün geribildirimleri göster [Savedata] -Date = Date +Date = Tarih Filename = Dosya adı No screenshot = Ekran görüntüsü yok -None yet. Things will appear here after you save. = Henüz birşey yok.Kayıt aldığında kayıtların burada gözükecek. +None yet. Things will appear here after you save. = Henüz bir şey yok. Kayıt aldığında kayıtların burada görünecek. Nothing matching '%1' was found. = '%1' ile eşleşen hiçbir şey bulunamadı. Save Data = Normal Kayıtlar Save States = Durum Kayıtları @@ -986,7 +985,7 @@ Failed to load state = Durum yüklenemedi. Failed to save state = Durum kaydedilemedi. fixed = Hız: Alternatif GLToolsWarning = UYARI: GLTools algılandı, problemlere sebep olabilir. -In menu = In menu +In menu = Menüde Load savestate failed = Durum kaydı yüklenemedi. Loaded State = Durum yüklendi. Loaded. Game may refuse to save over different savedata. = Yüklendi. Oyun belki farklı verilerin üzerine kaydetmeyi reddedebilir. @@ -996,7 +995,7 @@ LoadStateDoesntExist = Durum yüklenemedi: Durum kaydı yerinde yok! LoadStateWrongVersion = Durum yüklenemedi: Durum kaydı eski bir PPSSPP versiyonu için uygun! norewind = Geriye sarma durumu bulunamadı. Playing = Oynatılıyor... -PressESC = PPSSPP menüsünü açmak için ESC'ye bas. +PressESC = PPSSPP menüsünü açmak için ESC'ye basın. replaceTextures_false = Dokular artık değiştirilmiyor. replaceTextures_true = Doku değiştirme etkinleştirildi. Save State Failed = Durum kaydı yapılamadı! @@ -1009,11 +1008,11 @@ State load undone = Durum yüklemesi tamamlanmadı Untitled PSP game = Başlıksız PSP oyunu [Search] -Clear filter = Clear filter -Filter = Filter -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -No settings matched '%1' = No settings matched '%1' +Clear filter = Filtreyi temizle +Filter = Filtre +Filtering settings by '%1' = Ayarlar '%1''e göre filtreleniyor +Find settings = Ayarları ara +No settings matched '%1' = '%1' ile eşleşen ayar yok [Store] Already Installed = Zaten yüklü @@ -1047,9 +1046,9 @@ Debug = Hata Ayıklama Debugger Present = Hata ayıklayıcı var Device Info = Cihaz bilgisi Directories = Dizinler -Display Color Formats = Display Color Formats +Display Color Formats = Renk Biçimlerini Görüntüle Display Information = Ekran bilgisi -Driver bugs = Driver bugs +Driver bugs = Sürücü hataları Driver Version = Sürücü sürümü EGL Extensions = EGL eklentileri Frames per buffer = Tampon başına çerçeveler @@ -1058,19 +1057,19 @@ High precision float range = High precision float range High precision int range = High precision int range Lang/Region = Dil/Bölge Memory Page Size = Bellek sayfa boyutu -Native Resolution = Doğal çözünürlük -No GPU driver bugs detected = No GPU driver bugs detected +Native Resolution = Yerel çözünürlük +No GPU driver bugs detected = GPU sürücü hatası algılanmadı OGL Extensions = OGL eklentileri OpenGL ES 2.0 Extensions = OpenGL ES 2.0 eklentileri OpenGL ES 3.0 Extensions = OpenGL ES 3.0 eklentileri OpenGL Extensions = OpenGL eklentileri Optimal frames per buffer = Optimum tampon başına çerçeveler Optimal sample rate = Optimum örnekleme hızı -OS Information = İS bilgisi +OS Information = İşletim sistemi bilgisi PPSSPP build = PPSSPP derlemesi Refresh rate = Yenileme hızı Release = Release -RW/RX exclusive = RW/RX 'e özel +RW/RX exclusive = RW/RX'e özel Sample rate = Örnekleme hızı Shading Language = Gölgelendirme dili Storage = Depolama @@ -1079,8 +1078,8 @@ System Information = Sistem bilgisi System Name = Ad System Version = Sistem sürümü Threads = İzlekler -Vendor = Satıcı -Vendor (detected) = Satıcı (tespit edildi) +Vendor = Üretici +Vendor (detected) = Üretici (tespit edildi) Version Information = Sürüm bilgisi Vulkan Extensions = Vulkan eklentileri Vulkan Features = Vulkan özellikleri @@ -1091,15 +1090,15 @@ Vulkan Features = Vulkan özellikleri 24HR = 24 saat Auto = Otomatik Auto Load Savestate = Otomatik durum kaydı yükle -AVI Dump started. = AVI kaydı başladı -AVI Dump stopped. = AVI kaydı bitti +AVI Dump started. = AVI kaydı başladı. +AVI Dump stopped. = AVI kaydı bitti. Cache ISO in RAM = Bütün ISO'yu RAM'e önbellekle Change CPU Clock = Taklit edilen PSP'nin CPU sayacını değiştir (kararsız) -Color Saturation = Color Saturation -Color Tint = Color Tint +Color Saturation = Renk Doygunluğu +Color Tint = Renk Tonu Error: load undo state is from a different game = Hata: yükleme geri alma durumu farklı bir oyundan Failed to load state for load undo. Error in the file system. = Yüklemeyi geri alma durumu yüklenemedi. Dosya sisteminde hata. -Floating symbols = kayan simgeler +Floating symbols = Kayan simgeler Memory Stick folder = Hafıza Kartı klasörü Memory Stick size = Hafıza Kartı boyutu Change Nickname = Kullanıcı adını değiştir @@ -1116,12 +1115,12 @@ DDMMYYYY = GGAAYYYY Decrease size = Boyutu küçült Developer Tools = Geliştirici araçları Display Extra Info = Fazladan bilgileri göster -Display Games on a grid = "Oyunlar"ı bir ızgarada göster -Display Homebrew on a grid = "Bağımsız Yapımlar && Demolar"ı bir ızgarada göster -Display Recent on a grid = "Geçmiş"i bir ızgarada göster +Display Games on a grid = Oyunları ızgarada göster +Display Homebrew on a grid = Demolar && Bağımsız Yapımları ızgarada göster +Display Recent on a grid = Geçmişi ızgarada göster Dynarec (JIT) = Dynarec (JIT) Emulation = Emülasyon -Enable Cheats = Hileleri aç +Enable Cheats = Hileleri etkinleştir Enable Compatibility Server Reports = Uyumluluk sunucusu raporlarını etkinleştir Failed to load state. Error in the file system. = Durum yüklenemedi. Dosya sistemi hatası. Failed to save state. Error in the file system. = Durum kaydedilemedi. Dosya sistemi hatası. @@ -1137,7 +1136,7 @@ Host (bugs, less lag) = Host (buglu, daha az kasma) Ignore bad memory accesses = Kötü bellek erişimlerini yoksay Increase size = Boyutu arttır Interpreter = Tercüman -IO timing method = G / Ç zamanlama yöntemi +IO timing method = G/Ç zamanlama yöntemi IR Interpreter = IR tercümanı Memory Stick Folder = Hafıza Kartı klasörü Memory Stick inserted = Hafıza kartı takıldı @@ -1160,15 +1159,15 @@ Record Audio = Sesi kaydet Record Display = Görüntüyü kaydet Reset Recording on Save/Load State = Kaydet/Yükle durumunda kaydı sıfırla Restore Default Settings = Varsayılan ayarları yükle -Rewind Snapshot Frequency = Geri sarma görüntüsü sıklılığı (mem hog) +Rewind Snapshot Frequency = Geri sarma görüntüsü sıklığı (mem hog) Save path in installed.txt = Yolu installed.txt'ye kaydet Save path in My Documents = Dosyaları "Belgeler"'e kaydet Savestate Slot = Durum kaydı yeri Savestate slot backups = Durum kaydı slot yedekleri -Screenshots as PNG = Ekran görüntülerini PNG formatında kaydet +Screenshots as PNG = Ekran görüntülerini PNG olarak kaydet Set UI background... = Arayüz arkaplanı ayarla... Show ID = ID'yi göster -Show Memory Stick folder = Show Memory Stick folder +Show Memory Stick folder = Hafıza Kartı klasörünü göster Show region flag = Bölge bayrağını göster Simulate UMD delays = UMD gecikmelerini simule et Slot 1 = Slot 1 @@ -1178,44 +1177,44 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Depolama dolu Sustained performance mode = Sürekli performans modu -Theme = Theme +Theme = Tema Time Format = Zaman biçimi UI = Kullanıcı arayüzü UI background animation = UI arka plan animasyonu UI Sound = UI sesi undo %c = %c 'yi yedekle USB = USB -Use Lossless Video Codec (FFV1) = Kayıpsız video kodek'i kullan (FFV1) +Use Lossless Video Codec (FFV1) = Kayıpsız video codec'i kullan (FFV1) Use O to confirm = O (Japonya) Use output buffer (with overlay) for recording = Kayıt için çıktı arabelleğini kullanın (bindirmeli) Use system native keyboard = Sistem yerel klavyesini kullan Use X to confirm = X (Küresel) VersionCheck = Güncellemeleri denetle -WARNING: Android battery save mode is on = UYARI: Android güç tasaruufu açık -WARNING: Battery save mode is on = UYARI: Güç tasarrufu açık +WARNING: Android battery save mode is on = UYARI: Android pil tasarrufu açık +WARNING: Battery save mode is on = UYARI: Pil tasarrufu açık Waves = Dalgalar YYYYMMDD = YYYYAAGG [TextureShaders] Off = Off TexMMPX = TexMMPX -Tex2xBRZ = Tex2xBRZ +Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ [Themes] -Default = Default +Default = Varsayılan [UI Elements] -%1 button = %1 button -%1 checkbox = %1 checkbox -%1 choice = %1 choice -%1 heading = %1 heading -%1 radio button = %1 radio button -%1 text field = %1 text field -Choices: = Choices: -List: = List: +%1 button = %1 düğmesi +%1 checkbox = %1 onay kutusu +%1 choice = %1 seçeneği +%1 heading = %1 başlığı +%1 radio button = %1 radyo düğmesi +%1 text field = %1 metin alanı +Choices: = Seçenekler: +List: = Liste: Progress: %1% = Progress: %1% -Screen representation = Screen representation +Screen representation = Ekran gösterimi [Upgrade] Details = Detaylar Dismiss = Reddet From f4d5c59b2e40c8fb4733e49e819083bbb47a91ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Von=C3=A1sek?= Date: Sat, 22 Oct 2022 16:16:23 +0200 Subject: [PATCH 076/715] OpenXR - Refactor compatvr.ini file (#16270) * OpenXR - Compat GTA games * OpenXR - Compat 0-9 games * OpenXR - Compat A games * OpenXR - Compat B games part 1 * OpenXR - Compat B games part 2 * OpenXR - Compat C games part 1 * OpenXR - Compat C games part 2 * OpenXR - Compat D games * OpenXR - Compat E games * OpenXR - Compat F games * OpenXR - Compat G games * OpenXR - Compat H games * OpenXR - Compat I games * OpenXR - Compat J games * OpenXR - Compat K games * OpenXR - Compat L games * OpenXR - Compat M games * OpenXR - Compat N games * OpenXR - Compat P games * OpenXR - Compat R games * OpenXR - Compat S games * OpenXR - Compat T games * OpenXR - Compat U games * OpenXR - Compat V games * OpenXR - Compat W games * OpenXR - Compat games sorting out part 1 * OpenXR - Compat games sorting out part 2 * OpenXR - Compat games sorting out part 3 * OpenXR - Compat games sorting out part 4 * OpenXR - Compat games sorting out part 5 * OpenXR - Compat games sorting out part 6 * OpenXR - Compat list description * OpenXR - Support getting compatvr.ini from filesystem --- Core/Compatibility.cpp | 21 +- Core/Compatibility.h | 1 + assets/compatvr.ini | 1722 +++++++++++++++++++++++++++------------- 3 files changed, 1194 insertions(+), 550 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 861e926429..f59a0da45b 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -42,21 +42,29 @@ void Compatibility::Load(const std::string &gameID) { } } + { + IniFile compat2; + // This one is user-editable. Need to load it after the system one. + Path path = GetSysDirectory(DIRECTORY_SYSTEM) / "compat.ini"; + if (compat2.Load(path.ToString())) { + CheckSettings(compat2, gameID); + } + } + { IniFile compat; // This loads from assets. if (compat.LoadFromVFS("compatvr.ini")) { - CheckSetting(compat, gameID, "Skyplane", &vrCompat_.Skyplane); - CheckSetting(compat, gameID, "UnitsPerMeter", &vrCompat_.UnitsPerMeter); + CheckVRSettings(compat, gameID); } } { IniFile compat2; // This one is user-editable. Need to load it after the system one. - Path path = GetSysDirectory(DIRECTORY_SYSTEM) / "compat.ini"; + Path path = GetSysDirectory(DIRECTORY_SYSTEM) / "compatvr.ini"; if (compat2.Load(path.ToString())) { - CheckSettings(compat2, gameID); + CheckVRSettings(compat2, gameID); } } } @@ -111,6 +119,11 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "NearestFilteringOnFramebufferCreate", &flags_.NearestFilteringOnFramebufferCreate); } +void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { + CheckSetting(iniFile, gameID, "Skyplane", &vrCompat_.Skyplane); + CheckSetting(iniFile, gameID, "UnitsPerMeter", &vrCompat_.UnitsPerMeter); +} + void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { if (ignored_.find(option) == ignored_.end()) { iniFile.Get(option, gameID.c_str(), flag, *flag); diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 8bbdc52ebd..5946f1633b 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -114,6 +114,7 @@ public: private: void Clear(); void CheckSettings(IniFile &iniFile, const std::string &gameID); + void CheckVRSettings(IniFile &iniFile, const std::string &gameID); void CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag); void CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, float *value); diff --git a/assets/compatvr.ini b/assets/compatvr.ini index c3ec3f926a..92cf0d32d1 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -31,314 +31,508 @@ [Skyplane] +# Workaround to remove the background skyplane and add clearing framebuffer with a fog color. + # Grand Theft Auto: Liberty City Stories -ULUS10041 = true +NPJH50825 = true +ULES00051 = true ULES00151 = true +ULES00181 = true +ULES00182 = true ULJM05255 = true ULJM05359 = true ULJM05885 = true -NPJH50825 = true +ULUS10041 = true # Grand Theft Auto: Vice City Stories +NPJH50827 = true ULES00502 = true -ULUS10160 = true +ULES00503 = true ULJM05297 = true ULJM05395 = true ULJM05884 = true -NPJH50827 = true +ULUS10160 = true [UnitsPerMeter] -# Values exported from https://github.com/CarlKenner/ppsspp/tree/VR/Sys/GameSettings +# Scale of game world to convert the world units into meters. This enables following VR features: +# + 3D stereoscopy (that can work only with accurate values) +# * 6DoF motion tracking (that can work with inaccurate values) + +# cube.elf ELF000000 = 10.0 -JRPG00001 = 80 -JRPG00002 = 80 -NPEG00001 = 1.0 -NPEG00003 = 1000.0 -NPEG00023 = 1.0 -NPEG90003 = 1.0 -NPEH00003 = 30.0 -NPEH00017 = 1.0 -NPEH00031 = 1.0 -NPEH00134 = 8.0 -NPEH00135 = 1.0 -NPEH00138 = 80 -NPEH90011 = 100.0 -NPEH90014 = 1.0 -NPEH90023 = 1000.0 -NPEH90028 = 128.0 -NPEX00005 = 1.0 -NPEZ00007 = 1.0 -NPEZ00008 = 20.0 -NPEZ00011 = 1.0 -NPEZ00023 = 1.0 -NPEZ00041 = 1.0 -NPEZ00044 = 1.0 -NPEZ00045 = 1.0 -NPEZ00081 = 1.0 -NPEZ00101 = 1.0 -NPEZ00104 = 1.0 -NPEZ00107 = 1.0 -NPEZ00108 = 1.0 -NPEZ00118 = 70.0 -NPEZ00127 = 1.0 -NPEZ00140 = 1.0 -NPHG00002 = 1.0 -NPHG00025 = 80.0 -NPHH00351 = 8.0 -NPJB40001 = 100.0 -NPJG00004 = 1000.0 -NPJG00045 = 80.0 -NPJG00103 = 1.0 -NPJG00122 = 100.0 -NPJH00002 = 30.0 -NPJH50040 = 1.0 -NPJH50045 = 1000.0 -NPJH50065 = 1.0 -NPJH50145 = 9.0 -NPJH50148 = 1.0 -NPJH50180 = 1.0 -NPJH50184 = 1000.0 -NPJH50352 = 100 -NPJH50401 = 1.0 -NPJH50414 = 1.0 -NPJH50443 = 100.0 -NPJH50444 = 100.0 -NPJH50448 = 80 -NPJH50457 = 1.0 -NPJH50475 = 4.0 -NPJH50515 = 8.0 -NPJH50625 = 1.8 -NPJH50626 = 8.0 -NPJH50701 = 1.0 -NPJH90066 = 1.0 -NPUG70008 = 1.0 -NPUG80086 = 1000.0 -NPUG80325 = 1.0 -NPUH10006 = 30.0 -NPUH10023 = 1.0 -NPUH10024 = 1.0 -NPUH10026 = 1.0 -NPUH10034 = 1.0 -NPUH10125 = 8.0 -NPUH10126 = 80 -NPUH90019 = 1.0 -NPUH90029 = 1.0 -NPUH90048 = 1.0 -NPUH90067 = 128.0 -NPUX80433 = 1.0 -NPUZ00002 = 1.0 -NPUZ00007 = 1.0 -NPUZ00010 = 1.0 -NPUZ00020 = 1.0 -NPUZ00021 = 1.0 -NPUZ00024 = 1.0 -NPUZ00027 = 20.0 -NPUZ00028 = 1.0 -NPUZ00031 = 1.0 -NPUZ00033 = 70.0 -NPUZ00034 = 1.0 -NPUZ00040 = 1.0 -NPUZ00056 = 1.0 -NPUZ00080 = 1.0 -UCAS40011 = 1.0 -UCAS40012 = 1.0 -UCAS40018 = 9.0 -UCAS40020 = 100.0 -UCAS40021 = 10.0 -UCAS40023 = 9.0 -UCAS40024 = 0.98 -UCAS40025 = 83 -UCAS40026 = 0.1 -UCAS40049 = 1.0 -UCAS40063 = 1.0 -UCAS40076 = 5.0 -UCAS40089 = 9.0 -UCAS40092 = 100.0 -UCAS40095 = 1000.0 -UCAS40098 = 0.96 -UCAS40099 = 1000.0 -UCAS40102 = 1.0 -UCAS40113 = 1000.0 -UCAS40116 = 9.0 -UCAS40119 = 1000.0 + +# 300: March to Glory +ULES00766 = 0.95 +ULUS10241 = 0.95 + +# 50 Cent: Bulletproof G Unit Edition +ULES00451 = 1.0 +ULES00452 = 1.0 +ULUS10128 = 1.0 + +# 7 Wonders of the Ancient World +ULES01037 = 1.0 +ULUS10227 = 1.0 + +# Ace Combat X: Skies of Deception UCAS40120 = 1.0 -UCAS40129 = 7.0 -UCAS40130 = 0.98 -UCAS40145 = 1.0 -UCAS40146 = 6.8 -UCAS40148 = 1.0 -UCAS40149 = 0.96 -UCAS40156 = 9.0 -UCAS40164 = 1000.0 -UCAS40165 = 1000.0 -UCAS40167 = 100.0 UCAS40169 = 1.0 -UCAS40177 = 0.96 -UCAS40179 = 1.0 -UCAS40180 = 9.5 -UCAS40191 = 1.0 -UCAS40193 = 80.0 -UCAS40198 = 1.0 -UCAS40204 = 100.0 -UCAS40212 = 1.0 -UCAS40258 = 0.96 -UCAS40265 = 1.0 -UCAS40318 = 100.0 -UCED00432 = 1.0 -UCED00448 = 1000.0 -UCED00970 = 1.0 -UCED00971 = 1.0 -UCED90007 = 1.0 -UCES00001 = 1.0 -UCES00004 = 0.1 -UCES00010 = 100.0 -UCES00044 = 2.0 -UCES00109 = 5.0 -UCES00178 = 9.0 -UCES00249 = 1.0 -UCES00302 = 100.0 -UCES00304 = 1.0 -UCES00356 = 1000.0 -UCES00420 = 1.0 -UCES00422 = 1000.0 UCES00423 = 1.0 -UCES00465 = 1.0 -UCES00842 = 1.0 -UCES00995 = 80.0 -UCES01245 = 1.0 -UCES01312 = 80.0 -UCES01401 = 1.0 -UCES01421 = 100.0 -UCES01473 = 1.0 -UCET00179 = 5.0 -UCET00247 = 9.0 -UCET00357 = 1.0 -UCET00424 = 1000.0 -UCET00713 = 1.0 -UCJB98011 = 1.0 -UCJM95402 = 9.0 -UCJS10007 = 1.0 -UCJS10008 = 1.0 -UCJS10010 = 9.0 -UCJS10011 = 10.0 -UCJS10017 = 0.98 -UCJS10018 = 83 -UCJS10019 = 0.1 -UCJS10028 = 5.0 -UCJS10041 = 1.0 -UCJS10042 = 0.96 -UCJS10047 = 9.0 -UCJS10048 = 7.0 -UCJS10052 = 1.0 -UCJS10057 = 0.96 -UCJS10061 = 9.5 -UCJS10077 = 80.0 -UCJS10082 = 0.96 -UCJS10085 = 1.0 -UCJS10092 = 1.0 -UCJS10093 = 0.96 -UCJS10100 = 1.0 -UCJS10106 = 1.0 -UCJS10114 = 1.0 -UCJS18005 = 1.0 -UCJS18010 = 0.98 -UCJS18014 = 7.0 -UCJS18015 = 0.96 -UCJX90019 = 7.0 -UCKS45007 = 10.0 -UCKS45008 = 1.0 -UCKS45011 = 9.0 -UCKS45018 = 1.0 -UCKS45020 = 1.0 -UCKS45022 = 1.0 -UCKS45027 = 1000.0 -UCKS45032 = 1000.0 -UCKS45034 = 9.0 UCKS45038 = 1.0 -UCKS45050 = 10.0 -UCKS45052 = 100.0 -UCKS45056 = 6.8 UCKS45067 = 1.0 -UCKS45071 = 9.5 -UCKS45076 = 80.0 -UCKS45120 = 1.0 -UCUS98612 = 1.0 -UCUS98618 = 2.0 -UCUS98623 = 9.0 -UCUS98632 = 1.0 -UCUS98633 = 1.0 -UCUS98647 = 5.0 -UCUS98648 = 1.0 -UCUS98653 = 1.0 -UCUS98654 = 2.0 -UCUS98662 = 1.0 -UCUS98671 = 5.0 -UCUS98681 = 1.0 -UCUS98700 = 7.0 -UCUS98706 = 7.0 -UCUS98711 = 80.0 -UCUS98712 = 1.0 -UCUS98713 = 1.0 -UCUS98717 = 80.0 -UCUS98732 = 80.0 -UCUS98737 = 1.0 -UCUS98740 = 80.0 -UCUS98751 = 100.0 -ULAS40129 = 7.0 -ULAS40155 = 1.0 -ULAS42007 = 1000.0 -ULAS42019 = 1.0 -ULAS42035 = 930.0 -ULAS42037 = 1.0 -ULAS42052 = 10.0 -ULAS42069 = 7.8 -ULAS42072 = 1.0 -ULAS42073 = 7.8 -ULAS42087 = 970.0 -ULAS42093 = 100.0 -ULAS42097 = 10.0 -ULAS42099 = 1.0 -ULAS42110 = 100.0 -ULAS42115 = 1.0 -ULAS42117 = 1.0 -ULAS42119 = 1.0 -ULES00008 = 1000.0 +ULJS00086 = 1.0 +ULJS19018 = 1.0 +ULUS10176 = 1.0 + +# Activision Hits Remixed +ULES00640 = 1.0 +ULUS10186 = 1.0 + +# Age of Zombies +NPEZ00044 = 1.0 +NPUZ00024 = 1.0 + +# Alien Syndrome +ULES00772 = 1.0 +ULUS10245 = 1.0 + +# Ape Escape Academy +NPJG00048 = 100.0 +UCAS40007 = 100.0 +UCES00010 = 100.0 +UCJS10003 = 100.0 +UCJS18007 = 100.0 +UCJS18043 = 100.0 +UCUS98619 = 100.0 + +# Ape Escape Academy 2 +NPJG00049 = 100.0 +UCAS40041 = 100.0 +UCAS40052 = 100.0 +UCAS40123 = 100.0 +UCES00302 = 100.0 +UCJS10020 = 100.0 +UCJS18009 = 100.0 +UCKS45024 = 100.0 + +# Archer Maclean's Mercury +UCAS40021 = 10.0 +UCJS10011 = 10.0 +UCKS45007 = 10.0 ULES00011 = 10.0 -ULES00026 = 0.1 -ULES00033 = 0.005 -ULES00034 = 0.005 -ULES00035 = 0.005 -ULES00051 = 1.0 -ULES00118 = 0.1 -ULES00119 = 0.1 +ULUS10017 = 10.0 + +# Are You Alice? +AAPP11042 = 1.0 +ULJM05848 = 1.0 + +# Army of Two: The 40th Day +NPEH90028 = 128.0 +NPUH90067 = 128.0 +ULAS42215 = 128.0 +ULES01381 = 128.0 +ULJM05643 = 128.0 +ULJM05849 = 128.0 +ULUS10472 = 128.0 + +# Armored Core 3 Portable +NPEH00045 = 1.0 +NPUH10023 = 1.0 +UCAS40268 = 1.0 +ULJM05492 = 1.0 +ULKS46210 = 1.0 + +# Armored Core: Formula Front - Extreme Battle +NPJH50041 = 1.0 +UCAS40004 = 1.0 +UCAS40036 = 1.0 +ULES00219 = 1.0 +ULJS00003 = 1.0 +ULJS19001 = 1.0 +ULKS46003 = 1.0 +ULUS10034 = 1.0 + +# Armored Core: Last Raven Portable +NPEH00046 = 1.0 +NPUH10024 = 1.0 +ULJM05611 = 1.0 +UCAS40302 = 1.0 +UCKS45148 = 1.0 + +# Assassin's Creed: Bloodlines +NPEH00029 = 1.0 +NPUH10032 = 1.0 +ULES01367 = 1.0 +ULKS46231 = 1.0 +ULJM05571 = 1.0 +ULJM05720 = 1.0 +ULUS10455 = 1.0 + +# Astonishia Story +ULES00363 = 1.0 +ULJM05176 = 1.0 +ULKS46021 = 1.0 +ULUS10083 = 1.0 + +# Atari Classics Evolved +ULUS10325 = 1.0 + +# ATV Offroad Fury Pro +UCES00786 = 1.0 +UCUS98648 = 1.0 +UCUS98681 = 1.0 + +# Audition Portable +ULKS46122 = 32.0 + +# B-Boy +UCED00432 = 1.0 +UCES00249 = 1.0 +ULUS10363 = 1.0 + +# Battle Poker +NPUZ00020 = 1.0 + +# BattleZone +ULES00522 = 1.0 +ULET00456 = 1.0 +ULUS10156 = 1.0 + +# Beam 'em up +NPEZ00081 = 1.0 + +# Beaterator +ULES01023 = 1.0 +ULUS10405 = 1.0 + +# Beats +NPEG00001 = 1.0 +NPHG00002 = 1.0 +NPJG00001 = 1.0 +NPUG80060 = 1.0 + +# Big head snooker +NPEZ00104 = 1.0 + +# Black Rock Shooter: The Game +JRPG00001 = 80.0 +JRPG00002 = 80.0 +NPEH00138 = 80.0 +NPJH50448 = 80.0 +NPUH10126 = 80.0 +ULJM05859 = 80.0 + +# Blast Off +NPEZ00041 = 1.0 +NPUZ00021 = 1.0 + +# BlazBlue: Calamity Trigger Portable +NPJH50180 = 1.0 +UCAS40299 = 1.0 +ULJM05613 = 1.0 +ULJM05970 = 1.0 +ULUS10519 = 1.0 + +# BlazBlue: Continuum Shift II +NPJH50401 = 1.0 +UCKS45170 = 1.0 +ULES01526 = 1.0 +ULJM05850 = 1.0 +ULUS10579 = 1.0 + +# Bleach: Heat the Soul 1 +UCAS40011 = 1.0 +UCJS18005 = 1.0 +UCJS10008 = 1.0 + +# Bleach: Heat the Soul 2 +UCAS40024 = 0.98 +UCAS40130 = 0.98 +UCJS18010 = 0.98 +UCJS10017 = 0.98 + +# Bleach: Heat the Soul 3 +UCAS40098 = 0.96 +UCAS40177 = 0.96 +UCJS10042 = 0.96 +UCJS18015 = 0.96 + +# Bleach: Heat the Soul 4 +UCAS40149 = 0.96 +UCAS40216 = 0.96 +UCJS10057 = 0.96 +UCJS18025 = 0.96 + +# Bleach: Heat the Soul 5 +UCAS40210 = 0.96 +UCJS10082 = 0.96 +UCJS18033 = 0.96 + +# Bleach: Heat the Soul 6 +NPJG00021 = 0.96 +UCAS40258 = 0.96 +UCAS40308 = 0.96 +UCJS10093 = 0.96 +UCJS18039 = 0.96 + +# Bleach: Heat the Soul 7 +NPJG00114 = 0.96 +UCAS40314 = 0.96 +UCJS10110 = 0.96 +UCJS18057 = 0.96 +UCKS45158 = 0.96 + +# Bleach: Soul Carnival 1 +NPJG00008 = 1.0 +UCAS40227 = 1.0 +UCAS40234 = 1.0 +UCAS40296 = 1.0 +UCJS10085 = 1.0 +UCJS18038 = 1.0 +UCKS45102 = 1.0 +ULJS10085 = 1.0 + +# Bleach: Soul Carnival 2 +NPJG00070 = 1.0 +UCJS10106 = 1.0 +UCAS40291 = 1.0 +UCAS40297 = 1.0 + +# Bloons +NPEZ00045 = 1.0 +NPUZ00010 = 1.0 + +# Bomberman Land Portable +NPJH50142 = 10.0 +ULAS42097 = 10.0 +ULES00959 = 10.0 +ULJM05181 = 10.0 +ULJM05319 = 10.0 +ULUS10319 = 10.0 + +# Bowling 3D +NPUZ00002 = 1.0 + +# Burnout Legends +NPJH50305 = 1.0 +ULAS42019 = 1.0 ULES00125 = 1.0 -ULES00126 = 10.0 -ULES00135 = 83 -ULES00144 = 1.0 -ULES00151 = 1.0 -ULES00153 = 83 +ULJM05049 = 1.0 +ULJM05228 = 1.0 +ULKS46027 = 1.0 +ULUS10025 = 1.0 + +# Brain Challenge +NPEH00003 = 30.0 +NPJH00002 = 30.0 +NPUH10006 = 30.0 + +# BreakQuest +NPEZ00011 = 1.0 +NPUZ00031 = 1.0 + +# Bubble Trubble +NPEZ00023 = 1.0 +NPUZ00007 = 1.0 + +# Bust-A-Move Deluxe +NPJH50087 = 1.0 +ULES00233 = 1.0 +ULUS10057 = 1.0 +ULJM05116 = 1.0 + +# Cabela's African Safari +ULUS10175 = 1.0 + +# Call of Duty: Roads to Victory +ULES00643 = 1.05 +ULES00644 = 1.05 +ULUS10218 = 1.05 + +# Capcom Classics Collection Reloaded +ULAS42072 = 1.0 +ULES00377 = 1.0 +ULJM05104 = 1.0 +ULJM05280 = 1.0 +ULUS10134 = 1.0 + +# Castlevania: The Dracula X Chronicles +NPJH50028 = 100.0 +ULES00841 = 100.0 +ULJM05287 = 100.0 +ULKS46155 = 100.0 +ULUS10277 = 100.0 + +# Championship Manager +ULES00174 = 1.0 + +# Charge! Tank Squad +NPEX00005 = 1.0 +NPJG00103 = 1.0 +NPUX80433 = 1.0 + +# Chessmaster: The Art of Learning +ULES01013 = 1.0 +ULUS10335 = 1.0 + +# Circles, Circles, Circles +NPEZ00007 = 1.0 +NPUZ00028 = 1.0 + +# Coded Arms: Contagion +ULAS42099 = 1.0 +ULES00718 = 1.0 +ULJM05243 = 1.0 +ULKS46139 = 1.0 +ULUS10184 = 1.0 + +# Coded Soul: Uketsugareshi Idea +NPJG00043 = 9.5 +UCAS40180 = 9.5 +UCJS10061 = 9.5 +UCKS45071 = 9.5 + +# Crash Tag Team Racing ULES00168 = 1.0 ULES00169 = 1.0 ULES00170 = 1.0 ULES00171 = 1.0 ULES00172 = 1.0 -ULES00174 = 1.0 -ULES00181 = 1.0 -ULES00182 = 1.0 -ULES00183 = 1.0 -ULES00210 = 1.0 -ULES00214 = 1.0 -ULES00215 = 1.0 -ULES00216 = 1.0 -ULES00219 = 1.0 -ULES00223 = 1.0 -ULES00227 = 10.0 -ULES00233 = 1.0 -ULES00235 = 1.0 -ULES00277 = 100.0 -ULES00283 = 256.0 -ULES00284 = 930.0 -ULES00307 = 10.0 +ULJM05036 = 1.0 +ULUS10044 = 1.0 + +# Crazy Taxi: Fare Wars +NPJH50490 = 10.0 +ULES00811 = 10.0 +ULJM05340 = 10.0 +ULUS10273 = 10.0 + +# Creature Defense +NPEH00027 = 1.0 +NPJH00006 = 1.0 +NPUH10034 = 1.0 + +# Crimson Gem Saga +UCAS40212 = 1.0 +ULJM05369 = 1.0 +ULKS46142 = 1.0 +ULUS10400 = 1.0 + +# Crimson Room Reverse +NPJH50046 = 32.0 +NPUH10037 = 32.0 +ULJM05408 = 32.0 + +# Crisis Core: Final Fantasy VII +UCAS40167 = 100.0 +UCAS40204 = 100.0 +UCAS40272 = 100.0 +UCKS45052 = 100.0 +ULES01044 = 100.0 +ULES01045 = 100.0 +ULES01046 = 100.0 +ULES01047 = 100.0 +ULJM05254 = 100.0 +ULJM05275 = 100.0 +ULJM05517 = 100.0 +ULUS10336 = 100.0 + +# Crush +ULES00765 = 1.0 +ULUS10238 = 1.0 + +# Crystal Defenders +NPEH00017 = 1.0 +NPJH00005 = 1.0 +NPJH90066 = 1.0 +NPUH10026 = 1.0 +NPUH90048 = 1.0 + +# Cube +ULES00722 = 10.0 +ULJS00108 = 10.0 +ULUS10223 = 10.0 + +# Cubixx +NPEZ00101 = 1.0 +NPUZ00080 = 1.0 + +# D-Cube Planet +NPEZ00008 = 20.0 +NPUZ00027 = 20.0 + +# Dangan-Ronpa +NPJH50515 = 8.0 +ULJS00337 = 8.0 +ULJS00438 = 8.0 +ULJS19060 = 8.0 + +# Daxter +NPEG00025 = 2.0 +UCES00044 = 2.0 +UCKS45025 = 2.0 +UCUS98618 = 2.0 +UCUS98654 = 2.0 + +# Dead or Alive Paradise +NPEH00038 = 0.8 +NPJH50239 = 0.8 +ULES01416 = 0.8 +ULES01431 = 0.8 +ULJM05640 = 0.8 +ULJM08046 = 0.8 +ULKS46246 = 0.8 +ULUS10521 = 0.8 + +# Death Jr. +ULES00144 = 1.0 +ULUS10027 = 1.0 + +# Deflector +NPEZ00127 = 1.0 +NPUZ00040 = 1.0 + +# Diamond and the Sound of a Gunshot +UCJS10092 = 1.0 +UCKS45120 = 1.0 + +# Dissidia 012: Duodecim Final Fantasy +NPJH50377 = 1.0 +UCAS40333 = 1.0 +UCAS40329 = 1.0 +UCAS40335 = 1.0 +UCKS45166 = 1.0 +ULES01505 = 1.0 +ULJM05814 = 1.0 +ULJM06121 = 1.0 +ULUS10566 = 1.0 + +# Dissidia: Final Fantasy +NPEH90014 = 1.0 +NPJH50065 = 1.0 +NPJH50330 = 1.0 +NPUH90029 = 1.0 +UCAS40322 = 1.0 +ULES01270 = 1.0 +ULJM05262 = 1.0 +ULJM05405 = 1.0 +ULJM05550 = 1.0 +ULJM05760 = 1.0 +ULJM05761 = 1.0 +ULUS10437 = 1.0 + +# Disney G-Force +ULES01238 = 1.0 +ULES01239 = 1.0 +ULES01240 = 1.0 +ULUS10439 = 1.0 + +# Disney Hannah Montana: Rock Out the Show +ULES01303 = 1.0 +ULUS10431 = 1.0 + +# Disney/Pixar Cars +UCKS45018 = 1.0 ULES00319 = 1.0 ULES00320 = 1.0 ULES00321 = 1.0 @@ -348,30 +542,11 @@ ULES00324 = 1.0 ULES00325 = 1.0 ULES00326 = 1.0 ULES00327 = 1.0 -ULES00339 = 1.0 -ULES00363 = 1.0 -ULES00377 = 1.0 -ULES00382 = 1.0 -ULES00383 = 50.0 -ULES00419 = 7.8 -ULES00452 = 1.0 -ULES00474 = 0.1 -ULES00475 = 0.1 -ULES00479 = 47.0 -ULES00484 = 1.0 -ULES00502 = 1.0 -ULES00503 = 1.0 -ULES00522 = 1.0 -ULES00567 = 1.0 -ULES00601 = 1.0 -ULES00623 = 0.01 -ULES00640 = 1.0 -ULES00643 = 1.05 -ULES00644 = 1.05 -ULES00645 = 970.0 -ULES00704 = 1.0 -ULES00718 = 1.0 -ULES00722 = 10.0 +ULJM05149 = 1.0 +ULUS10073 = 1.0 + +# Disney/Pixar Ratatouille +UCKS45050 = 10.0 ULES00734 = 10.0 ULES00735 = 10.0 ULES00736 = 10.0 @@ -386,254 +561,709 @@ ULES00746 = 10.0 ULES00747 = 10.0 ULES00748 = 10.0 ULES00749 = 10.0 -ULES00757 = 1.0 -ULES00765 = 1.0 -ULES00766 = 0.95 -ULES00772 = 1.0 -ULES00811 = 10.0 +ULUS10247 = 10.0 + +# DJ Max Fever +NPEH00030 = 1.0 +ULUS10403 = 1.0 + +# DJ Max Portable 2 +ULKS46116 = 1.0 + +# DJ Max Portable 3 +NPJH50471 = 1.0 +ULKS46236 = 1.0 +ULJM05836 = 1.0 +ULJM06033 = 1.0 +ULUS10538 = 1.0 + +# DJ Max Portable: Black Square +NPJH50559 = 1.0 +ULJM06034 = 1.0 +ULKS46189 = 1.0 + +# DJ Max Portable: Clazziquai Edition +ULKS46190 = 1.0 +ULKS46191 = 1.0 + +# DJ Max Portable Hot Tunes +ULKS46240 = 1.0 + +# DreamWorks Shrek the Third +ULES00812 = 0.5 ULES00813 = 0.5 -ULES00841 = 100.0 +ULKS46141 = 0.5 +ULUS10248 = 0.5 + +# Dynasty Warriors +NPJH50030 = 0.1 +ULES00026 = 0.1 +ULES00118 = 0.1 +ULES00119 = 0.1 +ULJM05003 = 0.1 +ULJM08008 = 0.1 +ULJM08017 = 0.1 +ULKS46012 = 0.1 +ULUS10004 = 0.1 + +# Eragon +ULES00474 = 0.1 +ULES00475 = 0.1 +ULUS10146 = 0.1 + +# Evangelion Shin Gekijoban: 3nd Impact +ULAS42293 = 1.0 +ULJS00408 = 1.0 +NPJH50457 = 1.0 + +# F1 Grand Prix +UCAS40026 = 0.1 +UCES00004 = 0.1 +UCJS10019 = 0.1 + +# Family Guy +ULES00567 = 1.0 +ULES00601 = 1.0 +ULUS10185 = 1.0 + +# Fat Princess: Fistful of Cake +NPHG00025 = 80.0 +NPJG00045 = 80.0 +UCAS40285 = 80.0 +UCES01312 = 80.0 +UCKS45137 = 80.0 +UCUS98740 = 80.0 + +# Final Fantasy I +NPJH50406 = 6.8 +UCAS40146 = 6.8 +UCKS45056 = 6.8 +ULES00986 = 6.8 +ULJM05241 = 6.8 +ULJM05514 = 6.8 +ULUS10251 = 6.8 + +# Final Fantasy II +NPJH50407 = 1.0 +UCAS40152 = 1.0 +ULJM05245 = 1.0 +ULJM05515 = 1.0 +ULES00987 = 1.0 +ULUS10263 = 1.0 + +# Final Fantasy III +NPEH00134 = 8.0 +NPHH00351 = 8.0 +NPJH50626 = 8.0 +NPUH10125 = 8.0 +ULJM06133 = 8.0 + +# Final Fantasy IV +NPJH50414 = 1.0 +UCAS40334 = 1.0 +UCAS40342 = 1.0 +ULES01521 = 1.0 +ULJM05855 = 1.0 +ULJM06122 = 1.0 +ULUS10560 = 1.0 + +# Final Fantasy Tactics: The War of the Lions +NPJH50408 = 1.0 +UCAS40148 = 1.0 ULES00850 = 1.0 +ULJM05194 = 1.0 +ULJM05516 = 1.0 +ULUS10297 = 1.0 + +# Final Fantasy Type-0 +NPJH50443 = 100.0 +NPJH50444 = 100.0 +UCAS40346 = 100.0 +ULJM05900 = 100.0 +ULJM06217 = 100.0 + +# flOw +NPEG00003 = 1000.0 +NPJG00004 = 1000.0 +NPUG80086 = 1000.0 + +# Free Running +ULES00704 = 1.0 + +# Ghost in the Shell: Stand Alone Complex +UCAS40025 = 83.0 +UCJS10018 = 83.0 +ULES00135 = 83.0 +ULES00153 = 83.0 +ULUS10020 = 83.0 + +# Ghostbusters: The Video Game +UCES01276 = 3.28 +ULUS10485 = 3.28 +ULUS10486 = 3.28 + +# Gitaroo Man Lives! +NPJH50035 = 50.0 +ULES00383 = 50.0 +ULJM05130 = 50.0 +ULKS46071 = 50.0 +ULUS10207 = 50.0 + +# Gods Eater Burst +NPJH50352 = 100.0 +ULES01519 = 100.0 +ULJS00350 = 100.0 +ULJS00351 = 100.0 +ULJS19056 = 100.0 +ULJS19081 = 100.0 +ULKS46263 = 100.0 +ULUS10563 = 100.0 + +# God of War: Ghost of Sparta +NPEG00044 = 1.0 +NPHG00092 = 1.0 +NPJG00120 = 1.0 +UCAS40323 = 1.0 +UCES01401 = 1.0 +UCES01473 = 1.0 +UCJS10114 = 1.0 +UCKS45161 = 1.0 +UCUS98737 = 1.0 + +# God of War: Chains of Olympus +NPEG00023 = 1.0 +NPUG80325 = 1.0 +UCAS40191 = 1.0 +UCAS40198 = 1.0 +UCED00970 = 1.0 +UCED00971 = 1.0 +UCES00842 = 1.0 +ULJM05348 = 1.0 +UCKS45084 = 1.0 +UCUS98653 = 1.0 +UCUS98705 = 1.0 +UCUS98713 = 1.0 + +# Gran Turismo: The Real Driving Simulator +NPJG00027 = 1.0 +UCAS40265 = 1.0 +UCES01245 = 1.0 +UCJS10100 = 1.0 +UCUS98632 = 1.0 + +# Grand Theft Auto: Chinatown Wars +NPJH00138 = 1.0 +ULES01347 = 1.0 +ULJM05604 = 1.0 +ULUS10490 = 1.0 + +# Grand Theft Auto: Liberty City Stories +NPJH50825 = 1.0 +ULES00051 = 1.0 +ULES00151 = 1.0 +ULES00181 = 1.0 +ULES00182 = 1.0 +ULJM05255 = 1.0 +ULJM05359 = 1.0 +ULJM05885 = 1.0 +ULUS10041 = 1.0 + +# Grand Theft Auto: Vice City Stories +NPJH50827 = 1.0 +ULES00502 = 1.0 +ULES00503 = 1.0 +ULJM05297 = 1.0 +ULJM05395 = 1.0 +ULJM05884 = 1.0 +ULUS10160 = 1.0 + +# Gun Showdown +ULES00484 = 1.0 +ULUS10158 = 1.0 + +# Gungnir +NPEH00135 = 1.0 +NPJH50397 = 1.0 +ULJM05779 = 1.0 +ULUS10592 = 1.0 + +# Harry Potter and the Goblet of Fire +ULES00210 = 1.0 +ULES00214 = 1.0 +ULES00215 = 1.0 +ULES00216 = 1.0 +ULUS10032 = 1.0 + +# Hatsune Miku: Project Diva +NPJH50494 = 3.6 +UCKS45123 = 3.6 +ULAS42163 = 3.6 +ULJM05472 = 3.6 +ULJM05682 = 3.6 + +# Hatsune Miku: Project Diva 2nd +NPJH50475 = 4.0 +ULJM05681 = 4.0 +ULJM05952 = 4.0 + +# Indiana Jones and the Staff of Kings +ULES00939 = 1.0 +ULUS10316 = 1.0 + +# Iron Man 2 +ULES01422 = 1.000999 +ULUS10497 = 1.000999 + +# James Cameron's Avatar: The Game +NPEH00031 = 1.0 +ULES01357 = 1.0 +ULUS10451 = 1.0 + +# Jeanne d'Arc +NPJG00032 = 7.0 +UCAS40129 = 7.0 +UCJS10048 = 7.0 +UCJS18014 = 7.0 +UCJX90019 = 7.0 +UCKS45033 = 7.0 +UCUS98700 = 7.0 +UCUS98706 = 7.0 +ULAS40129 = 7.0 + +# Kingdom Hearts: Birth by Sleep +UCAS40295 = 1.0 +UCAS40317 = 1.0 +UCAS40326 = 1.0 +UCKS45143 = 1.0 +UCKS45168 = 1.0 +ULES01441 = 1.0 +ULJM05600 = 1.0 +ULJM05775 = 1.0 +ULJM06213 = 1.0 +ULJM06214 = 1.0 +ULUS10505 = 1.0 + +# Kingdom of Paradise 1 +UCAS40018 = 9.0 +UCAS40023 = 9.0 +UCAS40089 = 9.0 +UCES00178 = 9.0 +UCET00247 = 9.0 +UCJM95402 = 9.0 +UCJS10010 = 9.0 +UCKS45011 = 9.0 +UCUS98623 = 9.0 + +# Kingdom of Paradise 2 +UCAS40116 = 9.0 +UCAS40156 = 9.0 +UCJS10047 = 9.0 +UCKS45034 = 9.0 + +# LEGO Batman: The Videogame +NPUH90019 = 1.0 +ULES01151 = 1.0 +ULUS10380 = 1.0 + +# LEGO Indiana Jones 1: The Original Adventures +ULES01086 = 47.0 +ULUS10365 = 47.0 + +# LEGO Indiana Jones 2: The Adventure Continues +ULES01370 = 47.0 +ULUS10487 = 47.0 + +# LEGO Star Wars II: The Original Trilogy +ULES00479 = 47.0 +ULUS10155 = 47.0 + +# Lemmings +NPJG00058 = 5.0 +UCAS40076 = 5.0 +UCES00109 = 5.0 +UCET00179 = 5.0 +UCJS10028 = 5.0 +UCUS98647 = 5.0 +UCUS98671 = 5.0 + +# LocoRoco +NPJG00057 = 1.0 +UCAS40063 = 1.0 +UCAS40157 = 1.0 +UCED90007 = 1.0 +UCES00304 = 1.0 +UCET00357 = 1.0 +UCJB98011 = 1.0 +UCJS10041 = 1.0 +UCJS18041 = 1.0 +UCKS45020 = 1.0 +UCKS45055 = 1.0 +UCUS98662 = 1.0 + +# Macross Ace Frontier +ULJS00158 = 1.0 +ULJS19029 = 1.0 + +# Me & My Katamari +NPJH50141 = 1.0 +UCAS40049 = 1.0 +UCKS45022 = 1.0 +ULAS40155 = 1.0 +ULES00339 = 1.0 +ULJS00033 = 1.0 +ULJS19009 = 1.0 +ULUS10094 = 1.0 + +# Mega Man Powered Up +NPJH50183 = 10.0 +UCAS40208 = 10.0 +ULAS42050 = 10.0 +ULAS42052 = 10.0 +ULES00307 = 10.0 +ULJM05044 = 10.0 +ULJM05391 = 10.0 +ULUS10091 = 10.0 + +# Metal Gear Acid 1 +ULAS42007 = 1000.0 +ULES00008 = 1000.0 +ULJM05001 = 1000.0 +ULJM08001 = 1000.0 +ULUS10006 = 1000.0 + +# Metal Gear Acid 2 +ULAS42035 = 930.0 +ULES00284 = 930.0 +ULJM05047 = 930.0 +ULJM08011 = 930.0 +ULKS46065 = 930.0 +ULUS10077 = 930.0 + +# Metal Gear Solid: Digital Graphic Novel +NPJH50128 = 1.0 +ULES00382 = 1.0 +ULJM05150 = 1.0 +ULUS10108 = 1.0 + +# Metal Gear Solid: Peace Walker +NPEH90023 = 1000.0 +NPJH50045 = 1000.0 +ULES01372 = 1000.0 +ULJM05630 = 1000.0 +ULJM08038 = 1000.0 +ULKS46239 = 1000.0 +ULUS10509 = 1000.0 + +# Metal Gear Solid: Portable Ops +NPJH50112 = 970.0 +ULAS42087 = 970.0 +ULES00645 = 970.0 +ULJM05193 = 970.0 +ULJM05227 = 970.0 +ULJM05256 = 970.0 +ULJM05284 = 970.0 +ULJM05573 = 970.0 +ULJM08016 = 970.0 +ULKS46119 = 970.0 +ULUS10202 = 970.0 + +# Monopoly +NPEZ00118 = 70.0 +NPUZ00033 = 70.0 + +# Monster Hunter Freedom 2 +ULAS42110 = 100.0 ULES00851 = 100.0 +ULJM05156 = 100.0 +ULKS46152 = 100.0 +ULUS10266 = 100.0 + +# Monster Hunter Freedom Unite +NPEH90011 = 100.0 +NPJH50244 = 100.0 +ULAS42093 = 100.0 +ULES01213 = 100.0 +ULJM05500 = 100.0 +ULJM08019 = 100.0 +ULJM08053 = 100.0 +ULKS46177 = 100.0 +ULKS46202 = 100.0 +ULUS10391 = 100.0 +ULUS90003 = 100.0 + +# Monster Hunter Portable 3rd +NPJB40001 = 100.0 +NPJH55800 = 100.0 +ULJM05800 = 100.0 +ULJM08058 = 100.0 + +# Nayuta no Kiseki +NPJH50625 = 1.0 +ULJM06113 = 1.0 +ULJM08069 = 1.0 + +# Patapon 1 +NPJG00054 = 80.0 +UCAS40193 = 80.0 +UCAS40221 = 80.0 +UCES00995 = 80.0 +UCJS10077 = 80.0 +UCJS18027 = 80.0 +UCJS18042 = 80.0 +UCKS45076 = 80.0 +UCUS98711 = 80.0 +UCUS98717 = 80.0 + +# Patapon 2 +NPJG00010 = 80.0 +NPUG98732 = 80.0 +UCAS40232 = 80.0 +UCAS40239 = 80.0 +UCAS40292 = 80.0 +UCES01177 = 80.0 +UCJS10089 = 80.0 +UCJS18036 = 80.0 +UCJS18053 = 80.0 +UCUS98732 = 80.0 + +# Patapon 3 +NPJG00122 = 100.0 +UCAS40318 = 100.0 +UCES01421 = 100.0 +UCJS10113 = 100.0 +UCJS18048 = 100.0 +UCJS18059 = 100.0 +UCKS45169 = 100.0 +UCUS98751 = 100.0 + +# Petz: Dogz Family +ULUS10463 = 3.28 + +# Prince of Persia Revelations +ULES00223 = 1.0 +ULUS10063 = 1.0 + +# Ratchet & Clank: Size Matters +NPJG00015 = 1.0 +UCAS40145 = 1.0 +UCES00420 = 1.0 +UCJS10052 = 1.0 +UCJS18030 = 1.0 +UCJS18047 = 1.0 +UCKS45048 = 1.0 +UCUS98633 = 1.0 + +# Ridge Racer 2 +NPJH50366 = 1000.0 +UCAS40113 = 1000.0 +UCAS40119 = 1000.0 +UCAS40273 = 1000.0 +UCES00422 = 1000.0 +UCKS45032 = 1000.0 +ULJS00080 = 1000.0 + +# Sega Rally Revo +ULAS42119 = 1.0 +ULES00910 = 1.0 +ULET00919 = 1.0 +ULJM05302 = 1.0 +ULJM05417 = 1.0 +ULUS10311 = 1.0 + +# Shin Megami Tensei: Persona 3 Portable +NPJH50040 = 1.0 +UCAS40288 = 1.0 +UCKS45140 = 1.0 +UCKS45175 = 1.0 +ULES01523 = 1.0 +ULJM05489 = 1.0 +ULJM08044 = 1.0 +ULUS10512 = 1.0 + +# Silent Hill: Origins +NPJH50051 = 1.0 +ULAS42117 = 1.0 ULES00869 = 1.0 -ULES00959 = 1.0 +ULJM05281 = 1.0 +ULKS46161 = 1.0 +ULUS10285 = 1.0 + +# Silent Hill: Shattered Memories +NPJH50148 = 1.0 +ULAS42189 = 1.0 +ULES01352 = 1.0 +ULJM05564 = 1.0 +ULJM05828 = 1.0 +ULUS10450 = 1.0 + +# SoulCalibur: Broken Destiny +NPJH50034 = 1.0 +UCKS45126 = 1.0 +ULES01298 = 1.0 +ULJS00202 = 1.0 +ULJS19055 = 1.0 +ULUS10457 = 1.0 + +# Spectral vs Generation +UCAS40102 = 1.0 +ULES00757 = 1.0 +ULJM05162 = 1.0 +ULJM05599 = 1.0 +ULUS10076 = 1.0 + +# Spot the Differences! +NPEZ00107 = 1.0 +NPEZ00108 = 1.0 +NPUZ00034 = 1.0 + +# Star Soldier +NPJH50261 = 1.0 +ULJM05026 = 1.0 +ULJM05235 = 1.0 + +# Star Trek: Tactical Assault +ULES00623 = 0.01 +ULUS10150 = 0.01 + +# Star Wars: Battlefront II +ULAS42037 = 1.0 +ULES00183 = 1.0 +ULJM05060 = 1.0 +ULUS10053 = 1.0 + +# Star Wars: The Force Unleashed +ULES00981 = 100.0 +ULES00982 = 100.0 +ULKS46143 = 100.0 +ULUS10345 = 100.0 + +# Street Fighter Alpha 3 MAX +ULES00235 = 1.0 +ULJM05082 = 1.0 +ULJM05225 = 1.0 +ULUS10062 = 1.0 + +# Sword Art Online: Infinity Moment +NPJH50701 = 1.0 +ULJS00557 = 1.0 +ULJS00558 = 1.0 + +# Tekken: Dark Resurrection +NPJH50137 = 1000.0 +UCAS40095 = 1000.0 +UCAS40099 = 1000.0 +UCAS40164 = 1000.0 +UCAS40165 = 1000.0 +UCED00448 = 1000.0 +UCES00356 = 1000.0 +UCET00424 = 1000.0 +UCKS45027 = 1000.0 +ULJS00048 = 1000.0 +ULJS19013 = 1000.0 +ULUS10139 = 1000.0 + +# Tekken 6 +NPJH50184 = 1000.0 +NPUH10047 = 1000.0 +ULAS42214 = 1000.0 +ULES01376 = 1000.0 +ULJS00224 = 1000.0 +ULJS19054 = 1000.0 +ULKS46235 = 1000.0 +ULKS46265 = 1000.0 +ULUS10466 = 1000.0 + +# Tenchu: Shadow Assassins +UCAS40247 = 10.0 +ULES01237 = 10.0 +ULJM05425 = 10.0 +ULJM05471 = 10.0 +ULJM08027 = 10.0 +ULUS10419 = 10.0 + +# Tenchu: Time of the Assassins +NPJH50042 = 100.0 +UCAS40020 = 100.0 +UCAS40092 = 100.0 +ULES00277 = 100.0 +ULJS00018 = 100.0 +ULJS19007 = 100.0 + +# The 3rd Birthday +NPJH50361 = 100.0 +UCAS40325 = 100.0 +UCAS40336 = 100.0 +UCKS45163 = 100.0 +ULES01513 = 100.0 +ULJM05798 = 100.0 +ULJM06008 = 100.0 +ULUS10567 = 100.0 + +# The Simpsons Game +ULAS42115 = 1.0 ULES00975 = 1.0 ULES00976 = 1.0 ULES00977 = 1.0 ULES00978 = 1.0 ULES00979 = 1.0 -ULES00981 = 100.0 -ULES00982 = 100.0 -ULES00986 = 6.8 -ULES00987 = 1.0 -ULES01013 = 1.0 -ULES01037 = 1.0 -ULES01044 = 100.0 -ULES01045 = 100.0 -ULES01046 = 100.0 -ULES01047 = 100.0 -ULES01086 = 47.0 -ULES01151 = 1.0 -ULES01213 = 100.0 -ULES01237 = 10.0 -ULES01238 = 1.0 -ULES01239 = 1.0 -ULES01240 = 1.0 -ULES01270 = 1.0 -ULES01298 = 1.0 -ULES01347 = 1.0 -ULES01352 = 1.0 -ULES01357 = 1.0 -ULES01367 = 1.0 -ULES01370 = 47.0 -ULES01372 = 1000.0 -ULES01376 = 1000.0 -ULES01381 = 128.0 -ULES01417 = 9.0 -ULES01422 = 1.000999 -ULES01431 = 0.8 -ULES01441 = 1.0 -ULES01505 = 1.0 -ULES01513 = 100.0 -ULES01519 = 100 -ULES01521 = 1.0 -ULES01523 = 1.0 -ULES01526 = 1.0 -ULET00456 = 1.0 -ULET00919 = 1.0 -ULJM05001 = 1000.0 -ULJM05003 = 0.1 -ULJM05026 = 1.0 -ULJM05036 = 1.0 -ULJM05047 = 930.0 -ULJM05049 = 1.0 -ULJM05060 = 1.0 -ULJM05082 = 1.0 -ULJM05104 = 1.0 -ULJM05105 = 1.0 -ULJM05130 = 50.0 -ULJM05149 = 1.0 -ULJM05150 = 1.0 -ULJM05156 = 100.0 -ULJM05162 = 1.0 -ULJM05176 = 1.0 -ULJM05180 = 256.0 -ULJM05181 = 10.0 -ULJM05193 = 970.0 -ULJM05194 = 1.0 -ULJM05227 = 970.0 -ULJM05228 = 1.0 -ULJM05235 = 1.0 -ULJM05241 = 6.8 -ULJM05243 = 1.0 -ULJM05245 = 1.0 -ULJM05254 = 100.0 -ULJM05255 = 1.0 -ULJM05262 = 1.0 -ULJM05275 = 100.0 -ULJM05280 = 1.0 -ULJM05281 = 1.0 -ULJM05284 = 970.0 -ULJM05287 = 100.0 -ULJM05297 = 1.0 -ULJM05302 = 1.0 -ULJM05319 = 10.0 -ULJM05340 = 1.0 -ULJM05348 = 1.0 -ULJM05369 = 1.0 -ULJM05408 = 32.0 -ULJM05425 = 10.0 -ULJM05471 = 10.0 -ULJM05472 = 3.6 -ULJM05492 = 1.0 -ULJM05550 = 1.0 -ULJM05571 = 1.0 -ULJM05600 = 1.0 -ULJM05604 = 1.0 -ULJM05643 = 128.0 -ULJM05681 = 4.0 -ULJM05775 = 1.0 -ULJM05779 = 1.0 -ULJM05798 = 100.0 -ULJM05836 = 1.0 -ULJM05848 = 1.0 -ULJM05859 = 80 -ULJM06034 = 1.0 -ULJM08001 = 1000.0 -ULJM08011 = 930.0 -ULJM08027 = 10.0 -ULJS00003 = 1.0 -ULJS00018 = 100.0 -ULJS00033 = 1.0 -ULJS00048 = 1000.0 -ULJS00080 = 1000.0 -ULJS00086 = 1.0 -ULJS00158 = 1.0 -ULJS00202 = 1.0 -ULJS00224 = 1000.0 -ULJS00350 = 100 -ULJS19001 = 1.0 -ULJS19007 = 100.0 -ULJS19009 = 1.0 -ULJS19013 = 1000.0 -ULJS19018 = 1.0 -ULKS46003 = 1.0 -ULKS46012 = 0.1 -ULKS46021 = 1.0 -ULKS46023 = 10.0 -ULKS46027 = 1.0 -ULKS46057 = 10.0 -ULKS46065 = 930.0 -ULKS46071 = 50.0 -ULKS46116 = 1.0 -ULKS46119 = 970.0 -ULKS46122 = 32.0 -ULKS46139 = 1.0 -ULKS46142 = 1.0 -ULKS46152 = 100.0 -ULKS46155 = 100.0 -ULKS46189 = 1.0 -ULKS46190 = 1.0 -ULKS46236 = 1.0 -ULKS46240 = 1.0 -ULUS10004 = 0.1 -ULUS10006 = 1000.0 -ULUS10014 = 0.005 -ULUS10017 = 10.0 -ULUS10020 = 83 -ULUS10025 = 1.0 -ULUS10027 = 1.0 -ULUS10032 = 1.0 -ULUS10034 = 1.0 -ULUS10037 = 10.0 -ULUS10041 = 1.0 -ULUS10044 = 1.0 -ULUS10050 = 10.0 -ULUS10053 = 1.0 -ULUS10057 = 1.0 -ULUS10062 = 1.0 -ULUS10063 = 1.0 -ULUS10073 = 1.0 -ULUS10077 = 930.0 -ULUS10083 = 1.0 -ULUS10091 = 10.0 -ULUS10094 = 1.0 -ULUS10105 = 7.8 -ULUS10108 = 1.0 -ULUS10110 = 256.0 -ULUS10128 = 1.0 -ULUS10134 = 1.0 -ULUS10139 = 1000.0 -ULUS10146 = 0.1 -ULUS10150 = 0.01 -ULUS10155 = 47.0 -ULUS10156 = 1.0 -ULUS10158 = 1.0 -ULUS10160 = 1.0 -ULUS10175 = 1.0 -ULUS10176 = 1.0 -ULUS10184 = 1.0 -ULUS10185 = 1.0 -ULUS10186 = 1.0 -ULUS10202 = 970.0 -ULUS10207 = 50.0 -ULUS10218 = 1.05 -ULUS10223 = 10.0 -ULUS10227 = 1.0 -ULUS10238 = 1.0 -ULUS10241 = 0.95 -ULUS10245 = 1.0 -ULUS10247 = 10.0 -ULUS10248 = 0.5 -ULUS10251 = 6.8 -ULUS10263 = 1.0 -ULUS10266 = 100.0 -ULUS10273 = 1.0 -ULUS10277 = 100.0 -ULUS10285 = 1.0 ULUS10295 = 1.0 -ULUS10297 = 1.0 -ULUS10311 = 1.0 -ULUS10316 = 1.0 -ULUS10319 = 10.0 -ULUS10325 = 1.0 -ULUS10335 = 1.0 -ULUS10336 = 100.0 -ULUS10345 = 100.0 -ULUS10363 = 1.0 -ULUS10365 = 47.0 -ULUS10380 = 1.0 -ULUS10391 = 100.0 -ULUS10400 = 1.0 -ULUS10403 = 1.0 -ULUS10405 = 1.0 -ULUS10419 = 10.0 -ULUS10431 = 1.0 -ULUS10437 = 1.0 -ULUS10439 = 1.0 -ULUS10450 = 1.0 -ULUS10451 = 1.0 -ULUS10455 = 1.0 -ULUS10457 = 1.0 -ULUS10463 = 3.28 -ULUS10466 = 1000.0 -ULUS10472 = 128.0 -ULUS10486 = 3.28 -ULUS10487 = 47.0 -ULUS10490 = 1.0 -ULUS10497 = 1.000999 -ULUS10505 = 1.0 -ULUS10509 = 1000.0 -ULUS10512 = 1.0 -ULUS10515 = 9.0 -ULUS10519 = 1.0 -ULUS10521 = 0.8 -ULUS10538 = 1.0 -ULUS10560 = 1.0 -ULUS10563 = 100 -ULUS10566 = 1.0 -ULUS10567 = 100.0 -ULUS10579 = 1.0 -ULUS10592 = 1.0 -ULUS90003 = 100.0 +# The Terminator +NPEZ00140 = 1.0 +NPUZ00056 = 1.0 + +# Tomb Raider: Legend +ULES00283 = 256.0 +ULJM05180 = 256.0 +ULUS10110 = 256.0 + +# Tony Hawk's Underground 2 Remix +ULES00033 = 0.005 +ULES00034 = 0.005 +ULES00035 = 0.005 +ULUS10014 = 0.005 + +# Ultimate Ghosts 'n Goblins +NPJH50235 = 7.8 +ULAS42069 = 7.8 +ULAS42073 = 7.8 +ULES00419 = 7.8 +ULJM05147 = 7.8 +ULUS10105 = 7.8 + +# Valkyria Chronicles II +NPJH50145 = 9.0 +ULES01417 = 9.0 +ULJM05560 = 9.0 +ULJM05807 = 9.0 +ULUS10515 = 9.0 + +# Virtua Tennis: World Tour +ULES00126 = 10.0 +ULJM05079 = 10.0 +ULKS46023 = 10.0 +ULUS10037 = 10.0 + +# Wipeout Pulse +NPEG90003 = 1.0 +NPUG70008 = 1.0 +UCAS40179 = 1.0 +UCES00465 = 1.0 +UCET00713 = 1.0 +UCKS45078 = 1.0 +UCUS98712 = 1.0 + +# Wipeout Pure +NPJG00059 = 1.0 +UCAS40012 = 1.0 +UCES00001 = 1.0 +ULJM05105 = 1.0 +UCJS10007 = 1.0 +UCKS45008 = 1.0 +UCUS98612 = 1.0 + +# WWE SmackDown! vs. Raw 2006 +ULES00227 = 10.0 +ULJM05103 = 10.0 +ULKS46057 = 10.0 +ULUS10050 = 10.0 From df04280c3473ac211cf2ebf83d8cf8453fa83953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Von=C3=A1sek?= Date: Sat, 22 Oct 2022 16:45:57 +0200 Subject: [PATCH 077/715] OpenXR - Wrong condition removed (#16271) --- Common/VR/PPSSPPVR.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index edb88a3400..a3f550bee3 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -367,8 +367,6 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { // Quick analyze if the object is in 2D if ((fabs(fabs(projMatrix[12]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[13]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[14]) - 1.0f) < EPSILON)) { return true; - } else if ((fabs(projMatrix[0] - 1) < EPSILON) && (fabs(projMatrix[5] - 1) < EPSILON)) { - return true; } else if ((fabs(projMatrix[0]) > 10.0f) && (fabs(projMatrix[5]) > 10.0f)) { return true; } else if (fabs(projMatrix[15] - 1) < EPSILON) { From 767bf55afb28ebc9dfc4bc3c5e66261f4b33f75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 22 Oct 2022 17:11:40 +0200 Subject: [PATCH 078/715] Remove duplicate line in libretro makefile. Fixes #16269 --- libretro/Makefile.common | 1 - 1 file changed, 1 deletion(-) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 7a8fd74121..cd9f7f04d7 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -321,7 +321,6 @@ SOURCES_CXX += \ $(COMMONDIR)/VR/VRMath.cpp \ $(COMMONDIR)/VR/VRFramebuffer.cpp \ $(COMMONDIR)/VR/VRInput.cpp \ - $(COMMONDIR)/VR/VRMath.cpp \ $(COMMONDIR)/VR/VRRenderer.cpp SOURCES_C +=\ From 3af86ec6f7d0a26541104c92b216d4b0a1d5041c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 22 Oct 2022 17:41:42 +0200 Subject: [PATCH 079/715] Make it possible to specify extensions for Vulkan in the ShaderWriter --- Common/GPU/ShaderWriter.cpp | 14 ++++++++------ Common/GPU/ShaderWriter.h | 7 ++++--- GPU/Common/FragmentShaderGenerator.cpp | 2 +- GPU/Common/GeometryShaderGenerator.cpp | 2 +- GPU/Common/StencilCommon.cpp | 4 ++-- GPU/Common/VertexShaderGenerator.cpp | 2 +- unittest/TestShaderGenerators.cpp | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 7ca6deaeb0..0f0d416bf7 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -7,7 +7,6 @@ #include "Common/Log.h" const char * const vulkan_glsl_preamble_fs = -"#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" "#extension GL_ARB_conservative_depth : enable\n" @@ -45,7 +44,6 @@ static const char * const hlsl_d3d9_preamble_fs = "#define DISCARD_BELOW(x) clip(x)\n"; static const char * const vulkan_glsl_preamble_vs = -"#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" "#define mul(x, y) ((x) * (y))\n" @@ -69,7 +67,6 @@ static const char * const hlsl_preamble_gs = "\n"; static const char * const vulkan_glsl_preamble_gs = -"#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" "#define mul(x, y) ((x) * (y))\n" @@ -113,9 +110,14 @@ ShaderWriter & ShaderWriter::F(const char *format, ...) { return *this; } -void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions) { +void ShaderWriter::Preamble(Slice extensions) { switch (lang_.shaderLanguage) { case GLSL_VULKAN: + C("#version 450\n"); + // IMPORTANT! Extensions must be the first thing after #version. + for (size_t i = 0; i < extensions.size(); i++) { + F("%s\n", extensions[i]); + } switch (stage_) { case ShaderStage::Vertex: W(vulkan_glsl_preamble_vs); @@ -154,8 +156,8 @@ void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions default: // OpenGL F("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : ""); // IMPORTANT! Extensions must be the first thing after #version. - for (size_t i = 0; i < num_gl_extensions; i++) { - F("%s\n", gl_extensions[i]); + for (size_t i = 0; i < extensions.size(); i++) { + F("%s\n", extensions[i]); } // Print some system info - useful to gather information directly from screenshots. if (strlen(lang_.driverInfo) != 0) { diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 50f3bb1f0d..a957362b70 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -37,8 +37,9 @@ enum FSFlags { class ShaderWriter { public: - ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions = nullptr, size_t num_gl_extensions = 0) : p_(buffer), lang_(lang), stage_(stage) { - Preamble(gl_extensions, num_gl_extensions); + // Extensions are supported for both OpenGL ES and Vulkan (though of course, they're different). + ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice extensions = Slice()) : p_(buffer), lang_(lang), stage_(stage) { + Preamble(extensions); } ShaderWriter(const ShaderWriter &) = delete; @@ -110,7 +111,7 @@ private: void DeclareSampler2D(const char *name, int binding); void DeclareTexture2D(const char *name, int binding); - void Preamble(const char **gl_extensions, size_t num_gl_extensions); + void Preamble(Slice extensions); char *p_; const ShaderLanguageDesc &lang_; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 5fe27b19c0..223cd7976f 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -74,7 +74,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } } - ShaderWriter p(buffer, compat, ShaderStage::Fragment, gl_exts.data(), gl_exts.size()); + ShaderWriter p(buffer, compat, ShaderStage::Fragment, gl_exts); bool lmode = id.Bit(FS_BIT_LMODE); bool doTexture = id.Bit(FS_BIT_DO_TEXTURE); diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index 18a2bc182e..fc8a9f9a27 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -48,7 +48,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu bool vertexRangeCulling = !id.Bit(GS_BIT_CURVE); bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP); - ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts.data(), gl_exts.size()); + ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts); p.C("layout(triangles) in;\n"); if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { p.C("layout(triangle_strip, max_vertices = 12) out;\n"); diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 02dea5f739..fd552208f7 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -84,7 +84,7 @@ static const SamplerDef samplers[1] = { }; void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { - ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); + ShaderWriter writer(buffer, lang, ShaderStage::Fragment); writer.HighPrecisionFloat(); writer.DeclareSamplers(samplers); @@ -111,7 +111,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: // This can probably be shared with some other shaders, like reinterpret or the future depth upload. void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) { - ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); + ShaderWriter writer(buffer, lang, ShaderStage::Vertex); writer.BeginVSMain(lang.vertexIndex ? Slice::empty() : inputs, Slice::empty(), varyings); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index ab8ed2a80f..5b7e321277 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -153,7 +153,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } } - ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts.data(), gl_exts.size()); + ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts); bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); bool lmode = id.Bit(VS_BIT_LMODE); diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index d5f2f9cc55..a9546408a5 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -243,7 +243,7 @@ bool TestReinterpretShaders() { for (int j = 0; j < 3; j++) { if (i == j) continue; // useless shader! - ShaderWriter writer(buffer, desc, ShaderStage::Fragment, nullptr, 0); + ShaderWriter writer(buffer, desc, ShaderStage::Fragment); GenerateReinterpretFragmentShader(writer, fmts[i], fmts[j]); if (strlen(buffer) >= 8192) { printf("Reinterpret fragment shader %d exceeded buffer:\n\n%s\n", (int)j, LineNumberString(buffer).c_str()); From 299033929ad53ab685f728ea3451fb826c6774b2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 09:04:48 -0700 Subject: [PATCH 080/715] GE Debugger: List verts on bounding box command. --- Windows/GEDebugger/TabVertices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index f7ab9af7ac..024938a43d 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -293,7 +293,7 @@ int CtrlVertexList::GetRowCount() { DisplayList list; if (gpuDebug->GetCurrentDisplayList(list)) { u32 cmd = Memory::Read_U32(list.pc); - if ((cmd >> 24) == GE_CMD_PRIM) { + if ((cmd >> 24) == GE_CMD_PRIM || (cmd >> 24) == GE_CMD_BOUNDINGBOX) { rowCount_ = cmd & 0xFFFF; } else if ((cmd >> 24) == GE_CMD_BEZIER || (cmd >> 24) == GE_CMD_SPLINE) { u32 u = (cmd & 0x00FF) >> 0; From 6ddf22487b3dd43d79a529a2504e5d0640f948b6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 09:06:33 -0700 Subject: [PATCH 081/715] GPU: Correct bounding box for larger counts. Matches tests on a PSP with float/transform format. --- GPU/Common/DrawEngineCommon.cpp | 6 +----- GPU/Common/DrawEngineCommon.h | 2 +- GPU/GPUCommon.cpp | 23 ++++++++++++++++++----- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 495b206515..46742e79b7 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -244,7 +244,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex // // It does the simplest and safest test possible: If all points of a bbox is outside a single of // our clipping planes, we reject the box. Tighter bounds would be desirable but would take more calculations. -bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCount, u32 vertType, int *bytesRead) { +bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCount, u32 vertType) { SimpleVertex *corners = (SimpleVertex *)(decoded + 65536 * 12); float *verts = (float *)(decoded + 65536 * 18); @@ -252,19 +252,16 @@ bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCou // and a large vertex format. if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT) { verts = (float *)control_points; - *bytesRead = 3 * sizeof(float) * vertexCount; } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT) { const s8 *vtx = (const s8 *)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 128.0f); } - *bytesRead = 3 * sizeof(s8) * vertexCount; } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT) { const s16 *vtx = (const s16*)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 32768.0f); } - *bytesRead = 3 * sizeof(s16) * vertexCount; } else { // Simplify away bones and morph before proceeding u8 *temp_buffer = decoded + 65536 * 24; @@ -275,7 +272,6 @@ bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCou verts[i * 3 + 1] = corners[i].pos.y; verts[i * 3 + 2] = corners[i].pos.z; } - *bytesRead = vertexSize * vertexCount; } Plane planes[6]; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 8fc0382a29..7a6ba863fd 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -92,7 +92,7 @@ public: virtual void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation); - bool TestBoundingBox(const void* control_points, int vertexCount, u32 vertType, int *bytesRead); + bool TestBoundingBox(const void* control_points, int vertexCount, u32 vertType); void SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead); template diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 7a6b3fea88..35d91df78a 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2153,13 +2153,17 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { // Just resetting, nothing to check bounds for. - const u32 count = op & 0xFFFFFF; + const u32 count = op & 0xFFFF; if (count == 0) { currentList->bboxResult = false; return; } - if (((count & 7) == 0) && count <= 64) { // Sanity check - const void *control_points = Memory::GetPointer(gstate_c.vertexAddr); + + VertexDecoder *dec = drawEngineCommon_->GetVertexDecoder(gstate.vertType); + int bytesRead = dec->VertexSize() * count; + + if (Memory::IsValidRange(gstate_c.vertexAddr, bytesRead)) { + const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); if (!control_points) { ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Invalid verts in bounding box check"); currentList->bboxResult = true; @@ -2174,8 +2178,17 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { } // Test if the bounding box is within the drawing region. - int bytesRead; - currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, count, gstate.vertType, &bytesRead); + // The PSP only seems to vary the result based on a single range of 0x100. + if (count > 0x200) { + // The second to last set of 0x100 is checked (even for odd counts.) + size_t skipSize = (count - 0x200) * dec->VertexSize(); + currentList->bboxResult = drawEngineCommon_->TestBoundingBox((const uint8_t *)control_points + skipSize, 0x100, gstate.vertType); + } else if (count > 0x100) { + int checkSize = count - 0x100; + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, checkSize, gstate.vertType); + } else { + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, count, gstate.vertType); + } AdvanceVerts(gstate.vertType, count, bytesRead); } else { ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Bad bounding box data: %06x", count); From b7a617023c31fdc9cd399a8c7448de92e9aea075 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 09:09:17 -0700 Subject: [PATCH 082/715] GPU: Consume cycles in bounding box check. --- GPU/GPUCommon.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 35d91df78a..4fb2963851 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2159,6 +2159,9 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { return; } + // Approximate based on timings of several counts on a PSP. + cyclesExecuted += count * 22; + VertexDecoder *dec = drawEngineCommon_->GetVertexDecoder(gstate.vertType); int bytesRead = dec->VertexSize() * count; From 519c90e0494952890b1f58965d8a599cc80fe4fb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 09:41:09 -0700 Subject: [PATCH 083/715] GPU: Correct large morph vertex advance. Can be 544 bytes per vertex. --- GPU/Common/VertexDecoderCommon.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 6a06093902..d3785e13c9 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -460,7 +460,8 @@ public: bool throughmode; bool skinInDecode; - u8 size; + // With morph and weights, this can be more than 256 bytes. + u16 size; u8 onesize_; u8 weightoff; From 8b80c5fb28871ad65f8508092f737281c9995ac4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 10:01:56 -0700 Subject: [PATCH 084/715] GPU: Allow/use indices in bounding box check. Not sure any games actually use this, but it's supported. --- GPU/Common/DrawEngineCommon.cpp | 27 ++++++++++++++++++--------- GPU/Common/DrawEngineCommon.h | 2 +- GPU/GPUCommon.cpp | 23 ++++++++++++++--------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 46742e79b7..ad3f733a40 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -244,33 +244,42 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex // // It does the simplest and safest test possible: If all points of a bbox is outside a single of // our clipping planes, we reject the box. Tighter bounds would be desirable but would take more calculations. -bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCount, u32 vertType) { +bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *inds, int vertexCount, u32 vertType) { SimpleVertex *corners = (SimpleVertex *)(decoded + 65536 * 12); float *verts = (float *)(decoded + 65536 * 18); // Try to skip NormalizeVertices if it's pure positions. No need to bother with a vertex decoder // and a large vertex format. - if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT) { + if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT && !inds) { verts = (float *)control_points; - } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT) { + } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT && !inds) { const s8 *vtx = (const s8 *)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 128.0f); } - } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT) { + } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT && !inds) { const s16 *vtx = (const s16*)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 32768.0f); } } else { - // Simplify away bones and morph before proceeding + // Simplify away indices, bones, and morph before proceeding. u8 *temp_buffer = decoded + 65536 * 24; int vertexSize = 0; - NormalizeVertices((u8 *)corners, temp_buffer, (const u8 *)control_points, 0, vertexCount, vertType, &vertexSize); + + u16 indexLowerBound = 0; + u16 indexUpperBound = (u16)vertexCount - 1; + if (vertexCount > 0 && inds) { + GetIndexBounds(inds, vertexCount, vertType, &indexLowerBound, &indexUpperBound); + } + + NormalizeVertices((u8 *)corners, temp_buffer, (const u8 *)control_points, indexLowerBound, indexUpperBound, vertType); + + IndexConverter conv(vertType, inds); for (int i = 0; i < vertexCount; i++) { - verts[i * 3] = corners[i].pos.x; - verts[i * 3 + 1] = corners[i].pos.y; - verts[i * 3 + 2] = corners[i].pos.z; + verts[i * 3] = corners[conv(i)].pos.x; + verts[i * 3 + 1] = corners[conv(i)].pos.y; + verts[i * 3 + 2] = corners[conv(i)].pos.z; } } diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 7a6ba863fd..ea14a07884 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -92,7 +92,7 @@ public: virtual void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation); - bool TestBoundingBox(const void* control_points, int vertexCount, u32 vertType); + bool TestBoundingBox(const void *control_points, const void *inds, int vertexCount, u32 vertType); void SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead); template diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 4fb2963851..c80aab881c 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2162,8 +2162,9 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { // Approximate based on timings of several counts on a PSP. cyclesExecuted += count * 22; + const bool useInds = (gstate.vertType & GE_VTYPE_IDX_MASK) != 0; VertexDecoder *dec = drawEngineCommon_->GetVertexDecoder(gstate.vertType); - int bytesRead = dec->VertexSize() * count; + int bytesRead = (useInds ? 1 : dec->VertexSize()) * count; if (Memory::IsValidRange(gstate_c.vertexAddr, bytesRead)) { const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); @@ -2173,11 +2174,15 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { return; } - if (gstate.vertType & GE_VTYPE_IDX_MASK) { - ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Indexed bounding box data not supported."); - // Data seems invalid. Let's assume the box test passed. - currentList->bboxResult = true; - return; + const void *inds = nullptr; + if (useInds) { + int indexShift = ((gstate.vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1; + inds = Memory::GetPointerUnchecked(gstate_c.indexAddr); + if (!inds || !Memory::IsValidRange(gstate_c.indexAddr, count << indexShift)) { + ERROR_LOG_REPORT_ONCE(boundingboxInds, G3D, "Invalid inds in bounding box check"); + currentList->bboxResult = true; + return; + } } // Test if the bounding box is within the drawing region. @@ -2185,12 +2190,12 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { if (count > 0x200) { // The second to last set of 0x100 is checked (even for odd counts.) size_t skipSize = (count - 0x200) * dec->VertexSize(); - currentList->bboxResult = drawEngineCommon_->TestBoundingBox((const uint8_t *)control_points + skipSize, 0x100, gstate.vertType); + currentList->bboxResult = drawEngineCommon_->TestBoundingBox((const uint8_t *)control_points + skipSize, inds, 0x100, gstate.vertType); } else if (count > 0x100) { int checkSize = count - 0x100; - currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, checkSize, gstate.vertType); + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, inds, checkSize, gstate.vertType); } else { - currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, count, gstate.vertType); + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, inds, count, gstate.vertType); } AdvanceVerts(gstate.vertType, count, bytesRead); } else { From 93ee82d84f6b95c46ee2ea30ee64b66cc0441ff3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 10:29:47 -0700 Subject: [PATCH 085/715] GPU: Respect depth clamp in bounding box check. Although, logically, this feels reversed - it rejects the point if it's outside positive Z, which would clamp. This matches PSP tests. --- GPU/Common/DrawEngineCommon.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index ad3f733a40..17b93dc810 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -295,7 +295,9 @@ bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *i Matrix4ByMatrix4(worldview, world, view); Matrix4ByMatrix4(worldviewproj, worldview, gstate.projMatrix); PlanesFromMatrix(worldviewproj, planes); - for (int plane = 0; plane < 6; plane++) { + // Note: near/far are not checked without clamp/clip enabled, so we skip those planes. + int totalPlanes = gstate.isDepthClampEnabled() ? 6 : 4; + for (int plane = 0; plane < totalPlanes; plane++) { int inside = 0; int out = 0; for (int i = 0; i < vertexCount; i++) { From 261f1e13dbd6d3205d588f3f9fe855e435a4295e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 15:47:14 -0700 Subject: [PATCH 086/715] GPU: Account for scissor/viewport in bound test. The bounding box check doesn't check against viewport (which the PSP generally doesn't clip against), but instead checks against the scissor. If the scissor doesn't fit inside the offset 4096x4096 box, that direction is cannot fail the test. --- GPU/Common/DrawEngineCommon.cpp | 49 ++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 17b93dc810..85efff21c6 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -16,8 +16,10 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "Common/Data/Convert/ColorConv.h" +#include "Common/Math/lin/matrix4x4.h" #include "Common/Profiler/Profiler.h" #include "Common/LogReporting.h" #include "Core/Config.h" @@ -294,7 +296,34 @@ bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *i // TODO: Create a Matrix4x3ByMatrix4x3, and Matrix4x4ByMatrix4x3? Matrix4ByMatrix4(worldview, world, view); Matrix4ByMatrix4(worldviewproj, worldview, gstate.projMatrix); - PlanesFromMatrix(worldviewproj, planes); + + // Next, we need to apply viewport, scissor, region, and even offset - but only for X/Y. + // Note that the PSP does not clip against the viewport. + const Vec2f baseOffset = Vec2f(gstate.getOffsetX(), gstate.getOffsetY()); + // Region1 (rate) is used as an X1/Y1 here, matching PSP behavior. + Vec2f minOffset = baseOffset + Vec2f(std::max(gstate.getRegionRateX() - 0x100, gstate.getScissorX1()), std::max(gstate.getRegionRateY() - 0x100, gstate.getScissorY1())) - Vec2f(1.0f, 1.0f); + Vec2f maxOffset = baseOffset + Vec2f(std::min(gstate.getRegionX2(), gstate.getScissorX2()), std::min(gstate.getRegionY2(), gstate.getScissorY2())) + Vec2f(1.0f, 1.0f); + + // Now let's apply the viewport to our scissor/region + offset range. + Vec2f inverseViewportScale = Vec2f(1.0f / gstate.getViewportXScale(), 1.0f / gstate.getViewportYScale()); + Vec2f minViewport = (minOffset - Vec2f(gstate.getViewportXCenter(), gstate.getViewportYCenter())) * inverseViewportScale; + Vec2f maxViewport = (maxOffset - Vec2f(gstate.getViewportXCenter(), gstate.getViewportYCenter())) * inverseViewportScale; + + Lin::Matrix4x4 applyViewport; + applyViewport.empty(); + // Scale to the viewport's size. + applyViewport.xx = 2.0f / (maxViewport.x - minViewport.x); + applyViewport.yy = 2.0f / (maxViewport.y - minViewport.y); + applyViewport.zz = 1.0f; + applyViewport.ww = 1.0f; + // And offset to the viewport's centers. + applyViewport.wx = -(maxViewport.x + minViewport.x) / (maxViewport.x - minViewport.x); + applyViewport.wy = -(maxViewport.y + minViewport.y) / (maxViewport.y - minViewport.y); + + float screenBounds[16]; + Matrix4ByMatrix4(screenBounds, worldviewproj, applyViewport.m); + + PlanesFromMatrix(screenBounds, planes); // Note: near/far are not checked without clamp/clip enabled, so we skip those planes. int totalPlanes = gstate.isDepthClampEnabled() ? 6 : 4; for (int plane = 0; plane < totalPlanes; plane++) { @@ -303,15 +332,27 @@ bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *i for (int i = 0; i < vertexCount; i++) { // Here we can test against the frustum planes! float value = planes[plane].Test(verts + i * 3); - if (value < 0) + if (value <= -FLT_EPSILON) out++; else inside++; } if (inside == 0) { - // All out - return false; + // All out - but check for X and Y if the offset was near the cullbox edge. + bool outsideEdge = false; + if (plane == 1) + outsideEdge = minOffset.x < 1.0f; + if (plane == 2) + outsideEdge = minOffset.y < 1.0f; + else if (plane == 0) + outsideEdge = maxOffset.x >= 4096.0f; + else if (plane == 3) + outsideEdge = maxOffset.y >= 4096.0f; + + // Only consider this outside if offset + scissor/region is fully inside the cullbox. + if (!outsideEdge) + return false; } // Any out. For testing that the planes are in the right locations. From add2edcab8f21e10c2f130ebef1418a404362c9e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 16:09:14 -0700 Subject: [PATCH 087/715] VR: Always pass the bounding box check. Likely better to draw all objects, even if they wouldn't have been on screen, for VR purposes. --- GPU/Common/DrawEngineCommon.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 85efff21c6..35cfb7dfa9 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -250,6 +250,11 @@ bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *i SimpleVertex *corners = (SimpleVertex *)(decoded + 65536 * 12); float *verts = (float *)(decoded + 65536 * 18); + // Although this may lead to drawing that shouldn't happen, the viewport is more complex on VR. + // Let's always say objects are within bounds. + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) + return true; + // Try to skip NormalizeVertices if it's pure positions. No need to bother with a vertex decoder // and a large vertex format. if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT && !inds) { From 10531ec9e6da494f0e34ee0ecbf32b3e3aedf179 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 22 Oct 2022 22:49:41 -0700 Subject: [PATCH 088/715] headless: Update tests. --- pspautotests | 2 +- test.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pspautotests b/pspautotests index 2a607edab7..d40a8e05c3 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 2a607edab7c3f50d9597c3a2b77082c3be871b55 +Subproject commit d40a8e05c3892bd67af71c6f80ea4396f8051541 diff --git a/test.py b/test.py index 4bc6b25ff9..b407f82686 100755 --- a/test.py +++ b/test.py @@ -138,6 +138,10 @@ tests_good = [ "font/optimum", "font/resolution", "font/shadowimagerect", + "gpu/bounding/count", + "gpu/bounding/planes", + "gpu/bounding/vertexaddr", + "gpu/bounding/viewport", "gpu/callbacks/ge_callbacks", "gpu/clipping/homogeneous", "gpu/clut/address", From 813bfded927d5ae67d7257733f567110ad405d1e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Oct 2022 01:09:29 -0700 Subject: [PATCH 089/715] x86jit: Correct vh2f NAN handling (#16275) * x86jit: Correct vh2f NAN handling. Allows another test to pass. * x86jit: Reuse MAccessibleDisp(). --- Common/x64Emitter.h | 13 ++++++++++ Core/MIPS/x86/CompVFPU.cpp | 48 ++++++++++++++++++++++++----------- GPU/Software/DrawPixelX86.cpp | 13 ---------- test.py | 2 +- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h index 50887f18bf..b52a81f35b 100644 --- a/Common/x64Emitter.h +++ b/Common/x64Emitter.h @@ -278,6 +278,19 @@ inline OpArg MRegSum(X64Reg base, X64Reg offset) return MComplex(base, offset, 1, 0); } +template +inline bool Accessible(const T *t1, const T *t2) { + ptrdiff_t diff = (const uint8_t *)t1 - (const uint8_t *)t2; + return diff > -0x7FFFFFE0 && diff < 0x7FFFFFE0; +} + +template +inline OpArg MAccessibleDisp(X64Reg r, const T *tbase, const T *t) { + _assert_(Accessible(tbase, t)); + ptrdiff_t diff = (const uint8_t *)t - (const uint8_t *)tbase; + return MDisp(r, (int)diff); +} + inline OpArg Imm8 (u8 imm) {return OpArg(imm, SCALE_IMM8);} inline OpArg Imm16(u16 imm) {return OpArg(imm, SCALE_IMM16);} //rarely used inline OpArg Imm32(u32 imm) {return OpArg(imm, SCALE_IMM32);} diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 88aa7da0b9..f2380c8499 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -1605,13 +1605,25 @@ void Jit::Comp_Vh2f(MIPSOpcode op) { #define SSE_CONST4(name, val) alignas(16) static const u32 name[4] = { (val), (val), (val), (val) } SSE_CONST4(mask_nosign, 0x7fff); + SSE_CONST4(nan_mantissa, 0x800003ff); SSE_CONST4(magic, (254 - 15) << 23); SSE_CONST4(was_infnan, 0x7bff); SSE_CONST4(exp_infnan, 255 << 23); - // TODO: Fix properly - if (!RipAccessible(mask_nosign)) { - DISABLE; + OpArg mask_nosign_arg, nan_mantissa_arg, magic_arg, was_infnan_arg, exp_infnan_arg; + if (RipAccessible(mask_nosign)) { + mask_nosign_arg = M(&mask_nosign[0]); + nan_mantissa_arg = M(&nan_mantissa[0]); + magic_arg = M(&magic[0]); + was_infnan_arg = M(&was_infnan[0]); + exp_infnan_arg = M(&exp_infnan[0]); + } else { + MOV(PTRBITS, R(TEMPREG), ImmPtr(&mask_nosign[0])); + mask_nosign_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &mask_nosign[0]); + nan_mantissa_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &nan_mantissa[0]); + magic_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &magic[0]); + was_infnan_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &was_infnan[0]); + exp_infnan_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &exp_infnan[0]); } #undef SSE_CONST4 @@ -1649,30 +1661,36 @@ void Jit::Comp_Vh2f(MIPSOpcode op) { // OK, 16 bits in each word. // Let's go. Deep magic here. MOVAPS(XMM1, R(XMM0)); - ANDPS(XMM0, M(&mask_nosign[0])); // xmm0 = expmant. not rip accessible but bailing above + ANDPS(XMM0, mask_nosign_arg); // xmm0 = expmant XORPS(XMM1, R(XMM0)); // xmm1 = justsign = expmant ^ xmm0 MOVAPS(tempR, R(XMM0)); - PCMPGTD(tempR, M(&was_infnan[0])); // xmm2 = b_wasinfnan. not rip accessible but bailing above PSLLD(XMM0, 13); - MULPS(XMM0, M(magic)); /// xmm0 = scaled + MULPS(XMM0, magic_arg); /// xmm0 = scaled PSLLD(XMM1, 16); // xmm1 = sign - ANDPS(tempR, M(&exp_infnan[0])); // not rip accessible but bailing above - ORPS(XMM1, R(tempR)); ORPS(XMM0, R(XMM1)); + // Now create a NAN mask, adding in the sign. + ORPS(XMM1, R(tempR)); // xmm1 = sign + original mantissa. + ANDPS(XMM1, nan_mantissa_arg); // xmm1 = original mantissa + PCMPGTD(tempR, was_infnan_arg); // xmm2 = b_wasinfnan + ORPS(XMM1, exp_infnan_arg); // xmm1 = infnan result + ANDPS(XMM1, R(tempR)); // xmm1 = infnan result OR zero if not infnan + ANDNPS(tempR, R(XMM0)); // tempR = result OR zero if infnan + ORPS(XMM1, R(tempR)); + fpr.MapRegsV(dregs, outsize, MAP_NOINIT | MAP_DIRTY); // TODO: Could apply D-prefix in parallel here... - MOVSS(fpr.V(dregs[0]), XMM0); - SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(3, 3, 2, 1)); - MOVSS(fpr.V(dregs[1]), XMM0); + MOVSS(fpr.V(dregs[0]), XMM1); + SHUFPS(XMM1, R(XMM1), _MM_SHUFFLE(3, 3, 2, 1)); + MOVSS(fpr.V(dregs[1]), XMM1); if (sz != V_Single) { - SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(3, 3, 2, 1)); - MOVSS(fpr.V(dregs[2]), XMM0); - SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(3, 3, 2, 1)); - MOVSS(fpr.V(dregs[3]), XMM0); + SHUFPS(XMM1, R(XMM1), _MM_SHUFFLE(3, 3, 2, 1)); + MOVSS(fpr.V(dregs[2]), XMM1); + SHUFPS(XMM1, R(XMM1), _MM_SHUFFLE(3, 3, 2, 1)); + MOVSS(fpr.V(dregs[3]), XMM1); } ApplyPrefixD(dregs, outsize); diff --git a/GPU/Software/DrawPixelX86.cpp b/GPU/Software/DrawPixelX86.cpp index 53f9c94279..c2c7ce9493 100644 --- a/GPU/Software/DrawPixelX86.cpp +++ b/GPU/Software/DrawPixelX86.cpp @@ -31,19 +31,6 @@ using namespace Gen; namespace Rasterizer { -template -static bool Accessible(const T *t1, const T *t2) { - ptrdiff_t diff = (const uint8_t *)t1 - (const uint8_t *)t2; - return diff > -0x7FFFFFE0 && diff < 0x7FFFFFE0; -} - -template -static OpArg MAccessibleDisp(X64Reg r, const T *tbase, const T *t) { - _assert_(Accessible(tbase, t)); - ptrdiff_t diff = (const uint8_t *)t - (const uint8_t *)tbase; - return MDisp(r, (int)diff); -} - SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) { // Setup the reg cache and disallow spill for arguments. regCache_.SetupABI({ diff --git a/test.py b/test.py index 4bc6b25ff9..94e501681a 100755 --- a/test.py +++ b/test.py @@ -69,6 +69,7 @@ tests_good = [ "cpu/cpu_alu/cpu_branch", "cpu/cpu_alu/cpu_branch2", "cpu/vfpu/colors", + "cpu/vfpu/convert", "cpu/vfpu/gum", "cpu/vfpu/matrix", "cpu/vfpu/vavg", @@ -368,7 +369,6 @@ tests_good = [ tests_next = [ # These are the next tests up for fixing. These run by default. "cpu/fpu/fcr", - "cpu/vfpu/convert", "cpu/vfpu/prefixes", "cpu/vfpu/vector", "cpu/vfpu/vregs", From 79b1d1d35f2aef9fdbfc841e0bcf28ddfe941189 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Oct 2022 01:15:43 -0700 Subject: [PATCH 090/715] softgpu: Better approximate slope mip level mode (#16276) * samplerjit: Remove unused x/y parameters. Still need to tune the accuracy of filtering, but those were not the right way. * softgpu: Better approximate slope mip level mode. This isn't exactly right, but it's closer. * softgpu: Calculate auto from largest difference. Direction shouldn't matter. --- GPU/Software/Rasterizer.cpp | 41 ++++++----- GPU/Software/RasterizerRectangle.cpp | 7 +- GPU/Software/Sampler.cpp | 28 ++++---- GPU/Software/Sampler.h | 4 +- GPU/Software/SamplerX86.cpp | 104 +++++++++++++-------------- unittest/TestSoftwareGPUJit.cpp | 4 +- 6 files changed, 94 insertions(+), 94 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index d75f7f9476..e6d4a5a84f 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -303,18 +303,18 @@ static inline bool IsRightSideOrFlatBottomLine(const Vec2& vertex, const Ve } } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { const u8 **tptr0 = const_cast(&state.texptr[texlevel]); const uint16_t *bufw0 = &state.texbufw[texlevel]; if (!bilinear) { - return state.nearest(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); + return state.nearest(s, t, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); } - return state.linear(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); + return state.linear(s, t, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { - return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texlevel, frac_texlevel, bilinear, state); +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { + return ApplyTexturing(s, t, prim_color, texlevel, frac_texlevel, bilinear, state); } // Produces a signed 1.27.4 value. @@ -332,7 +332,7 @@ static int TexLog2(float delta) { return useful - 127 * 16; } -static inline void CalculateSamplingParams(const float ds, const float dt, const RasterizerState &state, int &level, int &levelFrac, bool &filt) { +static inline void CalculateSamplingParams(const float ds, const float dt, float w, const RasterizerState &state, int &level, int &levelFrac, bool &filt) { const int width = 1 << state.samplerID.width0Shift; const int height = 1 << state.samplerID.height0Shift; @@ -340,11 +340,11 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const int detail; switch (state.TexLevelMode()) { case GE_TEXLEVEL_MODE_AUTO: - detail = TexLog2(std::max(ds * width, dt * height)); + detail = TexLog2(std::max(std::abs(ds * width), std::abs(dt * height))); break; case GE_TEXLEVEL_MODE_SLOPE: // This is always offset by an extra texlevel. - detail = 1 * 16 + TexLog2(state.textureLodSlope); + detail = TexLog2(2.0f * w * state.textureLodSlope); break; case GE_TEXLEVEL_MODE_CONST: default: @@ -377,19 +377,19 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const filt = state.magFilt; } -static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, int x, int y) { +static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, float w) { float ds = s[1] - s[0]; float dt = t[2] - t[0]; int level; int levelFrac; bool bilinear; - CalculateSamplingParams(ds, dt, state, level, levelFrac, bilinear); + CalculateSamplingParams(ds, dt, w, state, level, levelFrac, bilinear); PROFILE_THIS_SCOPE("sampler"); for (int i = 0; i < 4; ++i) { if (mask[i] >= 0) - prim_color[i] = ApplyTexturing(s[i], t[i], ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, ToVec4IntArg(prim_color[i]), level, levelFrac, bilinear, state); + prim_color[i] = ApplyTexturing(s[i], t[i], ToVec4IntArg(prim_color[i]), level, levelFrac, bilinear, state); } } @@ -717,7 +717,13 @@ void DrawTriangleSlice( GetTextureCoordinates(v0, v1, v2, w0, w1, w2, wsum_recip, s, t); } - ApplyTexturing(state, prim_color, mask, s, t, curX, curY); + if (state.TexLevelMode() == GE_TEXLEVEL_MODE_SLOPE) { + // Not sure what's right, but we need one value for the slope. + float clipw = (v0.clipw * w0.x + v1.clipw * w1.x + v2.clipw * w2.x) * wsum_recip.x; + ApplyTexturing(state, prim_color, mask, s, t, clipw); + } else { + ApplyTexturing(state, prim_color, mask, s, t, 0.0f); + } } if (!clearMode) { @@ -923,7 +929,7 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & s = Vec4::AssignToAll(st.s()) + sto4; t = Vec4::AssignToAll(st.t()) + tto4; - ApplyTexturing(state, prim_color, mask, s, t, curX, curY); + ApplyTexturing(state, prim_color, mask, s, t, v1.clipw); } if (!state.pixelID.clearMode) { @@ -1014,9 +1020,9 @@ void DrawPoint(const VertexData &v0, const BinCoords &range, const RasterizerSta int texLevel; int texLevelFrac; bool bilinear; - CalculateSamplingParams(0.0f, 0.0f, state, texLevel, texLevelFrac, bilinear); + CalculateSamplingParams(0.0f, 0.0f, v0.clipw, state, texLevel, texLevelFrac, bilinear); PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, bilinear, state); + prim_color = ApplyTexturingSingle(s, t, ToVec4IntArg(prim_color), texLevel, texLevelFrac, bilinear, state); } if (!pixelID.clearMode) @@ -1342,11 +1348,12 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range // If inc is 0, force the delta to zero. float ds = xinc == 0.0 ? 0.0f : (s1 - s) * (float)SCREEN_SCALE_FACTOR * (1.0f / xinc); float dt = yinc == 0.0 ? 0.0f : (t1 - t) * (float)SCREEN_SCALE_FACTOR * (1.0f / yinc); + float w = (v0.clipw * (float)(steps - i) + v1.clipw * (float)i) / steps1; int texLevel; int texLevelFrac; bool texBilinear; - CalculateSamplingParams(ds, dt, state, texLevel, texLevelFrac, texBilinear); + CalculateSamplingParams(ds, dt, w, state, texLevel, texLevelFrac, texBilinear); if (state.antialiasLines) { // TODO: This is a naive and wrong implementation. @@ -1358,7 +1365,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range } PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, texBilinear, state); + prim_color = ApplyTexturingSingle(s, t, ToVec4IntArg(prim_color), texLevel, texLevelFrac, texBilinear, state); } if (!pixelID.clearMode) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 8d39a2426a..445c36bc32 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -245,9 +245,6 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran } } } else { - int xoff = ((v0.screenpos.x & 15) + 1) / 2; - int yoff = ((v0.screenpos.y & 15) + 1) / 2; - float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); float dtf = dt * (1.0f / (float)(1 << state.samplerID.height0Shift)); float sf_start = s_start * (1.0f / (float)(1 << state.samplerID.width0Shift)); @@ -261,7 +258,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran // Not really that fast but faster than triangle. for (int x = pos0.x; x < pos1.x; x++) { if (CheckDepthTestPassed(pixelID.DepthTestFunc(), x, y, pixelID.cached.depthbufStride, z)) { - Vec4 prim_color = state.nearest(s, t, xoff, yoff, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); + Vec4 prim_color = state.nearest(s, t, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); state.drawPixel(x, y, z, fog, ToVec4IntArg(prim_color), pixelID); } @@ -274,7 +271,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran float s = sf_start; // Not really that fast but faster than triangle. for (int x = pos0.x; x < pos1.x; x++) { - Vec4 prim_color = state.nearest(s, t, xoff, yoff, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); + Vec4 prim_color = state.nearest(s, t, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); state.drawPixel(x, y, z, fog, ToVec4IntArg(prim_color), pixelID); s += dsf; } diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index fa3b1a730f..28d83034de 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -38,8 +38,8 @@ using namespace Rasterizer; namespace Sampler { -static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); static Vec4IntResult SOFTRAST_CALL SampleFetch(int u, int v, const u8 *tptr, int bufw, int level, const SamplerID &samplerID); std::mutex jitCacheLock; @@ -416,7 +416,7 @@ static inline void ApplyTexelClamp(int out_u[N], int out_v[N], const int u[N], c } } -static inline void GetTexelCoordinates(int level, float s, float t, int &out_u, int &out_v, int x, int y, const SamplerID &samplerID) { +static inline void GetTexelCoordinates(int level, float s, float t, int &out_u, int &out_v, const SamplerID &samplerID) { int width = samplerID.cached.sizes[level].w; int height = samplerID.cached.sizes[level].h; @@ -535,15 +535,15 @@ Vec4IntResult SOFTRAST_CALL GetTextureFunctionOutput(Vec4IntArg prim_color_in, V return ToVec4IntResult(Vec4(out_rgb, out_a)); } -static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID) { +static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID) { int u, v; // Nearest filtering only. Round texcoords. - GetTexelCoordinates(level, s, t, u, v, x, y, samplerID); + GetTexelCoordinates(level, s, t, u, v, samplerID); Vec4 c0 = Vec4::FromRGBA(SampleNearest<1>(&u, &v, tptr[0], bufw[0], level, samplerID).v[0]); if (levelFrac) { - GetTexelCoordinates(level + 1, s, t, u, v, x, y, samplerID); + GetTexelCoordinates(level + 1, s, t, u, v, samplerID); Vec4 c1 = Vec4::FromRGBA(SampleNearest<1>(&u, &v, tptr[1], bufw[1], level + 1, samplerID).v[0]); c0 = (c1 * levelFrac + c0 * (16 - levelFrac)) / 16; @@ -609,7 +609,7 @@ static inline Vec4IntResult SOFTRAST_CALL ApplyTexelClampQuadT(bool clamp, int v #endif } -static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadS(int level, float in_s, int &frac_u, int x, const SamplerID &samplerID) { +static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadS(int level, float in_s, int &frac_u, const SamplerID &samplerID) { int width = samplerID.cached.sizes[level].w; int base_u = (int)(in_s * width * 256) - 128; @@ -620,7 +620,7 @@ static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadS(int level, fl return ApplyTexelClampQuadS(samplerID.clampS, base_u, width); } -static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadT(int level, float in_t, int &frac_v, int y, const SamplerID &samplerID) { +static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadT(int level, float in_t, int &frac_v, const SamplerID &samplerID) { int height = samplerID.cached.sizes[level].h; int base_v = (int)(in_t * height * 256) - 128; @@ -631,10 +631,10 @@ static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadT(int level, fl return ApplyTexelClampQuadT(samplerID.clampT, base_v, height); } -static Vec4IntResult SOFTRAST_CALL SampleLinearLevel(float s, float t, int x, int y, const u8 *const *tptr, const uint16_t *bufw, int texlevel, const SamplerID &samplerID) { +static Vec4IntResult SOFTRAST_CALL SampleLinearLevel(float s, float t, const u8 *const *tptr, const uint16_t *bufw, int texlevel, const SamplerID &samplerID) { int frac_u, frac_v; - const Vec4 u = GetTexelCoordinatesQuadS(texlevel, s, frac_u, x, samplerID); - const Vec4 v = GetTexelCoordinatesQuadT(texlevel, t, frac_v, y, samplerID); + const Vec4 u = GetTexelCoordinatesQuadS(texlevel, s, frac_u, samplerID); + const Vec4 v = GetTexelCoordinatesQuadT(texlevel, t, frac_v, samplerID); Nearest4 c = SampleNearest<4>(u.AsArray(), v.AsArray(), tptr[0], bufw[0], texlevel, samplerID); Vec4 texcolor_tl = Vec4::FromRGBA(c.v[0]); @@ -646,10 +646,10 @@ static Vec4IntResult SOFTRAST_CALL SampleLinearLevel(float s, float t, int x, in return ToVec4IntResult((top * (0x10 - frac_v) + bot * frac_v) / (16 * 16)); } -static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int texlevel, int levelFrac, const SamplerID &samplerID) { - Vec4 c0 = SampleLinearLevel(s, t, x, y, tptr, bufw, texlevel, samplerID); +static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int texlevel, int levelFrac, const SamplerID &samplerID) { + Vec4 c0 = SampleLinearLevel(s, t, tptr, bufw, texlevel, samplerID); if (levelFrac) { - const Vec4 c1 = SampleLinearLevel(s, t, x, y, tptr + 1, bufw + 1, texlevel + 1, samplerID); + const Vec4 c1 = SampleLinearLevel(s, t, tptr + 1, bufw + 1, texlevel + 1, samplerID); c0 = (c1 * levelFrac + c0 * (16 - levelFrac)) / 16; } return GetTextureFunctionOutput(prim_color, ToVec4IntArg(c0), samplerID); diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 9af945a9f2..292a93527f 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -36,10 +36,10 @@ namespace Sampler { typedef Rasterizer::Vec4IntResult(SOFTRAST_CALL *FetchFunc)(int u, int v, const u8 *tptr, int bufw, int level, const SamplerID &samplerID); FetchFunc GetFetchFunc(SamplerID id); -typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(float s, float t, int x, int y, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); NearestFunc GetNearestFunc(SamplerID id); -typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, int x, int y, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); LinearFunc GetLinearFunc(SamplerID id); void Init(); diff --git a/GPU/Software/SamplerX86.cpp b/GPU/Software/SamplerX86.cpp index 150856f6f5..7b05debdb5 100644 --- a/GPU/Software/SamplerX86.cpp +++ b/GPU/Software/SamplerX86.cpp @@ -133,8 +133,6 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { regCache_.SetupABI({ RegCache::VEC_ARG_S, RegCache::VEC_ARG_T, - RegCache::GEN_ARG_X, - RegCache::GEN_ARG_Y, RegCache::VEC_ARG_COLOR, RegCache::GEN_ARG_TEXPTR_PTR, RegCache::GEN_ARG_BUFW_PTR, @@ -144,16 +142,16 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { }); #if PPSSPP_PLATFORM(WINDOWS) - // RET + shadow space + 8 byte space for color arg (the Win32 ABI is kinda ugly.) - stackArgPos_ = 8 + 32 + 8; + // RET + shadow space. + stackArgPos_ = 8 + 32; - // Positions: stackArgPos_+0=src, stackArgPos_+8=bufw, stackArgPos_+16=level, stackArgPos_+24=levelFrac - stackIDOffset_ = 32; - stackLevelOffset_ = 16; + // Positions: stackArgPos_+0=bufwptr, stackArgPos_+8=level, stackArgPos_+16=levelFrac + stackIDOffset_ = 24; + stackLevelOffset_ = 8; #else stackArgPos_ = 0; - // This is the only arg that went to the stack, it's after the RET. - stackIDOffset_ = 8; + // No args on the stack. + stackIDOffset_ = -1; stackLevelOffset_ = -1; #endif @@ -182,23 +180,20 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { if (!id.hasAnyMips && regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) regCache_.ForceRelease(RegCache::GEN_ARG_LEVELFRAC); - if (regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { - // On Linux, RCX is currently bufwptr, but we'll need it for other things. + if (regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) { + // On Linux, RCX is currently levelFrac, but we'll need it for other things. if (!cpu_info.bBMI2) { - X64Reg bufwReg = regCache_.Find(RegCache::GEN_ARG_BUFW_PTR); - MOV(64, R(R15), R(bufwReg)); - regCache_.Unlock(bufwReg, RegCache::GEN_ARG_BUFW_PTR); - regCache_.ForceRelease(RegCache::GEN_ARG_BUFW_PTR); - regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); - regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); + X64Reg levelFracReg = regCache_.Find(RegCache::GEN_ARG_LEVELFRAC); + MOV(64, R(R15), R(levelFracReg)); + regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); + regCache_.ForceRelease(RegCache::GEN_ARG_LEVELFRAC); + regCache_.ChangeReg(R15, RegCache::GEN_ARG_LEVELFRAC); + regCache_.ForceRetain(RegCache::GEN_ARG_LEVELFRAC); } - } else { - // Let's load bufwptr/texptrptr into regs. Match Linux just for consistency - RDX is free. + } else if (!regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { + // Let's load bufwptr into regs. RDX is free. MOV(64, R(RDX), MDisp(RSP, stackArgPos_ + 0)); - MOV(64, R(R15), MDisp(RSP, stackArgPos_ + 8)); - regCache_.ChangeReg(RDX, RegCache::GEN_ARG_TEXPTR_PTR); - regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); - regCache_.ForceRetain(RegCache::GEN_ARG_TEXPTR_PTR); + regCache_.ChangeReg(RDX, RegCache::GEN_ARG_BUFW_PTR); regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); } // Okay, now lock RCX as a shifting reg. @@ -284,7 +279,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { CMP(8, R(levelFracReg), Imm8(0)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); } else { - CMP(8, MDisp(RSP, stackArgPos_ + 24), Imm8(0)); + CMP(8, MDisp(RSP, stackArgPos_ + 16), Imm8(0)); } FixupBranch skip = J_CC(CC_Z, true); @@ -295,7 +290,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { regCache_.Unlock(levelReg, RegCache::GEN_ARG_LEVEL); } else { // It's fine to just modify this in place. - ADD(32, MDisp(RSP, stackArgPos_ + 16), Imm8(1)); + ADD(32, MDisp(RSP, stackArgPos_ + stackLevelOffset_), Imm8(1)); } // This is inside the conditional, but it's okay because we throw it away after. @@ -357,7 +352,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { Describe("BlendMips"); if (!regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) { X64Reg levelFracReg = regCache_.Alloc(RegCache::GEN_ARG_LEVELFRAC); - MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 24)); + MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 16)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); regCache_.ForceRetain(RegCache::GEN_ARG_LEVELFRAC); } @@ -413,6 +408,8 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { } regCache_.ForceRelease(RegCache::VEC_RESULT); + if (regCache_.Has(RegCache::GEN_ARG_ID)) + regCache_.ForceRelease(RegCache::GEN_ARG_ID); if (!success) { regCache_.Reset(false); @@ -525,8 +522,6 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.SetupABI({ RegCache::VEC_ARG_S, RegCache::VEC_ARG_T, - RegCache::GEN_ARG_X, - RegCache::GEN_ARG_Y, RegCache::VEC_ARG_COLOR, RegCache::GEN_ARG_TEXPTR_PTR, RegCache::GEN_ARG_BUFW_PTR, @@ -536,22 +531,21 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { }); #if PPSSPP_PLATFORM(WINDOWS) - // RET + shadow space + 8 byte space for color arg (the Win32 ABI is kinda ugly.) - stackArgPos_ = 8 + 32 + 8; + // RET + shadow space. + stackArgPos_ = 8 + 32; // Free up some more vector regs on Windows too, where we're a bit tight. stackArgPos_ += WriteProlog(0, { XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12 }, { R15, R14, R13, R12 }); - // Positions: stackArgPos_+0=src, stackArgPos_+8=bufw, stackArgPos_+16=level, stackArgPos_+24=levelFrac - stackIDOffset_ = 32; - stackLevelOffset_ = 16; + // Positions: stackArgPos_+0=bufwptr, stackArgPos_+8=level, stackArgPos_+16=levelFrac + stackIDOffset_ = 24; + stackLevelOffset_ = 8; - // If needed, we could store UV1 data in shadow space, but we no longer due. + // If needed, we could store UV1 data in shadow space, but we no longer do. stackUV1Offset_ = -8; #else stackArgPos_ = 0; stackArgPos_ += WriteProlog(0, {}, { R15, R14, R13, R12 }); - // Just after the RET. - stackIDOffset_ = 8; + stackIDOffset_ = -1; stackLevelOffset_ = -1; // Use the red zone. @@ -591,8 +585,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { } // We also want to save src and bufw for later. Might be in a reg already. - if (regCache_.Has(RegCache::GEN_ARG_TEXPTR_PTR)) { - _assert_(regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)); + if (regCache_.Has(RegCache::GEN_ARG_TEXPTR_PTR) && regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { X64Reg srcReg = regCache_.Find(RegCache::GEN_ARG_TEXPTR_PTR); X64Reg bufwReg = regCache_.Find(RegCache::GEN_ARG_BUFW_PTR); MOV(64, R(R14), R(srcReg)); @@ -601,6 +594,12 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.Unlock(bufwReg, RegCache::GEN_ARG_BUFW_PTR); regCache_.ForceRelease(RegCache::GEN_ARG_TEXPTR_PTR); regCache_.ForceRelease(RegCache::GEN_ARG_BUFW_PTR); + } else if (regCache_.Has(RegCache::GEN_ARG_TEXPTR_PTR)) { + X64Reg srcReg = regCache_.Find(RegCache::GEN_ARG_TEXPTR_PTR); + MOV(64, R(R14), R(srcReg)); + regCache_.Unlock(srcReg, RegCache::GEN_ARG_TEXPTR_PTR); + regCache_.ForceRelease(RegCache::GEN_ARG_TEXPTR_PTR); + MOV(64, R(R15), MDisp(RSP, stackArgPos_ + 0)); } else { MOV(64, R(R14), MDisp(RSP, stackArgPos_ + 0)); MOV(64, R(R15), MDisp(RSP, stackArgPos_ + 8)); @@ -608,9 +607,11 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { // Okay, and now remember we moved to R14/R15. regCache_.ChangeReg(R14, RegCache::GEN_ARG_TEXPTR_PTR); - regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); regCache_.ForceRetain(RegCache::GEN_ARG_TEXPTR_PTR); - regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); + if (!regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { + regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); + regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); + } bool success = true; @@ -758,7 +759,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { CMP(8, R(levelFracReg), Imm8(0)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); } else { - CMP(8, MDisp(RSP, stackArgPos_ + 24), Imm8(0)); + CMP(8, MDisp(RSP, stackArgPos_ + 16), Imm8(0)); } FixupBranch skip = J_CC(CC_Z, true); @@ -769,7 +770,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.Unlock(levelReg, RegCache::GEN_ARG_LEVEL); } else { // It's fine to just modify this in place. - ADD(32, MDisp(RSP, stackArgPos_ + 16), Imm8(1)); + ADD(32, MDisp(RSP, stackArgPos_ + stackLevelOffset_), Imm8(1)); } if (nearest != nullptr) { @@ -808,7 +809,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { Describe("BlendMips"); if (!regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) { X64Reg levelFracReg = regCache_.Alloc(RegCache::GEN_ARG_LEVELFRAC); - MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 24)); + MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 16)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); regCache_.ForceRetain(RegCache::GEN_ARG_LEVELFRAC); } @@ -870,6 +871,8 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { } regCache_.ForceRelease(RegCache::VEC_RESULT); + if (regCache_.Has(RegCache::GEN_ARG_ID)) + regCache_.ForceRelease(RegCache::GEN_ARG_ID); if (!success) { regCache_.Reset(false); @@ -1223,9 +1226,9 @@ bool SamplerJitCache::Jit_ReadClutQuad(const SamplerID &id, bool level1) { } else { #if PPSSPP_PLATFORM(WINDOWS) if (cpu_info.bAVX2) { - VPBROADCASTD(128, vecLevelReg, MDisp(RSP, stackArgPos_ + 16)); + VPBROADCASTD(128, vecLevelReg, MDisp(RSP, stackArgPos_ + stackLevelOffset_)); } else { - MOVD_xmm(vecLevelReg, MDisp(RSP, stackArgPos_ + 16)); + MOVD_xmm(vecLevelReg, MDisp(RSP, stackArgPos_ + stackLevelOffset_)); PSHUFD(vecLevelReg, R(vecLevelReg), _MM_SHUFFLE(0, 0, 0, 0)); } #else @@ -2583,11 +2586,6 @@ bool SamplerJitCache::Jit_GetTexDataSwizzled(const SamplerID &id, int bitsPerTex bool SamplerJitCache::Jit_GetTexelCoords(const SamplerID &id) { Describe("Texel"); - // First, adjust X and Y... - // TODO: Shouldn't do this in the sampler, need to get s/t right. - regCache_.ForceRelease(RegCache::GEN_ARG_X); - regCache_.ForceRelease(RegCache::GEN_ARG_Y); - X64Reg uReg = regCache_.Alloc(RegCache::GEN_ARG_U); X64Reg vReg = regCache_.Alloc(RegCache::GEN_ARG_V); X64Reg sReg = regCache_.Find(RegCache::VEC_ARG_S); @@ -2602,7 +2600,7 @@ bool SamplerJitCache::Jit_GetTexelCoords(const SamplerID &id) { levelReg = regCache_.Find(RegCache::GEN_ARG_LEVEL); } else { levelReg = regCache_.Alloc(RegCache::GEN_ARG_LEVEL); - MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + 16)); + MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + stackLevelOffset_)); } // We'll multiply these at the same time, so it's nice to put together. @@ -2774,7 +2772,7 @@ bool SamplerJitCache::Jit_GetTexelCoordsQuad(const SamplerID &id) { } else { releaseLevelReg = true; levelReg = regCache_.Alloc(RegCache::GEN_ARG_LEVEL); - MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + 16)); + MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + stackLevelOffset_)); } // This will load the current and next level's sizes, 16x4. @@ -2826,8 +2824,6 @@ bool SamplerJitCache::Jit_GetTexelCoordsQuad(const SamplerID &id) { PSLLD(tempXYReg, 7); PADDD(sReg, R(tempXYReg)); regCache_.Release(tempXYReg, RegCache::VEC_TEMP0); - regCache_.ForceRelease(RegCache::GEN_ARG_X); - regCache_.ForceRelease(RegCache::GEN_ARG_Y); // We do want the fraction, though, so extract that to an XMM for later. X64Reg allFracReg = INVALID_REG; diff --git a/unittest/TestSoftwareGPUJit.cpp b/unittest/TestSoftwareGPUJit.cpp index 54b8ceda52..17d0415264 100644 --- a/unittest/TestSoftwareGPUJit.cpp +++ b/unittest/TestSoftwareGPUJit.cpp @@ -89,8 +89,8 @@ static bool TestSamplerJit() { // Try running each to make sure they don't trivially crash. const auto primArg = Rasterizer::ToVec4IntArg(Math3D::Vec4(127, 127, 127, 127)); - linearFunc(0.0f, 0.0f, 0, 0, primArg, tptr, bufw, 1, 7, id); - nearestFunc(0.0f, 0.0f, 0, 0, primArg, tptr, bufw, 1, 7, id); + linearFunc(0.0f, 0.0f, primArg, tptr, bufw, 1, 7, id); + nearestFunc(0.0f, 0.0f, primArg, tptr, bufw, 1, 7, id); fetchFunc(0, 0, tptr[0], bufw[0], 1, id); } From ecf2797173f5818b4ff0b91f5803304737f50bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 23 Oct 2022 21:50:29 +0200 Subject: [PATCH 091/715] Minor refactor of ShaderWriter flags. Extracted from the stereo PR --- Common/GPU/ShaderWriter.cpp | 16 ++++++++-------- Common/GPU/ShaderWriter.h | 15 +++++++++------ GPU/Common/DepalettizeShaderCommon.cpp | 4 ++-- GPU/Common/Draw2D.cpp | 23 +++++++++++++---------- GPU/Common/GeometryShaderGenerator.cpp | 6 +++--- GPU/Common/ReinterpretFramebuffer.cpp | 4 ++-- GPU/Common/StencilCommon.cpp | 4 ++-- 7 files changed, 39 insertions(+), 33 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 0f0d416bf7..5399c6241a 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -252,7 +252,7 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform } } -void ShaderWriter::BeginFSMain(Slice uniforms, Slice varyings, FSFlags flags) { +void ShaderWriter::BeginFSMain(Slice uniforms, Slice varyings) { _assert_(this->stage_ == ShaderStage::Fragment); switch (lang_.shaderLanguage) { case HLSL_D3D11: @@ -266,13 +266,13 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var C("};\n"); } - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C("float gl_FragDepth;\n"); } C("struct PS_OUT {\n"); C(" vec4 target : SV_Target0;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float depth : SV_Depth;\n"); } C("};\n"); @@ -287,14 +287,14 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var F(") {\n"); C(" PS_OUT ps_out;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float gl_FragDepth;\n"); } break; case HLSL_D3D9: C("struct PS_OUT {\n"); C(" vec4 target : SV_Target0;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float depth : DEPTH;\n"); } C("};\n"); @@ -312,7 +312,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var F(") {\n"); C(" PS_OUT ps_out;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float gl_FragDepth;\n"); } @@ -406,13 +406,13 @@ void ShaderWriter::EndVSMain(Slice varyings) { C("}\n"); } -void ShaderWriter::EndFSMain(const char *vec4_color_variable, FSFlags flags) { +void ShaderWriter::EndFSMain(const char *vec4_color_variable) { _assert_(this->stage_ == ShaderStage::Fragment); switch (lang_.shaderLanguage) { case HLSL_D3D11: case HLSL_D3D9: F(" ps_out.target = %s;\n", vec4_color_variable); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" ps_out.depth = gl_FragDepth;\n"); } C(" return ps_out;\n"); diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index a957362b70..f9160c0491 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -30,15 +30,16 @@ struct VaryingDef { const char *precision; }; -enum FSFlags { - FSFLAG_NONE = 0, - FSFLAG_WRITEDEPTH = 1, +enum class ShaderWriterFlags { + NONE = 0, + FS_WRITE_DEPTH = 1, }; +ENUM_CLASS_BITOPS(ShaderWriterFlags); class ShaderWriter { public: // Extensions are supported for both OpenGL ES and Vulkan (though of course, they're different). - ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice extensions = Slice()) : p_(buffer), lang_(lang), stage_(stage) { + ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice extensions = Slice(), ShaderWriterFlags flags = ShaderWriterFlags::NONE) : p_(buffer), lang_(lang), stage_(stage) { Preamble(extensions); } ShaderWriter(const ShaderWriter &) = delete; @@ -77,6 +78,7 @@ public: void DeclareSamplers(Slice samplers); void ConstFloat(const char *name, float value); + void SetFlags(ShaderWriterFlags flags) { flags_ |= flags; } ShaderWriter &SampleTexture2D(const char *texName, const char *uv); ShaderWriter &SampleTexture2DOffset(const char *texName, const char *uv, int offX, int offY); @@ -85,12 +87,12 @@ public: // Simple shaders with no special tricks. void BeginVSMain(Slice inputs, Slice uniforms, Slice varyings); - void BeginFSMain(Slice uniforms, Slice varyings, FSFlags flags); + void BeginFSMain(Slice uniforms, Slice varyings); void BeginGSMain(Slice varyings, Slice outVaryings); // For simple shaders that output a single color, we can deal with this generically. void EndVSMain(Slice varyings); - void EndFSMain(const char *vec4_color_variable, FSFlags flags); + void EndFSMain(const char *vec4_color_variable); void EndGSMain(); const ShaderLanguageDesc &Lang() const { @@ -116,4 +118,5 @@ private: char *p_; const ShaderLanguageDesc &lang_; const ShaderStage stage_; + ShaderWriterFlags flags_; }; diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 628efc787f..7ff6c8b587 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -349,7 +349,7 @@ void GenerateDepalSmoothed(ShaderWriter &writer, const DepalConfig &config) { void GenerateDepalFs(ShaderWriter &writer, const DepalConfig &config) { writer.DeclareSamplers(samplers); writer.HighPrecisionFloat(); - writer.BeginFSMain(config.bufferFormat == GE_FORMAT_DEPTH16 ? g_draw2Duniforms : Slice::empty(), varyings, FSFLAG_NONE); + writer.BeginFSMain(config.bufferFormat == GE_FORMAT_DEPTH16 ? g_draw2Duniforms : Slice::empty(), varyings); if (config.smoothedDepal) { // Handles a limited set of cases, but doesn't need any integer math so we don't // need two variants. @@ -369,5 +369,5 @@ void GenerateDepalFs(ShaderWriter &writer, const DepalConfig &config) { _assert_msg_(false, "Shader language not supported for depal: %d", (int)writer.Lang().shaderLanguage); } } - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); } diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 05bead52e4..93d542bafb 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -59,9 +59,9 @@ const UniformBufferDesc draw2DUBDesc{ sizeof(Draw2DUB), { Draw2DPipelineInfo GenerateDraw2DCopyColorFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_NONE); + writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_copy_color", @@ -72,13 +72,13 @@ Draw2DPipelineInfo GenerateDraw2DCopyColorFs(ShaderWriter &writer) { Draw2DPipelineInfo GenerateDraw2DCopyColorRect2LinFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); - writer.BeginFSMain(g_draw2Duniforms, varyings, FSFLAG_NONE); + writer.BeginFSMain(g_draw2Duniforms, varyings); writer.C(" vec2 tSize = texSize / scaleFactor;\n"); writer.C(" vec2 pixels = v_texcoord * tSize;\n"); writer.C(" float u = mod(pixels.x, tSize.x);\n"); writer.C(" float v = floor(pixels.x / tSize.x);\n"); writer.C(" vec4 outColor = ").SampleTexture2D("tex", "vec2(u, v) / tSize").C(";\n"); - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_copy_color_rect2lin", @@ -89,10 +89,11 @@ Draw2DPipelineInfo GenerateDraw2DCopyColorRect2LinFs(ShaderWriter &writer) { Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_WRITEDEPTH); + writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); writer.C(" gl_FragDepth = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n"); - writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_copy_depth", @@ -103,7 +104,8 @@ Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) { Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_WRITEDEPTH); + writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); // Unlike when just copying a depth buffer, here we're generating new depth values so we'll // have to apply the scaling. @@ -111,7 +113,7 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { writer.C(" vec3 rgb = ").SampleTexture2D("tex", "v_texcoord.xy").C(".xyz;\n"); writer.F(" highp float depthValue = (floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0); \n"); writer.F(" gl_FragDepth = (depthValue / %f) + %f;\n", factors.scale, factors.offset); - writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_565_to_depth", @@ -122,7 +124,8 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { Draw2DPipelineInfo GenerateDraw2D565ToDepthDeswizzleFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); - writer.BeginFSMain(g_draw2Duniforms, varyings, FSFLAG_WRITEDEPTH); + writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.BeginFSMain(g_draw2Duniforms, varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); // Unlike when just copying a depth buffer, here we're generating new depth values so we'll // have to apply the scaling. @@ -136,7 +139,7 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthDeswizzleFs(ShaderWriter &writer) { writer.C(" vec3 rgb = ").SampleTexture2D("tex", "coord").C(".xyz;\n"); writer.F(" highp float depthValue = (floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0); \n"); writer.F(" gl_FragDepth = (depthValue / %f) + %f;\n", factors.scale, factors.offset); - writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_565_to_depth_deswizzle", diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index fc8a9f9a27..586afdca0f 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -39,16 +39,16 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, std::string *errorString) { - std::vector gl_exts; + std::vector extensions; if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (gl_extensions.EXT_gpu_shader4) { - gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); + extensions.push_back("#extension GL_EXT_gpu_shader4 : enable"); } } bool vertexRangeCulling = !id.Bit(GS_BIT_CURVE); bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP); - ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts); + ShaderWriter p(buffer, compat, ShaderStage::Geometry, extensions); p.C("layout(triangles) in;\n"); if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { p.C("layout(triangle_strip, max_vertices = 12) out;\n"); diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index 09f2552a9b..ea80fa8b3d 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -161,7 +161,7 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf } } - writer.BeginFSMain(g_draw2Duniforms, varyings, FSFLAG_NONE); + writer.BeginFSMain(g_draw2Duniforms, varyings); if (IsBufferFormat16Bit(from) && IsBufferFormat16Bit(to)) { writer.C(" vec4 val = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); @@ -182,7 +182,7 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf writer.C(" vec4 outColor = unpackColor(u == 0.0 ? packColor(val.rg) : packColor(val.ba));\n"); } - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "reinterpret", diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index fd552208f7..c829e40f03 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -94,7 +94,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.C("float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n"); - writer.BeginFSMain(uniforms, varyings, FSFLAG_NONE); + writer.BeginFSMain(uniforms, varyings); writer.C(" vec4 index = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a. @@ -106,7 +106,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.C(" gl_FragDepth = gl_FragCoord.z;\n"); } - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); } // This can probably be shared with some other shaders, like reinterpret or the future depth upload. From e77ff0281fbc3c5c152143bbe282b98e0be1cba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 24 Oct 2022 00:20:45 +0200 Subject: [PATCH 092/715] Testfix --- Common/GPU/ShaderWriter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index f9160c0491..bcfc2f8263 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -118,5 +118,5 @@ private: char *p_; const ShaderLanguageDesc &lang_; const ShaderStage stage_; - ShaderWriterFlags flags_; + ShaderWriterFlags flags_ = ShaderWriterFlags::NONE; }; From 1d8ab38ce55f8b013ed42ca7b7af80cd7a297c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 23 Oct 2022 22:05:33 +0200 Subject: [PATCH 093/715] Vulkan: Use v2 feature checks, and add check for multiview features. Extracted from the multiview PR, and renamed some stuff. --- Common/GPU/Vulkan/VulkanContext.cpp | 41 +++++++++++++++++++++-------- Common/GPU/Vulkan/VulkanContext.h | 9 +++++-- Common/GPU/Vulkan/thin3d_vulkan.cpp | 25 ++++++++++-------- GPU/Vulkan/GPU_Vulkan.cpp | 6 ++--- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 937276d10f..a3bbf1f0ea 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -585,22 +585,32 @@ void VulkanContext::ChooseDevice(int physical_device) { // Optional features if (extensionsLookup_.KHR_get_physical_device_properties2) { VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR}; + // Add to chain even if not supported, GetPhysicalDeviceFeatures is supposed to ignore unknown structs. + VkPhysicalDeviceMultiviewFeatures multiViewFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; + features2.pNext = &multiViewFeatures; vkGetPhysicalDeviceFeatures2KHR(physical_devices_[physical_device_], &features2); - deviceFeatures_.available = features2.features; + deviceFeatures_.available.standard = features2.features; + deviceFeatures_.available.multiview = multiViewFeatures; } else { - vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available); + vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard); + deviceFeatures_.available.multiview = {}; } deviceFeatures_.enabled = {}; // Enable a few safe ones if they are available. - deviceFeatures_.enabled.dualSrcBlend = deviceFeatures_.available.dualSrcBlend; - deviceFeatures_.enabled.logicOp = deviceFeatures_.available.logicOp; - deviceFeatures_.enabled.depthClamp = deviceFeatures_.available.depthClamp; - deviceFeatures_.enabled.depthBounds = deviceFeatures_.available.depthBounds; - deviceFeatures_.enabled.samplerAnisotropy = deviceFeatures_.available.samplerAnisotropy; - deviceFeatures_.enabled.shaderClipDistance = deviceFeatures_.available.shaderClipDistance; - deviceFeatures_.enabled.shaderCullDistance = deviceFeatures_.available.shaderCullDistance; - deviceFeatures_.enabled.geometryShader = deviceFeatures_.available.geometryShader; + deviceFeatures_.enabled.standard.dualSrcBlend = deviceFeatures_.available.standard.dualSrcBlend; + deviceFeatures_.enabled.standard.logicOp = deviceFeatures_.available.standard.logicOp; + deviceFeatures_.enabled.standard.depthClamp = deviceFeatures_.available.standard.depthClamp; + deviceFeatures_.enabled.standard.depthBounds = deviceFeatures_.available.standard.depthBounds; + deviceFeatures_.enabled.standard.samplerAnisotropy = deviceFeatures_.available.standard.samplerAnisotropy; + deviceFeatures_.enabled.standard.shaderClipDistance = deviceFeatures_.available.standard.shaderClipDistance; + deviceFeatures_.enabled.standard.shaderCullDistance = deviceFeatures_.available.standard.shaderCullDistance; + deviceFeatures_.enabled.standard.geometryShader = deviceFeatures_.available.standard.geometryShader; + + deviceFeatures_.enabled.multiview = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; + // Don't yet enable these. + // deviceFeatures_.enabled.multiview.multiview = deviceFeatures_.available.multiview.multiview; + // deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader; GetDeviceLayerExtensionList(nullptr, device_extension_properties_); @@ -671,6 +681,8 @@ VkResult VulkanContext::CreateDevice() { extensionsLookup_.EXT_fragment_shader_interlock = EnableDeviceExtension(VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME); extensionsLookup_.ARM_rasterization_order_attachment_access = EnableDeviceExtension(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME); + VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; device_info.queueCreateInfoCount = 1; device_info.pQueueCreateInfos = &queue_info; @@ -678,7 +690,14 @@ VkResult VulkanContext::CreateDevice() { device_info.ppEnabledLayerNames = device_info.enabledLayerCount ? device_layer_names_.data() : nullptr; device_info.enabledExtensionCount = (uint32_t)device_extensions_enabled_.size(); device_info.ppEnabledExtensionNames = device_info.enabledExtensionCount ? device_extensions_enabled_.data() : nullptr; - device_info.pEnabledFeatures = &deviceFeatures_.enabled; + + if (extensionsLookup_.KHR_get_physical_device_properties2) { + device_info.pNext = &features2; + features2.features = deviceFeatures_.enabled.standard; + features2.pNext = &deviceFeatures_.enabled.multiview; + } else { + device_info.pEnabledFeatures = &deviceFeatures_.enabled.standard; + } VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_); if (res != VK_SUCCESS) { diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index fb98b5a0db..60ef6d373e 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -252,6 +252,11 @@ public: VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProperties; }; + struct AllPhysicalDeviceFeatures { + VkPhysicalDeviceFeatures standard; + VkPhysicalDeviceMultiviewFeatures multiview; + }; + const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const { if (i < 0) i = GetCurrentPhysicalDeviceIndex(); @@ -276,8 +281,8 @@ public: } struct PhysicalDeviceFeatures { - VkPhysicalDeviceFeatures available{}; - VkPhysicalDeviceFeatures enabled{}; + AllPhysicalDeviceFeatures available{}; + AllPhysicalDeviceFeatures enabled{}; }; const PhysicalDeviceFeatures &GetDeviceFeatures() const { return deviceFeatures_; } diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index adfe90d14c..cedb21b49f 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -777,14 +777,14 @@ VKContext::VKContext(VulkanContext *vulkan) VkFormat depthStencilFormat = vulkan->GetDeviceInfo().preferredDepthStencilFormat; - caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.samplerAnisotropy != 0; - caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.geometryShader != 0; - caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.tessellationShader != 0; - caps_.multiViewport = vulkan->GetDeviceFeatures().enabled.multiViewport != 0; - caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.dualSrcBlend != 0; - caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.depthClamp != 0; - caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.shaderClipDistance != 0; - caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.shaderCullDistance != 0; + caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.standard.samplerAnisotropy != 0; + caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.geometryShader != 0; + caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.tessellationShader != 0; + caps_.multiViewport = vulkan->GetDeviceFeatures().enabled.standard.multiViewport != 0; + caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.standard.dualSrcBlend != 0; + caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.standard.depthClamp != 0; + caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderClipDistance != 0; + caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderCullDistance != 0; caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat; @@ -798,7 +798,7 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.textureNPOTFullySupported = true; caps_.fragmentShaderDepthWriteSupported = true; caps_.blendMinMaxSupported = true; - caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.logicOp != 0; + caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0; auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties; @@ -1414,8 +1414,8 @@ void AddFeature(std::vector &features, const char *name, VkBool32 a } std::vector VKContext::GetFeatureList() const { - const VkPhysicalDeviceFeatures &available = vulkan_->GetDeviceFeatures().available; - const VkPhysicalDeviceFeatures &enabled = vulkan_->GetDeviceFeatures().enabled; + const VkPhysicalDeviceFeatures &available = vulkan_->GetDeviceFeatures().available.standard; + const VkPhysicalDeviceFeatures &enabled = vulkan_->GetDeviceFeatures().enabled.standard; std::vector features; AddFeature(features, "dualSrcBlend", available.dualSrcBlend, enabled.dualSrcBlend); @@ -1434,6 +1434,9 @@ std::vector VKContext::GetFeatureList() const { AddFeature(features, "occlusionQueryPrecise", available.occlusionQueryPrecise, enabled.occlusionQueryPrecise); AddFeature(features, "multiDrawIndirect", available.multiDrawIndirect, enabled.multiDrawIndirect); + AddFeature(features, "multiview", vulkan_->GetDeviceFeatures().available.multiview.multiview, vulkan_->GetDeviceFeatures().enabled.multiview.multiview); + AddFeature(features, "multiviewGeometryShader", vulkan_->GetDeviceFeatures().available.multiview.multiviewGeometryShader, vulkan_->GetDeviceFeatures().enabled.multiview.multiviewGeometryShader); + features.emplace_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat)); return features; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index fbc31a90e3..c46b8b2812 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -227,7 +227,7 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { features |= GPU_USE_VERTEX_TEXTURE_FETCH; features |= GPU_USE_TEXTURE_FLOAT; - auto &enabledFeatures = vulkan->GetDeviceFeatures().enabled; + auto &enabledFeatures = vulkan->GetDeviceFeatures().enabled.standard; if (enabledFeatures.depthClamp) { features |= GPU_USE_DEPTH_CLAMP; } @@ -325,9 +325,9 @@ void GPU_Vulkan::EndHostFrame() { void GPU_Vulkan::BuildReportingInfo() { VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); const auto &props = vulkan->GetPhysicalDeviceProperties().properties; - const auto &features = vulkan->GetDeviceFeatures().available; + const auto &available = vulkan->GetDeviceFeatures().available; -#define CHECK_BOOL_FEATURE(n) do { if (features.n) { featureNames += ", " #n; } } while (false) +#define CHECK_BOOL_FEATURE(n) do { if (available.standard.n) { featureNames += ", " #n; } } while (false) std::string featureNames = ""; CHECK_BOOL_FEATURE(robustBufferAccess); From 7533b649406ab34a4b5911abeeff48344a8bc865 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Oct 2022 22:01:50 -0700 Subject: [PATCH 094/715] GE Debugger: Allow reading tex on D3D11. --- GPU/D3D11/TextureCacheD3D11.cpp | 34 ++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 83c2c4869c..486ad9417f 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -470,8 +470,31 @@ bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level D3D11_TEXTURE2D_DESC desc; texture->GetDesc(&desc); - if (desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM) { - // TODO: Support the other formats + int width = desc.Width >> level; + int height = desc.Height >> level; + + switch (desc.Format) { + case DXGI_FORMAT_B8G8R8A8_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_8888); + break; + + case DXGI_FORMAT_B5G6R5_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_565); + break; + + case DXGI_FORMAT_B4G4R4A4_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_4444); + break; + + case DXGI_FORMAT_B5G5R5A1_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_5551); + break; + + case DXGI_FORMAT_R8_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_8BIT); + break; + + default: return false; } @@ -483,18 +506,15 @@ bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level device_->CreateTexture2D(&desc, nullptr, &stagingCopy); context_->CopyResource(stagingCopy, texture); - int width = desc.Width >> level; - int height = desc.Height >> level; - buffer.Allocate(width, height, GPU_DBG_FORMAT_8888); - D3D11_MAPPED_SUBRESOURCE map; if (FAILED(context_->Map(stagingCopy, level, D3D11_MAP_READ, 0, &map))) { stagingCopy->Release(); return false; } + int bufferRowSize = buffer.PixelSize() * width; for (int y = 0; y < height; y++) { - memcpy(buffer.GetData() + 4 * width * y, (const uint8_t *)map.pData + map.RowPitch * y, 4 * width); + memcpy(buffer.GetData() + bufferRowSize * y, (const uint8_t *)map.pData + map.RowPitch * y, bufferRowSize); } context_->Unmap(stagingCopy, level); From 80e1db07a7b388edb7ecf21267e25c3d87326e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 24 Oct 2022 17:41:41 +0200 Subject: [PATCH 095/715] Minor ShaderWriter refactor, prep for later changes --- Common/GPU/Shader.h | 1 + Common/GPU/ShaderWriter.cpp | 28 +++++++++++++++++--------- Common/GPU/ShaderWriter.h | 9 +++++++-- GPU/Common/DepalettizeShaderCommon.cpp | 4 ++-- GPU/Common/Draw2D.cpp | 2 +- GPU/Common/ReinterpretFramebuffer.cpp | 2 +- GPU/Common/StencilCommon.cpp | 2 +- GPU/Common/TextureShaderCommon.cpp | 4 ++-- 8 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 75e1a9b2e9..4020a7b253 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -92,6 +92,7 @@ struct UniformDef { }; struct SamplerDef { + int binding; // Might only be used by some backends. const char *name; // TODO: Might need unsigned samplers, 3d samplers, or other types in the future. }; diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 5399c6241a..e00a468e35 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -456,34 +456,35 @@ void ShaderWriter::ConstFloat(const char *name, float value) { void ShaderWriter::DeclareSamplers(Slice samplers) { for (int i = 0; i < (int)samplers.size(); i++) { - DeclareTexture2D(samplers[i].name, i); - DeclareSampler2D(samplers[i].name, i); + DeclareTexture2D(samplers[i]); + DeclareSampler2D(samplers[i]); } + samplerDefs_ = samplers; } -void ShaderWriter::DeclareTexture2D(const char *name, int binding) { +void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { switch (lang_.shaderLanguage) { case HLSL_D3D11: - F("Texture2D %s : register(t%d);\n", name, binding); + F("Texture2D %s : register(t%d);\n", def.name, def.binding); break; case HLSL_D3D9: - F("sampler %s: register(s%d);\n", name, binding); + F("sampler %s: register(s%d);\n", def.name, def.binding); break; case GLSL_VULKAN: // In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1. - F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", binding + 1, name); + F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); break; default: - F("uniform sampler2D %s;\n", name); + F("uniform sampler2D %s;\n", def.name); break; } } -void ShaderWriter::DeclareSampler2D(const char *name, int binding) { +void ShaderWriter::DeclareSampler2D(const SamplerDef &def) { // We only use separate samplers in HLSL D3D11, where we have no choice. switch (lang_.shaderLanguage) { case HLSL_D3D11: - F("SamplerState %sSamp : register(s%d);\n", name, binding); + F("SamplerState %sSamp : register(s%d);\n", def.name, def.binding); break; default: break; @@ -555,3 +556,12 @@ ShaderWriter &ShaderWriter::GetTextureSize(const char *szVariable, const char *t } return *this; } + +const SamplerDef *ShaderWriter::GetSamplerDef(const char *name) const { + for (int i = 0; i < (int)samplerDefs_.size(); i++) { + if (!strcmp(samplerDefs_[i].name, name)) { + return &samplerDefs_[i]; + } + } + return nullptr; +} diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index bcfc2f8263..6eb42719f0 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -75,10 +75,12 @@ public: void HighPrecisionFloat(); void LowPrecisionFloat(); + // NOTE: samplers must live for the rest of ShaderWriter's lifetime. No way to express that in C++ though :( void DeclareSamplers(Slice samplers); void ConstFloat(const char *name, float value); void SetFlags(ShaderWriterFlags flags) { flags_ |= flags; } + void SetTexBindingBase(int base) { texBindingBase_ = base; } ShaderWriter &SampleTexture2D(const char *texName, const char *uv); ShaderWriter &SampleTexture2DOffset(const char *texName, const char *uv, int offX, int offY); @@ -110,8 +112,9 @@ public: private: // Several of the shader languages ignore samplers, beware of that. - void DeclareSampler2D(const char *name, int binding); - void DeclareTexture2D(const char *name, int binding); + void DeclareSampler2D(const SamplerDef &def); + void DeclareTexture2D(const SamplerDef &def); + const SamplerDef *GetSamplerDef(const char *name) const; void Preamble(Slice extensions); @@ -119,4 +122,6 @@ private: const ShaderLanguageDesc &lang_; const ShaderStage stage_; ShaderWriterFlags flags_ = ShaderWriterFlags::NONE; + Slice samplerDefs_; + int texBindingBase_ = 1; }; diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 7ff6c8b587..a784d22377 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -35,8 +35,8 @@ static const InputDef vsInputs[2] = { // TODO: Deduplicate with TextureShaderCommon.cpp static const SamplerDef samplers[2] = { - { "tex" }, - { "pal" }, + { 0, "tex" }, + { 1, "pal" }, }; static const VaryingDef varyings[1] = { diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 93d542bafb..9b342e05bc 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -37,7 +37,7 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { "tex" }, + { 0, "tex" }, }; const UniformDef g_draw2Duniforms[2] = { diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index ea80fa8b3d..b14e324d0d 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -14,7 +14,7 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { "tex" } + { 0, "tex" } }; // Requires full size integer math. It would be possible to make a floating point-only version with lots of diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index c829e40f03..682d8a1f0c 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -80,7 +80,7 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { "tex" }, + { 0, "tex" }, }; void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { diff --git a/GPU/Common/TextureShaderCommon.cpp b/GPU/Common/TextureShaderCommon.cpp index 2860389fc2..5919d5442e 100644 --- a/GPU/Common/TextureShaderCommon.cpp +++ b/GPU/Common/TextureShaderCommon.cpp @@ -34,8 +34,8 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[2] = { - { "tex" }, - { "pal" }, + { 0, "tex" }, + { 1, "pal" }, }; TextureShaderCache::TextureShaderCache(Draw::DrawContext *draw, Draw2D *draw2D) : draw_(draw), draw2D_(draw2D) { } From 1e1c75d5520606ce8f67979519f1a5b51e90d058 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 25 Oct 2022 22:14:16 -0700 Subject: [PATCH 096/715] GE Debugger: Correct UV display with prescale. Sometimes these weren't flushed yet, and it made the texture preview and vertices confusing and wrong (using old factors, not just no factors.) --- GPU/GPUCommon.cpp | 1 + GPU/Software/SoftGpu.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index c80aab881c..b8c80a76ed 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3204,6 +3204,7 @@ std::vector GPUCommon::GetFramebufferList() const { } bool GPUCommon::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { + UpdateUVScaleOffset(); return drawEngineCommon_->GetCurrentSimpleVertices(count, vertices, indices); } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index ba6da9455c..04e3c1d5c7 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -1423,8 +1423,8 @@ bool SoftGPU::GetCurrentClut(GPUDebugBuffer &buffer) return true; } -bool SoftGPU::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) -{ +bool SoftGPU::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { + UpdateUVScaleOffset(); return drawEngine_->transformUnit.GetCurrentSimpleVertices(count, vertices, indices); } From deba3d40bc01563d88670b1b06ee7dc095a25fc4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 25 Oct 2022 22:15:47 -0700 Subject: [PATCH 097/715] headless: Update tests. --- pspautotests | 2 +- test.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pspautotests b/pspautotests index d40a8e05c3..1790e574bd 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit d40a8e05c3892bd67af71c6f80ea4396f8051541 +Subproject commit 1790e574bd069c7e4883bf097db46094526b0dc9 diff --git a/test.py b/test.py index 7b76dbca07..b9cf9260ca 100755 --- a/test.py +++ b/test.py @@ -192,6 +192,7 @@ tests_good = [ "gpu/textures/mipmap", "gpu/textures/rotate", "gpu/vertices/colors", + "gpu/vertices/morph", "gpu/vertices/texcoords", "hash/hash", "hle/check_not_used_uids", From e7eddab2a1f72639d7d44fbbea51b2351420437b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 26 Oct 2022 00:18:14 -0700 Subject: [PATCH 098/715] Build: Update deprecated actions. There are some deprecations coming and some actions might stop working. It seems softprops/action-gh-release@v1 is not being actively maintained, and isn't updated here. --- .github/workflows/build.yml | 36 +++++++++-------------- .github/workflows/generateDockerLayer.yml | 8 ++--- .github/workflows/manual_generate_apk.yml | 7 +++-- .github/workflows/tarball.yml | 4 +-- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cc776d30a0..06392a23f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,12 +34,12 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1 + uses: microsoft/setup-msbuild@v1.1 - name: Build Windows working-directory: ${{ env.GITHUB_WORKSPACE }} @@ -63,7 +63,7 @@ jobs: run: cp Windows/Release/*.exe ppsspp/ - name: Upload build - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 with: name: Windows ${{ matrix.platform }} build path: ppsspp/ @@ -71,12 +71,12 @@ jobs: build-uwp: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1 + uses: microsoft/setup-msbuild@v1.1 - name: Build UWP working-directory: ${{ env.GITHUB_WORKSPACE }} @@ -87,7 +87,7 @@ jobs: needs: build-windows timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: false @@ -97,7 +97,7 @@ jobs: run: git submodule update --init pspautotests assets/lang - name: Download build - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: Windows x64 build path: ppsspp/ @@ -192,7 +192,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive @@ -202,19 +202,11 @@ jobs: run: | git fetch --deepen=15000 --no-recurse-submodules --tags || exit 0 - - name: Cache Qt - uses: actions/cache@v1 - if: matrix.extra == 'qt' - id: cache-qt - with: - path: ${{ runner.workspace }}/Qt - key: ${{ runner.os }}-QtCache - - name: Install Qt - uses: jurplel/install-qt-action@v2 + uses: jurplel/install-qt-action@v3 if: matrix.extra == 'qt' with: - cached: ${{ steps.cache-qt.outputs.cache-hit }} + cache: true - uses: nttld/setup-ndk@v1 if: matrix.extra == 'android' @@ -236,7 +228,7 @@ jobs: echo "#define PPSSPP_GIT_VERSION_NO_UPDATE 1" >> git-version.cpp - name: Setup ccache - uses: hendrikmuhs/ccache-action@v1 + uses: hendrikmuhs/ccache-action@v1.2 with: key: ${{ matrix.id }} @@ -279,7 +271,7 @@ jobs: fi - name: Upload build - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 if: matrix.extra == 'test' with: name: ${{ matrix.os }} build @@ -313,7 +305,7 @@ jobs: needs: build timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: false @@ -335,7 +327,7 @@ jobs: git submodule update --init SDL/macOS - name: Download build - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: ${{ matrix.os }} build path: ppsspp/ diff --git a/.github/workflows/generateDockerLayer.yml b/.github/workflows/generateDockerLayer.yml index 91164f5af8..5e038f398f 100644 --- a/.github/workflows/generateDockerLayer.yml +++ b/.github/workflows/generateDockerLayer.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Extract DOCKER_TAG using tag name if: startsWith(github.ref, 'refs/tags/') @@ -25,13 +25,13 @@ jobs: echo "DOCKER_TAG=latest" >> $GITHUB_ENV - name: Login to Github registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io - - uses: docker/build-push-action@v2 + - uses: docker/build-push-action@v3 with: push: true - tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_TAG }} \ No newline at end of file + tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_TAG }} diff --git a/.github/workflows/manual_generate_apk.yml b/.github/workflows/manual_generate_apk.yml index 3f38055ac5..4c48320259 100644 --- a/.github/workflows/manual_generate_apk.yml +++ b/.github/workflows/manual_generate_apk.yml @@ -19,14 +19,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 submodules: recursive - name: Setup JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: + distribution: 'zulu' java-version: '11' #- name: Setup SDK @@ -54,7 +55,7 @@ jobs: fi - name: Upload APK - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 with: name: android-${{ github.event.inputs.buildVariant }} build path: ppsspp/ diff --git a/.github/workflows/tarball.yml b/.github/workflows/tarball.yml index 47c022593e..84fec3625a 100644 --- a/.github/workflows/tarball.yml +++ b/.github/workflows/tarball.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive @@ -40,7 +40,7 @@ jobs: sed -i "s;unknown;${VERSION};" $PKGNAME/git-version.cmake || true TARBALL=$PKGNAME.tar.xz tar cJf $TARBALL $PKGNAME - echo "::set-output name=tarball::$TARBALL" + echo "tarball=$TARBALL" >> $GITHUB_OUTPUT - name: upload tarball uses: softprops/action-gh-release@v1 From d3e99fa3089bd026583b1b5b5b97b9d2eb21b45b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 26 Oct 2022 00:21:55 -0700 Subject: [PATCH 099/715] Build: Fix Android/macOS ccache. --- .github/workflows/build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 06392a23f9..778b601445 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -238,8 +238,20 @@ jobs: CXX: ${{ matrix.cxx }} NDK: ${{ steps.setup-ndk.outputs.ndk-path }} NDK_CCACHE: ccache + USE_CCACHE: 1 run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + export CCACHE_SLOPPINESS=clang_index_store,ivfsoverlay,include_file_ctime,include_file_mtime,modules,system_headers,time_macros + if [ "${{ matrix.extra }}" == "android" ]; then + export CCACHE_FILECLONE=true + export CCACHE_DEPEND=true + export CCACHE_COMPILERCHECK=content + elif [ "$RUNNER_OS" == "macOS" ]; then + export CCACHE_SLOPPINESS=pch_defines,$CCACHE_SLOPPINESS + export CCACHE_FILECLONE=true + export CCACHE_DEPEND=true + export CCACHE_COMPILERCHECK=content + fi ${{ matrix.args }} - name: Package build From 5ad27d07697991ff0ac7c71926b2692e8435b196 Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 26 Oct 2022 21:23:40 +0200 Subject: [PATCH 100/715] OpenXR - 6DoF and stereo in Lego Star Wars II fixed --- assets/compatvr.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/compatvr.ini b/assets/compatvr.ini index 92cf0d32d1..30fa562230 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -874,8 +874,8 @@ ULES01370 = 47.0 ULUS10487 = 47.0 # LEGO Star Wars II: The Original Trilogy -ULES00479 = 47.0 -ULUS10155 = 47.0 +ULES00479 = 1.0 +ULUS10155 = 1.0 # Lemmings NPJG00058 = 5.0 From b632b48724830a838a8b0ea823abfd0c451b9dca Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 26 Oct 2022 21:42:58 +0200 Subject: [PATCH 101/715] OpenXR - Lego Star Wars III stereo support added --- assets/compatvr.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/compatvr.ini b/assets/compatvr.ini index 30fa562230..7bfc3e5c94 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -877,6 +877,10 @@ ULUS10487 = 47.0 ULES00479 = 1.0 ULUS10155 = 1.0 +# LEGO Star Wars III: The Clone Wars +ULES01446 = 3.0 +ULUS10531 = 3.0 + # Lemmings NPJG00058 = 5.0 UCAS40076 = 5.0 From d011c02fee27c8cc61b1e836cf2bb300fee08861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Thu, 27 Oct 2022 15:26:11 +0800 Subject: [PATCH 102/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 1872 ++++++++++++++++++++--------------------- 1 file changed, 929 insertions(+), 943 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 6f57d92d16..4a7b474d9c 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -1,1207 +1,1195 @@ [Audio] -Alternate speed volume = 自定義速度下的音量 -Audio backend = 音訊引擎(需要重新啟動) +Alternate speed volume = 替代速度音量 +Audio backend = 音訊後端 (需要重新啟動) Audio Error = 音訊錯誤 -AudioBufferingForBluetooth = 藍牙友好緩衝區(較慢) +AudioBufferingForBluetooth = 藍牙友好緩衝區 (更慢) Auto = 自動 -Device = 設備 -Disabled = Disabled -DSound (compatible) = DirectSound(兼容) +Device = 裝置 +Disabled = 已停用 +DSound (compatible) = DSound (相容) Enable Sound = 啟用音效 -Global volume = 全局音量 -Microphone = Microphone +Global volume = 全域音量 +Microphone = 麥克風 Microphone Device = 麥克風裝置 Mute = 靜音 -Reverb volume = 混響音量 -Use new audio devices automatically = 自動開啟新的音頻設備 -Use global volume = 使用全局量 -WASAPI (fast) = WASAPI(快) +Reverb volume = 混響裝置音量 +Use new audio devices automatically = 自動使用新音訊裝置 +Use global volume = 使用全域音量 +WASAPI (fast) = WASAPI (快) [Controls] -Analog Binding = 搖桿綁定 -Analog Settings = 搖桿配置 -Analog Style = 搖桿樣式 -Auto-rotation speed = 模擬自動轉速 -Analog Limiter = 搖桿限制器 +Analog Binding = 類比繫結 +Analog Limiter = 類比限制器 +Analog Settings = 類比設定 Analog Stick = 類比搖桿 -AnalogLimiter Tip = 按下模擬限制器按鈕時 +Analog Style = 類比樣式 +AnalogLimiter Tip = 類比限制器按鈕被按下時 Auto = 自動 -Auto-centering analog stick = 自動定心搖桿 +Auto-centering analog stick = 自動置中類比搖桿 Auto-hide buttons after seconds = 數秒後自動隱藏按鈕 -Auto-switch = 自動轉換 -Base tilt position = 標準體感位置 -Binds = 綁定 -Button Binding = 按鈕綁定 -Button Opacity = 按鈕透明度 +Auto-rotation speed = 自動旋轉速度 +Auto-switch = 自動切換 +Base tilt position = 基準傾斜位置 +Binds = 繫結 +Button Binding = 按鈕繫結 +Button Opacity = 按鈕不透明度 Button style = 按鈕樣式 -Calibrate Analog Stick = 校準搖桿 -Calibrate D-Pad = 校正方向鍵 -Calibrated = 校正後 +Calibrate Analog Stick = 校正類比搖桿 +Calibrate D-Pad = 校正 +Calibrated = 已校正 Calibration = 校正 -Circular stick input = 環形搖桿錄入 +Circular stick input = 圓形搖桿輸入 Classic = 傳統 -Confine Mouse = 在窗口/顯示區域內捕獲鼠標 -Control Mapping = 按鍵對應 -Custom Key Setting = 自訂鍵位配置 +Confine Mouse = 在視窗/顯示區域內截獲滑鼠 +Control Mapping = 控制對應 +Custom Key Setting = 自訂按鍵設定 Customize = 自訂 -Customize Touch Controls = 自訂佈局 -Customize tilt = 自訂傾斜 +Customize Touch Controls = 編輯觸控控制版面配置… +Customize tilt = 自訂傾斜… D-PAD = 方向鍵 Deadzone radius = 死區半徑 -Disable D-Pad diagonals (4-way touch) = 停用方向鍵對角線(四方向觸控) -Disable diagonal input = 停用對角線錄入 -Double tap = 雙擊 -Enable gesture control = 開啓體感控制 -Enable standard shortcut keys = 開啓標準熱鍵 -Gesture = 體感 -Gesture mapping = 體感映射 -Glowing borders = 細邊框 -HapticFeedback = 按鍵反饋(震動) -Hide touch analog stick background circle = 隱藏觸屏搖桿背景圈 -Icon = 圖標 -Ignore gamepads when not focused = 非作用時忽略遊戲手把 -Ignore Windows Key = 忽略Windows鍵 -Invert Axes = 軸反轉 -Invert Tilt along X axis = 沿X軸傾斜反轉 -Invert Tilt along Y axis = 沿Y軸傾斜反轉 -Keep this button pressed when right analog is pressed = 點擊右模擬鍵時保持點擊此按鈕 +Disable D-Pad diagonals (4-way touch) = 停用方向鍵對角線 (4 向觸控) +Disable diagonal input = 停用對角線輸入 +Double tap = 點兩下 +Enable gesture control = 啟用手勢控制 +Enable standard shortcut keys = 啟用標準快速鍵 +Gesture = 手勢 +Gesture mapping = 手勢對應 +Glowing borders = 發光框線 +HapticFeedback = 觸覺回饋 (震動) +Hide touch analog stick background circle = 隱藏觸控式類比搖桿背景圓環 +Icon = 圖示 +Ignore gamepads when not focused = 未聚焦時忽略手把 +Ignore Windows Key = 停用 Windows 按鍵 +Invert Axes = 反轉軸 +Invert Tilt along X axis = 沿 X 軸反轉傾斜 +Invert Tilt along Y axis = 沿 Y 軸反轉傾斜 +Keep this button pressed when right analog is pressed = 右類比搖桿被按下時保持此按鈕按下 Keyboard = 鍵盤控制設定 -L/R Trigger Buttons = L/R觸發按鈕 -#L/R扳机按钮 +L/R Trigger Buttons = L/R 觸發按鈕 Landscape = 橫向 -Landscape Auto = 自動橫向 +Landscape Auto = 橫向自動 Landscape Reversed = 橫向反轉 -Low end radius = 尾端半徑 -Mouse = 鼠標配置 -Mouse sensitivity = 鼠標靈敏度 -Mouse smoothing = 鼠標平滑 -MouseControl Tip = 您現在可以在按鍵映射界面上按“ M”圖標來映射鼠標按鍵。 -None (Disabled) = 無(停用) +Low end radius = 低端半徑 +Mouse = 滑鼠設定 +Mouse sensitivity = 滑鼠敏感度 +Mouse smoothing = 滑鼠平滑 +MouseControl Tip = 您現在可以透過按下「M」圖示在控制對應畫面中對應滑鼠。 +None (Disabled) = 無 (已停用) Off = 關閉 -OnScreen = 顯示虛擬控制器 -Portrait = 縱向 -Portrait Reversed = 縱向反轉 -PSP Action Buttons = PSP功能鍵 -Raw input = 原始錄入 -Repeat mode = Repeat mode -#重复模式 -Reset to defaults = 重置爲默認 -Screen aligned to ground = 屏幕水平地面 -Screen at right angle to ground = 屏幕垂直地面 +OnScreen = 螢幕觸控控制 +Portrait = 直向 +Portrait Reversed = 直向反轉 +PSP Action Buttons = PSP 動作按鈕 +Raw input = 原始輸入 +Reset to defaults = 重設為預設值 +Screen aligned to ground = 螢幕與地面水平對齊 +Screen at right angle to ground = 螢幕與地面垂直對齊 Screen Rotation = 螢幕旋轉 seconds, 0 : off = 秒,0 = 關閉 -Sensitivity (scale) = 靈敏度(倍數) -Sensitivity = 靈敏度 -Shape = 形狀 -Show Touch Pause Menu Button = 顯示觸控暫停選單鍵 +Sensitivity = 敏感度 +Sensitivity (scale) = 敏感度 (比例) +Shape = 圖形 +Show Touch Pause Menu Button = 顯示暫停選單按鈕 Swipe = 滑動 -Swipe sensitivity = 滑動靈敏性 -Swipe smoothing = 滑動光滑度 -Thin borders = 薄邊框 -Tilt Base Radius = 傾斜基本半徑 +Swipe sensitivity = 滑動敏感度 +Swipe smoothing = 滑動平滑 +Thin borders = 特細框線 +Tilt Base Radius = 傾斜基準半徑 Tilt Input Type = 傾斜輸入類型 -Tilt Sensitivity along X axis = 沿X軸傾斜靈敏度 -Tilt Sensitivity along Y axis = 沿Y軸傾斜靈敏度 -To Calibrate = 請將裝置放在平面上,然後按「校正」。 +Tilt Sensitivity along X axis = 沿 X 軸傾斜敏感度 +Tilt Sensitivity along Y axis = 沿 Y 軸傾斜敏感度 +To Calibrate = 若要校正,把裝置放置水平表面,然後按下「校正」。 Toggle mode = 切換模式 -Touch Control Visibility = 觸控可視性 -Use custom right analog = 使用自定義右模擬 -Use Mouse Control = 使用鼠標控制 -Visibility = 可視設定 -Visible = 可視 +Repeat mode = 重複模式 +Touch Control Visibility = 觸控控制可見性 +Use custom right analog = 使用自訂右類比搖桿 +Use Mouse Control = 使用滑鼠控制 +Visibility = 可見性 +Visible = 可見 X = X Y = Y [CwCheats] -Cheats = 金手指 -Edit Cheat File = 編輯金手指文件 -Enable/Disable All = 全部啟用/停用 -Import Cheats = 由cheat.db匯入 +Cheats = 密技 +Edit Cheat File = 編輯密技檔案 +Enable/Disable All = 啟用/停用所有密技 +Import Cheats = 從 cheat.db 匯入 Options = 選項 -Refresh Rate = 刷新率 +Refresh Rate = 重新整理速率 [DesktopUI] # If your language does not show well with the default font, you can use Font to specify a different one. # Just add it to your language's ini file and uncomment it (remove the # by Font). -Auto Max Quality = 自動最高質量 (&Q) Font = Microsoft JhengHei -About PPSSPP... = 關於PPSSPP (&A)... +About PPSSPP... = 關於 PPSSPP (&A)… Auto = 自動 (&A) -Backend = 繪圖引擎(需要重新啟動) (&b) +Auto Max Quality = 自動最高品質 (&Q) +Backend = 轉譯後端 (需要重新啟動) (&b) Bicubic = 雙立方 (&B) -Break = 停止 -Break on Load = 載入后停止 -Buffered Rendering = 緩衝渲染 (&B) +Break = 中斷 +Break on Load = 載入時中斷 +Buffered Rendering = 緩衝轉譯 (&B) Buy Gold = 購買黃金版 (&G) -Control Mapping... = 按鍵對應 (&O)... -Debugging = 除錯 (&D) +Control Mapping... = 控制對應 (&O)… +Debugging = 偵錯 (&D) Deposterize = 色調混合 (&D) Direct3D9 = Direct3D 9 (&9) Direct3D11 = Direct3D 11 (&11) -Disassembly = 反組譯 (&D) +Disassembly = 反組譯碼 (&D)… Discord = Discord -Display Layout Editor = 自訂版面 -Display Rotation = 旋轉畫面 -Dump Next Frame to Log = 轉儲下一幀到除錯日誌 -Emulation = 模擬 (&E) -Enable Cheats = 啓用金手指 (&C) -Enable Sound = 開啟聲音 (&O) +Display Layout Editor = 顯示版面配置編輯器… +Display Rotation = 顯示旋轉 +Dump Next Frame to Log = 傾印下一影格至記錄 (&U) +Emulation = 仿真 (&E) +Enable Cheats = 啟用密技 (&C) +Enable Sound = 啟用音效 (&O) Exit = 離開 (&X) -Extract File... = 提取檔案 (&F)... +Extract File... = 擷取檔案 (&X)… File = 檔案 (&F) -Frame Skipping = 跳幀 (&F) -Frame Skipping Type = 跳幀類型 +Frame Skipping = 影格跳過 (&F) +Frame Skipping Type = 影格跳過類型 Fullscreen = 全螢幕 (&L) Game Settings = 遊戲設定 (&G) -GE Debugger... = GE 除錯器 (&R) +GE Debugger... = GE 偵錯工具 (&R)… GitHub = Git&Hub -Hardware Transform = 硬體幾何轉換 (&H) -Help = 幫助 (&H) +Hardware Transform = 硬體轉換 (&H) +Help = 說明 (&H) Hybrid = 混合 (&H) -Hybrid + Bicubic = 混合+雙立方 (&Y) +Hybrid + Bicubic = 混合 + 雙立方 (&Y) Ignore Illegal Reads/Writes = 忽略非法存取 (&I) -Ignore Windows Key = 忽略Windows鍵 -Keep PPSSPP On Top = 保持PPSSPP視窗在最上層 (&K) -Landscape = 横向 +Ignore Windows Key = 忽略 Windows 按鍵 +Keep PPSSPP On Top = 保持 PPSSPP 視窗在最上層 (&K) +Landscape = 橫向 Landscape reversed = 橫向反轉 -Language... = 語言設定 (&a) +Language... = 語言 (&N)… Linear = 線性 (&L) -Load = 載入遊戲 (&L) -Load .sym File... = 載入.sym檔案 (&A)... -Load Map File... = 載入Map檔案(&M)... -Load State = 載入即時存檔 (&O) -Load State File... = 載入即時存檔檔案 (&L)... -Log Console = 控制台日誌 (&L) -Memory View... = 查看記憶體 (&M)... -More Settings... = 更多設定 (&M) -Nearest = 臨近取樣 (&N) -Non-Buffered Rendering = 跳過緩衝效果 (不緩衝,速度更快) (&S) +Load = 載入 (&L)… +Load .sym File... = 載入 .sym 檔案 (&A)… +Load Map File... = 載入對應檔案 (&M)… +Load State = 載入存檔 (&O) +Load State File... = 載入存檔檔案 (&L)… +Log Console = 記錄主控台 (&L) +Memory View... = 記憶體檢視 (&V)… +More Settings... = 更多設定 (&M)… +Nearest = 鄰近取樣 (&N) +Non-Buffered Rendering = 跳過緩衝區效果 (非緩衝區,更快) (&S) Off = 關閉 (&O) -Open Chat = 打開聊天 -Open Directory... = 打開目錄 (&D)... -Open from MS:/PSP/GAME... = 打開 MS:/PSP/GAME (&P)... -#从MS:/PSP/GAME处打开 (&p)... -Open Memory Stick = 打開記憶卡 (&M) -Open New Instance = 打開新實例 +Open Chat = 開啟聊天 +Open Directory... = 開啟目錄 (&D)… +Open from MS:/PSP/GAME... = 開啟自 MS:/PSP/GAME (&P)… +Open Memory Stick = 開啟記憶棒 (&M) +Open New Instance = 開啟新執行個體 OpenGL = OpenGL (&O) Pause = 暫停 (&P) -Pause When Not Focused = 非使用中時暫停 (&P) -Portrait = 縱向 -Portrait reversed = 縱向反轉 +Pause When Not Focused = 未聚焦時暫停 (&P) +Portrait = 直向 +Portrait reversed = 直向反轉 Postprocessing Shader = 後處理著色器 (&G) -PPSSPP Forums = PPSSPP 官方論壇 (&F) +PPSSPP Forums = PPSSPP 論壇 (&F) Record = 錄製 (&R) -Record Audio = 錄音 (&A) -Record Display = 錄製畫面 (&D) -Rendering Mode = 渲染模式 (&O) -Rendering Resolution = 渲染解析度 (&R) -Reset = 重置 (&E) -Reset Symbol Table = 重置符號表 (&R) +Record Audio = 錄製音訊 (&A) +Record Display = 錄製視訊 (&D) +Rendering Mode = 轉譯模式 (&O) +Rendering Resolution = 轉譯解析度 (&R) +Reset = 重設 (&E) +Reset Symbol Table = 重設符號表 (&Y) Run = 執行 (&R) -Save .sym File... = 保存.sym檔案 (&e)... -Save Map File... = 保存Map檔案 (&S)... -Save State = 即時存檔 (&a) -Save State File... = 保存即時存檔檔案 (&S)... -Savestate Slot = 即時存檔插槽 (&t) -Screen Scaling Filter = 螢幕縮放濾鏡 (&e) -Show Debug Statistics = 顯示除錯數據 (&g) -Show FPS Counter = 顯示FPS計數器 (&F) -Skip Number of Frames = 跳過幀數 -Skip Percent of FPS = 跳過FPS的百分比 +Save .sym File... = 儲存 .sym 檔案 (&E)… +Save Map File... = 儲存對應檔案 (&S)… +Save State = 儲存存檔 (&A) +Save State File... = 儲存存檔檔案 (&S)… +Savestate Slot = 存檔插槽 (&T) +Screen Scaling Filter = 螢幕縮放濾鏡 (&E) +Show Debug Statistics = 顯示偵錯統計資料 (&G) +Show FPS Counter = 顯示 FPS 計數器 (&F) +Skip Number of Frames = 跳過影格數 +Skip Percent of FPS = 跳過 FPS 百分比 Stop = 停止 (&S) -Switch UMD = 切換UMD光碟 -Take Screenshot = 截圖 (&T) -Texture Filtering = 紋理過濾 (&x) +Switch UMD = 切換 UMD +Take Screenshot = 擷取螢幕畫面 (&T) +Texture Filtering = 紋理過濾 (&X) Texture Scaling = 紋理縮放 (&T) -Use Lossless Video Codec (FFV1) = 使用無損視訊轉碼器(FFV1) (&U) -Use output buffer for video = 將輸出緩衝區用於視頻 +Use Lossless Video Codec (FFV1) = 使用不失真視訊轉碼器 (FFV1) (&U) +Use output buffer for video = 為視訊使用輸出緩衝區 Vertex Cache = 頂點快取 (&V) -VSync = 垂直同步 (&y) +VSync = 垂直同步 (&Y) Vulkan = Vulkan Window Size = 視窗大小 (&W) -www.ppsspp.org = 拜訪www.&ppsspp.org +www.ppsspp.org = 造訪 www.&ppsspp.org xBRZ = &xBRZ [Developer] -Allocator Viewer = 分配器查看器(Vulkan) -Allow remote debugger = 允許遠程調試器 -Backspace = 向前刪除 +Allocator Viewer = 配置器檢視器 (Vulkan) +Allow remote debugger = 允許遠端偵錯工具 +Backspace = 退格鍵 Block address = 區塊位址 -By Address = 由位址 -Copy savestates to memstick root = 副本保存狀態,以記憶棒根目錄 -Create/Open textures.ini file for current game = 創建/打開當前游戲的textures.ini文件 +By Address = 依位址 +Copy savestates to memstick root = 複製存檔至記憶棒根目錄 +Create/Open textures.ini file for current game = 為目前遊戲建立/開啟 textures.ini 檔案 Current = 目前 Dev Tools = 開發工具 -DevMenu = 開發菜單 -Disabled JIT functionality = 禁用JIT功能 -Draw Frametimes Graph = 繪製幀時間圖 -Dump Decrypted Eboot = 載入遊戲時,轉儲已解密的EBOOT.BIN -Dump Frame GPU Commands = 轉儲幀GPU指令 -Enable driver bug workarounds = 啟用驅動程序錯誤解決方法 -Enable Logging = 啟用日誌 +DevMenu = 開發選單 +Disabled JIT functionality = 停用 JIT 功能 +Draw Frametimes Graph = 繪製影格時間圖形 +Dump Decrypted Eboot = 遊戲啟動時傾印已解密的 EBOOT.BIN +Dump Frame GPU Commands = 傾印影格 GPU 命令 +Enable driver bug workarounds = 啟用驅動程式錯誤因應措施 +Enable Logging = 啟用偵錯記錄 Enter address = 輸入位址 FPU = FPU -Framedump tests = 幀轉儲測試 -Frame Profiler = 幀分析器 -GPU Driver Test = GPU驅動程序測試 -GPU Log Profiler = GPU日志分析器 -GPU Profile = GPU配置文件 -Jit Compare = Jit比較 -JIT debug tools = JIT調試工具 -Language = 語言設定 -Load language ini = 載入語言設定 -Log Dropped Frame Statistics = 日志丟棄幀統計信息 -Log Level = 日誌級別 -Log View = 查看日誌 -Logging Channels = 記錄頻道 +Framedump tests = 影格傾印測試 +Frame Profiler = 影格分析工具 +GPU Driver Test = GPU 驅動程式測試 +GPU Profile = GPU 設定檔 +GPU Log Profiler = GPU 記錄分析工具 +Jit Compare = JIT 比較 +JIT debug tools = JIT 偵錯工具 +Language = 語言 +Load language ini = 載入語言 ini 檔案 +Log Dropped Frame Statistics = 記錄捨棄影格統計資料 +Log Level = 記錄層級 +Log View = 記錄檢視 +Logging Channels = 記錄通道 Next = 下一個 -No block = 沒有記憶體區塊 +No block = 沒有區塊 Prev = 上一個 Random = 隨機 -Replace textures = 紋理更換 -Reset = 重置 -Reset limited logging = 重置受限日誌 -RestoreDefaultSettings = 你確定要所有設定還原到預設值 (除了按鍵配置)?\n此動作無法恢復。\n需要重新啟動PPSSPP,變更才會生效。 -RestoreGameDefaultSettings = 你確定要恢復特定遊戲的配置,\n回到PPSSPP的預設值? +Replace textures = 取代紋理 +Reset = 重設 +Reset limited logging = 重設受限記錄 +RestoreDefaultSettings = 您確定要將所有設定還原為預設值嗎?\n控制對應設定將不會變更。\n\n您無法復原此動作。\n請重新啟動 PPSSPP 以使變更生效。 +RestoreGameDefaultSettings = 您確定要將遊戲特定設定\n還原為 PPSSPP 預設值嗎? Resume = 恢復 -Run CPU Tests = 執行CPU測試 -Save language ini = 儲存語言設定 -Save new textures = 保存新纹理 -Shader Viewer = 著色器查看器 -Show Developer Menu = 顯示開發者選單 -Show on-screen messages = 顯示屏幕消息 -Stats = 統計 -System Information = 系統資料 -Texture ini file created = 創建紋理INI文件 -Texture Replacement = 纹理更换 -Toggle Audio Debug = 切換音訊除錯 -Toggle Freeze = 切換凍結 -Touchscreen Test = 觸摸屏測試 +Run CPU Tests = 執行 CPU 測試 +Save language ini = 儲存語言 ini 檔案 +Save new textures = 儲存新紋理 +Shader Viewer = 著色器檢視器 +Show Developer Menu = 顯示開發人員選單 +Show on-screen messages = 顯示螢幕訊息 +Stats = 統計資料 +System Information = 系統資訊 +Texture ini file created = 紋理 ini 檔案已建立 +Texture Replacement = 紋理取代 +Toggle Audio Debug = 切換音訊偵錯開關 +Toggle Freeze = 切換凍結開關 +Touchscreen Test = 觸控式螢幕測試 VFPU = VFPU [Dialog] -* PSP res = * PSP解析度 -Active = 激活 +* PSP res = * PSP 解析度 +Active = Active Back = 返回 Cancel = 取消 -Center = 中間 -ChangingGPUBackends = 改變渲染引擎之後需要重新啟動PPSSPP。現在重新啟動嗎? -ChangingInflightFrames = 更改圖形命令緩衝要求PPSSPP重新啟動。 現在重啟? -Channel: = 頻道: -Choose PPSSPP save folder = 選擇PPSSPP的存檔資料夾 -Confirm Overwrite = 你要覆蓋這份檔案嗎? -Confirm Save = 你要儲存這份檔案嗎? -ConfirmLoad = 你要載入這份檔案嗎? -ConnectingAP = 連接到接入點\n請稍候... -ConnectingPleaseWait = 連接中.\n請稍候... -ConnectionName = 連接名稱 -Corrupted Data = 數據損壞 +Center = 中心 +ChangingGPUBackends = 變更 GPU 後端需要重新啟動 PPSSPP,要立即重新啟動嗎? +ChangingInflightFrames = 變更圖形命令緩衝需要重新啟動 PPSSPP,要立即重新啟動嗎? +Channel: = 頻道: +Choose PPSSPP save folder = 選擇 PPSSPP 存檔資料夾 +Confirm Overwrite = 要覆寫這個存檔的資料嗎? +Confirm Save = 要儲存這個存檔的資料嗎? +ConfirmLoad = 要載入這個存檔的資料嗎? +ConnectingAP = 正在連線至存取點\n請稍候… +ConnectingPleaseWait = 正在連線\n請稍候… +ConnectionName = 連線名稱 +Corrupted Data = 已損毀的資料 Delete = 刪除 Delete all = 全部刪除 -Delete completed = 檔案已刪除。 -DeleteConfirm = 這份檔案將被刪除。\n你確定要繼續嗎? -DeleteConfirmAll = 你確定要刪除此遊戲的所有檔案? -DeleteConfirmGame = 你確定要刪除此遊戲?\n此動作無法還原。 -DeleteConfirmGameConfig = 你確定要刪除這個遊戲的配置? -DeleteFailed = 無法刪除資料。 -Deleting = 刪除中\n請稍候... -Disable All = 禁用所有 -Dumps = 轉儲 +Delete completed = 刪除完成 +DeleteConfirm = 這個存檔的資料將被刪除\n仍要繼續嗎? +DeleteConfirmAll = 您確定要刪除\n這個遊戲的全部存檔資料嗎? +DeleteConfirmGame = 您確定要從您的裝置上刪除這個遊戲嗎?\n您無法復原此動作。 +DeleteConfirmGameConfig = 您確定要刪除這個遊戲的全部設定嗎? +DeleteFailed = 無法刪除資料 +Deleting = 正在刪除\n請稍候… +Disable All = 全部停用 +Dumps = 傾印 Edit = 編輯 Enable All = 全部啟用 -Enter = 決定 -Filter = 篩選 +Enter = 輸入 +Filter = 篩選器 Finish = 完成 -GE Frame Dumps = GE幀轉儲 -Grid = 格 -Inactive = 不活躍 -InternalError = 發生了一個內部錯誤. +GE Frame Dumps = GE 影格傾印 +Grid = 格狀 +Inactive = 未啟用 +InternalError = 發生內部錯誤 Load = 載入 -Load completed = 檔案已載入。 -Loading = 載入中\n請稍候... -LoadingFailed = 無法載入資料。 -Move = 位置設定 +Load completed = 載入完成 +Loading = 正在載入\n請稍候… +LoadingFailed = 無法載入資料 +Move = 移動 Network Connection = 網路連線 -NEW DATA = 建立新檔案 +NEW DATA = 新存檔 No = 否 -ObtainingIP = 獲取IP地址.\n請稍候... +ObtainingIP = 正在取得 IP 位址\n請稍候… OK = 確定 -Old savedata detected = 偵測到舊版的存檔資料 +Old savedata detected = 偵測到舊版存檔資料 Options = 選項 Reset = 重設 -Resize = 大小設定 -Retry = 重新嘗試 +Resize = 調整大小 +Retry = 重試 Save = 儲存 -Save completed = 檔案已儲存。 -Saving = 儲存中\n請稍候... -SavingFailed = 無法儲存資料。 +Save completed = 儲存完成 +Saving = 正在儲存\n請稍候… +SavingFailed = 無法儲存資料 Search = 搜尋 -Select = 選擇 -Shift = 翻頁 +Select = 選取 +Shift = 移位 Skip = 跳過 -Snap = 對齊 -Space = 空格鍵 +Snap = 貼齊 +Space = 空白 SSID = SSID Submit = 提交 -Supported = 支持 -There is no data = 沒有檔案。 +Supported = 支援 +There is no data = 沒有資料 Toggle All = 切換全部 -Toggle List = 切換列表 -Unsupported = 不支持 -When you save, it will load on a PSP, but not an older PPSSPP = 當您保存,它會加載一個真正的PSP,但不是舊版本PPSSPP -When you save, it will not work on outdated PSP Firmware anymore = 保存後,它將不再適用於過時的PSP固件 +Toggle List = 切換清單 +Unsupported = 不支援 +When you save, it will load on a PSP, but not an older PPSSPP = 在您儲存後,它將會只能在 PSP 上載入,而非舊版 PPSSPP +When you save, it will not work on outdated PSP Firmware anymore = 在您儲存後,它將無法在已過期的 PSP 韌體上運作 Yes = 是 -Zoom = 放大 +Zoom = 縮放 [Error] -7z file detected (Require 7-Zip) = 檔案是7z壓縮檔。\n請先解壓縮 (使用 7-zip 或 WinRAR)。 -A PSP game couldn't be found on the disc. = 光盤上找不到PSP遊戲. -Cannot boot ELF located outside mountRoot. = 無法引導位於裝載根外部的ELF. -Could not save screenshot file = 無法保存截圖檔案 -D3D9or11 = 使用 Direct3D 9? (或者 "否" 以使用Direct3D 11) -D3D11CompilerMissing = D3DCompiler_47.dll未找到。 請安裝。 或者按“是”,再次嘗試使用Direct3D 9。 -D3D11InitializationError = Direct3D 11初始化錯誤 -D3D11Missing = 您的操作系統版本不包括 D3D11。 請運行Windows Update.\n\n按是,嘗試使用 Direct3D 9. -D3D11NotSupported = 您的GPU似乎不支持Direct3D 11.\n\n您是否想改用Direct3D 9? -Disk full while writing data = 寫入數據時硬碟空間不足 -ELF file truncated - can't load = ELF文件被截斷-無法加載 -Error loading file = 檔案載入錯誤 -Error reading file = 讀取檔案錯誤 -Failed initializing CPU/Memory = 初始化CPU或內存失敗 -Failed to load executable: = 無法加載可執行文件: -File corrupt = 文件損壞 -Game disc read error - ISO corrupt = 遊戲光盤讀取錯誤:ISO損壞. -GenericAllStartupError = PPSSPP無法使用任何圖形後端啟動。 嘗試升級圖形和其他驅動程序. -GenericBackendSwitchCrash = 啟動時PPSSPP 崩潰了.\n\n這通常意味著圖形驅動程序問題。 嘗試升級圖形驅動程序.\n\n圖形後端已切換: -GenericDirect3D9Error = 圖形初始化失敗,請試著更新你的圖形驅動程式與DirectX 9 runtime。\n\n你要切換到 OpenGL 試試看嗎?\n\n錯誤訊息: +7z file detected (Require 7-Zip) = 檔案已壓縮 (7z)\n請先解壓縮 (嘗試 7-Zip 或 WinRAR) +A PSP game couldn't be found on the disc. = 此光碟上找不到 PSP 遊戲 +Cannot boot ELF located outside mountRoot. = 無法啟動位於 mountRoot 外的 ELF +Could not save screenshot file = 無法儲存螢幕截圖檔案 +D3D9or11 = 使用 Direct3D 9?(或「否」以使用 Direct3D 11) +D3D11CompilerMissing = 找不到 D3DCompiler_47.dll,請安裝或按下「是」以改為使用 Direct3D 9 +D3D11InitializationError = Direct3D 11 初始化錯誤 +D3D11Missing = 您的作業系統不包括 D3D11,請執行 Windows 更新\n\n按下「是」以改為使用 Direct3D 9 +D3D11NotSupported = 您的 GPU 似乎不支援 Direct3D 11\n\n要改為使用 Direct3D 9 並重試嗎? +Disk full while writing data = 寫入資料時磁碟已滿 +ELF file truncated - can't load = ELF 檔案已截斷 - 無法載入 +Error loading file = 無法載入遊戲 +Error reading file = 無法讀取檔案 +Failed initializing CPU/Memory = 無法初始化 CPU 或記憶體 +Failed to load executable: = 無法載入可執行檔: +File corrupt = 檔案損毀 +Game disc read error - ISO corrupt = 遊戲光碟讀取錯誤:ISO 損毀 +GenericAllStartupError = PPSSPP 無法以任何圖形後端啟動,請嘗試更新您的圖形和其他驅動程式 +GenericBackendSwitchCrash = PPSSPP 在啟動時當機\n\n這通常表示出現了圖形驅動程式問題,請嘗試升級圖形驅動程式\n\n圖形後端已切換: +GenericDirect3D9Error = 無法初始化圖形,請嘗試更新圖形驅動程式和 DirectX 9 執行階段\n\n要嘗試切換至 OpenGL 嗎?\n\n錯誤訊息: GenericGraphicsError = 圖形錯誤 -GenericOpenGLError = 圖形初始化失敗,請試著更新你的圖形驅動程式。\n\n你要切換到DirectX 9 試試看嗎?\n\n錯誤訊息: -GenericVulkanError = 初始化圖形失敗。 嘗試升級圖形驅動程序.\n\n您想嘗試切換到OpenGL嗎?\n\n錯誤信息: -InsufficientOpenGLDriver = 偵測到OpenGL 驅動程式的支援不足\n\n你想嘗試DirectX嗎?\n\n目前兼容DirectX 的遊戲較少,但對你的GPU而言可能是唯一的選擇。 -Just a directory. = 只是一個目錄。 -Missing key = 缺失密鑰 -MsgErrorCode = 錯誤代碼: -MsgErrorSavedataDataBroken = 保存數據已損壞. -MsgErrorSavedataMSFull = 記憶棒已滿. 檢查您的存儲空間. -MsgErrorSavedataNoData = 警告:未找到保存數據. -MsgErrorSavedataNoMS = 未插入記憶棒. -No EBOOT.PBP, misidentified game = 沒有EBOOT.PBP,錯誤識別遊戲。 -Not a valid disc image. = 無效的光盤映像. +GenericOpenGLError = 無法初始化圖形,請嘗試更新圖形驅動程式\n\n要嘗試切換至 DirectX 9 嗎?\n\n錯誤訊息: +GenericVulkanError = 無法初始化圖形,請嘗試更新圖形驅動程式\n\n要嘗試切換至 OpenGL 嗎?\n\n錯誤訊息: +InsufficientOpenGLDriver = 偵測到 OpenGL 驅動程式支援不足!\n\n您的 GPU 回報其不支援 OpenGL 2.0,要改為使用 DirectX 嗎?\n\nDirectX 目前相容的遊戲較少,但這可能是您的 GPU 的唯一選擇。\n\n造訪 https://forums.ppsspp.org 論壇以取得更多資訊。\n\n +Just a directory. = 只是一個目錄 +Missing key = 遺失金鑰 +MsgErrorCode = 錯誤碼: +MsgErrorSavedataDataBroken = 存檔資料已損毀 +MsgErrorSavedataMSFull = 記憶棒已滿,請檢查您的儲存空間 +MsgErrorSavedataNoData = 警告:找不到存檔資料 +MsgErrorSavedataNoMS = 記憶棒未插入 +No EBOOT.PBP, misidentified game = 沒有 EBOOT.PBP,無法辨識的遊戲 +Not a valid disc image. = 不是有效的光碟映像 OpenGLDriverError = OpenGL 驅動程式錯誤 -PPSSPP doesn't support UMD Music. = PPSSPP不支持UMD音樂 -PPSSPP doesn't support UMD Video. = PPSSPP不支持UMD視頻 -PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP玩 PSP遊戲,而不是PlayStation1或2遊戲. -#PPSSPP只能运行PSP游戏, 不能运行PS1或2的游戏 -PPSSPPDoesNotSupportInternet = PPSSPP目前不支援透過網路進行DLC、PSN 或更新遊戲 -PS1 EBOOTs are not supported by PPSSPP. = PPSSPP不支援PS1 EBOOTS -PSX game image detected. = 抱歉,不支援PSX遊戲 -RAR file detected (Require UnRAR) = 檔案是RAR壓縮檔。\ n請先解壓縮(需使用UnRAR)。 -RAR file detected (Require WINRAR) = 檔案是RAR壓縮檔。\ n請先解壓縮(需使用WinRAR)。 -Running slow: try frameskip, sound is choppy when slow = 運行速度慢:嘗試跳幀,聲音不連貫時慢 -Running slow: Try turning off Software Rendering = 運行緩慢:嘗試關閉“軟件渲染” -Save encryption failed. This save won't work on real PSP = 存檔加密失敗。真正的PSP將無法讀取這份存檔 -textures.ini filenames may not be cross-platform = "textures.ini"文件名可能不是跨平台的。 -This is a saved state, not a game. = 這是保存狀態,而不是遊戲。 -This is save data, not a game. = 這是保存數據,而不是遊戲。 -Unable to create cheat file, disk may be full = 無法建立金手指文件,硬碟可能已滿 -Unable to initialize rendering engine. = 無法初始化渲染引擎。 -Unable to write savedata, disk may be full = 無法記錄,硬碟可能已滿 -Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = 警告:視訊記憶體已滿,降低像素提升並切換到慢速快取模式。 -Warning: Video memory FULL, switching to slow caching mode = 警告:視訊記憶體已滿,切換到慢速快取模式。 -ZIP file detected (Require UnRAR) = 檔案是ZIP壓縮檔。\ n請先解壓縮 (需使用UnRAR)。 -ZIP file detected (Require WINRAR) = 檔案是ZIP壓縮檔。\ n請先解壓縮 (需使用WinRAR)。 +PPSSPP doesn't support UMD Music. = PPSSPP 不支援 UMD 音樂 +PPSSPP doesn't support UMD Video. = PPSSPP 不支援 UMD 影片 +PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP 僅支援 PSP 遊戲,無法執行 PlayStation 1 或 PlayStation 2 遊戲 +PPSSPPDoesNotSupportInternet = PPSSPP 目前不支援連線至網際網路使用 DLC、PSN 或更新遊戲 +PS1 EBOOTs are not supported by PPSSPP. = PPSSPP 不支援 PS1 EBOOT +PSX game image detected. = 檔案為 MODE2 映像,PPSSPP 不支援 PS1 遊戲 +RAR file detected (Require UnRAR) = 檔案已壓縮 (RAR)\n請先解壓縮 (嘗試 UnRAR) +RAR file detected (Require WINRAR) = 檔案已壓縮 (RAR)\n請先解壓縮 (嘗試 WinRAR) +Running slow: try frameskip, sound is choppy when slow = 執行速度緩慢:嘗試影格跳過,速度緩慢時音效可能會斷斷續續 +Running slow: Try turning off Software Rendering = 執行速度緩慢:嘗試關閉「軟體轉譯」 +Save encryption failed. This save won't work on real PSP = 存檔加密失敗,這個存檔將無法在真實 PSP 中運作 +textures.ini filenames may not be cross-platform = 「textures.ini」檔案名稱可能無法跨平台 +This is a saved state, not a game. = 這是一個存檔,並非遊戲 +This is save data, not a game. = 這是一個存檔資料,並非遊戲 +Unable to create cheat file, disk may be full = 無法建立密技檔案,磁碟可能已滿 +Unable to initialize rendering engine. = 無法初始化轉譯引擎 +Unable to write savedata, disk may be full = 無法寫入存檔資料,磁碟可能已滿 +Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = 警告:視訊記憶體已滿,降低放大倍率並切換至慢速快取模式 +Warning: Video memory FULL, switching to slow caching mode = 警告:視訊記憶體已滿,切換至慢速快取模式 +ZIP file detected (Require UnRAR) = 檔案已壓縮 (ZIP)\n請先解壓縮 (嘗試 UnRAR) +ZIP file detected (Require WINRAR) = 檔案已壓縮 (ZIP)\n請先解壓縮 (嘗試 WinRAR) [Game] -Asia = 亞洲 -Calculate CRC = 計算CRC -ConfirmDelete = 確定 -Create Game Config = 建立遊戲配置 +Asia = 亞州 +Calculate CRC = 計算 CRC +ConfirmDelete = 刪除 +Create Game Config = 建立遊戲組態 Create Shortcut = 建立捷徑 Delete Game = 刪除遊戲 -Delete Game Config = 刪除遊戲配置 -Delete Save Data = 刪除存檔 +Delete Game Config = 刪除遊戲組態 +Delete Save Data = 刪除存檔資料 Europe = 歐洲 Game = 遊戲 Game Settings = 遊戲設定 -Homebrew = 自製游戲 +Homebrew = 自製遊戲 Hong Kong = 香港 -InstallData = 安裝數據 +InstallData = 資料安裝 Japan = 日本 -Korea = 韓國 +Korea = 南韓 MB = MB -One moment please... = 稍等一會兒... +One moment please... = 請稍候… Play = 開始遊戲 -Remove From Recent = 刪除此記錄 -SaveData = 存檔 -Setting Background = 配置背景 -Show In Folder = 顯示資料夾 +Remove From Recent = 從「最近遊玩」中移除 +SaveData = 儲存資料 +Setting Background = 設定背景 +Show In Folder = 在資料夾中顯示 USA = 美國 -Use UI background = 使用UI背景 +Use UI background = 使用 UI 背景 [Graphics] -% of the void = % 的邊框 -% of viewport = % 的視區 -%, 0:unlimited = %,0 = 無限 -(supersampling) = (超級采樣) -(upscaling) = (倍增) -1x PSP = 1倍PSP -2x = 2倍 -2x PSP = 2倍PSP -3x = 3倍 -3x PSP = 3倍PSP -4x = 4倍 -4x PSP = 4倍PSP -5x = 5倍 -5x PSP = 5倍PSP -6x PSP = 6倍PSP -7x PSP = 7倍PSP -8x = 8倍 -8x PSP = 8倍PSP -9x PSP = 9倍PSP -10x PSP = 10倍PSP -16x = 16倍 -Aggressive = 激進 -Alternative Speed = 速度控制(%,0 = 無限) -Alternative Speed 2 = 替代速度2(in %, 0 = 無限) -Anisotropic Filtering = 非等方性過濾 +% of the void = % 的無效區 +% of viewport = % 的檢視區 +%, 0:unlimited = %,0 = 無限制 +(supersampling) = (超級取樣) +(upscaling) = (放大) +1x PSP = 1× PSP +2x = 2× +2x PSP = 2× PSP +3x = 3× +3x PSP = 3× PSP +4x = 4× +4x PSP = 4× PSP +5x = 5× +5x PSP = 5× PSP +6x PSP = 6× PSP +7x PSP = 7× PSP +8x = 8× +8x PSP = 8× PSP +9x PSP = 9× PSP +10x PSP = 10× PSP +16x = 16× +Aggressive = 積極 +Alternative Speed = 替代速度 (於 %,0 = 無限制) +Alternative Speed 2 = 替代速度 2 (於 %,0 = 無限制) +Anisotropic Filtering = 非等向性過濾 Auto = 自動 -Auto (1:1) = 自動(1:1) -Auto (same as Rendering) = 自動(同渲染) -Auto FrameSkip = 自動跳幀 -Auto Max Quality = 自動最高質量 +Auto (1:1) = 自動 (1:1) +Auto (same as Rendering) = 自動 (同於轉譯解析度) +Auto FrameSkip = 自動影格跳過 +Auto Max Quality = 自動最大品質 Auto Scaling = 自動縮放 Backend = 後端 -Balanced = 均衡 +Balanced = 平衡 Bicubic = 雙立方 -BlockTransfer Tip = 有些遊戲需要這樣才能開啟正確的圖形 -BlockTransferRequired = 警告:此遊戲需要將模擬塊傳輸模式配置為開。 -Both = 兩者 -Buffer graphics commands (faster, input lag) = 緩衝區圖形命令(更快,輸入延遲) -Buffered Rendering = 緩衝渲染 -BufferedRenderingRequired = 警告:此遊戲需要將“渲染模式”配置為“緩衝”。 +BlockTransfer Tip = 部分遊戲需要開啟此項以顯示正確的圖形 +BlockTransferRequired = 警告:這個遊戲需要開啟「模擬區塊傳輸效果」 +Both = 全部 +Buffer graphics commands (faster, input lag) = 緩衝圖形命令 (更快,有輸入延遲) +Buffered Rendering = 緩衝轉譯 +BufferedRenderingRequired = 警告:這個遊戲需要將「轉譯模式」設為「緩衝轉譯」 Camera = 相機 -Camera Device = 攝像頭設備 -Cardboard Screen Size = 螢幕大小(視區%) -Cardboard Screen X Shift = 水平% -Cardboard Screen Y Shift = 垂直% +Camera Device = 相機裝置 +Cardboard Screen Size = 螢幕大小 (於 % 的檢視區) +Cardboard Screen X Shift = X 移位 (於 % 的空白區) +Cardboard Screen Y Shift = Y 移位 (於 % 的空白區) Cardboard VR Settings = Google Cardboard VR 設定 -Cheats = 金手指 -CPU Core = CPU 核心模式 -Debugging = 除錯 -DefaultCPUClockRequired = 警告:此遊戲需要將CPU時鐘配置為默認值。 +Cheats = 密技 +CPU Core = CPU 核心 +Debugging = 偵錯 +DefaultCPUClockRequired = 警告:這個遊戲需要將 CPU 時脈設為預設值 Deposterize = 色調混合 -Deposterize Tip = 修復在紋理被放大時可能發生的小紋理內部毛刺 -Device = 設備 +Deposterize Tip = 修正放大化紋理中的視覺帶狀故障 +Device = 裝置 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disabled = 已禁用 -Display layout editor = 自訂版面 -Display Resolution (HW scaler) = 顯示解析度(硬體縮放) -Dump next frame to log = 將下一幀儲存到日誌 -Enable Cardboard VR = 啟用Cardboard VR +Disabled = Disabled +Display layout editor = 顯示版面配置編輯器 +Display Resolution (HW scaler) = 顯示解析度 (硬體縮放) +Dump next frame to log = 將下一個影格傾印至記錄 +Enable Cardboard VR = 啟用 Cardboard VR FPS = FPS -Frame Rate Control = 幀速率控制 -Frame Skipping = 跳幀 -Frame Skipping Type = 跳幀類型 +Frame Rate Control = 影格速率控制 +Frame Skipping = 影格跳過 +Frame Skipping Type = 影格跳過類型 FullScreen = 全螢幕 -GPU log profiler = GPU日志分析器 -Hack Settings = 修正設定 -Hardware Tessellation = 硬體曲面細分 -Hardware Transform = 硬體幾何轉換 -hardware transform error - falling back to software = 硬體轉換錯誤,改用軟體轉換 -HardwareTessellation Tip = 使用硬體繪製曲綫,使用固定的質量 +Hack Settings = 駭客設定 (可能會造成故障) +Hardware Tessellation = 硬體鑲嵌式 +Hardware Transform = 硬體轉換 +hardware transform error - falling back to software = 硬體轉換錯誤,將回復到軟體轉換 +HardwareTessellation Tip = 使用硬體繪製曲線 High = 高 Hybrid = 混合 -Hybrid + Bicubic = 混合+雙立方 -Ignore camera notch when centering = 居中時忽略攝像頭缺口 -Internal Resolution = 內部分辨率 -Lazy texture caching = 緩慢紋理快取(提升速度) -Lazy texture caching Tip = 更快,在一些游戲裏會引起文字渲染錯誤更快, 在一些游戏里引起文字渲染錯誤 +Hybrid + Bicubic = 混合 + 雙立方 +Ignore camera notch when centering = 置中時忽略相機凹口 +Internal Resolution = 內部解析度 +Lazy texture caching = 消極式紋理快取 (加速) +Lazy texture caching Tip = 更快,但在某些遊戲中可能會造成文字問題 Linear = 線性 Low = 低 -LowCurves = 樣條函數/貝茲曲線品質 -LowCurves Tip = 此選項將顯著提高/降低渲染樣條和貝塞爾曲線的質量 -Lower resolution for effects (reduces artifacts) = 降低效果的解析度(減少圖像錯誤) +LowCurves = 曲線/貝茲曲線品質 +LowCurves Tip = 僅供少數遊戲使用,控制曲線平滑度 +Lower resolution for effects (reduces artifacts) = 降低效果解析度 (降低假影) Manual Scaling = 手動縮放 Medium = 中 Mode = 模式 -Must Restart = 你必須重新啟動 PPSSPP,此更改才會生效 -Native device resolution = 原生裝置的解析度 +Must Restart = 您必須重新啟動 PPSSPP 以使這項變更生效 +Native device resolution = 原生裝置解析度 Nearest = 鄰近取樣 -No buffer = 不緩衝 -Non-Buffered Rendering = 非緩衝渲染(跳過緩衝效果,較快速) -None = 關閉 -Number of Frames = 幀數 +No buffer = 無緩衝 +Non-Buffered Rendering = 跳過緩衝效果 (無緩衝,更快) +None = 無 +Number of Frames = 影格數 Off = 關閉 OpenGL = OpenGL -Overlay Information = 覆蓋訊息 -Partial Stretch = 局部拉伸 -Percent of FPS = FPS百分比 -Performance = 性能 +Overlay Information = 覆疊資訊 +Partial Stretch = 部分延展 +Percent of FPS = FPS 百分比 +Performance = 效能 Postprocessing effect = 後處理效果 -Postprocessing Shader = 後期處理著色器 -Recreate Activity = 重新創建活動 -Render duplicate frames to 60hz = 渲染重複幀至60Hz -RenderDuplicateFrames Tip = 在以較低幀速率運行的遊戲中可以使幀速率更平滑 -Rendering Mode = 渲染模式 -Rendering Resolution = 渲染解析度 -RenderingMode NonBuffered Tip = 較快速,但在某些遊戲中可能什麼都不會顯示 -Retain changed textures = 保留更改紋理(有時更慢) -RetainChangedTextures Tip = 許多遊戲的速度變慢,但某些遊戲則變快許多 +Postprocessing Shader = 後處理著色器 +Recreate Activity = 重新建立活動 +Render duplicate frames to 60hz = 轉譯重複影格至 60 Hz +RenderDuplicateFrames Tip = 可以使以較低影格速率執行的遊戲更加順暢 +Rendering Mode = 轉譯模式 +Rendering Resolution = 轉譯解析度 +RenderingMode NonBuffered Tip = 更快,但在某些遊戲中可能無法繪圖 +Retain changed textures = 保留變更的紋理 (有時會更慢) +RetainChangedTextures Tip = 使很多遊戲變慢,但某些遊戲會變快許多 Rotation = 旋轉 Safe = 安全 -Screen layout = 屏幕佈局 +Screen layout = 螢幕版面配置 Screen Scaling Filter = 螢幕縮放濾鏡 -Show Debug Statistics = 顯示除錯數據 +Show Debug Statistics = 顯示偵錯統計資料 Show FPS Counter = 顯示 FPS 計數器 -Simulate Block Transfer = 模擬塊傳送的影響 -Software Rendering = 軟體渲染 -Software Skinning = 減少繪圖調用(提升速度) -SoftwareSkinning Tip = 在使用高級皮膚技術的遊戲中減少繪圖和更快,但有些遊戲更慢 +Simulate Block Transfer = 模擬區塊傳輸效果 +Software Rendering = 軟體轉譯 (慢) +Software Skinning = 軟體除皮 +SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 -Stretching = 拉伸 -Texture Filter = 紋理過濾 -Texture Filtering = 紋理過濾 +Stretching = 延伸 +Texture Filter = 紋理濾鏡 +Texture Filtering = 紋理濾鏡 Texture Scaling = 紋理縮放 Texture Shader = 紋理著色器 -Turn off Hardware Tessellation - unsupported = 關閉“硬件曲面細分”:不支持 -Unlimited = 無限 -Up to 1 = 上到1 -Up to 2 = 上到2 -Upscale Level = 縮放倍率 -Upscale Type = 縮放類型 -UpscaleLevel Tip = CPU的負擔大,某些縮放可能會延遲,以免遊戲不流暢 -Use all displays = 使用所有顯示 +Turn off Hardware Tessellation - unsupported = 關閉「硬體鑲嵌式」:不支援 +Unlimited = 無限制 +Up to 1 = 最多至 1 +Up to 2 = 最多至 2 +Upscale Level = 放大層級 +Upscale Type = 放大類型 +UpscaleLevel Tip = CPU 負載過重 - 部分縮放可能會延遲以避免間斷 +Use all displays = 使用所有顯示器 Vertex Cache = 頂點快取 -VertexCache Tip = 速度更快,但可能會造成螢幕暫時閃爍 +VertexCache Tip = 更快,但可能會造成暫時閃爍 VSync = 垂直同步 Vulkan = Vulkan Window Size = 視窗大小 xBRZ = xBRZ +GPU log profiler = GPU 記錄分析工具 [InstallZip] -Delete ZIP file = 刪除ZIP檔案 +Delete ZIP file = 刪除 ZIP 檔案 Install = 安裝 -Install game from ZIP file? = 從ZIP檔案安裝遊戲? -Install textures from ZIP file? = 從ZIP文件安裝紋理? -Installed! = 安裝完成! -Texture pack doesn't support install = 紋理包不支持安裝 -Zip archive corrupt = ZIP檔案損壞 -Zip file does not contain PSP software = ZIP文件不包含PSP軟件 +Install game from ZIP file? = 從 ZIP 檔案安裝遊戲? +Install textures from ZIP file? = 從 ZIP 檔案安裝紋理? +Installed! = 已安裝! +Texture pack doesn't support install = 紋理套件不支援安裝 +Zip archive corrupt = ZIP 封存損毀 +Zip file does not contain PSP software = ZIP 檔案不包含 PSP 軟體 [KeyMapping] -Autoconfigure = 自動配置 -Autoconfigure for device = 設備自動配置 -Bind All = 全部綁定 +Autoconfigure = 自動設定 +Autoconfigure for device = 自動設定裝置 +Bind All = 全部繫結 Clear All = 全部清除 -Default All = 全部恢復預設 -Map a new key for = 你按下的按鈕將會對應到此功能: -Map Key = 按鍵映射 -Map Mouse = 鼠標映射 -Replace = 替換 +Default All = 重設為預設值 +Map a new key for = 對應新按鍵: +Map Key = 對應按鍵 +Map Mouse = 對應滑鼠 +Replace = 取代 Show PSP = 顯示 PSP -You can press ESC to cancel. = 您可以按Esc取消。 +You can press ESC to cancel. = 您可以按下 ESC 取消 [MainMenu] -Browse = 瀏覽... -Buy PPSSPP Gold = 購買PPSSPP黃金版 -Choose folder = 選擇文件夾 -Credits = 製作團隊 -PPSSPP Homebrew Store = 從PPSSPP自製游戲商店下載 +Browse = 瀏覽… +Buy PPSSPP Gold = 購買 PPSSPP 黃金版 +Choose folder = 選擇資料夾 +Credits = 製作名單 +PPSSPP Homebrew Store = PPSSPP 自製遊戲商店 Exit = 離開 -Game Settings = 遊戲設定 +Game Settings = 設定 Games = 遊戲 -Give PPSSPP permission to access storage = 給予PPSSPP存取權限 -Homebrew & Demos = 自製遊戲和試玩 -How to get games = 如何獲得遊戲 -How to get homebrew & demos = 如何獲得自製遊戲和試玩 -Load = 載入遊戲... -Loading... = 載入中... -PinPath = 標記 -PPSSPP can't load games or save right now = PPSSPP現在無法載入遊戲或存檔 -Recent = 最近執行的遊戲 -SavesAreTemporary = PPSSPP正在保存在臨時存儲中 -SavesAreTemporaryGuidance = 將PPSSPP提取到某個地方以永久保存 +Give PPSSPP permission to access storage = 授與 PPSSPP 權限以存取儲存空間 +Homebrew & Demos = 自製遊戲與試玩 +How to get games = 如何取得遊戲? +How to get homebrew & demos = 如何取得自製遊戲與試玩? +Load = 載入… +Loading... = 正在載入… +PinPath = 釘選 +PPSSPP can't load games or save right now = PPSSPP 目前無法載入或儲存遊戲 +Recent = Recent +SavesAreTemporary = PPSSPP 正在儲存於暫時儲存空間 +SavesAreTemporaryGuidance = 將 PPSSPP 擷取至其他位置以永久儲存 SavesAreTemporaryIgnore = 忽略警告 -UnpinPath = 取消標記 -UseBrowseOrLoad = 瀏覽以選擇文件夾,或者加載以載入遊戲文件 +UnpinPath = 取消釘選 +UseBrowseOrLoad = 使用「瀏覽」以選擇資料夾,或載入以選擇檔案 www.ppsspp.org = www.ppsspp.org [MainSettings] -Audio = 聲音設定 -Controls = 控制器設定 -Graphics = 圖形設定 -Networking = 網路連線 -Search = 搜索 -System = 系統設定 +Audio = 音訊 +Controls = 控制 +Graphics = 圖形 +Networking = 網路 +System = 系統 Tools = 工具 +Search = 搜尋 [MappableControls] -Alt speed 1 = 自定義速度1 -Alt speed 2 = 自定義速度2 -An.Down = 左搖桿:下 -An.Left = 左搖桿:左 -An.Right = 左搖桿:右 -An.Up = 左搖桿:上 -Analog limiter = 搖桿限制器 -Analog Stick = 搖桿 -Audio/Video Recording = 音頻/視頻錄製 +Alt speed 1 = 替代速度 1 +Alt speed 2 = 替代速度 2 +An.Down = 類比搖桿:下 +An.Left = 類比搖桿:左 +An.Right = 類比搖桿:右 +An.Up = 類比搖桿:上 +Analog limiter = 類比限制器 +Analog Stick = 類比搖桿 +Audio/Video Recording = 音訊/視訊錄製 AxisSwap = 軸交換 -Circle = 圈 -Cross = 叉 -Custom 1 = 預設1 -Custom 10 = 預設10 -Custom 2 = 預設2 -Custom 3 = 預設3 -Custom 4 = 預設4 -Custom 5 = 預設5 -Custom 6 = 預設6 -Custom 7 = 預設7 -Custom 8 = 預設8 -Custom 9 = 預設9 -D-pad down = 方向鍵:下 -D-pad left = 方向鍵:左 -D-pad right = 方向鍵:右 -D-pad up = 方向鍵:上 -DevMenu = 開發者選單 -Display Landscape = 顯示橫向 -Display Landscape Reversed = 顯示橫向反轉 -Display Portrait = 顯示縱向 -Display Portrait Reversed = 顯示縱向反轉 -Double tap button = 雙擊鍵 -Down = 方向鍵:下 +Circle = ○ +Cross = × +Custom 1 = 自訂 1 +Custom 2 = 自訂 2 +Custom 3 = 自訂 3 +Custom 4 = 自訂 4 +Custom 5 = 自訂 5 +Custom 6 = 自訂 6 +Custom 7 = 自訂 7 +Custom 8 = 自訂 8 +Custom 9 = 自訂 9 +Custom 10 = 自訂 10 +D-pad down = 方向鍵:下 +D-pad left = 方向鍵:左 +D-pad right = 方向鍵:右 +D-pad up = 方向鍵:上 +DevMenu = 開發選單 +Double tap button = 點兩下按鈕 +Down = 方向鍵:下 Dpad = 方向鍵 -Frame Advance = 逐幀播放 -Hold = 短按電源鍵 -Home = Home +Frame Advance = 逐影格 +Hold = 固定 +Home = PS 按鈕 L = L -Left = 方向鍵:左 -Load State = 載入即時存檔 -Mute toggle = 靜音 -Next Slot = 下一槽 +Left = 方向鍵:左 +Load State = 載入存檔 +Mute toggle = 靜音切換 +Next Slot = 下一存檔插槽 None = 無 -Note = Note -OpenChat = 打開聊天 +Note = 聲音按鈕 +OpenChat = 開啟聊天 Pause = 暫停 R = R -RapidFire = 連射 +RapidFire = 快速開火 Record = 錄製 -Remote hold = 長按電源鍵 -Rewind = 倒回 -Right = 方向鍵:右 -Right Analog Stick = 右搖桿 +Remote hold = 遠端固定 +Rewind = 倒轉 +Right = 方向鍵:右 +Right Analog Stick = 右類比搖桿 RightAn.Down = 右搖桿:下 RightAn.Left = 右搖桿:左 RightAn.Right = 右搖桿:右 RightAn.Up = 右搖桿:上 -Rotate Analog (CCW) = 旋轉模擬(CCW) -Rotate Analog (CW) = 旋轉模擬(CW) -Save State = 即時存檔 -Screen = 屏幕 -Screenshot = 屏幕截圖 +Rotate Analog (CCW) = 旋轉類比 (CCW) +Rotate Analog (CW) = 旋轉類比 (CW) +Save State = 儲存存檔 +Screen = 螢幕 +Screenshot = 螢幕截圖 Select = 選擇 SpeedToggle = 速度切換 -Square = 正方 +Square = □ Start = 開始 Swipe Down = 向下滑動 Swipe Left = 向左滑動 Swipe Right = 向右滑動 Swipe Up = 向上滑動 -tap to customize = 點擊並自定義 -Texture Dumping = 紋理轉儲 -Texture Replacement = 紋理替換 -Toggle Fullscreen = 切換全屏 +tap to customize = 點選以自訂 +Texture Dumping = 紋理傾印 +Texture Replacement = 紋理取代 +Toggle Fullscreen = 切換全螢幕 Toggle mode = 切換模式 -Triangle = 三角形 -Fast-forward = 解除速限 +Triangle = △ +Fast-forward = 快轉 Up = 方向鍵:上 -Vol + = 音量+ -Vol - = 音量- -Wlan = 無綫網絡 - -[MemStick] -Already contains PSP data = 已包含PSP數據 -Create or Choose a PSP folder = 創建或選擇PSP文件夾 -Current = 目前 -DataCanBeShared = 數據可在PPSSPP普通版/黃金版共用 -DataCannotBeShared = 數據無法在PPSSPP普通版/黃金版共用! -DataWillBeLostOnUninstall = 警告! 卸載PPSSPP會丟失數據! -DataWillStay = 卸載PPSSPP會保留數據 -Done! = 完成! -EasyUSBAccess = 輕鬆USB訪問 -Failed to move some files! = 無法移動部分文件! -Failed to save config = 無法保存配置 -Free space = 可用空間 -Manually specify PSP folder = 手動指定PSP文件夾 -MemoryStickDescription = 選擇PSP文件存放位置(記憶棒) -Move Data = 移動PSP數據 -Selected PSP Data Folder = 選擇PSP數據文件夾 -No data will be changed = 數據不會更改 -PPSSPP will restart after the change = 完成配置后會重啓PPSSPP -Skip for now = 暫時跳過 -Starting move... = 開始移動... -That folder doesn't work as a memstick folder. = 所選文件夾無法作爲記憶棒目錄您选择的文件夹无法作为记忆棒目录。 -USBAccessThrough = USB連接時請打開 Android/data/org.ppsspp.ppsspp/files -USBAccessThroughGold = USB連接時請打開 Android/data/org.ppsspp.ppssppgold/files -Use App Private Data = 在APP内置的目錄中保存 -Use PSP folder at root of storage = 在手機目錄中保存PSP文件 -Welcome to PPSSPP! = 歡迎使用PPSSPP! -WhatsThis = 這個配置有什麽用? +Vol + = 音量 + +Vol - = 音量 - +Wlan = WLAN +Display Landscape = 顯示器橫向 +Display Landscape Reversed = 顯示器橫向反轉 +Display Portrait = 顯示器直向 +Display Portrait Reversed = 顯示器直向反轉 [Networking] -AdHoc Server = Ad hoc服務器 -AdhocServer Failed to Bind Port = 無法綁定Adhoc服務器端口 -AM: Data from Unknown Port = AM:來自未知端口的數據 +AdHoc Server = 臨機操作伺服器 +AdhocServer Failed to Bind Port = 臨機操作伺服器無法繫結連接埠 +AM: Data from Unknown Port = AM:來自不明連接埠的資料 Auto = 自動 -Bottom Center = 中間下面 -Bottom Left = 下左面 -Bottom Right = 右下面 -Center Left = 中間左面 -Center Right = 中間右面 -Change Mac Address = 改變 Mac 網路位址 -Change proAdhocServer Address = 改變PRO Adhoc網路位址(localhost = 多個實例) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +Bottom Center = 正下 +Bottom Left = 左下 +Bottom Right = 右下 +Center Left = 正左 +Center Right = 正右 +Change Mac Address = 變更 MAC 位址 +ChangeMacSaveConfirm = 產生新的 MAC 位址? +ChangeMacSaveWarning = 某些遊戲在載入儲存資料時會驗證 MAC 位址,這可能會損毀舊存檔 +Change proAdhocServer Address = 變更 PRO 臨機操作伺服器 IP 位址 (本機主機 = 多重執行個體) Chat = 聊天 Chat Button Position = 聊天按鈕位置 Chat Here = 在這裡聊天 -Chat message = 聊天消息 +Chat message = 聊天訊息 Chat Screen Position = 聊天畫面位置 -Disconnected from AdhocServer = 與 dhoc服務器斷開連接 -DNS Error Resolving = DNS錯誤解決 -Enable built-in PRO Adhoc Server = 啟用內建PRO Adhoc伺服器 -Enable network chat = 啟用網絡聊天 -Enable networking = 啟用網路連線/無線區域網路(測試) -Enable UPnP = 啟用UPnP(需要幾秒鐘來檢測) +Disconnected from AdhocServer = 從臨機操作伺服器中斷連線 +DNS Error Resolving = DNS 解析錯誤 +Enable built-in PRO Adhoc Server = 啟用內建 PRO 臨機操作伺服器 +Enable network chat = 啟用網路聊天 +Enable networking = 啟用網路功能/WLAN (測試版,可能損毀遊戲) +Enable UPnP = 啟用 UPnP (需要數秒鐘來偵測) EnableQuickChat = 啟用快速聊天 -Enter a new PSP nickname = 輸入新的PSP暱稱 -Enter Quick Chat 1 = 輸入快速聊天1 -Enter Quick Chat 2 = 輸入快速聊天2 -Enter Quick Chat 3 = 輸入快速聊天3 -Enter Quick Chat 4 = 輸入快速聊天4 -Enter Quick Chat 5 = 輸入快速聊天5 -Error = Error -Failed to Bind Localhost IP = 無法綁定本地主機IP -Failed to Bind Port = 無法綁定端口 -Failed to connect to Adhoc Server = 無法連接Adhoc服務器 -Forced First Connect = 強制首次連接(更快的連接) -GM: Data from Unknown Port = GM:數據來自未知端口 -Hostname = 主機名 -Invalid IP or hostname = 無效的IP或主機名 -Minimum Timeout = 最小超時(以毫秒為單位,0=默認) -Misc = 其他(默認= PSP兼容性) +Enter a new PSP nickname = 輸入新的 PSP 暱稱 +Enter Quick Chat 1 = 輸入快速聊天 1 +Enter Quick Chat 2 = 輸入快速聊天 2 +Enter Quick Chat 3 = 輸入快速聊天 3 +Enter Quick Chat 4 = 輸入快速聊天 4 +Enter Quick Chat 5 = 輸入快速聊天 5 +Error = 錯誤 +Failed to Bind Localhost IP = 無法繫結本機主機 IP +Failed to Bind Port = 無法繫結連接埠 +Failed to connect to Adhoc Server = 無法連線至臨機操作伺服器 +Forced First Connect = 強制首次連線 (更快連線) +GM: Data from Unknown Port = GM:來自不明連接埠的資料 +Hostname = 主機名稱 +Invalid IP or hostname = 無效的 IP 或主機名稱 +Minimum Timeout = 最小逾時 (單位為毫秒,0 = 預設) +Misc = 雜項 (預設 = PSP 相容性) Network Initialized = 網路已初始化 None = 無 -Please change your Port Offset = 請更改您的端口偏移 -Port offset = 端口偏移 (0 = PSP 實機兼容) -Open PPSSPP Multiplayer Wiki Page = 打開PPSSPP多人百科頁面 -#打开PPSSPP多人联机百科页面 -proAdhocServer Address: = Ad hoc服務器地址: -Quick Chat 1 = 快速聊天1 -Quick Chat 2 = 快速聊天2 -Quick Chat 3 = 快速聊天3 -Quick Chat 4 = 快速聊天4 -Quick Chat 5 = 快速聊天5 +Please change your Port Offset = 請變更您的連接埠位移 +Port offset = 連接埠位移 (0 = PSP 相容性) +Open PPSSPP Multiplayer Wiki Page = 開啟 PPSSPP 多人遊戲維基頁面 +proAdhocServer Address: = 臨機操作伺服器位址: +Quick Chat 1 = 快速聊天 1 +Quick Chat 2 = 快速聊天 2 +Quick Chat 3 = 快速聊天 3 +Quick Chat 4 = 快速聊天 4 +Quick Chat 5 = 快速聊天 5 QuickChat = 快速聊天 -Send = 發送 -Send Discord Presence information = 發送Discord "Rich Presence" information -#发送Discord"在线状态"信息 -Top Center = 中間上面 -Top Left = 左上面 -Top Right = 右上面 -Unable to find UPnP device = 找不到UPnP設備 -UPnP (port-forwarding) = UPnP(端口轉發) -UPnP need to be reinitialized = UPnP需要重新初始化 -UPnP use original port = UPnP使用原始端口(已啟用=PSP兼容性) -Validating address... = 驗證地址... +Send = 傳送 +Send Discord Presence information = 傳送 Discord「Rich Presence」資訊 +Top Center = 正上 +Top Left = 左上 +Top Right = 右上 +Unable to find UPnP device = 找不到 UPnP 裝置 +UPnP (port-forwarding) = UPnP (連接埠轉送) +UPnP need to be reinitialized = UPnP 需要重新初始化 +UPnP use original port = UPnP 使用原始連接埠 (已啟用 = PSP 相容性) +Validating address... = 正在驗證位址… WLAN Channel = WLAN 頻道 -You're in Offline Mode, go to lobby or online hall = 您現在是離綫模式,請進入房間或在綫大廳 +You're in Offline Mode, go to lobby or online hall = 您目前處於離線模式,請前往大廳或線上大廳 [Pause] -Cheats = 金手指 +Cheats = 密技 Continue = 繼續 -Create Game Config = 建立遊戲配置 -Delete Game Config = 刪除遊戲配置 -Exit to menu = 返回主選單 +Create Game Config = 建立遊戲組態 +Delete Game Config = 刪除遊戲組態 +Exit to menu = 返回選單 Game Settings = 遊戲設定 Load State = 載入存檔 -Rewind = 倒回 -Save State = 即時存檔 +Rewind = 倒轉 +Save State = 儲存存檔 Settings = 設定 -Switch UMD = 切換光碟 -Undo last load = 撤銷加載 -Undo last save = 撤銷保存 +Switch UMD = 切換 UMD +Undo last load = 復原上次載入 +Undo last save = 復原上次儲存 [PostShaders] -(duplicated setting, previous slider will be used) = (配置重複, 將使用上面滑塊的值) +(duplicated setting, previous slider will be used) = (重複的設定,將使用上一個滑桿) 4xHqGLSL = 4×HQ GLSL 5xBR = 5xBR 5xBR-lv2 = 5xBR-lv2 AAColor = AA-Color Amount = 數量 -Animation speed (0 -> disable) = 動畫速度(0->禁用) -Black border = 黑色描邊 -Bloom = 汎光 +Black border = 黑色框線 +Bloom = 光圈 Brightness = 亮度 Cartoon = 卡通 -CatmullRom = Bicubic 雙三插值縮放 -ColorCorrection = 顔色修正 +ColorCorrection = 色彩修正 Contrast = 對比度 -CRT = CRT 掃描綫 -FXAA = FXAA (快速近似抗鋸齒) -Gamma = 伽馬 -Grayscale = 灰度图 -Intensity = 强度 -InverseColors = 反色 -MitchellNetravali = Bicubic 雙三插值縮放 -Natural = 自然色 -NaturalA = 自然色-無模糊 +CRT = CRT 掃描線 +FXAA = FXAA 消除鋸齒 +Gamma = 色差補正 +Grayscale = 灰階 +Intensity = 濃度 +InverseColors = 反轉色彩 +Natural = 自然色彩 +NaturalA = 自然色彩 (無模糊) Off = 關閉 -Power = 效果强度 -PSPColor = PSP顔色 -Saturation = 色彩 -Scanlines = 掃描綫(CRT) -Sharpen = 銳化 -SSAA(Gauss) = Supersampling AA(超級采樣抗鋸齒:高斯) +Power = Power +PSPColor = PSP 色彩 +Saturation = 飽和度 +Scanlines = 掃描線 (CRT) +Sharpen = 銳利化 +SSAA(Gauss) = 超級取樣 AA (高斯) Tex4xBRZ = 4xBRZ TexMMPX = MMPX -UpscaleSpline36 = Spline36縮放 -VideoSmoothingAA = VideoSmoothingAA(視頻平滑抗鋸齒) -Vignette = 光暈 +UpscaleSpline36 = Spline36 放大 +VideoSmoothingAA = 視訊平滑 AA +Vignette = 暈影 +Animation speed (0 -> disable) = 動畫速度 (0 -> 停用) +CatmullRom = 雙立方 (卡特姆 - 羅姆) 放大 +MitchellNetravali = 雙立方 (密契爾 - 內拉瓦利) 放大 [PSPCredits] -all the forum mods = 論壇上所有的mod -build server = 編譯服務器 +all the forum mods = 所有論壇模組 +build server = 組建伺服器 Buy Gold = 購買黃金版 -check = 也歡迎你試用海豚模擬器,最好用的Wii/GC 模擬器 -CheckOutPPSSPP = 查閲 PPSSPP, 一款超棒的PSP模擬器:https://www.ppsspp.org/ +check = 同樣歡迎使用海豚模擬器,這是最棒的 Wii/GC 模擬器 +CheckOutPPSSPP = 體驗 PPSSPP,一款絕佳的 PSP 模擬器:https://www.ppsspp.org/ contributors = 參與者: -created = 作者: +created = 作者 Discord = Discord -info1 = PPSSPP僅限教學用途 -info2 = 請確認你有權使用該遊戲, -info3 = 例如持有該遊戲的正版光碟, -info4 = 或是透過PSP於PSN商店購買數位版。 -info5 = PSP®是索尼公司的註冊商標。 -iOS builds = iOS builds -license = PPSSPP是遵循GPL 2.0+授權條款的自由軟體 -list = 網站上有相容性列表、官方論壇以及開發動態 -PPSSPP Forums = PPSSPP官方論壇 -Privacy Policy = 隱私政策 -Share PPSSPP = 分享PPSSPP +info1 = PPSSPP 僅適用於教育用途, +info2 = 請確保您擁有遊戲的版權, +info3 = 您擁有遊戲的 UMD 光碟, +info4 = 或是透過 PSP 在 PSN 商店中購買數位版。 +info5 = PSP® 是 Sony, Inc 的註冊商標 +iOS builds = iOS 組建 +license = PPSSPP 是遵循 GPL 2.0+ 授權條款的自由軟體 +list = 瞭解相容性清單、官方論壇和開發資訊 +PPSSPP Forums = PPSSPP 論壇 +Privacy Policy = 隱私權政策 +Share PPSSPP = 分享 PPSSPP specialthanks = 特別感謝: -specialthanksKeithGalocy = 的硬件,建議,他來自NVIDIA -specialthanksMaxim = 的出色Atrac3 +解碼 -testing = 負責測試 -this translation by = 譯者: -title = 快速、方便攜帶的PSP模擬器 -tools = 使用自由工具: +specialthanksKeithGalocy = 的硬體和建議,他來自 NVIDIA +specialthanksMaxim = 的出色的解碼器工作 +testing = 測試人員: +this translation by = 正體中文翻譯: +title = 快速、方便攜帶的 PSP 模擬器 +tools = 使用的自由工具: # Add translators or contributors who translated PPSSPP into your language here. # Add translators1-6 for up to 6 lines of translator credits. # Leave extra lines blank. 4 contributors per line seems to look best. -translators1 = sum2012, kaienfr, raven02, aquanull, xiwo4525 -translators2 = wuspring, zzq920817, W-MS, xzapk, Arthur200000 -translators3 = Playhi, PeaceShi, Nargacuga, driver1998 -translators4 = xujibbs +translators1 = sum2012, xujibbs, leoxxx, Adeptus2 +translators2 = +translators3 = +translators4 = translators5 = translators6 = Twitter @PPSSPP_emu = Twitter @PPSSPP_emu -website = 歡迎參觀我們的網站: -written = 使用C++編寫以保證移植性和速度 +website = 歡迎造訪我們的網站: +written = 使用 C++ 編寫,以保證建置速度和相容性 + +[MemStick] +Already contains PSP data = 已包含 PSP 資料 +Create or Choose a PSP folder = 建立或選擇 PSP 資料夾 +Current = 目前 +DataCanBeShared = 資料可在 PPSSPP 標準版/黃金版之間共用 +DataCannotBeShared = 資料無法在 PPSSPP 標準版/黃金版之間共用! +DataWillBeLostOnUninstall = 警告!資料會在解除安裝 PPSSPP 後遺失! +DataWillStay = 資料會在解除安裝 PPSSPP 後保留 +Done! = 完成! +EasyUSBAccess = USB 輕鬆存取 +Failed to move some files! = 無法移動部分檔案! +Failed to save config = 無法儲存組態 +Free space = 可用空間 +Manually specify PSP folder = 手動指定 PSP 資料夾 +MemoryStickDescription = 選擇 PSP 資料存放位置 (記憶棒) +Move Data = 移動資料 +Selected PSP Data Folder = 選取的 PSP 資料資料夾 +Skip for now = 暫時跳過 +No data will be changed = 沒有要變更的資料 +PPSSPP will restart after the change = PPSSPP 將在完成變更後重新啟動 +Starting move... = 開始移動… +That folder doesn't work as a memstick folder. = 這個資料夾無法作為記憶棒資料夾正常運作 +USBAccessThrough = 透過 USB 存取 Android/data/org.ppsspp.ppsspp/files +USBAccessThroughGold = 透過 USB 存取 Android/data/org.ppsspp.ppssppgold/files +Use App Private Data = 使用應用程式私人資料夾 +Use PSP folder at root of storage = 使用儲存空間 PSP 資料夾 +Welcome to PPSSPP! = 歡迎使用 PPSSPP! +WhatsThis = 這是什麼? [RemoteISO] Browse Games = 瀏覽遊戲 -Local Server Port = 本地服務器端口 -Manual Mode Client = 手動模式客戶端 -Remote disc streaming = 遠程光盤流 -Remote Port = 遠端埠 +Local Server Port = 本機伺服器連接埠 +Manual Mode Client = 手動設定用戶端 +Remote disc streaming = 遠端光碟串流 +Remote Port = 遠端連接埠 Remote Server = 遠端伺服器 -Remote Subdirectory = 遠程子目錄 -RemoteISODesc = 您最近列表中的遊戲將被共享 -RemoteISOLoading = 已連接,正在加載遊戲列表... -RemoteISOScanning = 掃描...單擊服務器設備上的“共享遊戲” -RemoteISOScanningTimeout = 正在掃描...檢查您桌面的防火牆配置 -RemoteISOWifi = 注意:將兩個設備都連接到同一Wi-Fi網絡 -RemoteISOWinFirewall = 警告:Windows防火牆阻止共享 -Settings = 設定值 -Share Games (Server) = 分享遊戲(服務器) -Share on PPSSPP startup = 分享PPSSPP啟動 -Stop Sharing = 停止分享 -Stopping.. = 正在停止... +Remote Subdirectory = 遠端子目錄 +RemoteISODesc = 「最近遊玩」清單中的遊戲將被共用 +RemoteISOLoading = 已連線,正在載入遊戲清單… +RemoteISOScanning = 正在掃描… 在您的伺服器裝置上按一下「共用遊戲」 +RemoteISOScanningTimeout = 正在掃描… 檢查您的桌面防火牆設定 +RemoteISOWifi = 注意:將兩部裝置皆連線至同一 Wi-Fi 網路 +RemoteISOWinFirewall = 警告:Windows 防火牆已封鎖共用 +Settings = 設定 +Share Games (Server) = 共用遊戲 (伺服器) +Share on PPSSPP startup = PPSSPP 啟動時共用 +Stop Sharing = 停止共用 +Stopping.. = 正在停止… [Reporting] -Bad = 壞 -FeedbackCRCCalculating = 光碟CRC: 計算中... -FeedbackCRCValue = 光碟CRC: %1 -FeedbackDelayInfo = 您的數據正在後台提交. -FeedbackDesc = 模擬的效果怎麼樣?說給我們聽聽! -FeedbackDisabled = 兼容性服務器報告必須啟用. -FeedbackIncludeCRC = 注意:電池將用於發送光盤CRC -FeedbackIncludeScreen = 包括屏幕截圖 -FeedbackSubmitDone = 您的數據已提交. -FeedbackSubmitFail = 無法將數據提交到服務器。 嘗試更新PPSSPP。 -FeedbackThanks = 感謝您的反饋意見! -Gameplay = 遊戲過程 +Bad = 不佳 +FeedbackCRCCalculating = 光碟 CRC:正在計算… +FeedbackCRCValue = 光碟 CRC:%1 +FeedbackDelayInfo = 您的資料正在背景提交 +FeedbackDesc = 模擬效果如何?說給我們聽聽! +FeedbackDisabled = 必須啟用相容性伺服器回報 +FeedbackIncludeCRC = 注意:傳送光碟 CRC 將會損耗電池電力 +FeedbackIncludeScreen = 包含螢幕截圖 +FeedbackSubmitDone = 您的資料已提交 +FeedbackSubmitFail = 無法將資料提交至伺服器,嘗試更新 PPSSPP +FeedbackThanks = 感謝您的意見反應 +Gameplay = 遊戲歷程 Graphics = 圖形 -Great = 很好 -In-game = 在遊戲中 -In-game Description = 能進入遊戲玩,但太多問題 +Great = 絕佳 +In-game = 遊戲內 +In-game Description = 可以進入遊戲,但存在很多錯誤 Menu/Intro = 選單/簡介 -Menu/Intro Description = 無法進入遊戲本身 -Nothing = 沒畫面 -Nothing Description = 完全壞了 -OK = 好 -Open Browser = 打開瀏覽器 +Menu/Intro Description = 無法進入遊戲 +Nothing = 沒有畫面 +Nothing Description = 完全損毀 +OK = 確定 +Open Browser = 開啟報告網站 Overall = 整體 Perfect = 完美 -Perfect Description = 完美模擬整個游戲 - 太棒了! +Perfect Description = 完美模擬整個遊戲 - 太棒了! Plays = 可玩 -Plays Description = 基本模擬整個游戲,但有時會出現故障 -ReportButton = 報告反饋 -Show disc CRC = 顯示光碟CRC +Plays Description = 可以遊玩,但可能會出現故障 +ReportButton = 回報意見反應 +Show disc CRC = 顯示光碟 CRC Speed = 速度 -Submit Feedback = 提交反饋 -SuggestionConfig = 請參閱網站上的報告以了解正確的配置。 -SuggestionCPUSpeed0 = 禁用鎖定的CPU速度配置。 -SuggestionDowngrade = 降級到較舊的PPSSPP版本(請報告此錯誤)。 -SuggestionsFound = 其他用戶報告了更好的結果。 點擊“查看反饋”以獲取更多詳細信息。 -SuggestionsNone = 其他用戶也不能運行該游戲。 -SuggestionsWaiting = 提交並檢查其他用戶的反饋... -SuggestionUpgrade = 升級到更新的PPSSPP版本。 -SuggestionVerifyDisc = 檢查您的ISO是否是光盤的良好副本。 +Submit Feedback = 提交意見反應 +SuggestionConfig = 參閱網站上的報告以瞭解最佳設定 +SuggestionCPUSpeed0 = 停用鎖定的 CPU 速度設定 +SuggestionDowngrade = 降級為舊版 PPSSPP (請回報此錯誤) +SuggestionsFound = 其他使用者已回報了更佳的結果,點選「檢視意見反映」以取得更多詳細資料 +SuggestionsNone = 這個遊戲在其他使用者的裝置上也無法運作 +SuggestionsWaiting = 正在提交並檢查其他使用者的意見反應… +SuggestionUpgrade = 升級至新版 PPSSPP 組建 +SuggestionVerifyDisc = 檢查 ISO 是否為您光碟的良好複本 Unselected Overall Description = 這個遊戲的模擬效果如何? -View Feedback = 查看所有反饋 +View Feedback = 檢視所有意見反應 [Savedata] Date = 日期 -Filename = 文件名 -No screenshot = 沒有截圖 -None yet. Things will appear here after you save. = 暫無。在你存檔之後這裡才會出現數據。 -Nothing matching '%1' was found. = 沒有找到符合'%1'的結果。 -Save Data = 存檔資料 -Save States = 即時存檔資料 -Savedata Manager = 管理存檔資料 -Showing matches for '%1'. = 找到符合'%1'的搜尋結果。 +Filename = 檔案名稱 +No screenshot = 沒有螢幕截圖 +None yet. Things will appear here after you save. = 尚無,將在存檔後出現新項目 +Nothing matching '%1' was found. = 找不到與「%1」相符的項目 +Save Data = 儲存資料 +Save States = 存檔 +Savedata Manager = 儲存資料管理員 +Showing matches for '%1'. = 顯示與「%1」相符的項目 Size = 大小 [Screen] -Cardboard VR OFF = Cardboard VR關閉 -Chainfire3DWarning = 警告:偵測到Chainfire3D,可能造成問題 -Failed to load state = 無法載入快速存檔 -Failed to save state = 無法儲存快速存檔 -fixed = 速度:固定 -GLToolsWarning = 警告:偵測到GLTools,可能造成問題 -In menu = In menu -Load savestate failed = 無法載入快速存檔 -Loaded State = 已載入即時存檔 -Loaded. Game may refuse to save over different savedata. = 已加載。游戲可能無法保存在別的存檔。 -Loaded. Game may refuse to save over newer savedata. = 已加載。游戲可能無法保存在進度提前的存檔。 -Loaded. Save in game, restart, and load for less bugs. = 已加載。 保存在遊戲中,重新啟動並加載,以減少錯誤。 -LoadStateDoesntExist = 無法載入:存檔不存在! -LoadStateWrongVersion = 無法載入:存檔為舊版的PPSSPP的! -norewind = 倒带即時存檔不可用 -Playing = 游戲中 -PressESC = 按下ESC鍵以暫停遊戲 -replaceTextures_false = 不再替換紋理. -replaceTextures_true = 啟用紋理替換. -Save State Failed = 即時存檔失敗! -Saved State = 即時存檔完成 -saveNewTextures_false = 紋理保存已禁用. -saveNewTextures_true = 紋理現在將保存到您的存儲中. -SpeedCustom2 = 速度:備用2 +Cardboard VR OFF = Cardboard VR 關閉 +Chainfire3DWarning = 警告:偵測到 Chainfire3D,可能會造成問題 +Failed to load state = 無法載入存檔 +Failed to save state = 無法儲存存檔 +fixed = 速度:替代 +GLToolsWarning = 警告:偵測到 GLTools,可能會造成問題 +In menu = 選單中 +Load savestate failed = 無法載入存檔 +Loaded State = 存檔已載入 +Loaded. Save in game, restart, and load for less bugs. = 已載入,在遊戲中儲存、重新啟動,然後載入,將會減少錯誤 +Loaded. Game may refuse to save over different savedata. = 已載入,遊戲可能會拒絕覆寫不同的存檔 +Loaded. Game may refuse to save over newer savedata. = 已載入,遊戲可能會拒絕覆寫較新的存檔 +LoadStateDoesntExist = 無法載入存檔:存檔不存在! +LoadStateWrongVersion = 無法載入存檔:存檔僅適用於舊版 PPSSPP! +norewind = 沒有可用的倒轉存檔 +Playing = 正在遊玩 +PressESC = 按下 ESC 以開啟暫停選單 +replaceTextures_false = 紋理將不再被取代 +replaceTextures_true = 紋理取代已啟用 +Save State Failed = 無法儲存存檔! +Saved State = 已存檔 +saveNewTextures_false = 紋理儲存已停用 +saveNewTextures_true = 紋理將儲存至您的儲存空間 +SpeedCustom2 = 速度:替代 2 standard = 速度:標準 -State load undone = 撤銷載入存檔 -Untitled PSP game = 無標題的PSP遊戲 - -[Search] -Clear filter = 清楚篩選結果 -Filter = 篩選 -Filtering settings by '%1' = 配置篩選'%1' -Find settings = 搜索配置 -No settings matched '%1' = 未找到配置'%1' +State load undone = 存檔載入復原 +Untitled PSP game = 未命名 PSP 遊戲 [Store] -Already Installed = 已安裝完成 +Already Installed = 已安裝 Connection Error = 連線錯誤 Install = 安裝 -Launch Game = 開始遊戲 -Loading... = 載入中... +Launch Game = 啟動遊戲 +Loading... = 正在載入… MB = MB Size = 大小 Uninstall = 解除安裝 [SysInfo] -%d (%d per core, %d cores) = %d (每核心 %d 綫程, %d 核心) -%d bytes = %d 字節 -(none detected) = (未檢測到) +%d (%d per core, %d cores) = %d (每核心 %d 執行緒,%d 核心) +%d bytes = %d 位元組 +(none detected) = (未偵測到) 3D API = 3D API ABI = ABI -API Version = API版本 -Audio Information = 音頻信息 -Board = 主板 -Build Config = 編譯配置 -Build Configuration = 編譯配置 -Built by = 編譯者 -Core Context = 核心上下文 +API Version = API 版本 +Audio Information = 音訊資訊 +Board = 主機板 +Build Config = 組建組態 +Build Configuration = 組建組態 +Built by = 建置者 +Core Context = 核心內容 Cores = 核心數 -CPU Extensions = CPU擴展 -CPU Information = CPU信息 -CPU Name = CPU名稱 -D3DCompiler Version = D3DCompiler版本 -Debug = 調試 -Debugger Present = 調試器已連接 -Device Info = 設備信息 -Directories = 路徑 -Display Color Formats = 顯示顔色格式 -Display Information = 顯示信息 -Driver Version = 驅動程序版本 -EGL Extensions = EGL擴展 -Frames per buffer = 每緩存區幀數 -GPU Information = GPU信息 -High precision float range = 高精度浮點範圍 -High precision int range = 高精度整數範圍 +CPU Extensions = CPU 擴充 +CPU Information = CPU 資訊 +CPU Name = CPU 名稱 +D3DCompiler Version = D3DCompiler 版本 +Debug = 偵錯 +Debugger Present = 偵錯工具呈現 +Device Info = 裝置資訊 +Directories = 目錄 +Display Information = 顯示器資訊 +Driver bugs = 驅動程式錯誤 +Driver Version = 驅動程式版本 +EGL Extensions = EGL 擴充 +Frames per buffer = 每緩衝區影格數 +GPU Information = GPU 資訊 +High precision float range = 高精確度浮點數範圍 +High precision int range = 高精確度整數範圍 Lang/Region = 語言/區域 -Memory Page Size = 内存頁大小 -Native Resolution = 原生分辨率 -OGL Extensions = OGL 擴展 -OpenGL ES 2.0 Extensions = OpenGL ES 2.0擴展 -OpenGL ES 3.0 Extensions = OpenGL ES 3.0擴展 -OpenGL Extensions = OpenGL擴展 -Optimal frames per buffer = 最佳每緩存區幀數 -Optimal sample rate = 最佳采樣率 -OS Information = OS信息 -PPSSPP build = PPSSPP編譯版本 -Refresh rate = 刷新率 -Release = 發佈 -RW/RX exclusive = RW/RX獨占 -Sample rate = 采樣率 -Shading Language = 著色語言 -Storage = 存儲 -Sustained perf mode = 持久性能模式 -System Information = 系統信息 +Memory Page Size = 記憶體分頁大小 +Native Resolution = 原生解析度 +No GPU driver bugs detected = 未偵測到 GPU 驅動程式錯誤 +OGL Extensions = OGL 擴充 +OpenGL ES 2.0 Extensions = OpenGL ES 2.0 擴充 +OpenGL ES 3.0 Extensions = OpenGL ES 3.0 擴充 +OpenGL Extensions = OpenGL 擴充 +Optimal frames per buffer = 最佳每緩衝區影格數 +Optimal sample rate = 最佳取樣率 +OS Information = OS 資訊 +PPSSPP build = PPSSPP 組建 +Refresh rate = 重新整理速率 +Release = 發行版本 +RW/RX exclusive = RW/RX 排除 +Sample rate = 取樣率 +Shading Language = 網底語言 +Storage = 儲存空間 +Sustained perf mode = 持續效能模式 +System Information = 系統資訊 System Name = 系統名稱 System Version = 系統版本 -Threads = 綫程數 -Vendor = 供應商 -Vendor (detected) = 供應商 (已檢測到的) -Version Information = 版本信息 -Vulkan Extensions = Vulkan擴展 -Vulkan Features = Vulkan特性 -Driver bugs = 驅動錯誤 -No GPU driver bugs detected = 未檢測到GPU驅動錯誤 +Threads = 執行緒 +Vendor = 廠商 +Vendor (detected) = 廠商 (偵測到) +Version Information = 版本資訊 +Vulkan Extensions = Vulkan 擴充 +Vulkan Features = Vulkan 功能 +Display Color Formats = 顯示器色彩格式 [System] -(broken) = (壞了) -12HR = 12小時 -24HR = 24小時 +(broken) = (已損毀) +12HR = 12 小時制 +24HR = 24 小時制 Auto = 自動 -Auto Load Savestate = 自動加載保存狀態 -AVI Dump started. = AVI轉儲開始 -AVI Dump stopped. = AVI轉儲停止 -Cache ISO in RAM = 將整個ISO檔暫存於記憶體中 -Change CPU Clock = 調整CPU時鐘(不穩定) -Color Tint = 色調 -Color Saturation = 顔色飽和度 -Error: load undo state is from a different game = 錯誤: 撤回的即時存檔來自不同游戲 -Failed to load state for load undo. Error in the file system. = 無法撤銷加載的即時存檔,文件系統有錯誤。 -Floating symbols = 漂浮的符號 -Memory Stick folder = 更改記憶棒文件夾 -Memory Stick size = 更改記憶棒大小(GB) -Change Nickname = 更改別名 -ChangingMemstickPath = 游戲存檔、即時存檔以及其他數據不會被複製到新路徑。\n\n確定要修改記憶棒文件嗎? -ChangingMemstickPathInvalid = 目標路徑不能用於保存記憶棒數據。 -Cheats = 金手指 -Clear Recent = 清除最近的游戲 -Clear Recent Games List = 清除最近遊戲清單 -Clear UI background = 清除背景 -Confirmation Button = 確認鍵 +Auto Load Savestate = 自動載入存檔 +AVI Dump started. = AVI 傾印已啟動 +AVI Dump stopped. = AVI 傾印已停止 +Cache ISO in RAM = 將完整 ISO 快取於 RAM +Change CPU Clock = 變更模擬 PSP CPU 時脈 (不穩定) +Memory Stick folder = 記憶棒資料夾 +Memory Stick size = 記憶棒大小 +Change Nickname = 變更暱稱 +ChangingMemstickPath = 遊戲、存檔和其他資料將不會複製到這個資料夾\n\n要變更記憶棒資料夾嗎? +ChangingMemstickPathInvalid = 這個路徑將無法用於儲存記憶棒檔案 +Cheats = 密技 +Clear Recent = 清除「最近遊玩」 +Clear Recent Games List = 清除「最近遊玩」清單 +Clear UI background = 清除 UI 背景 +Confirmation Button = 確認按鈕 Date Format = 日期格式 Day Light Saving = 日光節約時間 -DDMMYYYY = DDMMYYYY -Decrease size = 減少尺寸 -Developer Tools = 開發者工具 -Display Extra Info = 顯示額外信息 -Display Games on a grid = 以方格顯示“游戲” -Display Homebrew on a grid = 以方格顯示 "自製游戲" -Display Recent on a grid = 以方格顯示最近的游戲 -Dynarec (JIT) = 動態重編譯(JIT) +DDMMYYYY = 日/月/年 +Decrease size = 減小尺寸 +Developer Tools = 開發人員工具 +Display Extra Info = 顯示額外資訊 +Display Games on a grid = 以格狀顯示「遊戲」 +Display Homebrew on a grid = 以格狀顯示「自製遊戲與試玩」 +Display Recent on a grid = 以格狀顯示「最近遊玩」 +Dynarec (JIT) = 動態重新編譯 (JIT) Emulation = 模擬 -Enable Cheats = 啓用金手指 -Enable Compatibility Server Reports = 向伺服器回報相容性問題 -Failed to load state. Error in the file system. = 無法讀取即時存檔。檔案系統錯誤。 -Failed to save state. Error in the file system. = 無法儲存即時存檔。檔案系統錯誤。 -Fast (lag on slow storage) = 快速 (存取較慢的系統仍會延遲) -Fast Memory = 快速記憶體存取(不穩定) -Force real clock sync (slower, less lag) = 強制實際時鐘同步(速度較慢,但較少延遲) -frames, 0:off = 幀,0 = 關閉 -Games list settings = 游戲列表配置 +Enable Cheats = 啟用密技 +Enable Compatibility Server Reports = 啟用相容性伺服器回報 +Error: load undo state is from a different game = 錯誤:載入復原存檔來自不同遊戲 +Failed to load state. Error in the file system. = 無法載入存檔,檔案系統錯誤 +Failed to save state. Error in the file system. = 無法儲存存檔,檔案系統錯誤 +Failed to load state for load undo. Error in the file system. = 無法載入復原存檔,檔案系統錯誤 +Fast (lag on slow storage) = 快速 (慢速儲存體延遲) +Fast Memory = 快速記憶體 (不穩定) +Floating symbols = 浮動符號 +Force real clock sync (slower, less lag) = 強制真實時脈同步 (更慢,減少延遲) +frames, 0:off = 影格,0 = 關閉 +Games list settings = 遊戲清單設定 General = 一般 -Grid icon size = 倍率圖標尺寸 -Help the PPSSPP team = 幫助PPSSPP團隊 -Host (bugs, less lag) = 主機(較少延遲,但可能造成問題;有助於魔法少女小圓) -Ignore bad memory accesses = 忽略錯誤的內存訪問 -Increase size = 增加大小 -Interpreter = 解釋器 -IO timing method = I/O計時方法 -IR Interpreter = IR解釋器 -Memory Stick Folder = 記憶棒文件夾 -Memory Stick inserted = 插入記憶棒 -MHz, 0:default = MHz,預設為0 -MMDDYYYY = MMDDYYYY -Moving background = 動態壁紙 -Newest Save = 最新存礑 -No animation = 靜態壁紙 -Not a PSP game = 不是PSP遊戲 +Grid icon size = 格狀圖示大小 +Help the PPSSPP team = 協助 PPSSPP 團隊 +Host (bugs, less lag) = 主機 (更多錯誤,減少延遲) +Ignore bad memory accesses = 忽略損毀的記憶體存取 +Increase size = 加大尺寸 +Interpreter = 解譯器 +IO timing method = I/O 計時方法 +IR Interpreter = IR 解譯器 +Memory Stick Folder = 記憶棒資料夾 +Memory Stick inserted = 記憶棒已插入 +MHz, 0:default = MHz,0 = 預設 +MMDDYYYY = 月/日/年 +Moving background = 動態背景 +Newest Save = 最新存檔 +No animation = 靜態背景 +Not a PSP game = 這不是 PSP 遊戲 Off = 關閉 -Oldest Save = 最早存礑 -Path does not exist! = 路徑不存在! -PSP Memory Stick = PSP記憶棒 -PSP Model = PSP機型 +Oldest Save = 最舊存檔 +Path does not exist! = 路徑不存在! +PSP Memory Stick = PSP 記憶棒 +PSP Model = PSP 型號 PSP Settings = PSP 設定 PSP-1000 = PSP-1000 PSP-2000/3000 = PSP-2000/3000 -Recent games = 最近的游戲 -Record Audio = 錄音 -Record Display = 錄製畫面 -Reset Recording on Save/Load State = 在保存/加載狀態下重置記錄 -Restore Default Settings = 還原出廠設定 -Rewind Snapshot Frequency = 快照倒回頻率 -Save path in installed.txt = 存檔路徑在installed.txt -Save path in My Documents = 存檔路徑在我的文件 -Savestate Slot = 即時存檔插槽 -Savestate slot backups = 即時存檔插槽備份 -Screenshots as PNG = PNG格式截圖 -Set UI background... = 配置UI背景... -Show ID = 顯示ID -Show Memory Stick folder = 顯示記憶棒文件夾 -Show region flag = 顯示區域標誌 -Simulate UMD delays = 模擬UMD延遲(修正紙箱戰機W) -Slot 1 = 插槽1 -Slot 2 = 插槽2 -Slot 3 = 插槽3 -Slot 4 = 插槽4 -Slot 5 = 插槽5 -Storage full = 存儲容量已滿 -Sustained performance mode = 持續性能模式 -Theme = 主題 +Recent games = 最近遊戲 +Record Audio = 錄製音訊 +Record Display = 錄製視訊 +Reset Recording on Save/Load State = 儲存/載入存檔時重設錄製 +Restore Default Settings = 將 PPSSPP 設定重設為預設值 +Rewind Snapshot Frequency = 倒轉快照頻率 +Save path in installed.txt = 儲存路徑於 installed.txt +Save path in My Documents = 儲存路徑於「我的文件」 +Savestate Slot = 存檔插槽 +Savestate slot backups = 存檔插槽備份 +Screenshots as PNG = 以 PNG 格式儲存螢幕截圖 +Set UI background... = 設定 UI 背景… +Show ID = 顯示 ID +Show region flag = 顯示區域旗幟 +Simulate UMD delays = 模擬 UMD 延遲 +Slot 1 = 插槽 1 +Slot 2 = 插槽 2 +Slot 3 = 插槽 3 +Slot 4 = 插槽 4 +Slot 5 = 插槽 5 +Storage full = 儲存空間已滿 +Sustained performance mode = 持續效能模式 Time Format = 時間格式 -UI = 用戶界面 -UI background animation = UI背景效果 -UI Sound = 介面聲音 -undo %c = 備用 %c +UI = UI +UI Sound = UI 音效 +UI background animation = UI 背景動畫 +undo %c = 備份 %c USB = USB -Use Lossless Video Codec (FFV1) = 使用無損視訊轉碼器(FFV1) -Use O to confirm = 使用O確認 -Use output buffer (with overlay) for recording =使用輸出緩衝區(帶有覆蓋)進行記錄 -Use system native keyboard = 使用系統本機鍵盤 -Use X to confirm = 使用X確認 +Use Lossless Video Codec (FFV1) = 使用不失真視訊轉碼器 (FFV1) +Use O to confirm = 使用 O 作為確認按鈕 +Use output buffer (with overlay) for recording = 為錄製使用輸出緩衝區 (覆疊) +Use system native keyboard = 使用系統原生鍵盤 +Use X to confirm = 使用 X 作為確認按鈕 VersionCheck = 檢查 PPSSPP 新版本 -WARNING: Android battery save mode is on = 警告:Android省電模式已開啟 +WARNING: Android battery save mode is on = 警告:Android 省電模式已開啟 WARNING: Battery save mode is on = 警告:省電模式已開啟 Waves = 波浪 -YYYYMMDD = YYYYMMDD +YYYYMMDD = 年/月/日 Theme = 主題 -Show Memory Stick folder = 顯示記憶棒文件夾 +Color Tint = 色彩濃淡 +Color Saturation = 色彩飽和度 +Show Memory Stick folder = 顯示記憶棒資料夾 + +[Themes] +Default = 預設 [TextureShaders] Off = 關閉 @@ -1209,29 +1197,27 @@ TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ -[Themes] -Default = 默認 +[Search] +No settings matched '%1' = 沒有與「%1」相符的設定 +Filtering settings by '%1' = 依「%1」篩選設定 +Find settings = 尋找設定 +Filter = 篩選器 +Clear filter = 清除篩選器 + +[Upgrade] +Details = 詳細資料 +Dismiss = 關閉 +Download = 下載 +New version of PPSSPP available = PPSSPP 有可用的新版本 [UI Elements] %1 button = %1 按鈕 -%1 checkbox = %1 複選框 +%1 checkbox = %1 核取方塊 %1 choice = %1 選擇 -%1 heading = %1 heading -%1 radio button = %1 單選按鈕 -%1 text field = %1 文本域 -Choices: = 選擇: -List: = 列表: -Progress: %1% = 進程: %1% -Screen representation = 屏幕表現 -[Upgrade] -Details = 詳情 -Dismiss = 忽略 -Download = 下載 -New version of PPSSPP available = 已有新版的PPSSPP - -[Search] -Filtering settings by '%1' = 配置篩選 '%1' -Find settings = 搜索配置 -Filter = 篩選 -Clear filter = 清楚篩選 -No settings matched '%1' = 未找到配置 '%1' +%1 heading = %1 標題 +%1 radio button = %1 選項按鈕 +%1 text field = %1 文字欄位 +Choices: = 選擇: +List: = 清單: +Progress: %1% = 進度:%1% +Screen representation = 螢幕呈現 From 7a620962aa9c4d0e5e5fb2851c15b42c11b74dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 9 Oct 2022 19:17:29 +0200 Subject: [PATCH 103/715] thin3d: Replace hint at future MRT support with basic multi layer support --- Common/GPU/D3D11/thin3d_d3d11.cpp | 61 ++++++++++++----------- Common/GPU/D3D9/thin3d_d3d9.cpp | 3 ++ Common/GPU/OpenGL/thin3d_gl.cpp | 3 ++ Common/GPU/Vulkan/VulkanRenderManager.cpp | 13 +++-- Common/GPU/Vulkan/VulkanRenderManager.h | 6 ++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- Common/GPU/thin3d.h | 2 +- 7 files changed, 50 insertions(+), 40 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index ddbdecb0aa..45e67adb1d 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -1306,35 +1306,38 @@ public: Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { HRESULT hr; D3D11Framebuffer *fb = new D3D11Framebuffer(desc.width, desc.height); - if (desc.numColorAttachments) { - fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - D3D11_TEXTURE2D_DESC descColor{}; - descColor.Width = desc.width; - descColor.Height = desc.height; - descColor.MipLevels = 1; - descColor.ArraySize = 1; - descColor.Format = fb->colorFormat; - descColor.SampleDesc.Count = 1; - descColor.SampleDesc.Quality = 0; - descColor.Usage = D3D11_USAGE_DEFAULT; - descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; - descColor.CPUAccessFlags = 0; - descColor.MiscFlags = 0; - hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex); - if (FAILED(hr)) { - delete fb; - return nullptr; - } - hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView); - if (FAILED(hr)) { - delete fb; - return nullptr; - } - hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView); - if (FAILED(hr)) { - delete fb; - return nullptr; - } + + // We don't (yet?) support multiview for D3D11. Not sure if there's a way to do it. + // Texture arrays are supported but we don't have any other use cases yet. + _dbg_assert_(desc.numLayers == 1); + + fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + D3D11_TEXTURE2D_DESC descColor{}; + descColor.Width = desc.width; + descColor.Height = desc.height; + descColor.MipLevels = 1; + descColor.ArraySize = 1; + descColor.Format = fb->colorFormat; + descColor.SampleDesc.Count = 1; + descColor.SampleDesc.Quality = 0; + descColor.Usage = D3D11_USAGE_DEFAULT; + descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + descColor.CPUAccessFlags = 0; + descColor.MiscFlags = 0; + hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView); + if (FAILED(hr)) { + delete fb; + return nullptr; } if (desc.z_stencil) { diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 162c8febec..80ee1bec97 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -1244,6 +1244,9 @@ public: }; Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { + // Don't think D3D9 does array layers. + _dbg_assert_(desc.numLayers == 1); + static uint32_t id = 0; D3D9Framebuffer *fbo = new D3D9Framebuffer(desc.width, desc.height); diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 91f89e7807..f3ade40b9a 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1390,6 +1390,9 @@ void OpenGLInputLayout::Compile(const InputLayoutDesc &desc) { Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) { CheckGLExtensions(); + // TODO: Support multiview later. (It's our only use case for multi layers). + _dbg_assert_(desc.numLayers == 1); + GLRFramebuffer *framebuffer = renderManager_.CreateFramebuffer(desc.width, desc.height, desc.z_stencil); OpenGLFramebuffer *fbo = new OpenGLFramebuffer(&renderManager_, framebuffer); return fbo; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 8da78975d2..a3bce70e0d 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -155,15 +155,14 @@ bool VKRComputePipeline::Create(VulkanContext *vulkan) { return success; } -VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, bool createDepthStencilBuffer, const char *tag) : vulkan_(vk), tag_(tag) { - width = _width; - height = _height; +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag) + : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { _dbg_assert_(tag); - CreateImage(vulkan_, initCmd, color, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); if (createDepthStencilBuffer) { - CreateImage(vulkan_, initCmd, depth, width, height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + CreateImage(vulkan_, initCmd, depth, width, height, numLayers, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); } UpdateTag(tag); @@ -243,9 +242,9 @@ VKRFramebuffer::~VKRFramebuffer() { } } -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - ici.arrayLayers = 1; + ici.arrayLayers = numLayers; ici.mipLevels = 1; ici.extent.width = width; ici.extent.height = height; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 074e0c1db4..97771514e0 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -40,17 +40,19 @@ struct VKRImage { // For debugging. std::string tag; }; -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); class VKRFramebuffer { public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, bool createDepthStencilBuffer, const char *tag); + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag); ~VKRFramebuffer(); VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); int width = 0; int height = 0; + int numLayers = 0; + VKRImage color{}; // color.image is always there. VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE. diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index cedb21b49f..0c03d240ed 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1505,7 +1505,7 @@ private: Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.z_stencil, desc.tag); + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.z_stencil, desc.numLayers, desc.tag); return new VKFramebuffer(vkrfb); } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 2d9ce7f8c5..7c3a6d240d 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -293,7 +293,7 @@ struct FramebufferDesc { int width; int height; int depth; - int numColorAttachments; + int numLayers; bool z_stencil; const char *tag; // For graphics debuggers }; From d3804ec2e593ed9cedaccacf3041689a83ed3fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 9 Oct 2022 20:19:39 +0200 Subject: [PATCH 104/715] Misc multiview hackery --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 18 ++++++++++++++++-- Common/GPU/Vulkan/VulkanQueueRunner.h | 18 +++++++++++++++--- GPU/Common/TextureCacheCommon.cpp | 2 +- GPU/Common/VertexShaderGenerator.cpp | 5 ++++- GPU/Common/VertexShaderGenerator.h | 8 +++++++- GPU/D3D11/ShaderManagerD3D11.cpp | 2 +- GPU/Directx9/ShaderManagerDX9.cpp | 4 ++-- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/Vulkan/PipelineManagerVulkan.cpp | 3 +++ GPU/Vulkan/ShaderManagerVulkan.cpp | 16 +++++++++------- GPU/Vulkan/ShaderManagerVulkan.h | 6 ++++-- unittest/TestShaderGenerators.cpp | 10 +++++----- 12 files changed, 68 insertions(+), 26 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 98bd2e7773..5873c3e974 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -326,9 +326,10 @@ static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) { // Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) { - bool selfDependency = rpType == RP_TYPE_COLOR_INPUT || rpType == RP_TYPE_COLOR_DEPTH_INPUT; + bool selfDependency = RenderPassTypeHasInput(rpType); bool isBackbuffer = rpType == RP_TYPE_BACKBUFFER; - bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT; + bool hasDepth = RenderPassTypeHasDepth(rpType); + bool multiview = RenderPassTypeHasMultiView(rpType); VkAttachmentDescription attachments[2] = {}; attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; @@ -390,6 +391,19 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas rp.subpassCount = 1; rp.pSubpasses = &subpass; + VkRenderPassMultiviewCreateInfoKHR mv{ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR }; + uint32_t viewMask = 0x3; // Must be outside the 'if (multiview)' scope! + int viewOffset = 0; + if (multiview) { + rp.pNext = &mv; + mv.subpassCount = 1; + mv.pViewMasks = &viewMask; + mv.dependencyCount = 0; + mv.pCorrelationMasks = &viewMask; // same masks + mv.correlationMaskCount = 1; + mv.pViewOffsets = &viewOffset; + } + if (isBackbuffer) { deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL; deps[numDeps].dstSubpass = 0; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index ab0bc3ac71..d5ea7163ed 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -48,18 +48,24 @@ enum class PipelineFlags { USES_DEPTH_STENCIL = (1 << 2), // Reads or writes the depth or stencil buffers. USES_INPUT_ATTACHMENT = (1 << 3), USES_GEOMETRY_SHADER = (1 << 4), + USES_MULTIVIEW = (1 << 5), // Inherited from the render pass it was created with. }; ENUM_CLASS_BITOPS(PipelineFlags); // Pipelines need to be created for the right type of render pass. enum RenderPassType { - // These four are organized so that bit 0 is DEPTH and bit 1 is INPUT, so + // These eight are organized so that bit 0 is DEPTH and bit 1 is INPUT and bit 2 is MULTIVIEW, so // they can be OR-ed together in MergeRPTypes. RP_TYPE_COLOR, RP_TYPE_COLOR_DEPTH, RP_TYPE_COLOR_INPUT, RP_TYPE_COLOR_DEPTH_INPUT, + RP_TYPE_MULTIVIEW_COLOR, + RP_TYPE_MULTIVIEW_COLOR_DEPTH, + RP_TYPE_MULTIVIEW_COLOR_INPUT, + RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT, + // This is the odd one out, and gets special handling in MergeRPTypes. RP_TYPE_BACKBUFFER, // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible. @@ -67,12 +73,18 @@ enum RenderPassType { RP_TYPE_COUNT, }; +// Hm, soon time to exploit the bit properties in these.. + inline bool RenderPassTypeHasDepth(RenderPassType type) { - return type == RP_TYPE_BACKBUFFER || type == RP_TYPE_COLOR_DEPTH || type == RP_TYPE_COLOR_DEPTH_INPUT; + return type == RP_TYPE_BACKBUFFER || type == RP_TYPE_COLOR_DEPTH || type == RP_TYPE_COLOR_DEPTH_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT; } inline bool RenderPassTypeHasInput(RenderPassType type) { - return type == RP_TYPE_COLOR_INPUT || type == RP_TYPE_COLOR_DEPTH_INPUT; + return type == RP_TYPE_COLOR_INPUT || type == RP_TYPE_COLOR_DEPTH_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT; +} + +inline bool RenderPassTypeHasMultiView(RenderPassType type) { + return type == RP_TYPE_MULTIVIEW_COLOR || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH || type == RP_TYPE_MULTIVIEW_COLOR_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT; } struct VkRenderData { diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 3877b2df22..a1ed25094b 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1295,7 +1295,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { desc.height = 1; desc.depth = 1; desc.z_stencil = false; - desc.numColorAttachments = 1; + desc.numLayers = 1; desc.tag = "dynamic_clut"; dynamicClutFbo_ = draw_->CreateFramebuffer(desc); desc.tag = "dynamic_clut_temp"; diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 5b7e321277..b0c3cbca50 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -126,9 +126,12 @@ static const char * const boneWeightDecl[9] = { "layout(location = 3) in vec4 w1;\nlayout(location = 4) in vec4 w2;\n", }; -bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) { +bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, VertexShaderFlags *vertexShaderFlags, std::string *errorString) { *attrMask = 0; *uniformMask = 0; + if (vertexShaderFlags) { + *vertexShaderFlags = (VertexShaderFlags)0; + } bool highpFog = false; bool highpTexcoord = false; diff --git a/GPU/Common/VertexShaderGenerator.h b/GPU/Common/VertexShaderGenerator.h index c1899001e6..9d3707411c 100644 --- a/GPU/Common/VertexShaderGenerator.h +++ b/GPU/Common/VertexShaderGenerator.h @@ -25,7 +25,13 @@ struct VShaderID; -bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString); +// Can technically be deduced from the vertex shader ID, but this is safer. +enum class VertexShaderFlags : u32 { + MULTI_VIEW = 1, +}; +ENUM_CLASS_BITOPS(VertexShaderFlags); + +bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, VertexShaderFlags *vertexShaderFlags, std::string *errorString); // D3D9 constants. enum { diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 0560b52941..0c9fec1817 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -212,7 +212,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString); + GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform); vsCache_[VSID] = vs; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 6e20ec45e0..1e56e5ab37 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -581,7 +581,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString)) { + if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString)) { vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform); } if (!vs || vs->Failed()) { @@ -606,7 +606,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // Can still work with software transform. uint32_t attrMask; uint64_t uniformMask; - bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString); + bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString); _assert_(success); vs = new VSShader(device_, VSID, codeBuffer_, false); } diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 3bdd9c4f86..e4a6350de1 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -743,7 +743,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { uint32_t attrMask; uint64_t uniformMask; std::string errorString; - if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &errorString)) { + if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &errorString)) { ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 3d7745b452..95b019483b 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -336,6 +336,9 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * if (fs->Flags() & FragmentShaderFlags::INPUT_ATTACHMENT) { pipelineFlags |= PipelineFlags::USES_INPUT_ATTACHMENT; } + if (vs->Flags() & VertexShaderFlags::MULTI_VIEW) { + pipelineFlags |= PipelineFlags::USES_MULTIVIEW; + } VulkanPipeline *pipeline = CreateVulkanPipeline( renderManager, pipelineCache_, layout, pipelineFlags, diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 249078cf43..6356f43e0a 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -135,8 +135,8 @@ std::string VulkanFragmentShader::GetShaderString(DebugShaderStringType type) co } } -VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform) - : vulkan_(vulkan), useHWTransform_(useHWTransform), id_(id) { +VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, VertexShaderFlags flags, const char *code, bool useHWTransform) + : vulkan_(vulkan), useHWTransform_(useHWTransform), flags_(flags), id_(id) { source_ = code; module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str(), new std::string(VertexShaderDesc(id))); if (!module_) { @@ -331,10 +331,11 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader std::string genErrorString; uint64_t uniformMask = 0; // Not used uint32_t attributeMask = 0; // Not used - bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString); + VertexShaderFlags flags{}; + bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString); _assert_msg_(success, "VS gen error: %s", genErrorString.c_str()); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); - vs = new VulkanVertexShader(vulkan, VSID, codeBuffer_, useHWTransform); + vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform); vsCache_.Insert(VSID, vs); } @@ -343,7 +344,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader // Fragment shader not in cache. Let's compile it. std::string genErrorString; uint64_t uniformMask = 0; // Not used - FragmentShaderFlags flags; + FragmentShaderFlags flags{}; bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString); _assert_msg_(success, "FS gen error: %s", genErrorString.c_str()); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); @@ -515,11 +516,12 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { std::string genErrorString; uint32_t attributeMask = 0; uint64_t uniformMask = 0; - if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString)) { + VertexShaderFlags flags; + if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString)) { return false; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); - VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, codeBuffer_, useHWTransform); + VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, flags, codeBuffer_, useHWTransform); vsCache_.Insert(id, vs); } uint32_t vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID; diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h index 4c89f91ef5..88f138d923 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.h +++ b/GPU/Vulkan/ShaderManagerVulkan.h @@ -61,13 +61,14 @@ protected: class VulkanVertexShader { public: - VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform); + VulkanVertexShader(VulkanContext *vulkan, VShaderID id, VertexShaderFlags flags, const char *code, bool useHWTransform); ~VulkanVertexShader(); const std::string &source() const { return source_; } bool Failed() const { return failed_; } - bool UseHWTransform() const { return useHWTransform_; } + bool UseHWTransform() const { return useHWTransform_; } // TODO: Roll into flags + VertexShaderFlags Flags() const { return flags_; } std::string GetShaderString(DebugShaderStringType type) const; Promise *GetModule() { return module_; } @@ -81,6 +82,7 @@ protected: bool failed_ = false; bool useHWTransform_; VShaderID id_; + VertexShaderFlags flags_; }; class VulkanGeometryShader { diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index a9546408a5..a420299520 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -67,27 +67,27 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs case ShaderLanguage::GLSL_VULKAN: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); } case ShaderLanguage::GLSL_1xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); } case ShaderLanguage::GLSL_3xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); } case ShaderLanguage::HLSL_D3D9: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); } case ShaderLanguage::HLSL_D3D11: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); } default: return false; From fb250c4b29642ae1477073a6aa0033b113f695b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Oct 2022 00:26:10 +0200 Subject: [PATCH 105/715] More multiview work --- Common/GPU/D3D11/thin3d_d3d11.cpp | 15 ++-- Common/GPU/D3D9/thin3d_d3d9.cpp | 17 ++-- Common/GPU/OpenGL/thin3d_gl.cpp | 13 ++- Common/GPU/Vulkan/VulkanContext.cpp | 7 +- Common/GPU/Vulkan/VulkanContext.h | 2 +- Common/GPU/Vulkan/VulkanImage.cpp | 10 +-- Common/GPU/Vulkan/VulkanMemory.h | 10 +++ Common/GPU/Vulkan/VulkanQueueRunner.cpp | 23 +++-- Common/GPU/Vulkan/VulkanQueueRunner.h | 10 ++- Common/GPU/Vulkan/VulkanRenderManager.cpp | 100 ++++++++++++++++------ Common/GPU/Vulkan/VulkanRenderManager.h | 37 ++++++-- Common/GPU/Vulkan/thin3d_vulkan.cpp | 17 ++-- Common/GPU/thin3d.h | 11 ++- Common/UI/UIScreen.cpp | 2 +- GPU/Common/FragmentShaderGenerator.cpp | 7 +- GPU/Common/FramebufferManagerCommon.cpp | 55 +++++++----- GPU/Common/FramebufferManagerCommon.h | 6 +- GPU/Common/PresentationCommon.cpp | 14 +-- GPU/Common/ShaderId.cpp | 9 ++ GPU/Common/ShaderId.h | 2 + GPU/Common/ShaderUniforms.h | 10 +++ GPU/Common/StencilCommon.cpp | 6 +- GPU/Common/TextureCacheCommon.cpp | 16 ++-- GPU/D3D11/StateMappingD3D11.cpp | 2 +- GPU/Directx9/StateMappingDX9.cpp | 4 +- GPU/GLES/DepthBufferGLES.cpp | 8 +- GPU/GLES/FramebufferManagerGLES.cpp | 4 +- GPU/GLES/StateMappingGLES.cpp | 2 +- GPU/GPUState.h | 1 + GPU/Software/SoftGpu.cpp | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 7 +- GPU/Vulkan/DrawEngineVulkan.h | 3 +- GPU/Vulkan/GPU_Vulkan.cpp | 5 ++ GPU/Vulkan/StateMappingVulkan.cpp | 2 +- UI/EmuScreen.cpp | 14 +-- Windows/PPSSPP.vcxproj | 1 + Windows/PPSSPP.vcxproj.filters | 3 + headless/Headless.cpp | 2 +- 38 files changed, 302 insertions(+), 157 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 45e67adb1d..b7972d49ed 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -94,11 +94,8 @@ public: bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return curRenderTarget_; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1658,7 +1655,8 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel return true; } -void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { +void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { + _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D // TODO: deviceContext1 can actually discard. Useful on Windows Mobile. if (fbo) { D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; @@ -1704,8 +1702,9 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren stepId_++; } -void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { - _assert_(binding < MAX_BOUND_TEXTURES); +void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { + _dbg_assert_(binding < MAX_BOUND_TEXTURES); + _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; switch (channelBit) { case FBChannel::FB_COLOR_BIT: diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 80ee1bec97..ba51fb42fa 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -531,12 +531,9 @@ public: bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return curRenderTarget_; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; - + void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; + uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1292,7 +1289,8 @@ D3D9Framebuffer::~D3D9Framebuffer() { } } -void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { +void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { + _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support if (fbo) { D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; device_->SetRenderTarget(0, fb->surf); @@ -1351,8 +1349,9 @@ uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit } } -void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { - _assert_(binding < MAX_BOUND_TEXTURES); +void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { + _dbg_assert_(binding < MAX_BOUND_TEXTURES); + _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; switch (channelBit) { case FB_DEPTH_BIT: diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index f3ade40b9a..53f294c35d 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -354,11 +354,8 @@ public: bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return curRenderTarget_; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1398,7 +1395,9 @@ Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) { return fbo; } -void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { +void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { + _dbg_assert_(layer == ALL_LAYERS || layer == 0); + OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; GLRRenderPassAction color = (GLRRenderPassAction)rp.color; GLRRenderPassAction depth = (GLRRenderPassAction)rp.depth; @@ -1439,7 +1438,7 @@ bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, in return true; } -void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { +void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; _assert_(binding < MAX_TEXTURE_SLOTS); diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index a3bbf1f0ea..8a69c0f037 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -608,8 +608,7 @@ void VulkanContext::ChooseDevice(int physical_device) { deviceFeatures_.enabled.standard.geometryShader = deviceFeatures_.available.standard.geometryShader; deviceFeatures_.enabled.multiview = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; - // Don't yet enable these. - // deviceFeatures_.enabled.multiview.multiview = deviceFeatures_.available.multiview.multiview; + deviceFeatures_.enabled.multiview.multiview = deviceFeatures_.available.multiview.multiview; // deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader; GetDeviceLayerExtensionList(nullptr, device_extension_properties_); @@ -1246,7 +1245,7 @@ bool VulkanContext::CreateShaderModule(const std::vector &spirv, VkSha } } -void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask, +void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) { @@ -1259,7 +1258,7 @@ void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int image_memory_barrier.subresourceRange.aspectMask = aspectMask; image_memory_barrier.subresourceRange.baseMipLevel = baseMip; image_memory_barrier.subresourceRange.levelCount = numMipLevels; - image_memory_barrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. + image_memory_barrier.subresourceRange.layerCount = numLayers; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index 60ef6d373e..a7622e7a8f 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -441,7 +441,7 @@ private: }; // Detailed control. -void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, VkImageAspectFlags aspectMask, +void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); diff --git a/Common/GPU/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp index 72eb339c12..ad712b6a0f 100644 --- a/Common/GPU/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -87,7 +87,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i switch (initialLayout) { case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: case VK_IMAGE_LAYOUT_GENERAL: - TransitionImageLayout2(cmd, image_, 0, numMips, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT); @@ -164,7 +164,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo _assert_msg_(firstMipToGenerate < numMips_, "Can't generate levels beyond storage"); // Transition the pre-set levels to GENERAL. - TransitionImageLayout2(cmd, image_, 0, firstMipToGenerate, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, image_, 0, firstMipToGenerate, 1, VK_IMAGE_ASPECT_COLOR_BIT, fromCompute ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, fromCompute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -173,7 +173,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo VK_ACCESS_TRANSFER_READ_BIT); // Do the same with the uninitialized levels. - TransitionImageLayout2(cmd, image_, firstMipToGenerate, numMips_ - firstMipToGenerate, + TransitionImageLayout2(cmd, image_, firstMipToGenerate, numMips_ - firstMipToGenerate, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, @@ -206,7 +206,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo vkCmdBlitImage(cmd, image_, VK_IMAGE_LAYOUT_GENERAL, image_, VK_IMAGE_LAYOUT_GENERAL, 1, &blit, VK_FILTER_LINEAR); - TransitionImageLayout2(cmd, image_, mip, 1, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, image_, mip, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); @@ -214,7 +214,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo } void VulkanTexture::EndCreate(VkCommandBuffer cmd, bool vertexTexture, VkPipelineStageFlags prevStage, VkImageLayout layout) { - TransitionImageLayout2(cmd, image_, 0, numMips_, + TransitionImageLayout2(cmd, image_, 0, numMips_, 1, VK_IMAGE_ASPECT_COLOR_BIT, layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, prevStage, vertexTexture ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, diff --git a/Common/GPU/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h index 79a71d4ce6..c0a9c1ed02 100644 --- a/Common/GPU/Vulkan/VulkanMemory.h +++ b/Common/GPU/Vulkan/VulkanMemory.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -121,6 +122,15 @@ public: return writePtr_ + off; } + template + void PushUBOData(const T &data, VkDescriptorBufferInfo *info) { + uint32_t bindOffset; + void *ptr = PushAligned(sizeof(T), &bindOffset, &info->buffer, vulkan_->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment); + memcpy(ptr, &data, sizeof(T)); + info->offset = bindOffset; + info->range = sizeof(T); + } + size_t GetTotalSize() const; private: diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 5873c3e974..07371dfba9 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -249,7 +249,7 @@ bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) { vulkan_->SetDebugName(depth_.image, VK_OBJECT_TYPE_IMAGE, "BackbufferDepth"); - TransitionImageLayout2(cmd, depth_.image, 0, 1, + TransitionImageLayout2(cmd, depth_.image, 0, 1, 1, aspectMask, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, @@ -331,6 +331,10 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas bool hasDepth = RenderPassTypeHasDepth(rpType); bool multiview = RenderPassTypeHasMultiView(rpType); + if (multiview) { + // TODO: Assert that the device has multiview support enabled. + } + VkAttachmentDescription attachments[2] = {}; attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; @@ -905,6 +909,10 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { case RP_TYPE_COLOR_DEPTH: renderCmd = "RENDER_DEPTH"; break; case RP_TYPE_COLOR_INPUT: renderCmd = "RENDER_INPUT"; break; case RP_TYPE_COLOR_DEPTH_INPUT: renderCmd = "RENDER_DEPTH_INPUT"; break; + case RP_TYPE_MULTIVIEW_COLOR: renderCmd = "MV_RENDER"; break; + case RP_TYPE_MULTIVIEW_COLOR_DEPTH: renderCmd = "MV_RENDER_DEPTH"; break; + case RP_TYPE_MULTIVIEW_COLOR_INPUT: renderCmd = "MV_RENDER_INPUT"; break; + case RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT: renderCmd = "MV_RENDER_DEPTH_INPUT"; break; default: renderCmd = "N/A"; } snprintf(buffer, sizeof(buffer), "%s %s %s (draws: %d, %dx%d/%dx%d)", renderCmd, step.tag, step.render.framebuffer ? step.render.framebuffer->Tag() : "", step.render.numDraws, actual_w, actual_h, w, h); @@ -1565,6 +1573,10 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c vkCmdDraw(cmd, c.draw.count, 1, c.draw.offset, 0); break; + case VKRRenderCommand::BIND_DESCRIPTOR_SET: + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, c.bindDescSet.setIndex, 1, &c.bindDescSet.descSet, 0, nullptr); + break; + case VKRRenderCommand::CLEAR: { // If we get here, we failed to merge a clear into a render pass load op. This is bad for perf. @@ -1643,7 +1655,8 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR renderPass = GetRenderPass(key); VKRFramebuffer *fb = step.render.framebuffer; - framebuf = fb->Get(renderPass, step.render.renderPassType); + framebuf = fb->Get(renderPass, step.render.renderPassType, step.render.layer); + _dbg_assert_(framebuf != VK_NULL_HANDLE); w = fb->width; h = fb->height; @@ -2014,7 +2027,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd if (step.readback.src == nullptr) { // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. - TransitionImageLayout2(cmd, backbufferImage_, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT); @@ -2048,7 +2061,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd if (step.readback.src == nullptr) { // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. - TransitionImageLayout2(cmd, backbufferImage_, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_TRANSFER_READ_BIT, 0); @@ -2079,7 +2092,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe vkCmdCopyImageToBuffer(cmd, step.readback_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuffer_, 1, ®ion); // Now transfer it back to a texture. - TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, + TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, 1, // TODO: Handle multiple layers VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index d5ea7163ed..d51f2b638b 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -37,12 +37,13 @@ enum class VKRRenderCommand : uint8_t { DRAW, DRAW_INDEXED, PUSH_CONSTANTS, + BIND_DESCRIPTOR_SET, SELF_DEPENDENCY_BARRIER, DEBUG_ANNOTATION, NUM_RENDER_COMMANDS, }; -enum class PipelineFlags { +enum class PipelineFlags : u8 { NONE = 0, USES_BLEND_CONSTANT = (1 << 1), USES_DEPTH_STENCIL = (1 << 2), // Reads or writes the depth or stencil buffers. @@ -115,7 +116,7 @@ struct VkRenderData { VkDescriptorSet ds; int numUboOffsets; uint32_t uboOffsets[3]; - VkBuffer vbuffer; // might need to increase at some point + VkBuffer vbuffer; VkBuffer ibuffer; uint32_t voffset; uint32_t ioffset; @@ -152,6 +153,10 @@ struct VkRenderData { struct { const char *annotation; } debugAnnotation; + struct { + uint32_t setIndex; + VkDescriptorSet descSet; + } bindDescSet; }; }; @@ -207,6 +212,7 @@ struct VKRStep { VKRRenderPassStoreAction depthStore; VKRRenderPassStoreAction stencilStore; u8 clearStencil; + s8 layer; uint32_t clearColor; float clearDepth; int numDraws; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index a3bce70e0d..b19112f4b2 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -182,43 +182,51 @@ void VKRFramebuffer::UpdateTag(const char *newTag) { vulkan_->SetDebugName(depth.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name); } for (int rpType = 0; rpType < RP_TYPE_COUNT; rpType++) { - if (framebuf[rpType]) { - snprintf(name, sizeof(name), "fb_%s", tag_.c_str()); - vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name); + for (int i = 0; i < 2; i++) { + if (framebuf[rpType][i]) { + snprintf(name, sizeof(name), "fb_%s_%d", tag_.c_str(), i); + vulkan_->SetDebugName(framebuf[(int)rpType][i], VK_OBJECT_TYPE_FRAMEBUFFER, name); + } } } } -VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) { - if (framebuf[(int)rpType]) { - return framebuf[(int)rpType]; +VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType, int layer) { + bool multiview = RenderPassTypeHasMultiView(rpType); + + if (RenderPassTypeHasMultiView(rpType)) { + _dbg_assert_(layer == -1); + layer = 0; + } + + if (framebuf[(int)rpType][layer]) { + return framebuf[(int)rpType][layer]; } VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; VkImageView views[2]{}; - bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT; - - views[0] = color.imageView; + bool hasDepth = RenderPassTypeHasDepth(rpType); + views[0] = (multiview || numLayers == 0) ? color.imageView : color.layerViews[layer]; if (hasDepth) { _dbg_assert_(depth.imageView != VK_NULL_HANDLE); - views[1] = depth.imageView; + views[1] = (multiview || numLayers == 0) ? depth.imageView : depth.layerViews[layer]; } fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); fbci.attachmentCount = hasDepth ? 2 : 1; fbci.pAttachments = views; fbci.width = width; fbci.height = height; - fbci.layers = 1; + fbci.layers = 1; // With multiview, this should be set as 1. - VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]); + VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType][layer]); _assert_(res == VK_SUCCESS); if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) { - vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str()); + vulkan_->SetDebugName(framebuf[(int)rpType][layer], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s_%d", tag_.c_str(), layer).c_str()); } - return framebuf[(int)rpType]; + return framebuf[(int)rpType][layer]; } VKRFramebuffer::~VKRFramebuffer() { @@ -236,13 +244,27 @@ VKRFramebuffer::~VKRFramebuffer() { } if (depth.depthSampleView) vulkan_->Delete().QueueDeleteImageView(depth.depthSampleView); + for (int i = 0; i < 2; i++) { + if (color.layerViews[i]) { + vulkan_->Delete().QueueDeleteImageView(color.layerViews[i]); + } + if (depth.layerViews[i]) { + vulkan_->Delete().QueueDeleteImageView(depth.layerViews[i]); + } + } for (auto &fb : framebuf) { - if (fb) - vulkan_->Delete().QueueDeleteFramebuffer(fb); + for (int i = 0; i < 2; i++) { + if (fb[i]) { + vulkan_->Delete().QueueDeleteFramebuffer(fb[i]); + } + } } } void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { + // We don't support more exotic layer setups for now. Mono or stereo. + _dbg_assert_(numLayers == 1 || numLayers == 2); + VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; ici.arrayLayers = numLayers; ici.mipLevels = 1; @@ -275,11 +297,12 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; ivci.format = ici.format; ivci.image = img.image; - ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; + ivci.viewType = numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY; ivci.subresourceRange.aspectMask = aspects; - ivci.subresourceRange.layerCount = 1; + ivci.subresourceRange.layerCount = numLayers; ivci.subresourceRange.levelCount = 1; res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.imageView); + _dbg_assert_(res == VK_SUCCESS); // Separate view for texture sampling that only exposes depth. @@ -291,6 +314,18 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int img.depthSampleView = VK_NULL_HANDLE; } + // Create 2D views for both layers, if layered. + // Useful when multipassing shaders that don't yet exist in a single-pass-stereo version. + if (numLayers == 2) { + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; + ivci.subresourceRange.layerCount = 1; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.layerViews[0]); + _dbg_assert_(res == VK_SUCCESS); + ivci.subresourceRange.baseArrayLayer = 1; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.layerViews[1]); + _dbg_assert_(res == VK_SUCCESS); + } + VkPipelineStageFlags dstStage; VkAccessFlagBits dstAccessMask; switch (initialLayout) { @@ -311,12 +346,11 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int return; } - TransitionImageLayout2(cmd, img.image, 0, 1, aspects, + TransitionImageLayout2(cmd, img.image, 0, 1, numLayers, aspects, VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, 0, dstAccessMask); img.layout = initialLayout; - img.format = format; img.tag = tag ? tag : "N/A"; } @@ -710,10 +744,18 @@ void VulkanRenderManager::EndCurRenderStep() { RenderPassType rpType = depthStencil ? RP_TYPE_COLOR_DEPTH : RP_TYPE_COLOR; if (!curRenderStep_->render.framebuffer) { rpType = RP_TYPE_BACKBUFFER; - } else if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) { - // Not allowed on backbuffers. - rpType = depthStencil ? RP_TYPE_COLOR_DEPTH_INPUT : RP_TYPE_COLOR_INPUT; + } else { + if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) { + // Not allowed on backbuffers. + rpType = depthStencil ? RP_TYPE_COLOR_DEPTH_INPUT : RP_TYPE_COLOR_INPUT; + } + // Framebuffers can be stereo, and if so, will control the render pass type to match. + // Pipelines can be mono and render fine to stereo etc, so not checking them here. + if (curRenderStep_->render.framebuffer->numLayers > 1) { + rpType = (RenderPassType)(rpType | RP_TYPE_MULTIVIEW_COLOR); + } } + // TODO: Also add render pass types for depth/stencil-less. VKRRenderPass *renderPass = queueRunner_.GetRenderPass(key); @@ -752,7 +794,7 @@ void VulkanRenderManager::BindCurrentFramebufferAsInputAttachment0(VkImageAspect curRenderStep_->commands.push_back(VkRenderData{ VKRRenderCommand::SELF_DEPENDENCY_BARRIER }); } -void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) { +void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, int layer, const char *tag) { _dbg_assert_(insideFrame_); // Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible. if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) { @@ -833,6 +875,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR VKRStep *step = new VKRStep{ VKRStepType::RENDER }; step->render.framebuffer = fb; + step->render.layer = layer; step->render.colorLoad = color; step->render.depthLoad = depth; step->render.stencilLoad = stencil; @@ -1175,7 +1218,7 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, steps_.push_back(step); } -VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit) { +VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit, int layer) { _dbg_assert_(curRenderStep_ != nullptr); // We don't support texturing from stencil, neither do we support texturing from depth|stencil together (nonsensical). @@ -1210,7 +1253,12 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in // Add this pretransition unless we already have it. TransitionRequest rq{ fb, aspectBit, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; curRenderStep_->preTransitions.insert(rq); // Note that insert avoids inserting duplicates. - return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; + + if (layer == -1 || (layer == 0 && fb->numLayers == 1)) { + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; + } else { + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.layerViews[layer] : fb->depth.layerViews[layer]; + } } // Called on main thread. diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 97771514e0..4247157809 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -24,13 +24,19 @@ // Forward declaration VK_DEFINE_HANDLE(VmaAllocation); -// Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine -// to let them have individual non-pooled allocations. Until it's not fine. We'll see. +// Simple independent framebuffer image. struct VKRImage { // These four are "immutable". VkImage image; + + // These are 2D if single layer, 2D_ARRAY if multiple. Need to take that into account when picking + // shaders, or use layerViews below and multiple passes to work around it. VkImageView imageView; VkImageView depthSampleView; + + // If it's a layered image (for stereo), this is two 2D views of it, to make it compatible with shaders that don't yet support stereo. + VkImageView layerViews[2]{}; + VmaAllocation alloc; VkFormat format; @@ -40,6 +46,9 @@ struct VKRImage { // For debugging. std::string tag; }; + +// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. +// This requires a different sampling path! void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); class VKRFramebuffer { @@ -47,7 +56,7 @@ public: VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag); ~VKRFramebuffer(); - VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); + VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType, int layer); int width = 0; int height = 0; @@ -65,7 +74,7 @@ public: // TODO: Hide. VulkanContext *vulkan_; private: - VkFramebuffer framebuf[RP_TYPE_COUNT]{}; + VkFramebuffer framebuf[RP_TYPE_COUNT][2]{}; std::string tag_; }; @@ -213,7 +222,7 @@ public: // Zaps queued up commands. Use if you know there's a risk you've queued up stuff that has already been deleted. Can happen during in-game shutdown. void Wipe(); - // This starts a new step containing a render pass. + // This starts a new step containing a render pass (unless it can be trivially merged into the previous one, which is pretty common). // // After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce // making any new render state changes or draw calls. @@ -228,11 +237,16 @@ public: // // It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're // not keeping track of your calls to this function on your own. - void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag); + // + // For layer, we use the same convention as thin3d, where layer = -1 means all layers together. For texturing, that means that you + // get an array texture view. + void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, int layer, const char *tag); // Returns an ImageView corresponding to a framebuffer. Is called BindFramebufferAsTexture to maintain a similar interface // as the other backends, even though there's no actual binding happening here. - VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits); + // For layer, we use the same convention as thin3d, where layer = -1 means all layers together. For texturing, that means that you + // get an array texture view. + VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits, int layer); void BindCurrentFramebufferAsInputAttachment0(VkImageAspectFlags aspectBits); @@ -256,6 +270,15 @@ public: compileMutex_.unlock(); } + // We always pass in desc set 0 directly in draw commands. This is used only to bind higher descriptor sets. + void BindDescriptorSet(int index, const VkDescriptorSet descSet) { + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::BIND_DESCRIPTOR_SET }; + data.bindDescSet.setIndex = index; + data.bindDescSet.descSet = descSet; + curRenderStep_->commands.push_back(data); + } + void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 0c03d240ed..d3b0d8581c 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -404,11 +404,8 @@ public: DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return (Framebuffer *)curFramebuffer_.ptr; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void BindCurrentFramebufferForColorInput() override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1505,7 +1502,7 @@ private: Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.z_stencil, desc.numLayers, desc.tag); + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.z_stencil, desc.tag); return new VKFramebuffer(vkrfb); } @@ -1556,17 +1553,17 @@ DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) { return DrawContext::PreferredFramebufferReadbackFormat(src); } -void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { +void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { VKFramebuffer *fb = (VKFramebuffer *)fbo; VKRRenderPassLoadAction color = (VKRRenderPassLoadAction)rp.color; VKRRenderPassLoadAction depth = (VKRRenderPassLoadAction)rp.depth; VKRRenderPassLoadAction stencil = (VKRRenderPassLoadAction)rp.stencil; - renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, tag); + renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, layer, tag); curFramebuffer_ = fb; } -void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) { +void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { VKFramebuffer *fb = (VKFramebuffer *)fbo; _assert_(binding < MAX_BOUND_TEXTURES); @@ -1588,7 +1585,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne } boundTextures_[binding] = nullptr; - boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect); + boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, layer); } void VKContext::BindCurrentFramebufferForColorInput() { diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 7c3a6d240d..f2c886c054 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -415,9 +415,11 @@ class Framebuffer : public RefCountedObject { public: int Width() { return width_; } int Height() { return height_; } + int Layers() { return layers_; } + virtual void UpdateTag(const char *tag) {} protected: - int width_ = -1, height_ = -1; + int width_ = -1, height_ = -1, layers_ = 1; }; class Buffer : public RefCountedObject { @@ -593,6 +595,8 @@ struct RenderPassInfo { const char *tag; }; +const int ALL_LAYERS = -1; + class DrawContext { public: virtual ~DrawContext(); @@ -654,11 +658,10 @@ public: // These functions should be self explanatory. // Binding a zero render target means binding the backbuffer. - virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) = 0; - virtual Framebuffer *GetCurrentRenderTarget() = 0; + virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) = 0; // binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2). - virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) = 0; + virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) = 0; // Framebuffer fetch / input attachment support, needs to be explicit in Vulkan. virtual void BindCurrentFramebufferForColorInput() {} diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 41ec1bb76d..6bdd4382d9 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -85,7 +85,7 @@ void UIScreen::preRender() { } draw->BeginFrame(); // Bind and clear the back buffer - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); + draw->BindFramebufferAsRenderTarget(nullptr, ALL_LAYERS, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); screenManager()->getUIContext()->BeginFrame(); Draw::Viewport viewport; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 223cd7976f..b27aba7334 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -89,6 +89,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool doTextureProjection = id.Bit(FS_BIT_DO_TEXTURE_PROJ); bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA); + bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE); + bool arrayTextureFramebuffer = id.Bit(FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE); + bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled; bool doFlatShading = id.Bit(FS_BIT_FLATSHADE) && !flatBug; @@ -155,11 +158,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); if (doTexture) { - WRITE(p, "layout (binding = 0) uniform %s tex;\n", texture3D ? "sampler3D" : "sampler2D"); + WRITE(p, "layout (binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "array" : ""); } if (readFramebufferTex) { - WRITE(p, "layout (binding = 1) uniform sampler2D fbotex;\n"); + WRITE(p, "layout (binding = 1) uniform sampler2D%s fbotex;\n", arrayTextureFramebuffer ? "array" : ""); } else if (fetchFramebuffer) { WRITE(p, "layout (input_attachment_index = 0, binding = 9) uniform subpassInput inputColor;\n"); if (fragmentShaderFlags) { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 07f933778f..6809922dd9 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -863,7 +863,7 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra if (currentRenderVfb_ && dst != currentRenderVfb_ && tookActions) { // Will probably just change the name of the current renderpass, since one was started by the reinterpret itself. - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After Reinterpret"); + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After Reinterpret"); } shaderManager_->DirtyLastShader(); @@ -1011,7 +1011,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe if (useBufferedRendering_) { if (vfb->fbo) { shaderManager_->DirtyLastShader(); - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "FBSwitch"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, {Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP}, "FBSwitch"); } else { // This should only happen very briefly when toggling useBufferedRendering_. ResizeFramebufFBO(vfb, vfb->width, vfb->height, true); @@ -1115,7 +1115,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int } else { flags = DRAWTEX_LINEAR; } - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); SetViewport2D(0, 0, vfb->renderWidth, vfb->renderHeight); draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight); } else { @@ -1153,7 +1153,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int } } -bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { +bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer) { if (!framebuffer->fbo || !useBufferedRendering_) { draw_->BindTexture(stage, nullptr); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; @@ -1173,17 +1173,17 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF if (renderCopy) { VirtualFramebuffer copyInfo = *framebuffer; copyInfo.fbo = renderCopy; - CopyFramebufferForColorTexture(©Info, framebuffer, flags); + CopyFramebufferForColorTexture(©Info, framebuffer, flags, layer); RebindFramebuffer("After BindFramebufferAsColorTexture"); - draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, layer); gpuStats.numCopiesForSelfTex++; } else { // Failed to get temp FBO? Weird. - draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, layer); } return true; } else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) { - draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, layer); return true; } else { ERROR_LOG_REPORT_ONCE(selfTextureFail, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); @@ -1197,7 +1197,7 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF } } -void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags) { +void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer) { int x = 0; int y = 0; int w = src->drawnWidth; @@ -1369,7 +1369,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); // No framebuffer to display! Clear to black. if (useBufferedRendering_) { - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput"); + draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput"); } gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); return; @@ -1433,7 +1433,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { // No framebuffer to display! Clear to black. if (useBufferedRendering_) { // Bind and clear the backbuffer. This should be the first time during the frame that it's bound. - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO"); + draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO"); } gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); return; @@ -1619,7 +1619,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, shaderManager_->DirtyLastShader(); char tag[128]; size_t len = FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, tag }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag }); if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) { NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len); } @@ -1631,7 +1631,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, if (old.fbo) { INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->fb_format)); if (vfb->fbo) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); if (!skipCopy) { BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0, RASTER_COLOR, "BlitColor_ResizeFramebufFBO"); } @@ -1640,9 +1640,9 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } } fbosToDelete_.push_back(old.fbo); - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO"); } else { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); } currentRenderVfb_ = vfb; @@ -1986,7 +1986,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd char name[64]; snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address); textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, name }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, name }); vfbs_.push_back(vfb); u32 byteSize = ColorBufferByteSize(vfb); @@ -2407,7 +2407,8 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u bool z_stencil = reason == TempFBO::STENCIL; char name[128]; snprintf(name, sizeof(name), "temp_fbo_%dx%d%s", w / renderScaleFactor_, h / renderScaleFactor_, z_stencil ? "_depth" : ""); - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, name }); + + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), z_stencil, name }); if (!fbo) { return nullptr; } @@ -2784,10 +2785,10 @@ void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { draw_->InvalidateCachedState(); shaderManager_->DirtyLastShader(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); } else { // Should this even happen? It could while debugging, but maybe we can just skip binding at all. - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad"); + draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad"); } } @@ -2906,7 +2907,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX // This can happen if they recently switched from non-buffered. if (useBufferedRendering_) { // Just bind the back buffer for rendering, forget about doing anything else as we're in a weird state. - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); + draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); } return; } @@ -3029,8 +3030,8 @@ void FramebufferManagerCommon::BlitUsingRaster( // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). draw_->BindTexture(0, nullptr); // This will get optimized away in case it's already bound (in VK and GL at least..) - draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); - draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT); + draw_->BindFramebufferAsRenderTarget(dest, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); + draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); if (destX1 == 0.0f && destY1 == 0.0f && destX2 >= destW && destY2 >= destH) { // We overwrite the whole channel of the framebuffer, so we can invalidate the current contents. @@ -3046,6 +3047,14 @@ void FramebufferManagerCommon::BlitUsingRaster( gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } +int FramebufferManagerCommon::GetFramebufferLayers() const { + int layers = 1; + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + layers = 2; + } + return layers; +} + VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(VirtualFramebuffer *src, GEBufferFormat newFormat) { // Look for an identical framebuffer with the new format _dbg_assert_(src->fb_format != newFormat); @@ -3089,7 +3098,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi char tag[128]; FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, tag }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag }); vfbs_.push_back(vfb); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 5a85d93541..d9f635d208 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -322,7 +322,7 @@ public: // Otherwise it doesn't get called. void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason); - bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); + bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer); void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes); @@ -460,7 +460,7 @@ protected: // Used by ReadFramebufferToMemory and later framebuffer block copies void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, RasterChannel channel, const char *tag); - void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags); + void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer); void EstimateDrawingSize(u32 fb_address, int fb_stride, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int &drawing_width, int &drawing_height); u32 ColorBufferByteSize(const VirtualFramebuffer *vfb) const; @@ -486,6 +486,8 @@ protected: void UpdateFramebufUsage(VirtualFramebuffer *vfb); + int GetFramebufferLayers() const; + static void SetColorUpdated(VirtualFramebuffer *dstBuffer, int skipDrawReason) { dstBuffer->memoryUpdated = false; dstBuffer->clutUpdatedBytes = 0; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index ce3e155c93..36453def3f 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -566,7 +566,7 @@ void PresentationCommon::BindSource(int binding) { if (srcTexture_) { draw_->BindTexture(binding, srcTexture_); } else if (srcFramebuffer_) { - draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); } else { _assert_(false); } @@ -685,13 +685,13 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u PostShaderUniforms uniforms; const auto performShaderPass = [&](const ShaderInfo *shaderInfo, Draw::Framebuffer *postShaderFramebuffer, Draw::Pipeline *postShaderPipeline) { if (postShaderOutput) { - draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); } else { BindSource(0); } BindSource(1); if (shaderInfo->usePreviousFrame) - draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT, 0); int nextWidth, nextHeight; draw_->GetFramebufferDimensions(postShaderFramebuffer, &nextWidth, &nextHeight); @@ -743,7 +743,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u postShaderFramebuffer = previousFramebuffers_[previousIndex_]; } - draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader"); + draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader"); performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline); } @@ -764,7 +764,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u previousIndex_ = 0; Draw::Framebuffer *postShaderFramebuffer = previousFramebuffers_[previousIndex_]; - draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "InterFrameBlit"); + draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "InterFrameBlit"); performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline); } @@ -773,13 +773,13 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u pipeline = postShaderPipelines_.back(); } - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit"); + draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit"); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); draw_->BindPipeline(pipeline); if (postShaderOutput) { - draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); } else { BindSource(0); } diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 78483cf8a5..d7dd5e2c6e 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -362,6 +362,15 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask); + // Stereo support + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + // All framebuffers are array textures in this mode. + if (gstate_c.arrayTexture) { + id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE); + } + id.SetBit(FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE); + } + if (g_Config.bVendorBugChecksEnabled && bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { bool stencilWithoutDepth = !IsStencilTestOutputDisabled() && (!gstate.isDepthTestEnabled() || !gstate.isDepthWriteEnabled()); if (stencilWithoutDepth) { diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 2edf271b6d..120264b628 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -98,6 +98,8 @@ enum FShaderBit : uint8_t { FS_BIT_COLOR_WRITEMASK = 50, FS_BIT_REPLACE_LOGIC_OP = 51, // 4 bits. GE_LOGIC_COPY means no-op/off. FS_BIT_SHADER_DEPAL_MODE = 55, // 2 bits (ShaderDepalMode) + FS_BIT_SAMPLE_ARRAY_TEXTURE = 57, // For multiview, framebuffers are array textures and we need to sample the two layers correctly. + FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE = 58, // Framebuffer texture might also be stereo. }; static inline FShaderBit operator +(FShaderBit bit, int i) { diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index c746179316..96cfe98411 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -131,6 +131,16 @@ static const char * const ub_vs_bonesStr = R"( mat3x4 u_bone0; mat3x4 u_bone1; mat3x4 u_bone2; mat3x4 u_bone3; mat3x4 u_bone4; mat3x4 u_bone5; mat3x4 u_bone6; mat3x4 u_bone7; mat3x4 u_bone8; )"; + +static const char * const ub_frame_globalstr = +R"( vec4 unused; +)"; + +// VR stuff will go here. +struct UB_FrameGlobal { + float unused[4]; +}; + void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ); void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport, bool useBufferedRendering); diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 682d8a1f0c..dfa36fe0e7 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -187,7 +187,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, // Otherwise, we can skip alpha in many cases, in which case we don't even use a shader. if (flags & WriteStencil::IGNORE_ALPHA) { if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Clear"); + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Clear"); } return true; } @@ -281,9 +281,9 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, Draw::Framebuffer *blitFBO = nullptr; if (useBlit) { blitFBO = GetTempFBO(TempFBO::STENCIL, w, h); - draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Blit"); + draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Blit"); } else if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_NoBlit"); + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_NoBlit"); } Draw::Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index a1ed25094b..3c288b13f4 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -2121,7 +2121,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture. BindAsClutTexture(clutTexture.texture, smoothedDepal); - framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); + framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, 0); // Vulkan needs to do some extra work here to pick out the native handle from Draw. BoundFramebufferTexture(); @@ -2191,13 +2191,13 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(TempFBO::DEPAL, depalWidth, framebuffer->renderHeight); draw_->BindTexture(0, nullptr); draw_->BindTexture(1, nullptr); - draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); + draw_->BindFramebufferAsRenderTarget(depalFBO, Draw::ALL_LAYERS, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT); draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1); Draw::Viewport vp{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f }; draw_->SetViewports(1, &vp); - draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, 0); draw_->BindTexture(1, clutTexture.texture); Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false); Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(smoothedDepal); @@ -2213,7 +2213,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer draw_->BindTexture(0, nullptr); framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); BoundFramebufferTexture(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); @@ -2226,7 +2226,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer shaderManager_->DirtyLastShader(); } else { framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); + framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, 0); BoundFramebufferTexture(); gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF); @@ -2292,14 +2292,14 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(TempFBO::DEPAL, texWidth, texHeight); draw_->BindTexture(0, nullptr); draw_->BindTexture(1, nullptr); - draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); + draw_->BindFramebufferAsRenderTarget(depalFBO, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT); draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1); Draw::Viewport vp{ 0.0f, 0.0f, (float)texWidth, (float)texHeight, 0.0f, 1.0f }; draw_->SetViewports(1, &vp); draw_->BindNativeTexture(0, GetNativeTextureView(entry)); - draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT, 0); Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false); Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(false); draw_->BindSamplerStates(0, 1, &nearest); @@ -2314,7 +2314,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { draw_->BindTexture(0, nullptr); framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT); + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); BoundFramebufferTexture(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index a902401122..efbbcad31b 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -159,7 +159,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { ApplyStencilReplaceAndLogicOpIgnoreBlend(blendState.replaceAlphaWithStencil, blendState); if (fboTexBindState == FBO_TEX_COPY_BIND_TEX) { - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0); // No sampler required, we do a plain Load in the pixel shader. fboTexBound_ = true; fboTexBindState = FBO_TEX_NONE; diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index bc1af41143..951a401189 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -101,7 +101,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { if (fboTexBindState_ = FBO_TEX_COPY_BIND_TEX) { // Note that this is positions, not UVs, that we need the copy from. - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0); // If we are rendering at a higher resolution, linear is probably best for the dest color. device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); @@ -139,7 +139,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) { // Note that this is positions, not UVs, that we need the copy from. - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS); // If we are rendering at a higher resolution, linear is probably best for the dest color. device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 5f783e48c7..e54d249061 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -204,11 +204,11 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int shaderManager_->DirtyLastShader(); auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height()); - draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync"); + draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync"); Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }; draw_->SetViewports(1, &viewport); - draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT); + draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT, 0); draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &depthReadbackSampler_); // We must bind the program after starting the render pass. @@ -322,11 +322,11 @@ bool FramebufferManagerGLES::ReadbackStencilbufferSync(Draw::Framebuffer *fbo, i shaderManager_->DirtyLastShader(); auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height()); - draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackStencilbufferSync"); + draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackStencilbufferSync"); Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }; draw_->SetViewports(1, &viewport); - draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT); + draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT, 0); draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilReadbackSampler_); // We must bind the program after starting the render pass. diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 9d1dc8d3dd..50ba4bfd99 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -54,9 +54,9 @@ void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) // Discard the previous contents of this buffer where possible. if (gl_extensions.GLES3) { - draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "UpdateDownloadTempBuffer"); + draw_->BindFramebufferAsRenderTarget(nvfb->fbo, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "UpdateDownloadTempBuffer"); } else if (gl_extensions.IsGLES) { - draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "UpdateDownloadTempBuffer"); + draw_->BindFramebufferAsRenderTarget(nvfb->fbo, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "UpdateDownloadTempBuffer"); gstate_c.Dirty(DIRTY_BLEND_STATE); } } diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 0b8f45c3c6..f80a3f5490 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -158,7 +158,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { // fboTexNeedsBind_ won't be set if we can read directly from the target. if (fboTexBindState == FBO_TEX_COPY_BIND_TEX) { // Note that this is positions, not UVs, that we need the copy from. - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0); // If we are rendering at a higher resolution, linear is probably best for the dest color. renderManager->SetTextureSampler(1, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_LINEAR, GL_LINEAR, 0.0f); fboTexBound_ = true; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index e7a15e9536..b323fc1067 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -583,6 +583,7 @@ struct GPUStateCache { bool bgraTexture; bool needShaderTexClamp; + bool arrayTexture; float morphWeights[8]; u32 deferredVertTypeDirty; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 04e3c1d5c7..5e8087b077 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -618,7 +618,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { u1 = 1.0f; } if (!hasImage) { - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam"); + draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam"); return; } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index b24e4b0021..a9702731c9 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -42,6 +42,7 @@ #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/SoftwareTransformCommon.h" #include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/ShaderUniforms.h" #include "GPU/Debugger/Debugger.h" #include "GPU/Vulkan/DrawEngineVulkan.h" #include "GPU/Vulkan/TextureCacheVulkan.h" @@ -184,8 +185,9 @@ void DrawEngineVulkan::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout layouts[1] = { descriptorSetLayout_ }; + pl.setLayoutCount = ARRAY_SIZE(layouts); + pl.pSetLayouts = layouts; pl.flags = 0; res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); _dbg_assert_(VK_SUCCESS == res); @@ -303,6 +305,7 @@ void DrawEngineVulkan::BeginFrame() { frame->pushIndex->Reset(); VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); + frame->pushUBO->Begin(vulkan); frame->pushVertex->Begin(vulkan); frame->pushIndex->Begin(vulkan); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index ebf50e33b5..258f95ae6d 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -211,8 +211,9 @@ private: Draw::DrawContext *draw_; - // We use a single descriptor set layout for all PSP draws. + // We use a shared descriptor set layout for all PSP draws. VkDescriptorSetLayout descriptorSetLayout_; + VkPipelineLayout pipelineLayout_; VulkanPipeline *lastPipeline_; VkDescriptorSet lastDs_ = VK_NULL_HANDLE; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index c46b8b2812..aa5243a8f0 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -268,6 +268,11 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { features |= GPU_ROUND_DEPTH_TO_16BIT; } + if (true) { + features |= GPU_USE_SINGLE_PASS_STEREO; + features &= ~GPU_USE_FRAMEBUFFER_FETCH; // Need to figure out if this can be supported with multiview rendering + } + return features; } diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index c29d2317d9..dbf3ce95cd 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -365,7 +365,7 @@ void DrawEngineVulkan::BindShaderBlendTex() { // Set the nearest/linear here (since we correctly know if alpha/color tests are needed)? if (!gstate.isModeClear()) { if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) { - bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS); _dbg_assert_(bindResult); boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE1_IMAGEVIEW); boundSecondaryIsInputAttachment_ = false; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index bcf5a47a48..f2425d6c41 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1359,9 +1359,9 @@ void EmuScreen::preRender() { if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) { // We need to clear here already so that drawing during the frame is done on a clean slate. if (Core_IsStepping() && gpuStats.numFlips != 0) { - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer"); + draw->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer"); } else { - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer"); + draw->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer"); } Viewport viewport; @@ -1400,7 +1400,7 @@ void EmuScreen::render() { // It's possible this might be set outside PSP_RunLoopFor(). // In this case, we need to double check it here. checkPowerDown(); - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid"); + thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid"); renderUI(); return; } @@ -1439,12 +1439,12 @@ void EmuScreen::render() { // Clear to blue background screen bool dangerousSettings = !Reporting::IsSupported(); uint32_t color = dangerousSettings ? 0xFF900050 : 0xFF900000; - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, color }, "EmuScreen_RuntimeError"); + thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, color }, "EmuScreen_RuntimeError"); // The info is drawn later in renderUI } else { // If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output. // This won't work in non-buffered, but that's fine. - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); + thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); // Just to make sure. if (PSP_IsInited()) { gpu->CopyDisplayToOutput(true); @@ -1456,7 +1456,7 @@ void EmuScreen::render() { // Didn't actually reach the end of the frame, ran out of the blockTicks cycles. // In this case we need to bind and wipe the backbuffer, at least. // It's possible we never ended up outputted anything - make sure we have the backbuffer cleared - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame"); + thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame"); break; } @@ -1470,7 +1470,7 @@ void EmuScreen::render() { if (hasVisibleUI()) { // In most cases, this should already be bound and a no-op. - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_UI"); + thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_UI"); cardboardDisableButton_->SetVisibility(g_Config.bEnableCardboardVR ? UI::V_VISIBLE : UI::V_GONE); screenManager()->getUIContext()->BeginFrame(); renderUI(); diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 63ecbc1691..67d3f25f66 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -1498,6 +1498,7 @@ + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 0706f8fb9c..9575308dd8 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -711,6 +711,9 @@ Other Platforms\SDL + + Resource Files + diff --git a/headless/Headless.cpp b/headless/Headless.cpp index ff5c3f94b4..8d02af8f21 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -240,7 +240,7 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const PSP_EndHostFrame(); if (draw) { - draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless"); + draw->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless"); // Vulkan may get angry if we don't do a final present. if (gpu) gpu->CopyDisplayToOutput(true); From 12d1f94d47274fb0c6ecff20a942107de1fd0573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Oct 2022 16:16:52 +0200 Subject: [PATCH 106/715] Start stereo postshader work --- GPU/Common/PostShader.cpp | 1 + GPU/Common/PostShader.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 2d8529f356..bdfce695c3 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -169,6 +169,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct info.vertexShaderFile = path / temp; section.Get("OutputResolution", &info.outputResolution, false); section.Get("Upscaling", &info.isUpscalingFilter, false); + section.Get("Stereo", &info.isStereo, false); section.Get("SSAA", &info.SSAAFilterLevel, 0); section.Get("60fps", &info.requires60fps, false); section.Get("UsePreviousFrame", &info.usePreviousFrame, false); diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index 5226638078..849ac884f3 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -39,6 +39,8 @@ struct ShaderInfo { bool outputResolution; // Use x1 rendering res + nearest screen scaling filter bool isUpscalingFilter; + // Is used to post-process stereo-rendering to mono, like red/blue. + bool isStereo; // Use 2x display resolution for supersampling with blurry shaders. int SSAAFilterLevel; // Force constant/max refresh for animated filters From 3ce8133656186d4ad4dbb557809a7e31f09d46ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 21 Oct 2022 15:44:38 +0200 Subject: [PATCH 107/715] Non-stereo bugfix --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index b19112f4b2..972bd1ee6e 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -207,10 +207,10 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas VkImageView views[2]{}; bool hasDepth = RenderPassTypeHasDepth(rpType); - views[0] = (multiview || numLayers == 0) ? color.imageView : color.layerViews[layer]; + views[0] = (multiview || numLayers == 1) ? color.imageView : color.layerViews[layer]; if (hasDepth) { _dbg_assert_(depth.imageView != VK_NULL_HANDLE); - views[1] = (multiview || numLayers == 0) ? depth.imageView : depth.layerViews[layer]; + views[1] = (multiview || numLayers == 1) ? depth.imageView : depth.layerViews[layer]; } fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); fbci.attachmentCount = hasDepth ? 2 : 1; From c66873692449ece758c26bce7dfa1345a32ff021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 21 Oct 2022 12:35:49 +0200 Subject: [PATCH 108/715] Add a couple of stereo display shaders, add infrastructure, compile stereo pipelines --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 1 + Core/Config.cpp | 2 + Core/Config.h | 6 +++ GPU/Common/PostShader.cpp | 17 +++++-- GPU/Common/PresentationCommon.cpp | 74 +++++++++++++++++++++++------ GPU/Common/PresentationCommon.h | 5 +- GPU/GPU.vcxproj | 20 ++++++++ GPU/GPU.vcxproj.filters | 6 +++ UI/GameSettingsScreen.cpp | 22 +++++++-- UI/MiscScreens.cpp | 23 ++++++--- UI/MiscScreens.h | 4 +- assets/shaders/defaultshaders.ini | 17 +++++++ assets/shaders/stereo_red_blue.fsh | 34 +++++++++++++ assets/shaders/stereo_sbs.fsh | 18 +++++++ 14 files changed, 218 insertions(+), 31 deletions(-) create mode 100644 assets/shaders/stereo_red_blue.fsh create mode 100644 assets/shaders/stereo_sbs.fsh diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index d3b0d8581c..03fda5f805 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1483,6 +1483,7 @@ public: _assert_msg_(fb, "Null fb in VKFramebuffer constructor"); width_ = fb->width; height_ = fb->height; + layers_ = fb->numLayers; } ~VKFramebuffer() { _assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?"); diff --git a/Core/Config.cpp b/Core/Config.cpp index 1e44ed482b..91457df787 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -888,6 +888,8 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true), ReportedConfigSetting("FrameSkipType", &g_Config.iFrameSkipType, 0, true, true), ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), + ConfigSetting("StereoRendering", &g_Config.bStereoRendering, false, true, true), + ConfigSetting("StereoToMonoShader", &g_Config.sStereoToMonoShader, "RedBlue", true, true), ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true), ConfigSetting("AnalogFrameRate", &g_Config.iAnalogFpsLimit, 240, true, true), diff --git a/Core/Config.h b/Core/Config.h index 497e8266bd..5a89c89732 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -241,6 +241,12 @@ public: std::vector vPostShaderNames; // Off for chain end (only Off for no shader) std::map mPostShaderSetting; + + // Note that this is separate from VR stereo, though it'll share some code paths. + bool bStereoRendering; + // There can only be one, unlike regular post shaders. + std::string sStereoToMonoShader; + bool bShaderChainRequires60FPS; std::string sTextureShaderName; bool bGfxDebugOutput; diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index bdfce695c3..43db9093ac 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -154,9 +154,11 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct continue; } - if (section.Exists("Fragment") && section.Exists("Vertex") && strncasecmp(shaderType.c_str(), "render", shaderType.size()) == 0) { + if (section.Exists("Fragment") && section.Exists("Vertex") && + (strncasecmp(shaderType.c_str(), "render", shaderType.size()) == 0 || + strncasecmp(shaderType.c_str(), "StereoToMono", shaderType.size()) == 0)) { // Valid shader! - ShaderInfo info; + ShaderInfo info{}; std::string temp; info.section = section.name(); @@ -169,7 +171,6 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct info.vertexShaderFile = path / temp; section.Get("OutputResolution", &info.outputResolution, false); section.Get("Upscaling", &info.isUpscalingFilter, false); - section.Get("Stereo", &info.isStereo, false); section.Get("SSAA", &info.SSAAFilterLevel, 0); section.Get("60fps", &info.requires60fps, false); section.Get("UsePreviousFrame", &info.usePreviousFrame, false); @@ -177,6 +178,12 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct if (info.parent == "Off") info.parent.clear(); + if (strncasecmp(shaderType.c_str(), "stereotomono", shaderType.size()) == 0) { + info.isStereo = true; + info.isUpscalingFilter = false; + info.parent.clear(); + } + for (size_t i = 0; i < ARRAY_SIZE(info.settings); ++i) { auto &setting = info.settings[i]; section.Get(StringFromFormat("SettingName%d", i + 1).c_str(), &setting.name, ""); @@ -207,7 +214,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } } else if (section.Exists("Compute") && strncasecmp(shaderType.c_str(), "texture", shaderType.size()) == 0) { // This is a texture shader. - TextureShaderInfo info; + TextureShaderInfo info{}; std::string temp; info.section = section.name(); section.Get("Name", &info.name, section.name().c_str()); @@ -217,6 +224,8 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct if (info.scaleFactor >= 2 && info.scaleFactor < 8) { appendTextureShader(info); } + } else if (!section.name().empty()) { + WARN_LOG(G3D, "Unrecognized shader type '%s' or invalid shader in section '%s' : %d", shaderType.c_str(), section.name().c_str()); } } } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 36453def3f..4350c08049 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -226,7 +226,19 @@ static std::string ReadShaderSrc(const Path &filename) { } // Note: called on resize and settings changes. +// Also takes care of making sure the appropriate stereo shader is compiled. bool PresentationCommon::UpdatePostShader() { + DestroyStereoShader(); + + if (g_Config.bStereoRendering) { + const ShaderInfo *stereoShaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); + bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); + if (!result) { + // We won't have a stereo shader. We have to check for this later. + stereoPipeline_ = nullptr; + } + } + std::vector shaderInfo; if (!g_Config.vPostShaderNames.empty()) { ReloadAllPostShaderInfo(draw_); @@ -517,6 +529,7 @@ void PresentationCommon::DestroyDeviceObjects() { restorePostShader_ = usePostShader_; DestroyPostShader(); + DestroyStereoShader(); } void PresentationCommon::DestroyPostShader() { @@ -529,6 +542,10 @@ void PresentationCommon::DestroyPostShader() { postShaderFBOUsage_.clear(); } +void PresentationCommon::DestroyStereoShader() { + DoRelease(stereoPipeline_); +} + Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) const { std::string translated = src; if (lang != lang_) { @@ -562,13 +579,28 @@ void PresentationCommon::SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidt srcHeight_ = bufferHeight; } -void PresentationCommon::BindSource(int binding) { +// Return value is if stereo binding succeeded. +bool PresentationCommon::BindSource(int binding, bool bindStereo) { if (srcTexture_) { draw_->BindTexture(binding, srcTexture_); + return false; } else if (srcFramebuffer_) { - draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); + if (bindStereo) { + if (srcFramebuffer_->Layers() > 1) { + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); + return true; + } else { + // Single layer + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); + return false; + } + } else { + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); + return false; + } } else { _assert_(false); + return false; } } @@ -584,7 +616,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u // This should auto-disable usePostShader_ and call ShowPostShaderError(). bool useNearest = flags & OutputFlags::NEAREST; - const bool usePostShader = usePostShader_ && !(flags & OutputFlags::RB_SWIZZLE); + bool useStereo = g_Config.bStereoRendering && stereoPipeline_ != nullptr; // TODO: Also check that the backend has support for it. + + const bool usePostShader = usePostShader_ && !useStereo && !(flags & OutputFlags::RB_SWIZZLE); const bool isFinalAtOutputResolution = usePostShader && postShaderFramebuffers_.size() < postShaderPipelines_.size(); Draw::Framebuffer *postShaderOutput = nullptr; int lastWidth = srcWidth_; @@ -687,9 +721,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u if (postShaderOutput) { draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); } else { - BindSource(0); + BindSource(0, false); } - BindSource(1); + BindSource(1, false); if (shaderInfo->usePreviousFrame) draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT, 0); @@ -768,22 +802,30 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline); } - Draw::Pipeline *pipeline = (flags & OutputFlags::RB_SWIZZLE) ? texColorRBSwizzle_ : texColor_; - if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { - pipeline = postShaderPipelines_.back(); - } - draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit"); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); - draw_->BindPipeline(pipeline); + Draw::Pipeline *pipeline = (flags & OutputFlags::RB_SWIZZLE) ? texColorRBSwizzle_ : texColor_; - if (postShaderOutput) { - draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); + if (useStereo) { + draw_->BindPipeline(stereoPipeline_); + if (!BindSource(0, true)) { + // Fall back + draw_->BindPipeline(texColor_); + } } else { - BindSource(0); + if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { + pipeline = postShaderPipelines_.back(); + } + + draw_->BindPipeline(pipeline); + if (postShaderOutput) { + draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); + } else { + BindSource(0, false); + } } - BindSource(1); + BindSource(1, false); if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, &postShaderInfo_.back(), &uniforms); @@ -809,6 +851,8 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u CardboardSettings cardboardSettings; GetCardboardSettings(&cardboardSettings); if (cardboardSettings.enabled) { + // TODO: This could actually support stereo now, with an appropriate shader. + // This is what the left eye sees. setViewport(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); draw_->DrawIndexed(6, 0); diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index c3faff6568..760753b31e 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -107,7 +107,9 @@ public: protected: void CreateDeviceObjects(); void DestroyDeviceObjects(); + void DestroyPostShader(); + void DestroyStereoShader(); static void ShowPostShaderError(const std::string &errorString); @@ -117,7 +119,7 @@ protected: bool BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next, Draw::Pipeline **outPipeline); bool AllocateFramebuffer(int w, int h); - void BindSource(int binding); + bool BindSource(int binding, bool bindStereo); void GetCardboardSettings(CardboardSettings *cardboardSettings) const; void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) const; @@ -131,6 +133,7 @@ protected: Draw::Buffer *idata_ = nullptr; std::vector postShaderPipelines_; + Draw::Pipeline *stereoPipeline_ = nullptr; std::vector postShaderFramebuffers_; std::vector postShaderInfo_; std::vector previousFramebuffers_; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 808ce53635..860dbc38f3 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -652,6 +652,26 @@ true true + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index e110c20b8b..b8a990374a 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -534,5 +534,11 @@ Shaders + + Shaders + + + Shaders + \ No newline at end of file diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 158fc547d0..53b54316e8 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -350,6 +350,22 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); + if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { + graphicsSettings->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering"))); + std::vector stereoShaderNames; + + ChoiceWithValueDisplay *stereoShaderChoice = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, "Stereo display shader", &PostShaderTranslateName)); + stereoShaderChoice->SetEnabledPtr(&g_Config.bStereoRendering); + stereoShaderChoice->OnClick.Add([=](EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto procScreen = new PostProcScreen(gr->T("Stereo display shader"), 0, true); + if (e.v) + procScreen->SetPopupOrigin(e.v); + screenManager()->push(procScreen); + return UI::EVENT_DONE; + }); + } + std::set alreadyAddedShader; for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread @@ -357,7 +373,7 @@ void GameSettingsScreen::CreateViews() { postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&shaderNames_[i], StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1), &PostShaderTranslateName)); postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); - auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i); + auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange); if (e.v) procScreen->SetPopupOrigin(e.v); @@ -365,7 +381,7 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_DONE; }); postProcChoice_->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !g_Config.bStereoRendering; }); // No need for settings on the last one. @@ -388,7 +404,7 @@ void GameSettingsScreen::CreateViews() { } else { PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !g_Config.bStereoRendering; }); } } diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index d90d92f76d..7d5421d0ec 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -521,7 +521,7 @@ void PromptScreen::TriggerFinish(DialogResult result) { UIDialogScreenWithBackground::TriggerFinish(result); } -PostProcScreen::PostProcScreen(const std::string &title, int id) : ListPopupScreen(title), id_(id) { } +PostProcScreen::PostProcScreen(const std::string &title, int id, bool showStereoShaders) : ListPopupScreen(title), id_(id), showStereoShaders_(showStereoShaders) { } void PostProcScreen::CreateViews() { auto ps = GetI18NCategory("PostShaders"); @@ -530,12 +530,16 @@ void PostProcScreen::CreateViews() { std::vector items; int selected = -1; const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_]; + for (int i = 0; i < (int)shaders_.size(); i++) { if (!shaders_[i].visible) continue; + if (shaders_[i].isStereo != showStereoShaders_) + continue; if (shaders_[i].section == selectedName) - selected = i; + selected = (int)indexTranslation_.size(); items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); + indexTranslation_.push_back(i); } adaptor_ = UI::StringVectorListAdaptor(items, selected); ListPopupScreen::CreateViews(); @@ -544,11 +548,16 @@ void PostProcScreen::CreateViews() { void PostProcScreen::OnCompleted(DialogResult result) { if (result != DR_OK) return; - const std::string &value = shaders_[listView_->GetSelected()].section; - if (id_ < (int)g_Config.vPostShaderNames.size()) - g_Config.vPostShaderNames[id_] = value; - else - g_Config.vPostShaderNames.push_back(value); + const std::string &value = shaders_[indexTranslation_[listView_->GetSelected()]].section; + // I feel this logic belongs more in the caller, but eh... + if (showStereoShaders_) { + g_Config.sStereoToMonoShader = value; + } else { + if (id_ < (int)g_Config.vPostShaderNames.size()) + g_Config.vPostShaderNames[id_] = value; + else + g_Config.vPostShaderNames.push_back(value); + } } TextureShaderScreen::TextureShaderScreen(const std::string &title) : ListPopupScreen(title) {} diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 164a06cfec..e799c20828 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -110,7 +110,7 @@ private: class PostProcScreen : public ListPopupScreen { public: - PostProcScreen(const std::string &title, int id); + PostProcScreen(const std::string &title, int id, bool showStereoShaders); void CreateViews() override; @@ -121,6 +121,8 @@ private: bool ShowButtons() const override { return true; } std::vector shaders_; int id_; + bool showStereoShaders_; + std::vector indexTranslation_; }; class TextureShaderScreen : public ListPopupScreen { diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index a125a09206..dbbcbd5c39 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -186,3 +186,20 @@ Name=MMPX (2x) Author=Morgan McGuire and Mara Gagiu Compute=tex_mmpx.csh Scale=2 +[RedBlue] +Type=StereoToMono +Name=Red/Blue glasses (anaglyph) +Author=Henrik Rydgård +SettingName1=ColorPreservation +SettingDefaultValue1=0.5 +SettingMaxValue1=1.0 +SettingMinValue1=1.0 +SettingStep1=0.05 +Fragment=stereo_red_blue.fsh +Vertex=fxaa.vsh +[SideBySize] +Type=StereoToMono +Name=SideBySide Stereo +Author=Henrik Rydgård +Fragment=stereo_sbs.fsh +Vertex=fxaa.vsh diff --git a/assets/shaders/stereo_red_blue.fsh b/assets/shaders/stereo_red_blue.fsh new file mode 100644 index 0000000000..9f0a806db3 --- /dev/null +++ b/assets/shaders/stereo_red_blue.fsh @@ -0,0 +1,34 @@ +// Red/Blue glasses stereo, also known as anaglyph. +// +// NOTE: Will only be compiled for Vulkan so doesn't follow all the usual conventions. + +uniform sampler2DArray sampler0; +varying vec2 v_texcoord0; + +uniform vec4 u_setting; + +void main() { + // To be adjusted. Used to desaturate colors. + vec3 grayDot = vec3(0.35, 0.5, 0.15); + // And these are the output color channels. + vec3 red = vec3(1.0, 0.0, 0.0); + vec3 blue = vec3(0.0, 0.0, 1.0); + // We should probably add the ability to tint the blue one between blue and green + // to match whatever glasses the user has. Not sure if there's any win to adjusting red. + + vec3 left = texture(sampler0, vec3(v_texcoord0, 0.0)).xyz; + vec3 right = texture(sampler0, vec3(v_texcoord0, 1.0)).xyz; + + float leftGray = dot(left, grayDot); + float rightGray = dot(right, grayDot); + + float saturation = u_setting.x; + + vec3 leftColor = mix(vec3(leftGray), left, saturation) * red; + vec3 rightColor = mix(vec3(rightGray), right, saturation) * blue; + + // TODO: Do something to gamma, maybe? + + gl_FragColor.rgb = leftColor + rightColor; + gl_FragColor.a = 1.0; +} diff --git a/assets/shaders/stereo_sbs.fsh b/assets/shaders/stereo_sbs.fsh new file mode 100644 index 0000000000..c308f3aa0d --- /dev/null +++ b/assets/shaders/stereo_sbs.fsh @@ -0,0 +1,18 @@ +// Side by side stereo, useful for old 3D TVs. +// +// NOTE: Will only be compiled for Vulkan so doesn't follow all the usual conventions. + +uniform sampler2DArray sampler0; +varying vec2 v_texcoord0; + +uniform vec4 u_setting; + +void main() { + if (v_texcoord0.x < 0.5) { + gl_FragColor.rgb = texture(sampler0, vec3(v_texcoord0.x * 2.0, v_texcoord0.y, 0.0)).xyz; + } else { + gl_FragColor.rgb = texture(sampler0, vec3((v_texcoord0.x - 0.5) * 2.0, v_texcoord0.y, 1.0)).xyz; + } + + gl_FragColor.a = 1.0; +} From 2e87f0bc0b9e24cf5af05d172af6cf91324106e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 22 Oct 2022 17:34:23 +0200 Subject: [PATCH 109/715] More work. Things are starting to work now. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 1 + GPU/Common/PresentationCommon.cpp | 12 +++++++++++- GPU/Common/PresentationCommon.h | 5 ++++- GPU/Common/ShaderId.cpp | 4 ++++ GPU/Common/ShaderId.h | 2 +- GPU/Common/VertexShaderGenerator.cpp | 26 +++++++++++++++++++------- UI/GameSettingsScreen.cpp | 13 +++++++++++++ assets/shaders/defaultshaders.ini | 7 ++++++- assets/shaders/stereo_red_blue.fsh | 9 ++++----- 9 files changed, 63 insertions(+), 16 deletions(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 03fda5f805..87b30311d7 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -270,6 +270,7 @@ public: } void SetDynamicUniformData(const void *data, size_t size) { + _dbg_assert_(size <= uboSize_); memcpy(ubo_, data, size); } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 4350c08049..fa3ab92c00 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -207,7 +207,7 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer uniforms->gl_HalfPixel[0] = u_pixel_delta * 0.5f; uniforms->gl_HalfPixel[1] = v_pixel_delta * 0.5f; - uniforms->setting[0] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue1"];; + uniforms->setting[0] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue1"]; uniforms->setting[1] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue2"]; uniforms->setting[2] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue3"]; uniforms->setting[3] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue4"]; @@ -235,7 +235,11 @@ bool PresentationCommon::UpdatePostShader() { bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); if (!result) { // We won't have a stereo shader. We have to check for this later. + delete stereoShaderInfo_; + stereoShaderInfo_ = nullptr; stereoPipeline_ = nullptr; + } else { + stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); } } @@ -544,6 +548,8 @@ void PresentationCommon::DestroyPostShader() { void PresentationCommon::DestroyStereoShader() { DoRelease(stereoPipeline_); + delete stereoShaderInfo_; + stereoShaderInfo_ = nullptr; } Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) const { @@ -812,6 +818,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u if (!BindSource(0, true)) { // Fall back draw_->BindPipeline(texColor_); + useStereo = false; // Otherwise we end up uploading the wrong uniforms } } else { if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { @@ -830,6 +837,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, &postShaderInfo_.back(), &uniforms); draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms)); + } else if (useStereo) { + CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, stereoShaderInfo_, &uniforms); + draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms)); } else { Draw::VsTexColUB ub{}; memcpy(ub.WorldViewProj, g_display_rot_matrix.m, sizeof(float) * 16); diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index 760753b31e..d100230a46 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -133,10 +133,13 @@ protected: Draw::Buffer *idata_ = nullptr; std::vector postShaderPipelines_; - Draw::Pipeline *stereoPipeline_ = nullptr; std::vector postShaderFramebuffers_; std::vector postShaderInfo_; std::vector previousFramebuffers_; + + Draw::Pipeline *stereoPipeline_ = nullptr; + ShaderInfo *stereoShaderInfo_ = nullptr; + int previousIndex_ = 0; PostShaderUniforms previousUniforms_{}; diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index d7dd5e2c6e..1acad76ab4 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -92,6 +92,10 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, id.SetBit(VS_BIT_HAS_COLOR, hasColor); id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling); + if (!isModeThrough && VS_BIT_SIMPLE_STEREO) { + id.SetBit(VS_BIT_SIMPLE_STEREO); + } + if (doTexture) { id.SetBit(VS_BIT_DO_TEXTURE); diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 120264b628..de1a6b0985 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -15,7 +15,7 @@ enum VShaderBit : uint8_t { VS_BIT_HAS_COLOR = 3, VS_BIT_DO_TEXTURE = 4, VS_BIT_VERTEX_RANGE_CULLING = 5, - // 6 is free, + VS_BIT_SIMPLE_STEREO = 6, // 7 is free. VS_BIT_USE_HW_TRANSFORM = 8, VS_BIT_HAS_NORMAL = 9, // conditioned on hw transform diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index b0c3cbca50..3eb92c4bcd 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -136,27 +136,33 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool highpFog = false; bool highpTexcoord = false; - std::vector gl_exts; + std::vector extensions; if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (gl_extensions.EXT_gpu_shader4) { - gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); + extensions.push_back("#extension GL_EXT_gpu_shader4 : enable"); } bool useClamp = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH); if (gl_extensions.EXT_clip_cull_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) { - gl_exts.push_back("#extension GL_EXT_clip_cull_distance : enable"); + extensions.push_back("#extension GL_EXT_clip_cull_distance : enable"); } if (gl_extensions.APPLE_clip_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) { - gl_exts.push_back("#extension GL_APPLE_clip_distance : enable"); + extensions.push_back("#extension GL_APPLE_clip_distance : enable"); } if (gl_extensions.ARB_cull_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) { - gl_exts.push_back("#extension GL_ARB_cull_distance : enable"); + extensions.push_back("#extension GL_ARB_cull_distance : enable"); } if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { - gl_exts.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;"); + extensions.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;"); } } - ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts); + bool useSimpleStereo = id.Bit(VS_BIT_SIMPLE_STEREO); + + if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN && useSimpleStereo) { + extensions.push_back("#extension GL_EXT_multiview : enable"); + } + + ShaderWriter p(buffer, compat, ShaderStage::Vertex, extensions); bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); bool lmode = id.Bit(VS_BIT_LMODE); @@ -1341,6 +1347,12 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " }\n"); } + if (useSimpleStereo) { + p.C(" float zFactor = 0.2 * float(gl_ViewIndex * 2 - 1);\n"); + p.C(" float zFocus = 0.0;\n"); + p.C(" gl_Position.x += (-gl_Position.z - zFocus) * zFactor;\n"); + } + if (needsZWHack) { // See comment in thin3d_vulkan.cpp. WRITE(p, " if (%sgl_Position.z == %sgl_Position.w) %sgl_Position.z *= 0.999999;\n", diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 53b54316e8..1d1d9c0125 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -364,6 +364,19 @@ void GameSettingsScreen::CreateViews() { screenManager()->push(procScreen); return UI::EVENT_DONE; }); + const ShaderInfo *shaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); + if (shaderInfo) { + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; + PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetEnabledFunc([] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && g_Config.bStereoRendering; + }); + } + } + } } std::set alreadyAddedShader; diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index dbbcbd5c39..79bb4bb5e6 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -193,8 +193,13 @@ Author=Henrik Rydgård SettingName1=ColorPreservation SettingDefaultValue1=0.5 SettingMaxValue1=1.0 -SettingMinValue1=1.0 +SettingMinValue1=0.0 SettingStep1=0.05 +SettingName2=GreenLevel +SettingDefaultValue2=0.5 +SettingMaxValue2=1.0 +SettingMinValue2=0.0 +SettingStep2=0.05 Fragment=stereo_red_blue.fsh Vertex=fxaa.vsh [SideBySize] diff --git a/assets/shaders/stereo_red_blue.fsh b/assets/shaders/stereo_red_blue.fsh index 9f0a806db3..b8156ee458 100644 --- a/assets/shaders/stereo_red_blue.fsh +++ b/assets/shaders/stereo_red_blue.fsh @@ -8,13 +8,14 @@ varying vec2 v_texcoord0; uniform vec4 u_setting; void main() { + float saturation = u_setting.x; + float greenMix = u_setting.y; + // To be adjusted. Used to desaturate colors. vec3 grayDot = vec3(0.35, 0.5, 0.15); // And these are the output color channels. vec3 red = vec3(1.0, 0.0, 0.0); - vec3 blue = vec3(0.0, 0.0, 1.0); - // We should probably add the ability to tint the blue one between blue and green - // to match whatever glasses the user has. Not sure if there's any win to adjusting red. + vec3 blue = vec3(0.0, greenMix, 1.0); vec3 left = texture(sampler0, vec3(v_texcoord0, 0.0)).xyz; vec3 right = texture(sampler0, vec3(v_texcoord0, 1.0)).xyz; @@ -22,8 +23,6 @@ void main() { float leftGray = dot(left, grayDot); float rightGray = dot(right, grayDot); - float saturation = u_setting.x; - vec3 leftColor = mix(vec3(leftGray), left, saturation) * red; vec3 rightColor = mix(vec3(rightGray), right, saturation) * blue; From 0de12f5ca979207088789cbcf6330f979d657c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 23 Oct 2022 11:21:35 +0200 Subject: [PATCH 110/715] Some refactoring of framebuffer views, layer issues, more work. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 5 +- Common/GPU/D3D9/thin3d_d3d9.cpp | 5 +- Common/GPU/OpenGL/thin3d_gl.cpp | 6 +- Common/GPU/Vulkan/VulkanBarrier.h | 8 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 121 ++++++++++++---------- Common/GPU/Vulkan/VulkanQueueRunner.h | 2 +- Common/GPU/Vulkan/VulkanRenderManager.cpp | 105 +++++++++---------- Common/GPU/Vulkan/VulkanRenderManager.h | 22 ++-- Common/GPU/Vulkan/thin3d_vulkan.cpp | 15 ++- Common/GPU/thin3d.h | 10 +- Common/UI/UIScreen.cpp | 2 +- GPU/Common/FragmentShaderGenerator.cpp | 26 +++-- GPU/Common/FramebufferManagerCommon.cpp | 37 ++++--- GPU/Common/FramebufferManagerCommon.h | 2 - GPU/Common/PresentationCommon.cpp | 6 +- GPU/Common/ShaderId.cpp | 10 +- GPU/Common/ShaderId.h | 2 +- GPU/Common/StencilCommon.cpp | 6 +- GPU/Common/TextureCacheCommon.cpp | 4 +- GPU/GLES/DepthBufferGLES.cpp | 4 +- GPU/GLES/FramebufferManagerGLES.cpp | 4 +- GPU/Software/SoftGpu.cpp | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 13 ++- GPU/Vulkan/StateMappingVulkan.cpp | 5 +- UI/EmuScreen.cpp | 14 +-- assets/shaders/stereo_red_blue.fsh | 2 - headless/Headless.cpp | 2 +- 27 files changed, 237 insertions(+), 203 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index b7972d49ed..aca3aaae93 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -94,7 +94,7 @@ public: bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1655,8 +1655,7 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel return true; } -void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { - _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D +void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { // TODO: deviceContext1 can actually discard. Useful on Windows Mobile. if (fbo) { D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index ba51fb42fa..4c3a83c2f5 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -531,7 +531,7 @@ public: bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) override; @@ -1289,8 +1289,7 @@ D3D9Framebuffer::~D3D9Framebuffer() { } } -void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { - _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support +void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { if (fbo) { D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; device_->SetRenderTarget(0, fb->surf); diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 53f294c35d..fe26e38591 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -354,7 +354,7 @@ public: bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -1395,9 +1395,7 @@ Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) { return fbo; } -void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { - _dbg_assert_(layer == ALL_LAYERS || layer == 0); - +void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; GLRRenderPassAction color = (GLRRenderPassAction)rp.color; GLRRenderPassAction depth = (GLRRenderPassAction)rp.depth; diff --git a/Common/GPU/Vulkan/VulkanBarrier.h b/Common/GPU/Vulkan/VulkanBarrier.h index 19edc548ba..1fefb5adfa 100644 --- a/Common/GPU/Vulkan/VulkanBarrier.h +++ b/Common/GPU/Vulkan/VulkanBarrier.h @@ -14,7 +14,7 @@ class VulkanContext; class VulkanBarrier { public: void TransitionImage( - VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask, + VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask @@ -36,7 +36,7 @@ public: imageBarrier.subresourceRange.aspectMask = aspectMask; imageBarrier.subresourceRange.baseMipLevel = baseMip; imageBarrier.subresourceRange.levelCount = numMipLevels; - imageBarrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. + imageBarrier.subresourceRange.layerCount = numLayers; // NOTE: We could usually use VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS, but really old Mali drivers have problems with those. imageBarrier.subresourceRange.baseArrayLayer = 0; imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -46,7 +46,7 @@ public: // Automatically determines access and stage masks from layouts. // Not universally usable, but works for PPSSPP's use. void TransitionImageAuto( - VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout + VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout ) { _dbg_assert_(image != VK_NULL_HANDLE); @@ -104,7 +104,7 @@ public: imageBarrier.subresourceRange.aspectMask = aspectMask; imageBarrier.subresourceRange.baseMipLevel = baseMip; imageBarrier.subresourceRange.levelCount = numMipLevels; - imageBarrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. + imageBarrier.subresourceRange.layerCount = numLayers; // NOTE: We could usually use VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS, but really old Mali drivers have problems with those. imageBarrier.subresourceRange.baseArrayLayer = 0; imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 07371dfba9..7b314cc0d1 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -37,6 +37,8 @@ RenderPassType MergeRPTypes(RenderPassType a, RenderPassType b) { return a; } + _dbg_assert_((a & RP_TYPE_MULTIVIEW_COLOR) == (b & RP_TYPE_MULTIVIEW_COLOR)); + // The rest we can just OR together to get the maximum feature set. return (RenderPassType)((u32)a | (u32)b); } @@ -166,7 +168,7 @@ bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit) { color_image_view.subresourceRange.baseMipLevel = 0; color_image_view.subresourceRange.levelCount = 1; color_image_view.subresourceRange.baseArrayLayer = 0; - color_image_view.subresourceRange.layerCount = 1; + color_image_view.subresourceRange.layerCount = 1; // TODO: Investigate hw-assisted stereo. color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D; color_image_view.flags = 0; color_image_view.image = sc_buffer.image; @@ -475,6 +477,7 @@ void VulkanQueueRunner::SelfDependencyBarrier(VKRImage &img, VkImageAspectFlags img.image, 0, 1, + img.numLayers, aspect, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, @@ -1167,7 +1170,7 @@ void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) { INFO_LOG(G3D, "%s", StepToString(step).c_str()); } -void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout, VulkanBarrier *recordBarrier) { +void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout, int numLayers, VulkanBarrier *recordBarrier) { if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { VkPipelineStageFlags srcStageMask = 0; VkAccessFlags srcAccessMask = 0; @@ -1200,7 +1203,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout break; } recordBarrier->TransitionImage( - colorImage, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + colorImage, 0, 1, numLayers, VK_IMAGE_ASPECT_COLOR_BIT, colorLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, srcAccessMask, @@ -1236,7 +1239,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout break; } recordBarrier->TransitionImage( - depthStencilImage, 0, 1, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + depthStencilImage, 0, 1, numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, depthStencilLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, srcAccessMask, @@ -1246,7 +1249,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout } } -void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout) { +void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, int numLayers, VkImageLayout depthStencilLayout) { VkPipelineStageFlags srcStageMask = 0; VkPipelineStageFlags dstStageMask = 0; @@ -1288,7 +1291,7 @@ void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayou barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier[0].subresourceRange.baseMipLevel = 0; barrier[0].subresourceRange.levelCount = 1; - barrier[0].subresourceRange.layerCount = 1; + barrier[0].subresourceRange.layerCount = numLayers; barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrierCount++; @@ -1327,7 +1330,7 @@ void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayou barrier[barrierCount].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; barrier[barrierCount].subresourceRange.baseMipLevel = 0; barrier[barrierCount].subresourceRange.levelCount = 1; - barrier[barrierCount].subresourceRange.layerCount = 1; + barrier[barrierCount].subresourceRange.layerCount = numLayers; barrier[barrierCount].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier[barrierCount].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrierCount++; @@ -1345,6 +1348,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c iter.fb->color.image, 0, 1, + iter.fb->numLayers, VK_IMAGE_ASPECT_COLOR_BIT, iter.fb->color.layout, iter.targetLayout @@ -1355,6 +1359,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c iter.fb->depth.image, 0, 1, + iter.fb->numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, iter.fb->depth.layout, iter.targetLayout @@ -1384,6 +1389,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c step.render.framebuffer->color.image, 0, 1, + step.render.framebuffer->numLayers, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -1398,6 +1404,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c step.render.framebuffer->depth.image, 0, 1, + step.render.framebuffer->numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, @@ -1583,7 +1590,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c int numAttachments = 0; VkClearRect rc{}; rc.baseArrayLayer = 0; - rc.layerCount = 1; + rc.layerCount = c.clear.numLayers; rc.rect.extent.width = (uint32_t)curWidth; rc.rect.extent.height = (uint32_t)curHeight; VkClearAttachment attachments[2]{}; @@ -1627,7 +1634,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c if (fb) { // If the desired final layout aren't the optimal layout for rendering, transition. - TransitionFromOptimal(cmd, fb->color.image, step.render.finalColorLayout, fb->depth.image, step.render.finalDepthStencilLayout); + TransitionFromOptimal(cmd, fb->color.image, step.render.finalColorLayout, fb->depth.image, fb->numLayers, step.render.finalDepthStencilLayout); fb->color.layout = step.render.finalColorLayout; fb->depth.layout = step.render.finalDepthStencilLayout; @@ -1655,7 +1662,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR renderPass = GetRenderPass(key); VKRFramebuffer *fb = step.render.framebuffer; - framebuf = fb->Get(renderPass, step.render.renderPassType, step.render.layer); + framebuf = fb->Get(renderPass, step.render.renderPassType); _dbg_assert_(framebuf != VK_NULL_HANDLE); w = fb->width; h = fb->height; @@ -1668,7 +1675,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR step.render.colorLoad == VKRRenderPassLoadAction::CLEAR && vulkan_->GetPhysicalDeviceProperties().properties.driverVersion == 0xaa9c4b29; if (maliBugWorkaround) { - recordBarrier_.TransitionImage(step.render.framebuffer->color.image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + recordBarrier_.TransitionImage(fb->color.image, 0, 1, fb->numLayers, VK_IMAGE_ASPECT_COLOR_BIT, fb->color.layout, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, @@ -1676,7 +1683,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR fb->color.layout = VK_IMAGE_LAYOUT_GENERAL; } - TransitionToOptimal(cmd, fb->color.image, fb->color.layout, fb->depth.image, fb->depth.layout, &recordBarrier_); + TransitionToOptimal(cmd, fb->color.image, fb->color.layout, fb->depth.image, fb->depth.layout, fb->numLayers, &recordBarrier_); // The transition from the optimal format happens after EndRenderPass, now that we don't // do it as part of the renderpass itself anymore. @@ -1746,20 +1753,11 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { VKRFramebuffer *src = step.copy.src; VKRFramebuffer *dst = step.copy.dst; - VkImageCopy copy{}; - copy.srcOffset.x = step.copy.srcRect.offset.x; - copy.srcOffset.y = step.copy.srcRect.offset.y; - copy.srcOffset.z = 0; - copy.srcSubresource.mipLevel = 0; - copy.srcSubresource.layerCount = 1; - copy.dstOffset.x = step.copy.dstPos.x; - copy.dstOffset.y = step.copy.dstPos.y; - copy.dstOffset.z = 0; - copy.dstSubresource.mipLevel = 0; - copy.dstSubresource.layerCount = 1; - copy.extent.width = step.copy.srcRect.extent.width; - copy.extent.height = step.copy.srcRect.extent.height; - copy.extent.depth = 1; + int layerCount = std::min(step.copy.src->numLayers, step.copy.dst->numLayers); + _dbg_assert_(step.copy.src->numLayers >= step.copy.dst->numLayers); + + // TODO: If dst covers exactly the whole destination, we can set up a UNDEFINED->TRANSFER_DST_OPTIMAL transition, + // which can potentially be more efficient. // First source barriers. if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { @@ -1790,6 +1788,21 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { recordBarrier_.Flush(cmd); + VkImageCopy copy{}; + copy.srcOffset.x = step.copy.srcRect.offset.x; + copy.srcOffset.y = step.copy.srcRect.offset.y; + copy.srcOffset.z = 0; + copy.srcSubresource.mipLevel = 0; + copy.srcSubresource.layerCount = layerCount; + copy.dstOffset.x = step.copy.dstPos.x; + copy.dstOffset.y = step.copy.dstPos.y; + copy.dstOffset.z = 0; + copy.dstSubresource.mipLevel = 0; + copy.dstSubresource.layerCount = layerCount; + copy.extent.width = step.copy.srcRect.extent.width; + copy.extent.height = step.copy.srcRect.extent.height; + copy.extent.depth = 1; + if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -1808,35 +1821,12 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { // The barrier code doesn't handle this case. We'd need to transition to GENERAL to do an intra-image copy. _dbg_assert_(step.blit.src != step.blit.dst); + int layerCount = std::min(step.blit.src->numLayers, step.blit.dst->numLayers); + _dbg_assert_(step.blit.src->numLayers >= step.blit.dst->numLayers); + VKRFramebuffer *src = step.blit.src; VKRFramebuffer *dst = step.blit.dst; - // If any validation needs to be performed here, it should probably have been done - // already when the blit was queued. So don't validate here. - VkImageBlit blit{}; - blit.srcOffsets[0].x = step.blit.srcRect.offset.x; - blit.srcOffsets[0].y = step.blit.srcRect.offset.y; - blit.srcOffsets[0].z = 0; - blit.srcOffsets[1].x = step.blit.srcRect.offset.x + step.blit.srcRect.extent.width; - blit.srcOffsets[1].y = step.blit.srcRect.offset.y + step.blit.srcRect.extent.height; - blit.srcOffsets[1].z = 1; - blit.srcSubresource.mipLevel = 0; - blit.srcSubresource.layerCount = 1; - blit.dstOffsets[0].x = step.blit.dstRect.offset.x; - blit.dstOffsets[0].y = step.blit.dstRect.offset.y; - blit.dstOffsets[0].z = 0; - blit.dstOffsets[1].x = step.blit.dstRect.offset.x + step.blit.dstRect.extent.width; - blit.dstOffsets[1].y = step.blit.dstRect.offset.y + step.blit.dstRect.extent.height; - blit.dstOffsets[1].z = 1; - blit.dstSubresource.mipLevel = 0; - blit.dstSubresource.layerCount = 1; - - VkPipelineStageFlags srcStage = 0; - VkPipelineStageFlags dstStage = 0; - - int srcCount = 0; - int dstCount = 0; - // First source barriers. if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { if (src->color.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { @@ -1862,6 +1852,26 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { recordBarrier_.Flush(cmd); + // If any validation needs to be performed here, it should probably have been done + // already when the blit was queued. So don't validate here. + VkImageBlit blit{}; + blit.srcOffsets[0].x = step.blit.srcRect.offset.x; + blit.srcOffsets[0].y = step.blit.srcRect.offset.y; + blit.srcOffsets[0].z = 0; + blit.srcOffsets[1].x = step.blit.srcRect.offset.x + step.blit.srcRect.extent.width; + blit.srcOffsets[1].y = step.blit.srcRect.offset.y + step.blit.srcRect.extent.height; + blit.srcOffsets[1].z = 1; + blit.srcSubresource.mipLevel = 0; + blit.srcSubresource.layerCount = layerCount; + blit.dstOffsets[0].x = step.blit.dstRect.offset.x; + blit.dstOffsets[0].y = step.blit.dstRect.offset.y; + blit.dstOffsets[0].z = 0; + blit.dstOffsets[1].x = step.blit.dstRect.offset.x + step.blit.dstRect.extent.width; + blit.dstOffsets[1].y = step.blit.dstRect.offset.y + step.blit.dstRect.extent.height; + blit.dstOffsets[1].z = 1; + blit.dstSubresource.mipLevel = 0; + blit.dstSubresource.layerCount = layerCount; + if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -1922,6 +1932,7 @@ void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspec img.image, 0, 1, + img.numLayers, imageAspect, img.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -1970,6 +1981,7 @@ void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageAspec img.image, 0, 1, + img.numLayers, aspect, img.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -1999,6 +2011,7 @@ void VulkanQueueRunner::SetupTransferDstWriteAfterWrite(VKRImage &img, VkImageAs img.image, 0, 1, + img.numLayers, aspect, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -2027,6 +2040,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd if (step.readback.src == nullptr) { // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. + // Regarding layers, backbuffer currently only has one layer. TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -2061,6 +2075,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd if (step.readback.src == nullptr) { // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. + // Regarding layers, backbuffer currently only has one layer. TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, @@ -2092,7 +2107,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe vkCmdCopyImageToBuffer(cmd, step.readback_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuffer_, 1, ®ion); // Now transfer it back to a texture. - TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, 1, // TODO: Handle multiple layers + TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, 1, // I don't think we have any multilayer cases for regular textures. Above in PerformReadback, though.. VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index d51f2b638b..ffac3003fa 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -129,6 +129,7 @@ struct VkRenderData { float clearZ; int clearStencil; int clearMask; // VK_IMAGE_ASPECT_COLOR_BIT etc + int numLayers; } clear; struct { VkViewport vp; @@ -212,7 +213,6 @@ struct VKRStep { VKRRenderPassStoreAction depthStore; VKRRenderPassStoreAction stencilStore; u8 clearStencil; - s8 layer; uint32_t clearColor; float clearDepth; int numDraws; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 972bd1ee6e..8c82fa00d1 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -175,42 +175,34 @@ void VKRFramebuffer::UpdateTag(const char *newTag) { char name[128]; snprintf(name, sizeof(name), "fb_color_%s", tag_.c_str()); vulkan_->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, name); - vulkan_->SetDebugName(color.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name); + vulkan_->SetDebugName(color.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); if (depth.image) { snprintf(name, sizeof(name), "fb_depth_%s", tag_.c_str()); vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, name); - vulkan_->SetDebugName(depth.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name); + vulkan_->SetDebugName(depth.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); } for (int rpType = 0; rpType < RP_TYPE_COUNT; rpType++) { - for (int i = 0; i < 2; i++) { - if (framebuf[rpType][i]) { - snprintf(name, sizeof(name), "fb_%s_%d", tag_.c_str(), i); - vulkan_->SetDebugName(framebuf[(int)rpType][i], VK_OBJECT_TYPE_FRAMEBUFFER, name); - } + if (framebuf[rpType]) { + snprintf(name, sizeof(name), "fb_%s", tag_.c_str()); + vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name); } } } -VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType, int layer) { +VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) { bool multiview = RenderPassTypeHasMultiView(rpType); - - if (RenderPassTypeHasMultiView(rpType)) { - _dbg_assert_(layer == -1); - layer = 0; - } - if (framebuf[(int)rpType][layer]) { - return framebuf[(int)rpType][layer]; + if (framebuf[(int)rpType]) { + return framebuf[(int)rpType]; } VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; VkImageView views[2]{}; bool hasDepth = RenderPassTypeHasDepth(rpType); - views[0] = (multiview || numLayers == 1) ? color.imageView : color.layerViews[layer]; + views[0] = color.rtView; // 2D array texture if multilayered. if (hasDepth) { - _dbg_assert_(depth.imageView != VK_NULL_HANDLE); - views[1] = (multiview || numLayers == 1) ? depth.imageView : depth.layerViews[layer]; + views[1] = depth.rtView; } fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); fbci.attachmentCount = hasDepth ? 2 : 1; @@ -219,21 +211,35 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas fbci.height = height; fbci.layers = 1; // With multiview, this should be set as 1. - VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType][layer]); + VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]); _assert_(res == VK_SUCCESS); if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) { - vulkan_->SetDebugName(framebuf[(int)rpType][layer], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s_%d", tag_.c_str(), layer).c_str()); + vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str()); } - return framebuf[(int)rpType][layer]; + return framebuf[(int)rpType]; } VKRFramebuffer::~VKRFramebuffer() { - if (color.imageView) - vulkan_->Delete().QueueDeleteImageView(color.imageView); - if (depth.imageView) - vulkan_->Delete().QueueDeleteImageView(depth.imageView); + // Get rid of the views first, feels cleaner (but in reality doesn't matter). + if (color.rtView) + vulkan_->Delete().QueueDeleteImageView(color.rtView); + if (depth.rtView) + vulkan_->Delete().QueueDeleteImageView(depth.rtView); + if (color.texAllLayersView) + vulkan_->Delete().QueueDeleteImageView(color.texAllLayersView); + if (depth.texAllLayersView) + vulkan_->Delete().QueueDeleteImageView(depth.texAllLayersView); + for (int i = 0; i < 2; i++) { + if (color.texLayerViews[i]) { + vulkan_->Delete().QueueDeleteImageView(color.texLayerViews[i]); + } + if (depth.texLayerViews[i]) { + vulkan_->Delete().QueueDeleteImageView(depth.texLayerViews[i]); + } + } + if (color.image) { _dbg_assert_(color.alloc); vulkan_->Delete().QueueDeleteImageAllocation(color.image, color.alloc); @@ -242,21 +248,9 @@ VKRFramebuffer::~VKRFramebuffer() { _dbg_assert_(depth.alloc); vulkan_->Delete().QueueDeleteImageAllocation(depth.image, depth.alloc); } - if (depth.depthSampleView) - vulkan_->Delete().QueueDeleteImageView(depth.depthSampleView); - for (int i = 0; i < 2; i++) { - if (color.layerViews[i]) { - vulkan_->Delete().QueueDeleteImageView(color.layerViews[i]); - } - if (depth.layerViews[i]) { - vulkan_->Delete().QueueDeleteImageView(depth.layerViews[i]); - } - } for (auto &fb : framebuf) { - for (int i = 0; i < 2; i++) { - if (fb[i]) { - vulkan_->Delete().QueueDeleteFramebuffer(fb[i]); - } + if (fb) { + vulkan_->Delete().QueueDeleteFramebuffer(fb); } } } @@ -301,28 +295,25 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ivci.subresourceRange.aspectMask = aspects; ivci.subresourceRange.layerCount = numLayers; ivci.subresourceRange.levelCount = 1; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.imageView); + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.rtView); _dbg_assert_(res == VK_SUCCESS); - // Separate view for texture sampling that only exposes depth. + // Separate view for texture sampling all layers together. if (!color) { ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.depthSampleView); - _dbg_assert_(res == VK_SUCCESS); - } else { - img.depthSampleView = VK_NULL_HANDLE; } - // Create 2D views for both layers, if layered. + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; // layered for consistency, even if single image. + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texAllLayersView); + + // Create 2D views for both layers. // Useful when multipassing shaders that don't yet exist in a single-pass-stereo version. - if (numLayers == 2) { + for (int i = 0; i < numLayers; i++) { ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; ivci.subresourceRange.layerCount = 1; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.layerViews[0]); - _dbg_assert_(res == VK_SUCCESS); - ivci.subresourceRange.baseArrayLayer = 1; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.layerViews[1]); + ivci.subresourceRange.baseArrayLayer = i; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texLayerViews[i]); _dbg_assert_(res == VK_SUCCESS); } @@ -353,6 +344,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int img.layout = initialLayout; img.format = format; img.tag = tag ? tag : "N/A"; + img.numLayers = numLayers; } VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) @@ -751,6 +743,7 @@ void VulkanRenderManager::EndCurRenderStep() { } // Framebuffers can be stereo, and if so, will control the render pass type to match. // Pipelines can be mono and render fine to stereo etc, so not checking them here. + // Note that we don't support rendering to just one layer of a multilayer framebuffer! if (curRenderStep_->render.framebuffer->numLayers > 1) { rpType = (RenderPassType)(rpType | RP_TYPE_MULTIVIEW_COLOR); } @@ -794,7 +787,7 @@ void VulkanRenderManager::BindCurrentFramebufferAsInputAttachment0(VkImageAspect curRenderStep_->commands.push_back(VkRenderData{ VKRRenderCommand::SELF_DEPENDENCY_BARRIER }); } -void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, int layer, const char *tag) { +void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) { _dbg_assert_(insideFrame_); // Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible. if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) { @@ -833,6 +826,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR data.clear.clearZ = clearDepth; data.clear.clearStencil = clearStencil; data.clear.clearMask = clearMask; + data.clear.numLayers = curRenderStep_->render.framebuffer ? curRenderStep_->render.framebuffer->numLayers : 1; curRenderStep_->commands.push_back(data); curRenderArea_.SetRect(0, 0, curWidth_, curHeight_); } @@ -875,7 +869,6 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR VKRStep *step = new VKRStep{ VKRStepType::RENDER }; step->render.framebuffer = fb; - step->render.layer = layer; step->render.colorLoad = color; step->render.depthLoad = depth; step->render.stencilLoad = stencil; @@ -1254,10 +1247,10 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in TransitionRequest rq{ fb, aspectBit, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; curRenderStep_->preTransitions.insert(rq); // Note that insert avoids inserting duplicates. - if (layer == -1 || (layer == 0 && fb->numLayers == 1)) { - return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; + if (layer == -1) { + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.texAllLayersView : fb->depth.texAllLayersView; } else { - return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.layerViews[layer] : fb->depth.layerViews[layer]; + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.texLayerViews[layer] : fb->depth.texLayerViews[layer]; } } diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 4247157809..cd1e843454 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -29,13 +29,14 @@ struct VKRImage { // These four are "immutable". VkImage image; - // These are 2D if single layer, 2D_ARRAY if multiple. Need to take that into account when picking - // shaders, or use layerViews below and multiple passes to work around it. - VkImageView imageView; - VkImageView depthSampleView; + VkImageView rtView; // Used for rendering to, and readbacks of stencil. 2D if single layer, 2D_ARRAY if multiple. Includes both depth and stencil if depth/stencil. + + // This is for texturing all layers at once. If aspect is depth/stencil, does not include stencil. + VkImageView texAllLayersView; // If it's a layered image (for stereo), this is two 2D views of it, to make it compatible with shaders that don't yet support stereo. - VkImageView layerViews[2]{}; + // If there's only one layer, layerViews[0] only is initialized. + VkImageView texLayerViews[2]{}; VmaAllocation alloc; VkFormat format; @@ -43,6 +44,8 @@ struct VKRImage { // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. VkImageLayout layout; + int numLayers; + // For debugging. std::string tag; }; @@ -56,7 +59,7 @@ public: VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag); ~VKRFramebuffer(); - VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType, int layer); + VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); int width = 0; int height = 0; @@ -74,7 +77,7 @@ public: // TODO: Hide. VulkanContext *vulkan_; private: - VkFramebuffer framebuf[RP_TYPE_COUNT][2]{}; + VkFramebuffer framebuf[RP_TYPE_COUNT]{}; std::string tag_; }; @@ -237,10 +240,7 @@ public: // // It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're // not keeping track of your calls to this function on your own. - // - // For layer, we use the same convention as thin3d, where layer = -1 means all layers together. For texturing, that means that you - // get an array texture view. - void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, int layer, const char *tag); + void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag); // Returns an ImageView corresponding to a framebuffer. Is called BindFramebufferAsTexture to maintain a similar interface // as the other backends, even though there's no actual binding happening here. diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 87b30311d7..fbcc288aa2 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -405,7 +405,7 @@ public: DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) override; // These functions should be self explanatory. - void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override; + void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void BindCurrentFramebufferForColorInput() override; @@ -1555,13 +1555,13 @@ DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) { return DrawContext::PreferredFramebufferReadbackFormat(src); } -void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) { +void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { VKFramebuffer *fb = (VKFramebuffer *)fbo; VKRRenderPassLoadAction color = (VKRRenderPassLoadAction)rp.color; VKRRenderPassLoadAction depth = (VKRRenderPassLoadAction)rp.depth; VKRRenderPassLoadAction stencil = (VKRRenderPassLoadAction)rp.stencil; - renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, layer, tag); + renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, tag); curFramebuffer_ = fb; } @@ -1650,8 +1650,13 @@ uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) { return (uint64_t)GetNullTexture()->GetImageView(); case NativeObject::TEXTURE_VIEW: return (uint64_t)(((VKTexture *)srcObject)->GetImageView()); - case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW: - return (uint64_t)curFramebuffer_->GetFB()->color.imageView; + case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS: + return (uint64_t)curFramebuffer_->GetFB()->color.texAllLayersView; + case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_LAYER: { + size_t layer = (size_t)srcObject; + _dbg_assert_(layer < curFramebuffer_->Layers()); + return (uint64_t)curFramebuffer_->GetFB()->color.texLayerViews[layer]; + } default: Crash(); return 0; diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index f2c886c054..947c89aae0 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -241,9 +241,10 @@ enum class NativeObject { BACKBUFFER_DEPTH_TEX, FEATURE_LEVEL, INIT_COMMANDBUFFER, - BOUND_TEXTURE0_IMAGEVIEW, - BOUND_TEXTURE1_IMAGEVIEW, - BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW, + BOUND_TEXTURE0_IMAGEVIEW, // Layer etc depends on how you bound it... + BOUND_TEXTURE1_IMAGEVIEW, // Layer etc depends on how you bound it... + BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS, + BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_LAYER, // use an int cast to void *srcObject to specify layer. RENDER_MANAGER, TEXTURE_VIEW, NULL_IMAGEVIEW, @@ -658,7 +659,8 @@ public: // These functions should be self explanatory. // Binding a zero render target means binding the backbuffer. - virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) = 0; + // If an fbo has two layers, we bind for stereo rendering ALWAYS. There's no rendering to one layer anymore. + virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) = 0; // binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2). virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) = 0; diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 6bdd4382d9..41ec1bb76d 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -85,7 +85,7 @@ void UIScreen::preRender() { } draw->BeginFrame(); // Bind and clear the back buffer - draw->BindFramebufferAsRenderTarget(nullptr, ALL_LAYERS, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); + draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); screenManager()->getUIContext()->BeginFrame(); Draw::Viewport viewport; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index b27aba7334..e6ce4a0f94 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -43,6 +43,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } errorString->clear(); + bool useStereo = id.Bit(FS_BIT_STEREO); + bool highpFog = false; bool highpTexcoord = false; bool enableFragmentTestCache = gstate_c.Use(GPU_USE_FRAGMENT_TEST_CACHE); @@ -58,23 +60,27 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu ReplaceAlphaType stencilToAlpha = static_cast(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)); - std::vector gl_exts; + std::vector extensions; if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { - gl_exts.push_back("#extension GL_EXT_blend_func_extended : require"); + extensions.push_back("#extension GL_EXT_blend_func_extended : require"); } if (gl_extensions.EXT_gpu_shader4) { - gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); + extensions.push_back("#extension GL_EXT_gpu_shader4 : enable"); } if (compat.framebufferFetchExtension) { - gl_exts.push_back(compat.framebufferFetchExtension); + extensions.push_back(compat.framebufferFetchExtension); } if (gl_extensions.OES_texture_3D && texture3D) { - gl_exts.push_back("#extension GL_OES_texture_3D: enable"); + extensions.push_back("#extension GL_OES_texture_3D: enable"); } + } + + if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN && useStereo) { + extensions.push_back("#extension GL_EXT_multiview : enable"); } - ShaderWriter p(buffer, compat, ShaderStage::Fragment, gl_exts); + ShaderWriter p(buffer, compat, ShaderStage::Fragment, extensions); bool lmode = id.Bit(FS_BIT_LMODE); bool doTexture = id.Bit(FS_BIT_DO_TEXTURE); @@ -90,7 +96,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA); bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE); - bool arrayTextureFramebuffer = id.Bit(FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE); bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled; @@ -162,9 +167,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } if (readFramebufferTex) { - WRITE(p, "layout (binding = 1) uniform sampler2D%s fbotex;\n", arrayTextureFramebuffer ? "array" : ""); + // The framebuffer texture is always bound as an array. + p.C("layout (binding = 1) uniform sampler2DArray fbotex;\n"); } else if (fetchFramebuffer) { - WRITE(p, "layout (input_attachment_index = 0, binding = 9) uniform subpassInput inputColor;\n"); + p.C("layout (input_attachment_index = 0, binding = 9) uniform subpassInput inputColor;\n"); if (fragmentShaderFlags) { *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; } @@ -517,6 +523,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " vec4 destColor = fbotex.Load(int3((int)gl_FragCoord.x, (int)gl_FragCoord.y, 0));\n"); } else if (compat.shaderLanguage == HLSL_D3D9) { WRITE(p, " vec4 destColor = tex2D(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture); + } else if (compat.shaderLanguage == GLSL_VULKAN) { + WRITE(p, " lowp vec4 destColor = %s(fbotex, ivec3(gl_FragCoord.x, gl_FragCoord.y, %s), 0);\n", compat.texelFetch, useStereo ? "float(gl_ViewIndex)" : "0"); } else if (!compat.texelFetch) { WRITE(p, " lowp vec4 destColor = %s(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture); } else { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 6809922dd9..4558d63b2b 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -863,7 +863,7 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra if (currentRenderVfb_ && dst != currentRenderVfb_ && tookActions) { // Will probably just change the name of the current renderpass, since one was started by the reinterpret itself. - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After Reinterpret"); + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After Reinterpret"); } shaderManager_->DirtyLastShader(); @@ -1011,7 +1011,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe if (useBufferedRendering_) { if (vfb->fbo) { shaderManager_->DirtyLastShader(); - draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, {Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP}, "FBSwitch"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, {Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP}, "FBSwitch"); } else { // This should only happen very briefly when toggling useBufferedRendering_. ResizeFramebufFBO(vfb, vfb->width, vfb->height, true); @@ -1115,7 +1115,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int } else { flags = DRAWTEX_LINEAR; } - draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); SetViewport2D(0, 0, vfb->renderWidth, vfb->renderHeight); draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight); } else { @@ -1369,7 +1369,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); // No framebuffer to display! Clear to black. if (useBufferedRendering_) { - draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput"); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput"); } gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); return; @@ -1433,7 +1433,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { // No framebuffer to display! Clear to black. if (useBufferedRendering_) { // Bind and clear the backbuffer. This should be the first time during the frame that it's bound. - draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO"); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO"); } gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); return; @@ -1631,7 +1631,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, if (old.fbo) { INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->fb_format)); if (vfb->fbo) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); if (!skipCopy) { BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0, RASTER_COLOR, "BlitColor_ResizeFramebufFBO"); } @@ -1640,9 +1640,9 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } } fbosToDelete_.push_back(old.fbo); - draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO"); } else { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); } currentRenderVfb_ = vfb; @@ -2396,6 +2396,17 @@ void FramebufferManagerCommon::DestroyAllFBOs() { fbosToDelete_.clear(); } +static const char *TempFBOReasonToString(TempFBO reason) { + switch (reason) { + case TempFBO::DEPAL: return "depal"; + case TempFBO::BLIT: return "blit"; + case TempFBO::COPY: return "copy"; + case TempFBO::STENCIL: return "stencil"; + default: break; + } + return ""; +} + Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h) { u64 key = ((u64)reason << 48) | ((u32)w << 16) | h; auto it = tempFBOs_.find(key); @@ -2406,7 +2417,7 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u bool z_stencil = reason == TempFBO::STENCIL; char name[128]; - snprintf(name, sizeof(name), "temp_fbo_%dx%d%s", w / renderScaleFactor_, h / renderScaleFactor_, z_stencil ? "_depth" : ""); + snprintf(name, sizeof(name), "tempfbo_%s_%dx%d", TempFBOReasonToString(reason), w / renderScaleFactor_, h / renderScaleFactor_); Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), z_stencil, name }); if (!fbo) { @@ -2785,10 +2796,10 @@ void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { draw_->InvalidateCachedState(); shaderManager_->DirtyLastShader(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); } else { // Should this even happen? It could while debugging, but maybe we can just skip binding at all. - draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad"); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad"); } } @@ -2907,7 +2918,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX // This can happen if they recently switched from non-buffered. if (useBufferedRendering_) { // Just bind the back buffer for rendering, forget about doing anything else as we're in a weird state. - draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); } return; } @@ -3030,7 +3041,7 @@ void FramebufferManagerCommon::BlitUsingRaster( // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). draw_->BindTexture(0, nullptr); // This will get optimized away in case it's already bound (in VK and GL at least..) - draw_->BindFramebufferAsRenderTarget(dest, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); + draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); if (destX1 == 0.0f && destY1 == 0.0f && destX2 >= destW && destY2 >= destH) { diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index d9f635d208..76ad0bd8f6 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -204,8 +204,6 @@ enum class TempFBO { BLIT, // For copies of framebuffers (e.g. shader blending.) COPY, - // For another type of framebuffers that can happen together with COPY (see Outrun) - REINTERPRET, // Used to copy stencil data, means we need a stencil backing. STENCIL, }; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index fa3ab92c00..4feb0bd21c 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -783,7 +783,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u postShaderFramebuffer = previousFramebuffers_[previousIndex_]; } - draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader"); + draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader"); performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline); } @@ -804,11 +804,11 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u previousIndex_ = 0; Draw::Framebuffer *postShaderFramebuffer = previousFramebuffers_[previousIndex_]; - draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "InterFrameBlit"); + draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "InterFrameBlit"); performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline); } - draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit"); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit"); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); Draw::Pipeline *pipeline = (flags & OutputFlags::RB_SWIZZLE) ? texColorRBSwizzle_ : texColor_; diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 1acad76ab4..40b31393c9 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -62,6 +62,8 @@ std::string VertexShaderDesc(const VShaderID &id) { if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN "; if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc << "Cull "; + if (id.Bit(VS_BIT_SIMPLE_STEREO)) desc << "SimpleStereo "; + return desc.str(); } @@ -92,7 +94,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, id.SetBit(VS_BIT_HAS_COLOR, hasColor); id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling); - if (!isModeThrough && VS_BIT_SIMPLE_STEREO) { + if (!isModeThrough && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { id.SetBit(VS_BIT_SIMPLE_STEREO); } @@ -255,7 +257,8 @@ std::string FragmentShaderDesc(const FShaderID &id) { if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc << "TestDiscardToZero "; if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc << "StencilDiscardWorkaround "; if (id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) desc << "ReplaceLogic "; - + if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc << "TexArray "; + if (id.Bit(FS_BIT_STEREO)) desc << "Stereo "; return desc.str(); } @@ -363,7 +366,6 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip id.SetBits(FS_BIT_BLENDFUNC_B, 4, gstate.getBlendFuncB()); } id.SetBit(FS_BIT_FLATSHADE, doFlatShading); - id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask); // Stereo support @@ -372,7 +374,7 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip if (gstate_c.arrayTexture) { id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE); } - id.SetBit(FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE); + id.SetBit(FS_BIT_STEREO); } if (g_Config.bVendorBugChecksEnabled && bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index de1a6b0985..effe330763 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -99,7 +99,7 @@ enum FShaderBit : uint8_t { FS_BIT_REPLACE_LOGIC_OP = 51, // 4 bits. GE_LOGIC_COPY means no-op/off. FS_BIT_SHADER_DEPAL_MODE = 55, // 2 bits (ShaderDepalMode) FS_BIT_SAMPLE_ARRAY_TEXTURE = 57, // For multiview, framebuffers are array textures and we need to sample the two layers correctly. - FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE = 58, // Framebuffer texture might also be stereo. + FS_BIT_STEREO = 58, }; static inline FShaderBit operator +(FShaderBit bit, int i) { diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index dfa36fe0e7..682d8a1f0c 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -187,7 +187,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, // Otherwise, we can skip alpha in many cases, in which case we don't even use a shader. if (flags & WriteStencil::IGNORE_ALPHA) { if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Clear"); + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Clear"); } return true; } @@ -281,9 +281,9 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, Draw::Framebuffer *blitFBO = nullptr; if (useBlit) { blitFBO = GetTempFBO(TempFBO::STENCIL, w, h); - draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Blit"); + draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Blit"); } else if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_NoBlit"); + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_NoBlit"); } Draw::Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 3c288b13f4..4e04144c96 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -2191,7 +2191,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(TempFBO::DEPAL, depalWidth, framebuffer->renderHeight); draw_->BindTexture(0, nullptr); draw_->BindTexture(1, nullptr); - draw_->BindFramebufferAsRenderTarget(depalFBO, Draw::ALL_LAYERS, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT); draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1); Draw::Viewport vp{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f }; @@ -2292,7 +2292,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(TempFBO::DEPAL, texWidth, texHeight); draw_->BindTexture(0, nullptr); draw_->BindTexture(1, nullptr); - draw_->BindFramebufferAsRenderTarget(depalFBO, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal"); draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT); draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1); Draw::Viewport vp{ 0.0f, 0.0f, (float)texWidth, (float)texHeight, 0.0f, 1.0f }; diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index e54d249061..7be1adf9d3 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -204,7 +204,7 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int shaderManager_->DirtyLastShader(); auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height()); - draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync"); + draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync"); Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }; draw_->SetViewports(1, &viewport); @@ -322,7 +322,7 @@ bool FramebufferManagerGLES::ReadbackStencilbufferSync(Draw::Framebuffer *fbo, i shaderManager_->DirtyLastShader(); auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height()); - draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackStencilbufferSync"); + draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackStencilbufferSync"); Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }; draw_->SetViewports(1, &viewport); diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 50ba4bfd99..9d1dc8d3dd 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -54,9 +54,9 @@ void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) // Discard the previous contents of this buffer where possible. if (gl_extensions.GLES3) { - draw_->BindFramebufferAsRenderTarget(nvfb->fbo, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "UpdateDownloadTempBuffer"); + draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "UpdateDownloadTempBuffer"); } else if (gl_extensions.IsGLES) { - draw_->BindFramebufferAsRenderTarget(nvfb->fbo, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "UpdateDownloadTempBuffer"); + draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "UpdateDownloadTempBuffer"); gstate_c.Dirty(DIRTY_BLEND_STATE); } } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 5e8087b077..04e3c1d5c7 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -618,7 +618,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { u1 = 1.0f; } if (!hasImage) { - draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam"); + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam"); return; } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index a9702731c9..335fc29ad9 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -582,10 +582,6 @@ void DrawEngineVulkan::DoFlush() { // Always use software for flat shading to fix the provoking index. bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT); - VulkanVertexShader *vshader = nullptr; - VulkanFragmentShader *fshader = nullptr; - VulkanGeometryShader *gshader = nullptr; - uint32_t ibOffset; uint32_t vbOffset; @@ -779,6 +775,10 @@ void DrawEngineVulkan::DoFlush() { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } + VulkanVertexShader *vshader = nullptr; + VulkanFragmentShader *fshader = nullptr; + VulkanGeometryShader *gshader = nullptr; + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform if (!vshader) { // We're screwed. @@ -909,6 +909,11 @@ void DrawEngineVulkan::DoFlush() { if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } + + VulkanVertexShader *vshader = nullptr; + VulkanFragmentShader *fshader = nullptr; + VulkanGeometryShader *gshader = nullptr; + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); // usehwtransform _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0); diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index dbf3ce95cd..4e877d335a 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -365,7 +365,8 @@ void DrawEngineVulkan::BindShaderBlendTex() { // Set the nearest/linear here (since we correctly know if alpha/color tests are needed)? if (!gstate.isModeClear()) { if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) { - bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS); + VirtualFramebuffer *curRenderVfb = framebufferManager_->GetCurrentRenderVFB(); + bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, curRenderVfb, BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS); _dbg_assert_(bindResult); boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE1_IMAGEVIEW); boundSecondaryIsInputAttachment_ = false; @@ -376,7 +377,7 @@ void DrawEngineVulkan::BindShaderBlendTex() { dirtyRequiresRecheck_ |= DIRTY_BLEND_STATE; } else if (fboTexBindState_ == FBO_TEX_READ_FRAMEBUFFER) { draw_->BindCurrentFramebufferForColorInput(); - boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW); + boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_LAYER, (void *)0); boundSecondaryIsInputAttachment_ = true; fboTexBindState_ = FBO_TEX_NONE; } else { diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index f2425d6c41..bcf5a47a48 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1359,9 +1359,9 @@ void EmuScreen::preRender() { if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) { // We need to clear here already so that drawing during the frame is done on a clean slate. if (Core_IsStepping() && gpuStats.numFlips != 0) { - draw->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer"); + draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer"); } else { - draw->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer"); + draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer"); } Viewport viewport; @@ -1400,7 +1400,7 @@ void EmuScreen::render() { // It's possible this might be set outside PSP_RunLoopFor(). // In this case, we need to double check it here. checkPowerDown(); - thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid"); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid"); renderUI(); return; } @@ -1439,12 +1439,12 @@ void EmuScreen::render() { // Clear to blue background screen bool dangerousSettings = !Reporting::IsSupported(); uint32_t color = dangerousSettings ? 0xFF900050 : 0xFF900000; - thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, color }, "EmuScreen_RuntimeError"); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, color }, "EmuScreen_RuntimeError"); // The info is drawn later in renderUI } else { // If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output. // This won't work in non-buffered, but that's fine. - thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); // Just to make sure. if (PSP_IsInited()) { gpu->CopyDisplayToOutput(true); @@ -1456,7 +1456,7 @@ void EmuScreen::render() { // Didn't actually reach the end of the frame, ran out of the blockTicks cycles. // In this case we need to bind and wipe the backbuffer, at least. // It's possible we never ended up outputted anything - make sure we have the backbuffer cleared - thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame"); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame"); break; } @@ -1470,7 +1470,7 @@ void EmuScreen::render() { if (hasVisibleUI()) { // In most cases, this should already be bound and a no-op. - thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_UI"); + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_UI"); cardboardDisableButton_->SetVisibility(g_Config.bEnableCardboardVR ? UI::V_VISIBLE : UI::V_GONE); screenManager()->getUIContext()->BeginFrame(); renderUI(); diff --git a/assets/shaders/stereo_red_blue.fsh b/assets/shaders/stereo_red_blue.fsh index b8156ee458..1ad875b6b3 100644 --- a/assets/shaders/stereo_red_blue.fsh +++ b/assets/shaders/stereo_red_blue.fsh @@ -26,8 +26,6 @@ void main() { vec3 leftColor = mix(vec3(leftGray), left, saturation) * red; vec3 rightColor = mix(vec3(rightGray), right, saturation) * blue; - // TODO: Do something to gamma, maybe? - gl_FragColor.rgb = leftColor + rightColor; gl_FragColor.a = 1.0; } diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 8d02af8f21..ff5c3f94b4 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -240,7 +240,7 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const PSP_EndHostFrame(); if (draw) { - draw->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless"); + draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless"); // Vulkan may get angry if we don't do a final present. if (gpu) gpu->CopyDisplayToOutput(true); From 6af4644ab274503b6dcf24c43c78e3ace07ceca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 23 Oct 2022 21:50:00 +0200 Subject: [PATCH 111/715] Stereo on mobile fixes --- GPU/Common/PresentationCommon.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 4feb0bd21c..d72eb55a2c 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -699,7 +699,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u } } - if (isFinalAtOutputResolution) { + if (isFinalAtOutputResolution || useStereo) { // In this mode, we ignore the g_display_rot_matrix. Apply manually. if (g_display_rotation != DisplayRotation::ROTATE_0) { for (int i = 0; i < 4; i++) { diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index aa5243a8f0..29c5e1e459 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -268,9 +268,15 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { features |= GPU_ROUND_DEPTH_TO_16BIT; } - if (true) { + if (g_Config.bStereoRendering) { features |= GPU_USE_SINGLE_PASS_STEREO; features &= ~GPU_USE_FRAMEBUFFER_FETCH; // Need to figure out if this can be supported with multiview rendering + if (features & GPU_USE_GS_CULLING) { + // Many devices that support stereo and GS don't support GS during stereo. + // So we revert back to VS range culling. + features &= ~GPU_USE_GS_CULLING; + features |= GPU_USE_VS_RANGE_CULLING; + } } return features; From f1b515caafbe4187ffc9715a4ae6d47d2b191b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 23 Oct 2022 21:50:29 +0200 Subject: [PATCH 112/715] Minor shaderwriter refactor --- Common/GPU/ShaderWriter.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 6eb42719f0..610a7fe0ec 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -33,6 +33,7 @@ struct VaryingDef { enum class ShaderWriterFlags { NONE = 0, FS_WRITE_DEPTH = 1, + FS_AUTO_STEREO = 2, }; ENUM_CLASS_BITOPS(ShaderWriterFlags); From 2bea495981ffb3a8b164e9f73dd72276fae6cc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 24 Oct 2022 17:36:54 +0200 Subject: [PATCH 113/715] wip --- Common/GPU/Shader.h | 1 + Common/GPU/ShaderWriter.cpp | 43 +++++++++++++++++++++++--- Common/GPU/ShaderWriter.h | 5 ++- GPU/Common/FragmentShaderGenerator.cpp | 18 ++++++++++- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 4020a7b253..4daa5717d1 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -94,6 +94,7 @@ struct UniformDef { struct SamplerDef { int binding; // Might only be used by some backends. const char *name; + bool array; // TODO: Might need unsigned samplers, 3d samplers, or other types in the future. }; diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index e00a468e35..238ce848ed 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -114,6 +114,9 @@ void ShaderWriter::Preamble(Slice extensions) { switch (lang_.shaderLanguage) { case GLSL_VULKAN: C("#version 450\n"); + if (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) { + C("#extension GL_EXT_multiview : enable\n"); + } // IMPORTANT! Extensions must be the first thing after #version. for (size_t i = 0; i < extensions.size(); i++) { F("%s\n", extensions[i]); @@ -462,6 +465,15 @@ void ShaderWriter::DeclareSamplers(Slice samplers) { samplerDefs_ = samplers; } +const SamplerDef *ShaderWriter::GetSamplerDef(const char *name) const { + for (int i = 0; i < (int)samplers_.size(); i++) { + if (!strcmp(samplers_[i].name, name)) { + return &samplers_[i]; + } + } + return nullptr; +} + void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { switch (lang_.shaderLanguage) { case HLSL_D3D11: @@ -472,7 +484,11 @@ void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { break; case GLSL_VULKAN: // In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1. - F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); + if ((flags_ & ShaderWriterFlags::FS_AUTO_STEREO) && def.array) { + F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); + } else { + F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); + } break; default: F("uniform sampler2D %s;\n", def.name); @@ -492,6 +508,7 @@ void ShaderWriter::DeclareSampler2D(const SamplerDef &def) { } ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv) { + const SamplerDef *samp = GetSamplerDef(sampName); switch (lang_.shaderLanguage) { case HLSL_D3D11: F("%s.Sample(%sSamp, %s)", sampName, sampName, uv); @@ -501,13 +518,20 @@ ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - F("%s(%s, %s)", lang_.texture, sampName, uv); + if (samp && samp->array) { + const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; + F("%s(%s, vec3(%s, %s))", lang_.texture, sampName, uv, index); + } else { + F("%s(%s, %s)", lang_.texture, sampName, uv); + } break; } return *this; } ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const char *uv, int offX, int offY) { + const SamplerDef *samp = GetSamplerDef(sampName); + switch (lang_.shaderLanguage) { case HLSL_D3D11: F("%s.Sample(%sSamp, %s, int2(%d, %d))", sampName, sampName, uv, offX, offY); @@ -518,13 +542,20 @@ ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const ch break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY); + if (samp->array) { + const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; + F("%sOffset(%s, vec3(%s, %s), ivec3(%d, %d))", lang_.texture, sampName, uv, index, offX, offY); + } else { + F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY); + } break; } return *this; } ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, int level) { + const SamplerDef *samp = GetSamplerDef(sampName); + switch (lang_.shaderLanguage) { case HLSL_D3D11: F("%s.Load(ivec3(%s, %d))", sampName, uv, level); @@ -535,7 +566,11 @@ ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - F("texelFetch(%s, %s, %d)", sampName, uv, level); + if ((flags_ & ShaderWriterFlags::FS_AUTO_STEREO) && samp->array) { + F("texelFetch(%s, %s, %d)", sampName, uv, level); + } else { + F("texelFetch(%s, %s, %d)", sampName, uv, level); + } break; } return *this; diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 610a7fe0ec..567e4c33a5 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -33,7 +33,7 @@ struct VaryingDef { enum class ShaderWriterFlags { NONE = 0, FS_WRITE_DEPTH = 1, - FS_AUTO_STEREO = 2, + FS_AUTO_STEREO = 2, // Automatically makes sampler 0 an array sampler, and samples it by gl_ViewIndex. Useful for stereo rendering. }; ENUM_CLASS_BITOPS(ShaderWriterFlags); @@ -119,9 +119,12 @@ private: void Preamble(Slice extensions); + const SamplerDef *GetSamplerDef(const char *name) const; + char *p_; const ShaderLanguageDesc &lang_; const ShaderStage stage_; + Slice samplers_; ShaderWriterFlags flags_ = ShaderWriterFlags::NONE; Slice samplerDefs_; int texBindingBase_ = 1; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index e6ce4a0f94..64693097a4 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -96,6 +96,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA); bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE); + if (texture3D && arrayTexture) { + *errorString = "Invalid combination of 3D texture and array texture, shouldn't happen"; + return false; + } bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled; @@ -156,6 +160,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu return false; } + // Currently only used by Vulkan. + std::vector samplers; + if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN) { if (useDiscardStencilBugWorkaround && !gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); @@ -163,7 +170,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); if (doTexture) { - WRITE(p, "layout (binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "array" : ""); + WRITE(p, "layout (binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); } if (readFramebufferTex) { @@ -639,6 +646,15 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } else { WRITE(p, " vec4 t = %s(tex, vec3(%s.xy, u_mipBias));\n", compat.texture3D, texcoord); } + } else if (arrayTexture) { + // Used for stereo rendering. + if (doTextureProjection) { + if (doTextureProjection) { + WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord); + } else { + WRITE(p, " vec4 t = %s(tex, %s.xy);\n", compat.texture, texcoord); + } + } } else { if (doTextureProjection) { WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord); From 91259aaad7138bb3424076a2367c79e88e62e9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Oct 2022 23:32:28 +0200 Subject: [PATCH 114/715] Always use array textures for framebuffers in Vulkan for simplicity. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 4 +-- Common/GPU/D3D9/thin3d_d3d9.cpp | 4 +-- Common/GPU/OpenGL/thin3d_gl.cpp | 4 +-- Common/GPU/Shader.h | 12 ++++++--- Common/GPU/ShaderWriter.cpp | 20 +++++--------- Common/GPU/ShaderWriter.h | 4 +-- Common/GPU/Vulkan/VulkanImage.cpp | 10 +++++++ Common/GPU/Vulkan/VulkanImage.h | 4 +++ Common/GPU/Vulkan/thin3d_vulkan.cpp | 35 ++++++++++++++++++++----- Common/GPU/thin3d.h | 9 ++++++- GPU/Common/Draw2D.cpp | 13 ++++++--- GPU/Common/FramebufferManagerCommon.cpp | 4 +-- 12 files changed, 83 insertions(+), 40 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index aca3aaae93..428e86fdb3 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -101,7 +101,7 @@ public: void InvalidateCachedState() override; - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int index, void *nativeTexture) override; void BindSamplerStates(int start, int count, SamplerState **states) override; void BindVertexBuffers(int start, int count, Buffer **buffers, const int *offsets) override; @@ -1381,7 +1381,7 @@ Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { return fb; } -void D3D11DrawContext::BindTextures(int start, int count, Texture **textures) { +void D3D11DrawContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { // Collect the resource views from the textures. ID3D11ShaderResourceView *views[MAX_BOUND_TEXTURES]; _assert_(start + count <= ARRAY_SIZE(views)); diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 4c3a83c2f5..ec524c8dab 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -538,7 +538,7 @@ public: void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int index, void *nativeTexture) override; void BindSamplerStates(int start, int count, SamplerState **states) override { @@ -912,7 +912,7 @@ Texture *D3D9Context::CreateTexture(const TextureDesc &desc) { return tex; } -void D3D9Context::BindTextures(int start, int count, Texture **textures) { +void D3D9Context::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { _assert_(start + count <= MAX_BOUND_TEXTURES); for (int i = start; i < start + count; i++) { D3D9Texture *tex = static_cast(textures[i - start]); diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index fe26e38591..bd8a252e10 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -397,7 +397,7 @@ public: curPipeline_->depthStencil->stencilPass); } - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int sampler, void *nativeTexture) override; void BindPipeline(Pipeline *pipeline) override; @@ -1127,7 +1127,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const } } -void OpenGLContext::BindTextures(int start, int count, Texture **textures) { +void OpenGLContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { _assert_(start + count <= MAX_TEXTURE_SLOTS); for (int i = start; i < start + count; i++) { OpenGLTexture *glTex = static_cast(textures[i - start]); diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 4daa5717d1..6e29445734 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -4,9 +4,12 @@ #include #include // for size_t +#include "Common/Common.h" + // GLSL_1xx and GLSL_3xx each cover a lot of sub variants. All the little quirks // that differ are covered in ShaderLanguageDesc. // Defined as a bitmask so stuff like GetSupportedShaderLanguages can return combinations. +// TODO: We can probably move away from this distinction soon, now that we mostly generate/translate shaders. enum ShaderLanguage { GLSL_1xx = 1, GLSL_3xx = 2, @@ -30,7 +33,6 @@ enum class ShaderStage { const char *ShaderStageAsString(ShaderStage lang); - struct ShaderLanguageDesc { ShaderLanguageDesc() {} explicit ShaderLanguageDesc(ShaderLanguage lang); @@ -91,14 +93,18 @@ struct UniformDef { int index; }; +enum class SamplerFlags { + ARRAY_ON_VULKAN = 1, +}; +ENUM_CLASS_BITOPS(SamplerFlags); + struct SamplerDef { int binding; // Might only be used by some backends. const char *name; - bool array; + SamplerFlags flags; // TODO: Might need unsigned samplers, 3d samplers, or other types in the future. }; - // For passing error messages from shader compilation (and other critical issues) back to the host. // This can run on any thread - be aware! // TODO: See if we can find a less generic name for this. diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 238ce848ed..4e98e17d0c 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -465,15 +465,6 @@ void ShaderWriter::DeclareSamplers(Slice samplers) { samplerDefs_ = samplers; } -const SamplerDef *ShaderWriter::GetSamplerDef(const char *name) const { - for (int i = 0; i < (int)samplers_.size(); i++) { - if (!strcmp(samplers_[i].name, name)) { - return &samplers_[i]; - } - } - return nullptr; -} - void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { switch (lang_.shaderLanguage) { case HLSL_D3D11: @@ -484,7 +475,7 @@ void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { break; case GLSL_VULKAN: // In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1. - if ((flags_ & ShaderWriterFlags::FS_AUTO_STEREO) && def.array) { + if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) { F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); } else { F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); @@ -518,7 +509,7 @@ ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - if (samp && samp->array) { + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN)) { const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; F("%s(%s, vec3(%s, %s))", lang_.texture, sampName, uv, index); } else { @@ -542,7 +533,7 @@ ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const ch break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - if (samp->array) { + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN)) { const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; F("%sOffset(%s, vec3(%s, %s), ivec3(%d, %d))", lang_.texture, sampName, uv, index, offX, offY); } else { @@ -566,8 +557,9 @@ ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - if ((flags_ & ShaderWriterFlags::FS_AUTO_STEREO) && samp->array) { - F("texelFetch(%s, %s, %d)", sampName, uv, level); + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN)) { + const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "gl_ViewIndex" : "0"; + F("texelFetch(%s, vec3(%s, %s), %d)", sampName, uv, index, level); } else { F("texelFetch(%s, %s, %d)", sampName, uv, level); } diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 567e4c33a5..761eacd867 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -33,7 +33,7 @@ struct VaryingDef { enum class ShaderWriterFlags { NONE = 0, FS_WRITE_DEPTH = 1, - FS_AUTO_STEREO = 2, // Automatically makes sampler 0 an array sampler, and samples it by gl_ViewIndex. Useful for stereo rendering. + FS_AUTO_STEREO = 2, // Automatically indexes makes samplers tagged with `array` by gl_ViewIndex. Useful for stereo rendering. }; ENUM_CLASS_BITOPS(ShaderWriterFlags); @@ -119,8 +119,6 @@ private: void Preamble(Slice extensions); - const SamplerDef *GetSamplerDef(const char *name) const; - char *p_; const ShaderLanguageDesc &lang_; const ShaderStage stage_; diff --git a/Common/GPU/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp index ad712b6a0f..8a439d4d3e 100644 --- a/Common/GPU/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -123,6 +123,13 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } + + // Additionally, create an array view, but only if it's a 2D texture. + if (view_info.viewType == VK_IMAGE_VIEW_TYPE_2D) { + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &arrayView_); + _assert_(res == VK_SUCCESS); + } return true; } @@ -245,6 +252,9 @@ void VulkanTexture::Destroy() { if (view_ != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteImageView(view_); } + if (arrayView_ != VK_NULL_HANDLE) { + vulkan_->Delete().QueueDeleteImageView(arrayView_); + } if (image_ != VK_NULL_HANDLE) { _dbg_assert_(allocation_ != VK_NULL_HANDLE); vulkan_->Delete().QueueDeleteImageAllocation(image_, allocation_); diff --git a/Common/GPU/Vulkan/VulkanImage.h b/Common/GPU/Vulkan/VulkanImage.h index 50d7e0c7f5..e0aa32d385 100644 --- a/Common/GPU/Vulkan/VulkanImage.h +++ b/Common/GPU/Vulkan/VulkanImage.h @@ -51,6 +51,9 @@ public: // Used for sampling, generally. VkImageView GetImageView() const { return view_; } + // For use with some shaders, we might want to view it as a single entry array for convenience. + VkImageView GetImageArrayView() const { return arrayView_; } + int32_t GetWidth() const { return width_; } int32_t GetHeight() const { return height_; } int32_t GetNumMips() const { return numMips_; } @@ -62,6 +65,7 @@ private: VulkanContext *vulkan_; VkImage image_ = VK_NULL_HANDLE; VkImageView view_ = VK_NULL_HANDLE; + VkImageView arrayView_ = VK_NULL_HANDLE; VmaAllocation allocation_ = VK_NULL_HANDLE; int16_t width_ = 0; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index fbcc288aa2..e673ba5ff9 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -338,10 +338,16 @@ public: if (vkTex_) { vkTex_->Touch(); return vkTex_->GetImageView(); - } else { - // This would be bad. - return VK_NULL_HANDLE; } + return VK_NULL_HANDLE; // This would be bad. + } + + VkImageView GetImageArrayView() { + if (vkTex_) { + vkTex_->Touch(); + return vkTex_->GetImageArrayView(); + } + return VK_NULL_HANDLE; // This would be bad. } private: @@ -417,7 +423,7 @@ public: void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override; void BindSamplerStates(int start, int count, SamplerState **state) override; - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int sampler, void *nativeTexture) override; void BindPipeline(Pipeline *pipeline) override { @@ -520,6 +526,7 @@ private: MAX_FRAME_COMMAND_BUFFERS = 256, }; AutoRef boundTextures_[MAX_BOUND_TEXTURES]; + TextureBindFlags boundTextureFlags_[MAX_BOUND_TEXTURES]; AutoRef boundSamplers_[MAX_BOUND_TEXTURES]; VkImageView boundImageView_[MAX_BOUND_TEXTURES]{}; @@ -994,7 +1001,11 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { FrameData *frame = &frame_[vulkan_->GetCurFrame()]; for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) { - key.imageViews_[i] = boundTextures_[i] ? boundTextures_[i]->GetImageView() : boundImageView_[i]; + if (boundTextures_[i]) { + key.imageViews_[i] = (boundTextureFlags_[i] & TextureBindFlags::VULKAN_BIND_ARRAY) ? boundTextures_[i]->GetImageArrayView() : boundTextures_[i]->GetImageView(); + } else { + key.imageViews_[i] = boundImageView_[i]; + } key.samplers_[i] = boundSamplers_[i]; } key.buffer_ = buf; @@ -1296,11 +1307,21 @@ void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, memcpy(buf->data_ + offset, data, size); } -void VKContext::BindTextures(int start, int count, Texture **textures) { +void VKContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { _assert_(start + count <= MAX_BOUND_TEXTURES); for (int i = start; i < start + count; i++) { boundTextures_[i] = static_cast(textures[i - start]); - boundImageView_[i] = boundTextures_[i] ? boundTextures_[i]->GetImageView() : GetNullTexture()->GetImageView(); + boundTextureFlags_[i] = flags; + if (boundTextures_[i]) { + // NOTE: These image views are actually not used, it seems - they get overridden in GetOrCreateDescriptorSet + if (flags & TextureBindFlags::VULKAN_BIND_ARRAY) { + boundImageView_[i] = boundTextures_[i]->GetImageArrayView(); + } else { + boundImageView_[i] = boundTextures_[i]->GetImageView(); + } + } else { + boundImageView_[i] = GetNullTexture()->GetImageView(); + } } } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 947c89aae0..2097debe46 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -13,6 +13,7 @@ #include #include +#include "Common/Common.h" #include "Common/GPU/DataFormat.h" #include "Common/GPU/Shader.h" #include "Common/Data/Collections/Slice.h" @@ -598,6 +599,12 @@ struct RenderPassInfo { const int ALL_LAYERS = -1; +enum class TextureBindFlags { + NONE = 0, + VULKAN_BIND_ARRAY = 1, +}; +ENUM_CLASS_BITOPS(TextureBindFlags); + class DrawContext { public: virtual ~DrawContext(); @@ -688,7 +695,7 @@ public: virtual void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) = 0; virtual void BindSamplerStates(int start, int count, SamplerState **state) = 0; - virtual void BindTextures(int start, int count, Texture **textures) = 0; + virtual void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags = TextureBindFlags::NONE) = 0; virtual void BindVertexBuffers(int start, int count, Buffer **buffers, const int *offsets) = 0; virtual void BindIndexBuffer(Buffer *indexBuffer, int offset) = 0; diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 9b342e05bc..06560282d8 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -37,7 +37,7 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { 0, "tex" }, + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, }; const UniformDef g_draw2Duniforms[2] = { @@ -88,8 +88,8 @@ Draw2DPipelineInfo GenerateDraw2DCopyColorRect2LinFs(ShaderWriter &writer) { } Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) { - writer.DeclareSamplers(samplers); writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.DeclareSamplers(samplers); writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); writer.C(" gl_FragDepth = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n"); @@ -103,8 +103,8 @@ Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) { } Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { - writer.DeclareSamplers(samplers); writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.DeclareSamplers(samplers); writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); // Unlike when just copying a depth buffer, here we're generating new depth values so we'll @@ -123,8 +123,8 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { } Draw2DPipelineInfo GenerateDraw2D565ToDepthDeswizzleFs(ShaderWriter &writer) { - writer.DeclareSamplers(samplers); writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.DeclareSamplers(samplers); writer.BeginFSMain(g_draw2Duniforms, varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); // Unlike when just copying a depth buffer, here we're generating new depth values so we'll @@ -182,6 +182,10 @@ void Draw2D::Ensure2DResources() { if (!draw2DVs_) { char *vsCode = new char[8192]; + ShaderWriterFlags flags = ShaderWriterFlags::NONE; + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + flags = ShaderWriterFlags::FS_AUTO_STEREO; + } ShaderWriter writer(vsCode, shaderLanguageDesc, ShaderStage::Vertex); GenerateDraw2DVS(writer); _assert_msg_(strlen(vsCode) < 8192, "Draw2D VS length error: %d", (int)strlen(vsCode)); @@ -315,6 +319,7 @@ void Draw2D::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCoun draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); if (tex) { + // This won't work since all the shaders above expect array textures on Vulkan. draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); } draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, linearFilter ? &draw2DSamplerLinear_ : &draw2DSamplerNearest_); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 4558d63b2b..a2b60d231b 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1140,7 +1140,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height); if (pixelsTex) { - draw_->BindTextures(0, 1, &pixelsTex); + draw_->BindTextures(0, 1, &pixelsTex, Draw::TextureBindFlags::VULKAN_BIND_ARRAY); // TODO: Replace with draw2D_.Blit() directly. DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); @@ -3042,7 +3042,7 @@ void FramebufferManagerCommon::BlitUsingRaster( draw_->BindTexture(0, nullptr); // This will get optimized away in case it's already bound (in VK and GL at least..) draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); - draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); + draw_->BindFramebufferAsTexture(src, Draw::ALL_LAYERS, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); if (destX1 == 0.0f && destY1 == 0.0f && destX2 >= destW && destY2 >= destH) { // We overwrite the whole channel of the framebuffer, so we can invalidate the current contents. From 524e92374f0443d5070c028d79498ef3ddc642af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Oct 2022 23:59:42 +0200 Subject: [PATCH 115/715] Use arrays more consistently. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 12 +++++++++--- Common/GPU/thin3d.h | 10 ++++++++++ GPU/Common/DepalettizeShaderCommon.cpp | 2 +- GPU/Common/Draw2D.cpp | 7 ++++++- GPU/Common/FramebufferManagerCommon.cpp | 2 +- GPU/Common/PresentationCommon.cpp | 2 +- GPU/Common/ReinterpretFramebuffer.cpp | 3 +-- GPU/Vulkan/TextureCacheVulkan.cpp | 2 +- 8 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index e673ba5ff9..d49f1d51a6 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -526,9 +526,9 @@ private: MAX_FRAME_COMMAND_BUFFERS = 256, }; AutoRef boundTextures_[MAX_BOUND_TEXTURES]; - TextureBindFlags boundTextureFlags_[MAX_BOUND_TEXTURES]; AutoRef boundSamplers_[MAX_BOUND_TEXTURES]; VkImageView boundImageView_[MAX_BOUND_TEXTURES]{}; + TextureBindFlags boundTextureFlags_[MAX_BOUND_TEXTURES]; struct FrameData { FrameData() : descriptorPool("VKContext", false) { @@ -1310,6 +1310,7 @@ void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, void VKContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { _assert_(start + count <= MAX_BOUND_TEXTURES); for (int i = start; i < start + count; i++) { + _dbg_assert_(i >= 0 && i < MAX_BOUND_TEXTURES); boundTextures_[i] = static_cast(textures[i - start]); boundTextureFlags_[i] = flags; if (boundTextures_[i]) { @@ -1326,6 +1327,7 @@ void VKContext::BindTextures(int start, int count, Texture **textures, TextureBi } void VKContext::BindNativeTexture(int sampler, void *nativeTexture) { + _dbg_assert_(sampler >= 0 && sampler < MAX_BOUND_TEXTURES); boundTextures_[sampler] = nullptr; boundImageView_[sampler] = (VkImageView)nativeTexture; } @@ -1587,8 +1589,12 @@ void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPass } void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { + if (layer != ALL_LAYERS) { + layer = layer; + } + VKFramebuffer *fb = (VKFramebuffer *)fbo; - _assert_(binding < MAX_BOUND_TEXTURES); + _assert_(binding >= 0 && binding < MAX_BOUND_TEXTURES); // TODO: There are cases where this is okay, actually. But requires layout transitions and stuff - // we're not ready for this. @@ -1607,7 +1613,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne break; } - boundTextures_[binding] = nullptr; + boundTextures_[binding].clear(); boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, layer); } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 2097debe46..226270f8c9 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -397,6 +397,16 @@ struct AutoRef { operator T *() { return ptr; } + operator bool() const { + return ptr != nullptr; + } + + void clear() { + if (ptr) { + ptr->Release(); + ptr = nullptr; + } + } T *ptr = nullptr; }; diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index a784d22377..52c67152ef 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -35,7 +35,7 @@ static const InputDef vsInputs[2] = { // TODO: Deduplicate with TextureShaderCommon.cpp static const SamplerDef samplers[2] = { - { 0, "tex" }, + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, { 1, "pal" }, }; diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 06560282d8..2b81178233 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -184,6 +184,7 @@ void Draw2D::Ensure2DResources() { char *vsCode = new char[8192]; ShaderWriterFlags flags = ShaderWriterFlags::NONE; if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + // Hm, we're compiling the vertex shader here, probably don't need this... flags = ShaderWriterFlags::FS_AUTO_STEREO; } ShaderWriter writer(vsCode, shaderLanguageDesc, ShaderStage::Vertex); @@ -224,7 +225,11 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::functionGetShaderLanguageDesc(); char *fsCode = new char[8192]; - ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment); + ShaderWriterFlags flags = ShaderWriterFlags::NONE; + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + flags = ShaderWriterFlags::FS_AUTO_STEREO; + } + ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment, Slice::empty(), flags); Draw2DPipelineInfo info = generate(writer); _assert_msg_(strlen(fsCode) < 8192, "Draw2D FS length error: %d", (int)strlen(fsCode)); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index a2b60d231b..f7a470bb7d 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -3042,7 +3042,7 @@ void FramebufferManagerCommon::BlitUsingRaster( draw_->BindTexture(0, nullptr); // This will get optimized away in case it's already bound (in VK and GL at least..) draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); - draw_->BindFramebufferAsTexture(src, Draw::ALL_LAYERS, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); + draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, Draw::ALL_LAYERS); if (destX1 == 0.0f && destY1 == 0.0f && destX2 >= destW && destY2 >= destH) { // We overwrite the whole channel of the framebuffer, so we can invalidate the current contents. diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index d72eb55a2c..1cd86101d5 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -596,7 +596,7 @@ bool PresentationCommon::BindSource(int binding, bool bindStereo) { draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); return true; } else { - // Single layer + // Single layer. This might be from a post shader and those don't yet support stereo. draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); return false; } diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index b14e324d0d..ccb58c1c9b 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -14,14 +14,13 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { 0, "tex" } + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN } }; // Requires full size integer math. It would be possible to make a floating point-only version with lots of // modulo and stuff, might do it one day. Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBufferFormat from, GEBufferFormat to) { writer.HighPrecisionFloat(); - writer.DeclareSamplers(samplers); if (writer.Lang().bitwiseOps) { diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index c465aa31c2..8f80aa8474 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -846,6 +846,6 @@ std::string TextureCacheVulkan::DebugGetSamplerString(std::string id, DebugShade } void *TextureCacheVulkan::GetNativeTextureView(const TexCacheEntry *entry) { - VkImageView view = entry->vkTex->GetImageView(); + VkImageView view = entry->vkTex->GetImageArrayView(); return (void *)view; } From 8413473fa4e2448be9e97ac716aa5acf902bde5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 00:24:43 +0200 Subject: [PATCH 116/715] Fix more cases, GTA works now. --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 3 ++- GPU/Common/FragmentShaderGenerator.cpp | 9 ++++----- GPU/Common/TextureCacheCommon.cpp | 13 ++++++++++--- GPU/Common/TextureShaderCommon.cpp | 2 +- GPU/GPUState.h | 6 ++++++ GPU/Vulkan/PipelineManagerVulkan.cpp | 8 +++++++- 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 7b314cc0d1..cee212ee98 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1444,7 +1444,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c const RenderPassType rpType = step.render.renderPassType; - for (const auto &c : commands) { + for (size_t i = 0; i < commands.size(); i++) { + const VkRenderData &c = commands[i]; switch (c.cmd) { case VKRRenderCommand::REMOVED: break; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 64693097a4..7b29c19cf0 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -648,12 +648,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } } else if (arrayTexture) { // Used for stereo rendering. + const char *arrayIndex = useStereo ? "float(gl_ViewIndex)" : "0.0"; if (doTextureProjection) { - if (doTextureProjection) { - WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord); - } else { - WRITE(p, " vec4 t = %s(tex, %s.xy);\n", compat.texture, texcoord); - } + WRITE(p, " vec4 t = %sProj(tex, vec4(%s, %s));\n", compat.texture, texcoord, arrayIndex); + } else { + WRITE(p, " vec4 t = %s(tex, vec3(%s.xy, %s));\n", compat.texture, texcoord, arrayIndex); } } else { if (doTextureProjection) { diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 4e04144c96..fdfc874fda 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -371,6 +371,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { if (!Memory::IsValidAddress(texaddr)) { // Bind a null texture and return. Unbind(); + gstate_c.arrayTexture = false; return nullptr; } @@ -528,6 +529,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); + gstate_c.SetTextureIsArray(false); if (rehash) { // Update in case any of these changed. entry->sizeInRAM = (textureBitsPerPixel[texFormat] * bufw * h / 2) / 8; @@ -636,6 +638,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); + gstate_c.SetTextureIsArray(false); // Ordinary 2D textures still aren't used by array view in VK. We probably might as well, though, at this point.. failedTexture_ = false; nextTexture_ = entry; @@ -1126,6 +1129,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) } gstate_c.SetTextureIs3D(false); + gstate_c.SetTextureIsArray(true); nextNeedsRehash_ = false; nextNeedsChange_ = false; @@ -2020,11 +2024,13 @@ void TextureCacheCommon::ApplyTexture() { entry->lastFrame = gpuStats.numFlips; gstate_c.SetTextureFullAlpha(false); gstate_c.SetTextureIs3D(false); + gstate_c.SetTextureIsArray(false); } else { entry->lastFrame = gpuStats.numFlips; BindTexture(entry); gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL); gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); + gstate_c.SetTextureIsArray(false); } } @@ -2121,7 +2127,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture. BindAsClutTexture(clutTexture.texture, smoothedDepal); - framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, 0); + framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, Draw::ALL_LAYERS); // Vulkan needs to do some extra work here to pick out the native handle from Draw. BoundFramebufferTexture(); @@ -2197,7 +2203,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer Draw::Viewport vp{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f }; draw_->SetViewports(1, &vp); - draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); draw_->BindTexture(1, clutTexture.texture); Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false); Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(smoothedDepal); @@ -2226,7 +2232,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer shaderManager_->DirtyLastShader(); } else { framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, 0); + framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, Draw::ALL_LAYERS); BoundFramebufferTexture(); gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF); @@ -2331,6 +2337,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { // Since we've drawn using thin3d, might need these. gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); + } void TextureCacheCommon::Clear(bool delete_them) { diff --git a/GPU/Common/TextureShaderCommon.cpp b/GPU/Common/TextureShaderCommon.cpp index 5919d5442e..a1ba51de53 100644 --- a/GPU/Common/TextureShaderCommon.cpp +++ b/GPU/Common/TextureShaderCommon.cpp @@ -34,7 +34,7 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[2] = { - { 0, "tex" }, + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, { 1, "pal" }, }; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index b323fc1067..0347371212 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -562,6 +562,12 @@ struct GPUStateCache { Dirty(DIRTY_FRAGMENTSHADER_STATE | (is3D ? DIRTY_MIPBIAS : 0)); } } + void SetTextureIsArray(bool isArrayTexture) { // VK only + if (arrayTexture != isArrayTexture) { + arrayTexture = isArrayTexture; + Dirty(DIRTY_FRAGMENTSHADER_STATE); + } + } u32 useFlags; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 95b019483b..d9ae5ddd70 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -12,6 +12,7 @@ #include "GPU/Vulkan/PipelineManagerVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/ShaderId.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/Vulkan/VulkanRenderManager.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" @@ -296,7 +297,12 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, desc->pipelineLayout = layout; - VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, "game"); + std::string tag = "game"; +#ifdef _DEBUG + tag = FragmentShaderDesc(fs->GetID()) + " VS " + VertexShaderDesc(vs->GetID()); +#endif + + VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, tag.c_str()); vulkanPipeline->pipeline = pipeline; if (useBlendConstant) { From 390a136cb5c743f1adbe1a475d5c6bb7d088d836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 00:34:28 +0200 Subject: [PATCH 117/715] Stereo now works through shader depal too --- Common/GPU/ShaderWriter.cpp | 6 +++++- Common/GPU/ShaderWriter.h | 6 +++++- GPU/Common/FragmentShaderGenerator.cpp | 22 ++++++++++++++++++++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 4e98e17d0c..495267ce48 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -465,6 +465,10 @@ void ShaderWriter::DeclareSamplers(Slice samplers) { samplerDefs_ = samplers; } +void ShaderWriter::ApplySamplerMetadata(Slice samplers) { + samplerDefs_ = samplers; +} + void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { switch (lang_.shaderLanguage) { case HLSL_D3D11: @@ -535,7 +539,7 @@ ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const ch // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN)) { const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; - F("%sOffset(%s, vec3(%s, %s), ivec3(%d, %d))", lang_.texture, sampName, uv, index, offX, offY); + F("%sOffset(%s, vec3(%s, %s), ivec2(%d, %d))", lang_.texture, sampName, uv, index, offX, offY); } else { F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY); } diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 761eacd867..48b0bff9e5 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -40,7 +40,7 @@ ENUM_CLASS_BITOPS(ShaderWriterFlags); class ShaderWriter { public: // Extensions are supported for both OpenGL ES and Vulkan (though of course, they're different). - ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice extensions = Slice(), ShaderWriterFlags flags = ShaderWriterFlags::NONE) : p_(buffer), lang_(lang), stage_(stage) { + ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice extensions = Slice(), ShaderWriterFlags flags = ShaderWriterFlags::NONE) : p_(buffer), lang_(lang), stage_(stage), flags_(flags) { Preamble(extensions); } ShaderWriter(const ShaderWriter &) = delete; @@ -79,6 +79,10 @@ public: // NOTE: samplers must live for the rest of ShaderWriter's lifetime. No way to express that in C++ though :( void DeclareSamplers(Slice samplers); + // Same as DeclareSamplers, but doesn't actually declare them. + // This is currently only required by FragmentShaderGenerator. + void ApplySamplerMetadata(Slice samplers); + void ConstFloat(const char *name, float value); void SetFlags(ShaderWriterFlags flags) { flags_ |= flags; } void SetTexBindingBase(int base) { texBindingBase_ = base; } diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 7b29c19cf0..e218746fcb 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -36,6 +36,19 @@ #define WRITE(p, ...) p.F(__VA_ARGS__) +// This is only used in stereo mode, so okay to declare "tex" as ARRAY_ON_ +static const SamplerDef samplersMono[3] = { + { 0, "tex" }, + { 1, "fbotex", SamplerFlags::ARRAY_ON_VULKAN }, + { 2, "pal" }, +}; + +static const SamplerDef samplersStereo[3] = { + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, + { 1, "fbotex", SamplerFlags::ARRAY_ON_VULKAN }, + { 2, "pal" }, +}; + bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint64_t *uniformMask, FragmentShaderFlags *fragmentShaderFlags, std::string *errorString) { *uniformMask = 0; if (fragmentShaderFlags) { @@ -44,7 +57,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu errorString->clear(); bool useStereo = id.Bit(FS_BIT_STEREO); - bool highpFog = false; bool highpTexcoord = false; bool enableFragmentTestCache = gstate_c.Use(GPU_USE_FRAGMENT_TEST_CACHE); @@ -80,7 +92,13 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu extensions.push_back("#extension GL_EXT_multiview : enable"); } - ShaderWriter p(buffer, compat, ShaderStage::Fragment, extensions); + ShaderWriterFlags flags = ShaderWriterFlags::NONE; + if (useStereo) { + flags |= ShaderWriterFlags::FS_AUTO_STEREO; + } + + ShaderWriter p(buffer, compat, ShaderStage::Fragment, extensions, flags); + p.ApplySamplerMetadata(useStereo ? samplersStereo : samplersMono); bool lmode = id.Bit(FS_BIT_LMODE); bool doTexture = id.Bit(FS_BIT_DO_TEXTURE); From 2a1526c352a2bdf836ed67190fa46f29d3f7f860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 10:45:58 +0200 Subject: [PATCH 118/715] Address feedback --- Common/GPU/ShaderWriter.cpp | 2 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 7 ++----- GPU/Common/FragmentShaderGenerator.cpp | 5 ----- GPU/Common/TextureCacheCommon.cpp | 4 ++-- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 495267ce48..d7e0d16856 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -478,7 +478,7 @@ void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { F("sampler %s: register(s%d);\n", def.name, def.binding); break; case GLSL_VULKAN: - // In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1. + // texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1. if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) { F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); } else { diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index d49f1d51a6..8b7144927b 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1314,7 +1314,8 @@ void VKContext::BindTextures(int start, int count, Texture **textures, TextureBi boundTextures_[i] = static_cast(textures[i - start]); boundTextureFlags_[i] = flags; if (boundTextures_[i]) { - // NOTE: These image views are actually not used, it seems - they get overridden in GetOrCreateDescriptorSet + // If a texture is bound, we set these up in GetOrCreateDescriptorSet too. + // But we might need to set the view here anyway so it can be queried using GetNativeObject. if (flags & TextureBindFlags::VULKAN_BIND_ARRAY) { boundImageView_[i] = boundTextures_[i]->GetImageArrayView(); } else { @@ -1589,10 +1590,6 @@ void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPass } void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { - if (layer != ALL_LAYERS) { - layer = layer; - } - VKFramebuffer *fb = (VKFramebuffer *)fbo; _assert_(binding >= 0 && binding < MAX_BOUND_TEXTURES); diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index e218746fcb..10c516f45d 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -36,7 +36,6 @@ #define WRITE(p, ...) p.F(__VA_ARGS__) -// This is only used in stereo mode, so okay to declare "tex" as ARRAY_ON_ static const SamplerDef samplersMono[3] = { { 0, "tex" }, { 1, "fbotex", SamplerFlags::ARRAY_ON_VULKAN }, @@ -88,10 +87,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } } - if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN && useStereo) { - extensions.push_back("#extension GL_EXT_multiview : enable"); - } - ShaderWriterFlags flags = ShaderWriterFlags::NONE; if (useStereo) { flags |= ShaderWriterFlags::FS_AUTO_STEREO; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index fdfc874fda..8e60f8e5aa 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -371,7 +371,8 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { if (!Memory::IsValidAddress(texaddr)) { // Bind a null texture and return. Unbind(); - gstate_c.arrayTexture = false; + gstate_c.SetTextureIs3D(false); + gstate_c.SetTextureIsArray(false); return nullptr; } @@ -2337,7 +2338,6 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { // Since we've drawn using thin3d, might need these. gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); - } void TextureCacheCommon::Clear(bool delete_them) { From 15d4495f76d79591c290038908069c854e3080ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 11:02:58 +0200 Subject: [PATCH 119/715] Pass shadergen tests --- Common/GPU/ShaderWriter.cpp | 6 +++--- Common/GPU/ShaderWriter.h | 1 + GPU/Common/FragmentShaderGenerator.cpp | 4 ++-- GPU/Common/VertexShaderGenerator.cpp | 6 +++++- unittest/TestShaderGenerators.cpp | 6 ++++++ 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index d7e0d16856..ed7a3612f9 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -513,7 +513,7 @@ ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN)) { + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) { const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; F("%s(%s, vec3(%s, %s))", lang_.texture, sampName, uv, index); } else { @@ -537,7 +537,7 @@ ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const ch break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN)) { + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) { const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; F("%sOffset(%s, vec3(%s, %s), ivec2(%d, %d))", lang_.texture, sampName, uv, index, offX, offY); } else { @@ -561,7 +561,7 @@ ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN)) { + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) { const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "gl_ViewIndex" : "0"; F("texelFetch(%s, vec3(%s, %s), %d)", sampName, uv, index, level); } else { diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 48b0bff9e5..379e704319 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -41,6 +41,7 @@ class ShaderWriter { public: // Extensions are supported for both OpenGL ES and Vulkan (though of course, they're different). ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice extensions = Slice(), ShaderWriterFlags flags = ShaderWriterFlags::NONE) : p_(buffer), lang_(lang), stage_(stage), flags_(flags) { + buffer[0] = '\0'; Preamble(extensions); } ShaderWriter(const ShaderWriter &) = delete; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 10c516f45d..93b1e20464 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -68,6 +68,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } bool texture3D = id.Bit(FS_BIT_3D_TEXTURE); + bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE); ReplaceAlphaType stencilToAlpha = static_cast(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)); @@ -93,7 +94,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } ShaderWriter p(buffer, compat, ShaderStage::Fragment, extensions, flags); - p.ApplySamplerMetadata(useStereo ? samplersStereo : samplersMono); + p.ApplySamplerMetadata(arrayTexture ? samplersStereo : samplersMono); bool lmode = id.Bit(FS_BIT_LMODE); bool doTexture = id.Bit(FS_BIT_DO_TEXTURE); @@ -108,7 +109,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool doTextureProjection = id.Bit(FS_BIT_DO_TEXTURE_PROJ); bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA); - bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE); if (texture3D && arrayTexture) { *errorString = "Invalid combination of 3D texture and array texture, shouldn't happen"; return false; diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 3eb92c4bcd..9e6ab317b0 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -158,7 +158,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool useSimpleStereo = id.Bit(VS_BIT_SIMPLE_STEREO); - if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN && useSimpleStereo) { + if (useSimpleStereo) { + if (compat.shaderLanguage != ShaderLanguage::GLSL_VULKAN) { + *errorString = "Multiview only supported with Vulkan for now"; + return false; + } extensions.push_back("#extension GL_EXT_multiview : enable"); } diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index a420299520..6701e162fd 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -28,6 +28,8 @@ static constexpr size_t CODE_BUFFER_SIZE = 32768; bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { + buffer[0] = '\0'; + uint64_t uniformMask; switch (lang) { case ShaderLanguage::GLSL_VULKAN: @@ -61,6 +63,8 @@ bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs } bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { + buffer[0] = '\0'; + uint32_t attrMask; uint64_t uniformMask; switch (lang) { @@ -95,6 +99,8 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs } bool GenerateGShader(GShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { + buffer[0] = '\0'; + errorString->clear(); switch (lang) { From cd203291ba20332fb0746e1366b5df066fa42602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 11:23:12 +0200 Subject: [PATCH 120/715] Fix rendering in non-stereo mode --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 1 + GPU/Common/ShaderId.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index cee212ee98..fef2673d0a 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1629,6 +1629,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c default: ERROR_LOG(G3D, "Unimpl queue command"); + break; } } vkCmdEndRenderPass(cmd); diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 40b31393c9..9110ca7443 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -368,12 +368,13 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip id.SetBit(FS_BIT_FLATSHADE, doFlatShading); id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask); + // All framebuffers are array textures now. + if (gstate_c.arrayTexture) { + id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE); + } + // Stereo support if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { - // All framebuffers are array textures in this mode. - if (gstate_c.arrayTexture) { - id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE); - } id.SetBit(FS_BIT_STEREO); } From 31fd928a5c6b7813aa8e6c5b59c002b1e7200ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 13:29:56 +0200 Subject: [PATCH 121/715] Name more image views. Very useful with a little patch to the Vulkan debug layers. --- Common/GPU/Vulkan/VulkanContext.h | 3 +++ Common/GPU/Vulkan/VulkanImage.cpp | 4 ++++ Common/GPU/Vulkan/VulkanMemory.cpp | 11 +++++++---- Common/GPU/Vulkan/VulkanMemory.h | 2 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 2 ++ Common/GPU/Vulkan/VulkanRenderManager.cpp | 7 +++++++ Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 2 +- GPU/Vulkan/VulkanUtil.cpp | 2 +- 9 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index a7622e7a8f..7baf795717 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -222,6 +222,9 @@ public: SetDebugNameImpl((uint64_t)handle, type, name); } } + bool DebugLayerEnabled() const { + return extensionsLookup_.EXT_debug_utils; + } bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); diff --git a/Common/GPU/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp index 8a439d4d3e..47b1432360 100644 --- a/Common/GPU/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -123,13 +123,16 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } + vulkan_->SetDebugName(view_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_.c_str()); // Additionally, create an array view, but only if it's a 2D texture. if (view_info.viewType == VK_IMAGE_VIEW_TYPE_2D) { view_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &arrayView_); _assert_(res == VK_SUCCESS); + vulkan_->SetDebugName(arrayView_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_.c_str()); } + return true; } @@ -244,6 +247,7 @@ VkImageView VulkanTexture::CreateViewForMip(int mip) { view_info.subresourceRange.layerCount = 1; VkImageView view; VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view); + vulkan_->SetDebugName(view, VK_OBJECT_TYPE_IMAGE_VIEW, "mipview"); _assert_(res == VK_SUCCESS); return view; } diff --git a/Common/GPU/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp index 8206c80c91..d8184098a5 100644 --- a/Common/GPU/Vulkan/VulkanMemory.cpp +++ b/Common/GPU/Vulkan/VulkanMemory.cpp @@ -153,7 +153,7 @@ void VulkanDescSetPool::Create(VulkanContext *vulkan, const VkDescriptorPoolCrea _assert_msg_(res == VK_SUCCESS, "Could not create VulkanDescSetPool %s", tag_); } -VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout *layouts) { +VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag) { if (descPool_ == VK_NULL_HANDLE || usage_ + n >= info_.maxSets) { // Missing or out of space, need to recreate. VkResult res = Recreate(grow_); @@ -180,9 +180,12 @@ VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout * _assert_msg_(result == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to allocate after recreating a descriptor pool. res=%d", (int)result); } - if (result == VK_SUCCESS) - return desc; - return VK_NULL_HANDLE; + if (result != VK_SUCCESS) { + return VK_NULL_HANDLE; + } + + vulkan_->SetDebugName(desc, VK_OBJECT_TYPE_DESCRIPTOR_SET, tag); + return desc; } void VulkanDescSetPool::Reset() { diff --git a/Common/GPU/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h index c0a9c1ed02..275ca4bb78 100644 --- a/Common/GPU/Vulkan/VulkanMemory.h +++ b/Common/GPU/Vulkan/VulkanMemory.h @@ -163,7 +163,7 @@ public: void Create(VulkanContext *vulkan, const VkDescriptorPoolCreateInfo &info, const std::vector &sizes); // Allocate a new set, which may resize and empty the current sets. // Use only for the current frame, unless in a cache cleared by clear_. - VkDescriptorSet Allocate(int n, const VkDescriptorSetLayout *layouts); + VkDescriptorSet Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag); void Reset(); void Destroy(); diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index fef2673d0a..ead24a47fe 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -178,6 +178,7 @@ bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit) { // Also, turns out it's illegal to transition un-acquired images, thanks Hans-Kristian. See #11417. res = vkCreateImageView(vulkan_->GetDevice(), &color_image_view, nullptr, &sc_buffer.view); + vulkan_->SetDebugName(sc_buffer.view, VK_OBJECT_TYPE_IMAGE_VIEW, "swapchain_view"); swapchainImages_.push_back(sc_buffer); _dbg_assert_(res == VK_SUCCESS); } @@ -276,6 +277,7 @@ bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) { VkDevice device = vulkan_->GetDevice(); res = vkCreateImageView(device, &depth_view_info, NULL, &depth_.view); + vulkan_->SetDebugName(depth_.view, VK_OBJECT_TYPE_IMAGE_VIEW, "depth_stencil_backbuffer"); _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) return false; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 8c82fa00d1..a83ff65539 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -296,6 +296,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ivci.subresourceRange.layerCount = numLayers; ivci.subresourceRange.levelCount = 1; res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.rtView); + vulkan->SetDebugName(img.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); _dbg_assert_(res == VK_SUCCESS); @@ -306,6 +307,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; // layered for consistency, even if single image. res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texAllLayersView); + vulkan->SetDebugName(img.texAllLayersView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); // Create 2D views for both layers. // Useful when multipassing shaders that don't yet exist in a single-pass-stereo version. @@ -314,6 +316,11 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ivci.subresourceRange.layerCount = 1; ivci.subresourceRange.baseArrayLayer = i; res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texLayerViews[i]); + if (vulkan->DebugLayerEnabled()) { + char temp[128]; + snprintf(temp, sizeof(temp), "%s_layer%d", tag, i); + vulkan->SetDebugName(img.texLayerViews[i], VK_OBJECT_TYPE_IMAGE_VIEW, temp); + } _dbg_assert_(res == VK_SUCCESS); } diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 8b7144927b..285f08a757 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1015,7 +1015,7 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { return iter->second; } - VkDescriptorSet descSet = frame->descriptorPool.Allocate(1, &descriptorSetLayout_); + VkDescriptorSet descSet = frame->descriptorPool.Allocate(1, &descriptorSetLayout_, "thin3d_descset"); if (descSet == VK_NULL_HANDLE) { ERROR_LOG(G3D, "GetOrCreateDescriptorSet failed"); return VK_NULL_HANDLE; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 335fc29ad9..8af2727736 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -404,7 +404,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView // Didn't find one in the frame descriptor set cache, let's make a new one. // We wipe the cache on every frame. - VkDescriptorSet desc = frame.descPool.Allocate(1, &descriptorSetLayout_); + VkDescriptorSet desc = frame.descPool.Allocate(1, &descriptorSetLayout_, "game_descset"); // Even in release mode, this is bad. _assert_msg_(desc != VK_NULL_HANDLE, "Ran out of descriptor space in pool. sz=%d", (int)frame.descSets.size()); diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index fb82f9a474..d23f2ad9b2 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -136,7 +136,7 @@ void VulkanComputeShaderManager::DestroyDeviceObjects() { VkDescriptorSet VulkanComputeShaderManager::GetDescriptorSet(VkImageView image, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkBuffer buffer2, VkDeviceSize offset2, VkDeviceSize range2) { int curFrame = vulkan_->GetCurFrame(); FrameData &frameData = frameData_[curFrame]; - VkDescriptorSet desc = frameData.descPool.Allocate(1, &descriptorSetLayout_); + VkDescriptorSet desc = frameData.descPool.Allocate(1, &descriptorSetLayout_, "compute_descset"); _assert_(desc != VK_NULL_HANDLE); VkWriteDescriptorSet writes[2]{}; From 7d5bb7925747d3f6ac5ebdf41895961ba93275a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 13:32:38 +0200 Subject: [PATCH 122/715] Fix depal texture binding bug --- GPU/Common/TextureCacheCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 8e60f8e5aa..e660bb20f8 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -2220,7 +2220,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer draw_->BindTexture(0, nullptr); framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); BoundFramebufferTexture(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); From 931c869ca9a61dd6957ca603d30caed33e521d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 13:40:13 +0200 Subject: [PATCH 123/715] Fix for stereo with textureProj (emulated projection). --- GPU/Common/FragmentShaderGenerator.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 93b1e20464..879552e253 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -663,7 +663,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu // Used for stereo rendering. const char *arrayIndex = useStereo ? "float(gl_ViewIndex)" : "0.0"; if (doTextureProjection) { - WRITE(p, " vec4 t = %sProj(tex, vec4(%s, %s));\n", compat.texture, texcoord, arrayIndex); + // There's no textureProj for array textures, so we need to emulate it. + // Should be fine on any Vulkan-compatible hardware. + WRITE(p, " vec2 uv_proj = (%s.xy) / (%s.z);\n", texcoord, texcoord); + WRITE(p, " vec4 t = %s(tex, vec3(uv_proj, %s));\n", compat.texture, texcoord, arrayIndex); } else { WRITE(p, " vec4 t = %s(tex, vec3(%s.xy, %s));\n", compat.texture, texcoord, arrayIndex); } From 763afd4a8e8125c157c1168ab0641a043ae768a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 16:02:18 +0200 Subject: [PATCH 124/715] Improve compatibility checks for stereo rendering. --- Common/GPU/D3D9/thin3d_d3d9.cpp | 1 - Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- Common/GPU/thin3d.h | 2 +- GPU/Common/PresentationCommon.cpp | 5 +++-- GPU/Vulkan/GPU_Vulkan.cpp | 5 +++-- UI/GameSettingsScreen.cpp | 23 ++++++++++++++--------- UI/GameSettingsScreen.h | 2 ++ 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index ec524c8dab..8de75b09d0 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -746,7 +746,6 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID } caps_.deviceID = identifier_.DeviceId; - caps_.multiViewport = false; caps_.depthRangeMinusOneToOne = false; caps_.preferredDepthBufferFormat = DataFormat::D24_S8; caps_.dualSourceBlend = false; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 285f08a757..c5dcc65f40 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -785,7 +785,6 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.standard.samplerAnisotropy != 0; caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.geometryShader != 0; caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.tessellationShader != 0; - caps_.multiViewport = vulkan->GetDeviceFeatures().enabled.standard.multiViewport != 0; caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.standard.dualSrcBlend != 0; caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.standard.depthClamp != 0; caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderClipDistance != 0; @@ -804,6 +803,7 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.fragmentShaderDepthWriteSupported = true; caps_.blendMinMaxSupported = true; caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0; + caps_.multiViewSupported = vulkan->GetDeviceFeatures().enabled.multiview.multiview != 0; auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties; diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 226270f8c9..e617954010 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -548,7 +548,6 @@ struct DeviceCaps { bool depthRangeMinusOneToOne; // OpenGL style depth bool geometryShaderSupported; bool tesselationShaderSupported; - bool multiViewport; bool dualSourceBlend; bool logicOpSupported; bool depthClampSupported; @@ -567,6 +566,7 @@ struct DeviceCaps { bool fragmentShaderDepthWriteSupported; bool textureDepthSupported; bool blendMinMaxSupported; + bool multiViewSupported; std::string deviceName; // The device name to use when creating the thin3d context, to get the same one. }; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 1cd86101d5..025888896c 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -34,6 +34,7 @@ #include "Core/HW/Display.h" #include "GPU/Common/PostShader.h" #include "GPU/Common/PresentationCommon.h" +#include "GPU/GPUState.h" #include "Common/GPU/ShaderTranslation.h" struct Vertex { @@ -230,7 +231,7 @@ static std::string ReadShaderSrc(const Path &filename) { bool PresentationCommon::UpdatePostShader() { DestroyStereoShader(); - if (g_Config.bStereoRendering) { + if (gstate_c.Use(GPU_USE_SIMPLE_STEREO_PERSPECTIVE)) { const ShaderInfo *stereoShaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); if (!result) { @@ -622,7 +623,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u // This should auto-disable usePostShader_ and call ShowPostShaderError(). bool useNearest = flags & OutputFlags::NEAREST; - bool useStereo = g_Config.bStereoRendering && stereoPipeline_ != nullptr; // TODO: Also check that the backend has support for it. + bool useStereo = gstate_c.Use(GPU_USE_SIMPLE_STEREO_PERSPECTIVE) && stereoPipeline_ != nullptr; // TODO: Also check that the backend has support for it. const bool usePostShader = usePostShader_ && !useStereo && !(flags & OutputFlags::RB_SWIZZLE); const bool isFinalAtOutputResolution = usePostShader && postShaderFramebuffers_.size() < postShaderPipelines_.size(); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 29c5e1e459..d7ac28d3c6 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -268,12 +268,13 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { features |= GPU_ROUND_DEPTH_TO_16BIT; } - if (g_Config.bStereoRendering) { + if (g_Config.bStereoRendering && draw_->GetDeviceCaps().multiViewSupported) { features |= GPU_USE_SINGLE_PASS_STEREO; + features |= GPU_USE_SIMPLE_STEREO_PERSPECTIVE; + features &= ~GPU_USE_FRAMEBUFFER_FETCH; // Need to figure out if this can be supported with multiview rendering if (features & GPU_USE_GS_CULLING) { // Many devices that support stereo and GS don't support GS during stereo. - // So we revert back to VS range culling. features &= ~GPU_USE_GS_CULLING; features |= GPU_USE_VS_RANGE_CULLING; } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 1d1d9c0125..822f566221 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -350,12 +350,17 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); - if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { - graphicsSettings->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering"))); + enableStereo_ = g_Config.bStereoRendering && draw->GetDeviceCaps().multiViewSupported; + + if (draw->GetDeviceCaps().multiViewSupported) { + graphicsSettings->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering")))->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + enableStereo_ = g_Config.bStereoRendering && draw->GetDeviceCaps().multiViewSupported; + return UI::EVENT_DONE; + }); std::vector stereoShaderNames; ChoiceWithValueDisplay *stereoShaderChoice = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, "Stereo display shader", &PostShaderTranslateName)); - stereoShaderChoice->SetEnabledPtr(&g_Config.bStereoRendering); + stereoShaderChoice->SetEnabledPtr(&enableStereo_); stereoShaderChoice->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Stereo display shader"), 0, true); @@ -371,8 +376,8 @@ void GameSettingsScreen::CreateViews() { if (!setting.name.empty()) { auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); - settingValue->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && g_Config.bStereoRendering; + settingValue->SetEnabledFunc([&] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && enableStereo_; }); } } @@ -393,8 +398,8 @@ void GameSettingsScreen::CreateViews() { screenManager()->push(procScreen); return UI::EVENT_DONE; }); - postProcChoice_->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !g_Config.bStereoRendering; + postProcChoice_->SetEnabledFunc([&] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo_; }); // No need for settings on the last one. @@ -416,8 +421,8 @@ void GameSettingsScreen::CreateViews() { settingValue->SetEnabled(false); } else { PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); - settingValue->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !g_Config.bStereoRendering; + settingValue->SetEnabledFunc([&] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo_; }); } } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 82b4cd859e..9a9456cf4f 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -142,6 +142,8 @@ private: bool enableReports_ = false; bool enableReportsSet_ = false; bool analogSpeedMapped_ = false; + bool enableStereo_ = false; + std::string shaderNames_[256]; std::string searchFilter_; From e0bbebc65e8ca7c7c07bf3fb150aa3ad5747fcf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 18:39:43 +0200 Subject: [PATCH 125/715] Clean up GPU_Vulkan::BuildReportingInfo a bit --- GPU/Vulkan/GPU_Vulkan.cpp | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index d7ac28d3c6..12d0328f98 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -340,14 +340,11 @@ void GPU_Vulkan::BuildReportingInfo() { const auto &available = vulkan->GetDeviceFeatures().available; #define CHECK_BOOL_FEATURE(n) do { if (available.standard.n) { featureNames += ", " #n; } } while (false) +#define CHECK_BOOL_FEATURE_MULTIVIEW(n) do { if (available.multiview.n) { featureNames += ", " #n; } } while (false) std::string featureNames = ""; - CHECK_BOOL_FEATURE(robustBufferAccess); CHECK_BOOL_FEATURE(fullDrawIndexUint32); - CHECK_BOOL_FEATURE(imageCubeArray); - CHECK_BOOL_FEATURE(independentBlend); CHECK_BOOL_FEATURE(geometryShader); - CHECK_BOOL_FEATURE(tessellationShader); CHECK_BOOL_FEATURE(sampleRateShading); CHECK_BOOL_FEATURE(dualSrcBlend); CHECK_BOOL_FEATURE(logicOp); @@ -355,46 +352,23 @@ void GPU_Vulkan::BuildReportingInfo() { CHECK_BOOL_FEATURE(drawIndirectFirstInstance); CHECK_BOOL_FEATURE(depthClamp); CHECK_BOOL_FEATURE(depthBiasClamp); - CHECK_BOOL_FEATURE(fillModeNonSolid); CHECK_BOOL_FEATURE(depthBounds); - CHECK_BOOL_FEATURE(alphaToOne); - CHECK_BOOL_FEATURE(multiViewport); CHECK_BOOL_FEATURE(samplerAnisotropy); CHECK_BOOL_FEATURE(textureCompressionETC2); CHECK_BOOL_FEATURE(textureCompressionASTC_LDR); CHECK_BOOL_FEATURE(textureCompressionBC); CHECK_BOOL_FEATURE(occlusionQueryPrecise); CHECK_BOOL_FEATURE(pipelineStatisticsQuery); - CHECK_BOOL_FEATURE(vertexPipelineStoresAndAtomics); CHECK_BOOL_FEATURE(fragmentStoresAndAtomics); CHECK_BOOL_FEATURE(shaderTessellationAndGeometryPointSize); - CHECK_BOOL_FEATURE(shaderImageGatherExtended); - CHECK_BOOL_FEATURE(shaderStorageImageExtendedFormats); CHECK_BOOL_FEATURE(shaderStorageImageMultisample); - CHECK_BOOL_FEATURE(shaderStorageImageReadWithoutFormat); - CHECK_BOOL_FEATURE(shaderStorageImageWriteWithoutFormat); - CHECK_BOOL_FEATURE(shaderUniformBufferArrayDynamicIndexing); CHECK_BOOL_FEATURE(shaderSampledImageArrayDynamicIndexing); - CHECK_BOOL_FEATURE(shaderStorageBufferArrayDynamicIndexing); - CHECK_BOOL_FEATURE(shaderStorageImageArrayDynamicIndexing); CHECK_BOOL_FEATURE(shaderClipDistance); CHECK_BOOL_FEATURE(shaderCullDistance); - CHECK_BOOL_FEATURE(shaderFloat64); CHECK_BOOL_FEATURE(shaderInt64); CHECK_BOOL_FEATURE(shaderInt16); - CHECK_BOOL_FEATURE(shaderResourceResidency); - CHECK_BOOL_FEATURE(shaderResourceMinLod); - CHECK_BOOL_FEATURE(sparseBinding); - CHECK_BOOL_FEATURE(sparseResidencyBuffer); - CHECK_BOOL_FEATURE(sparseResidencyImage2D); - CHECK_BOOL_FEATURE(sparseResidencyImage3D); - CHECK_BOOL_FEATURE(sparseResidency2Samples); - CHECK_BOOL_FEATURE(sparseResidency4Samples); - CHECK_BOOL_FEATURE(sparseResidency8Samples); - CHECK_BOOL_FEATURE(sparseResidency16Samples); - CHECK_BOOL_FEATURE(sparseResidencyAliased); - CHECK_BOOL_FEATURE(variableMultisampleRate); - CHECK_BOOL_FEATURE(inheritedQueries); + CHECK_BOOL_FEATURE_MULTIVIEW(multiview); + CHECK_BOOL_FEATURE_MULTIVIEW(multiviewGeometryShader); #undef CHECK_BOOL_FEATURE From 6d9008dab572fc63a4360a32f8c472612b2a6247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 20:26:30 +0200 Subject: [PATCH 126/715] Fix validation issue with clears, remove redundant code --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 6 +----- Common/GPU/Vulkan/VulkanQueueRunner.h | 6 ------ Common/GPU/Vulkan/VulkanRenderManager.cpp | 1 - Common/GPU/Vulkan/VulkanRenderManager.h | 9 --------- GPU/Common/VertexShaderGenerator.cpp | 2 +- 5 files changed, 2 insertions(+), 22 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index ead24a47fe..1e31ca8525 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1583,17 +1583,13 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c vkCmdDraw(cmd, c.draw.count, 1, c.draw.offset, 0); break; - case VKRRenderCommand::BIND_DESCRIPTOR_SET: - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, c.bindDescSet.setIndex, 1, &c.bindDescSet.descSet, 0, nullptr); - break; - case VKRRenderCommand::CLEAR: { // If we get here, we failed to merge a clear into a render pass load op. This is bad for perf. int numAttachments = 0; VkClearRect rc{}; rc.baseArrayLayer = 0; - rc.layerCount = c.clear.numLayers; + rc.layerCount = 1; // In multiview mode, 1 means to replicate to all the active layers. rc.rect.extent.width = (uint32_t)curWidth; rc.rect.extent.height = (uint32_t)curHeight; VkClearAttachment attachments[2]{}; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index ffac3003fa..effc3645bc 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -37,7 +37,6 @@ enum class VKRRenderCommand : uint8_t { DRAW, DRAW_INDEXED, PUSH_CONSTANTS, - BIND_DESCRIPTOR_SET, SELF_DEPENDENCY_BARRIER, DEBUG_ANNOTATION, NUM_RENDER_COMMANDS, @@ -129,7 +128,6 @@ struct VkRenderData { float clearZ; int clearStencil; int clearMask; // VK_IMAGE_ASPECT_COLOR_BIT etc - int numLayers; } clear; struct { VkViewport vp; @@ -154,10 +152,6 @@ struct VkRenderData { struct { const char *annotation; } debugAnnotation; - struct { - uint32_t setIndex; - VkDescriptorSet descSet; - } bindDescSet; }; }; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index a83ff65539..314e1920c3 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -833,7 +833,6 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR data.clear.clearZ = clearDepth; data.clear.clearStencil = clearStencil; data.clear.clearMask = clearMask; - data.clear.numLayers = curRenderStep_->render.framebuffer ? curRenderStep_->render.framebuffer->numLayers : 1; curRenderStep_->commands.push_back(data); curRenderArea_.SetRect(0, 0, curWidth_, curHeight_); } diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index cd1e843454..afe8ac15fe 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -270,15 +270,6 @@ public: compileMutex_.unlock(); } - // We always pass in desc set 0 directly in draw commands. This is used only to bind higher descriptor sets. - void BindDescriptorSet(int index, const VkDescriptorSet descSet) { - _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); - VkRenderData data{ VKRRenderCommand::BIND_DESCRIPTOR_SET }; - data.bindDescSet.setIndex = index; - data.bindDescSet.descSet = descSet; - curRenderStep_->commands.push_back(data); - } - void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 9e6ab317b0..cbf51f1b24 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1351,7 +1351,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " }\n"); } - if (useSimpleStereo) { + if (useSimpleStereo && useHWTransform) { p.C(" float zFactor = 0.2 * float(gl_ViewIndex * 2 - 1);\n"); p.C(" float zFocus = 0.0;\n"); p.C(" gl_Position.x += (-gl_Position.z - zFocus) * zFactor;\n"); From 1da6d29a0f704abfc45902af55d339b32d1b58a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 20:39:53 +0200 Subject: [PATCH 127/715] Crashfix in settings menu (Android only, for whatever reason) --- UI/GameSettingsScreen.cpp | 19 ++++++++++--------- UI/GameSettingsScreen.h | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 822f566221..95bd12d276 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -350,17 +350,18 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); - enableStereo_ = g_Config.bStereoRendering && draw->GetDeviceCaps().multiViewSupported; + bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; + + auto enableStereo = [=]() -> bool { + return g_Config.bStereoRendering && multiViewSupported; + }; if (draw->GetDeviceCaps().multiViewSupported) { - graphicsSettings->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering")))->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { - enableStereo_ = g_Config.bStereoRendering && draw->GetDeviceCaps().multiViewSupported; - return UI::EVENT_DONE; - }); + graphicsSettings->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering"))); std::vector stereoShaderNames; ChoiceWithValueDisplay *stereoShaderChoice = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, "Stereo display shader", &PostShaderTranslateName)); - stereoShaderChoice->SetEnabledPtr(&enableStereo_); + stereoShaderChoice->SetEnabledFunc(enableStereo); stereoShaderChoice->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Stereo display shader"), 0, true); @@ -377,7 +378,7 @@ void GameSettingsScreen::CreateViews() { auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetEnabledFunc([&] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && enableStereo_; + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && enableStereo(); }); } } @@ -399,7 +400,7 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_DONE; }); postProcChoice_->SetEnabledFunc([&] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo_; + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo(); }); // No need for settings on the last one. @@ -422,7 +423,7 @@ void GameSettingsScreen::CreateViews() { } else { PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetEnabledFunc([&] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo_; + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo(); }); } } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 9a9456cf4f..2fd7d6e59d 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -142,7 +142,6 @@ private: bool enableReports_ = false; bool enableReportsSet_ = false; bool analogSpeedMapped_ = false; - bool enableStereo_ = false; std::string shaderNames_[256]; std::string searchFilter_; From e058f8aee61d6e1963a8a2e046cd3e713c25ff9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Oct 2022 23:48:45 +0200 Subject: [PATCH 128/715] Shadergen fix for OpenGL --- GPU/Common/FragmentShaderGenerator.cpp | 5 +++++ GPU/Common/ShaderId.cpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 879552e253..7f09f7c390 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -113,6 +113,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu *errorString = "Invalid combination of 3D texture and array texture, shouldn't happen"; return false; } + if (compat.shaderLanguage != ShaderLanguage::GLSL_VULKAN && arrayTexture) { + *errorString = "We only do array textures for framebuffers in Vulkan."; + return false; + } bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled; @@ -660,6 +664,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " vec4 t = %s(tex, vec3(%s.xy, u_mipBias));\n", compat.texture3D, texcoord); } } else if (arrayTexture) { + _dbg_assert_(compat.shaderLanguage == GLSL_VULKAN); // Used for stereo rendering. const char *arrayIndex = useStereo ? "float(gl_ViewIndex)" : "0.0"; if (doTextureProjection) { diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 9110ca7443..aee52476cf 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -368,8 +368,8 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip id.SetBit(FS_BIT_FLATSHADE, doFlatShading); id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask); - // All framebuffers are array textures now. - if (gstate_c.arrayTexture) { + // All framebuffers are array textures in Vulkan now. + if (gstate_c.arrayTexture && g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE); } From 85e7933e7a4ba806c4349fe86d434cbd194f976d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 27 Oct 2022 11:05:38 +0200 Subject: [PATCH 129/715] Format string fix --- GPU/Common/PostShader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 43db9093ac..6b0b94387a 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -225,7 +225,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct appendTextureShader(info); } } else if (!section.name().empty()) { - WARN_LOG(G3D, "Unrecognized shader type '%s' or invalid shader in section '%s' : %d", shaderType.c_str(), section.name().c_str()); + WARN_LOG(G3D, "Unrecognized shader type '%s' or invalid shader in section '%s'", shaderType.c_str(), section.name().c_str()); } } } From 3454ea9c1dfcac6c668cdebc3349e54fed77a04b Mon Sep 17 00:00:00 2001 From: iota97 Date: Thu, 27 Oct 2022 14:57:19 +0200 Subject: [PATCH 130/715] Fix UB --- UI/GameSettingsScreen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 95bd12d276..706eb07cfe 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -377,7 +377,7 @@ void GameSettingsScreen::CreateViews() { if (!setting.name.empty()) { auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); - settingValue->SetEnabledFunc([&] { + settingValue->SetEnabledFunc([=] { return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && enableStereo(); }); } @@ -399,7 +399,7 @@ void GameSettingsScreen::CreateViews() { screenManager()->push(procScreen); return UI::EVENT_DONE; }); - postProcChoice_->SetEnabledFunc([&] { + postProcChoice_->SetEnabledFunc([=] { return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo(); }); @@ -422,7 +422,7 @@ void GameSettingsScreen::CreateViews() { settingValue->SetEnabled(false); } else { PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); - settingValue->SetEnabledFunc([&] { + settingValue->SetEnabledFunc([=] { return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo(); }); } From 906f8b5d8bcb857b5dfa5cbc02e979de3c105a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Thu, 27 Oct 2022 23:47:53 +0800 Subject: [PATCH 131/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 4a7b474d9c..b99a218f01 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -819,7 +819,7 @@ InverseColors = 反轉色彩 Natural = 自然色彩 NaturalA = 自然色彩 (無模糊) Off = 關閉 -Power = Power +Power = 強度 PSPColor = PSP 色彩 Saturation = 飽和度 Scanlines = 掃描線 (CRT) From 28229e28867a690470f795b9170eb00eb4c1c305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Thu, 27 Oct 2022 23:54:37 +0800 Subject: [PATCH 132/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index b99a218f01..e94959fd9e 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -278,7 +278,7 @@ VFPU = VFPU [Dialog] * PSP res = * PSP 解析度 -Active = Active +Active = 啟用 Back = 返回 Cancel = 取消 Center = 中心 From b9de1a44df3eb4586a24f825f35c5085fa3db640 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 27 Oct 2022 23:26:44 -0700 Subject: [PATCH 133/715] jit: Reduce some include pollution. Usually no need for all of MIPSAnalyst. --- Core/MIPS/ARM/ArmCompALU.cpp | 1 + Core/MIPS/ARM/ArmJit.cpp | 1 + Core/MIPS/ARM/ArmRegCache.h | 7 +++++-- Core/MIPS/ARM/ArmRegCacheFPU.h | 7 +++++-- Core/MIPS/ARM64/Arm64CompALU.cpp | 1 + Core/MIPS/ARM64/Arm64Jit.cpp | 1 + Core/MIPS/ARM64/Arm64RegCache.h | 5 ++++- Core/MIPS/ARM64/Arm64RegCacheFPU.h | 7 +++++-- Core/MIPS/JitCommon/JitBlockCache.h | 1 - Core/MIPS/x86/CompALU.cpp | 1 + Core/MIPS/x86/Jit.cpp | 1 + Core/MIPS/x86/JitSafeMem.cpp | 1 + Core/MIPS/x86/RegCache.h | 5 ++++- Core/MIPS/x86/RegCacheFPU.h | 5 ++++- unittest/TestArmEmitter.cpp | 1 + 15 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 0b5bf067f8..01bf94203e 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -24,6 +24,7 @@ #include "Common/CPUDetect.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/ARM/ArmJit.h" #include "Core/MIPS/ARM/ArmRegCache.h" diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 74675a6ae4..3048773bb6 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -33,6 +33,7 @@ #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPSInt.h" #include "Core/MIPS/MIPSTables.h" diff --git a/Core/MIPS/ARM/ArmRegCache.h b/Core/MIPS/ARM/ArmRegCache.h index bd85cc10b2..0a405a7158 100644 --- a/Core/MIPS/ARM/ArmRegCache.h +++ b/Core/MIPS/ARM/ArmRegCache.h @@ -17,8 +17,7 @@ #pragma once -#include "../MIPS.h" -#include "../MIPSAnalyst.h" +#include "Core/MIPS/MIPS.h" #include "ArmEmitter.h" namespace ArmJitConstants { @@ -52,6 +51,10 @@ enum { } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + // R1 to R6: mapped MIPS regs // R8 = flags (maybe we could do better here?) // R9 = code pointers diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.h b/Core/MIPS/ARM/ArmRegCacheFPU.h index 3e08d719bb..f572c84a97 100644 --- a/Core/MIPS/ARM/ArmRegCacheFPU.h +++ b/Core/MIPS/ARM/ArmRegCacheFPU.h @@ -19,8 +19,7 @@ #pragma once -#include "../MIPS.h" -#include "../MIPSAnalyst.h" +#include "Core/MIPS/MIPS.h" #include "Core/MIPS/ARM/ArmRegCache.h" #include "Core/MIPS/MIPSVFPUUtils.h" #include "Common/ArmEmitter.h" @@ -46,6 +45,10 @@ enum { } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct FPURegARM { int mipsReg; // if -1, no mipsreg attached. bool isDirty; // Should the register be written back? diff --git a/Core/MIPS/ARM64/Arm64CompALU.cpp b/Core/MIPS/ARM64/Arm64CompALU.cpp index afb8d2b4a8..13a2361d86 100644 --- a/Core/MIPS/ARM64/Arm64CompALU.cpp +++ b/Core/MIPS/ARM64/Arm64CompALU.cpp @@ -24,6 +24,7 @@ #include "Common/CPUDetect.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/ARM64/Arm64Jit.h" #include "Core/MIPS/ARM64/Arm64RegCache.h" diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index b111784c1a..f9d7e2d684 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -34,6 +34,7 @@ #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPSInt.h" #include "Core/MIPS/MIPSTables.h" diff --git a/Core/MIPS/ARM64/Arm64RegCache.h b/Core/MIPS/ARM64/Arm64RegCache.h index 62f7771192..5528120098 100644 --- a/Core/MIPS/ARM64/Arm64RegCache.h +++ b/Core/MIPS/ARM64/Arm64RegCache.h @@ -18,7 +18,6 @@ #pragma once #include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSAnalyst.h" #include "Common/Arm64Emitter.h" namespace Arm64JitConstants { @@ -55,6 +54,10 @@ enum { } // namespace +namespace MIPSAnalyst { +struct AnalysisResults; +}; + typedef int MIPSReg; struct RegARM64 { diff --git a/Core/MIPS/ARM64/Arm64RegCacheFPU.h b/Core/MIPS/ARM64/Arm64RegCacheFPU.h index 13284d2389..657d218611 100644 --- a/Core/MIPS/ARM64/Arm64RegCacheFPU.h +++ b/Core/MIPS/ARM64/Arm64RegCacheFPU.h @@ -19,8 +19,7 @@ #pragma once -#include "../MIPS.h" -#include "../MIPSAnalyst.h" +#include "Core/MIPS/MIPS.h" #include "Core/MIPS/ARM64/Arm64RegCache.h" #include "Core/MIPS/MIPSVFPUUtils.h" #include "Common/Arm64Emitter.h" @@ -46,6 +45,10 @@ enum { } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct FPURegARM64 { int mipsReg; // if -1, no mipsreg attached. bool isDirty; // Should the register be written back? diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index 28a432fafe..f8836160ea 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -26,7 +26,6 @@ #include "ppsspp_config.h" #include "Common/CommonTypes.h" #include "Common/CodeBlock.h" -#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPS.h" #if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) diff --git a/Core/MIPS/x86/CompALU.cpp b/Core/MIPS/x86/CompALU.cpp index e3534b39fe..c8319efcb0 100644 --- a/Core/MIPS/x86/CompALU.cpp +++ b/Core/MIPS/x86/CompALU.cpp @@ -23,6 +23,7 @@ #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/x86/Jit.h" #include "Core/MIPS/x86/RegCache.h" diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index c27ee3b502..266b97da00 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -34,6 +34,7 @@ #include "Core/Reporting.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPSInt.h" #include "Core/MIPS/MIPSTables.h" diff --git a/Core/MIPS/x86/JitSafeMem.cpp b/Core/MIPS/x86/JitSafeMem.cpp index 38c6c75554..0fedb39882 100644 --- a/Core/MIPS/x86/JitSafeMem.cpp +++ b/Core/MIPS/x86/JitSafeMem.cpp @@ -23,6 +23,7 @@ #include "Core/Debugger/Breakpoints.h" #include "Core/MemMap.h" #include "Core/MIPS/JitCommon/JitCommon.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/x86/Jit.h" #include "Core/MIPS/x86/JitSafeMem.h" #include "Core/System.h" diff --git a/Core/MIPS/x86/RegCache.h b/Core/MIPS/x86/RegCache.h index 218677485d..f852401f8d 100644 --- a/Core/MIPS/x86/RegCache.h +++ b/Core/MIPS/x86/RegCache.h @@ -20,7 +20,6 @@ #include "ppsspp_config.h" #include "Common/x64Emitter.h" #include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSAnalyst.h" namespace X64JitConstants { #if PPSSPP_ARCH(AMD64) @@ -42,6 +41,10 @@ namespace X64JitConstants { #endif } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct MIPSCachedReg { Gen::OpArg location; bool away; // value not in source register diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index 04faf64cdd..0e63de5a68 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -19,7 +19,6 @@ #include "Common/x64Emitter.h" #include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSVFPUUtils.h" #undef MAP_NOINIT @@ -56,6 +55,10 @@ enum { #define NUM_X_FPREGS 8 #endif +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct X64CachedFPReg { union { int mipsReg; diff --git a/unittest/TestArmEmitter.cpp b/unittest/TestArmEmitter.cpp index 94acdbdb1f..8932ba7c9c 100644 --- a/unittest/TestArmEmitter.cpp +++ b/unittest/TestArmEmitter.cpp @@ -2,6 +2,7 @@ #include "Core/MIPS/ARM/ArmRegCacheFPU.h" #include "Core/MIPS/ARM/ArmJit.h" #include "Core/MIPS/JitCommon/JitState.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSVFPUUtils.h" #include "ext/disarm.h" From 96a5c520373d53febf3825395abdfb37905a51a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 28 Oct 2022 09:23:44 +0200 Subject: [PATCH 134/715] Vulkan: Reserve descriptor set 0 for frame-global data, move everything else to set 1 --- Common/GPU/ShaderTranslation.cpp | 8 ++--- Common/GPU/ShaderWriter.cpp | 6 ++-- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 8 +++-- Common/GPU/Vulkan/VulkanQueueRunner.h | 6 ++++ Common/GPU/Vulkan/VulkanRenderManager.h | 10 ++++++ Common/GPU/Vulkan/thin3d_vulkan.cpp | 44 ++++++++++++++++++++----- Common/GPU/thin3d.cpp | 8 ++--- Common/GPU/thin3d.h | 2 ++ GPU/Common/FragmentShaderGenerator.cpp | 10 +++--- GPU/Common/VertexShaderGenerator.cpp | 12 +++---- GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++- GPU/Vulkan/DrawEngineVulkan.h | 3 +- GPU/Vulkan/TextureCacheVulkan.cpp | 8 ++--- GPU/Vulkan/VulkanUtil.cpp | 14 ++++---- GPU/Vulkan/VulkanUtil.h | 9 ++--- UI/GPUDriverTestScreen.cpp | 10 +++--- 16 files changed, 108 insertions(+), 54 deletions(-) diff --git a/Common/GPU/ShaderTranslation.cpp b/Common/GPU/ShaderTranslation.cpp index 9391d1b7da..732ef68633 100644 --- a/Common/GPU/ShaderTranslation.cpp +++ b/Common/GPU/ShaderTranslation.cpp @@ -98,7 +98,7 @@ R"(#version 450 )"; static const char *vulkanUboDecl = R"( -layout (std140, set = 0, binding = 0) uniform Data { +layout (std140, set = 1, binding = 0) uniform Data { vec2 u_texelDelta; vec2 u_pixelDelta; vec4 u_time; @@ -187,11 +187,11 @@ bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetada continue; } else if (line.find("uniform sampler2D") == 0) { if (sscanf(line.c_str(), "uniform sampler2D sampler%d", &num) == 1) - line = StringFromFormat("layout(set = 0, binding = %d) ", num + 1) + line; + line = StringFromFormat("layout(set = 1, binding = %d) ", num + 1) + line; else if (line.find("sampler0") != line.npos) - line = "layout(set = 0, binding = 1) " + line; + line = "layout(set = 1, binding = 1) " + line; else - line = "layout(set = 0, binding = 2) " + line; + line = "layout(set = 1, binding = 2) " + line; } else if (line.find("uniform ") != std::string::npos) { continue; } else if (2 == sscanf(line.c_str(), "varying vec%d v_texcoord%d;", &vecSize, &num)) { diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index ed7a3612f9..01132b11de 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -326,7 +326,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var } C("layout(location = 0, index = 0) out vec4 fragColor0;\n"); if (!uniforms.is_empty()) { - C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n"); + C("layout(std140, set = 1, binding = 0) uniform bufferVals {\n"); for (auto &uniform : uniforms) { F("%s %s;\n", uniform.type, uniform.name); } @@ -480,9 +480,9 @@ void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { case GLSL_VULKAN: // texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1. if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) { - F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); + F("layout(set = 1, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); } else { - F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); + F("layout(set = 1, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); } break; default: diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 1e31ca8525..47e5b94046 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1567,7 +1567,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c case VKRRenderCommand::DRAW_INDEXED: { - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, (VkIndexType)c.drawIndexed.indexType); VkDeviceSize voffset = c.drawIndexed.voffset; vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &voffset); @@ -1576,7 +1576,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } case VKRRenderCommand::DRAW: - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); if (c.draw.vbuffer) { vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); } @@ -1625,6 +1625,10 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } break; + case VKRRenderCommand::BIND_DESCRIPTOR_SET: + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.bindDescSet.pipelineLayout, c.bindDescSet.setNumber, 1, &c.bindDescSet.set, 0, nullptr); + break; + default: ERROR_LOG(G3D, "Unimpl queue command"); break; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index effc3645bc..2466e576f7 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -39,6 +39,7 @@ enum class VKRRenderCommand : uint8_t { PUSH_CONSTANTS, SELF_DEPENDENCY_BARRIER, DEBUG_ANNOTATION, + BIND_DESCRIPTOR_SET, NUM_RENDER_COMMANDS, }; @@ -152,6 +153,11 @@ struct VkRenderData { struct { const char *annotation; } debugAnnotation; + struct { + int setNumber; + VkDescriptorSet set; + VkPipelineLayout pipelineLayout; + } bindDescSet; }; }; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index afe8ac15fe..26e1eb5220 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -270,6 +270,16 @@ public: compileMutex_.unlock(); } + // Mainly used to bind the frame-global desc set. + // Can be done before binding a pipeline, so not asserting on that. + void BindDescriptorSet(int setNumber, VkDescriptorSet set, VkPipelineLayout pipelineLayout) { + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::BIND_DESCRIPTOR_SET }; + data.bindDescSet.setNumber = setNumber; + data.bindDescSet.set = set; + curRenderStep_->commands.push_back(data); + } + void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index c5dcc65f40..fda775f1d0 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -35,15 +35,22 @@ #include "Core/Config.h" -// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point. -// binding 0 - uniform data -// binding 1 - sampler -// binding 2 - sampler -// -// Vertex data lives in a separate namespace (location = 0, 1, etc) - #include "Common/GPU/Vulkan/VulkanLoader.h" +// We support a frame-global descriptor set, which can be optionally used by other code, +// but is not directly used by thin3d. It has to be defined here though, be in set 0 +// and specified in every pipeline layout, otherwise it can't sit undisturbed when other +// descriptor sets are bound on top. + +// For descriptor set 1, we use a simple descriptor set for all thin3d rendering: 1 UBO binding point, 3 combined texture/samples. +// +// binding 0 - uniform buffer +// binding 1 - texture/sampler +// binding 2 - texture/sampler +// binding 3 - texture/sampler +// +// Vertex data lives in a separate namespace (location = 0, 1, etc). + using namespace PPSSPP_VK; namespace Draw { @@ -514,6 +521,7 @@ private: int curIBufferOffset_ = 0; VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE; + VkDescriptorSetLayout frameDescSetLayout_ = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE; VkPipelineCache pipelineCache_ = VK_NULL_HANDLE; AutoRef curFramebuffer_; @@ -921,13 +929,25 @@ VKContext::VKContext(VulkanContext *vulkan) VkResult res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_); _assert_(VK_SUCCESS == res); + VkDescriptorSetLayoutBinding frameBindings[1]{}; + frameBindings[0].descriptorCount = 1; + frameBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + frameBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + frameBindings[0].binding = 0; + + dsl.bindingCount = ARRAY_SIZE(frameBindings); + dsl.pBindings = frameBindings; + res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &frameDescSetLayout_); + _dbg_assert_(VK_SUCCESS == res); + vulkan_->SetDebugName(descriptorSetLayout_, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "thin3d_d_layout"); VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout setLayouts[2] = { frameDescSetLayout_, descriptorSetLayout_ }; + pl.setLayoutCount = ARRAY_SIZE(setLayouts); + pl.pSetLayouts = setLayouts; res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_); _assert_(VK_SUCCESS == res); @@ -947,6 +967,7 @@ VKContext::~VKContext() { delete frame_[i].pushBuffer; } vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); + vulkan_->Delete().QueueDeleteDescriptorSetLayout(frameDescSetLayout_); vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_); vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_); } @@ -1681,6 +1702,11 @@ uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) { _dbg_assert_(layer < curFramebuffer_->Layers()); return (uint64_t)curFramebuffer_->GetFB()->color.texLayerViews[layer]; } + case NativeObject::FRAME_DATA_DESC_SET_LAYOUT: + return (uint64_t)frameDescSetLayout_; + case NativeObject::THIN3D_PIPELINE_LAYOUT: + return (uint64_t)pipelineLayout_; + default: Crash(); return 0; diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index ac2daa68c7..3aad02abc6 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -137,7 +137,7 @@ static const std::vector fsTexCol = { "layout(location = 0) in vec4 oColor0;\n" "layout(location = 1) in vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0;\n" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n" } }; @@ -181,7 +181,7 @@ static const std::vector fsTexColRBSwizzle = { "layout(location = 0) in vec4 oColor0;\n" "layout(location = 1) in vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0\n;" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0).bgra * oColor0; }\n" } }; @@ -270,7 +270,7 @@ static const std::vector vsCol = { R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (std140, set = 0, binding = 0) uniform bufferVals { +layout (std140, set = 1, binding = 0) uniform bufferVals { mat4 WorldViewProj; vec2 TintSaturation; } myBufferVals; @@ -416,7 +416,7 @@ VS_OUTPUT main(VS_INPUT input) { R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (std140, set = 0, binding = 0) uniform bufferVals { +layout (std140, set = 1, binding = 0) uniform bufferVals { mat4 WorldViewProj; vec2 TintSaturation; } myBufferVals; diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index e617954010..695e1c83c8 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -249,6 +249,8 @@ enum class NativeObject { RENDER_MANAGER, TEXTURE_VIEW, NULL_IMAGEVIEW, + FRAME_DATA_DESC_SET_LAYOUT, + THIN3D_PIPELINE_LAYOUT, }; enum FBChannel { diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 7f09f7c390..1cfd750540 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -185,23 +185,23 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); if (doTexture) { - WRITE(p, "layout (binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); + WRITE(p, "layout (set = 1, binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); } if (readFramebufferTex) { // The framebuffer texture is always bound as an array. - p.C("layout (binding = 1) uniform sampler2DArray fbotex;\n"); + p.C("layout (set = 1, binding = 1) uniform sampler2DArray fbotex;\n"); } else if (fetchFramebuffer) { - p.C("layout (input_attachment_index = 0, binding = 9) uniform subpassInput inputColor;\n"); + p.C("layout (input_attachment_index = 0, set = 1, binding = 9) uniform subpassInput inputColor;\n"); if (fragmentShaderFlags) { *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; } } if (shaderDepalMode != ShaderDepalMode::OFF) { - WRITE(p, "layout (binding = 2) uniform sampler2D pal;\n"); + WRITE(p, "layout (set = 1, binding = 2) uniform sampler2D pal;\n"); } // Note: the precision qualifiers must match the vertex shader! diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index cbf51f1b24..6c6cc57ab2 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -249,11 +249,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (compat.shaderLanguage == GLSL_VULKAN) { WRITE(p, "\n"); - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); if (enableLighting || doShadeMapping) - WRITE(p, "layout (std140, set = 0, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); + WRITE(p, "layout (std140, set = 1, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); if (enableBones) - WRITE(p, "layout (std140, set = 0, binding = 5) uniform boneVars {\n%s};\n", ub_vs_bonesStr); + WRITE(p, "layout (std140, set = 1, binding = 5) uniform boneVars {\n%s};\n", ub_vs_bonesStr); if (enableBones) { WRITE(p, "%s", boneWeightDecl[numBoneWeights]); @@ -631,7 +631,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 tex;\n"); WRITE(p, " vec4 col;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 6) readonly buffer s_tess_data {\n"); + WRITE(p, "layout (std430, set = 1, binding = 6) readonly buffer s_tess_data {\n"); WRITE(p, " TessData tess_data[];\n"); WRITE(p, "};\n"); @@ -639,10 +639,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 basis;\n"); WRITE(p, " vec4 deriv;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 7) readonly buffer s_tess_weights_u {\n"); + WRITE(p, "layout (std430, set = 1, binding = 7) readonly buffer s_tess_weights_u {\n"); WRITE(p, " TessWeight tess_weights_u[];\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 8) readonly buffer s_tess_weights_v {\n"); + WRITE(p, "layout (std430, set = 1, binding = 8) readonly buffer s_tess_weights_v {\n"); WRITE(p, " TessWeight tess_weights_v[];\n"); WRITE(p, "};\n"); } else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 8af2727736..71d601d805 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -185,10 +185,12 @@ void DrawEngineVulkan::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - VkDescriptorSetLayout layouts[1] = { descriptorSetLayout_ }; + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw_->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + VkDescriptorSetLayout layouts[2] = { frameDescSetLayout, descriptorSetLayout_}; pl.setLayoutCount = ARRAY_SIZE(layouts); pl.pSetLayouts = layouts; pl.flags = 0; + res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); _dbg_assert_(VK_SUCCESS == res); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 258f95ae6d..0cf03f275c 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -211,7 +211,8 @@ private: Draw::DrawContext *draw_; - // We use a shared descriptor set layout for all PSP draws. + // We use a shared descriptor set layouts for all PSP draws. + // Descriptors created from descriptorSetLayout_ is rebound all the time at set 1. VkDescriptorSetLayout descriptorSetLayout_; VkPipelineLayout pipelineLayout_; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 8f80aa8474..d536bedabd 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -65,9 +65,9 @@ const char *uploadShader = R"( // hardware vendors. layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; -uniform layout(binding = 0, rgba8) writeonly image2D img; +uniform layout(set = 1, binding = 0, rgba8) writeonly image2D img; -layout(std430, binding = 1) buffer Buf { +layout(std430, set = 1, binding = 1) buffer Buf { uint data[]; } buf; @@ -251,7 +251,7 @@ void TextureCacheVulkan::DeviceRestore(Draw::DrawContext *draw) { CompileScalingShader(); - computeShaderManager_.DeviceRestore(vulkan); + computeShaderManager_.DeviceRestore(draw); } void TextureCacheVulkan::NotifyConfigChanged() { @@ -626,7 +626,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, "Compute Upload: %dx%d->%dx%d", mipUnscaledWidth, mipUnscaledHeight, mipWidth, mipHeight); vkCmdBindPipeline(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipeline(uploadCS_)); - vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 0, 1, &descSet, 0, nullptr); + vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 1, 1, &descSet, 0, nullptr); vkCmdPushConstants(cmdInit, computeShaderManager_.GetPipelineLayout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(params), ¶ms); vkCmdDispatch(cmdInit, (mipUnscaledWidth + 7) / 8, (mipUnscaledHeight + 7) / 8, 1); VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index d23f2ad9b2..27149b2be1 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -56,7 +56,7 @@ VulkanComputeShaderManager::VulkanComputeShaderManager(VulkanContext *vulkan) : } VulkanComputeShaderManager::~VulkanComputeShaderManager() {} -void VulkanComputeShaderManager::InitDeviceObjects() { +void VulkanComputeShaderManager::InitDeviceObjects(Draw::DrawContext *draw) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); _assert_(VK_SUCCESS == res); @@ -85,14 +85,14 @@ void VulkanComputeShaderManager::InitDeviceObjects() { std::vector dpTypes; dpTypes.resize(2); - dpTypes[0].descriptorCount = 8192; + dpTypes[0].descriptorCount = 4096; dpTypes[0].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - dpTypes[1].descriptorCount = 4096; + dpTypes[1].descriptorCount = 2048; dpTypes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; dp.flags = 0; // Don't want to mess around with individually freeing these, let's go fixed each frame and zap the whole array. Might try the dynamic approach later. - dp.maxSets = 4096; // GTA can end up creating more than 1000 textures in the first frame! + dp.maxSets = 2048; // GTA can end up creating more than 1000 textures in the first frame! for (int i = 0; i < ARRAY_SIZE(frameData_); i++) { frameData_[i].descPool.Create(vulkan_, dp, dpTypes); @@ -106,8 +106,10 @@ void VulkanComputeShaderManager::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = &push; pl.pushConstantRangeCount = 1; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + VkDescriptorSetLayout setLayouts[2] = { frameDescSetLayout, descriptorSetLayout_ }; + pl.setLayoutCount = ARRAY_SIZE(setLayouts); + pl.pSetLayouts = setLayouts; pl.flags = 0; res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); _assert_(VK_SUCCESS == res); diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h index b31fdb75f9..8663d3ce1e 100644 --- a/GPU/Vulkan/VulkanUtil.h +++ b/GPU/Vulkan/VulkanUtil.h @@ -25,6 +25,7 @@ #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanLoader.h" #include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/thin3d.h" extern const VkComponentMapping VULKAN_4444_SWIZZLE; extern const VkComponentMapping VULKAN_1555_SWIZZLE; @@ -47,9 +48,9 @@ public: void DeviceLost() { DestroyDeviceObjects(); } - void DeviceRestore(VulkanContext *vulkan) { - vulkan_ = vulkan; - InitDeviceObjects(); + void DeviceRestore(Draw::DrawContext *draw) { + vulkan_ = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); + InitDeviceObjects(draw); } // Note: This doesn't cache. The descriptor is for immediate use only. @@ -63,7 +64,7 @@ public: void EndFrame(); private: - void InitDeviceObjects(); + void InitDeviceObjects(Draw::DrawContext *draw); void DestroyDeviceObjects(); VulkanContext *vulkan_ = nullptr; diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 023b9e1def..ab0a11d300 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -44,7 +44,7 @@ static const std::vector fsDiscard = { layout(location = 0) in vec4 oColor0; layout(location = 1) in vec2 oTexCoord0; layout(location = 0) out vec4 fragColor0; - layout(set = 0, binding = 1) uniform sampler2D Sampler0; + layout(set = 1, binding = 1) uniform sampler2D Sampler0; void main() { vec4 color = texture(Sampler0, oTexCoord0) * oColor0; if (color.a <= 0.0) @@ -86,7 +86,7 @@ static const std::vector fsAdrenoLogicTest = { layout(location = 0) in vec4 oColor0; layout(location = 1) in highp vec2 oTexCoord0; layout(location = 0) out vec4 fragColor0; - layout(set = 0, binding = 1) uniform sampler2D Sampler0; + layout(set = 1, binding = 1) uniform sampler2D Sampler0; void main() { vec4 v = texture(Sampler0, oTexCoord0).aaaa * oColor0; if (v.r < 0.2 && v.g < 0.2 && v.b < 0.2) discard; @@ -117,7 +117,7 @@ static const std::vector vsAdrenoLogicTest = { "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" - "layout (std140, set = 0, binding = 0) uniform bufferVals {\n" + "layout (std140, set = 1, binding = 0) uniform bufferVals {\n" " mat4 WorldViewProj;\n" "} myBufferVals;\n" "layout (location = 0) in vec4 pos;\n" @@ -173,7 +173,7 @@ static const std::vector fsFlat = { "layout(location = 0) flat in lowp vec4 oColor0;\n" "layout(location = 1) in highp vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0;\n" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n" } }; @@ -214,7 +214,7 @@ static const std::vector vsFlat = { "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" - "layout (std140, set = 0, binding = 0) uniform bufferVals {\n" + "layout (std140, set = 1, binding = 0) uniform bufferVals {\n" " mat4 WorldViewProj;\n" "} myBufferVals;\n" "layout (location = 0) in vec4 pos;\n" From ab1cebec5190e7d9826d895144e1ed1855a89f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 28 Oct 2022 10:15:36 +0200 Subject: [PATCH 135/715] Actually bind a global uniform buffer, too. Not yet used. --- Common/GPU/Vulkan/VulkanRenderManager.h | 2 +- GPU/Common/ShaderUniforms.h | 6 +++--- GPU/Vulkan/DrawEngineVulkan.cpp | 27 ++++++++++++++++++++++++- GPU/Vulkan/DrawEngineVulkan.h | 2 ++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 26e1eb5220..c8ca219d17 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -273,10 +273,10 @@ public: // Mainly used to bind the frame-global desc set. // Can be done before binding a pipeline, so not asserting on that. void BindDescriptorSet(int setNumber, VkDescriptorSet set, VkPipelineLayout pipelineLayout) { - _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); VkRenderData data{ VKRRenderCommand::BIND_DESCRIPTOR_SET }; data.bindDescSet.setNumber = setNumber; data.bindDescSet.set = set; + data.bindDescSet.pipelineLayout = pipelineLayout; curRenderStep_->commands.push_back(data); } diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 96cfe98411..12bc273da3 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -133,12 +133,12 @@ R"( mat3x4 u_bone0; mat3x4 u_bone1; mat3x4 u_bone2; mat3x4 u_bone3; mat3x4 u_bon static const char * const ub_frame_globalstr = -R"( vec4 unused; +R"( vec4 stereoParams; )"; -// VR stuff will go here. +// Frame-global uniforms. struct UB_FrameGlobal { - float unused[4]; + float stereoParams[4]; }; void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 71d601d805..4d933b09d7 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -312,7 +312,8 @@ void DrawEngineVulkan::BeginFrame() { frame->pushVertex->Begin(vulkan); frame->pushIndex->Begin(vulkan); - // TODO: How can we make this nicer... + frame->frameDescSetUpdated = false; + tessDataTransferVulkan->SetPushBuffer(frame->pushUBO); DirtyAllUBOs(); @@ -1016,6 +1017,30 @@ void DrawEngineVulkan::DoFlush() { } void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { + if (!frame->frameDescSetUpdated) { + // Push frame global constants. + UB_FrameGlobal frameConstants{}; + VkDescriptorBufferInfo frameConstantsBufInfo; + frame->pushUBO->PushUBOData(frameConstants, &frameConstantsBufInfo); + + VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw_->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + + VkDescriptorSet frameDescSet = frame->descPool.Allocate(1, &frameDescSetLayout, "frame_desc_set"); + + VkWriteDescriptorSet descWrite{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descWrite.descriptorCount = 1; + descWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descWrite.dstBinding = 0; + descWrite.dstSet = frameDescSet; + descWrite.pBufferInfo = &frameConstantsBufInfo; + vkUpdateDescriptorSets(vulkan->GetDevice(), 1, &descWrite, 0, nullptr); + renderManager->BindDescriptorSet(0, frameDescSet, pipelineLayout_); + + frame->frameDescSetUpdated = true; + } + if ((dirtyUniforms_ & DIRTY_BASE_UNIFORMS) || baseBuf == VK_NULL_HANDLE) { baseUBOOffset = shaderManager_->PushBaseBuffer(frame->pushUBO, &baseBuf); dirtyUniforms_ &= ~DIRTY_BASE_UNIFORMS; diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 0cf03f275c..035bc595df 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -255,6 +255,8 @@ private: VulkanPushBuffer *pushVertex = nullptr; VulkanPushBuffer *pushIndex = nullptr; + bool frameDescSetUpdated = false; + // We do rolling allocation and reset instead of caching across frames. That we might do later. DenseHashMap descSets; From 10eb21d3b3705419b0582d0a4fbc0e12d23bd11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 28 Oct 2022 10:17:29 +0200 Subject: [PATCH 136/715] Add some extra checking for valid stereo shader. --- GPU/Common/PresentationCommon.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 025888896c..756bce0873 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -233,14 +233,21 @@ bool PresentationCommon::UpdatePostShader() { if (gstate_c.Use(GPU_USE_SIMPLE_STEREO_PERSPECTIVE)) { const ShaderInfo *stereoShaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); - bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); - if (!result) { + if (stereoShaderInfo) { + bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); + if (!result) { + // We won't have a stereo shader. We have to check for this later. + delete stereoShaderInfo_; + stereoShaderInfo_ = nullptr; + stereoPipeline_ = nullptr; + } else { + stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); + } + } else { // We won't have a stereo shader. We have to check for this later. delete stereoShaderInfo_; stereoShaderInfo_ = nullptr; stereoPipeline_ = nullptr; - } else { - stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); } } @@ -296,6 +303,8 @@ bool PresentationCommon::UpdatePostShader() { } bool PresentationCommon::CompilePostShader(const ShaderInfo *shaderInfo, Draw::Pipeline **outPipeline) const { + _assert_(shaderInfo); + std::string vsSourceGLSL = ReadShaderSrc(shaderInfo->vertexShaderFile); std::string fsSourceGLSL = ReadShaderSrc(shaderInfo->fragmentShaderFile); if (vsSourceGLSL.empty() || fsSourceGLSL.empty()) { From d9cfcf215e8758e16e4c134a87c371bc8202734b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 28 Oct 2022 10:20:47 +0200 Subject: [PATCH 137/715] Need to request the proper type of uniform buffer descriptors. Otherwise, assert on Mali. --- GPU/Vulkan/DrawEngineVulkan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 4d933b09d7..68108fe107 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -154,7 +154,7 @@ void DrawEngineVulkan::InitDeviceObjects() { static constexpr int DEFAULT_DESC_POOL_SIZE = 512; std::vector dpTypes; - dpTypes.resize(4); + dpTypes.resize(5); dpTypes[0].descriptorCount = DEFAULT_DESC_POOL_SIZE * 3; dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; dpTypes[1].descriptorCount = DEFAULT_DESC_POOL_SIZE * 3; // Don't use these for tess anymore, need max three per set. @@ -163,6 +163,8 @@ void DrawEngineVulkan::InitDeviceObjects() { dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; dpTypes[3].descriptorCount = DEFAULT_DESC_POOL_SIZE; // TODO: Use a separate layout when no spline stuff is needed to reduce the need for these. dpTypes[3].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + dpTypes[4].descriptorCount = 1; // For the frame global uniform buffer. + dpTypes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; // Don't want to mess around with individually freeing these. From f4f7dc570f23ddd855213bcd140f0ae73e40bba0 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 28 Oct 2022 14:59:12 +0200 Subject: [PATCH 138/715] OpenXR - Make VR camera parameters floating numbers --- Common/VR/PPSSPPVR.cpp | 6 +++--- Common/VR/VRRenderer.cpp | 2 +- Core/Config.cpp | 6 +++--- Core/Config.h | 6 +++--- UI/GameSettingsScreen.cpp | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index a3f550bee3..b2daa2fb8a 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -319,9 +319,9 @@ bool StartVRRender() { // Set customizations VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); - VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.iCameraDistance); - VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.iCanvasDistance); - VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.iFieldOfViewPercentage); + VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance * 1000); + VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); + VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.fFieldOfViewPercentage); VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, false); return true; } diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 5a8084941b..a43b169f8e 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -339,7 +339,7 @@ bool VR_InitFrame( engine_t* engine ) { vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; } if (abs(vrConfig[VR_CONFIG_CAMERA_DISTANCE]) > 0) { - XrVector3f forward = {0.0f, 0.0f, (float)vrConfig[VR_CONFIG_CAMERA_DISTANCE] * scale}; + XrVector3f forward = {0.0f, 0.0f, (float)vrConfig[VR_CONFIG_CAMERA_DISTANCE] * 0.001f * scale}; forward = XrQuaternionf_Rotate(invView.orientation, forward); forward = XrVector3f_ScalarMultiply(forward, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); vrMatrix[matrix].M[0][3] += forward.x; diff --git a/Core/Config.cpp b/Core/Config.cpp index 91457df787..da71b8bfff 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1208,9 +1208,9 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VREnable", &g_Config.bEnableVR, true), ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, true), ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false), - ConfigSetting("VRCameraDistance", &g_Config.iCameraDistance, 0), - ConfigSetting("VRCanvasDistance", &g_Config.iCanvasDistance, 6), - ConfigSetting("VRFieldOfView", &g_Config.iFieldOfViewPercentage, 100), + ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f), + ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), + ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), ConfigSetting(false), }; diff --git a/Core/Config.h b/Core/Config.h index 5a89c89732..f42fd77720 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -463,9 +463,9 @@ public: bool bEnableVR; bool bEnable6DoF; bool bEnableStereo; - int iCameraDistance; - int iCanvasDistance; - int iFieldOfViewPercentage; + float fCameraDistance; + float fCanvasDistance; + float fFieldOfViewPercentage; // Debugger int iDisasmWindowX; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 706eb07cfe..5dce2e89cd 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1165,9 +1165,9 @@ void GameSettingsScreen::CreateViews() { vrStereo->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); - vrSettings->Add(new PopupSliderChoice(&g_Config.iCameraDistance, -10, 10, vr->T("Camera distance adjust", "Camera distance adjust"), 1, screenManager(), "")); - vrSettings->Add(new PopupSliderChoice(&g_Config.iCanvasDistance, 1, 10, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1, screenManager(), "")); - vrSettings->Add(new PopupSliderChoice(&g_Config.iFieldOfViewPercentage, 100, 200, vr->T("Field of view scale", "Headset's field of view scale"), 10, screenManager(), vr->T("% of native FoV"))); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale", "Headset's field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); } } From 96f89f4bd74aa77307e570b2f0db5eb225797a6b Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 28 Oct 2022 15:50:00 +0200 Subject: [PATCH 139/715] OpenXR - Allow updating camera in realtime --- Common/VR/PPSSPPVR.cpp | 22 ++++++++++++++++++++-- Common/VR/PPSSPPVR.h | 4 ++-- Common/VR/VRRenderer.h | 2 +- UI/NativeApp.cpp | 4 ++-- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index b2daa2fb8a..704eba7422 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -221,11 +221,16 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con } } -void UpdateVRScreenKey(const KeyInput &key) { +void UpdateVRSpecialKeys(const KeyInput &key) { std::vector nativeKeys; if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { - if (nativeKey == CTRL_SCREEN) { + // adjust camera parameters + if (nativeKey == CTRL_HOLD) { + VR_SetConfig(VR_CONFIG_CAMERA_CONTROL, key.flags & KEY_DOWN); + } + // force 2D rendering + else if (nativeKey == CTRL_SCREEN) { VR_SetConfig(VR_CONFIG_FORCE_2D, key.flags & KEY_DOWN); } } @@ -317,6 +322,19 @@ bool StartVRRender() { // Set compatibility vrCompat[VR_COMPAT_SKYPLANE] = PSP_CoreParameter().compat.vrCompat().Skyplane; + // Camera control + if (VR_GetConfig(VR_CONFIG_CAMERA_CONTROL)) { + float dst = g_Config.fCameraDistance; + float fov = g_Config.fFieldOfViewPercentage; + int status = IN_VRGetButtonState(1); + if (status & ovrButton_Left) fov -= 1.0f; + if (status & ovrButton_Right) fov += 1.0f; + if (status & ovrButton_Down) dst -= 0.1f; + if (status & ovrButton_Up) dst += 0.1f; + g_Config.fCameraDistance = std::clamp(dst, -10.0f, 10.0f); + g_Config.fFieldOfViewPercentage = std::clamp(fov, 100.0f, 200.0f); + } + // Set customizations VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance * 1000); diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 91f5862ff0..440f27859d 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -25,7 +25,7 @@ void InitVROnAndroid(void* vm, void* activity, int version, const char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); -void UpdateVRScreenKey(const KeyInput &key); +void UpdateVRSpecialKeys(const KeyInput &key); // VR games compatibility void PreprocessStepVR(void* step); @@ -53,7 +53,7 @@ inline void InitVROnAndroid(void* vm, void* activity, int version, const char* n inline void EnterVR(bool firstTime, void* vulkanContext) {} inline void GetVRResolutionPerEye(int* width, int* height) {} inline void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {} -inline void UpdateVRScreenKey(const KeyInput &key) {} +inline void UpdateVRSpecialKeys(const KeyInput &key) {} // VR games compatibility inline void PreprocessStepVR(void* step) {} diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 1c93f98752..7ba37ae407 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -7,7 +7,7 @@ enum VRConfig { //switching between 2D and 3D VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, //camera setup - VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_DISTANCE, VR_CONFIG_CANVAS_DISTANCE, + VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_CONTROL, VR_CONFIG_CAMERA_DISTANCE, VR_CONFIG_CANVAS_DISTANCE, //6DoF VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 36ce962ea4..0f4cac7f37 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1296,9 +1296,9 @@ bool NativeTouch(const TouchInput &touch) { } bool NativeKey(const KeyInput &key) { - // Hack to quickly enable 2D mode in VR game mode. + // Special key VR actions if (IsVRBuild()) { - UpdateVRScreenKey(key); + UpdateVRSpecialKeys(key); } // INFO_LOG(SYSTEM, "Key code: %i flags: %i", key.keyCode, key.flags); From 8e0b82f92e8b7312e08de0edd5d0634362a14b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 28 Oct 2022 17:42:21 +0200 Subject: [PATCH 140/715] Address feedback --- GPU/Common/PresentationCommon.cpp | 12 ++---------- GPU/Vulkan/VulkanUtil.cpp | 6 +++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 756bce0873..b4e05d8d50 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -235,19 +235,11 @@ bool PresentationCommon::UpdatePostShader() { const ShaderInfo *stereoShaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); if (stereoShaderInfo) { bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); - if (!result) { - // We won't have a stereo shader. We have to check for this later. - delete stereoShaderInfo_; - stereoShaderInfo_ = nullptr; - stereoPipeline_ = nullptr; - } else { + if (result) { stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); } } else { - // We won't have a stereo shader. We have to check for this later. - delete stereoShaderInfo_; - stereoShaderInfo_ = nullptr; - stereoPipeline_ = nullptr; + WARN_LOG(G3D, "Failed to get info about stereo shader '%s'", g_Config.sStereoToMonoShader.c_str()); } } diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index 27149b2be1..fbfb8ad3fa 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -85,14 +85,14 @@ void VulkanComputeShaderManager::InitDeviceObjects(Draw::DrawContext *draw) { std::vector dpTypes; dpTypes.resize(2); - dpTypes[0].descriptorCount = 4096; + dpTypes[0].descriptorCount = 8192; dpTypes[0].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - dpTypes[1].descriptorCount = 2048; + dpTypes[1].descriptorCount = 4096; dpTypes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; dp.flags = 0; // Don't want to mess around with individually freeing these, let's go fixed each frame and zap the whole array. Might try the dynamic approach later. - dp.maxSets = 2048; // GTA can end up creating more than 1000 textures in the first frame! + dp.maxSets = 4096; // GTA can end up creating more than 1000 textures in the first frame! for (int i = 0; i < ARRAY_SIZE(frameData_); i++) { frameData_[i].descPool.Create(vulkan_, dp, dpTypes); From c6fe91224a6422f4bceeac035f2c778d3a6e1ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 28 Oct 2022 18:40:55 +0200 Subject: [PATCH 141/715] Vulkan: Fixes validation errors with "null" textures These arise in non-buffered rendering when we don't have a framebuffer to texture from. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 8 +++++++- Common/GPU/thin3d.h | 1 + GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index fda775f1d0..17d6ed113c 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1343,7 +1343,11 @@ void VKContext::BindTextures(int start, int count, Texture **textures, TextureBi boundImageView_[i] = boundTextures_[i]->GetImageView(); } } else { - boundImageView_[i] = GetNullTexture()->GetImageView(); + if (flags & TextureBindFlags::VULKAN_BIND_ARRAY) { + boundImageView_[i] = GetNullTexture()->GetImageArrayView(); + } else { + boundImageView_[i] = GetNullTexture()->GetImageView(); + } } } } @@ -1693,6 +1697,8 @@ uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) { return (uint64_t)(uintptr_t)&renderManager_; case NativeObject::NULL_IMAGEVIEW: return (uint64_t)GetNullTexture()->GetImageView(); + case NativeObject::NULL_IMAGEVIEW_ARRAY: + return (uint64_t)GetNullTexture()->GetImageArrayView(); case NativeObject::TEXTURE_VIEW: return (uint64_t)(((VKTexture *)srcObject)->GetImageView()); case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS: diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 695e1c83c8..9bc0c3a14a 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -249,6 +249,7 @@ enum class NativeObject { RENDER_MANAGER, TEXTURE_VIEW, NULL_IMAGEVIEW, + NULL_IMAGEVIEW_ARRAY, FRAME_DATA_DESC_SET_LAYOUT, THIN3D_PIPELINE_LAYOUT, }; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 68108fe107..f54afee3a9 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -770,7 +770,7 @@ void DrawEngineVulkan::DoFlush() { textureCache_->ApplyTexture(); textureCache_->GetVulkanHandles(imageView, sampler); if (imageView == VK_NULL_HANDLE) - imageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::NULL_IMAGEVIEW); + imageView = (VkImageView)draw_->GetNativeObject(gstate_c.arrayTexture ? Draw::NativeObject::NULL_IMAGEVIEW_ARRAY : Draw::NativeObject::NULL_IMAGEVIEW); if (sampler == VK_NULL_HANDLE) sampler = nullSampler_; } @@ -906,7 +906,7 @@ void DrawEngineVulkan::DoFlush() { textureCache_->ApplyTexture(); textureCache_->GetVulkanHandles(imageView, sampler); if (imageView == VK_NULL_HANDLE) - imageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::NULL_IMAGEVIEW); + imageView = (VkImageView)draw_->GetNativeObject(gstate_c.arrayTexture ? Draw::NativeObject::NULL_IMAGEVIEW_ARRAY : Draw::NativeObject::NULL_IMAGEVIEW); if (sampler == VK_NULL_HANDLE) sampler = nullSampler_; } From f9c6f0a39e47d8660c3d9ada8733570c34149548 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 08:53:19 -0700 Subject: [PATCH 142/715] headless: Update tests. --- pspautotests | 2 +- test.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pspautotests b/pspautotests index 1790e574bd..a886587cc2 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 1790e574bd069c7e4883bf097db46094526b0dc9 +Subproject commit a886587cc29ffadc93f5533a0f8dc329ae355b9a diff --git a/test.py b/test.py index b9cf9260ca..dbfe4d1ad7 100755 --- a/test.py +++ b/test.py @@ -201,6 +201,7 @@ tests_good = [ "intr/suspended", "intr/vblank/vblank", "io/cwd/cwd", + "io/open/badparent", "jpeg/create", "jpeg/delete", "jpeg/finish", From 79d53552a5467790f1041148cbe9a9a27412e350 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 09:02:12 -0700 Subject: [PATCH 143/715] armips: Update to latest. --- UWP/Armips_UWP/Armips_UWP.vcxproj | 12 +++++++ UWP/Armips_UWP/Armips_UWP.vcxproj.filters | 39 +++++++++++++++++++++++ android/jni/Android.mk | 6 ++++ ext/armips | 2 +- ext/libarmips.vcxproj | 12 +++++++ ext/libarmips.vcxproj.filters | 39 +++++++++++++++++++++++ 6 files changed, 109 insertions(+), 1 deletion(-) diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj b/UWP/Armips_UWP/Armips_UWP.vcxproj index a836263550..4610681d23 100644 --- a/UWP/Armips_UWP/Armips_UWP.vcxproj +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj @@ -278,6 +278,12 @@ + + + + + + @@ -329,6 +335,12 @@ + + + + + + diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj.filters b/UWP/Armips_UWP/Armips_UWP.vcxproj.filters index 37d23a6b09..0ba78a266d 100644 --- a/UWP/Armips_UWP/Armips_UWP.vcxproj.filters +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj.filters @@ -56,6 +56,24 @@ Archs\MIPS + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + Archs @@ -202,6 +220,24 @@ Archs\MIPS + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + Archs @@ -300,6 +336,9 @@ {bef7b4a2-b049-4d00-810c-6d8d6605c2a3} + + {bef7b4a2-b049-4d00-810c-6d8d6605c2a4} + {2ce1016b-f93c-48b9-abe5-d3fbbcd24780} diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 333733382e..8913f641e5 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -584,6 +584,12 @@ LIBARMIPS_FILES := \ $(SRC)/ext/armips/Archs/MIPS/MipsOpcodes.cpp \ $(SRC)/ext/armips/Archs/MIPS/MipsParser.cpp \ $(SRC)/ext/armips/Archs/MIPS/PsxRelocator.cpp \ + $(SRC)/ext/armips/Archs/SuperH/CShInstruction.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShElfRelocator.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShExpressionFunctions.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShOpcodes.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShParser.cpp \ + $(SRC)/ext/armips/Archs/SuperH/SuperH.cpp \ $(SRC)/ext/armips/Archs/Architecture.cpp \ $(SRC)/ext/armips/Commands/CAssemblerCommand.cpp \ $(SRC)/ext/armips/Commands/CAssemblerLabel.cpp \ diff --git a/ext/armips b/ext/armips index b4335f04fa..6719edebaa 160000 --- a/ext/armips +++ b/ext/armips @@ -1 +1 @@ -Subproject commit b4335f04fa62c1b4f7833c70fbb15505b6772274 +Subproject commit 6719edebaae03330ee5441d9b28280672edf00d5 diff --git a/ext/libarmips.vcxproj b/ext/libarmips.vcxproj index c0484e63d1..bd9f5c9911 100644 --- a/ext/libarmips.vcxproj +++ b/ext/libarmips.vcxproj @@ -502,6 +502,12 @@ + + + + + + @@ -554,6 +560,12 @@ + + + + + + diff --git a/ext/libarmips.vcxproj.filters b/ext/libarmips.vcxproj.filters index 61282421bb..4a9b54143c 100644 --- a/ext/libarmips.vcxproj.filters +++ b/ext/libarmips.vcxproj.filters @@ -31,6 +31,9 @@ {d1037c70-bb54-46fc-8b0c-a47c4ea4a252} + + {496988ff-1b2f-4046-bc02-b5ad9a1952b4} + @@ -183,6 +186,24 @@ Core + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + @@ -341,5 +362,23 @@ Core + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + \ No newline at end of file From 0bc2bb9efb19754f14ca42448400e4e840fab623 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 09:05:14 -0700 Subject: [PATCH 144/715] Vulkan: Log additional queue command. --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 47e5b94046..bce57f549d 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1145,6 +1145,9 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { case VKRRenderCommand::DEBUG_ANNOTATION: INFO_LOG(G3D, " DebugAnnotation(%s)", cmd.debugAnnotation.annotation); break; + case VKRRenderCommand::BIND_DESCRIPTOR_SET: + INFO_LOG(G3D, " BindDescSet(%d)", cmd.bindDescSet.setNumber); + break; case VKRRenderCommand::NUM_RENDER_COMMANDS: break; From 48f9c98559949aa1492d1cc154ea337325a3c282 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 29 Oct 2022 18:50:51 +0200 Subject: [PATCH 145/715] OpenXR - Do not process key actions during camera adjust --- Common/VR/PPSSPPVR.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 704eba7422..2c3e730bfc 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -150,22 +150,42 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con KeyInput keyInput = {}; for (int j = 0; j < 2; j++) { int status = IN_VRGetButtonState(j); + bool cameraControl = VR_GetConfig(VR_CONFIG_CAMERA_CONTROL); for (ButtonMapping& m : controllerMapping[j]) { + + //check if camera key was pressed + bool cameraKey = false; + std::vector nativeKeys; + if (KeyMap::KeyToPspButton(controllerIds[j], m.keycode, &nativeKeys)) { + for (int& nativeKey : nativeKeys) { + if (nativeKey == CTRL_HOLD) { + cameraKey = true; + break; + } + } + } + + //fill KeyInput structure bool pressed = status & m.ovr; keyInput.flags = pressed ? KEY_DOWN : KEY_UP; keyInput.keyCode = m.keycode; keyInput.deviceId = controllerIds[j]; + //process the key action if (m.pressed != pressed) { if (pressed && haptics) { INVR_Vibrate(100, j, 1000); } - NativeKey(keyInput); + if (!cameraControl || cameraKey) { + NativeKey(keyInput); + } m.pressed = pressed; m.repeat = 0; } else if (pressed && (m.repeat > 30)) { keyInput.flags |= KEY_IS_REPEAT; - NativeKey(keyInput); + if (!cameraControl || cameraKey) { + NativeKey(keyInput); + } m.repeat = 0; } else { m.repeat++; @@ -331,6 +351,10 @@ bool StartVRRender() { if (status & ovrButton_Right) fov += 1.0f; if (status & ovrButton_Down) dst -= 0.1f; if (status & ovrButton_Up) dst += 0.1f; + if (status & ovrButton_RThumb) { + fov = 100; + dst = 0; + } g_Config.fCameraDistance = std::clamp(dst, -10.0f, 10.0f); g_Config.fFieldOfViewPercentage = std::clamp(fov, 100.0f, 200.0f); } From b7da6f7e45bf8a9f09c5a2dd4fbb935a73b21ace Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 29 Oct 2022 19:19:25 +0200 Subject: [PATCH 146/715] OpenXR - Camera height adjust added --- Common/VR/PPSSPPVR.cpp | 14 +++++++++++++- Common/VR/VRRenderer.cpp | 8 ++++++++ Common/VR/VRRenderer.h | 3 ++- Core/Config.cpp | 1 + Core/Config.h | 1 + UI/GameSettingsScreen.cpp | 1 + 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 2c3e730bfc..84ce7274fd 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -344,9 +344,20 @@ bool StartVRRender() { // Camera control if (VR_GetConfig(VR_CONFIG_CAMERA_CONTROL)) { + //light joystick controls height + float height = g_Config.fCameraHeight; + int status = IN_VRGetButtonState(0); + if (status & ovrButton_Down) height -= 0.05f; + if (status & ovrButton_Up) height += 0.05f; + if (status & ovrButton_LThumb) { + height = 0; + } + g_Config.fCameraHeight = std::clamp(height, -10.0f, 10.0f); + + //right joystick controls distance and fov float dst = g_Config.fCameraDistance; float fov = g_Config.fFieldOfViewPercentage; - int status = IN_VRGetButtonState(1); + status = IN_VRGetButtonState(1); if (status & ovrButton_Left) fov -= 1.0f; if (status & ovrButton_Right) fov += 1.0f; if (status & ovrButton_Down) dst -= 0.1f; @@ -362,6 +373,7 @@ bool StartVRRender() { // Set customizations VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance * 1000); + VR_SetConfig(VR_CONFIG_CAMERA_HEIGHT, g_Config.fCameraHeight * 1000); VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.fFieldOfViewPercentage); VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, false); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index a43b169f8e..aba7c4def0 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -346,6 +346,14 @@ bool VR_InitFrame( engine_t* engine ) { vrMatrix[matrix].M[1][3] += forward.y; vrMatrix[matrix].M[2][3] += forward.z; } + if (abs(vrConfig[VR_CONFIG_CAMERA_HEIGHT]) > 0) { + XrVector3f up = {0.0f, -(float)vrConfig[VR_CONFIG_CAMERA_HEIGHT] * 0.001f * scale, 0.0f}; + up = XrQuaternionf_Rotate(invView.orientation, up); + up = XrVector3f_ScalarMultiply(up, vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f); + vrMatrix[matrix].M[0][3] += up.x; + vrMatrix[matrix].M[1][3] += up.y; + vrMatrix[matrix].M[2][3] += up.z; + } if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 7ba37ae407..95671fc0c2 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -7,7 +7,8 @@ enum VRConfig { //switching between 2D and 3D VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, //camera setup - VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_CONTROL, VR_CONFIG_CAMERA_DISTANCE, VR_CONFIG_CANVAS_DISTANCE, + VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_CONTROL, VR_CONFIG_CAMERA_DISTANCE, + VR_CONFIG_CAMERA_HEIGHT, VR_CONFIG_CANVAS_DISTANCE, //6DoF VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, diff --git a/Core/Config.cpp b/Core/Config.cpp index da71b8bfff..f52738b8bd 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1209,6 +1209,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, true), ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false), ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f), + ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f), ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), diff --git a/Core/Config.h b/Core/Config.h index f42fd77720..2a66f73fa2 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -464,6 +464,7 @@ public: bool bEnable6DoF; bool bEnableStereo; float fCameraDistance; + float fCameraHeight; float fCanvasDistance; float fFieldOfViewPercentage; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 5dce2e89cd..a6311ab4ef 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1166,6 +1166,7 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraHeight, -10.0f, 10.0f, vr->T("Camera height adjust", "Camera height adjust"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale", "Headset's field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); } From 92422160a0f4248ab055bf8d5f3dccca01d909db Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 29 Oct 2022 19:31:57 +0200 Subject: [PATCH 147/715] OpenXR - Camera side adjust added --- Common/VR/PPSSPPVR.cpp | 8 +++++++- Common/VR/VRRenderer.cpp | 8 ++++++++ Common/VR/VRRenderer.h | 2 +- Core/Config.cpp | 1 + Core/Config.h | 1 + UI/GameSettingsScreen.cpp | 1 + 6 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 84ce7274fd..7c8c522ec0 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -344,15 +344,20 @@ bool StartVRRender() { // Camera control if (VR_GetConfig(VR_CONFIG_CAMERA_CONTROL)) { - //light joystick controls height + //light joystick controls height and side float height = g_Config.fCameraHeight; + float side = g_Config.fCameraSide; int status = IN_VRGetButtonState(0); + if (status & ovrButton_Left) side -= 0.05f; + if (status & ovrButton_Right) side += 0.05f; if (status & ovrButton_Down) height -= 0.05f; if (status & ovrButton_Up) height += 0.05f; if (status & ovrButton_LThumb) { height = 0; + side = 0; } g_Config.fCameraHeight = std::clamp(height, -10.0f, 10.0f); + g_Config.fCameraSide = std::clamp(side, -10.0f, 10.0f); //right joystick controls distance and fov float dst = g_Config.fCameraDistance; @@ -374,6 +379,7 @@ bool StartVRRender() { VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance * 1000); VR_SetConfig(VR_CONFIG_CAMERA_HEIGHT, g_Config.fCameraHeight * 1000); + VR_SetConfig(VR_CONFIG_CAMERA_SIDE, g_Config.fCameraSide * 1000); VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.fFieldOfViewPercentage); VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, false); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index aba7c4def0..3d4cce0222 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -354,6 +354,14 @@ bool VR_InitFrame( engine_t* engine ) { vrMatrix[matrix].M[1][3] += up.y; vrMatrix[matrix].M[2][3] += up.z; } + if (abs(vrConfig[VR_CONFIG_CAMERA_SIDE]) > 0) { + XrVector3f side = {-(float)vrConfig[VR_CONFIG_CAMERA_SIDE] * 0.001f * scale, 0.0f, 0.0f}; + side = XrQuaternionf_Rotate(invView.orientation, side); + side = XrVector3f_ScalarMultiply(side, vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f); + vrMatrix[matrix].M[0][3] += side.x; + vrMatrix[matrix].M[1][3] += side.y; + vrMatrix[matrix].M[2][3] += side.z; + } if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 95671fc0c2..863212bd7d 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -8,7 +8,7 @@ enum VRConfig { VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, //camera setup VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_CONTROL, VR_CONFIG_CAMERA_DISTANCE, - VR_CONFIG_CAMERA_HEIGHT, VR_CONFIG_CANVAS_DISTANCE, + VR_CONFIG_CAMERA_HEIGHT, VR_CONFIG_CAMERA_SIDE, VR_CONFIG_CANVAS_DISTANCE, //6DoF VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, diff --git a/Core/Config.cpp b/Core/Config.cpp index f52738b8bd..f62a4baaae 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1210,6 +1210,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false), ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f), ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f), + ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), diff --git a/Core/Config.h b/Core/Config.h index 2a66f73fa2..a494cf4c61 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -465,6 +465,7 @@ public: bool bEnableStereo; float fCameraDistance; float fCameraHeight; + float fCameraSide; float fCanvasDistance; float fFieldOfViewPercentage; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index a6311ab4ef..6b68d9c866 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1167,6 +1167,7 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraHeight, -10.0f, 10.0f, vr->T("Camera height adjust", "Camera height adjust"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraSide, -10.0f, 10.0f, vr->T("Camera side adjust", "Camera side adjust"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale", "Headset's field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); } From 363f102cc5139ee1155035353870fd91ae73b2eb Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 29 Oct 2022 20:47:29 +0200 Subject: [PATCH 148/715] OpenXR - Add new virtual key for camera adjust --- Common/VR/PPSSPPVR.cpp | 4 ++-- Core/KeyMap.cpp | 4 ++++ Core/KeyMap.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 7c8c522ec0..ba6ff6ba64 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -158,7 +158,7 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con std::vector nativeKeys; if (KeyMap::KeyToPspButton(controllerIds[j], m.keycode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { - if (nativeKey == CTRL_HOLD) { + if (nativeKey == VIRTKEY_VR_CAMERA_ADJUST) { cameraKey = true; break; } @@ -246,7 +246,7 @@ void UpdateVRSpecialKeys(const KeyInput &key) { if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { // adjust camera parameters - if (nativeKey == CTRL_HOLD) { + if (nativeKey == VIRTKEY_VR_CAMERA_ADJUST) { VR_SetConfig(VR_CONFIG_CAMERA_CONTROL, key.flags & KEY_DOWN); } // force 2D rendering diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index b0a3b69c7e..30b005d86f 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -399,10 +399,14 @@ const KeyMap_IntStrPair psp_button_names[] = { {VIRTKEY_ANALOG_ROTATE_CW, "Rotate Analog (CW)"}, {VIRTKEY_ANALOG_ROTATE_CCW, "Rotate Analog (CCW)"}, +#ifdef OPENXR + {VIRTKEY_VR_CAMERA_ADJUST, "VR camera adjust"}, +#else {VIRTKEY_SCREEN_ROTATION_VERTICAL, "Display Portrait"}, {VIRTKEY_SCREEN_ROTATION_VERTICAL180, "Display Portrait Reversed"}, {VIRTKEY_SCREEN_ROTATION_HORIZONTAL, "Display Landscape"}, {VIRTKEY_SCREEN_ROTATION_HORIZONTAL180, "Display Landscape Reversed"}, +#endif {CTRL_HOME, "Home"}, {CTRL_HOLD, "Hold"}, diff --git a/Core/KeyMap.h b/Core/KeyMap.h index a8ae9f672a..74859d3628 100644 --- a/Core/KeyMap.h +++ b/Core/KeyMap.h @@ -68,6 +68,7 @@ enum { VIRTKEY_SCREEN_ROTATION_HORIZONTAL = 0x40000022, VIRTKEY_SCREEN_ROTATION_HORIZONTAL180 = 0x40000023, VIRTKEY_SPEED_ANALOG = 0x40000024, + VIRTKEY_VR_CAMERA_ADJUST = 0x40000025, VIRTKEY_LAST, VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST }; From d44315a2ec0d453d224fe299c0e3d039cc3fb10a Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 29 Oct 2022 21:00:10 +0200 Subject: [PATCH 149/715] OpenXR - Stereo support for Outrun 2006 added --- assets/compatvr.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assets/compatvr.ini b/assets/compatvr.ini index 7bfc3e5c94..79b1c04678 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -1006,6 +1006,11 @@ NPJH50625 = 1.0 ULJM06113 = 1.0 ULJM08069 = 1.0 +# OutRun 2006: Coast 2 Coast +ULES00262 = 10.0 +ULKS46087 = 10.0 +ULUS10064 = 10.0 + # Patapon 1 NPJG00054 = 80.0 UCAS40193 = 80.0 From cbf93d586c8b81c504445a9fbb95bc7adf4c673a Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 29 Oct 2022 21:39:46 +0200 Subject: [PATCH 150/715] typo fixed --- Common/VR/PPSSPPVR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index ba6ff6ba64..0c496d55e0 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -344,7 +344,7 @@ bool StartVRRender() { // Camera control if (VR_GetConfig(VR_CONFIG_CAMERA_CONTROL)) { - //light joystick controls height and side + //left joystick controls height and side float height = g_Config.fCameraHeight; float side = g_Config.fCameraSide; int status = IN_VRGetButtonState(0); From 0cc94ceb15256a4b642fdda449903a6b1a837adf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 12:52:00 -0700 Subject: [PATCH 151/715] Draw: Correct ambiguous comparison overload. --- Common/GPU/thin3d.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 9bc0c3a14a..7a2c012f89 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -393,6 +393,9 @@ struct AutoRef { *this = p.ptr; return *this; } + bool operator !=(const AutoRef &p) const { + return ptr != p.ptr; + } T *operator->() const { return ptr; From 485249a83e1f7945354f9786a34fdb0e6fc06223 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 12:52:24 -0700 Subject: [PATCH 152/715] Windows: Avoid compile param conflict warning. --- ext/native/tools/atlastool/atlastool.vcxproj | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/native/tools/atlastool/atlastool.vcxproj b/ext/native/tools/atlastool/atlastool.vcxproj index 65b315ebdc..9ad9d35117 100644 --- a/ext/native/tools/atlastool/atlastool.vcxproj +++ b/ext/native/tools/atlastool/atlastool.vcxproj @@ -97,7 +97,6 @@ true ../../../../;../../ext;../../;../../../../ext;../prebuilt;../../../../ext/zstd/lib MultiThreaded - false Console From 10a356c23bf70df1701855cc74db645f6503d48c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 13:00:12 -0700 Subject: [PATCH 153/715] UWP: Avoid some float conversion warnings. --- UWP/Common/DeviceResources.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UWP/Common/DeviceResources.cpp b/UWP/Common/DeviceResources.cpp index 8527d77f51..ab1bbcbf40 100644 --- a/UWP/Common/DeviceResources.cpp +++ b/UWP/Common/DeviceResources.cpp @@ -470,13 +470,13 @@ void DX::DeviceResources::SetWindow(CoreWindow^ window) try { const auto dm = hdi->GetCurrentDisplayMode(); - const unsigned int hdmi_width = dm->ResolutionWidthInRawPixels; - const unsigned int hdmi_height = dm->ResolutionHeightInRawPixels; + const float hdmi_width = (float)dm->ResolutionWidthInRawPixels; + const float hdmi_height = (float)dm->ResolutionHeightInRawPixels; // If we're running on Xbox, use the HDMI mode instead of the CoreWindow size. // In UWP, the CoreWindow is always 1920x1080, even when running at 4K. m_logicalSize = Windows::Foundation::Size(hdmi_width, hdmi_height); - m_dpi = currentDisplayInformation->LogicalDpi * 1.5; + m_dpi = currentDisplayInformation->LogicalDpi * 1.5f; } catch (const Platform::Exception^) { From 8cefb98e97ee30e8a765a572823c914fe6a9b22e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 17:35:14 -0700 Subject: [PATCH 154/715] Debugger: Fix input.analog.send validation. --- Core/Debugger/WebSocket/InputSubscriber.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Debugger/WebSocket/InputSubscriber.cpp b/Core/Debugger/WebSocket/InputSubscriber.cpp index 36278eea0e..fd0f478e76 100644 --- a/Core/Debugger/WebSocket/InputSubscriber.cpp +++ b/Core/Debugger/WebSocket/InputSubscriber.cpp @@ -227,7 +227,7 @@ static bool AnalogValue(DebuggerRequest &req, float *value, const char *name) { } double val = node->value.toNumber(); - if (val < 1.0 || val > 1.0) { + if (val < -1.0 || val > 1.0) { req.Fail(StringFromFormat("Parameter '%s' must be between -1.0 and 1.0", name)); return false; } From 0a98ac43fa9656b4bf9d4b811fb3d5235d6d09ed Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 17:43:35 -0700 Subject: [PATCH 155/715] Debugger: Allow currently-invalid memory reference. --- Core/MIPS/MIPSDebugInterface.cpp | 38 +++++++++++--------------------- GPU/Common/GPUDebugInterface.cpp | 13 +++++------ 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/Core/MIPS/MIPSDebugInterface.cpp b/Core/MIPS/MIPSDebugInterface.cpp index f81b55ca98..bffdee83b6 100644 --- a/Core/MIPS/MIPSDebugInterface.cpp +++ b/Core/MIPS/MIPSDebugInterface.cpp @@ -159,37 +159,25 @@ public: return EXPR_TYPE_UINT; } - bool getMemoryValue(uint32_t address, int size, uint32_t& dest, char* error) override - { - switch (size) - { - case 1: case 2: case 4: - break; - default: - sprintf(error,"Invalid memory access size %d",size); - return false; - } + bool getMemoryValue(uint32_t address, int size, uint32_t& dest, char* error) override { + // We allow, but ignore, bad access. + // If we didn't, log/condition statements that reference registers couldn't be configured. + bool valid = Memory::IsValidRange(address, size); - if (address % size) - { - sprintf(error,"Invalid memory access (unaligned)"); - return false; - } - - switch (size) - { + switch (size) { case 1: - dest = Memory::Read_U8(address); - break; + dest = valid ? Memory::Read_U8(address) : 0; + return true; case 2: - dest = Memory::Read_U16(address); - break; + dest = valid ? Memory::Read_U16(address) : 0; + return true; case 4: - dest = Memory::Read_U32(address); - break; + dest = valid ? Memory::Read_U32(address) : 0; + return true; } - return true; + sprintf(error, "Unexpected memory access size %d", size); + return false; } private: diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp index a94a3b46a1..4d80d4b83c 100644 --- a/GPU/Common/GPUDebugInterface.cpp +++ b/GPU/Common/GPUDebugInterface.cpp @@ -916,20 +916,19 @@ ExpressionType GEExpressionFunctions::getFieldType(GECmdFormat fmt, GECmdField f } bool GEExpressionFunctions::getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) { - if (!Memory::IsValidRange(address, size)) { - sprintf(error, "Invalid address or size %08x + %d", address, size); - return false; - } + // We allow, but ignore, bad access. + // If we didn't, log/condition statements that reference registers couldn't be configured. + bool valid = Memory::IsValidRange(address, size); switch (size) { case 1: - dest = Memory::Read_U8(address); + dest = valid ? Memory::Read_U8(address) : 0; return true; case 2: - dest = Memory::Read_U16(address); + dest = valid ? Memory::Read_U16(address) : 0; return true; case 4: - dest = Memory::Read_U32(address); + dest = valid ? Memory::Read_U32(address) : 0; return true; } From 17d94cd3586223aa023a0ef998868727bf24af9f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 17:56:47 -0700 Subject: [PATCH 156/715] SaveState: Restore replacements in only one place. --- Core/HLE/ReplaceTables.cpp | 3 ++- Core/MIPS/x86/Jit.cpp | 2 +- Core/SaveState.cpp | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 85817a49e3..3797e660e2 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -1652,7 +1652,8 @@ std::map SaveAndClearReplacements() { std::map saved; for (auto it = replacedInstructions.begin(), end = replacedInstructions.end(); it != end; ++it) { const u32 addr = it->first; - const u32 curInstr = Memory::Read_U32(addr); + // This will not retain jit blocks. + const u32 curInstr = Memory::Read_Opcode_JIT(addr).encoding; if (MIPS_IS_REPLACEMENT(curInstr)) { saved[addr] = curInstr; Memory::Write_U32(it->second, addr); diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 266b97da00..97f32b7b72 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -591,7 +591,7 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) { // Not sure about the cause. Memory::Opcode origInstruction = Memory::Read_Instruction(GetCompilerPC(), true); if (origInstruction.encoding == op.encoding) { - ERROR_LOG(HLE, "Replacement broken (savestate problem?): %08x", op.encoding); + ERROR_LOG(HLE, "Replacement broken (savestate problem?): %08x at %08x", op.encoding, GetCompilerPC()); return; } diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index bf9f3070ca..148e4307d1 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -316,7 +316,11 @@ namespace SaveState } else { Memory::DoState(p); } - RestoreSavedReplacements(savedReplacements); + + // Don't bother restoring if reading, we'll deal with that in KernelModuleDoState. + // In theory, different functions might have been runtime loaded in the state. + if (p.mode != p.MODE_READ) + RestoreSavedReplacements(savedReplacements); MemoryStick_DoState(p); currentMIPS->DoState(p); From 3f997518f36097cf36570a8a7eca8b9b0997b26e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 22:24:05 -0700 Subject: [PATCH 157/715] irjit: Handle vrot overlap more correctly. Sine ignores overlap, cosine does not. --- Core/MIPS/IR/IRCompVFPU.cpp | 35 ++++++++++++++++++++++++++++------- Core/MIPS/MIPSIntVFPU.cpp | 19 ++++++++++++++++++- Core/MIPS/MIPSVFPUUtils.cpp | 4 ++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 4fffc6765d..42cc1970a1 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -1848,33 +1848,54 @@ namespace MIPSComp { int imm = (op >> 16) & 0x1f; VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); + int sineLane = (imm >> 2) & 3; + int cosineLane = imm & 3; bool negSin = (imm & 0x10) ? true : false; + bool broadcastSine = sineLane == cosineLane; char d[4] = { '0', '0', '0', '0' }; - if (((imm >> 2) & 3) == (imm & 3)) { + if (broadcastSine) { for (int i = 0; i < 4; i++) d[i] = 's'; } - d[(imm >> 2) & 3] = 's'; - d[imm & 3] = 'c'; + d[sineLane] = 's'; + d[cosineLane] = 'c'; u8 dregs[4]; GetVectorRegs(dregs, sz, vd); u8 sreg[1]; GetVectorRegs(sreg, V_Single, vs); + + // If there's overlap, sin is calculated without it, but cosine uses the result. + // This corresponds with prefix handling, where cosine doesn't get in prefixes. + if (broadcastSine || !IsOverlapSafe(n, dregs, 1, sreg)) { + ir.Write(IROp::FSin, IRVTEMP_0, sreg[0]); + if (negSin) + ir.Write(IROp::FNeg, IRVTEMP_0, IRVTEMP_0); + } + for (int i = 0; i < n; i++) { switch (d[i]) { case '0': ir.Write(IROp::SetConstF, dregs[i], ir.AddConstantFloat(0.0f)); break; case 's': - ir.Write(IROp::FSin, dregs[i], sreg[0]); - if (negSin) { - ir.Write(IROp::FNeg, dregs[i], dregs[i]); + if (broadcastSine || !IsOverlapSafe(n, dregs, 1, sreg)) { + ir.Write(IROp::FMov, dregs[i], IRVTEMP_0); + } else { + ir.Write(IROp::FSin, dregs[i], sreg[0]); + if (negSin) { + ir.Write(IROp::FNeg, dregs[i], dregs[i]); + } } break; case 'c': - ir.Write(IROp::FCos, dregs[i], sreg[0]); + if (IsOverlapSafe(n, dregs, 1, sreg)) + ir.Write(IROp::FCos, dregs[i], sreg[0]); + else if (dregs[sineLane] == sreg[0]) + ir.Write(IROp::FCos, dregs[i], IRVTEMP_0); + else + ir.Write(IROp::SetConstF, dregs[i], ir.AddConstantFloat(1.0f)); break; } } diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index c8df6b21dc..5e6d5ad54c 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -1607,7 +1607,24 @@ namespace MIPSInt } else { d[sineLane] = sine; } - d[cosineLane] = cosine; + + if (((vd >> 2) & 7) == ((vs >> 2) & 7)) { + u8 dregs[4]{}; + GetVectorRegs(dregs, sz, vd); + // Calculate cosine based on sine/zero result. + bool written = false; + for (int i = 0; i < 4; i++) { + if (vs == dregs[i]) { + d[cosineLane] = vfpu_cos(d[i]); + written = true; + break; + } + } + if (!written) + d[cosineLane] = cosine; + } else { + d[cosineLane] = cosine; + } // D prefix works, just not for x. currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] &= 0xFFEFC; diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index 0f1d6688ab..e7f7bf7a7f 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -343,6 +343,10 @@ void WriteMatrix(const float *rd, MatrixSize size, int reg) { } int GetVectorOverlap(int vec1, VectorSize size1, int vec2, VectorSize size2) { + // Different matrices? Can't overlap, return early. + if (((vec1 >> 2) & 7) != ((vec2 >> 2) & 7)) + return 0; + int n1 = GetNumVectorElements(size1); int n2 = GetNumVectorElements(size2); u8 regs1[4]; From bbdc8a8f9847ba777056e8f11f9406cc1c8e18c0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Oct 2022 22:43:30 -0700 Subject: [PATCH 158/715] interp: Correct vscl/vmscl t prefix handling. This makes more sense. Fixes Dissidia 012 issues. --- Core/MIPS/IR/IRCompVFPU.cpp | 4 ++-- Core/MIPS/MIPSIntVFPU.cpp | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 42cc1970a1..4694986cf7 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -1185,8 +1185,8 @@ namespace MIPSComp { int vt = _VT; u8 sregs[4], dregs[4], treg; GetVectorRegsPrefixS(sregs, sz, vs); - // TODO: Prefixes seem strange... - GetVectorRegsPrefixT(&treg, V_Single, vt); + // T prefixes handled by interp. + GetVectorRegs(&treg, V_Single, vt); GetVectorRegsPrefixD(dregs, sz, vd); bool overlap = false; diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 5e6d5ad54c..bc1120921e 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -540,8 +540,10 @@ namespace MIPSInt ApplySwizzleS(&s[(n - 1) * 4], V_Quad); // T prefix applies only for the last row, and is used per element. // This is like vscl, but instead of zzzz it uses xxxx. + int tlane = (vt >> 5) & 3; + t[tlane] = t[0]; u32 tprefixRemove = VFPU_ANY_SWIZZLE(); - u32 tprefixAdd = VFPU_SWIZZLE(0, 0, 0, 0); + u32 tprefixAdd = VFPU_SWIZZLE(tlane, tlane, tlane, tlane); ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad); for (int b = 0; b < n; b++) { @@ -1518,9 +1520,10 @@ namespace MIPSInt // T prefix forces swizzle (zzzz for some reason, so we force V_Quad.) // That means negate still works, but constants are a bit weird. - t[2] = V(vt); + int tlane = (vt >> 5) & 3; + t[tlane] = V(vt); u32 tprefixRemove = VFPU_ANY_SWIZZLE(); - u32 tprefixAdd = VFPU_SWIZZLE(2, 2, 2, 2); + u32 tprefixAdd = VFPU_SWIZZLE(tlane, tlane, tlane, tlane); ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad); int n = GetNumVectorElements(sz); From e504f0db8f69a7c202765451258bd3ec9c5f3580 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 07:50:57 -0700 Subject: [PATCH 159/715] Replacement: Avoid needless exists check per tex. --- Core/TextureReplacer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index fb6b436661..8dc2ae01b7 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -410,7 +410,7 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, for (int i = 0; i < MAX_MIP_LEVELS; ++i) { const std::string hashfile = LookupHashFile(cachekey, hash, i); const Path filename = basePath_ / hashfile; - if (hashfile.empty() || !File::Exists(filename)) { + if (hashfile.empty()) { // Out of valid mip levels. Bail out. break; } From 11d0be1fd2346870ef586eb6278839da2e01beef Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 07:55:17 -0700 Subject: [PATCH 160/715] Replacement: Reduce IO checks on startup. --- Core/TextureReplacer.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index 8dc2ae01b7..450fb0adb2 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -76,7 +76,7 @@ void TextureReplacer::NotifyConfigChanged() { File::CreateEmptyFile(newTextureDir / ".nomedia"); } - enabled_ = File::Exists(basePath_) && File::IsDirectory(basePath_); + enabled_ = File::IsDirectory(basePath_); } else if (wasEnabled) { Decimate(ReplacerDecimateMode::ALL); } @@ -101,10 +101,8 @@ bool TextureReplacer::LoadIni() { // Prevents dumping the mipmaps. ignoreMipmap_ = false; - if (File::Exists(basePath_ / INI_FILENAME)) { - IniFile ini; - ini.LoadFromVFS((basePath_ / INI_FILENAME).ToString()); - + IniFile ini; + if (ini.LoadFromVFS((basePath_ / INI_FILENAME).ToString())) { if (!LoadIniValues(ini)) { return false; } @@ -113,10 +111,13 @@ bool TextureReplacer::LoadIni() { std::string overrideFilename; if (ini.GetOrCreateSection("games")->Get(gameID_.c_str(), &overrideFilename, "")) { if (!overrideFilename.empty() && overrideFilename != INI_FILENAME) { - INFO_LOG(G3D, "Loading extra texture ini: %s", overrideFilename.c_str()); IniFile overrideIni; - overrideIni.LoadFromVFS((basePath_ / overrideFilename).ToString()); + if (!overrideIni.LoadFromVFS((basePath_ / overrideFilename).ToString())) { + ERROR_LOG(G3D, "Failed to load extra texture ini: %s", overrideFilename.c_str()); + return false; + } + INFO_LOG(G3D, "Loading extra texture ini: %s", overrideFilename.c_str()); if (!LoadIniValues(overrideIni, true)) { return false; } From 0db48c956ca4179f3bde0572b178ddf3670b76f5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 08:15:37 -0700 Subject: [PATCH 161/715] Replacement: Decimate aggressively with high usage. --- Core/TextureReplacer.cpp | 33 ++++++++++++++++++++++++++++----- Core/TextureReplacer.h | 4 +++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index 450fb0adb2..56bc897a47 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -47,6 +47,7 @@ static const std::string INI_FILENAME = "textures.ini"; static const std::string NEW_TEXTURE_DIR = "new/"; static const int VERSION = 1; static const int MAX_MIP_LEVELS = 12; // 12 should be plenty, 8 is the max mip levels supported by the PSP. +static const double MAX_CACHE_SIZE = 4.0; TextureReplacer::TextureReplacer() { none_.initDone_ = true; @@ -674,15 +675,27 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl void TextureReplacer::Decimate(ReplacerDecimateMode mode) { // Allow replacements to be cached for a long time, although they're large. double age = 1800.0; - if (mode == ReplacerDecimateMode::FORCE_PRESSURE) + if (mode == ReplacerDecimateMode::FORCE_PRESSURE) { age = 90.0; - else if (mode == ReplacerDecimateMode::ALL) + } else if (mode == ReplacerDecimateMode::ALL) { age = 0.0; + } else if (lastTextureCacheSizeGB_ > 1.0) { + double pressure = std::min(MAX_CACHE_SIZE, lastTextureCacheSizeGB_) / MAX_CACHE_SIZE; + // Get more aggressive the closer we are to the max. + age = 90.0 + (1.0 - pressure) * 1710.0; + } const double threshold = time_now_d() - age; + size_t totalSize = 0; for (auto &item : cache_) { - item.second.PurgeIfOlder(threshold); + totalSize += item.second.PurgeIfOlder(threshold); } + + double totalSizeGB = totalSize / (1024.0 * 1024.0 * 1024.0); + if (totalSizeGB >= 1.0) { + WARN_LOG(G3D, "Decimated replacements older than %fs, currently using %f GB of RAM", age, totalSizeGB); + } + lastTextureCacheSizeGB_ = totalSizeGB; } template @@ -968,11 +981,21 @@ void ReplacedTexture::PrepareData(int level) { fclose(fp); } -void ReplacedTexture::PurgeIfOlder(double t) { - if (lastUsed_ < t && (!threadWaitable_ || threadWaitable_->WaitFor(0.0))) { +size_t ReplacedTexture::PurgeIfOlder(double t) { + if (threadWaitable_ && !threadWaitable_->WaitFor(0.0)) + return 0; + + if (lastUsed_ < t) { levelData_.clear(); initDone_ = false; + return 0; } + + size_t s = 0; + for (auto &l : levelData_) { + s += l.size(); + } + return s; } ReplacedTexture::~ReplacedTexture() { diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index b32d31a7d3..f64c9d9b7f 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -166,7 +166,8 @@ struct ReplacedTexture { protected: void Prepare(); void PrepareData(int level); - void PurgeIfOlder(double t); + // Returns size of data not purged. + size_t PurgeIfOlder(double t); std::vector levels_; std::vector> levelData_; @@ -248,6 +249,7 @@ protected: bool reduceHash_ = false; float reduceHashSize = 1.0; // default value with reduceHash to false float reduceHashGlobalValue = 0.5; // Global value for textures dump pngs of all sizes, 0.5 by default but can be set in textures.ini + double lastTextureCacheSizeGB_ = 0.0; bool ignoreMipmap_ = false; std::string gameID_; Path basePath_; From b78c310b477b43852410326743bbd2b8c208e831 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 08:53:24 -0700 Subject: [PATCH 162/715] Replacement: Log only missing explicit filenames. --- Core/TextureReplacer.cpp | 7 ++++--- Core/TextureReplacer.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index 56bc897a47..bb854b3d92 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -420,7 +420,7 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, ReplacedTextureLevel level; level.fmt = Draw::DataFormat::R8G8B8A8_UNORM; level.file = filename; - bool good = PopulateLevel(level); + bool good = PopulateLevel(level, hashfile == HashName(cachekey, hash, i) + ".png"); // We pad files that have been hashrange'd so they are the same texture size. level.w = (level.w * w) / newW; @@ -463,12 +463,13 @@ static ReplacedImageType Identify(FILE *fp) { return ReplacedImageType::INVALID; } -bool TextureReplacer::PopulateLevel(ReplacedTextureLevel &level) { +bool TextureReplacer::PopulateLevel(ReplacedTextureLevel &level, bool ignoreError) { bool good = false; FILE *fp = File::OpenCFile(level.file, "rb"); if (!fp) { - ERROR_LOG(G3D, "Error opening replacement texture file '%s'", level.file.c_str()); + if (!ignoreError) + ERROR_LOG(G3D, "Error opening replacement texture file '%s'", level.file.c_str()); return false; } diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index f64c9d9b7f..62aceee7fa 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -241,7 +241,7 @@ protected: std::string LookupHashFile(u64 cachekey, u32 hash, int level); std::string HashName(u64 cachekey, u32 hash, int level); void PopulateReplacement(ReplacedTexture *result, u64 cachekey, u32 hash, int w, int h); - bool PopulateLevel(ReplacedTextureLevel &level); + bool PopulateLevel(ReplacedTextureLevel &level, bool ignoreError); bool enabled_ = false; bool allowVideo_ = false; From 0048dc2bb8a76abc1c33bca12dcdc3f002d7ab8c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 08:54:52 -0700 Subject: [PATCH 163/715] Replacement: Cache file data across cache keys. --- Core/TextureReplacer.cpp | 34 +++++++++++++++++++++++++++------- Core/TextureReplacer.h | 32 +++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index bb854b3d92..b0a473f20e 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -441,6 +441,12 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, break; } + // Populate the level data pointers for each level. + result->levelData_.resize(result->levels_.size()); + for (size_t i = 0; i < result->levels_.size(); ++i) { + result->levelData_[i] = &levelCache_[result->levels_[i]]; + } + result->prepareDone_ = true; } @@ -836,8 +842,11 @@ bool ReplacedTexture::IsReady(double budget) { } // Loaded already, or not yet on a thread? - if (initDone_ && !levelData_.empty()) + if (initDone_ && !levelData_.empty()) { + for (auto &l : levelData_) + l->lastUsed = lastUsed_; return true; + } // Let's not even start a new texture if we're already behind. if (budget < 0.0) return false; @@ -871,7 +880,6 @@ void ReplacedTexture::Prepare() { return; } - levelData_.resize(levels_.size()); for (int i = 0; i < (int)levels_.size(); ++i) { if (cancelPrepare_) break; @@ -885,9 +893,14 @@ void ReplacedTexture::Prepare() { void ReplacedTexture::PrepareData(int level) { _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel"); + _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel"); const ReplacedTextureLevel &info = levels_[level]; - std::vector &out = levelData_[level]; + std::vector &out = levelData_[level]->data; + + // Already populated from cache. + if (!out.empty()) + return; FILE *fp = File::OpenCFile(info.file, "rb"); if (!fp) { @@ -987,14 +1000,19 @@ size_t ReplacedTexture::PurgeIfOlder(double t) { return 0; if (lastUsed_ < t) { - levelData_.clear(); - initDone_ = false; + for (auto &l : levelData_) { + if (l->lastUsed < t) { + l->data.clear(); + // This means we have to reload. If we never purge any, there's no need. + initDone_ = false; + } + } return 0; } size_t s = 0; for (auto &l : levelData_) { - s += l.size(); + s += l->data.size(); } return s; } @@ -1018,8 +1036,10 @@ bool ReplacedTexture::Load(int level, void *out, int rowPitch) { if (levelData_.empty()) return false; + _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel"); + const ReplacedTextureLevel &info = levels_[level]; - const std::vector &data = levelData_[level]; + const std::vector &data = levelData_[level]->data; if (data.empty()) return false; diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index 62aceee7fa..347e987f16 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -17,11 +17,13 @@ #pragma once +#include "ppsspp_config.h" #include #include #include #include +#include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/MemoryUtil.h" #include "Common/File/Path.h" @@ -54,6 +56,33 @@ struct ReplacedTextureLevel { int h; Draw::DataFormat fmt; // NOTE: Right now, the only supported format is Draw::DataFormat::R8G8B8A8_UNORM. Path file; + + bool operator ==(const ReplacedTextureLevel &other) const { + if (w != other.w || h != other.h || fmt != other.fmt) + return false; + return file == other.file; + } +}; + +namespace std { + template <> + struct hash { + std::size_t operator()(const ReplacedTextureLevel &k) const { +#if PPSSPP_ARCH(64BIT) + uint64_t v = (uint64_t)k.w | ((uint64_t)k.h << 32); + v = __rotl64(v ^ (uint64_t)k.fmt, 13); +#else + uint32_t v = k.w ^ (uint32_t)k.fmt; + v = __rotl(__rotl(v, 13) ^ k.h, 13); +#endif + return v ^ hash()(k.file.ToString()); + } + }; +} + +struct ReplacedLevelCache { + std::vector data; + double lastUsed = 0.0; }; struct ReplacementCacheKey { @@ -170,7 +199,7 @@ protected: size_t PurgeIfOlder(double t); std::vector levels_; - std::vector> levelData_; + std::vector levelData_; ReplacedTextureAlpha alphaStatus_ = ReplacedTextureAlpha::UNKNOWN; double lastUsed_ = 0.0; LimitedWaitable *threadWaitable_ = nullptr; @@ -263,4 +292,5 @@ protected: ReplacedTexture none_; std::unordered_map cache_; std::unordered_map> savedCache_; + std::unordered_map levelCache_; }; From b1a087345a818f5c0a0da851f04d7648f2d01fdb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 10:39:28 -0700 Subject: [PATCH 164/715] Replacement: Lock around shared data access. --- Core/TextureReplacer.cpp | 9 +++++++++ Core/TextureReplacer.h | 1 + 2 files changed, 10 insertions(+) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index b0a473f20e..d70e03919b 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -895,6 +895,9 @@ void ReplacedTexture::PrepareData(int level) { _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel"); _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel"); + // We must lock around access to levelData_ in case two textures try to load it at once. + std::lock_guard guard(levelData_[level]->lock); + const ReplacedTextureLevel &info = levels_[level]; std::vector &out = levelData_[level]->data; @@ -1002,6 +1005,8 @@ size_t ReplacedTexture::PurgeIfOlder(double t) { if (lastUsed_ < t) { for (auto &l : levelData_) { if (l->lastUsed < t) { + // We have to lock since multiple textures might reference this same data. + std::lock_guard guard(l->lock); l->data.clear(); // This means we have to reload. If we never purge any, there's no need. initDone_ = false; @@ -1012,6 +1017,7 @@ size_t ReplacedTexture::PurgeIfOlder(double t) { size_t s = 0; for (auto &l : levelData_) { + std::lock_guard guard(l->lock); s += l->data.size(); } return s; @@ -1038,6 +1044,9 @@ bool ReplacedTexture::Load(int level, void *out, int rowPitch) { _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel"); + // We probably could avoid this lock, but better to play it safe. + std::lock_guard guard(levelData_[level]->lock); + const ReplacedTextureLevel &info = levels_[level]; const std::vector &data = levelData_[level]->data; diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index 347e987f16..b306b09182 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -81,6 +81,7 @@ namespace std { } struct ReplacedLevelCache { + std::mutex lock; std::vector data; double lastUsed = 0.0; }; From c89823ce9219ae107494016abe28b21a546a9901 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 10:34:25 -0700 Subject: [PATCH 165/715] Replacement: Allow use of textures.zip for Android. Will work on all platforms, but intended for situations like Android where random access to files on storage is horribly slow. --- Core/TextureReplacer.cpp | 277 ++++++++++++++++++++++++++++++++++----- Core/TextureReplacer.h | 10 +- ext/libzip/config.h | 4 +- 3 files changed, 256 insertions(+), 35 deletions(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index d70e03919b..6c6e78d579 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -21,6 +21,11 @@ #include #include #include +#ifdef SHARED_LIBZIP +#include +#else +#include "ext/libzip/zip.h" +#endif #include "ext/xxhash.h" @@ -44,6 +49,7 @@ #include "GPU/Common/TextureDecoder.h" static const std::string INI_FILENAME = "textures.ini"; +static const std::string ZIP_FILENAME = "textures.zip"; static const std::string NEW_TEXTURE_DIR = "new/"; static const int VERSION = 1; static const int MAX_MIP_LEVELS = 12; // 12 should be plenty, 8 is the max mip levels supported by the PSP. @@ -55,6 +61,8 @@ TextureReplacer::TextureReplacer() { } TextureReplacer::~TextureReplacer() { + if (zip_) + zip_close(zip_); } void TextureReplacer::Init() { @@ -79,6 +87,9 @@ void TextureReplacer::NotifyConfigChanged() { enabled_ = File::IsDirectory(basePath_); } else if (wasEnabled) { + if (zip_) + zip_close(zip_); + zip_ = nullptr; Decimate(ReplacerDecimateMode::ALL); } @@ -87,6 +98,44 @@ void TextureReplacer::NotifyConfigChanged() { } } +static struct zip *ZipOpenPath(Path fileName) { + int error = 0; + if (fileName.Type() == PathType::CONTENT_URI) { + int fd = File::OpenFD(fileName, File::OPEN_READ); + return zip_fdopen(fd, 0, &error); + } + return zip_open(fileName.c_str(), 0, &error); +} + +static constexpr zip_uint64_t INVALID_ZIP_SIZE = 0xFFFFFFFFFFFFFFFFULL; +static zip_uint64_t ZipFileSize(zip *z, zip_int64_t i) { + zip_stat_t zstat; + if (zip_stat_index(z, i, 0, &zstat) != 0) + return INVALID_ZIP_SIZE; + if ((zstat.valid & ZIP_STAT_SIZE) == 0) + return INVALID_ZIP_SIZE; + return zstat.size; +} + +static bool LoadIniZip(IniFile &ini, zip *z, const std::string &filename) { + zip_int64_t i = zip_name_locate(z, filename.c_str(), ZIP_FL_NOCASE); + if (i < 0) + return false; + + std::string inistr; + zip_uint64_t sz = ZipFileSize(z, i); + if (sz == INVALID_ZIP_SIZE) + return false; + inistr.resize(sz); + + zip_file_t *zf = zip_fopen_index(z, i, 0); + inistr.resize(zip_fread(zf, &inistr[0], inistr.size())); + zip_fclose(zf); + + std::stringstream sstream(inistr); + return ini.Load(sstream); +} + bool TextureReplacer::LoadIni() { // TODO: Use crc32c? hash_ = ReplacedTextureHash::QUICK; @@ -102,8 +151,32 @@ bool TextureReplacer::LoadIni() { // Prevents dumping the mipmaps. ignoreMipmap_ = false; + if (zip_) + zip_close(zip_); + zip_ = nullptr; + IniFile ini; - if (ini.LoadFromVFS((basePath_ / INI_FILENAME).ToString())) { + bool iniLoaded = false; + + // First, check for textures.zip, which is used to reduce IO. + zip *z = ZipOpenPath(basePath_ / ZIP_FILENAME); + if (z) { + iniLoaded = LoadIniZip(ini, z, INI_FILENAME); + // Require the zip have textures.ini to use it. + if (iniLoaded) { + iniLoaded = true; + zip_ = z; + } else { + zip_close(z); + z = nullptr; + } + } + + if (!iniLoaded) { + iniLoaded = ini.LoadFromVFS((basePath_ / INI_FILENAME).ToString()); + } + + if (iniLoaded) { if (!LoadIniValues(ini)) { return false; } @@ -113,7 +186,11 @@ bool TextureReplacer::LoadIni() { if (ini.GetOrCreateSection("games")->Get(gameID_.c_str(), &overrideFilename, "")) { if (!overrideFilename.empty() && overrideFilename != INI_FILENAME) { IniFile overrideIni; - if (!overrideIni.LoadFromVFS((basePath_ / overrideFilename).ToString())) { + if (zip_) + iniLoaded = LoadIniZip(overrideIni, zip_, overrideFilename); + else + iniLoaded = overrideIni.LoadFromVFS((basePath_ / overrideFilename).ToString()); + if (!iniLoaded) { ERROR_LOG(G3D, "Failed to load extra texture ini: %s", overrideFilename.c_str()); return false; } @@ -420,7 +497,16 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, ReplacedTextureLevel level; level.fmt = Draw::DataFormat::R8G8B8A8_UNORM; level.file = filename; - bool good = PopulateLevel(level, hashfile == HashName(cachekey, hash, i) + ".png"); + + bool good; + bool logError = hashfile != HashName(cachekey, hash, i) + ".png"; + if (zip_) { + level.z = zip_; + level.zi = zip_name_locate(zip_, hashfile.c_str(), ZIP_FL_NOCASE); + good = PopulateLevelFromZip(level, !logError); + } else { + good = PopulateLevelFromPath(level, !logError); + } // We pad files that have been hashrange'd so they are the same texture size. level.w = (level.w * w) / newW; @@ -456,12 +542,7 @@ enum class ReplacedImageType { INVALID, }; -static ReplacedImageType Identify(FILE *fp) { - uint8_t magic[4]; - if (fread(magic, 1, 4, fp) != 4) - return ReplacedImageType::INVALID; - rewind(fp); - +static ReplacedImageType Identify(const uint8_t magic[4]) { if (strncmp((const char *)magic, "ZIMG", 4) == 0) return ReplacedImageType::ZIM; if (magic[0] == 0x89 && strncmp((const char *)&magic[1], "PNG", 3) == 0) @@ -469,7 +550,24 @@ static ReplacedImageType Identify(FILE *fp) { return ReplacedImageType::INVALID; } -bool TextureReplacer::PopulateLevel(ReplacedTextureLevel &level, bool ignoreError) { +static ReplacedImageType Identify(FILE *fp) { + uint8_t magic[4]; + if (fread(magic, 1, 4, fp) != 4) + return ReplacedImageType::INVALID; + rewind(fp); + + return Identify(magic); +} + +static ReplacedImageType Identify(zip_file_t *zf) { + uint8_t magic[4]; + if (zip_fread(zf, magic, 4) != 4) + return ReplacedImageType::INVALID; + + return Identify(magic); +} + +bool TextureReplacer::PopulateLevelFromPath(ReplacedTextureLevel &level, bool ignoreError) { bool good = false; FILE *fp = File::OpenCFile(level.file, "rb"); @@ -508,6 +606,62 @@ bool TextureReplacer::PopulateLevel(ReplacedTextureLevel &level, bool ignoreErro return good; } +bool TextureReplacer::PopulateLevelFromZip(ReplacedTextureLevel &level, bool ignoreError) { + bool good = false; + + if (!level.z || level.zi < 0) { + if (!ignoreError) + ERROR_LOG(G3D, "Error opening replacement texture file '%s' in textures.zip", level.file.c_str()); + return false; + } + + zip_file_t *zf = zip_fopen_index(level.z, level.zi, 0); + if (!zf) + return false; + + auto imageType = Identify(zf); + zip_fclose(zf); + + zf = zip_fopen_index(level.z, level.zi, 0); + if (imageType == ReplacedImageType::ZIM) { + uint32_t ignore = 0; + good = zip_fread(zf, &ignore, 4) == 4; + good = good && zip_fread(zf, &level.w, 4) == 4; + good = good && zip_fread(zf, &level.h, 4) == 4; + int flags; + if (good && zip_fread(zf, &flags, 4) == 4) { + good = (flags & ZIM_FORMAT_MASK) == ZIM_RGBA8888; + } + } else if (imageType == ReplacedImageType::PNG) { + png_image png = {}; + png.version = PNG_IMAGE_VERSION; + + // TODO: Use some way to stream data into libpng. Better than the IO lookups on Android... + zip_uint64_t zsize = ZipFileSize(level.z, level.zi); + std::string pngdata; + if (zsize != INVALID_ZIP_SIZE) + pngdata.resize(zsize); + if (!pngdata.empty()) { + pngdata.resize(zip_fread(zf, pngdata.data(), pngdata.size())); + } + + if (png_image_begin_read_from_memory(&png, pngdata.data(), pngdata.size())) { + // We pad files that have been hashrange'd so they are the same texture size. + level.w = png.width; + level.h = png.height; + good = true; + } else { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", level.file.ToVisualString().c_str(), png.message); + } + png_image_free(&png); + } else { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - unsupported format (zip)", level.file.ToVisualString().c_str()); + } + zip_fclose(zf); + + return good; +} + static bool WriteTextureToPNG(png_imagep image, const Path &filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { FILE *fp = File::OpenCFile(filename, "wb"); if (!fp) { @@ -905,35 +1059,75 @@ void ReplacedTexture::PrepareData(int level) { if (!out.empty()) return; - FILE *fp = File::OpenCFile(info.file, "rb"); - if (!fp) { - // Leaving the data sized at zero means failure. - return; - } + FILE *fp = nullptr; + zip_file_t *zf = nullptr; + ReplacedImageType imageType; + if (info.z) { + zf = zip_fopen_index(info.z, info.zi, 0); + if (!zf) + return; - auto imageType = Identify(fp); - if (imageType == ReplacedImageType::ZIM) { - size_t zimSize = File::GetFileSize(fp); - std::unique_ptr zim(new uint8_t[zimSize]); - if (!zim) { - ERROR_LOG(G3D, "Failed to allocate memory for texture replacement"); - fclose(fp); + imageType = Identify(zf); + // Can't assume we can seek. Reopen. + zip_fclose(zf); + zf = zip_fopen_index(info.z, info.zi, 0); + } else { + fp = File::OpenCFile(info.file, "rb"); + if (!fp) { + // Leaving the data sized at zero means failure. return; } - if (fread(&zim[0], 1, zimSize, fp) != zimSize) { - ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM", info.file.c_str()); + imageType = Identify(fp); + } + + auto cleanup = [&] { + if (zf) + zip_fclose(zf); + if (fp) fclose(fp); + }; + + if (imageType == ReplacedImageType::ZIM) { + size_t zimSize; + if (fp) { + zimSize = File::GetFileSize(fp); + } else if (zf) { + zip_uint64_t zsize = ZipFileSize(info.z, info.zi); + zimSize = zsize == INVALID_ZIP_SIZE ? 0 : (size_t)zsize; + } else { + _assert_(false); + } + std::unique_ptr zim(new uint8_t[zimSize]); + if (!zim) { + ERROR_LOG(G3D, "Failed to allocate memory for texture replacement"); + cleanup(); return; } + if (fp) { + if (fread(&zim[0], 1, zimSize, fp) != zimSize) { + ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM", info.file.c_str()); + cleanup(); + return; + } + } else if (zf) { + if (zip_fread(zf, &zim[0], zimSize) != zimSize) { + ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM (zip)", info.file.c_str()); + cleanup(); + return; + } + } else { + _assert_(false); + } + int w, h, f; uint8_t *image; if (LoadZIMPtr(&zim[0], zimSize, &w, &h, &f, &image)) { if (w > info.w || h > info.h) { ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str()); - fclose(fp); + cleanup(); return; } @@ -956,14 +1150,33 @@ void ReplacedTexture::PrepareData(int level) { png_image png = {}; png.version = PNG_IMAGE_VERSION; - if (!png_image_begin_read_from_stdio(&png, fp)) { - ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s", info.file.c_str(), png.message); - fclose(fp); - return; + // Needs to survive for a little while, used for zip only. + std::string pngdata; + if (fp) { + if (!png_image_begin_read_from_stdio(&png, fp)) { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s", info.file.c_str(), png.message); + cleanup(); + return; + } + } else if (zf) { + zip_uint64_t zsize = ZipFileSize(info.z, info.zi); + if (zsize != INVALID_ZIP_SIZE) + pngdata.resize(zsize); + if (!pngdata.empty()) { + pngdata.resize(zip_fread(zf, pngdata.data(), pngdata.size())); + } + + if (!png_image_begin_read_from_memory(&png, pngdata.data(), pngdata.size())) { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", info.file.c_str(), png.message); + cleanup(); + return; + } + } else { + _assert_(false); } if (png.width > (uint32_t)info.w || png.height > (uint32_t)info.h) { ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str()); - fclose(fp); + cleanup(); return; } @@ -980,7 +1193,7 @@ void ReplacedTexture::PrepareData(int level) { out.resize(info.w * info.h * 4); if (!png_image_finish_read(&png, nullptr, &out[0], info.w * 4, nullptr)) { ERROR_LOG(G3D, "Could not load texture replacement: %s - %s", info.file.c_str(), png.message); - fclose(fp); + cleanup(); out.resize(0); return; } @@ -995,7 +1208,7 @@ void ReplacedTexture::PrepareData(int level) { } } - fclose(fp); + cleanup(); } size_t ReplacedTexture::PurgeIfOlder(double t) { diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index b306b09182..05d1488851 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -37,6 +37,7 @@ class TextureCacheCommon; class TextureReplacer; class ReplacedTextureTask; class LimitedWaitable; +struct zip; // These must match the constants in TextureCacheCommon. enum class ReplacedTextureAlpha { @@ -56,6 +57,10 @@ struct ReplacedTextureLevel { int h; Draw::DataFormat fmt; // NOTE: Right now, the only supported format is Draw::DataFormat::R8G8B8A8_UNORM. Path file; + // Can be ignored for hashing/equal, since file has all uniqueness. + // To be able to reload, we need to be able to reopen, unfortunate we can't use zip_file_t. + zip *z = nullptr; + int64_t zi = -1; bool operator ==(const ReplacedTextureLevel &other) const { if (w != other.w || h != other.h || fmt != other.fmt) @@ -271,7 +276,8 @@ protected: std::string LookupHashFile(u64 cachekey, u32 hash, int level); std::string HashName(u64 cachekey, u32 hash, int level); void PopulateReplacement(ReplacedTexture *result, u64 cachekey, u32 hash, int w, int h); - bool PopulateLevel(ReplacedTextureLevel &level, bool ignoreError); + bool PopulateLevelFromPath(ReplacedTextureLevel &level, bool ignoreError); + bool PopulateLevelFromZip(ReplacedTextureLevel &level, bool ignoreError); bool enabled_ = false; bool allowVideo_ = false; @@ -284,6 +290,8 @@ protected: std::string gameID_; Path basePath_; ReplacedTextureHash hash_ = ReplacedTextureHash::QUICK; + zip *zip_ = nullptr; + typedef std::pair WidthHeightPair; std::unordered_map hashranges_; std::unordered_map reducehashranges_; diff --git a/ext/libzip/config.h b/ext/libzip/config.h index a5d26ea015..77c373b611 100644 --- a/ext/libzip/config.h +++ b/ext/libzip/config.h @@ -27,11 +27,11 @@ #endif #ifndef MS_UWP #define HAVE_FILENO -#define HAVE_FSEEKO -#define HAVE_FTELLO #define HAVE_GETPROGNAME #endif #ifndef _WIN32 +#define HAVE_FSEEKO +#define HAVE_FTELLO #define HAVE_LOCALTIME_R #define HAVE_MKSTEMP 1 #endif From a1a484163f1b13298c4aa5c772f3bf1805eb3cb8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 10:44:33 -0700 Subject: [PATCH 166/715] Replacement: Don't double count memory usage. --- Core/TextureReplacer.cpp | 39 ++++++++++++++++++--------------------- Core/TextureReplacer.h | 3 +-- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index 6c6e78d579..a234ada347 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -847,9 +847,14 @@ void TextureReplacer::Decimate(ReplacerDecimateMode mode) { } const double threshold = time_now_d() - age; - size_t totalSize = 0; for (auto &item : cache_) { - totalSize += item.second.PurgeIfOlder(threshold); + item.second.PurgeIfOlder(threshold); + } + + size_t totalSize = 0; + for (auto &item : levelCache_) { + std::lock_guard guard(item.second.lock); + totalSize += item.second.data.size(); } double totalSizeGB = totalSize / (1024.0 * 1024.0 * 1024.0); @@ -1211,29 +1216,21 @@ void ReplacedTexture::PrepareData(int level) { cleanup(); } -size_t ReplacedTexture::PurgeIfOlder(double t) { +void ReplacedTexture::PurgeIfOlder(double t) { if (threadWaitable_ && !threadWaitable_->WaitFor(0.0)) - return 0; + return; + if (lastUsed_ >= t) + return; - if (lastUsed_ < t) { - for (auto &l : levelData_) { - if (l->lastUsed < t) { - // We have to lock since multiple textures might reference this same data. - std::lock_guard guard(l->lock); - l->data.clear(); - // This means we have to reload. If we never purge any, there's no need. - initDone_ = false; - } - } - return 0; - } - - size_t s = 0; for (auto &l : levelData_) { - std::lock_guard guard(l->lock); - s += l->data.size(); + if (l->lastUsed < t) { + // We have to lock since multiple textures might reference this same data. + std::lock_guard guard(l->lock); + l->data.clear(); + // This means we have to reload. If we never purge any, there's no need. + initDone_ = false; + } } - return s; } ReplacedTexture::~ReplacedTexture() { diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index 05d1488851..4fb5bf5224 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -201,8 +201,7 @@ struct ReplacedTexture { protected: void Prepare(); void PrepareData(int level); - // Returns size of data not purged. - size_t PurgeIfOlder(double t); + void PurgeIfOlder(double t); std::vector levels_; std::vector levelData_; From 56ff555309ac740d8b6c70eae5a8be8f8c3eaae3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 21:12:59 -0700 Subject: [PATCH 167/715] irjit: Fix unordered float compares. --- Core/MIPS/IR/IRCompALU.cpp | 4 ++-- Core/MIPS/IR/IRCompFPU.cpp | 2 +- Core/MIPS/IR/IRCompVFPU.cpp | 1 + Core/MIPS/IR/IRInterpreter.cpp | 12 +++++++++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Core/MIPS/IR/IRCompALU.cpp b/Core/MIPS/IR/IRCompALU.cpp index 62d813f3b2..e8fe1c46b6 100644 --- a/Core/MIPS/IR/IRCompALU.cpp +++ b/Core/MIPS/IR/IRCompALU.cpp @@ -118,7 +118,7 @@ void IRFrontend::Comp_RType3(MIPSOpcode op) { MIPSGPReg rd = _RD; // noop, won't write to ZERO. - if (rd == 0) + if (rd == MIPS_REG_ZERO) return; switch (op & 63) { @@ -298,7 +298,7 @@ void IRFrontend::Comp_Allegrex2(MIPSOpcode op) { MIPSGPReg rd = _RD; // Don't change $zr. - if (rd == 0) + if (rd == MIPS_REG_ZERO) return; switch (op & 0x3ff) { diff --git a/Core/MIPS/IR/IRCompFPU.cpp b/Core/MIPS/IR/IRCompFPU.cpp index c0aac3f3f1..cf6b4faa75 100644 --- a/Core/MIPS/IR/IRCompFPU.cpp +++ b/Core/MIPS/IR/IRCompFPU.cpp @@ -118,7 +118,7 @@ void IRFrontend::Comp_FPUComp(MIPSOpcode op) { break; case 3: // ueq, ngl (equal, unordered) mode = IRFpCompareMode::EqualUnordered; - return; + break; case 4: // olt, lt (less than, ordered) mode = IRFpCompareMode::LessOrdered; break; diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 4694986cf7..92b1171692 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -464,6 +464,7 @@ namespace MIPSComp { init = Vec4Init::AllONE; break; default: + INVALIDOP; return; } ir.Write(IROp::Vec4Init, vec[0], (int)init); diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index 27b0ba0ca3..da1e643888 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -881,17 +881,23 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { break; } case IRFpCompareMode::EqualOrdered: - case IRFpCompareMode::EqualUnordered: mips->fpcond = mips->f[inst->src1] == mips->f[inst->src2]; break; + case IRFpCompareMode::EqualUnordered: + mips->fpcond = mips->f[inst->src1] == mips->f[inst->src2] || my_isnan(mips->f[inst->src1]) || my_isnan(mips->f[inst->src2]); + break; case IRFpCompareMode::LessEqualOrdered: - case IRFpCompareMode::LessEqualUnordered: mips->fpcond = mips->f[inst->src1] <= mips->f[inst->src2]; break; + case IRFpCompareMode::LessEqualUnordered: + mips->fpcond = !(mips->f[inst->src1] > mips->f[inst->src2]); + break; case IRFpCompareMode::LessOrdered: - case IRFpCompareMode::LessUnordered: mips->fpcond = mips->f[inst->src1] < mips->f[inst->src2]; break; + case IRFpCompareMode::LessUnordered: + mips->fpcond = !(mips->f[inst->src1] >= mips->f[inst->src2]); + break; } break; From 2da1bf7ffc564c7ff62e05e98ad8b5662a18318f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 21:47:28 -0700 Subject: [PATCH 168/715] interp: Correct dprefix accuracy for vrot. Ignores cosine lane, not always x. --- Core/MIPS/MIPSIntVFPU.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index bc1120921e..1b2c8d60ec 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -1629,8 +1629,9 @@ namespace MIPSInt d[cosineLane] = cosine; } - // D prefix works, just not for x. - currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] &= 0xFFEFC; + // D prefix works, just not for the cosine lane. + uint32_t dprefixRemove = (3 << cosineLane) | (1 << (8 + cosineLane)); + currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] &= 0xFFFFF ^ dprefixRemove; ApplyPrefixD(d, sz); WriteVector(d, sz, vd); PC += 4; From eef29d5e952a4af88a9c039e7129b08e89d39484 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 22:34:41 -0700 Subject: [PATCH 169/715] irjit: Correct prefix validation. Some vcmps, etc. were perfectly valid but were forcing to interp. This also catches more cases that should go to interp correctly. --- Core/MIPS/IR/IRCompVFPU.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 4694986cf7..cd17e5b7b9 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -117,8 +117,9 @@ namespace MIPSComp { int abs = (prefix >> (8 + i)) & 1; int negate = (prefix >> (16 + i)) & 1; int constants = (prefix >> (12 + i)) & 1; - if (regnum < n || abs || negate || constants) { - return false; + if (regnum >= n && !constants) { + if (abs || negate || regnum != i) + return false; } } @@ -472,7 +473,7 @@ namespace MIPSComp { void IRFrontend::Comp_VHdp(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) { + if (js.HasUnknownPrefix() || js.HasSPrefix() || !IsPrefixWithinSize(js.prefixT, op)) { DISABLE; } @@ -754,8 +755,15 @@ namespace MIPSComp { void IRFrontend::Comp_VV2Op(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) - DISABLE; + int optype = (op >> 16) & 0x1f; + if (optype == 0) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op)) + DISABLE; + } else { + // Many of these apply the D prefix strangely or override parts of the S prefix. + if (!js.HasNoPrefix()) + DISABLE; + } // Vector unary operation // d[N] = OP(s[N]) (see below) @@ -763,7 +771,6 @@ namespace MIPSComp { int vs = _VS; int vd = _VD; - int optype = (op >> 16) & 0x1f; if (optype >= 16 && !js.HasNoPrefix()) { DISABLE; } else if ((optype == 1 || optype == 2) && js.HasSPrefix()) { @@ -1458,7 +1465,7 @@ namespace MIPSComp { void IRFrontend::Comp_VDet(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || (js.prefixT & 0x000CFCF0) != 0x000E0) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) { DISABLE; } @@ -1903,7 +1910,7 @@ namespace MIPSComp { void IRFrontend::Comp_Vsgn(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) { DISABLE; } @@ -1999,7 +2006,7 @@ namespace MIPSComp { void IRFrontend::Comp_Vbfy(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix() || (js.prefixS & VFPU_NEGATE(1, 1, 1, 1)) != 0) { DISABLE; } From b740bfbcfb67a724f84893c34eba74a1c09a7e07 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 31 Oct 2022 11:59:07 +0100 Subject: [PATCH 170/715] OpenXR - Map controller motions on keys --- Common/Input/KeyCodes.h | 9 +++++++- Common/VR/PPSSPPVR.cpp | 51 +++++++++++++++++++++++++++++++++++++++++ Core/KeyMap.cpp | 7 ++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Common/Input/KeyCodes.h b/Common/Input/KeyCodes.h index f00dbe8091..15f42c07c1 100644 --- a/Common/Input/KeyCodes.h +++ b/Common/Input/KeyCodes.h @@ -261,7 +261,14 @@ typedef enum _keycode_t { NKCODE_EXT_MOUSEBUTTON_4 = 1006, NKCODE_EXT_MOUSEBUTTON_5 = 1007, NKCODE_EXT_MOUSEWHEEL_UP = 1008, - NKCODE_EXT_MOUSEWHEEL_DOWN = 1009 + NKCODE_EXT_MOUSEWHEEL_DOWN = 1009, + + // Virtual reality controller motion + NKCODE_EXT_MOTION_UP = 1101, + NKCODE_EXT_MOTION_DOWN = 1102, + NKCODE_EXT_MOTION_LEFT = 1103, + NKCODE_EXT_MOTION_RIGHT = 1104, + NKCODE_EXT_MOTION_FORWARD = 1105, } keycode_t; enum AndroidJoystickAxis { diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 0c496d55e0..8c3ae30169 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -78,6 +78,7 @@ static std::vector controllerMapping[2] = { leftControllerMapping, rightControllerMapping }; +static bool controllerMotion[2][5]; static int mouseController = -1; static bool mousePressed[] = {false, false}; @@ -203,6 +204,56 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con } } + //motion control + bool activate; + for (int j = 0; j < 2; j++) { + float limit = 0.5f; //length of needed movement in meters + XrVector3f axis = {0, 1, 0}; + float center = ToRadians((float)VR_GetConfig(VR_CONFIG_MENU_YAW)); + XrQuaternionf orientation = XrQuaternionf_CreateFromVectorAngle(axis, center); + XrVector3f position = XrQuaternionf_Rotate(orientation, IN_VRGetPose(j).position); + + //up + activate = position.y > limit; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_UP; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][0] != activate) NativeKey(keyInput); + controllerMotion[j][0] = activate; + + //down + activate = position.y < -limit * 1.5f; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_DOWN; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][1] != activate) NativeKey(keyInput); + controllerMotion[j][1] = activate; + + //left + activate = position.x < -limit * (j == 0 ? 1.0f : 0.25f); + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_LEFT; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][2] != activate) NativeKey(keyInput); + controllerMotion[j][2] = activate; + + //right + activate = position.x > limit * (j == 1 ? 1.0f : 0.25f); + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_RIGHT; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][3] != activate) NativeKey(keyInput); + controllerMotion[j][3] = activate; + + //forward + activate = position.z < -limit; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_FORWARD; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][4] != activate) NativeKey(keyInput); + controllerMotion[j][4] = activate; + } + //mouse cursor if (mouseController >= 0) { //get position on screen diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index 30b005d86f..0be4dd7182 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -304,6 +304,13 @@ static const KeyMap_IntStrPair key_names[] = { {NKCODE_EXT_MOUSEWHEEL_UP, "MWheelU"}, {NKCODE_EXT_MOUSEWHEEL_DOWN, "MWheelD"}, + + {NKCODE_EXT_MOTION_UP, "MotionUp"}, + {NKCODE_EXT_MOTION_DOWN, "MotionDown"}, + {NKCODE_EXT_MOTION_LEFT, "MotionLeft"}, + {NKCODE_EXT_MOTION_RIGHT, "MotionRight"}, + {NKCODE_EXT_MOTION_FORWARD, "MotionFwd"}, + {NKCODE_START_QUESTION, "¿"}, {NKCODE_LEFTBRACE, "{"}, {NKCODE_RIGHTBRACE, "}"}, From 0101c464a5f3090fd21a2cdde5eefd56ccf5c585 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 31 Oct 2022 12:17:30 +0100 Subject: [PATCH 171/715] OpenXR - Option to disable controller mapping --- Common/VR/PPSSPPVR.cpp | 86 ++++++++++++++++++++------------------- Core/Config.cpp | 1 + Core/Config.h | 1 + UI/GameSettingsScreen.cpp | 2 + 4 files changed, 48 insertions(+), 42 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 8c3ae30169..4c85590107 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -205,53 +205,55 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con } //motion control - bool activate; - for (int j = 0; j < 2; j++) { - float limit = 0.5f; //length of needed movement in meters - XrVector3f axis = {0, 1, 0}; - float center = ToRadians((float)VR_GetConfig(VR_CONFIG_MENU_YAW)); - XrQuaternionf orientation = XrQuaternionf_CreateFromVectorAngle(axis, center); - XrVector3f position = XrQuaternionf_Rotate(orientation, IN_VRGetPose(j).position); + if (g_Config.bEnableMotions) { + for (int j = 0; j < 2; j++) { + bool activate; + float limit = 0.5f; //length of needed movement in meters + XrVector3f axis = {0, 1, 0}; + float center = ToRadians((float)VR_GetConfig(VR_CONFIG_MENU_YAW)); + XrQuaternionf orientation = XrQuaternionf_CreateFromVectorAngle(axis, center); + XrVector3f position = XrQuaternionf_Rotate(orientation, IN_VRGetPose(j).position); - //up - activate = position.y > limit; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_UP; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][0] != activate) NativeKey(keyInput); - controllerMotion[j][0] = activate; + //up + activate = position.y > limit; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_UP; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][0] != activate) NativeKey(keyInput); + controllerMotion[j][0] = activate; - //down - activate = position.y < -limit * 1.5f; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_DOWN; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][1] != activate) NativeKey(keyInput); - controllerMotion[j][1] = activate; + //down + activate = position.y < -limit * 1.5f; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_DOWN; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][1] != activate) NativeKey(keyInput); + controllerMotion[j][1] = activate; - //left - activate = position.x < -limit * (j == 0 ? 1.0f : 0.25f); - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_LEFT; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][2] != activate) NativeKey(keyInput); - controllerMotion[j][2] = activate; + //left + activate = position.x < -limit * (j == 0 ? 1.0f : 0.25f); + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_LEFT; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][2] != activate) NativeKey(keyInput); + controllerMotion[j][2] = activate; - //right - activate = position.x > limit * (j == 1 ? 1.0f : 0.25f); - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_RIGHT; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][3] != activate) NativeKey(keyInput); - controllerMotion[j][3] = activate; + //right + activate = position.x > limit * (j == 1 ? 1.0f : 0.25f); + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_RIGHT; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][3] != activate) NativeKey(keyInput); + controllerMotion[j][3] = activate; - //forward - activate = position.z < -limit; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_FORWARD; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][4] != activate) NativeKey(keyInput); - controllerMotion[j][4] = activate; + //forward + activate = position.z < -limit; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_FORWARD; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][4] != activate) NativeKey(keyInput); + controllerMotion[j][4] = activate; + } } //mouse cursor diff --git a/Core/Config.cpp b/Core/Config.cpp index f62a4baaae..94f96d15ad 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1208,6 +1208,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VREnable", &g_Config.bEnableVR, true), ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, true), ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false), + ConfigSetting("VREnableMotions", &g_Config.bEnableMotions, true), ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f), ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f), ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), diff --git a/Core/Config.h b/Core/Config.h index a494cf4c61..3415cc55e0 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -463,6 +463,7 @@ public: bool bEnableVR; bool bEnable6DoF; bool bEnableStereo; + bool bEnableMotions; float fCameraDistance; float fCameraHeight; float fCameraSide; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 6b68d9c866..a7044d946f 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1163,6 +1163,8 @@ void GameSettingsScreen::CreateViews() { vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); vrStereo->SetEnabledPtr(&g_Config.bEnableVR); + CheckBox *vrMotions = vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); + vrMotions->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); From 3c87e7117707e45f7f8c892a9f02c17ae7e9a83d Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 31 Oct 2022 13:19:06 +0100 Subject: [PATCH 172/715] OpenXR - Let users set the movement length --- Common/VR/PPSSPPVR.cpp | 2 +- Core/Config.cpp | 1 + Core/Config.h | 1 + UI/GameSettingsScreen.cpp | 9 ++++++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 4c85590107..a3b2506f88 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -208,7 +208,7 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con if (g_Config.bEnableMotions) { for (int j = 0; j < 2; j++) { bool activate; - float limit = 0.5f; //length of needed movement in meters + float limit = g_Config.fMotionLength; //length of needed movement in meters XrVector3f axis = {0, 1, 0}; float center = ToRadians((float)VR_GetConfig(VR_CONFIG_MENU_YAW)); XrQuaternionf orientation = XrQuaternionf_CreateFromVectorAngle(axis, center); diff --git a/Core/Config.cpp b/Core/Config.cpp index 94f96d15ad..e3aa3a5707 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1214,6 +1214,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), + ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f), ConfigSetting(false), }; diff --git a/Core/Config.h b/Core/Config.h index 3415cc55e0..4f212646d3 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -469,6 +469,7 @@ public: float fCameraSide; float fCanvasDistance; float fFieldOfViewPercentage; + float fMotionLength; // Debugger int iDisasmWindowX; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index a7044d946f..7fed6c3c18 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1163,15 +1163,18 @@ void GameSettingsScreen::CreateViews() { vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); vrStereo->SetEnabledPtr(&g_Config.bEnableVR); - CheckBox *vrMotions = vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); - vrMotions->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraHeight, -10.0f, 10.0f, vr->T("Camera height adjust", "Camera height adjust"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraSide, -10.0f, 10.0f, vr->T("Camera side adjust", "Camera side adjust"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale", "Headset's field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale", "Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); + + vrSettings->Add(new ItemHeader(vr->T("VR controllers"))); + vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); + PopupSliderChoiceFloat *vrMotions = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMotionLength, 0.3f, 1.0f, vr->T("Motion needed to generate action", "Motion needed to generate action"), 0.1f, screenManager(), vr->T("m"))); + vrMotions->SetEnabledPtr(&g_Config.bEnableMotions); } } From 823bfae5eaaa074f83830ef0374316bf25e56fb5 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 31 Oct 2022 15:00:09 +0100 Subject: [PATCH 173/715] Memory initialization fixed --- Common/VR/PPSSPPVR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index a3b2506f88..4dc3974761 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -78,7 +78,7 @@ static std::vector controllerMapping[2] = { leftControllerMapping, rightControllerMapping }; -static bool controllerMotion[2][5]; +static bool controllerMotion[2][5] = {}; static int mouseController = -1; static bool mousePressed[] = {false, false}; From d2a79f9ea3d1315ec0bfdd0ced799fad7dcd5089 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 31 Oct 2022 17:34:01 +0100 Subject: [PATCH 174/715] OpenXR - Workaround for not working inputbox --- android/src/org/ppsspp/ppsspp/NativeActivity.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 5de8a70b77..8727f39dc3 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -1235,6 +1235,12 @@ public abstract class NativeActivity extends Activity { // The return value is sent to C++ via seqID. public void inputBox(final String seqID, final String title, String defaultText, String defaultAction) { + // Workaround for issue #13363 to fix Split/Second game start + if (isVRDevice()) { + NativeApp.sendInputBox(seqID, false, defaultText); + return; + } + final FrameLayout fl = new FrameLayout(this); final EditText input = new EditText(this); input.setGravity(Gravity.CENTER); From a06c51b419cc6c7b648d530bfc14ec52fdef375a Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 31 Oct 2022 17:44:05 +0100 Subject: [PATCH 175/715] OpenXR - Enable stereo for Split/Second --- assets/compatvr.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assets/compatvr.ini b/assets/compatvr.ini index 79b1c04678..430fb80e47 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -1120,6 +1120,12 @@ ULJM05162 = 1.0 ULJM05599 = 1.0 ULUS10076 = 1.0 +# Split/Second +NPJH50371 = 10.0 +ULES01402 = 10.0 +ULJM05812 = 10.0 +ULUS10513 = 10.0 + # Spot the Differences! NPEZ00107 = 1.0 NPEZ00108 = 1.0 From 6105688c32a7944a51031ed74235fcaa1a9a72e5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Oct 2022 12:18:43 -0700 Subject: [PATCH 176/715] UI: Install textures as a zip if supported. --- Core/Util/GameManager.cpp | 57 +++++++++++++++++++++++++++++++++++++++ Core/Util/GameManager.h | 1 + 2 files changed, 58 insertions(+) diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index e808f07b6c..63952a5d81 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -325,6 +325,9 @@ bool GameManager::InstallGame(Path url, Path fileName, bool deleteAfter) { if (DetectTexturePackDest(z, info.textureIniIndex, dest)) { INFO_LOG(HLE, "Installing '%s' into '%s'", fileName.c_str(), dest.c_str()); File::CreateFullPath(dest); + // Install as a zip file if textures.ini is in the root. Performs better on Android. + if (info.stripChars == 0) + return InstallMemstickZip(z, fileName, dest / "textures.zip", info, deleteAfter); File::CreateEmptyFile(dest / ".nomedia"); return InstallMemstickGame(z, fileName, dest, info, true, deleteAfter); } else { @@ -617,6 +620,60 @@ bail: return false; } +bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const Path &dest, const ZipFileInfo &info, bool deleteAfter) { + size_t allBytes = 0; + size_t bytesCopied = 0; + + auto sy = GetI18NCategory("System"); + + // We don't need the zip anymore, as we're going to copy it as-is. + zip_close(z); + z = nullptr; + + // Not using File::Copy() so we can report progress. + FILE *inf = File::OpenCFile(zipfile, "rb"); + if (!inf) + return false; + + allBytes = (size_t)File::GetFileSize(inf); + FILE *outf = File::OpenCFile(dest, "wb"); + if (!outf) { + SetInstallError(sy->T("Storage full")); + fclose(inf); + return false; + } + + const size_t blockSize = 1024 * 128; + u8 *buffer = new u8[blockSize]; + while (bytesCopied < allBytes) { + size_t readSize = std::min(blockSize, allBytes - bytesCopied); + if (fread(buffer, readSize, 1, inf) != 1) + break; + if (fwrite(buffer, readSize, 1, outf) != 1) + break; + bytesCopied += readSize; + installProgress_ = (float)allBytes / (float)allBytes; + } + + delete[] buffer; + fclose(inf); + fclose(outf); + + if (bytesCopied < allBytes) { + File::Delete(dest); + SetInstallError(sy->T("Storage full")); + return false; + } + + installProgress_ = 1.0f; + if (deleteAfter) { + File::Delete(zipfile); + } + InstallDone(); + ResetInstallError(); + return true; +} + bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter) { // Let's place the output file in the currently selected Games directory. diff --git a/Core/Util/GameManager.h b/Core/Util/GameManager.h index df74af2fd7..f7fc8ff7b5 100644 --- a/Core/Util/GameManager.h +++ b/Core/Util/GameManager.h @@ -79,6 +79,7 @@ public: private: bool InstallGame(Path url, Path tempFileName, bool deleteAfter); bool InstallMemstickGame(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool allowRoot, bool deleteAfter); + bool InstallMemstickZip(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool deleteAfter); bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter); bool InstallRawISO(const Path &zipFile, const std::string &originalName, bool deleteAfter); void InstallDone(); From 15645ca480044b5eec20bcf680e60ac3258b6224 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 31 Oct 2022 20:17:18 -0700 Subject: [PATCH 177/715] Replacement: Avoid issues with c++14 data(). --- Core/TextureReplacer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index a234ada347..dcd413ff2b 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -642,10 +642,10 @@ bool TextureReplacer::PopulateLevelFromZip(ReplacedTextureLevel &level, bool ign if (zsize != INVALID_ZIP_SIZE) pngdata.resize(zsize); if (!pngdata.empty()) { - pngdata.resize(zip_fread(zf, pngdata.data(), pngdata.size())); + pngdata.resize(zip_fread(zf, &pngdata[0], pngdata.size())); } - if (png_image_begin_read_from_memory(&png, pngdata.data(), pngdata.size())) { + if (png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) { // We pad files that have been hashrange'd so they are the same texture size. level.w = png.width; level.h = png.height; @@ -1168,10 +1168,10 @@ void ReplacedTexture::PrepareData(int level) { if (zsize != INVALID_ZIP_SIZE) pngdata.resize(zsize); if (!pngdata.empty()) { - pngdata.resize(zip_fread(zf, pngdata.data(), pngdata.size())); + pngdata.resize(zip_fread(zf, &pngdata[0], pngdata.size())); } - if (!png_image_begin_read_from_memory(&png, pngdata.data(), pngdata.size())) { + if (!png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) { ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", info.file.c_str(), png.message); cleanup(); return; From 67af5baf3ead3b7201c3b1c49bd93d342a466809 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 1 Nov 2022 10:08:43 +0100 Subject: [PATCH 178/715] OpenXR - Settings code cleanup --- UI/GameSettingsScreen.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 7fed6c3c18..a3195adfc5 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1165,15 +1165,15 @@ void GameSettingsScreen::CreateViews() { vrStereo->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraHeight, -10.0f, 10.0f, vr->T("Camera height adjust", "Camera height adjust"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraSide, -10.0f, 10.0f, vr->T("Camera side adjust", "Camera side adjust"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale", "Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraHeight, -10.0f, 10.0f, vr->T("Camera height adjust"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraSide, -10.0f, 10.0f, vr->T("Camera side adjust"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); vrSettings->Add(new ItemHeader(vr->T("VR controllers"))); vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); - PopupSliderChoiceFloat *vrMotions = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMotionLength, 0.3f, 1.0f, vr->T("Motion needed to generate action", "Motion needed to generate action"), 0.1f, screenManager(), vr->T("m"))); + PopupSliderChoiceFloat *vrMotions = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMotionLength, 0.3f, 1.0f, vr->T("Motion needed to generate action"), 0.1f, screenManager(), vr->T("m"))); vrMotions->SetEnabledPtr(&g_Config.bEnableMotions); } } From 7967da0f6fb3806546acd6703fa6ce68614aa9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 1 Nov 2022 13:43:48 +0100 Subject: [PATCH 179/715] Vulkan: Fix descriptor set binding in geometry shader generator. Should fix #16315 --- GPU/Common/GeometryShaderGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index 586afdca0f..1438cbb6f5 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -58,7 +58,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu if (compat.shaderLanguage == GLSL_VULKAN) { WRITE(p, "\n"); - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); } else if (compat.shaderLanguage == HLSL_D3D11) { WRITE(p, "cbuffer base : register(b0) {\n%s};\n", ub_baseStr); } From e7185f93b3f5f29d3bb379c615d080c332d148ef Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Nov 2022 22:14:23 -0700 Subject: [PATCH 180/715] GE Debugger: Restrict marking of dirty VRAM better. --- GPU/Debugger/Record.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 6058546b0f..f27464a48a 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -123,10 +123,10 @@ static void DirtyVRAM(u32 start, u32 sz, DirtyVRAMFlag flag) { } static void DirtyDrawnVRAM() { - int w = std::max(gstate.getScissorX2(), gstate.getRegionX2()) + 1; - int h = std::max(gstate.getScissorY2(), gstate.getRegionY2()) + 1; + int w = std::min(gstate.getScissorX2(), gstate.getRegionX2()) + 1; + int h = std::min(gstate.getScissorY2(), gstate.getRegionY2()) + 1; - bool drawZ = gstate.isDepthWriteEnabled() && gstate.isDepthTestEnabled(); + bool drawZ = !gstate.isModeClear() && gstate.isDepthWriteEnabled() && gstate.isDepthTestEnabled(); bool clearZ = gstate.isModeClear() && gstate.isClearModeDepthMask(); if (drawZ || clearZ) { int bytes = 2 * gstate.DepthBufStride() * h; From 5afb009b56caedf4f41444afbc4730408fd90716 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Nov 2022 22:15:11 -0700 Subject: [PATCH 181/715] GE Debugger: Dump textures only if possibly used. --- GPU/Debugger/Record.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index f27464a48a..e6decebedc 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -420,9 +420,12 @@ static void FlushPrimState(int vcount) { // We re-flush textures always in case the game changed them... kinda expensive. // TODO: Dirty textures on transfer/stall/etc. somehow? // TODO: Or maybe de-dup by validating if it has changed? + bool textureEnabled = gstate.isTextureMapEnabled() || gstate.isAntiAliasEnabled(); + // Play it safe and allow texture coords to emit data too. + bool textureCoords = (gstate.vertType & GE_VTYPE_TC_MASK) != 0; for (int level = 0; level < 8; ++level) { u32 texaddr = gstate.getTextureAddress(level); - if (texaddr) { + if (texaddr && (textureEnabled || textureCoords)) { EmitTextureData(level, texaddr); } } From 00e8720749512518dee676a0209d2a44dd8b1e1d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Nov 2022 22:47:46 -0700 Subject: [PATCH 182/715] GE Debugger: Try harder to identify unchanged VRAM. If we exit to the CPU (stall), we don't know if VRAM gets changed by the CPU. We can check to avoid making the dump require unnecessary copying. --- GPU/Debugger/Record.cpp | 62 +++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index e6decebedc..97ed107470 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -60,11 +60,13 @@ static std::vector commands; static std::vector lastRegisters; static std::vector lastTextures; static std::set lastRenderTargets; +static std::vector lastVRAM; enum class DirtyVRAMFlag : uint8_t { CLEAN = 0, - DIRTY = 1, - DRAWN = 2, + UNKNOWN = 1, + DIRTY = 2, + DRAWN = 3, }; static constexpr uint32_t DIRTY_VRAM_SHIFT = 8; static constexpr uint32_t DIRTY_VRAM_ROUND = (1 << DIRTY_VRAM_SHIFT) - 1; @@ -106,8 +108,15 @@ static Path GenRecordingFilename() { } static void DirtyAllVRAM(DirtyVRAMFlag flag) { - for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i) - dirtyVRAM[i] = flag; + if (flag == DirtyVRAMFlag::UNKNOWN) { + for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i) { + if (dirtyVRAM[i] == DirtyVRAMFlag::CLEAN) + dirtyVRAM[i] = DirtyVRAMFlag::UNKNOWN; + } + } else { + for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i) + dirtyVRAM[i] = flag; + } } static void DirtyVRAM(u32 start, u32 sz, DirtyVRAMFlag flag) { @@ -155,6 +164,7 @@ static void BeginRecording() { pushbuf.resize(pushbuf.size() + sz); gstate.Save((u32_le *)(pushbuf.data() + ptr)); commands.push_back({CommandType::INIT, sz, ptr}); + lastVRAM.resize(2 * 1024 * 1024); // Also save the initial CLUT. GPUDebugBuffer clut; @@ -325,6 +335,7 @@ static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) { addr &= 0x041FFFFF; const bool isTarget = lastRenderTargets.find(addr) != lastRenderTargets.end(); + bool isUnknownVRAM = false; bool isDirtyVRAM = false; bool isDrawnVRAM = false; uint32_t start = (addr >> DIRTY_VRAM_SHIFT) & DIRTY_VRAM_MASK; @@ -333,16 +344,25 @@ static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) { bool endEven = ((addr + sizeInRAM) & DIRTY_VRAM_ROUND) == 0; for (uint32_t i = 0; i < blocks; ++i) { DirtyVRAMFlag flag = dirtyVRAM[start + i]; + isUnknownVRAM = (isUnknownVRAM || flag == DirtyVRAMFlag::UNKNOWN) && flag != DirtyVRAMFlag::DIRTY && flag != DirtyVRAMFlag::DRAWN; isDirtyVRAM = isDirtyVRAM || flag != DirtyVRAMFlag::CLEAN; isDrawnVRAM = isDrawnVRAM || flag == DirtyVRAMFlag::DRAWN; // Mark the VRAM clean now that it's been copied to VRAM. - if (flag == DirtyVRAMFlag::DIRTY) { + if (flag == DirtyVRAMFlag::UNKNOWN || flag == DirtyVRAMFlag::DIRTY) { if ((i > 0 || startEven) && (i < blocks || endEven)) dirtyVRAM[start + i] = DirtyVRAMFlag::CLEAN; } } + if (isUnknownVRAM && isDirtyVRAM) { + // This means it's only UNKNOWN/CLEAN and not known to be actually dirty. + // Let's check our shadow copy of what we last sent for this VRAM. + int diff = memcmp(&lastVRAM[addr & 0x001FFFFF], Memory::GetPointerUnchecked(addr), sizeInRAM); + if (diff == 0) + isDirtyVRAM = false; + } + // The isTarget flag is mostly used for replay of dumps on a PSP. u32 flags = isTarget ? 1 : 0; // The unchangedVRAM flag tells us we can skip recopying. @@ -376,13 +396,16 @@ static void EmitTextureData(int level, u32 texaddr) { u32 pad; }; - u32 flags = GetTargetFlags(texaddr, sizeInRAM); + u32 flags = GetTargetFlags(texaddr, bytes); FramebufData framebuf{ texaddr, bufw, flags }; framebufData.resize(sizeof(framebuf) + bytes); memcpy(&framebufData[0], &framebuf, sizeof(framebuf)); memcpy(&framebufData[sizeof(framebuf)], p, bytes); p = &framebufData[0]; + if ((flags & 2) == 0) + memcpy(&lastVRAM[texaddr & 0x001FFFFF], Memory::GetPointerUnchecked(texaddr), bytes); + // Okay, now we'll just emit this instead. type = CommandType((int)CommandType::FRAMEBUF0 + level); bytes += (u32)sizeof(framebuf); @@ -418,8 +441,6 @@ static void FlushPrimState(int vcount) { lastRenderTargets.insert(PSP_GetVidMemBase() | gstate.getDepthBufRawAddress()); // We re-flush textures always in case the game changed them... kinda expensive. - // TODO: Dirty textures on transfer/stall/etc. somehow? - // TODO: Or maybe de-dup by validating if it has changed? bool textureEnabled = gstate.isTextureMapEnabled() || gstate.isAntiAliasEnabled(); // Play it safe and allow texture coords to emit data too. bool textureCoords = (gstate.vertType & GE_VTYPE_TC_MASK) != 0; @@ -511,6 +532,9 @@ static void EmitClut(u32 op) { pushbuf.resize(pushbuf.size() + sizeof(data)); memcpy(pushbuf.data() + cmd.ptr, &data, sizeof(data)); commands.push_back(cmd); + + if ((flags & 2) == 0) + memcpy(&lastVRAM[addr & 0x001FFFFF], Memory::GetPointerUnchecked(addr), bytes); } EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes, 16); } @@ -561,6 +585,7 @@ static void FinishRecording() { Path filename = WriteRecording(); commands.clear(); pushbuf.clear(); + lastVRAM.clear(); NOTICE_LOG(SYSTEM, "Recording finished"); active = false; @@ -658,8 +683,9 @@ void NotifyMemcpy(u32 dest, u32 src, u32 sz) { sz = Memory::ValidSize(dest, sz); if (sz != 0) { - EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointer(dest), sz, 1); - DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY); + EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointerUnchecked(dest), sz, 1); + memcpy(&lastVRAM[dest & 0x001FFFFF], Memory::GetPointerUnchecked(dest), sz); + DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN); } } } @@ -685,20 +711,14 @@ void NotifyMemset(u32 dest, int v, u32 sz) { pushbuf.resize(pushbuf.size() + sizeof(data)); memcpy(pushbuf.data() + cmd.ptr, &data, sizeof(data)); commands.push_back(cmd); - DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY); + memset(&lastVRAM[dest & 0x001FFFFF], v, sz); + DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN); } } void NotifyUpload(u32 dest, u32 sz) { - if (!active) { - return; - } - - if (Memory::IsVRAMAddress(dest)) { - // This also checks the edram translation value. - NotifyMemcpy(dest, dest, sz); - DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY); - } + // This also checks the edram translation value and dirties VRAM. + NotifyMemcpy(dest, dest, sz); } static bool HasDrawCommands() { @@ -793,7 +813,7 @@ void NotifyCPU() { return; } - DirtyAllVRAM(DirtyVRAMFlag::DIRTY); + DirtyAllVRAM(DirtyVRAMFlag::UNKNOWN); } }; From 1ffdf0d5b8811e6598390d06fc608b1a3299e72a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Nov 2022 22:56:29 -0700 Subject: [PATCH 183/715] GE Debugger: Respect unchanged VRAM each frame. Oops, wasn't setting the version each run after caching the frame dump data. --- GPU/Debugger/Playback.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index eb3f9fa2bc..03472ba834 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -46,6 +46,7 @@ namespace GPURecord { static std::string lastExecFilename; +static uint32_t lastExecVersion; static std::vector lastExecCommands; static std::vector lastExecPushbuf; static std::mutex executeLock; @@ -761,6 +762,7 @@ static void ReplayStop() { lastExecFilename.clear(); lastExecCommands.clear(); lastExecPushbuf.clear(); + lastExecVersion = 0; } bool RunMountedReplay(const std::string &filename) { @@ -769,7 +771,7 @@ bool RunMountedReplay(const std::string &filename) { std::lock_guard guard(executeLock); Core_ListenStopRequest(&ReplayStop); - uint32_t version = 0; + uint32_t version = lastExecVersion; if (lastExecFilename != filename) { PROFILE_THIS_SCOPE("ReplayLoad"); u32 fp = pspFileSystem.OpenFile(filename, FILEACCESS_READ); @@ -812,6 +814,7 @@ bool RunMountedReplay(const std::string &filename) { } lastExecFilename = filename; + lastExecVersion = version; } DumpExecute executor(lastExecPushbuf, lastExecCommands, version); From 404f67be8afa08fa27927a0160e98f09908296a4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Nov 2022 23:08:24 -0700 Subject: [PATCH 184/715] Build: Enable libzip on libretro. --- libretro/Makefile.common | 250 +++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 126 deletions(-) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index cd9f7f04d7..7d858e0129 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -37,133 +37,131 @@ INCFLAGS += \ -I$(EXTDIR)/xxhash \ -I$(EXTDIR)/glew -ifeq ($(PLATFORM_EXT), android) - INCFLAGS += -I$(EXTDIR)/libzip - SOURCES_C += \ - $(EXTDIR)/libzip/zip_add.c \ - $(EXTDIR)/libzip/zip_add_dir.c \ - $(EXTDIR)/libzip/zip_add_entry.c \ - $(EXTDIR)/libzip/zip_algorithm_deflate.c \ - $(EXTDIR)/libzip/zip_buffer.c \ - $(EXTDIR)/libzip/zip_close.c \ - $(EXTDIR)/libzip/zip_delete.c \ - $(EXTDIR)/libzip/zip_dir_add.c \ - $(EXTDIR)/libzip/zip_dirent.c \ - $(EXTDIR)/libzip/zip_discard.c \ - $(EXTDIR)/libzip/zip_entry.c \ - $(EXTDIR)/libzip/zip_error.c \ - $(EXTDIR)/libzip/zip_error_clear.c \ - $(EXTDIR)/libzip/zip_error_get.c \ - $(EXTDIR)/libzip/zip_error_get_sys_type.c \ - $(EXTDIR)/libzip/zip_error_strerror.c \ - $(EXTDIR)/libzip/zip_error_to_str.c \ - $(EXTDIR)/libzip/zip_extra_field.c \ - $(EXTDIR)/libzip/zip_extra_field_api.c \ - $(EXTDIR)/libzip/zip_fclose.c \ - $(EXTDIR)/libzip/zip_fdopen.c \ - $(EXTDIR)/libzip/zip_file_add.c \ - $(EXTDIR)/libzip/zip_file_error_clear.c \ - $(EXTDIR)/libzip/zip_file_error_get.c \ - $(EXTDIR)/libzip/zip_file_get_comment.c \ - $(EXTDIR)/libzip/zip_file_get_external_attributes.c \ - $(EXTDIR)/libzip/zip_file_get_offset.c \ - $(EXTDIR)/libzip/zip_file_rename.c \ - $(EXTDIR)/libzip/zip_file_replace.c \ - $(EXTDIR)/libzip/zip_file_set_comment.c \ - $(EXTDIR)/libzip/zip_file_set_encryption.c \ - $(EXTDIR)/libzip/zip_file_set_external_attributes.c \ - $(EXTDIR)/libzip/zip_file_set_mtime.c \ - $(EXTDIR)/libzip/zip_file_strerror.c \ - $(EXTDIR)/libzip/zip_fopen.c \ - $(EXTDIR)/libzip/zip_fopen_encrypted.c \ - $(EXTDIR)/libzip/zip_fopen_index.c \ - $(EXTDIR)/libzip/zip_fopen_index_encrypted.c \ - $(EXTDIR)/libzip/zip_fread.c \ - $(EXTDIR)/libzip/zip_fseek.c \ - $(EXTDIR)/libzip/zip_ftell.c \ - $(EXTDIR)/libzip/zip_get_archive_comment.c \ - $(EXTDIR)/libzip/zip_get_archive_flag.c \ - $(EXTDIR)/libzip/zip_get_encryption_implementation.c \ - $(EXTDIR)/libzip/zip_get_file_comment.c \ - $(EXTDIR)/libzip/zip_get_name.c \ - $(EXTDIR)/libzip/zip_get_num_entries.c \ - $(EXTDIR)/libzip/zip_get_num_files.c \ - $(EXTDIR)/libzip/zip_hash.c \ - $(EXTDIR)/libzip/zip_io_util.c \ - $(EXTDIR)/libzip/zip_libzip_version.c \ - $(EXTDIR)/libzip/zip_memdup.c \ - $(EXTDIR)/libzip/zip_name_locate.c \ - $(EXTDIR)/libzip/zip_new.c \ - $(EXTDIR)/libzip/zip_open.c \ - $(EXTDIR)/libzip/zip_pkware.c \ - $(EXTDIR)/libzip/zip_progress.c \ - $(EXTDIR)/libzip/zip_rename.c \ - $(EXTDIR)/libzip/zip_replace.c \ - $(EXTDIR)/libzip/zip_set_archive_comment.c \ - $(EXTDIR)/libzip/zip_set_archive_flag.c \ - $(EXTDIR)/libzip/zip_set_default_password.c \ - $(EXTDIR)/libzip/zip_set_file_comment.c \ - $(EXTDIR)/libzip/zip_set_file_compression.c \ - $(EXTDIR)/libzip/zip_set_name.c \ - $(EXTDIR)/libzip/zip_source_accept_empty.c \ - $(EXTDIR)/libzip/zip_source_begin_write.c \ - $(EXTDIR)/libzip/zip_source_begin_write_cloning.c \ - $(EXTDIR)/libzip/zip_source_buffer.c \ - $(EXTDIR)/libzip/zip_source_call.c \ - $(EXTDIR)/libzip/zip_source_close.c \ - $(EXTDIR)/libzip/zip_source_commit_write.c \ - $(EXTDIR)/libzip/zip_source_compress.c \ - $(EXTDIR)/libzip/zip_source_crc.c \ - $(EXTDIR)/libzip/zip_source_error.c \ - $(EXTDIR)/libzip/zip_source_file_common.c \ - $(EXTDIR)/libzip/zip_source_file_stdio.c \ - $(EXTDIR)/libzip/zip_source_free.c \ - $(EXTDIR)/libzip/zip_source_function.c \ - $(EXTDIR)/libzip/zip_source_get_file_attributes.c \ - $(EXTDIR)/libzip/zip_source_is_deleted.c \ - $(EXTDIR)/libzip/zip_source_layered.c \ - $(EXTDIR)/libzip/zip_source_open.c \ - $(EXTDIR)/libzip/zip_source_pkware_decode.c \ - $(EXTDIR)/libzip/zip_source_pkware_encode.c \ - $(EXTDIR)/libzip/zip_source_read.c \ - $(EXTDIR)/libzip/zip_source_remove.c \ - $(EXTDIR)/libzip/zip_source_rollback_write.c \ - $(EXTDIR)/libzip/zip_source_seek.c \ - $(EXTDIR)/libzip/zip_source_seek_write.c \ - $(EXTDIR)/libzip/zip_source_stat.c \ - $(EXTDIR)/libzip/zip_source_supports.c \ - $(EXTDIR)/libzip/zip_source_tell.c \ - $(EXTDIR)/libzip/zip_source_tell_write.c \ - $(EXTDIR)/libzip/zip_source_window.c \ - $(EXTDIR)/libzip/zip_source_write.c \ - $(EXTDIR)/libzip/zip_source_zip.c \ - $(EXTDIR)/libzip/zip_source_zip_new.c \ - $(EXTDIR)/libzip/zip_stat.c \ - $(EXTDIR)/libzip/zip_stat_index.c \ - $(EXTDIR)/libzip/zip_stat_init.c \ - $(EXTDIR)/libzip/zip_strerror.c \ - $(EXTDIR)/libzip/zip_string.c \ - $(EXTDIR)/libzip/zip_unchange.c \ - $(EXTDIR)/libzip/zip_unchange_all.c \ - $(EXTDIR)/libzip/zip_unchange_archive.c \ - $(EXTDIR)/libzip/zip_unchange_data.c \ - $(EXTDIR)/libzip/zip_utf-8.c \ - $(EXTDIR)/libzip/zip_err_str.c +INCFLAGS += -I$(EXTDIR)/libzip +SOURCES_C += \ + $(EXTDIR)/libzip/zip_add.c \ + $(EXTDIR)/libzip/zip_add_dir.c \ + $(EXTDIR)/libzip/zip_add_entry.c \ + $(EXTDIR)/libzip/zip_algorithm_deflate.c \ + $(EXTDIR)/libzip/zip_buffer.c \ + $(EXTDIR)/libzip/zip_close.c \ + $(EXTDIR)/libzip/zip_delete.c \ + $(EXTDIR)/libzip/zip_dir_add.c \ + $(EXTDIR)/libzip/zip_dirent.c \ + $(EXTDIR)/libzip/zip_discard.c \ + $(EXTDIR)/libzip/zip_entry.c \ + $(EXTDIR)/libzip/zip_error.c \ + $(EXTDIR)/libzip/zip_error_clear.c \ + $(EXTDIR)/libzip/zip_error_get.c \ + $(EXTDIR)/libzip/zip_error_get_sys_type.c \ + $(EXTDIR)/libzip/zip_error_strerror.c \ + $(EXTDIR)/libzip/zip_error_to_str.c \ + $(EXTDIR)/libzip/zip_extra_field.c \ + $(EXTDIR)/libzip/zip_extra_field_api.c \ + $(EXTDIR)/libzip/zip_fclose.c \ + $(EXTDIR)/libzip/zip_fdopen.c \ + $(EXTDIR)/libzip/zip_file_add.c \ + $(EXTDIR)/libzip/zip_file_error_clear.c \ + $(EXTDIR)/libzip/zip_file_error_get.c \ + $(EXTDIR)/libzip/zip_file_get_comment.c \ + $(EXTDIR)/libzip/zip_file_get_external_attributes.c \ + $(EXTDIR)/libzip/zip_file_get_offset.c \ + $(EXTDIR)/libzip/zip_file_rename.c \ + $(EXTDIR)/libzip/zip_file_replace.c \ + $(EXTDIR)/libzip/zip_file_set_comment.c \ + $(EXTDIR)/libzip/zip_file_set_encryption.c \ + $(EXTDIR)/libzip/zip_file_set_external_attributes.c \ + $(EXTDIR)/libzip/zip_file_set_mtime.c \ + $(EXTDIR)/libzip/zip_file_strerror.c \ + $(EXTDIR)/libzip/zip_fopen.c \ + $(EXTDIR)/libzip/zip_fopen_encrypted.c \ + $(EXTDIR)/libzip/zip_fopen_index.c \ + $(EXTDIR)/libzip/zip_fopen_index_encrypted.c \ + $(EXTDIR)/libzip/zip_fread.c \ + $(EXTDIR)/libzip/zip_fseek.c \ + $(EXTDIR)/libzip/zip_ftell.c \ + $(EXTDIR)/libzip/zip_get_archive_comment.c \ + $(EXTDIR)/libzip/zip_get_archive_flag.c \ + $(EXTDIR)/libzip/zip_get_encryption_implementation.c \ + $(EXTDIR)/libzip/zip_get_file_comment.c \ + $(EXTDIR)/libzip/zip_get_name.c \ + $(EXTDIR)/libzip/zip_get_num_entries.c \ + $(EXTDIR)/libzip/zip_get_num_files.c \ + $(EXTDIR)/libzip/zip_hash.c \ + $(EXTDIR)/libzip/zip_io_util.c \ + $(EXTDIR)/libzip/zip_libzip_version.c \ + $(EXTDIR)/libzip/zip_memdup.c \ + $(EXTDIR)/libzip/zip_name_locate.c \ + $(EXTDIR)/libzip/zip_new.c \ + $(EXTDIR)/libzip/zip_open.c \ + $(EXTDIR)/libzip/zip_pkware.c \ + $(EXTDIR)/libzip/zip_progress.c \ + $(EXTDIR)/libzip/zip_rename.c \ + $(EXTDIR)/libzip/zip_replace.c \ + $(EXTDIR)/libzip/zip_set_archive_comment.c \ + $(EXTDIR)/libzip/zip_set_archive_flag.c \ + $(EXTDIR)/libzip/zip_set_default_password.c \ + $(EXTDIR)/libzip/zip_set_file_comment.c \ + $(EXTDIR)/libzip/zip_set_file_compression.c \ + $(EXTDIR)/libzip/zip_set_name.c \ + $(EXTDIR)/libzip/zip_source_accept_empty.c \ + $(EXTDIR)/libzip/zip_source_begin_write.c \ + $(EXTDIR)/libzip/zip_source_begin_write_cloning.c \ + $(EXTDIR)/libzip/zip_source_buffer.c \ + $(EXTDIR)/libzip/zip_source_call.c \ + $(EXTDIR)/libzip/zip_source_close.c \ + $(EXTDIR)/libzip/zip_source_commit_write.c \ + $(EXTDIR)/libzip/zip_source_compress.c \ + $(EXTDIR)/libzip/zip_source_crc.c \ + $(EXTDIR)/libzip/zip_source_error.c \ + $(EXTDIR)/libzip/zip_source_file_common.c \ + $(EXTDIR)/libzip/zip_source_file_stdio.c \ + $(EXTDIR)/libzip/zip_source_free.c \ + $(EXTDIR)/libzip/zip_source_function.c \ + $(EXTDIR)/libzip/zip_source_get_file_attributes.c \ + $(EXTDIR)/libzip/zip_source_is_deleted.c \ + $(EXTDIR)/libzip/zip_source_layered.c \ + $(EXTDIR)/libzip/zip_source_open.c \ + $(EXTDIR)/libzip/zip_source_pkware_decode.c \ + $(EXTDIR)/libzip/zip_source_pkware_encode.c \ + $(EXTDIR)/libzip/zip_source_read.c \ + $(EXTDIR)/libzip/zip_source_remove.c \ + $(EXTDIR)/libzip/zip_source_rollback_write.c \ + $(EXTDIR)/libzip/zip_source_seek.c \ + $(EXTDIR)/libzip/zip_source_seek_write.c \ + $(EXTDIR)/libzip/zip_source_stat.c \ + $(EXTDIR)/libzip/zip_source_supports.c \ + $(EXTDIR)/libzip/zip_source_tell.c \ + $(EXTDIR)/libzip/zip_source_tell_write.c \ + $(EXTDIR)/libzip/zip_source_window.c \ + $(EXTDIR)/libzip/zip_source_write.c \ + $(EXTDIR)/libzip/zip_source_zip.c \ + $(EXTDIR)/libzip/zip_source_zip_new.c \ + $(EXTDIR)/libzip/zip_stat.c \ + $(EXTDIR)/libzip/zip_stat_index.c \ + $(EXTDIR)/libzip/zip_stat_init.c \ + $(EXTDIR)/libzip/zip_strerror.c \ + $(EXTDIR)/libzip/zip_string.c \ + $(EXTDIR)/libzip/zip_unchange.c \ + $(EXTDIR)/libzip/zip_unchange_all.c \ + $(EXTDIR)/libzip/zip_unchange_archive.c \ + $(EXTDIR)/libzip/zip_unchange_data.c \ + $(EXTDIR)/libzip/zip_utf-8.c \ + $(EXTDIR)/libzip/zip_err_str.c - ifeq ($(PLATFORM_EXT), win32) - SOURCES_C += \ - $(EXTDIR)/libzip/zip_source_file_win32.c \ - $(EXTDIR)/libzip/zip_source_file_win32_named.c \ - $(EXTDIR)/libzip/zip_source_file_win32_utf16.c \ - $(EXTDIR)/libzip/zip_source_file_win32_utf8.c \ - $(EXTDIR)/libzip/zip_source_file_win32_ansi.c \ - $(EXTDIR)/libzip/zip_random_win32.c - else - SOURCES_C += \ - $(EXTDIR)/libzip/zip_mkstempm.c \ - $(EXTDIR)/libzip/zip_source_file_stdio_named.c \ - $(EXTDIR)/libzip/zip_random_unix.c - endif +ifeq ($(PLATFORM_EXT), win32) + SOURCES_C += \ + $(EXTDIR)/libzip/zip_source_file_win32.c \ + $(EXTDIR)/libzip/zip_source_file_win32_named.c \ + $(EXTDIR)/libzip/zip_source_file_win32_utf16.c \ + $(EXTDIR)/libzip/zip_source_file_win32_utf8.c \ + $(EXTDIR)/libzip/zip_source_file_win32_ansi.c \ + $(EXTDIR)/libzip/zip_random_win32.c +else + SOURCES_C += \ + $(EXTDIR)/libzip/zip_mkstempm.c \ + $(EXTDIR)/libzip/zip_source_file_stdio_named.c \ + $(EXTDIR)/libzip/zip_random_unix.c endif SOURCES_C += $(LIBRETRODIR)/ext/glew/glew.c From 46bb065b7e7449093fc56e86bd1d8b34e87ffc79 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Nov 2022 23:37:37 -0700 Subject: [PATCH 185/715] Build: Use Makefile for libretro. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 778b601445..d38a1ac0db 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -168,13 +168,13 @@ jobs: extra: libretro cc: gcc cxx: g++ - args: ./b.sh --libretro + args: make -C libretro -f Makefile -j2 id: gcc-libretro - os: ubuntu-latest extra: libretro cc: clang cxx: clang++ - args: ./b.sh --libretro + args: make -C libretro -f Makefile -j2 id: clang-libretro - os: macos-latest From 26a66dc37f1d1bdb1ffe741877fa8463fdce8a27 Mon Sep 17 00:00:00 2001 From: bslenul <33353403+bslenul@users.noreply.github.com> Date: Sun, 30 Oct 2022 13:29:53 +0100 Subject: [PATCH 186/715] [Libretro] Update core options to v2 + add a few new ones Updated core options to v2 + added the following options: "Cache Full ISO in RAM", "PSP Model" and "Hardware Tesselation". --- libretro/libretro.cpp | 908 +++++++++++------ libretro/libretro.h | 45 + libretro/libretro_core_options.h | 1359 +++++++++++++++++++++++++ libretro/libretro_core_options_intl.h | 91 ++ libretro/retro_inline.h | 39 + 5 files changed, 2104 insertions(+), 338 deletions(-) create mode 100644 libretro/libretro_core_options.h create mode 100644 libretro/libretro_core_options_intl.h create mode 100644 libretro/retro_inline.h diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 9b4a20bd97..3716f1989e 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -45,6 +45,7 @@ #include "libretro/libretro.h" #include "libretro/LibretroGraphicsContext.h" +#include "libretro/libretro_core_options.h" #if PPSSPP_PLATFORM(ANDROID) #include @@ -81,6 +82,10 @@ #define VSYNC_SWAP_INTERVAL_RUN_SPEED_THRESHOLD 5.0f static bool libretro_supports_bitmasks = false; +static bool libretro_supports_option_categories = false; +static bool show_ip_address_options = true; +static bool show_upnp_port_option = true; +static bool show_detect_frame_rate_option = true; static std::string changeProAdhocServer; namespace Libretro @@ -428,239 +433,72 @@ class PrintfLogger : public LogListener }; static PrintfLogger *printfLogger; -template class RetroOption -{ - public: - RetroOption(const char *id, const char *name, std::initializer_list> list) : id_(id), name_(name), list_(list.begin(), list.end()) {} - RetroOption(const char *id, const char *name, std::initializer_list list) : id_(id), name_(name) { - for (auto option : list) - list_.push_back({ option, (T)list_.size() }); - } - RetroOption(const char *id, const char *name, T first, std::initializer_list list) : id_(id), name_(name) { - for (auto option : list) - list_.push_back({ option, first + (int)list_.size() }); - } - RetroOption(const char *id, const char *name, T first, int count, int step = 1) : id_(id), name_(name) { - for (T i = first; i < first + count; i += step) - list_.push_back({ std::to_string(i), i }); - } - RetroOption(const char *id, const char *name, bool initial) : id_(id), name_(name) { - list_.push_back({ initial ? "enabled" : "disabled", initial }); - list_.push_back({ !initial ? "enabled" : "disabled", !initial }); - } - - retro_variable GetOptions() - { - if (options_.empty()) - { - options_ = name_; - options_.push_back(';'); - for (auto &option : list_) - { - if (option.first == list_.begin()->first) - options_ += std::string(" ") + option.first; - else - options_ += std::string("|") + option.first; - } - } - return { id_, options_.c_str() }; - } - - bool Update(T *dest) - { - retro_variable var{ id_ }; - T val = list_.front().second; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - for (auto option : list_) - { - if (option.first == var.value) - { - val = option.second; - break; - } - } - } - - if (*dest != val) - { - *dest = val; - return true; - } - - return false; - } - - void Show(bool show) - { - struct retro_core_option_display optionDisplay{id_, show}; - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &optionDisplay); - } - - void Set(const char *val) - { - struct retro_variable var{id_, val}; - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, &var); - } - - private: - const char *id_; - const char *name_; - std::string options_; - std::vector> list_; -}; - -#define MAC_INITIALIZER_LIST \ -{ \ - {"0", "0"}, \ - {"1", "1"}, \ - {"2", "2"}, \ - {"3", "3"}, \ - {"4", "4"}, \ - {"5", "5"}, \ - {"6", "6"}, \ - {"7", "7"}, \ - {"8", "8"}, \ - {"9", "9"}, \ - {"a", "a"}, \ - {"b", "b"}, \ - {"c", "c"}, \ - {"d", "d"}, \ - {"e", "e"}, \ - {"f", "f"} \ -} - -static RetroOption ppsspp_cpu_core("ppsspp_cpu_core", "CPU Core", { { "JIT", CPUCore::JIT }, { "IR JIT", CPUCore::IR_JIT }, { "Interpreter", CPUCore::INTERPRETER } }); -static RetroOption ppsspp_locked_cpu_speed("ppsspp_locked_cpu_speed", "Locked CPU Speed", { { "off", 0 }, { "222MHz", 222 }, { "266MHz", 266 }, { "333MHz", 333 } }); -static RetroOption ppsspp_language("ppsspp_language", "Language", { { "Automatic", -1 }, { "English", PSP_SYSTEMPARAM_LANGUAGE_ENGLISH }, { "Japanese", PSP_SYSTEMPARAM_LANGUAGE_JAPANESE }, { "French", PSP_SYSTEMPARAM_LANGUAGE_FRENCH }, { "Spanish", PSP_SYSTEMPARAM_LANGUAGE_SPANISH }, { "German", PSP_SYSTEMPARAM_LANGUAGE_GERMAN }, { "Italian", PSP_SYSTEMPARAM_LANGUAGE_ITALIAN }, { "Dutch", PSP_SYSTEMPARAM_LANGUAGE_DUTCH }, { "Portuguese", PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE }, { "Russian", PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN }, { "Korean", PSP_SYSTEMPARAM_LANGUAGE_KOREAN }, { "Chinese Traditional", PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL }, { "Chinese Simplified", PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED } }); -static RetroOption ppsspp_rendering_mode("ppsspp_rendering_mode", "Rendering Mode", { { "Buffered", FB_BUFFERED_MODE }, { "Skip Buffer Effects", FB_NON_BUFFERED_MODE } }); -static RetroOption ppsspp_auto_frameskip("ppsspp_auto_frameskip", "Auto Frameskip", false); -static RetroOption ppsspp_frameskip("ppsspp_frameskip", "Frameskip", { "Off", "1", "2", "3", "4", "5", "6", "7", "8" }); -static RetroOption ppsspp_frameskiptype("ppsspp_frameskiptype", "Frameskip Type", { {"Number of frames", 0}, {"Percent of FPS", 1} }); -static RetroOption ppsspp_internal_resolution("ppsspp_internal_resolution", "Internal Resolution (Restart)", 1, { "480x272", "960x544", "1440x816", "1920x1088", "2400x1360", "2880x1632", "3360x1904", "3840x2176", "4320x2448", "4800x2720" }); -static RetroOption ppsspp_button_preference("ppsspp_button_preference", "Confirmation Button", { { "Cross", PSP_SYSTEMPARAM_BUTTON_CROSS }, { "Circle", PSP_SYSTEMPARAM_BUTTON_CIRCLE } }); -static RetroOption ppsspp_fast_memory("ppsspp_fast_memory", "Fast Memory (Speedhack)", true); -static RetroOption ppsspp_block_transfer_gpu("ppsspp_block_transfer_gpu", "Block Transfer GPU", true); -static RetroOption ppsspp_inflight_frames("ppsspp_inflight_frames", "Buffered frames (Slower, less lag, restart)", { { "Up to 2", 2 }, { "Up to 1", 1 }, { "No buffer", 0 }, }); -static RetroOption ppsspp_texture_scaling_level("ppsspp_texture_scaling_level", "Texture Scaling Level", { { "Off", 1 }, { "2x", 2 }, { "3x", 3 }, { "4x", 4 }, { "5x", 5 } }); -static RetroOption ppsspp_texture_scaling_type("ppsspp_texture_scaling_type", "Texture Scaling Type", { { "xbrz", TextureScalerCommon::XBRZ }, { "hybrid", TextureScalerCommon::HYBRID }, { "bicubic", TextureScalerCommon::BICUBIC }, { "hybrid_bicubic", TextureScalerCommon::HYBRID_BICUBIC } }); -static RetroOption ppsspp_texture_shader("ppsspp_texture_shader", "Texture Shader (Vulkan only, overrides Texture Scaling Type)", { {"Off", "Off"}, {"2xBRZ", "Tex2xBRZ"}, {"4xBRZ", "Tex4xBRZ"}, {"MMPX", "TexMMPX"} }); -static RetroOption ppsspp_texture_filtering("ppsspp_texture_filtering", "Texture Filtering", { { "Auto", 1 }, { "Nearest", 2 }, { "Linear", 3 }, {"Auto max quality", 4}}); -static RetroOption ppsspp_texture_anisotropic_filtering("ppsspp_texture_anisotropic_filtering", "Anisotropic Filtering", { "off", "2x", "4x", "8x", "16x" }); -static RetroOption ppsspp_lower_resolution_for_effects("ppsspp_lower_resolution_for_effects", "Lower resolution for effects", { {"Off", 0}, {"Safe", 1}, {"Balanced", 2}, {"Aggressive", 3} }); -static RetroOption ppsspp_texture_deposterize("ppsspp_texture_deposterize", "Texture Deposterize", false); -static RetroOption ppsspp_texture_replacement("ppsspp_texture_replacement", "Texture Replacement", false); -static RetroOption ppsspp_gpu_hardware_transform("ppsspp_gpu_hardware_transform", "GPU Hardware T&L", true); -static RetroOption ppsspp_vertex_cache("ppsspp_vertex_cache", "Vertex Cache (Speedhack)", false); -static RetroOption ppsspp_cheats("ppsspp_cheats", "Internal Cheats Support", false); -static RetroOption ppsspp_io_timing_method("ppsspp_io_timing_method", "IO Timing Method", { { "Fast", IOTimingMethods::IOTIMING_FAST }, { "Host", IOTimingMethods::IOTIMING_HOST }, { "Simulate UMD delays", IOTimingMethods::IOTIMING_REALISTIC } }); -static RetroOption ppsspp_frame_duplication("ppsspp_frame_duplication", "Duplicate Frames in 30 Hz Games", false); -static RetroOption ppsspp_detect_vsync_swap_interval("ppsspp_detect_vsync_swap_interval", "Detect Frame Rate Changes (Notify Frontend)", false); -static RetroOption ppsspp_software_skinning("ppsspp_software_skinning", "Software Skinning", true); -static RetroOption ppsspp_ignore_bad_memory_access("ppsspp_ignore_bad_memory_access", "Ignore bad memory accesses", true); -static RetroOption ppsspp_lazy_texture_caching("ppsspp_lazy_texture_caching", "Lazy texture caching (Speedup)", false); -static RetroOption ppsspp_retain_changed_textures("ppsspp_retain_changed_textures", "Retain changed textures (Speedup, mem hog)", false); -static RetroOption ppsspp_force_lag_sync("ppsspp_force_lag_sync", "Force real clock sync (Slower, less lag)", false); -static RetroOption ppsspp_spline_quality("ppsspp_spline_quality", "Spline/Bezier curves quality", { {"Low", 0}, {"Medium", 1}, {"High", 2} }); -static RetroOption ppsspp_enable_wlan("ppsspp_enable_wlan", "Enable Networking/WLAN (beta, may break games)", false); -static RetroOption ppsspp_change_mac_address[] = { - {"ppsspp_change_mac_address01", "MAC address Pt 1: X-:--:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address02", "MAC address Pt 2: -X:--:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address03", "MAC address Pt 3: --:X-:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address04", "MAC address Pt 4: --:-X:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address05", "MAC address Pt 5: --:--:X-:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address06", "MAC address Pt 6: --:--:-X:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address07", "MAC address Pt 7: --:--:--:X-:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address08", "MAC address Pt 8: --:--:--:-X:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address09", "MAC address Pt 9: --:--:--:--:X-:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address10", "MAC address Pt 10: --:--:--:--:-X:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address11", "MAC address Pt 11: --:--:--:--:--:X-", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address12", "MAC address Pt 12: --:--:--:--:--:-X", MAC_INITIALIZER_LIST} -}; -static RetroOption ppsspp_wlan_channel("ppsspp_wlan_channel", "WLAN channel", {{"Auto", 0}, {"1", 1}, {"6", 6}, {"11", 11}} ); -static RetroOption ppsspp_enable_builtin_pro_ad_hoc_server("ppsspp_enable_builtin_pro_ad_hoc_server", "Enable built-in PRO ad hoc server", false); -static RetroOption ppsspp_change_pro_ad_hoc_server_address("ppsspp_change_pro_ad_hoc_server_address", "Change PRO ad hoc server IP address (localhost = multiple instances)", { - {"socom.cc", "socom.cc"}, - {"psp.gameplayer.club", "psp.gameplayer.club"}, - {"myneighborsushicat.com", "myneighborsushicat.com"}, - {"localhost", "localhost"}, - {"IP address", "IP address"} -}); -static RetroOption ppsspp_pro_ad_hoc_ipv4[] = { - {"ppsspp_pro_ad_hoc_server_address01", "PRO ad hoc server IP address Pt 1: x--.---.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address02", "PRO ad hoc server IP address Pt 2: -x-.---.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address03", "PRO ad hoc server IP address Pt 3: --x.---.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address04", "PRO ad hoc server IP address Pt 4: ---.x--.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address05", "PRO ad hoc server IP address Pt 5: ---.-x-.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address06", "PRO ad hoc server IP address Pt 6: ---.--x.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address07", "PRO ad hoc server IP address Pt 7: ---.---.x--.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address08", "PRO ad hoc server IP address Pt 8: ---.---.-x-.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address09", "PRO ad hoc server IP address Pt 9: ---.---.--x.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address10", "PRO ad hoc server IP address Pt 10: ---.---.---.x-- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address11", "PRO ad hoc server IP address Pt 11: ---.---.---.-x- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address12", "PRO ad hoc server IP address Pt 12: ---.---.---.--x ", 0, 10, 1} -}; -static RetroOption ppsspp_enable_upnp("ppsspp_enable_upnp", "Enable UPnP (need a few seconds to detect)", false); -static RetroOption ppsspp_upnp_use_original_port("ppsspp_upnp_use_original_port", "UPnP use original port (enabled = PSP compatibility)", true); -static RetroOption ppsspp_port_offset("ppsspp_port_offset", "Port offset (0 = PSP compatibility)", 0, 65001, 1000); -static RetroOption ppsspp_minimum_timeout("ppsspp_minimum timeout", "Minimum timeout (override in ms, 0 = default))", 0, 5001, 100); -static RetroOption ppsspp_forced_first_connect("ppsspp_forced_first_connect", "Forced first connect (faster connect)", false); - static bool set_variable_visibility(void) { + struct retro_core_option_display option_display; + struct retro_variable var; bool updated = false; - if (ppsspp_change_pro_ad_hoc_server_address.Update(&changeProAdhocServer)) - updated = true; + // Show/hide IP address options + bool show_ip_address_options_prev = show_ip_address_options; + show_ip_address_options = true; - if (changeProAdhocServer == "IP address") + var.key = "ppsspp_change_pro_ad_hoc_server_address"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && strcmp(var.value, "IP address")) + show_ip_address_options = false; + + if (show_ip_address_options != show_ip_address_options_prev) { - g_Config.proAdhocServer = ""; - for (int i = 0;;) + option_display.visible = show_ip_address_options; + for (int i = 0; i < 12; i++) { - int addressPt = 0; - ppsspp_pro_ad_hoc_ipv4[i].Show(true); - ppsspp_pro_ad_hoc_ipv4[i].Update(&addressPt); - g_Config.proAdhocServer += static_cast('0' + addressPt); - - if (++i == 12) - break; - - if (i % 3 == 0) - g_Config.proAdhocServer += '.'; + char key[64] = {0}; + option_display.key = key; + snprintf(key, sizeof(key), "ppsspp_pro_ad_hoc_server_address%02d", i + 1); + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); } - } - else - { - g_Config.proAdhocServer = changeProAdhocServer; - - for (int i = 0; i < 12; ++i) - ppsspp_pro_ad_hoc_ipv4[i].Show(false); - } - - if (ppsspp_enable_upnp.Update(&g_Config.bEnableUPnP)) updated = true; + } - ppsspp_upnp_use_original_port.Show(g_Config.bEnableUPnP); + // Show/hide 'UPnP Use Original Port' option + bool show_upnp_port_option_prev = show_upnp_port_option; + show_upnp_port_option = true; - bool detectVsyncSwapIntervalOptShownLast = detectVsyncSwapIntervalOptShown; - bool autoFrameSkip = false; - int frameSkip = 0; - bool renderDuplicateFrames = false; + var.key = "ppsspp_enable_upnp"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && !strcmp(var.value, "disabled")) + show_upnp_port_option = false; - ppsspp_auto_frameskip.Update(&autoFrameSkip); - ppsspp_frameskip.Update(&frameSkip); - ppsspp_frame_duplication.Update(&renderDuplicateFrames); - - detectVsyncSwapIntervalOptShown = - !autoFrameSkip && - (frameSkip == 0) && - !renderDuplicateFrames; - - if (detectVsyncSwapIntervalOptShown != detectVsyncSwapIntervalOptShownLast) + if (show_upnp_port_option != show_upnp_port_option_prev) { - ppsspp_detect_vsync_swap_interval.Show(detectVsyncSwapIntervalOptShown); + option_display.visible = show_upnp_port_option; + option_display.key = "ppsspp_upnp_use_original_port"; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); + updated = true; + } + + // Show/hide 'Detect Frame Rate Changes' option + bool show_detect_frame_rate_option_prev = show_detect_frame_rate_option; + int frameskip = 0; + bool auto_frameskip = false; + bool dupe_frames = false; + show_detect_frame_rate_option = true; + + var.key = "ppsspp_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && strcmp(var.value, "disabled")) + frameskip = atoi(var.value); + var.key = "ppsspp_auto_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && !strcmp(var.value, "enabled")) + auto_frameskip = true; + var.key = "ppsspp_frame_duplication"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && !strcmp(var.value, "enabled")) + dupe_frames = true; + + show_detect_frame_rate_option = (frameskip == 0) && !auto_frameskip && !dupe_frames; + if (show_detect_frame_rate_option != show_detect_frame_rate_option_prev) + { + option_display.visible = show_detect_frame_rate_option; + option_display.key = "ppsspp_detect_vsync_swap_interval"; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); updated = true; } @@ -671,59 +509,10 @@ void retro_set_environment(retro_environment_t cb) { environ_cb = cb; + libretro_set_core_options(environ_cb, &libretro_supports_option_categories); struct retro_core_options_update_display_callback update_display_cb; update_display_cb.callback = set_variable_visibility; environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK, &update_display_cb); - - std::vector vars; - vars.push_back(ppsspp_internal_resolution.GetOptions()); - vars.push_back(ppsspp_cpu_core.GetOptions()); - vars.push_back(ppsspp_locked_cpu_speed.GetOptions()); - vars.push_back(ppsspp_language.GetOptions()); - vars.push_back(ppsspp_button_preference.GetOptions()); - vars.push_back(ppsspp_rendering_mode.GetOptions()); - vars.push_back(ppsspp_gpu_hardware_transform.GetOptions()); - vars.push_back(ppsspp_texture_anisotropic_filtering.GetOptions()); - vars.push_back(ppsspp_spline_quality.GetOptions()); - vars.push_back(ppsspp_auto_frameskip.GetOptions()); - vars.push_back(ppsspp_frameskip.GetOptions()); - vars.push_back(ppsspp_frameskiptype.GetOptions()); - vars.push_back(ppsspp_frame_duplication.GetOptions()); - vars.push_back(ppsspp_detect_vsync_swap_interval.GetOptions()); - vars.push_back(ppsspp_vertex_cache.GetOptions()); - vars.push_back(ppsspp_fast_memory.GetOptions()); - vars.push_back(ppsspp_block_transfer_gpu.GetOptions()); - vars.push_back(ppsspp_inflight_frames.GetOptions()); - vars.push_back(ppsspp_software_skinning.GetOptions()); - vars.push_back(ppsspp_lazy_texture_caching.GetOptions()); - vars.push_back(ppsspp_retain_changed_textures.GetOptions()); - vars.push_back(ppsspp_force_lag_sync.GetOptions()); - vars.push_back(ppsspp_lower_resolution_for_effects.GetOptions()); - vars.push_back(ppsspp_texture_scaling_level.GetOptions()); - vars.push_back(ppsspp_texture_scaling_type.GetOptions()); - vars.push_back(ppsspp_texture_shader.GetOptions()); - vars.push_back(ppsspp_texture_filtering.GetOptions()); - vars.push_back(ppsspp_texture_deposterize.GetOptions()); - vars.push_back(ppsspp_texture_replacement.GetOptions()); - vars.push_back(ppsspp_io_timing_method.GetOptions()); - vars.push_back(ppsspp_ignore_bad_memory_access.GetOptions()); - vars.push_back(ppsspp_cheats.GetOptions()); - vars.push_back(ppsspp_enable_wlan.GetOptions()); - for (int i = 0; i < 12; ++i) - vars.push_back(ppsspp_change_mac_address[i].GetOptions()); - vars.push_back(ppsspp_wlan_channel.GetOptions()); - vars.push_back(ppsspp_enable_builtin_pro_ad_hoc_server.GetOptions()); - vars.push_back(ppsspp_change_pro_ad_hoc_server_address.GetOptions()); - for (int i = 0; i < 12; ++i) - vars.push_back(ppsspp_pro_ad_hoc_ipv4[i].GetOptions()); - vars.push_back(ppsspp_enable_upnp.GetOptions()); - vars.push_back(ppsspp_upnp_use_original_port.GetOptions()); - vars.push_back(ppsspp_port_offset.GetOptions()); - vars.push_back(ppsspp_minimum_timeout.GetOptions()); - vars.push_back(ppsspp_forced_first_connect.GetOptions()); - vars.push_back({}); - - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars.data()); } static int get_language_auto(void) @@ -803,46 +592,522 @@ static void check_variables(CoreParameter &coreParam) && !updated) return; - ppsspp_button_preference.Update(&g_Config.iButtonPreference); - ppsspp_fast_memory.Update(&g_Config.bFastMemory); - ppsspp_vertex_cache.Update(&g_Config.bVertexCache); - ppsspp_gpu_hardware_transform.Update(&g_Config.bHardwareTransform); - ppsspp_frameskip.Update(&g_Config.iFrameSkip); - ppsspp_frameskiptype.Update(&g_Config.iFrameSkipType); - ppsspp_auto_frameskip.Update(&g_Config.bAutoFrameSkip); - ppsspp_block_transfer_gpu.Update(&g_Config.bBlockTransferGPU); - ppsspp_texture_filtering.Update(&g_Config.iTexFiltering); - ppsspp_texture_anisotropic_filtering.Update(&g_Config.iAnisotropyLevel); - ppsspp_texture_deposterize.Update(&g_Config.bTexDeposterize); - ppsspp_texture_replacement.Update(&g_Config.bReplaceTextures); - ppsspp_cheats.Update(&g_Config.bEnableCheats); - ppsspp_locked_cpu_speed.Update(&g_Config.iLockedCPUSpeed); - ppsspp_rendering_mode.Update(&g_Config.iRenderingMode); - ppsspp_cpu_core.Update((CPUCore *)&g_Config.iCpuCore); - ppsspp_io_timing_method.Update((IOTimingMethods *)&g_Config.iIOTimingMethod); - ppsspp_lower_resolution_for_effects.Update(&g_Config.iBloomHack); - ppsspp_frame_duplication.Update(&g_Config.bRenderDuplicateFrames); - ppsspp_detect_vsync_swap_interval.Update(&detectVsyncSwapInterval); - ppsspp_software_skinning.Update(&g_Config.bSoftwareSkinning); - ppsspp_ignore_bad_memory_access.Update(&g_Config.bIgnoreBadMemAccess); - ppsspp_lazy_texture_caching.Update(&g_Config.bTextureBackoffCache); - ppsspp_retain_changed_textures.Update(&g_Config.bTextureSecondaryCache); - ppsspp_force_lag_sync.Update(&g_Config.bForceLagSync); - ppsspp_spline_quality.Update(&g_Config.iSplineBezierQuality); - ppsspp_inflight_frames.Update(&g_Config.iInflightFrames); - const bool do_scaling_type_update = ppsspp_texture_scaling_type.Update(&g_Config.iTexScalingType); - const bool do_scaling_level_update = ppsspp_texture_scaling_level.Update(&g_Config.iTexScalingLevel); - const bool do_texture_shader_update = ppsspp_texture_shader.Update(&g_Config.sTextureShaderName); + struct retro_variable var = {0}; + std::string sTextureShaderName_prev; + int iInternalResolution_prev; + int iTexScalingType_prev; + int iTexScalingLevel_prev; - g_Config.bTexHardwareScaling = "Off" != g_Config.sTextureShaderName; + var.key = "ppsspp_language"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Automatic")) + g_Config.iLanguage = -1; + else if (!strcmp(var.value, "English")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; + else if (!strcmp(var.value, "Japanese")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_JAPANESE; + else if (!strcmp(var.value, "French")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_FRENCH; + else if (!strcmp(var.value, "Spanish")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_SPANISH; + else if (!strcmp(var.value, "German")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_GERMAN; + else if (!strcmp(var.value, "Italian")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ITALIAN; + else if (!strcmp(var.value, "Dutch")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_DUTCH; + else if (!strcmp(var.value, "Portuguese")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE; + else if (!strcmp(var.value, "Russian")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN; + else if (!strcmp(var.value, "Korean")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_KOREAN; + else if (!strcmp(var.value, "Chinese Traditional")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL; + else if (!strcmp(var.value, "Chinese Simplified")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED; + } - if (gpu && (do_scaling_type_update || do_scaling_level_update || do_texture_shader_update)) + var.key = "ppsspp_cpu_core"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "JIT")) + g_Config.iCpuCore = (int)CPUCore::JIT; + else if (!strcmp(var.value, "IR JIT")) + g_Config.iCpuCore = (int)CPUCore::IR_JIT; + else if (!strcmp(var.value, "Interpreter")) + g_Config.iCpuCore = (int)CPUCore::INTERPRETER; + } + + var.key = "ppsspp_fast_memory"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bFastMemory = false; + else + g_Config.bFastMemory = true; + } + + var.key = "ppsspp_ignore_bad_memory_access"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bIgnoreBadMemAccess = false; + else + g_Config.bIgnoreBadMemAccess = true; + } + + var.key = "ppsspp_io_timing_method"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Fast")) + g_Config.iIOTimingMethod = IOTIMING_FAST; + else if (!strcmp(var.value, "Host")) + g_Config.iIOTimingMethod = IOTIMING_HOST; + else if (!strcmp(var.value, "Simulate UMD delays")) + g_Config.iIOTimingMethod = IOTIMING_REALISTIC; + } + + var.key = "ppsspp_force_lag_sync"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bForceLagSync = false; + else + g_Config.bForceLagSync = true; + } + + var.key = "ppsspp_locked_cpu_speed"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iLockedCPUSpeed = atoi(var.value); + + var.key = "ppsspp_cache_iso"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bCacheFullIsoInRam = false; + else + g_Config.bCacheFullIsoInRam = true; + } + + var.key = "ppsspp_cheats"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableCheats = false; + else + g_Config.bEnableCheats = true; + } + + var.key = "ppsspp_psp_model"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "psp_1000")) + g_Config.iPSPModel = PSP_MODEL_FAT; + else if (!strcmp(var.value, "psp_2000_3000")) + g_Config.iPSPModel = PSP_MODEL_SLIM; + } + + var.key = "ppsspp_button_preference"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Cross")) + g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS; + else if (!strcmp(var.value, "Circle")) + g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CIRCLE; + } + + var.key = "ppsspp_internal_resolution"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iInternalResolution_prev = g_Config.iInternalResolution; + + if (!strcmp(var.value, "480x272")) + g_Config.iInternalResolution = 1; + else if (!strcmp(var.value, "960x544")) + g_Config.iInternalResolution = 2; + else if (!strcmp(var.value, "1440x816")) + g_Config.iInternalResolution = 3; + else if (!strcmp(var.value, "1920x1088")) + g_Config.iInternalResolution = 4; + else if (!strcmp(var.value, "2400x1360")) + g_Config.iInternalResolution = 5; + else if (!strcmp(var.value, "2880x1632")) + g_Config.iInternalResolution = 6; + else if (!strcmp(var.value, "3360x1904")) + g_Config.iInternalResolution = 7; + else if (!strcmp(var.value, "3840x2176")) + g_Config.iInternalResolution = 8; + else if (!strcmp(var.value, "4320x2448")) + g_Config.iInternalResolution = 9; + else if (!strcmp(var.value, "4800x2720")) + g_Config.iInternalResolution = 10; + } + + var.key = "ppsspp_rendering_mode"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Buffered")) + g_Config.iRenderingMode = FB_BUFFERED_MODE; + else if (!strcmp(var.value, "Skip Buffer Effects")) + g_Config.iRenderingMode = FB_NON_BUFFERED_MODE; + } + + var.key = "ppsspp_block_transfer_gpu"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bBlockTransferGPU = false; + else + g_Config.bBlockTransferGPU = true; + } + + var.key = "ppsspp_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iFrameSkip = atoi(var.value); + + var.key = "ppsspp_frameskiptype"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Number of frames")) + g_Config.iFrameSkipType = 0; + else if (!strcmp(var.value, "Percent of FPS")) + g_Config.iFrameSkipType = 1; + } + + var.key = "ppsspp_auto_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bAutoFrameSkip = false; + else + g_Config.bAutoFrameSkip = true; + } + + var.key = "ppsspp_frame_duplication"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bRenderDuplicateFrames = false; + else + g_Config.bRenderDuplicateFrames = true; + } + + var.key = "ppsspp_detect_vsync_swap_interval"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + detectVsyncSwapInterval = false; + else + detectVsyncSwapInterval = true; + } + + var.key = "ppsspp_inflight_frames"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "No buffer")) + g_Config.iInflightFrames = 0; + else if (!strcmp(var.value, "Up to 1")) + g_Config.iInflightFrames = 1; + else if (!strcmp(var.value, "Up to 2")) + g_Config.iInflightFrames = 2; + } + + var.key = "ppsspp_gpu_hardware_transform"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bHardwareTransform = false; + else + g_Config.bHardwareTransform = true; + } + + var.key = "ppsspp_software_skinning"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bSoftwareSkinning = false; + else + g_Config.bSoftwareSkinning = true; + } + + var.key = "ppsspp_vertex_cache"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bVertexCache = false; + else + g_Config.bVertexCache = true; + } + + var.key = "ppsspp_lazy_texture_caching"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bTextureBackoffCache = false; + else + g_Config.bTextureBackoffCache = true; + } + + var.key = "ppsspp_retain_changed_textures"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bTextureSecondaryCache = false; + else + g_Config.bTextureSecondaryCache = true; + } + + var.key = "ppsspp_spline_quality"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Low")) + g_Config.iSplineBezierQuality = 0; + else if (!strcmp(var.value, "Medium")) + g_Config.iSplineBezierQuality = 1; + else if (!strcmp(var.value, "High")) + g_Config.iSplineBezierQuality = 2; + } + + var.key = "ppsspp_hardware_tesselation"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bHardwareTessellation = false; + else + g_Config.bHardwareTessellation = true; + } + + var.key = "ppsspp_lower_resolution_for_effects"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.iBloomHack = 0; + else if (!strcmp(var.value, "Safe")) + g_Config.iBloomHack = 1; + else if (!strcmp(var.value, "Balanced")) + g_Config.iBloomHack = 2; + else if (!strcmp(var.value, "Aggressive")) + g_Config.iBloomHack = 3; + } + + var.key = "ppsspp_texture_scaling_type"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iTexScalingType_prev = g_Config.iTexScalingType; + + if (!strcmp(var.value, "xbrz")) + g_Config.iTexScalingType = TextureScalerCommon::XBRZ; + else if (!strcmp(var.value, "hybrid")) + g_Config.iTexScalingType = TextureScalerCommon::HYBRID; + else if (!strcmp(var.value, "bicubic")) + g_Config.iTexScalingType = TextureScalerCommon::BICUBIC; + else if (!strcmp(var.value, "hybrid_bicubic")) + g_Config.iTexScalingType = TextureScalerCommon::HYBRID_BICUBIC; + } + + var.key = "ppsspp_texture_scaling_level"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iTexScalingLevel_prev = g_Config.iTexScalingLevel; + + if (!strcmp(var.value, "disabled")) + g_Config.iTexScalingLevel = 1; + else if (!strcmp(var.value, "2x")) + g_Config.iTexScalingLevel = 2; + else if (!strcmp(var.value, "3x")) + g_Config.iTexScalingLevel = 3; + else if (!strcmp(var.value, "4x")) + g_Config.iTexScalingLevel = 4; + else if (!strcmp(var.value, "5x")) + g_Config.iTexScalingLevel = 5; + } + + var.key = "ppsspp_texture_deposterize"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bTexDeposterize = false; + else + g_Config.bTexDeposterize = true; + } + + var.key = "ppsspp_texture_shader"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + sTextureShaderName_prev = g_Config.sTextureShaderName; + + if (!strcmp(var.value, "disabled")) + g_Config.sTextureShaderName = "Off"; + else if (!strcmp(var.value, "2xBRZ")) + g_Config.sTextureShaderName = "Tex2xBRZ"; + else if (!strcmp(var.value, "4xBRZ")) + g_Config.sTextureShaderName = "Tex4xBRZ"; + else if (!strcmp(var.value, "MMPX")) + g_Config.sTextureShaderName = "TexMMPX"; + } + + var.key = "ppsspp_texture_anisotropic_filtering"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.iAnisotropyLevel = 0; + else if (!strcmp(var.value, "2x")) + g_Config.iAnisotropyLevel = 1; + else if (!strcmp(var.value, "4x")) + g_Config.iAnisotropyLevel = 2; + else if (!strcmp(var.value, "8x")) + g_Config.iAnisotropyLevel = 3; + else if (!strcmp(var.value, "16x")) + g_Config.iAnisotropyLevel = 4; + } + + var.key = "ppsspp_texture_filtering"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Auto")) + g_Config.iTexFiltering = 1; + else if (!strcmp(var.value, "Nearest")) + g_Config.iTexFiltering = 2; + else if (!strcmp(var.value, "Linear")) + g_Config.iTexFiltering = 3; + else if (!strcmp(var.value, "Auto max quality")) + g_Config.iTexFiltering = 4; + } + + var.key = "ppsspp_texture_replacement"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bReplaceTextures = false; + else + g_Config.bReplaceTextures = true; + } + + var.key = "ppsspp_enable_wlan"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableWlan = false; + else + g_Config.bEnableWlan = true; + } + + var.key = "ppsspp_wlan_channel"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iWlanAdhocChannel = atoi(var.value); + + var.key = "ppsspp_enable_builtin_pro_ad_hoc_server"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableAdhocServer = false; + else + g_Config.bEnableAdhocServer = true; + } + + var.key = "ppsspp_change_pro_ad_hoc_server_address"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + changeProAdhocServer = var.value; + + var.key = "ppsspp_enable_upnp"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableUPnP = false; + else + g_Config.bEnableUPnP = true; + } + + var.key = "ppsspp_upnp_use_original_port"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bUPnPUseOriginalPort = false; + else + g_Config.bUPnPUseOriginalPort = true; + } + + var.key = "ppsspp_port_offset"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iPortOffset = atoi(var.value); + + var.key = "ppsspp_minimum_timeout"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iMinTimeout = atoi(var.value); + + var.key = "ppsspp_forced_first_connect"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bForcedFirstConnect = false; + else + g_Config.bForcedFirstConnect = true; + } + + std::string ppsspp_change_mac_address[12]; + int ppsspp_pro_ad_hoc_ipv4[12]; + char key[64] = {0}; + var.key = key; + g_Config.sMACAddress = ""; + g_Config.proAdhocServer = ""; + for (int i = 0; i < 12; i++) + { + snprintf(key, sizeof(key), "ppsspp_change_mac_address%02d", i + 1); + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + ppsspp_change_mac_address[i] = var.value; + + if (i && i % 2 == 0) + g_Config.sMACAddress += ":"; + + g_Config.sMACAddress += ppsspp_change_mac_address[i]; + } + + snprintf(key, sizeof(key), "ppsspp_pro_ad_hoc_server_address%02d", i + 1); + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + ppsspp_pro_ad_hoc_ipv4[i] = atoi(var.value); + } + + if (g_Config.sMACAddress == "00:00:00:00:00:00") + { + g_Config.sMACAddress = CreateRandMAC(); + + for (int i = 0; i < 12; i++) + { + snprintf(key, sizeof(key), "ppsspp_change_mac_address%02d", i + 1); + std::string digit = {g_Config.sMACAddress[i + i / 2]}; + var.value = digit.c_str(); + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, &var); + } + } + + if (changeProAdhocServer == "IP address") + { + g_Config.proAdhocServer = ""; + for (int i = 0; i < 12; i++) + { + if (i && i % 3 == 0) + g_Config.proAdhocServer += '.'; + + int addressPt = ppsspp_pro_ad_hoc_ipv4[i]; + g_Config.proAdhocServer += static_cast('0' + addressPt); + } + } + else + g_Config.proAdhocServer = changeProAdhocServer; + + g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off"; + + if (gpu && (g_Config.iTexScalingType != iTexScalingType_prev + || g_Config.iTexScalingLevel != iTexScalingLevel_prev + || g_Config.sTextureShaderName != sTextureShaderName_prev)) { gpu->ClearCacheNextFrame(); gpu->Resized(); } - ppsspp_language.Update(&g_Config.iLanguage); if (g_Config.iLanguage < 0) g_Config.iLanguage = get_language_auto(); @@ -864,7 +1129,7 @@ static void check_variables(CoreParameter &coreParam) updateAvInfo = true; } - if (ppsspp_internal_resolution.Update(&g_Config.iInternalResolution) && !PSP_IsInited()) + if (g_Config.iInternalResolution != iInternalResolution_prev && !PSP_IsInited()) { coreParam.pixelWidth = coreParam.renderWidth = g_Config.iInternalResolution * 480; coreParam.pixelHeight = coreParam.renderHeight = g_Config.iInternalResolution * 272; @@ -889,40 +1154,6 @@ static void check_variables(CoreParameter &coreParam) bool isFastForwarding = environ_cb(RETRO_ENVIRONMENT_GET_FASTFORWARDING, &isFastForwarding); coreParam.fastForward = isFastForwarding; - ppsspp_enable_wlan.Update(&g_Config.bEnableWlan); - ppsspp_wlan_channel.Update(&g_Config.iWlanAdhocChannel); - ppsspp_enable_builtin_pro_ad_hoc_server.Update(&g_Config.bEnableAdhocServer); - - ppsspp_upnp_use_original_port.Update(&g_Config.bUPnPUseOriginalPort); - ppsspp_port_offset.Update(&g_Config.iPortOffset); - ppsspp_minimum_timeout.Update(&g_Config.iMinTimeout); - ppsspp_forced_first_connect.Update(&g_Config.bForcedFirstConnect); - - g_Config.sMACAddress = ""; - for (int i = 0; i < 12;) - { - std::string digit; - ppsspp_change_mac_address[i].Update(&digit); - g_Config.sMACAddress += digit; - - if (++i == 12) - break; - - if (i % 2 == 0) - g_Config.sMACAddress += ":"; - } - - if (g_Config.sMACAddress == "00:00:00:00:00:00") - { - g_Config.sMACAddress = CreateRandMAC(); - - for (int i = 0; i < 12; ++i) - { - std::string digit = {g_Config.sMACAddress[i + i / 2]}; - ppsspp_change_mac_address[i].Set(digit.c_str()); - } - } - set_variable_visibility(); } @@ -1018,6 +1249,7 @@ void retro_deinit(void) host = nullptr; libretro_supports_bitmasks = false; + libretro_supports_option_categories = false; VsyncSwapIntervalReset(); AudioBufferDeinit(); diff --git a/libretro/libretro.h b/libretro/libretro.h index 2f17483701..bb114aed35 100644 --- a/libretro/libretro.h +++ b/libretro/libretro.h @@ -283,6 +283,12 @@ enum retro_language RETRO_LANGUAGE_HEBREW = 21, RETRO_LANGUAGE_ASTURIAN = 22, RETRO_LANGUAGE_FINNISH = 23, + RETRO_LANGUAGE_INDONESIAN = 24, + RETRO_LANGUAGE_SWEDISH = 25, + RETRO_LANGUAGE_UKRAINIAN = 26, + RETRO_LANGUAGE_CZECH = 27, + RETRO_LANGUAGE_CATALAN_VALENCIA = 28, + RETRO_LANGUAGE_CATALAN = 29, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -1753,6 +1759,12 @@ enum retro_mod * the frontend is attempting to call retro_run(). */ +#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* int * -- + * Tells the core about the context the frontend is asking for savestate. + * (see enum retro_savestate_context) + */ + /* VFS functionality */ /* File paths: @@ -2990,6 +3002,35 @@ enum retro_pixel_format RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX }; +enum retro_savestate_context +{ + /* Standard savestate written to disk. */ + RETRO_SAVESTATE_CONTEXT_NORMAL = 0, + + /* Savestate where you are guaranteed that the same instance will load the save state. + * You can store internal pointers to code or data. + * It's still a full serialization and deserialization, and could be loaded or saved at any time. + * It won't be written to disk or sent over the network. + */ + RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1, + + /* Savestate where you are guaranteed that the same emulator binary will load that savestate. + * You can skip anything that would slow down saving or loading state but you can not store internal pointers. + * It won't be written to disk or sent over the network. + * Example: "Second Instance" runahead + */ + RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY = 2, + + /* Savestate used within a rollback netplay feature. + * You should skip anything that would unnecessarily increase bandwidth usage. + * It won't be written to disk but it will be sent over the network. + */ + RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY = 3, + + /* Ensure sizeof() == sizeof(int). */ + RETRO_SAVESTATE_CONTEXT_UNKNOWN = INT_MAX +}; + struct retro_message { const char *msg; /* Message to be displayed. */ @@ -3461,6 +3502,10 @@ struct retro_core_option_definition const char *default_value; }; +#ifdef __PS3__ +#undef local +#endif + struct retro_core_options_intl { /* Pointer to an array of retro_core_option_definition structs diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h new file mode 100644 index 0000000000..78cab61d7d --- /dev/null +++ b/libretro/libretro_core_options.h @@ -0,0 +1,1359 @@ +#ifndef LIBRETRO_CORE_OPTIONS_H__ +#define LIBRETRO_CORE_OPTIONS_H__ + +#include +#include + +#include "libretro.h" +#include "retro_inline.h" + +#ifndef HAVE_NO_LANGEXTRA +#include "libretro_core_options_intl.h" +#endif + +#define BOOL_OPTIONS \ +{ \ + { "disabled", NULL }, \ + { "enabled", NULL }, \ + { NULL, NULL }, \ +} + +#define MAC_ADDRESS_OPTIONS \ +{ \ + { "0", NULL }, \ + { "1", NULL }, \ + { "2", NULL }, \ + { "3", NULL }, \ + { "4", NULL }, \ + { "5", NULL }, \ + { "6", NULL }, \ + { "7", NULL }, \ + { "8", NULL }, \ + { "9", NULL }, \ + { "a", NULL }, \ + { "b", NULL }, \ + { "c", NULL }, \ + { "d", NULL }, \ + { "e", NULL }, \ + { "f", NULL }, \ + { NULL, NULL }, \ +} + +#define IP_ADDRESS_OPTIONS \ +{ \ + { "0", NULL }, \ + { "1", NULL }, \ + { "2", NULL }, \ + { "3", NULL }, \ + { "4", NULL }, \ + { "5", NULL }, \ + { "6", NULL }, \ + { "7", NULL }, \ + { "8", NULL }, \ + { "9", NULL }, \ + { NULL, NULL }, \ +} + +/* + ******************************** + * VERSION: 2.0 + ******************************** + * + * - 2.0: Add support for core options v2 interface + * - 1.3: Move translations to libretro_core_options_intl.h + * - libretro_core_options_intl.h includes BOM and utf-8 + * fix for MSVC 2010-2013 + * - Added HAVE_NO_LANGEXTRA flag to disable translations + * on platforms/compilers without BOM support + * - 1.2: Use core options v1 interface when + * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1 + * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1) + * - 1.1: Support generation of core options v0 retro_core_option_value + * arrays containing options with a single value + * - 1.0: First commit +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ******************************** + * Core Option Definitions + ******************************** +*/ + +/* RETRO_LANGUAGE_ENGLISH */ + +/* Default language: + * - All other languages must include the same keys and values + * - Will be used as a fallback in the event that frontend language + * is not available + * - Will be used as a fallback for any missing entries in + * frontend language definition */ + +struct retro_core_option_v2_category option_cats_us[] = { + { + "system", + "System", + "Configure system options." + }, + { + "video", + "Video", + "Configure video options." + }, + { + "network", + "Network", + "Configure network options." + }, + { NULL, NULL, NULL }, +}; + +struct retro_core_option_v2_definition option_defs_us[] = { + { + "ppsspp_language", + "Language", + NULL, + "Choose language, 'Automatic' will use the frontend language.", + NULL, + "system", + { + { "Automatic", NULL }, + { "English", NULL }, + { "Japanese", NULL }, + { "French", NULL }, + { "Spanish", NULL }, + { "German", NULL }, + { "Italian", NULL }, + { "Dutch", NULL }, + { "Portuguese", NULL }, + { "Russian", NULL }, + { "Korean", NULL }, + { "Chinese Traditional", NULL }, + { "Chinese Simplified", NULL }, + { NULL, NULL }, + }, + "Automatic" + }, + { + "ppsspp_cpu_core", + "CPU Core", + NULL, + NULL, + NULL, + "system", + { + { "JIT", "Dynarec (JIT)" }, + { "IR JIT", "IR Interpreter" }, + { "Interpreter", NULL }, + { NULL, NULL }, + }, + "JIT" + }, + { + "ppsspp_fast_memory", + "Fast Memory", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_ignore_bad_memory_access", + "Ignore Bad Memory Accesses", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_io_timing_method", + "I/O Timing Method", + NULL, + NULL, + NULL, + "system", + { + { "Fast", NULL }, + { "Host", NULL }, + { "Simulate UMD delays", NULL }, + { NULL, NULL }, + }, + "Fast" + }, + { + "ppsspp_force_lag_sync", + "Force Real Clock Sync (Slower, less lag)", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_locked_cpu_speed", + "Locked CPU Speed", + NULL, + NULL, + NULL, + "system", + { + { "disabled", NULL }, + { "222MHz", NULL }, + { "266MHz", NULL }, + { "333MHz", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_cache_iso", + "Cache Full ISO in RAM", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_cheats", + "Internal Cheats Support", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_psp_model", + "PSP Model", + NULL, + NULL, + NULL, + "system", + { + { "psp_1000", "PSP-1000" }, + { "psp_2000_3000", "PSP-2000/3000" }, + { NULL, NULL }, + }, + "psp_2000_3000" + }, + { + "ppsspp_button_preference", + "Confirmation Button", + NULL, + NULL, + NULL, + "system", + { + { "Cross", NULL }, + { "Circle", NULL }, + { NULL, NULL }, + }, + "Cross" + }, + { + "ppsspp_internal_resolution", + "Internal Resolution (Restart)", + NULL, + NULL, + NULL, + "video", + { + { "480x272", NULL }, + { "960x544", NULL }, + { "1440x816", NULL }, + { "1920x1088", NULL }, + { "2400x1360", NULL }, + { "2880x1632", NULL }, + { "3360x1904", NULL }, + { "3840x2176", NULL }, + { "4320x2448", NULL }, + { "4800x2720", NULL }, + { NULL, NULL }, + }, + "480x272" + }, + { + "ppsspp_rendering_mode", + "Rendering Mode", + NULL, + "'Skip Buffer Effects' is faster, but nothing may draw in some games.", + NULL, + "video", + { + { "Buffered", NULL }, + { "Skip Buffer Effects", NULL }, + { NULL, NULL }, + }, + "Buffered" + }, + { + "ppsspp_block_transfer_gpu", + "Block Transfer GPU", + NULL, + "Some games require this to be enabled for correct graphics.", + NULL, + "video", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_frameskip", + "Frameskip", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "1", NULL }, + { "2", NULL }, + { "3", NULL }, + { "4", NULL }, + { "5", NULL }, + { "6", NULL }, + { "7", NULL }, + { "8", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_frameskiptype", + "Frameskip Type", + NULL, + NULL, + NULL, + "video", + { + { "Number of frames", NULL }, + { "Percent of FPS", NULL }, + { NULL, NULL }, + }, + "Number of frames" + }, + { + "ppsspp_auto_frameskip", + "Auto Frameskip", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_frame_duplication", + "Duplicate Frames in 30 Hz Games", + NULL, + "Can make framerate smoother in games that run at lower framerates.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_detect_vsync_swap_interval", + "Detect Frame Rate Changes (Notify frontend)", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_inflight_frames", + "Buffered Frames (GL/Vulkan only, slower, less lag, restart)", + NULL, + NULL, + NULL, + "video", + { + { "No buffer", NULL }, + { "Up to 1", NULL }, + { "Up to 2", NULL }, + { NULL, NULL }, + }, + "Up to 2" + }, + { + "ppsspp_gpu_hardware_transform", + "Hardware Transform", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_software_skinning", + "Software Skinning", + NULL, + "Combine skinned model draws on the CPU, faster in most games.", + NULL, + "video", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_vertex_cache", + "Vertex Cache", + NULL, + "Faster, but may cause temporary flicker.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_lazy_texture_caching", + "Lazy Texture Caching (Speedup)", + NULL, + "Faster, but can cause text problems in a few games.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_retain_changed_textures", + "Retain Changed Textures (Speedup, mem hog)", + NULL, + "Makes many games slower, but some games a lot faster.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_spline_quality", + "Spline/Bezier Curves Quality", + NULL, + "Only used by some games, controls smoothness of curves.", + NULL, + "video", + { + { "Low", NULL }, + { "Medium", NULL }, + { "High", NULL }, + { NULL, NULL }, + }, + "High" + }, + { + "ppsspp_hardware_tesselation", + "Hardware Tesselation", + NULL, + "Uses hardware to make curves.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_lower_resolution_for_effects", + "Lower Resolution for Effects", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "Safe", NULL }, + { "Balanced", NULL }, + { "Aggressive", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_texture_scaling_type", + "Texture Scaling Type", + NULL, + NULL, + NULL, + "video", + { + { "xbrz", "xBRZ" }, + { "hybrid", "Hybrid" }, + { "bicubic", "Bicubic" }, + { "hybrid_bicubic", "Hybrid + Bicubic" }, + { NULL, NULL }, + }, + "xbrz" + }, + { + "ppsspp_texture_scaling_level", + "Texture Scaling Level", + NULL, + "CPU heavy, some scaling may be delayed to avoid stutter.", + NULL, + "video", + { + { "disabled", NULL }, + { "2x", NULL }, + { "3x", NULL }, + { "4x", NULL }, + { "5x", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_texture_deposterize", + "Texture Deposterize", + NULL, + "Fixes visual banding glitches in upscaled textures.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_texture_shader", + "Texture Shader (Vulkan only, overrides 'Texture Scaling Type')", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "2xBRZ", "Tex2xBRZ" }, + { "4xBRZ", "Tex4xBRZ" }, + { "MMPX", "TexMMPX" }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_texture_anisotropic_filtering", + "Anisotropic Filtering", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "2x", NULL }, + { "4x", NULL }, + { "8x", NULL }, + { "16x", NULL }, + { NULL, NULL }, + }, + "16x" + }, + { + "ppsspp_texture_filtering", + "Texture Filtering", + NULL, + NULL, + NULL, + "video", + { + { "Auto", NULL }, + { "Nearest", NULL }, + { "Linear", NULL }, + { "Auto max quality", NULL }, + { NULL, NULL }, + }, + "Auto" + }, + { + "ppsspp_texture_replacement", + "Texture Replacement", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_enable_wlan", + "Enable Networking/WLAN (Beta, may break games)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_change_mac_address01", + "MAC Address Pt 1: X-:--:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address02", + "MAC Address Pt 2: -X:--:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address03", + "MAC Address Pt 3: --:X-:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address04", + "MAC Address Pt 4: --:-X:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address05", + "MAC Address Pt 5: --:--:X-:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address06", + "MAC Address Pt 6: --:--:-X:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address07", + "MAC Address Pt 7: --:--:--:X-:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address08", + "MAC Address Pt 8: --:--:--:-X:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address09", + "MAC Address Pt 9: --:--:--:--:X-:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address10", + "MAC Address Pt 10: --:--:--:--:-X:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address11", + "MAC Address Pt 11: --:--:--:--:--:X-", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address12", + "MAC Address Pt 12: --:--:--:--:--:-X", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_wlan_channel", + "WLAN Channel", + NULL, + NULL, + NULL, + "network", + { + { "Auto", NULL }, + { "1", NULL }, + { "6", NULL }, + { "11", NULL }, + { NULL, NULL }, + }, + "Auto" + }, + { + "ppsspp_enable_builtin_pro_ad_hoc_server", + "Enable Built-in PRO Ad Hoc Server", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_change_pro_ad_hoc_server_address", + "Change PRO Ad Hoc Server IP Address ('localhost' = multiple instances)", + NULL, + NULL, + NULL, + "network", + { + { "socom.cc", NULL }, + { "psp.gameplayer.club", NULL }, + { "myneighborsushicat.com", NULL }, + { "localhost", NULL }, + { "IP address", NULL }, + { NULL, NULL }, + }, + "socom.cc" + }, + { + "ppsspp_pro_ad_hoc_server_address01", + "PRO Ad Hoc Server IP Address Pt 1: x--.---.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address02", + "PRO Ad Hoc Server IP Address Pt 2: -x-.---.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address03", + "PRO Ad Hoc Server IP Address Pt 3: --x.---.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address04", + "PRO Ad Hoc Server IP Address Pt 4: ---.x--.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address05", + "PRO Ad Hoc Server IP Address Pt 5: ---.-x-.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address06", + "PRO Ad Hoc Server IP Address Pt 6: ---.--x.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address07", + "PRO Ad Hoc Server IP Address Pt 7: ---.---.x--.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address08", + "PRO Ad Hoc Server IP Address Pt 8: ---.---.-x-.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address09", + "PRO Ad Hoc Server IP Address Pt 9: ---.---.--x.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address10", + "PRO Ad Hoc Server IP Address Pt 10: ---.---.---.x--", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address11", + "PRO Ad Hoc Server IP Address Pt 11: ---.---.---.-x-", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address12", + "PRO Ad Hoc Server IP Address Pt 12: ---.---.---.--x", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_enable_upnp", + "Enable UPnP (Need a few seconds to detect)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_upnp_use_original_port", + "UPnP Use Original Port ('ON' = PSP compatibility)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_port_offset", + "Port Offset ('0' = PSP compatibility)", + NULL, + NULL, + NULL, + "network", + { + { "0", NULL }, + { "1000", NULL }, + { "2000", NULL }, + { "3000", NULL }, + { "4000", NULL }, + { "5000", NULL }, + { "6000", NULL }, + { "7000", NULL }, + { "8000", NULL }, + { "9000", NULL }, + { "10000", NULL }, + { "11000", NULL }, + { "12000", NULL }, + { "13000", NULL }, + { "14000", NULL }, + { "15000", NULL }, + { "16000", NULL }, + { "17000", NULL }, + { "18000", NULL }, + { "19000", NULL }, + { "20000", NULL }, + { "31000", NULL }, + { "32000", NULL }, + { "33000", NULL }, + { "34000", NULL }, + { "35000", NULL }, + { "36000", NULL }, + { "37000", NULL }, + { "38000", NULL }, + { "39000", NULL }, + { "40000", NULL }, + { "41000", NULL }, + { "42000", NULL }, + { "43000", NULL }, + { "44000", NULL }, + { "45000", NULL }, + { "46000", NULL }, + { "47000", NULL }, + { "48000", NULL }, + { "49000", NULL }, + { "50000", NULL }, + { "51000", NULL }, + { "52000", NULL }, + { "53000", NULL }, + { "54000", NULL }, + { "55000", NULL }, + { "56000", NULL }, + { "57000", NULL }, + { "58000", NULL }, + { "59000", NULL }, + { "60000", NULL }, + { "61000", NULL }, + { "62000", NULL }, + { "63000", NULL }, + { "64000", NULL }, + { "65000", NULL }, + { NULL, NULL }, + }, + "0" + }, + { + "ppsspp_minimum_timeout", + "Minimum Timeout (Override in ms, '0' = default)", + NULL, + NULL, + NULL, + "network", + { + { "0", NULL }, + { "100", NULL }, + { "200", NULL }, + { "300", NULL }, + { "400", NULL }, + { "500", NULL }, + { "600", NULL }, + { "700", NULL }, + { "800", NULL }, + { "900", NULL }, + { "1000", NULL }, + { "1100", NULL }, + { "1200", NULL }, + { "1300", NULL }, + { "1400", NULL }, + { "1500", NULL }, + { "1600", NULL }, + { "1700", NULL }, + { "1800", NULL }, + { "1900", NULL }, + { "2000", NULL }, + { "3100", NULL }, + { "3200", NULL }, + { "3300", NULL }, + { "3400", NULL }, + { "3500", NULL }, + { "3600", NULL }, + { "3700", NULL }, + { "3800", NULL }, + { "3900", NULL }, + { "4000", NULL }, + { "4100", NULL }, + { "4200", NULL }, + { "4300", NULL }, + { "4400", NULL }, + { "4500", NULL }, + { "4600", NULL }, + { "4700", NULL }, + { "4800", NULL }, + { "4900", NULL }, + { "5000", NULL }, + { NULL, NULL }, + }, + "0" + }, + { + "ppsspp_forced_first_connect", + "Forced First Connect (Faster connect)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, +}; + +struct retro_core_options_v2 options_us = { + option_cats_us, + option_defs_us +}; + +/* + ******************************** + * Language Mapping + ******************************** +*/ + +#ifndef HAVE_NO_LANGEXTRA +struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = { + &options_us, /* RETRO_LANGUAGE_ENGLISH */ + NULL, /* RETRO_LANGUAGE_JAPANESE */ + NULL, /* RETRO_LANGUAGE_FRENCH */ + NULL, /* RETRO_LANGUAGE_SPANISH */ + NULL, /* RETRO_LANGUAGE_GERMAN */ + NULL, /* RETRO_LANGUAGE_ITALIAN */ + NULL, /* RETRO_LANGUAGE_DUTCH */ + NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */ + NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */ + NULL, /* RETRO_LANGUAGE_RUSSIAN */ + NULL, /* RETRO_LANGUAGE_KOREAN */ + NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */ + NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */ + NULL, /* RETRO_LANGUAGE_ESPERANTO */ + NULL, /* RETRO_LANGUAGE_POLISH */ + NULL, /* RETRO_LANGUAGE_VIETNAMESE */ + NULL, /* RETRO_LANGUAGE_ARABIC */ + NULL, /* RETRO_LANGUAGE_GREEK */ + NULL, /* RETRO_LANGUAGE_TURKISH */ + NULL, /* RETRO_LANGUAGE_SLOVAK */ + NULL, /* RETRO_LANGUAGE_PERSIAN */ + NULL, /* RETRO_LANGUAGE_HEBREW */ + NULL, /* RETRO_LANGUAGE_ASTURIAN */ + NULL, /* RETRO_LANGUAGE_FINNISH */ + NULL, /* RETRO_LANGUAGE_INDONESIAN */ + NULL, /* RETRO_LANGUAGE_SWEDISH */ + NULL, /* RETRO_LANGUAGE_UKRAINIAN */ + NULL, /* RETRO_LANGUAGE_CZECH */ +}; +#endif + +/* + ******************************** + * Functions + ******************************** +*/ + +/* Handles configuration/setting of core options. + * Should be called as early as possible - ideally inside + * retro_set_environment(), and no later than retro_load_game() + * > We place the function body in the header to avoid the + * necessity of adding more .c files (i.e. want this to + * be as painless as possible for core devs) + */ + +static INLINE void libretro_set_core_options(retro_environment_t environ_cb, + bool *categories_supported) +{ + unsigned version = 0; +#ifndef HAVE_NO_LANGEXTRA + unsigned language = 0; +#endif + + if (!environ_cb || !categories_supported) + return; + + *categories_supported = false; + + if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version)) + version = 0; + + if (version >= 2) + { +#ifndef HAVE_NO_LANGEXTRA + struct retro_core_options_v2_intl core_options_intl; + + core_options_intl.us = &options_us; + core_options_intl.local = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && + (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH)) + core_options_intl.local = options_intl[language]; + + *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL, + &core_options_intl); +#else + *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2, + &options_us); +#endif + } + else + { + size_t i, j; + size_t option_index = 0; + size_t num_options = 0; + struct retro_core_option_definition + *option_v1_defs_us = NULL; +#ifndef HAVE_NO_LANGEXTRA + size_t num_options_intl = 0; + struct retro_core_option_v2_definition + *option_defs_intl = NULL; + struct retro_core_option_definition + *option_v1_defs_intl = NULL; + struct retro_core_options_intl + core_options_v1_intl; +#endif + struct retro_variable *variables = NULL; + char **values_buf = NULL; + + /* Determine total number of options */ + while (true) + { + if (option_defs_us[num_options].key) + num_options++; + else + break; + } + + if (version >= 1) + { + /* Allocate US array */ + option_v1_defs_us = (struct retro_core_option_definition *) + calloc(num_options + 1, sizeof(struct retro_core_option_definition)); + + /* Copy parameters from option_defs_us array */ + for (i = 0; i < num_options; i++) + { + struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i]; + struct retro_core_option_value *option_values = option_def_us->values; + struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i]; + struct retro_core_option_value *option_v1_values = option_v1_def_us->values; + + option_v1_def_us->key = option_def_us->key; + option_v1_def_us->desc = option_def_us->desc; + option_v1_def_us->info = option_def_us->info; + option_v1_def_us->default_value = option_def_us->default_value; + + /* Values must be copied individually... */ + while (option_values->value) + { + option_v1_values->value = option_values->value; + option_v1_values->label = option_values->label; + + option_values++; + option_v1_values++; + } + } + +#ifndef HAVE_NO_LANGEXTRA + if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && + (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) && + options_intl[language]) + option_defs_intl = options_intl[language]->definitions; + + if (option_defs_intl) + { + /* Determine number of intl options */ + while (true) + { + if (option_defs_intl[num_options_intl].key) + num_options_intl++; + else + break; + } + + /* Allocate intl array */ + option_v1_defs_intl = (struct retro_core_option_definition *) + calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition)); + + /* Copy parameters from option_defs_intl array */ + for (i = 0; i < num_options_intl; i++) + { + struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i]; + struct retro_core_option_value *option_values = option_def_intl->values; + struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i]; + struct retro_core_option_value *option_v1_values = option_v1_def_intl->values; + + option_v1_def_intl->key = option_def_intl->key; + option_v1_def_intl->desc = option_def_intl->desc; + option_v1_def_intl->info = option_def_intl->info; + option_v1_def_intl->default_value = option_def_intl->default_value; + + /* Values must be copied individually... */ + while (option_values->value) + { + option_v1_values->value = option_values->value; + option_v1_values->label = option_values->label; + + option_values++; + option_v1_values++; + } + } + } + + core_options_v1_intl.us = option_v1_defs_us; + core_options_v1_intl.local = option_v1_defs_intl; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl); +#else + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us); +#endif + } + else + { + /* Allocate arrays */ + variables = (struct retro_variable *)calloc(num_options + 1, + sizeof(struct retro_variable)); + values_buf = (char **)calloc(num_options, sizeof(char *)); + + if (!variables || !values_buf) + goto error; + + /* Copy parameters from option_defs_us array */ + for (i = 0; i < num_options; i++) + { + const char *key = option_defs_us[i].key; + const char *desc = option_defs_us[i].desc; + const char *default_value = option_defs_us[i].default_value; + struct retro_core_option_value *values = option_defs_us[i].values; + size_t buf_len = 3; + size_t default_index = 0; + + values_buf[i] = NULL; + + if (desc) + { + size_t num_values = 0; + + /* Determine number of values */ + while (true) + { + if (values[num_values].value) + { + /* Check if this is the default value */ + if (default_value) + if (strcmp(values[num_values].value, default_value) == 0) + default_index = num_values; + + buf_len += strlen(values[num_values].value); + num_values++; + } + else + break; + } + + /* Build values string */ + if (num_values > 0) + { + buf_len += num_values - 1; + buf_len += strlen(desc); + + values_buf[i] = (char *)calloc(buf_len, sizeof(char)); + if (!values_buf[i]) + goto error; + + strcpy(values_buf[i], desc); + strcat(values_buf[i], "; "); + + /* Default value goes first */ + strcat(values_buf[i], values[default_index].value); + + /* Add remaining values */ + for (j = 0; j < num_values; j++) + { + if (j != default_index) + { + strcat(values_buf[i], "|"); + strcat(values_buf[i], values[j].value); + } + } + } + } + + variables[option_index].key = key; + variables[option_index].value = values_buf[i]; + option_index++; + } + + /* Set variables */ + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables); + } + +error: + /* Clean up */ + + if (option_v1_defs_us) + { + free(option_v1_defs_us); + option_v1_defs_us = NULL; + } + +#ifndef HAVE_NO_LANGEXTRA + if (option_v1_defs_intl) + { + free(option_v1_defs_intl); + option_v1_defs_intl = NULL; + } +#endif + + if (values_buf) + { + for (i = 0; i < num_options; i++) + { + if (values_buf[i]) + { + free(values_buf[i]); + values_buf[i] = NULL; + } + } + + free(values_buf); + values_buf = NULL; + } + + if (variables) + { + free(variables); + variables = NULL; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro/libretro_core_options_intl.h b/libretro/libretro_core_options_intl.h new file mode 100644 index 0000000000..b2649b6b5e --- /dev/null +++ b/libretro/libretro_core_options_intl.h @@ -0,0 +1,91 @@ +#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__ +#define LIBRETRO_CORE_OPTIONS_INTL_H__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900) +/* https://support.microsoft.com/en-us/kb/980263 */ +#pragma execution_character_set("utf-8") +#pragma warning(disable:4566) +#endif + +#include "libretro.h" + +/* + ******************************** + * VERSION: 2.0 + ******************************** + * + * - 2.0: Add support for core options v2 interface + * - 1.3: Move translations to libretro_core_options_intl.h + * - libretro_core_options_intl.h includes BOM and utf-8 + * fix for MSVC 2010-2013 + * - Added HAVE_NO_LANGEXTRA flag to disable translations + * on platforms/compilers without BOM support + * - 1.2: Use core options v1 interface when + * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1 + * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1) + * - 1.1: Support generation of core options v0 retro_core_option_value + * arrays containing options with a single value + * - 1.0: First commit +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ******************************** + * Core Option Definitions + ******************************** +*/ + +/* RETRO_LANGUAGE_JAPANESE */ + +/* RETRO_LANGUAGE_FRENCH */ + +/* RETRO_LANGUAGE_SPANISH */ + +/* RETRO_LANGUAGE_GERMAN */ + +/* RETRO_LANGUAGE_ITALIAN */ + +/* RETRO_LANGUAGE_DUTCH */ + +/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */ + +/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */ + +/* RETRO_LANGUAGE_RUSSIAN */ + +/* RETRO_LANGUAGE_KOREAN */ + +/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */ + +/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */ + +/* RETRO_LANGUAGE_ESPERANTO */ + +/* RETRO_LANGUAGE_POLISH */ + +/* RETRO_LANGUAGE_VIETNAMESE */ + +/* RETRO_LANGUAGE_ARABIC */ + +/* RETRO_LANGUAGE_GREEK */ + +/* RETRO_LANGUAGE_TURKISH */ + +/* RETRO_LANGUAGE_SLOVAK */ + +/* RETRO_LANGUAGE_PERSIAN */ + +/* RETRO_LANGUAGE_HEBREW */ + +/* RETRO_LANGUAGE_ASTURIAN */ + +/* RETRO_LANGUAGE_FINNISH */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro/retro_inline.h b/libretro/retro_inline.h new file mode 100644 index 0000000000..b27d6dd6d4 --- /dev/null +++ b/libretro/retro_inline.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_inline.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_INLINE_H +#define __LIBRETRO_SDK_INLINE_H + +#ifndef INLINE + +#if defined(_WIN32) || defined(__INTEL_COMPILER) +#define INLINE __inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L +#define INLINE inline +#elif defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE +#endif + +#endif +#endif From c6b83dd9d8687fa012899ec355e19509115ad4dd Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 3 Nov 2022 20:00:30 +0100 Subject: [PATCH 187/715] OpenXR - Enable camera movement and stereo in flatscreen mode --- Common/VR/PPSSPPVR.cpp | 33 +++++++++++++++++---------------- Common/VR/PPSSPPVR.h | 2 ++ Common/VR/VRRenderer.cpp | 8 +++++++- GPU/GLES/ShaderManagerGLES.cpp | 3 ++- UI/GameSettingsScreen.cpp | 3 +-- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 0c496d55e0..ead9690173 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -453,22 +453,7 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { return identity; } -void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { - - // Update project matrices - float* dst[] = {leftEye, rightEye}; - VRMatrix enums[] = {VR_PROJECTION_MATRIX_LEFT_EYE, VR_PROJECTION_MATRIX_RIGHT_EYE}; - for (int index = 0; index < 2; index++) { - ovrMatrix4f hmdProjection = VR_GetMatrix(enums[index]); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - if ((hmdProjection.M[i][j] > 0) != (projMatrix[i * 4 + j] > 0)) { - hmdProjection.M[i][j] *= -1.0f; - } - } - } - memcpy(dst[index], hmdProjection.M, 16 * sizeof(float)); - } +void UpdateVRParams(float* projMatrix) { // Set mirroring of axes if (!VR_GetConfig(VR_CONFIG_MIRROR_UPDATED)) { @@ -506,6 +491,22 @@ void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { VR_SetConfig(VR_CONFIG_6DOF_SCALE, (int)(scale * 1000000)); } +void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { + float* dst[] = {leftEye, rightEye}; + VRMatrix enums[] = {VR_PROJECTION_MATRIX_LEFT_EYE, VR_PROJECTION_MATRIX_RIGHT_EYE}; + for (int index = 0; index < 2; index++) { + ovrMatrix4f hmdProjection = VR_GetMatrix(enums[index]); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if ((hmdProjection.M[i][j] > 0) != (projMatrix[i * 4 + j] > 0)) { + hmdProjection.M[i][j] *= -1.0f; + } + } + } + memcpy(dst[index], hmdProjection.M, 16 * sizeof(float)); + } +} + void UpdateVRView(float* leftEye, float* rightEye) { float* dst[] = {leftEye, rightEye}; VRMatrix enums[] = {VR_VIEW_MATRIX_LEFT_EYE, VR_VIEW_MATRIX_RIGHT_EYE}; diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 440f27859d..e926b9957a 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -42,6 +42,7 @@ int GetVRPassesCount(); bool IsMultiviewSupported(); bool IsFlatVRScene(); bool Is2DVRObject(float* projMatrix, bool ortho); +void UpdateVRParams(float* projMatrix); void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye); void UpdateVRView(float* leftEye, float* rightEye); @@ -70,6 +71,7 @@ inline int GetVRPassesCount() { return 1; } inline bool IsMultiviewSupported() { return false; } inline bool IsFlatVRScene() { return true; } inline bool Is2DVRObject(float* projMatrix, bool ortho) { return false; } +inline void UpdateVRParams(float* projMatrix) {} inline void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) {} inline void UpdateVRView(float* leftEye, float* rightEye) {} diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 3d4cce0222..c91d2f045f 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -306,7 +306,13 @@ bool VR_InitFrame( engine_t* engine ) { float nearPlane = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f; vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, nearPlane, 0.0f ); } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + bool flatScreen = false; XrPosef invView = invViewTransform[0]; + int vrMode = vrConfig[VR_CONFIG_MODE]; + if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { + invView = XrPosef_Identity(); + flatScreen = true; + } // get axis mirroring configuration float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1 : 1; @@ -333,7 +339,7 @@ bool VR_InitFrame( engine_t* engine ) { vrMatrix[matrix] = ovrMatrix4f_CreateFromQuaternion(&invView.orientation); float scale = (float)VR_GetConfig(VR_CONFIG_6DOF_SCALE) * 0.000001f; - if (vrConfig[VR_CONFIG_6DOF_ENABLED]) { + if (!flatScreen && vrConfig[VR_CONFIG_6DOF_ENABLED]) { vrMatrix[matrix].M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index e4a6350de1..118c8c3fed 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -411,6 +411,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } else { UpdateVRProjection(gstate.projMatrix, leftEyeMatrix.m, rightEyeMatrix.m); } + UpdateVRParams(gstate.projMatrix); FlipProjMatrix(leftEyeMatrix, useBufferedRendering); FlipProjMatrix(rightEyeMatrix, useBufferedRendering); @@ -542,7 +543,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu float rightEyeView[16]; ConvertMatrix4x3To4x4Transposed(leftEyeView, gstate.viewMatrix); ConvertMatrix4x3To4x4Transposed(rightEyeView, gstate.viewMatrix); - if (!flatScreen && !is2D) { + if (!is2D) { UpdateVRView(leftEyeView, rightEyeView); } render_->SetUniformM4x4Stereo("u_view", &u_view, leftEyeView, rightEyeView); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 6b68d9c866..78a162f3b3 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1161,8 +1161,7 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Virtual reality"))); CheckBox *vr6DoF = vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("6DoF movement"))); vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); - CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); - vrStereo->SetEnabledPtr(&g_Config.bEnableVR); + vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); From 1d452a2e0148a74a405ba388b33aba6b3d167fd9 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 3 Nov 2022 21:33:46 +0100 Subject: [PATCH 188/715] OpenXR - Add an option to disable 72Hz update --- Common/VR/PPSSPPVR.cpp | 3 +-- Core/Config.cpp | 1 + Core/Config.h | 1 + UI/GameSettingsScreen.cpp | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index ead9690173..5a81f71eec 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -111,8 +111,6 @@ void InitVROnAndroid(void* vm, void* activity, int version, const char* name) { java.AppVersion = version; strcpy(java.AppName, name); VR_Init(java, useVulkan); - - __DisplaySetFramerate(72); } #endif @@ -376,6 +374,7 @@ bool StartVRRender() { } // Set customizations + __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance * 1000); VR_SetConfig(VR_CONFIG_CAMERA_HEIGHT, g_Config.fCameraHeight * 1000); diff --git a/Core/Config.cpp b/Core/Config.cpp index f62a4baaae..03a5bb26ee 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1208,6 +1208,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VREnable", &g_Config.bEnableVR, true), ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, true), ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false), + ConfigSetting("VRbForce72Hz", &g_Config.bForce72Hz, true), ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f), ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f), ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), diff --git a/Core/Config.h b/Core/Config.h index a494cf4c61..4e15c3bb4b 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -463,6 +463,7 @@ public: bool bEnableVR; bool bEnable6DoF; bool bEnableStereo; + bool bForce72Hz; float fCameraDistance; float fCameraHeight; float fCameraSide; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 78a162f3b3..b6c3e06a8e 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1162,6 +1162,7 @@ void GameSettingsScreen::CreateViews() { CheckBox *vr6DoF = vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("6DoF movement"))); vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); + vrSettings->Add(new CheckBox(&g_Config.bForce72Hz, vr->T("Force 72Hz update"))); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust", "Camera distance adjust"), 1.0f, screenManager(), "")); From f8d29e0d19799ca78d8f14432956c46919e54fb7 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 4 Nov 2022 13:52:32 +0100 Subject: [PATCH 189/715] OpenXR - Fix ifdef ANDROID --- Common/VR/PPSSPPVR.cpp | 6 ++--- Common/VR/PPSSPPVR.h | 4 ++-- Common/VR/VRBase.cpp | 51 +++++++++++++++++++++--------------------- Common/VR/VRBase.h | 10 +-------- 4 files changed, 30 insertions(+), 41 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index ead9690173..26dd5a3137 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -102,15 +102,13 @@ bool IsVRBuild() { } #if PPSSPP_PLATFORM(ANDROID) -void InitVROnAndroid(void* vm, void* activity, int version, const char* name) { +void InitVROnAndroid(void* vm, void* activity, int version, char* name) { bool useVulkan = (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN; ovrJava java; java.Vm = (JavaVM*)vm; java.ActivityObject = (jobject)activity; - java.AppVersion = version; - strcpy(java.AppName, name); - VR_Init(java, useVulkan); + VR_Init(&java, useVulkan, name, version); __DisplaySetFramerate(72); } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index e926b9957a..153dce24af 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -21,7 +21,7 @@ enum VRCompatFlag { // VR app flow integration bool IsVRBuild(); -void InitVROnAndroid(void* vm, void* activity, int version, const char* name); +void InitVROnAndroid(void* vm, void* activity, int version, char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); @@ -50,7 +50,7 @@ void UpdateVRView(float* leftEye, float* rightEye); // VR app flow integration inline bool IsVRBuild() { return false; } -inline void InitVROnAndroid(void* vm, void* activity, int version, const char* name) {} +inline void InitVROnAndroid(void* vm, void* activity, int version, char* name) {} inline void EnterVR(bool firstTime, void* vulkanContext) {} inline void GetVRResolutionPerEye(int* width, int* height) {} inline void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {} diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index e0301bb6e6..7b8ad509ec 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -5,11 +5,10 @@ #include #include -#if defined(ANDROID) && defined(OPENXR) +#if defined(OPENXR) #include -#ifdef OPENXR_PLATFORM_PICO enum ConfigsSetEXT { UNREAL_VERSION = 0, TRACKING_ORIGIN, @@ -37,29 +36,30 @@ PFN_xrSetConfigPICO pfnXrSetConfigPICO = nullptr; PFN_xrSetEngineVersionPico pfnXrSetEngineVersionPico = nullptr; PFN_xrStartCVControllerThreadPico pfnXrStartCVControllerThreadPico = nullptr; PFN_xrStopCVControllerThreadPico pfnXrStopCVControllerThreadPico = nullptr; -#endif static engine_t vr_engine; int vr_initialized = 0; -void VR_Init( ovrJava java, bool useVulkan ) { +void VR_Init( void* system, bool useVulkan, char* name, int version ) { if (vr_initialized) return; ovrApp_Clear(&vr_engine.appState); +#ifdef ANDROID PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR; - xrGetInstanceProcAddr( - XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR); + xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR); if (xrInitializeLoaderKHR != NULL) { - XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid; - memset(&loaderInitializeInfoAndroid, 0, sizeof(loaderInitializeInfoAndroid)); - loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR; - loaderInitializeInfoAndroid.next = NULL; - loaderInitializeInfoAndroid.applicationVM = java.Vm; - loaderInitializeInfoAndroid.applicationContext = java.ActivityObject; - xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid); + ovrJava* java = (ovrJava*)system; + XrLoaderInitInfoAndroidKHR loaderInitializeInfo; + memset(&loaderInitializeInfo, 0, sizeof(loaderInitializeInfo)); + loaderInitializeInfo.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR; + loaderInitializeInfo.next = NULL; + loaderInitializeInfo.applicationVM = java->Vm; + loaderInitializeInfo.applicationContext = java->ActivityObject; + xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfo); } +#endif std::vector extensions; if (useVulkan) { @@ -84,23 +84,16 @@ void VR_Init( ovrJava java, bool useVulkan ) { // Create the OpenXR instance. XrApplicationInfo appInfo; memset(&appInfo, 0, sizeof(appInfo)); - strcpy(appInfo.applicationName, java.AppName); - strcpy(appInfo.engineName, java.AppName); - appInfo.applicationVersion = java.AppVersion; - appInfo.engineVersion = java.AppVersion; + strcpy(appInfo.applicationName, name); + strcpy(appInfo.engineName, name); + appInfo.applicationVersion = version; + appInfo.engineVersion = version; appInfo.apiVersion = XR_CURRENT_API_VERSION; XrInstanceCreateInfo instanceCreateInfo; memset(&instanceCreateInfo, 0, sizeof(instanceCreateInfo)); instanceCreateInfo.type = XR_TYPE_INSTANCE_CREATE_INFO; -#ifdef OPENXR_PLATFORM_PICO - XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; - instanceCreateInfoAndroid.applicationVM = java.Vm; - instanceCreateInfoAndroid.applicationActivity = java.ActivityObject; - instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; -#else instanceCreateInfo.next = NULL; -#endif instanceCreateInfo.createFlags = 0; instanceCreateInfo.applicationInfo = appInfo; instanceCreateInfo.enabledApiLayerCount = 0; @@ -108,6 +101,14 @@ void VR_Init( ovrJava java, bool useVulkan ) { instanceCreateInfo.enabledExtensionCount = extensions.size(); instanceCreateInfo.enabledExtensionNames = extensions.data(); +#if defined(ANDROID) && defined(OPENXR_PLATFORM_PICO) + ovrJava* java = (ovrJava*)system; + XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; + instanceCreateInfoAndroid.applicationVM = java->Vm; + instanceCreateInfoAndroid.applicationActivity = java->ActivityObject; + instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; +#endif + XrResult initResult; OXR(initResult = xrCreateInstance(&instanceCreateInfo, &vr_engine.appState.Instance)); if (initResult != XR_SUCCESS) { @@ -173,8 +174,6 @@ void VR_Init( ovrJava java, bool useVulkan ) { vr_engine.appState.MainThreadTid = gettid(); vr_engine.appState.SystemId = systemId; - - vr_engine.java = java; vr_engine.useVulkan = useVulkan; vr_initialized = 1; } diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 40c377ec84..efff9acc39 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -171,26 +171,18 @@ typedef struct { JavaVM* Vm; jobject ActivityObject; JNIEnv* Env; - char AppName[64]; - int AppVersion; } ovrJava; #endif typedef struct { uint64_t frameIndex; ovrApp appState; -#ifdef ANDROID - ovrJava java; -#endif float predictedDisplayTime; bool useVulkan; XrGraphicsBindingVulkanKHR graphicsBindingVulkan; } engine_t; -#ifdef ANDROID -void VR_Init( ovrJava java, bool useVulkan ); -#endif - +void VR_Init( void* system, bool useVulkan, char* name, int version ); void VR_Destroy( engine_t* engine ); void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ); void VR_LeaveVR( engine_t* engine ); From aafa17fa7332f051c8bd37743a8ee7f6ae963446 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 4 Nov 2022 14:22:42 +0100 Subject: [PATCH 190/715] OpenXR - Introduce platform flags --- Common/VR/PPSSPPVR.cpp | 13 ++++- Common/VR/VRBase.cpp | 109 +++++++++++++++++++++--------------- Common/VR/VRBase.h | 20 ++++--- Common/VR/VRFramebuffer.cpp | 20 ++----- Common/VR/VRInput.cpp | 32 ++++++----- Common/VR/VRRenderer.cpp | 16 +++--- 6 files changed, 120 insertions(+), 90 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 26dd5a3137..8bdcbf6688 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -103,12 +103,21 @@ bool IsVRBuild() { #if PPSSPP_PLATFORM(ANDROID) void InitVROnAndroid(void* vm, void* activity, int version, char* name) { - bool useVulkan = (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN; + + //TODO:get the flags in runtime +#ifdef OPENXR_PLATFORM_PICO + VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO, true); + VR_SetPlatformFLag(VR_PLATFORM_PICO_INIT, true); +#elifdef OPENXR_PLATFORM_QUEST + VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true); + VR_SetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT, true); +#endif + VR_SetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN, (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN); ovrJava java; java.Vm = (JavaVM*)vm; java.ActivityObject = (jobject)activity; - VR_Init(&java, useVulkan, name, version); + VR_Init(&java, name, version); __DisplaySetFramerate(72); } diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 7b8ad509ec..129d42880f 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -37,10 +37,11 @@ PFN_xrSetEngineVersionPico pfnXrSetEngineVersionPico = nullptr; PFN_xrStartCVControllerThreadPico pfnXrStartCVControllerThreadPico = nullptr; PFN_xrStopCVControllerThreadPico pfnXrStopCVControllerThreadPico = nullptr; +static bool vr_platform[VR_PLATFORM_MAX]; static engine_t vr_engine; int vr_initialized = 0; -void VR_Init( void* system, bool useVulkan, char* name, int version ) { +void VR_Init( void* system, char* name, int version ) { if (vr_initialized) return; @@ -62,24 +63,24 @@ void VR_Init( void* system, bool useVulkan, char* name, int version ) { #endif std::vector extensions; - if (useVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { extensions.push_back(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME); } else { extensions.push_back(XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME); } extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME); -#ifdef OPENXR_HAS_PERFORMANCE_EXTENSION - extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); - extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); -#endif -#ifdef OPENXR_PLATFORM_PICO - extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); - extensions.push_back("XR_PICO_android_controller_function_ext_enable"); - extensions.push_back("XR_PICO_view_state_ext_enable"); - extensions.push_back("XR_PICO_frame_end_info_ext"); - extensions.push_back("XR_PICO_configs_ext"); - extensions.push_back("XR_PICO_reset_sensor"); -#endif + if (VR_GetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT)) { + extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); + extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); + } + if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); + extensions.push_back("XR_PICO_android_controller_function_ext_enable"); + extensions.push_back("XR_PICO_view_state_ext_enable"); + extensions.push_back("XR_PICO_frame_end_info_ext"); + extensions.push_back("XR_PICO_configs_ext"); + extensions.push_back("XR_PICO_reset_sensor"); + } // Create the OpenXR instance. XrApplicationInfo appInfo; @@ -101,12 +102,14 @@ void VR_Init( void* system, bool useVulkan, char* name, int version ) { instanceCreateInfo.enabledExtensionCount = extensions.size(); instanceCreateInfo.enabledExtensionNames = extensions.data(); -#if defined(ANDROID) && defined(OPENXR_PLATFORM_PICO) - ovrJava* java = (ovrJava*)system; - XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; - instanceCreateInfoAndroid.applicationVM = java->Vm; - instanceCreateInfoAndroid.applicationActivity = java->ActivityObject; - instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; +#ifdef ANDROID + if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + ovrJava* java = (ovrJava*)system; + XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; + instanceCreateInfoAndroid.applicationVM = java->Vm; + instanceCreateInfoAndroid.applicationActivity = java->ActivityObject; + instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; + } #endif XrResult initResult; @@ -116,14 +119,14 @@ void VR_Init( void* system, bool useVulkan, char* name, int version ) { exit(1); } -#ifdef OPENXR_PLATFORM_PICO - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrSetEngineVersionPico", (PFN_xrVoidFunction*)(&pfnXrSetEngineVersionPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStartCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStartCVControllerThreadPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStopCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStopCVControllerThreadPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance,"xrSetConfigPICO", (PFN_xrVoidFunction*)(&pfnXrSetConfigPICO)); - if (pfnXrSetEngineVersionPico != nullptr) pfnXrSetEngineVersionPico(vr_engine.appState.Instance, "2.8.0.1"); - if (pfnXrStartCVControllerThreadPico != nullptr) pfnXrStartCVControllerThreadPico(vr_engine.appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); -#endif + if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrSetEngineVersionPico", (PFN_xrVoidFunction*)(&pfnXrSetEngineVersionPico)); + xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStartCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStartCVControllerThreadPico)); + xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStopCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStopCVControllerThreadPico)); + xrGetInstanceProcAddr(vr_engine.appState.Instance,"xrSetConfigPICO", (PFN_xrVoidFunction*)(&pfnXrSetConfigPICO)); + if (pfnXrSetEngineVersionPico != nullptr) pfnXrSetEngineVersionPico(vr_engine.appState.Instance, "2.8.0.1"); + if (pfnXrStartCVControllerThreadPico != nullptr) pfnXrStartCVControllerThreadPico(vr_engine.appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); + } XrInstanceProperties instanceInfo; instanceInfo.type = XR_TYPE_INSTANCE_PROPERTIES; @@ -150,7 +153,7 @@ void VR_Init( void* system, bool useVulkan, char* name, int version ) { } // Get the graphics requirements. - if (useVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { PFN_xrGetVulkanGraphicsRequirementsKHR pfnGetVulkanGraphicsRequirementsKHR = NULL; OXR(xrGetInstanceProcAddr( vr_engine.appState.Instance, @@ -174,17 +177,17 @@ void VR_Init( void* system, bool useVulkan, char* name, int version ) { vr_engine.appState.MainThreadTid = gettid(); vr_engine.appState.SystemId = systemId; - vr_engine.useVulkan = useVulkan; vr_initialized = 1; } void VR_Destroy( engine_t* engine ) { if (engine == &vr_engine) { -#ifdef OPENXR_PLATFORM_PICO - if (pfnXrStopCVControllerThreadPico != nullptr) { - pfnXrStopCVControllerThreadPico(engine->appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); + if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + if (pfnXrStopCVControllerThreadPico != nullptr) { + pfnXrStopCVControllerThreadPico(engine->appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); + } } -#endif + xrDestroyInstance(engine->appState.Instance); ovrApp_Destroy(&engine->appState); } @@ -199,17 +202,25 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu // Create the OpenXR Session. XrSessionCreateInfo sessionCreateInfo = {}; - XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingAndroidGLES = {}; +#ifdef ANDROID + XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingGL = {}; +#else + XrGraphicsBindingOpenGLWin32KHR graphicsBindingGL = {}; +#endif memset(&sessionCreateInfo, 0, sizeof(sessionCreateInfo)); - if (engine->useVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { sessionCreateInfo.next = graphicsBindingVulkan; } else { - graphicsBindingAndroidGLES.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; - graphicsBindingAndroidGLES.next = NULL; - graphicsBindingAndroidGLES.display = eglGetCurrentDisplay(); - graphicsBindingAndroidGLES.config = eglGetCurrentSurface(EGL_DRAW); - graphicsBindingAndroidGLES.context = eglGetCurrentContext(); - sessionCreateInfo.next = &graphicsBindingAndroidGLES; +#ifdef ANDROID + graphicsBindingGL.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; + graphicsBindingGL.next = NULL; + graphicsBindingGL.display = eglGetCurrentDisplay(); + graphicsBindingGL.config = eglGetCurrentSurface(EGL_DRAW); + graphicsBindingGL.context = eglGetCurrentContext(); +#else + //TODO:PCVR definition +#endif + sessionCreateInfo.next = &graphicsBindingGL; } sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO; sessionCreateInfo.createFlags = 0; @@ -221,9 +232,9 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu ALOGE("Failed to create XR session: %d.", initResult); exit(1); } -#ifdef OPENXR_PLATFORM_PICO - pfnXrSetConfigPICO(engine->appState.Session, TRACKING_ORIGIN, "1"); -#endif + if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + pfnXrSetConfigPICO(engine->appState.Session, TRACKING_ORIGIN, "1"); + } // Create a space to the first path XrReferenceSpaceCreateInfo spaceCreateInfo = {}; @@ -251,4 +262,12 @@ engine_t* VR_GetEngine( void ) { return &vr_engine; } +bool VR_GetPlatformFLag(VRPlatformFlag flag) { + return vr_platform[flag]; +} + +void VR_SetPlatformFLag(VRPlatformFlag flag, bool value) { + vr_platform[flag] = value; +} + #endif diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index efff9acc39..f87778e99e 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -100,10 +100,6 @@ static void OXR_CheckErrors(XrInstance instance, XrResult result, const char* fu #define OXR(func) func; #endif -#ifdef OPENXR_PLATFORM_QUEST -#define OPENXR_HAS_PERFORMANCE_EXTENSION -#endif - enum { ovrMaxLayerCount = 2 }; enum { ovrMaxNumEyes = 2 }; @@ -133,7 +129,6 @@ typedef struct { VkImageView* VKDepthImages; bool Acquired; - bool UseVulkan; XrGraphicsBindingVulkanKHR* VKContext; } ovrFramebuffer; @@ -178,16 +173,27 @@ typedef struct { uint64_t frameIndex; ovrApp appState; float predictedDisplayTime; - bool useVulkan; XrGraphicsBindingVulkanKHR graphicsBindingVulkan; } engine_t; -void VR_Init( void* system, bool useVulkan, char* name, int version ); +enum VRPlatformFlag { + VR_PLATFORM_CONTROLLER_PICO, + VR_PLATFORM_CONTROLLER_QUEST, + VR_PLATFORM_PERFORMANCE_EXT, + VR_PLATFORM_PICO_INIT, + VR_PLATFORM_RENDERER_VULKAN, + VR_PLATFORM_TRACKING_FLOOR, + VR_PLATFORM_MAX +}; + +void VR_Init( void* system, char* name, int version ); void VR_Destroy( engine_t* engine ); void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ); void VR_LeaveVR( engine_t* engine ); engine_t* VR_GetEngine( void ); +bool VR_GetPlatformFLag(VRPlatformFlag flag); +void VR_SetPlatformFLag(VRPlatformFlag flag, bool value); void ovrApp_Clear(ovrApp* app); void ovrApp_Destroy(ovrApp* app); diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 34e3a3cbb4..be4b14c3e0 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -49,7 +49,6 @@ bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int frameBuffer->Width = width; frameBuffer->Height = height; - frameBuffer->UseVulkan = false; if (strstr((const char*)glGetString(GL_EXTENSIONS), "GL_OVR_multiview2") == nullptr) { @@ -142,7 +141,6 @@ bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int frameBuffer->Width = width; frameBuffer->Height = height; - frameBuffer->UseVulkan = true; frameBuffer->VKContext = (XrGraphicsBindingVulkanKHR*)context; XrSwapchainCreateInfo swapChainCreateInfo; @@ -242,7 +240,7 @@ bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int } void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { - if (frameBuffer->UseVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { for (int i = 0; i < frameBuffer->TextureSwapChainLength; i++) { vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKColorImages[i], nullptr); vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKDepthImages[i], nullptr); @@ -266,7 +264,7 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { } void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { - if (frameBuffer->UseVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { return (void *)frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { #ifdef XR_USE_GRAPHICS_API_OPENGL_ES @@ -298,7 +296,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { ovrFramebuffer_SetCurrent(frameBuffer); - if (frameBuffer->UseVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { #ifdef XR_USE_GRAPHICS_API_OPENGL_ES @@ -320,7 +318,7 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = false; // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully - if (frameBuffer->UseVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { #ifdef XR_USE_GRAPHICS_API_OPENGL_ES @@ -369,7 +367,7 @@ void ovrRenderer_Destroy(ovrRenderer* renderer) { } void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { - if (renderer->FrameBuffer[0].UseVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { #ifdef XR_USE_GRAPHICS_API_OPENGL_ES @@ -428,14 +426,9 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { XrResult result; OXR(result = xrBeginSession(app->Session, &sessionBeginInfo)); - app->SessionActive = (result == XR_SUCCESS); - // Set session state once we have entered VR mode and have a valid session object. - - // TODO: This should be a runtime check of the extension's presence, no? -#ifdef OPENXR_HAS_PERFORMANCE_EXTENSION - if (app->SessionActive) { + if (app->SessionActive && VR_GetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT)) { XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; XrPerfSettingsLevelEXT gpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; @@ -457,7 +450,6 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { OXR(pfnSetAndroidApplicationThreadKHR(app->Session, XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, app->MainThreadTid)); OXR(pfnSetAndroidApplicationThreadKHR(app->Session, XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR, app->RenderThreadTid)); } -#endif } else if (state == XR_SESSION_STATE_STOPPING) { assert(app->SessionActive); diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index 7ea64f9674..27cf0eb2fd 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -268,25 +268,27 @@ void IN_VRInit( engine_t *engine ) { handPoseRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_right", NULL, 1, &rightHandPath); XrPath interactionProfilePath = XR_NULL_PATH; -#ifdef OPENXR_PLATFORM_QUEST - OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePath)); -#elif OPENXR_PLATFORM_PICO - OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/pico/neo3_controller", &interactionProfilePath)); -#endif + if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST)) { + OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePath)); + } else if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO)) { + OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/pico/neo3_controller", &interactionProfilePath)); + } + // Map bindings XrActionSuggestedBinding bindings[32]; // large enough for all profiles int currBinding = 0; -#ifdef OPENXR_PLATFORM_QUEST - bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); - bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); - bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click"); -#elif OPENXR_PLATFORM_PICO - bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger/click"); - bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger/click"); - bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/back/click"); - bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/right/input/back/click"); -#endif + + if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST)) { + bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); + bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); + bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click"); + } else if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO)) { + bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger/click"); + bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger/click"); + bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/back/click"); + bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/right/input/back/click"); + } bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/left/input/x/click"); bindings[currBinding++] = ActionSuggestedBinding(buttonYAction, "/user/hand/left/input/y/click"); bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/right/input/a/click"); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index c91d2f045f..020eae9ae9 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -152,9 +152,10 @@ void VR_Recenter(engine_t* engine) { // Create a default stage space to use if SPACE_TYPE_STAGE is not // supported, or calls to xrGetReferenceSpaceBoundsRect fail. spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; -#ifdef OPENXR_FLOOR_STAGE - spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f; -#endif + if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) + { + spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f; + } OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace)); ALOGV("Created fake stage space from local space with offset"); engine->appState.CurrentSpace = engine->appState.FakeStageSpace; @@ -164,9 +165,10 @@ void VR_Recenter(engine_t* engine) { spaceCreateInfo.poseInReferenceSpace.position.y = 0.0; OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace)); ALOGV("Created stage space"); -#ifdef OPENXR_FLOOR_STAGE - engine->appState.CurrentSpace = engine->appState.StageSpace; -#endif + if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) + { + engine->appState.CurrentSpace = engine->appState.StageSpace; + } } // Update menu orientation @@ -209,7 +211,7 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView))); void* vulkanContext = nullptr; - if (engine->useVulkan) { + if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { vulkanContext = &engine->graphicsBindingVulkan; } ovrRenderer_Create(engine->appState.Session, &engine->appState.Renderer, From aacbe4f4a3b4f2b3a7e6dcb9b3b076c142411d1e Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 4 Nov 2022 14:53:07 +0100 Subject: [PATCH 191/715] OpenXR - Get platform flags in runtime --- Common/VR/PPSSPPVR.cpp | 28 +++++++++++++++++++--------- Common/VR/PPSSPPVR.h | 4 ++-- Common/VR/VRBase.cpp | 2 +- android/jni/app-android.cpp | 2 +- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 8bdcbf6688..5184183864 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -102,18 +102,28 @@ bool IsVRBuild() { } #if PPSSPP_PLATFORM(ANDROID) -void InitVROnAndroid(void* vm, void* activity, int version, char* name) { +void InitVROnAndroid(void* vm, void* activity, const char* system, int version, char* name) { - //TODO:get the flags in runtime -#ifdef OPENXR_PLATFORM_PICO - VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO, true); - VR_SetPlatformFLag(VR_PLATFORM_PICO_INIT, true); -#elifdef OPENXR_PLATFORM_QUEST - VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true); - VR_SetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT, true); -#endif + //Get device vendor (uppercase) + char vendor[64]; + sscanf(system, "%[^:]", vendor); + for (unsigned int i = 0; i < strlen(vendor); i++) { + if ((vendor[i] >= 'a') && (vendor[i] <= 'z')) { + vendor[i] = vendor[i] - 'a' + 'A'; + } + } + + //Set platform flags + if (strcmp(vendor, "PICO") == 0) { + VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO, true); + VR_SetPlatformFLag(VR_PLATFORM_PICO_INIT, true); + } else if ((strcmp(vendor, "META") == 0) || (strcmp(vendor, "OCULUS") == 0)) { + VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true); + VR_SetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT, true); + } VR_SetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN, (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN); + //Init VR ovrJava java; java.Vm = (JavaVM*)vm; java.ActivityObject = (jobject)activity; diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 153dce24af..f6e2eefb27 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -21,7 +21,7 @@ enum VRCompatFlag { // VR app flow integration bool IsVRBuild(); -void InitVROnAndroid(void* vm, void* activity, int version, char* name); +void InitVROnAndroid(void* vm, void* activity, const char* system, int version, char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); @@ -50,7 +50,7 @@ void UpdateVRView(float* leftEye, float* rightEye); // VR app flow integration inline bool IsVRBuild() { return false; } -inline void InitVROnAndroid(void* vm, void* activity, int version, char* name) {} +inline void InitVROnAndroid(void* vm, void* activity, const char* system, int version, char* name) {} inline void EnterVR(bool firstTime, void* vulkanContext) {} inline void GetVRResolutionPerEye(int* width, int* height) {} inline void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {} diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 129d42880f..a548c8a168 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -103,9 +103,9 @@ void VR_Init( void* system, char* name, int version ) { instanceCreateInfo.enabledExtensionNames = extensions.data(); #ifdef ANDROID + XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { ovrJava* java = (ovrJava*)system; - XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; instanceCreateInfoAndroid.applicationVM = java->Vm; instanceCreateInfoAndroid.applicationActivity = java->ActivityObject; instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 365bbef903..9e685cfaaf 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -759,7 +759,7 @@ retry: if (IsVRBuild()) { Version gitVer(PPSSPP_GIT_VERSION); - InitVROnAndroid(gJvm, nativeActivity, gitVer.ToInteger(), "PPSSPP"); + InitVROnAndroid(gJvm, nativeActivity, systemName.c_str(), gitVer.ToInteger(), "PPSSPP"); } } From 22980c8b9f51d944a0f36cab4f3c40c71d45ae02 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 5 Nov 2022 10:16:24 +0100 Subject: [PATCH 192/715] Code formatting fixed --- Common/VR/VRRenderer.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 020eae9ae9..2cc95c73c2 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -152,8 +152,7 @@ void VR_Recenter(engine_t* engine) { // Create a default stage space to use if SPACE_TYPE_STAGE is not // supported, or calls to xrGetReferenceSpaceBoundsRect fail. spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; - if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) - { + if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) { spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f; } OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace)); @@ -165,8 +164,7 @@ void VR_Recenter(engine_t* engine) { spaceCreateInfo.poseInReferenceSpace.position.y = 0.0; OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace)); ALOGV("Created stage space"); - if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) - { + if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) { engine->appState.CurrentSpace = engine->appState.StageSpace; } } From a5100d2de0292fed626206bae76ba49cf34b42f3 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 5 Nov 2022 21:44:21 +0100 Subject: [PATCH 193/715] Support Android file intents with up to 3 dots in path --- android/AndroidManifest.xml | 53 +++++++++++++++---------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index bee1ccda15..7ce80a7a45 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -70,37 +70,28 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + From 7742fbdeb6aeab258d2ad828c1f0a6a70881ad63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 5 Nov 2022 22:06:53 +0100 Subject: [PATCH 194/715] Switch RenderPassType to be a "proper" bitfield enum. --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 40 +++++++++++------------ Common/GPU/Vulkan/VulkanQueueRunner.h | 37 +++++++++++---------- Common/GPU/Vulkan/VulkanRenderManager.cpp | 28 ++++++++-------- Common/GPU/Vulkan/VulkanRenderManager.h | 8 ++--- Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- 5 files changed, 58 insertions(+), 57 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index bce57f549d..4038c991d1 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -32,12 +32,12 @@ static void MergeRenderAreaRectInto(VkRect2D *dest, VkRect2D &src) { RenderPassType MergeRPTypes(RenderPassType a, RenderPassType b) { // Either both are backbuffer type, or neither are. // These can't merge with other renderpasses - if (a == RP_TYPE_BACKBUFFER || b == RP_TYPE_BACKBUFFER) { + if (a == RenderPassType::BACKBUFFER || b == RenderPassType::BACKBUFFER) { _dbg_assert_(a == b); return a; } - _dbg_assert_((a & RP_TYPE_MULTIVIEW_COLOR) == (b & RP_TYPE_MULTIVIEW_COLOR)); + _dbg_assert_((a & RenderPassType::MULTIVIEW) == (b & RenderPassType::MULTIVIEW)); // The rest we can just OR together to get the maximum feature set. return (RenderPassType)((u32)a | (u32)b); @@ -198,7 +198,7 @@ bool VulkanQueueRunner::InitBackbufferFramebuffers(int width, int height) { VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view }; VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RP_TYPE_BACKBUFFER); + fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RenderPassType::BACKBUFFER); fb_info.attachmentCount = 2; fb_info.pAttachments = attachments; fb_info.width = width; @@ -331,7 +331,7 @@ static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) { VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) { bool selfDependency = RenderPassTypeHasInput(rpType); - bool isBackbuffer = rpType == RP_TYPE_BACKBUFFER; + bool isBackbuffer = rpType == RenderPassType::BACKBUFFER; bool hasDepth = RenderPassTypeHasDepth(rpType); bool multiview = RenderPassTypeHasMultiView(rpType); @@ -898,6 +898,18 @@ const char *AspectToString(VkImageAspectFlags aspect) { } } +static const char *rpTypeDebugNames[] = { + "RENDER", + "RENDER_DEPTH", + "RENDER_INPUT", + "RENDER_DEPTH_INPUT", + "MV_RENDER", + "MV_RENDER_DEPTH", + "MV_RENDER_INPUT", + "MV_RENDER_DEPTH_INPUT", + "BACKBUF", +}; + std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { char buffer[256]; switch (step.stepType) { @@ -907,19 +919,7 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight(); int actual_w = step.render.renderArea.extent.width; int actual_h = step.render.renderArea.extent.height; - const char *renderCmd; - switch (step.render.renderPassType) { - case RP_TYPE_BACKBUFFER: renderCmd = "BACKBUF"; break; - case RP_TYPE_COLOR: renderCmd = "RENDER"; break; - case RP_TYPE_COLOR_DEPTH: renderCmd = "RENDER_DEPTH"; break; - case RP_TYPE_COLOR_INPUT: renderCmd = "RENDER_INPUT"; break; - case RP_TYPE_COLOR_DEPTH_INPUT: renderCmd = "RENDER_DEPTH_INPUT"; break; - case RP_TYPE_MULTIVIEW_COLOR: renderCmd = "MV_RENDER"; break; - case RP_TYPE_MULTIVIEW_COLOR_DEPTH: renderCmd = "MV_RENDER_DEPTH"; break; - case RP_TYPE_MULTIVIEW_COLOR_INPUT: renderCmd = "MV_RENDER_INPUT"; break; - case RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT: renderCmd = "MV_RENDER_DEPTH_INPUT"; break; - default: renderCmd = "N/A"; - } + const char *renderCmd = rpTypeDebugNames[(size_t)step.render.renderPassType]; snprintf(buffer, sizeof(buffer), "%s %s %s (draws: %d, %dx%d/%dx%d)", renderCmd, step.tag, step.render.framebuffer ? step.render.framebuffer->Tag() : "", step.render.numDraws, actual_w, actual_h, w, h); break; } @@ -1459,17 +1459,17 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c { VKRGraphicsPipeline *graphicsPipeline = c.graphics_pipeline.pipeline; if (graphicsPipeline != lastGraphicsPipeline) { - if (!graphicsPipeline->pipeline[rpType]) { + if (!graphicsPipeline->pipeline[(size_t)rpType]) { // NOTE: If render steps got merged, it can happen that, as they ended during recording, // they didn't know their final render pass type so they created the wrong pipelines in EndCurRenderStep(). // Unfortunately I don't know if we can fix it in any more sensible place than here. // Maybe a middle pass. But let's try to just block and compile here for now, this doesn't // happen all that much. - graphicsPipeline->pipeline[rpType] = Promise::CreateEmpty(); + graphicsPipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType), rpType); } - VkPipeline pipeline = graphicsPipeline->pipeline[rpType]->BlockUntilReady(); + VkPipeline pipeline = graphicsPipeline->pipeline[(size_t)rpType]->BlockUntilReady(); if (pipeline != VK_NULL_HANDLE) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); pipelineLayout = c.pipeline.pipelineLayout; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 2466e576f7..a3b120e60b 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -54,38 +54,38 @@ enum class PipelineFlags : u8 { ENUM_CLASS_BITOPS(PipelineFlags); // Pipelines need to be created for the right type of render pass. -enum RenderPassType { +// TODO: Rename to RenderPassType? It is currently a bitfield. +// When you add more flags, don't forget to update rpTypeDebugNames[]. +enum class RenderPassType { + DEFAULT = 0, // These eight are organized so that bit 0 is DEPTH and bit 1 is INPUT and bit 2 is MULTIVIEW, so // they can be OR-ed together in MergeRPTypes. - RP_TYPE_COLOR, - RP_TYPE_COLOR_DEPTH, - RP_TYPE_COLOR_INPUT, - RP_TYPE_COLOR_DEPTH_INPUT, - - RP_TYPE_MULTIVIEW_COLOR, - RP_TYPE_MULTIVIEW_COLOR_DEPTH, - RP_TYPE_MULTIVIEW_COLOR_INPUT, - RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT, + HAS_DEPTH = 1, + COLOR_INPUT = 2, // input attachment + MULTIVIEW = 4, // This is the odd one out, and gets special handling in MergeRPTypes. - RP_TYPE_BACKBUFFER, // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible. + // If this flag is set, none of the other flags can be set. + // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible + // so we don't bother with a non-depth version. + BACKBUFFER = 8, - // Later will add pure-color render passes. - RP_TYPE_COUNT, + TYPE_COUNT = BACKBUFFER + 1, }; +ENUM_CLASS_BITOPS(RenderPassType); // Hm, soon time to exploit the bit properties in these.. inline bool RenderPassTypeHasDepth(RenderPassType type) { - return type == RP_TYPE_BACKBUFFER || type == RP_TYPE_COLOR_DEPTH || type == RP_TYPE_COLOR_DEPTH_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT; + return (type & RenderPassType::HAS_DEPTH) || type == RenderPassType::BACKBUFFER; } inline bool RenderPassTypeHasInput(RenderPassType type) { - return type == RP_TYPE_COLOR_INPUT || type == RP_TYPE_COLOR_DEPTH_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT; + return (type & RenderPassType::COLOR_INPUT) != 0; } inline bool RenderPassTypeHasMultiView(RenderPassType type) { - return type == RP_TYPE_MULTIVIEW_COLOR || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH || type == RP_TYPE_MULTIVIEW_COLOR_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT; + return (type & RenderPassType::MULTIVIEW) != 0; } struct VkRenderData { @@ -270,7 +270,7 @@ public: VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType); void Destroy(VulkanContext *vulkan) { - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (pass[i]) { vulkan->Delete().QueueDeleteRenderPass(pass[i]); } @@ -278,7 +278,8 @@ public: } private: - VkRenderPass pass[RP_TYPE_COUNT]{}; + // TODO: Might be better off with a hashmap once the render pass type count grows really large.. + VkRenderPass pass[(size_t)RenderPassType::TYPE_COUNT]{}; RPKey key_; }; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 314e1920c3..3c1ea6f07f 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -93,10 +93,10 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR // Would really like to log more here, we could probably attach more info to desc. // // At least create a null placeholder to avoid creating over and over if something is broken. - pipeline[rpType]->Post(VK_NULL_HANDLE); + pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); success = false; } else if (result != VK_SUCCESS) { - pipeline[rpType]->Post(VK_NULL_HANDLE); + pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); success = false; } else { @@ -104,14 +104,14 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR if (!tag.empty()) { vulkan->SetDebugName(vkpipeline, VK_OBJECT_TYPE_PIPELINE, tag.c_str()); } - pipeline[rpType]->Post(vkpipeline); + pipeline[(size_t)rpType]->Post(vkpipeline); } return success; } void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (!pipeline[i]) continue; VkPipeline pipeline = this->pipeline[i]->BlockUntilReady(); @@ -125,7 +125,7 @@ void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { u32 VKRGraphicsPipeline::GetVariantsBitmask() const { u32 bitmask = 0; - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (pipeline[i]) { bitmask |= 1 << i; } @@ -181,7 +181,7 @@ void VKRFramebuffer::UpdateTag(const char *newTag) { vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, name); vulkan_->SetDebugName(depth.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); } - for (int rpType = 0; rpType < RP_TYPE_COUNT; rpType++) { + for (size_t rpType = 0; rpType < (size_t)RenderPassType::TYPE_COUNT; rpType++) { if (framebuf[rpType]) { snprintf(name, sizeof(name), "fb_%s", tag_.c_str()); vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name); @@ -688,7 +688,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe VKRRenderPass *compatibleRenderPass = queueRunner_.GetRenderPass(key); compileMutex_.lock(); bool needsCompile = false; - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (!(variantBitmask & (1 << i))) continue; RenderPassType rpType = (RenderPassType)i; @@ -707,7 +707,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe } } - pipeline->pipeline[rpType] = Promise::CreateEmpty(); + pipeline->pipeline[i] = Promise::CreateEmpty(); compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType), rpType)); needsCompile = true; } @@ -740,19 +740,19 @@ void VulkanRenderManager::EndCurRenderStep() { // We'll often be able to avoid loading/saving the depth/stencil buffer. curRenderStep_->render.pipelineFlags = curPipelineFlags_; bool depthStencil = (curPipelineFlags_ & PipelineFlags::USES_DEPTH_STENCIL) != 0; - RenderPassType rpType = depthStencil ? RP_TYPE_COLOR_DEPTH : RP_TYPE_COLOR; + RenderPassType rpType = depthStencil ? RenderPassType::HAS_DEPTH : RenderPassType::DEFAULT; if (!curRenderStep_->render.framebuffer) { - rpType = RP_TYPE_BACKBUFFER; + rpType = RenderPassType::BACKBUFFER; } else { if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) { // Not allowed on backbuffers. - rpType = depthStencil ? RP_TYPE_COLOR_DEPTH_INPUT : RP_TYPE_COLOR_INPUT; + rpType = depthStencil ? (RenderPassType::HAS_DEPTH | RenderPassType::COLOR_INPUT) : RenderPassType::COLOR_INPUT; } // Framebuffers can be stereo, and if so, will control the render pass type to match. // Pipelines can be mono and render fine to stereo etc, so not checking them here. // Note that we don't support rendering to just one layer of a multilayer framebuffer! if (curRenderStep_->render.framebuffer->numLayers > 1) { - rpType = (RenderPassType)(rpType | RP_TYPE_MULTIVIEW_COLOR); + rpType = (RenderPassType)(rpType | RenderPassType::MULTIVIEW); } } @@ -764,8 +764,8 @@ void VulkanRenderManager::EndCurRenderStep() { compileMutex_.lock(); bool needsCompile = false; for (VKRGraphicsPipeline *pipeline : pipelinesToCheck_) { - if (!pipeline->pipeline[rpType]) { - pipeline->pipeline[rpType] = Promise::CreateEmpty(); + if (!pipeline->pipeline[(size_t)rpType]) { + pipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType), rpType)); needsCompile = true; } diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index c8ca219d17..f9b1f68be6 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -77,7 +77,7 @@ public: // TODO: Hide. VulkanContext *vulkan_; private: - VkFramebuffer framebuf[RP_TYPE_COUNT]{}; + VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{}; std::string tag_; }; @@ -167,7 +167,7 @@ struct VKRComputePipelineDesc { // Wrapped pipeline. Doesn't own desc. struct VKRGraphicsPipeline { ~VKRGraphicsPipeline() { - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { delete pipeline[i]; } } @@ -180,7 +180,7 @@ struct VKRGraphicsPipeline { u32 GetVariantsBitmask() const; VKRGraphicsPipelineDesc *desc = nullptr; // not owned! - Promise *pipeline[RP_TYPE_COUNT]{}; + Promise *pipeline[(size_t)RenderPassType::TYPE_COUNT]{}; std::string tag; }; @@ -201,7 +201,7 @@ struct VKRComputePipeline { struct CompileQueueEntry { CompileQueueEntry(VKRGraphicsPipeline *p, VkRenderPass _compatibleRenderPass, RenderPassType _renderPassType) : type(Type::GRAPHICS), graphics(p), compatibleRenderPass(_compatibleRenderPass), renderPassType(_renderPassType) {} - CompileQueueEntry(VKRComputePipeline *p) : type(Type::COMPUTE), compute(p), renderPassType(RP_TYPE_COLOR_DEPTH) {} + CompileQueueEntry(VKRComputePipeline *p) : type(Type::COMPUTE), compute(p), renderPassType(RenderPassType::HAS_DEPTH) {} // renderpasstype here shouldn't matter enum class Type { GRAPHICS, COMPUTE, diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 17d6ed113c..97e6a6c80a 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1178,7 +1178,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; raster->ToVulkan(&gDesc.rs); - pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << RP_TYPE_BACKBUFFER, tag ? tag : "thin3d"); + pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, tag ? tag : "thin3d"); if (desc.uniformDesc) { pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize; From ad6725b68443f197be0693884f77ead849343bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 28 Oct 2022 18:26:59 +0200 Subject: [PATCH 195/715] VK/D3D11: Move the rarely used "u_rotation" uniform to the frame uniform buffer. This uniform is used in two cases: * Non-buffered rendering in Vulkan, software transform * Non-buffered rendering in D3D11 level 9 on Windows Phone, software transform - which I don't think anyone builds for anymore Nice to not have it in the main uniform buffer, but mainly a demonstrator/test of moving stuff to the new frame-global buffer, and setting up the infrastructure. --- GPU/Common/ShaderUniforms.cpp | 6 ++++-- GPU/Common/ShaderUniforms.h | 15 ++++++++------- GPU/Common/VertexShaderGenerator.cpp | 5 +++++ GPU/Vulkan/DrawEngineVulkan.cpp | 4 +++- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 3c56d833e5..724fd26080 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -72,6 +72,10 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo maxValues[3] = NAN; } +void FrameUpdateUniforms(UB_Frame *ub, bool useBufferedRendering) { + ub->rotation = useBufferedRendering ? 0 : (float)g_display_rotation; +} + void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport, bool useBufferedRendering) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat3(ub->texEnvColor, gstate.texenvcolor); @@ -139,7 +143,6 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView flippedMatrix = flippedMatrix * g_display_rot_matrix; } CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr()); - ub->rotation = useBufferedRendering ? 0 : (float)g_display_rotation; } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { @@ -160,7 +163,6 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView } CopyMatrix4x4(ub->proj_through, proj_through.getReadPtr()); - ub->rotation = useBufferedRendering ? 0 : (float)g_display_rotation; } // Transform diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 12bc273da3..ecddc4b3ca 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -27,7 +27,6 @@ struct alignas(16) UB_VS_FS_Base { float tex[12]; float uvScaleOffset[4]; float depthRange[4]; - // Rotation is used only for software transform. float matAmbient[4]; float cullRangeMin[4]; float cullRangeMax[4]; @@ -37,7 +36,7 @@ struct alignas(16) UB_VS_FS_Base { float fogColor[3]; uint32_t alphaColorRef; float texEnvColor[3]; uint32_t colorTestMask; float blendFixA[3]; float stencil; - float blendFixB[3]; float rotation; + float blendFixB[3]; float padUnused; float texClamp[4]; float texClampOffset[2]; float fogCoef[2]; // VR stuff is to go here, later. For normal drawing, we can then get away @@ -62,7 +61,7 @@ R"( mat4 u_proj; vec3 u_fogcolor; uint u_alphacolorref; vec3 u_texenv; uint u_alphacolormask; vec3 u_blendFixA; float u_stencilReplaceValue; - vec3 u_blendFixB; float u_rotation; + vec3 u_blendFixB; float u_padUnused; vec4 u_texclamp; vec2 u_texclampoff; vec2 u_fogcoef; @@ -132,13 +131,14 @@ R"( mat3x4 u_bone0; mat3x4 u_bone1; mat3x4 u_bone2; mat3x4 u_bone3; mat3x4 u_bon )"; -static const char * const ub_frame_globalstr = -R"( vec4 stereoParams; +static const char * const ub_frameStr = +R"( + float u_rotation; )"; // Frame-global uniforms. -struct UB_FrameGlobal { - float stereoParams[4]; +struct UB_Frame { + float rotation; // This is only used when using software transform, and non-buffered, to support native screen rotation. }; void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ); @@ -146,5 +146,6 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport, bool useBufferedRendering); void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms); void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms); +void FrameUpdateUniforms(UB_Frame *ub, bool useBufferedRendering); uint32_t PackLightControlBits(); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 6c6cc57ab2..155731ddd1 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -249,6 +249,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (compat.shaderLanguage == GLSL_VULKAN) { WRITE(p, "\n"); + + if (!useHWTransform) { + WRITE(p, "layout (std140, set = 0, binding = 0) uniform frameVars {\n%s};\n", ub_frameStr); + } + WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); if (enableLighting || doShadeMapping) WRITE(p, "layout (std140, set = 1, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index f54afee3a9..30a223f983 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -1021,7 +1021,9 @@ void DrawEngineVulkan::DoFlush() { void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { if (!frame->frameDescSetUpdated) { // Push frame global constants. - UB_FrameGlobal frameConstants{}; + UB_Frame frameConstants{}; + FrameUpdateUniforms(&frameConstants, framebufferManager_->UseBufferedRendering()); + VkDescriptorBufferInfo frameConstantsBufInfo; frame->pushUBO->PushUBOData(frameConstants, &frameConstantsBufInfo); From 0f37854ef9e17eb86b29b327288f946761c8ed06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 5 Nov 2022 22:17:06 +0100 Subject: [PATCH 196/715] Drop some D3D11 screen rotation support (was only used on Windows Phone) --- GPU/Common/VertexShaderGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 155731ddd1..fd99a52cd9 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -851,7 +851,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // The proj_through matrix already has the rotation, if needed. WRITE(p, " vec4 outPos = mul(u_proj_through, vec4(position.xyz, 1.0));\n"); } else { - if (compat.shaderLanguage == GLSL_VULKAN || compat.shaderLanguage == HLSL_D3D11) { + if (compat.shaderLanguage == GLSL_VULKAN) { // Apply rotation from the uniform. WRITE(p, " mat2 displayRotation = mat2(\n"); WRITE(p, " u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), u_rotation == 1.0 ? 1.0 : (u_rotation == 3.0 ? -1.0 : 0.0),\n"); From 675a0467593756ab6f7937f83af76e2dd4a7a0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 5 Nov 2022 23:31:30 +0100 Subject: [PATCH 197/715] Fix parsing ampersands in server listings for streaming Fixes #16263 , or so I hope - haven't actually tested it, but seems straightforward enough. --- Common/StringUtils.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index 3a9e29c61a..3115e1f03c 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -286,6 +286,25 @@ void SplitString(const std::string& str, const char delim, std::vector& output) { size_t next = 0; @@ -294,7 +313,7 @@ void GetQuotedStrings(const std::string& str, std::vector& output) if (str[pos] == '\"' || str[pos] == '\'') { if (even) { //quoted text - output.emplace_back(str.substr(next, pos - next)); + output.emplace_back(ApplyHtmlEscapes(str.substr(next, pos - next))); even = 0; } else { //non quoted text From 439b38f705b548617b7e9c7865d9398ee1ca7bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 00:11:04 +0100 Subject: [PATCH 198/715] Comment fixes (feedback) --- Common/GPU/Vulkan/VulkanQueueRunner.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index a3b120e60b..6b7242cadf 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -54,7 +54,7 @@ enum class PipelineFlags : u8 { ENUM_CLASS_BITOPS(PipelineFlags); // Pipelines need to be created for the right type of render pass. -// TODO: Rename to RenderPassType? It is currently a bitfield. +// TODO: Rename to RenderPassFlags? // When you add more flags, don't forget to update rpTypeDebugNames[]. enum class RenderPassType { DEFAULT = 0, @@ -74,8 +74,6 @@ enum class RenderPassType { }; ENUM_CLASS_BITOPS(RenderPassType); -// Hm, soon time to exploit the bit properties in these.. - inline bool RenderPassTypeHasDepth(RenderPassType type) { return (type & RenderPassType::HAS_DEPTH) || type == RenderPassType::BACKBUFFER; } From d575151a6e6d7982186facef5f56282595c8cc93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 09:24:35 +0100 Subject: [PATCH 199/715] Yet another gradle upgrade --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index bfad5c1419..d9fc3ebd95 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:7.3.1' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0b74ce0881..86463708b7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,6 +3,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip android.useAndroidX=true android.enableJetifier=true From 4d815060469eb15aabf64144df923ae678bfa5e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 09:44:06 +0100 Subject: [PATCH 200/715] Upgrade gradle, specify NDK version in android/build.gradle Also fix a warning. --- Common/VR/PPSSPPVR.cpp | 2 +- Common/VR/PPSSPPVR.h | 4 ++-- android/build.gradle | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 5007672b01..712ee9290d 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -103,7 +103,7 @@ bool IsVRBuild() { } #if PPSSPP_PLATFORM(ANDROID) -void InitVROnAndroid(void* vm, void* activity, const char* system, int version, char* name) { +void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name) { //Get device vendor (uppercase) char vendor[64]; diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index f6e2eefb27..65a14158ff 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -21,7 +21,7 @@ enum VRCompatFlag { // VR app flow integration bool IsVRBuild(); -void InitVROnAndroid(void* vm, void* activity, const char* system, int version, char* name); +void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); @@ -50,7 +50,7 @@ void UpdateVRView(float* leftEye, float* rightEye); // VR app flow integration inline bool IsVRBuild() { return false; } -inline void InitVROnAndroid(void* vm, void* activity, const char* system, int version, char* name) {} +inline void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name) {} inline void EnterVR(bool firstTime, void* vulkanContext) {} inline void GetVRResolutionPerEye(int* width, int* height) {} inline void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {} diff --git a/android/build.gradle b/android/build.gradle index 47eef16fd7..3ee429208b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -45,6 +45,8 @@ android { } } compileSdkVersion 32 + ndkVersion "21.4.7075529" + defaultConfig { applicationId 'org.ppsspp.ppsspp' if (androidGitVersion.name() != "unknown" && androidGitVersion.code() >= 14000000) { From 8bb2313f5d5145908bc8a0343ec4842360e92e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 11:32:42 +0100 Subject: [PATCH 201/715] Finish previous buildfix... --- Common/VR/VRBase.cpp | 2 +- Common/VR/VRBase.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index a548c8a168..9c36fab0db 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -41,7 +41,7 @@ static bool vr_platform[VR_PLATFORM_MAX]; static engine_t vr_engine; int vr_initialized = 0; -void VR_Init( void* system, char* name, int version ) { +void VR_Init( void* system, const char* name, int version ) { if (vr_initialized) return; diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index f87778e99e..73870ab7dd 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -186,7 +186,7 @@ enum VRPlatformFlag { VR_PLATFORM_MAX }; -void VR_Init( void* system, char* name, int version ); +void VR_Init( void* system, const char* name, int version ); void VR_Destroy( engine_t* engine ); void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ); void VR_LeaveVR( engine_t* engine ); From 9b619b8c0bcaf8ee5d51aa03797283099d74ea32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 11:30:27 +0100 Subject: [PATCH 202/715] Remove ugly float conversion hacks from VR config --- Common/VR/PPSSPPVR.cpp | 20 ++++++------ Common/VR/VRRenderer.cpp | 68 +++++++++++++++++++++++----------------- Common/VR/VRRenderer.h | 22 ++++++++++--- 3 files changed, 67 insertions(+), 43 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 712ee9290d..86c8fdd545 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -225,7 +225,7 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con bool activate; float limit = g_Config.fMotionLength; //length of needed movement in meters XrVector3f axis = {0, 1, 0}; - float center = ToRadians((float)VR_GetConfig(VR_CONFIG_MENU_YAW)); + float center = ToRadians(VR_GetConfigFloat(VR_CONFIG_MENU_YAW)); XrQuaternionf orientation = XrQuaternionf_CreateFromVectorAngle(axis, center); XrVector3f position = XrQuaternionf_Rotate(orientation, IN_VRGetPose(j).position); @@ -281,13 +281,13 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con float cx = width / 2; float cy = height / 2; float speed = (cx + cy) / 2; - float x = cx - tan(ToRadians(angles.y - (float)VR_GetConfig(VR_CONFIG_MENU_YAW))) * speed; + float x = cx - tan(ToRadians(angles.y - VR_GetConfigFloat(VR_CONFIG_MENU_YAW))) * speed; float y = cy - tan(ToRadians(angles.x)) * speed; //set renderer VR_SetConfig(VR_CONFIG_MOUSE_X, (int)x); VR_SetConfig(VR_CONFIG_MOUSE_Y, (int)y); - VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 6 * (int)pow(VR_GetConfig(VR_CONFIG_CANVAS_DISTANCE), 0.25f)); + VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 6 * (int)pow(VR_GetConfigFloat(VR_CONFIG_CANVAS_DISTANCE), 0.25f)); //inform engine about the status TouchInput touch; @@ -446,11 +446,11 @@ bool StartVRRender() { // Set customizations __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); - VR_SetConfig(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance * 1000); - VR_SetConfig(VR_CONFIG_CAMERA_HEIGHT, g_Config.fCameraHeight * 1000); - VR_SetConfig(VR_CONFIG_CAMERA_SIDE, g_Config.fCameraSide * 1000); - VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); - VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.fFieldOfViewPercentage); + VR_SetConfigFloat(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance); + VR_SetConfigFloat(VR_CONFIG_CAMERA_HEIGHT, g_Config.fCameraHeight); + VR_SetConfigFloat(VR_CONFIG_CAMERA_SIDE, g_Config.fCameraSide); + VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); + VR_SetConfigFloat(VR_CONFIG_FOV_SCALE, g_Config.fFieldOfViewPercentage); VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, false); return true; } @@ -550,14 +550,14 @@ void UpdateVRParams(float* projMatrix) { } // Set 6DoF scale - float scale = pow(fabs(projMatrix[14]), 1.15f); + float scale = 1.0f; if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) { scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter; VR_SetConfig(VR_CONFIG_6DOF_PRECISE, true); } else { VR_SetConfig(VR_CONFIG_6DOF_PRECISE, false); } - VR_SetConfig(VR_CONFIG_6DOF_SCALE, (int)(scale * 1000000)); + VR_SetConfigFloat(VR_CONFIG_6DOF_SCALE, scale); } void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 2cc95c73c2..0a18a840f1 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -1,3 +1,6 @@ +#define _USE_MATH_DEFINES +#include + #include "VRBase.h" #include "VRInput.h" #include "VRRenderer.h" @@ -12,8 +15,9 @@ XrPosef invViewTransform[2]; XrFrameState frameState = {}; bool initialized = false; bool stageSupported = false; -int vrConfig[VR_CONFIG_MAX] = {}; ovrMatrix4f vrMatrix[VR_MATRIX_COUNT]; +int vrConfig[VR_CONFIG_MAX] = {}; +float vrConfigFloat[VR_CONFIG_FLOAT_MAX] = {}; XrVector3f hmdorientation; XrVector3f hmdposition; @@ -133,12 +137,12 @@ void VR_Recenter(engine_t* engine) { OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc)); hmdorientation = XrQuaternionf_ToEulerAngles(loc.pose.orientation); - vrConfig[VR_CONFIG_RECENTER_YAW] += (int)hmdorientation.y; - float recenterYaw = ToRadians((float)vrConfig[VR_CONFIG_RECENTER_YAW]); + VR_SetConfigFloat(VR_CONFIG_RECENTER_YAW, VR_GetConfigFloat(VR_CONFIG_RECENTER_YAW) + hmdorientation.y); + float recenterYaw = ToRadians(VR_GetConfigFloat(VR_CONFIG_RECENTER_YAW)); spaceCreateInfo.poseInReferenceSpace.orientation.x = 0; - spaceCreateInfo.poseInReferenceSpace.orientation.y = sin(recenterYaw / 2); + spaceCreateInfo.poseInReferenceSpace.orientation.y = sinf(recenterYaw / 2); spaceCreateInfo.poseInReferenceSpace.orientation.z = 0; - spaceCreateInfo.poseInReferenceSpace.orientation.w = cos(recenterYaw / 2); + spaceCreateInfo.poseInReferenceSpace.orientation.w = cosf(recenterYaw / 2); } // Delete previous space instances @@ -170,8 +174,8 @@ void VR_Recenter(engine_t* engine) { } // Update menu orientation - vrConfig[VR_CONFIG_MENU_PITCH] = (int)hmdorientation.x; - vrConfig[VR_CONFIG_MENU_YAW] = 0; + VR_SetConfigFloat(VR_CONFIG_MENU_PITCH, hmdorientation.x); + VR_SetConfigFloat(VR_CONFIG_MENU_YAW, 0.0f); } void VR_InitRenderer( engine_t* engine, bool multiview ) { @@ -181,8 +185,8 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { int eyeW, eyeH; VR_GetResolution(engine, &eyeW, &eyeH); - vrConfig[VR_CONFIG_VIEWPORT_WIDTH] = eyeW; - vrConfig[VR_CONFIG_VIEWPORT_HEIGHT] = eyeH; + VR_SetConfig(VR_CONFIG_VIEWPORT_WIDTH, eyeW); + VR_SetConfig(VR_CONFIG_VIEWPORT_HEIGHT, eyeH); // Get the viewport configuration info for the chosen viewport configuration type. engine->appState.ViewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES; @@ -303,7 +307,7 @@ bool VR_InitFrame( engine_t* engine ) { // Update matrices for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) { - float nearPlane = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f; + float nearPlane = VR_GetConfigFloat(VR_CONFIG_FOV_SCALE) / 200.0f; vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, nearPlane, 0.0f ); } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { bool flatScreen = false; @@ -315,9 +319,9 @@ bool VR_InitFrame( engine_t* engine ) { } // get axis mirroring configuration - float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1 : 1; - float my = vrConfig[VR_CONFIG_MIRROR_YAW] ? -1 : 1; - float mz = vrConfig[VR_CONFIG_MIRROR_ROLL] ? -1 : 1; + float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1.0f : 1.0f; + float my = vrConfig[VR_CONFIG_MIRROR_YAW] ? -1.0f : 1.0f; + float mz = vrConfig[VR_CONFIG_MIRROR_ROLL] ? -1.0f : 1.0f; // ensure there is maximally one axis to mirror rotation if (mx + my + mz < 0) { @@ -338,30 +342,30 @@ bool VR_InitFrame( engine_t* engine ) { } vrMatrix[matrix] = ovrMatrix4f_CreateFromQuaternion(&invView.orientation); - float scale = (float)VR_GetConfig(VR_CONFIG_6DOF_SCALE) * 0.000001f; + float scale = VR_GetConfigFloat(VR_CONFIG_6DOF_SCALE) * 0.000001f; if (!flatScreen && vrConfig[VR_CONFIG_6DOF_ENABLED]) { vrMatrix[matrix].M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; } - if (abs(vrConfig[VR_CONFIG_CAMERA_DISTANCE]) > 0) { - XrVector3f forward = {0.0f, 0.0f, (float)vrConfig[VR_CONFIG_CAMERA_DISTANCE] * 0.001f * scale}; + if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE)) > 0.0f) { + XrVector3f forward = {0.0f, 0.0f, VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE) * scale}; forward = XrQuaternionf_Rotate(invView.orientation, forward); forward = XrVector3f_ScalarMultiply(forward, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); vrMatrix[matrix].M[0][3] += forward.x; vrMatrix[matrix].M[1][3] += forward.y; vrMatrix[matrix].M[2][3] += forward.z; } - if (abs(vrConfig[VR_CONFIG_CAMERA_HEIGHT]) > 0) { - XrVector3f up = {0.0f, -(float)vrConfig[VR_CONFIG_CAMERA_HEIGHT] * 0.001f * scale, 0.0f}; + if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT)) > 0.0f) { + XrVector3f up = {0.0f, -VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT) * scale, 0.0f}; up = XrQuaternionf_Rotate(invView.orientation, up); up = XrVector3f_ScalarMultiply(up, vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f); vrMatrix[matrix].M[0][3] += up.x; vrMatrix[matrix].M[1][3] += up.y; vrMatrix[matrix].M[2][3] += up.z; } - if (abs(vrConfig[VR_CONFIG_CAMERA_SIDE]) > 0) { - XrVector3f side = {-(float)vrConfig[VR_CONFIG_CAMERA_SIDE] * 0.001f * scale, 0.0f, 0.0f}; + if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE)) > 0.0f) { + XrVector3f side = {-VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE) * scale, 0.0f, 0.0f}; side = XrQuaternionf_Rotate(invView.orientation, side); side = XrVector3f_ScalarMultiply(side, vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f); vrMatrix[matrix].M[0][3] += side.x; @@ -414,7 +418,7 @@ void VR_FinishFrame( engine_t* engine ) { int vrMode = vrConfig[VR_CONFIG_MODE]; XrCompositionLayerProjectionView projection_layer_elements[2] = {}; if ((vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_STEREO_6DOF)) { - vrConfig[VR_CONFIG_MENU_YAW] = (int)hmdorientation.y; + VR_SetConfigFloat(VR_CONFIG_MENU_YAW, hmdorientation.y); for (int eye = 0; eye < ovrMaxNumEyes; eye++) { int imageLayer = engine->appState.Renderer.Multiview ? eye : 0; @@ -453,13 +457,13 @@ void VR_FinishFrame( engine_t* engine ) { } else if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { // Flat screen pose - float distance = (float)vrConfig[VR_CONFIG_CANVAS_DISTANCE]; - float menuPitch = ToRadians((float)vrConfig[VR_CONFIG_MENU_PITCH]); - float menuYaw = ToRadians((float)vrConfig[VR_CONFIG_MENU_YAW]); + float distance = VR_GetConfigFloat(VR_CONFIG_CANVAS_DISTANCE); + float menuPitch = ToRadians(VR_GetConfigFloat(VR_CONFIG_MENU_PITCH)); + float menuYaw = ToRadians(VR_GetConfigFloat(VR_CONFIG_MENU_YAW)); XrVector3f pos = { - invViewTransform[0].position.x - sin(menuYaw) * distance, + invViewTransform[0].position.x - sinf(menuYaw) * distance, invViewTransform[0].position.y, - invViewTransform[0].position.z - cos(menuYaw) * distance + invViewTransform[0].position.z - cosf(menuYaw) * distance }; XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, -menuPitch); XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, menuYaw); @@ -479,7 +483,7 @@ void VR_FinishFrame( engine_t* engine ) { cylinder_layer.pose.orientation = XrQuaternionf_Multiply(pitch, yaw); cylinder_layer.pose.position = pos; cylinder_layer.radius = 12.0f; - cylinder_layer.centralAngle = M_PI * 0.5f; + cylinder_layer.centralAngle = (float)(M_PI * 0.5); cylinder_layer.aspectRatio = 1; // Build the cylinder layer @@ -533,9 +537,17 @@ void VR_SetConfig( VRConfig config, int value) { vrConfig[config] = value; } +float VR_GetConfigFloat(VRConfigFloat config) { + return vrConfigFloat[config]; +} + +void VR_SetConfigFloat(VRConfigFloat config, float value) { + vrConfigFloat[config] = value; +} + void* VR_BindFramebuffer(engine_t *engine) { if (!initialized) return nullptr; - int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; + int fboIndex = VR_GetConfig(VR_CONFIG_CURRENT_FBO); return ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]); } diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 863212bd7d..70b1ac1018 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -7,14 +7,11 @@ enum VRConfig { //switching between 2D and 3D VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, //camera setup - VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_CONTROL, VR_CONFIG_CAMERA_DISTANCE, - VR_CONFIG_CAMERA_HEIGHT, VR_CONFIG_CAMERA_SIDE, VR_CONFIG_CANVAS_DISTANCE, + VR_CONFIG_CAMERA_CONTROL, //6DoF - VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, + VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, VR_CONFIG_MIRROR_PITCH, VR_CONFIG_MIRROR_YAW, VR_CONFIG_MIRROR_ROLL, - //2D canvas positioning - VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, //mouse cursor VR_CONFIG_MOUSE_SIZE, VR_CONFIG_MOUSE_X, VR_CONFIG_MOUSE_Y, //viewport setup @@ -26,6 +23,18 @@ enum VRConfig { VR_CONFIG_MAX }; +enum VRConfigFloat { + // 6dof + VR_CONFIG_6DOF_SCALE, + //camera setup + VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_DISTANCE, + VR_CONFIG_CAMERA_HEIGHT, VR_CONFIG_CAMERA_SIDE, VR_CONFIG_CANVAS_DISTANCE, + //2D canvas positioning + VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, + + VR_CONFIG_FLOAT_MAX +}; + enum VRMatrix { VR_PROJECTION_MATRIX_LEFT_EYE, VR_PROJECTION_MATRIX_RIGHT_EYE, @@ -53,5 +62,8 @@ void VR_FinishFrame( engine_t* engine ); int VR_GetConfig( VRConfig config ); void VR_SetConfig( VRConfig config, int value); +float VR_GetConfigFloat( VRConfigFloat config ); +void VR_SetConfigFloat( VRConfigFloat config, float value ); + void* VR_BindFramebuffer(engine_t *engine); ovrMatrix4f VR_GetMatrix( VRMatrix matrix ); From ef3b0607efaf4696493695ab1251a08d3fa4e988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 11:39:41 +0100 Subject: [PATCH 203/715] Rename 6DOF_PRECISE to HAS_UNIT_SCALE --- Common/VR/PPSSPPVR.cpp | 6 +++--- Common/VR/VRRenderer.cpp | 2 +- Common/VR/VRRenderer.h | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 86c8fdd545..ec20865e7b 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -400,7 +400,7 @@ bool StartVRRender() { // Decide if the scene is 3D or not if (g_Config.bEnableVR && !VR_GetConfig(VR_CONFIG_FORCE_2D) && (VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) > 15)) { - bool stereo = VR_GetConfig(VR_CONFIG_6DOF_PRECISE) && g_Config.bEnableStereo; + bool stereo = VR_GetConfig(VR_CONFIG_HAS_UNIT_SCALE) && g_Config.bEnableStereo; VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); } else { VR_SetConfig(VR_CONFIG_MODE, g_Config.bEnableStereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); @@ -553,9 +553,9 @@ void UpdateVRParams(float* projMatrix) { float scale = 1.0f; if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) { scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter; - VR_SetConfig(VR_CONFIG_6DOF_PRECISE, true); + VR_SetConfig(VR_CONFIG_HAS_UNIT_SCALE, true); } else { - VR_SetConfig(VR_CONFIG_6DOF_PRECISE, false); + VR_SetConfig(VR_CONFIG_HAS_UNIT_SCALE, false); } VR_SetConfigFloat(VR_CONFIG_6DOF_SCALE, scale); } diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 0a18a840f1..70b0acbd57 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -372,7 +372,7 @@ bool VR_InitFrame( engine_t* engine ) { vrMatrix[matrix].M[1][3] += side.y; vrMatrix[matrix].M[2][3] += side.z; } - if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + if (vrConfig[VR_CONFIG_HAS_UNIT_SCALE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 70b1ac1018..bd041ca366 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -8,8 +8,9 @@ enum VRConfig { VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, //camera setup VR_CONFIG_CAMERA_CONTROL, + VR_CONFIG_HAS_UNIT_SCALE, //6DoF - VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_PRECISE, VR_CONFIG_MIRROR_UPDATED, + VR_CONFIG_6DOF_ENABLED, VR_CONFIG_MIRROR_UPDATED, VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, VR_CONFIG_MIRROR_PITCH, VR_CONFIG_MIRROR_YAW, VR_CONFIG_MIRROR_ROLL, //mouse cursor @@ -26,10 +27,10 @@ enum VRConfig { enum VRConfigFloat { // 6dof VR_CONFIG_6DOF_SCALE, - //camera setup + // camera setup VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_DISTANCE, VR_CONFIG_CAMERA_HEIGHT, VR_CONFIG_CAMERA_SIDE, VR_CONFIG_CANVAS_DISTANCE, - //2D canvas positioning + // 2D canvas positioning VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, VR_CONFIG_FLOAT_MAX From 8398b779fbf75447d0f8c43f1aeb17b4a8cfd726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 11:51:28 +0100 Subject: [PATCH 204/715] 6dof fix --- Common/VR/VRRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 70b0acbd57..f04a3c15c8 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -342,7 +342,7 @@ bool VR_InitFrame( engine_t* engine ) { } vrMatrix[matrix] = ovrMatrix4f_CreateFromQuaternion(&invView.orientation); - float scale = VR_GetConfigFloat(VR_CONFIG_6DOF_SCALE) * 0.000001f; + float scale = VR_GetConfigFloat(VR_CONFIG_6DOF_SCALE); if (!flatScreen && vrConfig[VR_CONFIG_6DOF_ENABLED]) { vrMatrix[matrix].M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; From 5d3ec6c8ff43b2e0a5122aa5cea52f5a7983d223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 14:35:28 +0100 Subject: [PATCH 205/715] Fix type of predictedDisplayTime --- Common/VR/VRBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 73870ab7dd..b77e6dc7d0 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -172,7 +172,7 @@ typedef struct { typedef struct { uint64_t frameIndex; ovrApp appState; - float predictedDisplayTime; + XrTime predictedDisplayTime; XrGraphicsBindingVulkanKHR graphicsBindingVulkan; } engine_t; From b4507cd5cca1133a44a782658568590e854a7ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 14:36:51 +0100 Subject: [PATCH 206/715] Make a lot more code VR build for all platforms --- Common/GPU/OpenGL/GLQueueRunner.cpp | 6 ++-- Common/GPU/OpenGL/GLRenderManager.cpp | 2 +- Common/GPU/Vulkan/VulkanLoader.cpp | 2 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 2 +- Common/GPU/Vulkan/VulkanRenderManager.cpp | 2 +- Common/VR/PPSSPPVR.cpp | 8 ++++- Common/VR/PPSSPPVR.h | 4 +-- Common/VR/VRBase.cpp | 6 ++-- Common/VR/VRBase.h | 4 +-- Common/VR/VRFramebuffer.cpp | 40 +++++++++++++---------- Common/VR/VRInput.cpp | 4 --- Common/VR/VRRenderer.cpp | 4 --- Core/Compatibility.cpp | 3 ++ Core/Config.cpp | 2 +- Core/KeyMap.cpp | 2 +- GPU/Common/PresentationCommon.cpp | 2 +- GPU/GLES/GPU_GLES.cpp | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 2 +- UI/NativeApp.cpp | 2 +- android/jni/AndroidEGLContext.cpp | 2 +- android/jni/app-android.cpp | 12 +++---- assets/compatvr.ini | 18 +++++----- 22 files changed, 69 insertions(+), 62 deletions(-) diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 84f1b1a375..bf27a4fcfa 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -280,7 +280,7 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski _dbg_assert_(query.name); int location = -1; - if (IsVRBuild() && IsMultiviewSupported()) { + if (IsVREnabled() && IsMultiviewSupported()) { int index = GetStereoBufferIndex(query.name); if (index >= 0) { std::string layout = GetStereoBufferLayout(query.name); @@ -707,7 +707,7 @@ void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCal switch (step.stepType) { case GLRStepType::RENDER: renderCount++; - if (IsVRBuild()) { + if (IsVREnabled()) { GLRStep vrStep = step; PreprocessStepVR(&vrStep); PerformRenderPass(vrStep, renderCount == 1, renderCount == totalRenderCount); @@ -1603,7 +1603,7 @@ void GLQueueRunner::PerformBindFramebufferAsRenderTarget(const GLRStep &pass) { fbo_bind_fb_target(false, curFB_->handle); } else { fbo_unbind(); - if (IsVRBuild()) { + if (IsVREnabled()) { BindVRFramebuffer(); } // Backbuffer is now bound. diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index 23c133272d..f3eb5f59eb 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -577,7 +577,7 @@ void GLRenderManager::Run(int frame) { } } - if (IsVRBuild()) { + if (IsVREnabled()) { int passes = GetVRPassesCount(); for (int i = 0; i < passes; i++) { PreVRFrameRender(i); diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index 52ece65731..32984494ce 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -309,7 +309,7 @@ void VulkanSetAvailable(bool available) { bool VulkanMayBeAvailable() { // Unsupported in VR at the moment - if (IsVRBuild()) { + if (IsVREnabled()) { return false; } diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 4038c991d1..ae231d63df 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1711,7 +1711,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR }; renderPass = GetRenderPass(key); - if (IsVRBuild()) { + if (IsVREnabled()) { framebuf = (VkFramebuffer)BindVRFramebuffer(); } else { framebuf = backbuffer_; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 3c1ea6f07f..732aa2a0fd 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -1325,7 +1325,7 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { if (task.steps.empty() && !frameData.hasAcquired) frameData.skipSwap = true; //queueRunner_.LogSteps(stepsOnThread, false); - if (IsVRBuild()) { + if (IsVREnabled()) { int passes = GetVRPassesCount(); for (int i = 0; i < passes; i++) { PreVRFrameRender(i); diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index ec20865e7b..e133ebd277 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -98,8 +98,14 @@ VR app flow integration ================================================================================ */ -bool IsVRBuild() { +bool IsVREnabled() { + // For now, let the OPENXR build flag control enablement. + // This will change. +#ifdef OPENXR return true; +#else + return false; +#endif } #if PPSSPP_PLATFORM(ANDROID) diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 65a14158ff..dfb38471b1 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -20,7 +20,7 @@ enum VRCompatFlag { #ifdef OPENXR // VR app flow integration -bool IsVRBuild(); +bool IsVREnabled(); void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); @@ -49,7 +49,7 @@ void UpdateVRView(float* leftEye, float* rightEye); #else //dummy integration // VR app flow integration -inline bool IsVRBuild() { return false; } +inline bool IsVREnabled() { return false; } inline void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name) {} inline void EnterVR(bool firstTime, void* vulkanContext) {} inline void GetVRResolutionPerEye(int* width, int* height) {} diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 9c36fab0db..c6661f1cf0 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -5,9 +5,9 @@ #include #include -#if defined(OPENXR) - +#ifndef _WIN32 #include +#endif enum ConfigsSetEXT { UNREAL_VERSION = 0, @@ -41,6 +41,8 @@ static bool vr_platform[VR_PLATFORM_MAX]; static engine_t vr_engine; int vr_initialized = 0; +#if defined(OPENXR) + void VR_Init( void* system, const char* name, int version ) { if (vr_initialized) return; diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index b77e6dc7d0..4e0e1e266a 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -28,12 +28,12 @@ using namespace PPSSPP_VK; #include #elif defined(_WIN32) #include "Common/CommonWindows.h" +#include "Common/GPU/OpenGL/GLCommon.h" #include #define XR_USE_PLATFORM_WIN32 1 -#define XR_USE_GRAPHICS_API_OPENGL_ES 1 +#define XR_USE_GRAPHICS_API_OPENGL 1 #define XR_USE_GRAPHICS_API_VULKAN 1 #else -#define XR_USE_GRAPHICS_API_OPENGL_ES 1 #define XR_USE_GRAPHICS_API_VULKAN 1 #endif diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index be4b14c3e0..2122191bec 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -43,9 +43,9 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = false; } -#ifdef OPENXR +#if XR_USE_GRAPHICS_API_OPENGL_ES -bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { +static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { frameBuffer->Width = width; frameBuffer->Height = height; @@ -56,12 +56,11 @@ bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int } typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei); - auto glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)eglGetProcAddress ("glFramebufferTextureMultiviewOVR"); - if (!glFramebufferTextureMultiviewOVR) - { + PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR glFramebufferTextureMultiviewOVR = nullptr; + glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)eglGetProcAddress ("glFramebufferTextureMultiviewOVR"); + if (!glFramebufferTextureMultiviewOVR) { ALOGE("Can not get proc address for glFramebufferTextureMultiviewOVR.\n"); } - XrSwapchainCreateInfo swapChainCreateInfo; memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo)); swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO; @@ -136,8 +135,10 @@ bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int return true; } -bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, - bool multiview, void* context) { +#endif + +static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, + bool multiview, void* context) { frameBuffer->Width = width; frameBuffer->Height = height; @@ -241,7 +242,7 @@ bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { - for (int i = 0; i < frameBuffer->TextureSwapChainLength; i++) { + for (int i = 0; i < (int)frameBuffer->TextureSwapChainLength; i++) { vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKColorImages[i], nullptr); vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKDepthImages[i], nullptr); vkDestroyFramebuffer(frameBuffer->VKContext->device, frameBuffer->VKFrameBuffers[i], nullptr); @@ -250,7 +251,7 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { delete[] frameBuffer->VKDepthImages; delete[] frameBuffer->VKFrameBuffers; } else { -#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); free(frameBuffer->GLFrameBuffers); #endif @@ -267,7 +268,7 @@ void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { return (void *)frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { -#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); #endif return nullptr; @@ -299,7 +300,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { -#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL GL(glEnable( GL_SCISSOR_TEST )); GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); @@ -321,7 +322,7 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { -#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL(glClear(GL_COLOR_BUFFER_BIT)); @@ -352,8 +353,10 @@ void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int if (vulkanContext) { ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, multiview, vulkanContext); } else { -#ifdef XR_USE_GRAPHICS_API_OPENGL_ES - ovrFramebuffer_CreateGL(session, &renderer->FrameBuffer[i], width, height, multiview); +#if XR_USE_GRAPHICS_API_OPENGL_ES + ovrFramebuffer_CreateGLES(session, &renderer->FrameBuffer[i], width, height, multiview); +#elif XR_USE_GRAPHICS_API_OPENGL + // TODO #endif } } @@ -370,7 +373,7 @@ void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { -#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL GL(glEnable(GL_SCISSOR_TEST)); GL(glScissor(x, y, size, size)); GL(glViewport(x, y, size, size)); @@ -414,6 +417,7 @@ void ovrApp_Destroy(ovrApp* app) { ovrApp_Clear(app); } + void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { if (state == XR_SESSION_STATE_READY) { assert(app->SessionActive == false); @@ -428,6 +432,7 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { OXR(result = xrBeginSession(app->Session, &sessionBeginInfo)); app->SessionActive = (result == XR_SUCCESS); +#ifdef ANDROID if (app->SessionActive && VR_GetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT)) { XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; XrPerfSettingsLevelEXT gpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; @@ -450,6 +455,7 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { OXR(pfnSetAndroidApplicationThreadKHR(app->Session, XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, app->MainThreadTid)); OXR(pfnSetAndroidApplicationThreadKHR(app->Session, XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR, app->RenderThreadTid)); } +#endif } else if (state == XR_SESSION_STATE_STOPPING) { assert(app->SessionActive); @@ -538,5 +544,3 @@ int ovrApp_HandleXrEvents(ovrApp* app) { } return recenter; } - -#endif diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index 27cf0eb2fd..912bbca17f 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -1,8 +1,6 @@ #include "VRInput.h" #include -#ifdef OPENXR - //OpenXR XrPath leftHandPath; XrPath rightHandPath; @@ -464,5 +462,3 @@ XrPosef IN_VRGetPose( int controllerIndex ) { xrLocateSpace(aimSpace[controllerIndex], engine->appState.CurrentSpace, (XrTime)(engine->predictedDisplayTime), &loc); return loc.pose; } - -#endif diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index f04a3c15c8..50fc4c0003 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -22,8 +22,6 @@ float vrConfigFloat[VR_CONFIG_FLOAT_MAX] = {}; XrVector3f hmdorientation; XrVector3f hmdposition; -#ifdef OPENXR - void VR_UpdateStageBounds(ovrApp* pappState) { XrExtent2Df stageBounds = {}; @@ -554,5 +552,3 @@ void* VR_BindFramebuffer(engine_t *engine) { ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) { return vrMatrix[matrix]; } - -#endif diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index f59a0da45b..4ce6b322e5 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -17,6 +17,7 @@ #include +#include "Common/Log.h" #include "Common/Data/Format/IniFile.h" #include "Common/StringUtils.h" #include "Core/Compatibility.h" @@ -122,6 +123,8 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "Skyplane", &vrCompat_.Skyplane); CheckSetting(iniFile, gameID, "UnitsPerMeter", &vrCompat_.UnitsPerMeter); + + NOTICE_LOG(G3D, "UnitsPerMeter for %s: %f", gameID.c_str(), vrCompat_.UnitsPerMeter); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Config.cpp b/Core/Config.cpp index b8d1408144..b1f22523f4 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -697,7 +697,7 @@ const char * const vulkanDefaultBlacklist[] = { }; static int DefaultGPUBackend() { - if (IsVRBuild()) { + if (IsVREnabled()) { return (int)GPUBackend::OPENGL; } diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index 0be4dd7182..8c84be11e1 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -667,7 +667,7 @@ void RestoreDefault() { g_controllerMap.clear(); g_controllerMapGeneration++; - if (IsVRBuild()) { + if (IsVREnabled()) { SetDefaultKeyMap(DEFAULT_MAPPING_VR_HEADSET, false); return; } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index b4e05d8d50..aec95318ec 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -77,7 +77,7 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f SmallDisplayZoom zoomType = (SmallDisplayZoom)g_Config.iSmallDisplayZoomType; - if (IsVRBuild()) { + if (IsVREnabled()) { if (IsFlatVRScene()) { zoomType = SmallDisplayZoom::AUTO; } else { diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index b6b2b6a661..f67e90d335 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -210,7 +210,7 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_USE_FRAGMENT_TEST_CACHE; } - if (IsVRBuild()) { + if (IsVREnabled()) { features |= GPU_USE_VIRTUAL_REALITY; } if (IsMultiviewSupported()) { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 118c8c3fed..04a1a85974 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -457,7 +457,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } if (dirty & DIRTY_FOGCOLOR) { SetColorUniform3(render_, &u_fogcolor, gstate.fogcolor); - if (IsVRBuild()) { + if (IsVREnabled()) { SetVRCompat(VR_COMPAT_FOG_COLOR, gstate.fogcolor); } } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 0f4cac7f37..d387e7064b 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1297,7 +1297,7 @@ bool NativeTouch(const TouchInput &touch) { bool NativeKey(const KeyInput &key) { // Special key VR actions - if (IsVRBuild()) { + if (IsVREnabled()) { UpdateVRSpecialKeys(key); } diff --git a/android/jni/AndroidEGLContext.cpp b/android/jni/AndroidEGLContext.cpp index 9507c217e6..0cddc2b7f3 100644 --- a/android/jni/AndroidEGLContext.cpp +++ b/android/jni/AndroidEGLContext.cpp @@ -47,7 +47,7 @@ bool AndroidEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int des } gl->MakeCurrent(); if (gl->GetMode() == GLInterfaceMode::MODE_OPENGL) - SetGLCoreContext(!IsVRBuild()); + SetGLCoreContext(!IsVREnabled()); CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); SetGPUBackend(GPUBackend::OPENGL); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 9e685cfaaf..b74d345dc4 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -757,7 +757,7 @@ retry: EmuThreadStart(); } - if (IsVRBuild()) { + if (IsVREnabled()) { Version gitVer(PPSSPP_GIT_VERSION); InitVROnAndroid(gJvm, nativeActivity, systemName.c_str(), gitVer.ToInteger(), "PPSSPP"); } @@ -939,7 +939,7 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, } NativeMessageReceived("recreateviews", ""); - if (IsVRBuild()) { + if (IsVREnabled()) { EnterVR(firstStart, graphicsContext->GetAPIContext()); } @@ -982,7 +982,7 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv pixel_yres = bufh; backbuffer_format = format; - if (IsVRBuild()) { + if (IsVREnabled()) { GetVRResolutionPerEye(&pixel_xres, &pixel_yres); } @@ -1057,7 +1057,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, SetCurrentThreadName("AndroidRender"); } - if (IsVRBuild() && !StartVRRender()) + if (IsVREnabled() && !StartVRRender()) return; if (useCPUThread) { @@ -1068,7 +1068,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, UpdateRunLoopAndroid(env); } - if (IsVRBuild()) { + if (IsVREnabled()) { UpdateVRInput(NativeKey, NativeTouch, g_Config.bHapticFeedback, dp_xscale, dp_yscale); FinishVRRender(); } @@ -1291,7 +1291,7 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) { extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) { INFO_LOG(G3D, "NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate); - if (IsVRBuild()) { + if (IsVREnabled()) { int width, height; GetVRResolutionPerEye(&width, &height); xres = width; diff --git a/assets/compatvr.ini b/assets/compatvr.ini index 430fb80e47..bc4e1a6dd1 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -313,15 +313,6 @@ ULUS10319 = 10.0 # Bowling 3D NPUZ00002 = 1.0 -# Burnout Legends -NPJH50305 = 1.0 -ULAS42019 = 1.0 -ULES00125 = 1.0 -ULJM05049 = 1.0 -ULJM05228 = 1.0 -ULKS46027 = 1.0 -ULUS10025 = 1.0 - # Brain Challenge NPEH00003 = 30.0 NPJH00002 = 30.0 @@ -335,6 +326,15 @@ NPUZ00031 = 1.0 NPEZ00023 = 1.0 NPUZ00007 = 1.0 +# Burnout Legends +ULES00125 = 2.0 +ULUS10025 = 2.0 +ULJM05228 = 2.0 +NPJH50305 = 2.0 +ULJM05049 = 2.0 +ULKS46027 = 2.0 +ULAS42019 = 2.0 + # Bust-A-Move Deluxe NPJH50087 = 1.0 ULES00233 = 1.0 From c44afcf462195f8eee0b7b60750f2b2727ed1a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 14:37:56 +0100 Subject: [PATCH 207/715] Typo fix --- Common/VR/VRBase.cpp | 24 ++++++++++++------------ Common/VR/VRBase.h | 2 +- Common/VR/VRFramebuffer.cpp | 12 ++++++------ Common/VR/VRInput.cpp | 8 ++++---- Common/VR/VRRenderer.cpp | 6 +++--- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index c6661f1cf0..ec4a44c703 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -65,17 +65,17 @@ void VR_Init( void* system, const char* name, int version ) { #endif std::vector extensions; - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { extensions.push_back(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME); } else { extensions.push_back(XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME); } extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME); - if (VR_GetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT)) { + if (VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) { extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); } - if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); extensions.push_back("XR_PICO_android_controller_function_ext_enable"); extensions.push_back("XR_PICO_view_state_ext_enable"); @@ -106,7 +106,7 @@ void VR_Init( void* system, const char* name, int version ) { #ifdef ANDROID XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; - if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { ovrJava* java = (ovrJava*)system; instanceCreateInfoAndroid.applicationVM = java->Vm; instanceCreateInfoAndroid.applicationActivity = java->ActivityObject; @@ -121,7 +121,7 @@ void VR_Init( void* system, const char* name, int version ) { exit(1); } - if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrSetEngineVersionPico", (PFN_xrVoidFunction*)(&pfnXrSetEngineVersionPico)); xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStartCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStartCVControllerThreadPico)); xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStopCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStopCVControllerThreadPico)); @@ -155,7 +155,7 @@ void VR_Init( void* system, const char* name, int version ) { } // Get the graphics requirements. - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { PFN_xrGetVulkanGraphicsRequirementsKHR pfnGetVulkanGraphicsRequirementsKHR = NULL; OXR(xrGetInstanceProcAddr( vr_engine.appState.Instance, @@ -182,9 +182,11 @@ void VR_Init( void* system, const char* name, int version ) { vr_initialized = 1; } +#endif + void VR_Destroy( engine_t* engine ) { if (engine == &vr_engine) { - if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { if (pfnXrStopCVControllerThreadPico != nullptr) { pfnXrStopCVControllerThreadPico(engine->appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); } @@ -210,7 +212,7 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu XrGraphicsBindingOpenGLWin32KHR graphicsBindingGL = {}; #endif memset(&sessionCreateInfo, 0, sizeof(sessionCreateInfo)); - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { sessionCreateInfo.next = graphicsBindingVulkan; } else { #ifdef ANDROID @@ -234,7 +236,7 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu ALOGE("Failed to create XR session: %d.", initResult); exit(1); } - if (VR_GetPlatformFLag(VR_PLATFORM_PICO_INIT)) { + if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { pfnXrSetConfigPICO(engine->appState.Session, TRACKING_ORIGIN, "1"); } @@ -264,12 +266,10 @@ engine_t* VR_GetEngine( void ) { return &vr_engine; } -bool VR_GetPlatformFLag(VRPlatformFlag flag) { +bool VR_GetPlatformFlag(VRPlatformFlag flag) { return vr_platform[flag]; } void VR_SetPlatformFLag(VRPlatformFlag flag, bool value) { vr_platform[flag] = value; } - -#endif diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 4e0e1e266a..0893ac7f84 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -192,7 +192,7 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu void VR_LeaveVR( engine_t* engine ); engine_t* VR_GetEngine( void ); -bool VR_GetPlatformFLag(VRPlatformFlag flag); +bool VR_GetPlatformFlag(VRPlatformFlag flag); void VR_SetPlatformFLag(VRPlatformFlag flag, bool value); void ovrApp_Clear(ovrApp* app); diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 2122191bec..1739e1a0de 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -241,7 +241,7 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff } void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { for (int i = 0; i < (int)frameBuffer->TextureSwapChainLength; i++) { vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKColorImages[i], nullptr); vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKDepthImages[i], nullptr); @@ -265,7 +265,7 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { } void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { return (void *)frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; } else { #if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL @@ -297,7 +297,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { ovrFramebuffer_SetCurrent(frameBuffer); - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { #if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL @@ -319,7 +319,7 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = false; // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { #if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL @@ -370,7 +370,7 @@ void ovrRenderer_Destroy(ovrRenderer* renderer) { } void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { #if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL @@ -433,7 +433,7 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { app->SessionActive = (result == XR_SUCCESS); #ifdef ANDROID - if (app->SessionActive && VR_GetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT)) { + if (app->SessionActive && VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) { XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; XrPerfSettingsLevelEXT gpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index 912bbca17f..dec132ab34 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -266,9 +266,9 @@ void IN_VRInit( engine_t *engine ) { handPoseRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_right", NULL, 1, &rightHandPath); XrPath interactionProfilePath = XR_NULL_PATH; - if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST)) { + if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_QUEST)) { OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePath)); - } else if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO)) { + } else if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_PICO)) { OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/pico/neo3_controller", &interactionProfilePath)); } @@ -277,11 +277,11 @@ void IN_VRInit( engine_t *engine ) { int currBinding = 0; - if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST)) { + if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_QUEST)) { bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click"); - } else if (VR_GetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO)) { + } else if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_PICO)) { bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger/click"); bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger/click"); bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/back/click"); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 50fc4c0003..6895ad024f 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -154,7 +154,7 @@ void VR_Recenter(engine_t* engine) { // Create a default stage space to use if SPACE_TYPE_STAGE is not // supported, or calls to xrGetReferenceSpaceBoundsRect fail. spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; - if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) { + if (VR_GetPlatformFlag(VR_PLATFORM_TRACKING_FLOOR)) { spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f; } OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace)); @@ -166,7 +166,7 @@ void VR_Recenter(engine_t* engine) { spaceCreateInfo.poseInReferenceSpace.position.y = 0.0; OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace)); ALOGV("Created stage space"); - if (VR_GetPlatformFLag(VR_PLATFORM_TRACKING_FLOOR)) { + if (VR_GetPlatformFlag(VR_PLATFORM_TRACKING_FLOOR)) { engine->appState.CurrentSpace = engine->appState.StageSpace; } } @@ -211,7 +211,7 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView))); void* vulkanContext = nullptr; - if (VR_GetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN)) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { vulkanContext = &engine->graphicsBindingVulkan; } ovrRenderer_Create(engine->appState.Session, &engine->appState.Renderer, From 0ef39d11d8b2cd56cf70731ae67e3cfe0ba8726d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 15:37:58 +0100 Subject: [PATCH 208/715] Add a dynamic loader for OpenXR so the VR code can link. Make it all build on Windows. --- CMakeLists.txt | 2 + Common/Common.vcxproj | 4 +- Common/Common.vcxproj.filters | 8 +- Common/VR/OpenXRLoader.cpp | 160 ++++++++++++++++++++++++++++++++++ Common/VR/OpenXRLoader.h | 109 +++++++++++++++++++++++ Common/VR/PPSSPPVR.cpp | 18 ++-- Common/VR/PPSSPPVR.h | 33 ------- Common/VR/VRBase.cpp | 20 +++-- Common/VR/VRBase.h | 32 +------ Common/VR/VRRenderer.cpp | 1 + android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 12 files changed, 312 insertions(+), 77 deletions(-) create mode 100644 Common/VR/OpenXRLoader.cpp create mode 100644 Common/VR/OpenXRLoader.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b9084bea3a..12c75eaff3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -507,6 +507,8 @@ if(WIN32) endif() set(CommonVR + Common/VR/OpenXRLoader.cpp + Common/VR/OpenXRLoader.h Common/VR/PPSSPPVR.cpp Common/VR/PPSSPPVR.h Common/VR/VRBase.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 5c085bd0ed..39e804db79 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -557,6 +557,7 @@ + @@ -995,6 +996,7 @@ + @@ -1015,4 +1017,4 @@ - + \ No newline at end of file diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 5c58a6453f..33468b43d8 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -443,6 +443,9 @@ VR + + VR + @@ -839,6 +842,9 @@ VR + + VR + @@ -952,4 +958,4 @@ ext\libpng17 - + \ No newline at end of file diff --git a/Common/VR/OpenXRLoader.cpp b/Common/VR/OpenXRLoader.cpp new file mode 100644 index 0000000000..57b39f85f1 --- /dev/null +++ b/Common/VR/OpenXRLoader.cpp @@ -0,0 +1,160 @@ +#include "Common/VR/OpenXRLoader.h" +#ifdef _WIN32 +#include "Common/CommonWindows.h" +#endif + +#ifdef XR_NO_PROTOTYPES + +PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr; +PFN_xrEnumerateApiLayerProperties xrEnumerateApiLayerProperties; +PFN_xrEnumerateInstanceExtensionProperties xrEnumerateInstanceExtensionProperties; +PFN_xrCreateInstance xrCreateInstance; +PFN_xrDestroyInstance xrDestroyInstance; +PFN_xrGetInstanceProperties xrGetInstanceProperties; +PFN_xrPollEvent xrPollEvent; +PFN_xrResultToString xrResultToString; +PFN_xrStructureTypeToString xrStructureTypeToString; +PFN_xrGetSystem xrGetSystem; +PFN_xrGetSystemProperties xrGetSystemProperties; +PFN_xrEnumerateEnvironmentBlendModes xrEnumerateEnvironmentBlendModes; +PFN_xrCreateSession xrCreateSession; +PFN_xrDestroySession xrDestroySession; +PFN_xrEnumerateReferenceSpaces xrEnumerateReferenceSpaces; +PFN_xrCreateReferenceSpace xrCreateReferenceSpace; +PFN_xrGetReferenceSpaceBoundsRect xrGetReferenceSpaceBoundsRect; +PFN_xrCreateActionSpace xrCreateActionSpace; +PFN_xrLocateSpace xrLocateSpace; +PFN_xrDestroySpace xrDestroySpace; +PFN_xrEnumerateViewConfigurations xrEnumerateViewConfigurations; +PFN_xrGetViewConfigurationProperties xrGetViewConfigurationProperties; +PFN_xrEnumerateViewConfigurationViews xrEnumerateViewConfigurationViews; +PFN_xrEnumerateSwapchainFormats xrEnumerateSwapchainFormats; +PFN_xrCreateSwapchain xrCreateSwapchain; +PFN_xrDestroySwapchain xrDestroySwapchain; +PFN_xrEnumerateSwapchainImages xrEnumerateSwapchainImages; +PFN_xrAcquireSwapchainImage xrAcquireSwapchainImage; +PFN_xrWaitSwapchainImage xrWaitSwapchainImage; +PFN_xrReleaseSwapchainImage xrReleaseSwapchainImage; +PFN_xrBeginSession xrBeginSession; +PFN_xrEndSession xrEndSession; +PFN_xrRequestExitSession xrRequestExitSession; +PFN_xrWaitFrame xrWaitFrame; +PFN_xrBeginFrame xrBeginFrame; +PFN_xrEndFrame xrEndFrame; +PFN_xrLocateViews xrLocateViews; +PFN_xrStringToPath xrStringToPath; +PFN_xrPathToString xrPathToString; +PFN_xrCreateActionSet xrCreateActionSet; +PFN_xrDestroyActionSet xrDestroyActionSet; +PFN_xrCreateAction xrCreateAction; +PFN_xrDestroyAction xrDestroyAction; +PFN_xrSuggestInteractionProfileBindings xrSuggestInteractionProfileBindings; +PFN_xrAttachSessionActionSets xrAttachSessionActionSets; +PFN_xrGetCurrentInteractionProfile xrGetCurrentInteractionProfile; +PFN_xrGetActionStateBoolean xrGetActionStateBoolean; +PFN_xrGetActionStateFloat xrGetActionStateFloat; +PFN_xrGetActionStateVector2f xrGetActionStateVector2f; +PFN_xrGetActionStatePose xrGetActionStatePose; +PFN_xrSyncActions xrSyncActions; +PFN_xrEnumerateBoundSourcesForAction xrEnumerateBoundSourcesForAction; +PFN_xrGetInputSourceLocalizedName xrGetInputSourceLocalizedName; +PFN_xrApplyHapticFeedback xrApplyHapticFeedback; +PFN_xrStopHapticFeedback xrStopHapticFeedback; + +#ifdef _WIN32 +#define dlsym(x, y) GetProcAddress(x, y) +static HMODULE g_xrLibrary; +#else +#define dlsym(x, y) nullptr +void *xrLibrary; +#endif + +#define LOAD_INSTANCE_FUNC(name) (PFN_ ## name)xrGetInstanceProcAddr(instance, #name, (PFN_xrVoidFunction *)(&name)) + + +bool XRLoad() { + if (g_xrLibrary) { + // Already loaded. That's OK. + return true; + } + +#ifdef _WIN32 + g_xrLibrary = LoadLibrary(L"openxr_loader.dll"); + if (!g_xrLibrary) { + return false; + } +#else + void *library = nullptr; +#endif + + // Load the three basic functions. + xrGetInstanceProcAddr = (PFN_xrGetInstanceProcAddr)dlsym(g_xrLibrary, "xrGetInstanceProcAddr"); + xrEnumerateApiLayerProperties = (PFN_xrEnumerateApiLayerProperties)dlsym(g_xrLibrary, "xrEnumerateApiLayerProperties"); + xrEnumerateInstanceExtensionProperties = (PFN_xrEnumerateInstanceExtensionProperties)dlsym(g_xrLibrary, "xrEnumerateInstanceExtensionProperties"); + + // Load the rest. + return true; +} + +void XRLoadInstanceFunctions(XrInstance instance) { + LOAD_INSTANCE_FUNC(xrCreateInstance); + LOAD_INSTANCE_FUNC(xrGetInstanceProcAddr); + LOAD_INSTANCE_FUNC(xrEnumerateApiLayerProperties); + LOAD_INSTANCE_FUNC(xrEnumerateInstanceExtensionProperties); + LOAD_INSTANCE_FUNC(xrCreateInstance); + LOAD_INSTANCE_FUNC(xrDestroyInstance); + LOAD_INSTANCE_FUNC(xrGetInstanceProperties); + LOAD_INSTANCE_FUNC(xrPollEvent); + LOAD_INSTANCE_FUNC(xrResultToString); + LOAD_INSTANCE_FUNC(xrStructureTypeToString); + LOAD_INSTANCE_FUNC(xrGetSystem); + LOAD_INSTANCE_FUNC(xrGetSystemProperties); + LOAD_INSTANCE_FUNC(xrEnumerateEnvironmentBlendModes); + LOAD_INSTANCE_FUNC(xrCreateSession); + LOAD_INSTANCE_FUNC(xrDestroySession); + LOAD_INSTANCE_FUNC(xrEnumerateReferenceSpaces); + LOAD_INSTANCE_FUNC(xrCreateReferenceSpace); + LOAD_INSTANCE_FUNC(xrGetReferenceSpaceBoundsRect); + LOAD_INSTANCE_FUNC(xrCreateActionSpace); + LOAD_INSTANCE_FUNC(xrLocateSpace); + LOAD_INSTANCE_FUNC(xrDestroySpace); + LOAD_INSTANCE_FUNC(xrEnumerateViewConfigurations); + LOAD_INSTANCE_FUNC(xrGetViewConfigurationProperties); + LOAD_INSTANCE_FUNC(xrEnumerateViewConfigurationViews); + LOAD_INSTANCE_FUNC(xrEnumerateSwapchainFormats); + LOAD_INSTANCE_FUNC(xrCreateSwapchain); + LOAD_INSTANCE_FUNC(xrDestroySwapchain); + LOAD_INSTANCE_FUNC(xrEnumerateSwapchainImages); + LOAD_INSTANCE_FUNC(xrAcquireSwapchainImage); + LOAD_INSTANCE_FUNC(xrWaitSwapchainImage); + LOAD_INSTANCE_FUNC(xrReleaseSwapchainImage); + LOAD_INSTANCE_FUNC(xrBeginSession); + LOAD_INSTANCE_FUNC(xrEndSession); + LOAD_INSTANCE_FUNC(xrRequestExitSession); + LOAD_INSTANCE_FUNC(xrWaitFrame); + LOAD_INSTANCE_FUNC(xrBeginFrame); + LOAD_INSTANCE_FUNC(xrEndFrame); + LOAD_INSTANCE_FUNC(xrLocateViews); + LOAD_INSTANCE_FUNC(xrStringToPath); + LOAD_INSTANCE_FUNC(xrPathToString); + LOAD_INSTANCE_FUNC(xrCreateActionSet); + LOAD_INSTANCE_FUNC(xrDestroyActionSet); + LOAD_INSTANCE_FUNC(xrCreateAction); + LOAD_INSTANCE_FUNC(xrDestroyAction); + LOAD_INSTANCE_FUNC(xrSuggestInteractionProfileBindings); + LOAD_INSTANCE_FUNC(xrAttachSessionActionSets); + LOAD_INSTANCE_FUNC(xrGetCurrentInteractionProfile); + LOAD_INSTANCE_FUNC(xrGetActionStateBoolean); + LOAD_INSTANCE_FUNC(xrGetActionStateFloat); + LOAD_INSTANCE_FUNC(xrGetActionStateVector2f); + LOAD_INSTANCE_FUNC(xrGetActionStatePose); + LOAD_INSTANCE_FUNC(xrSyncActions); + LOAD_INSTANCE_FUNC(xrEnumerateBoundSourcesForAction); + LOAD_INSTANCE_FUNC(xrGetInputSourceLocalizedName); + LOAD_INSTANCE_FUNC(xrApplyHapticFeedback); + LOAD_INSTANCE_FUNC(xrStopHapticFeedback); + + // TODO: Load any extensions we need, too. +} + +#endif diff --git a/Common/VR/OpenXRLoader.h b/Common/VR/OpenXRLoader.h new file mode 100644 index 0000000000..e8b4822d86 --- /dev/null +++ b/Common/VR/OpenXRLoader.h @@ -0,0 +1,109 @@ +#pragma once + +//Vulkan +#ifdef VK_USE_NATIVE_LIB +#include +#else +#include "Common/GPU/Vulkan/VulkanLoader.h" +using namespace PPSSPP_VK; +#endif + +#ifdef ANDROID +//OpenXR +#define XR_USE_PLATFORM_ANDROID 1 +#define XR_USE_GRAPHICS_API_OPENGL_ES 1 +#define XR_USE_GRAPHICS_API_VULKAN 1 +#include +#include +#include +#elif defined(_WIN32) +#include "Common/CommonWindows.h" +#include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/VR/OpenXRLoader.h" +#include +#define XR_USE_PLATFORM_WIN32 1 +#define XR_USE_GRAPHICS_API_OPENGL 1 +#define XR_USE_GRAPHICS_API_VULKAN 1 +#define XR_NO_PROTOTYPES 1 +#else +#define XR_USE_GRAPHICS_API_VULKAN 1 +#define XR_NO_PROTOTYPES 1 +#endif + +#include +#include + +#ifdef XR_NO_PROTOTYPES + +extern PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr; +extern PFN_xrEnumerateApiLayerProperties xrEnumerateApiLayerProperties; +extern PFN_xrEnumerateInstanceExtensionProperties xrEnumerateInstanceExtensionProperties; +extern PFN_xrCreateInstance xrCreateInstance; +extern PFN_xrDestroyInstance xrDestroyInstance; +extern PFN_xrGetInstanceProperties xrGetInstanceProperties; +extern PFN_xrPollEvent xrPollEvent; +extern PFN_xrResultToString xrResultToString; +extern PFN_xrStructureTypeToString xrStructureTypeToString; +extern PFN_xrGetSystem xrGetSystem; +extern PFN_xrGetSystemProperties xrGetSystemProperties; +extern PFN_xrEnumerateEnvironmentBlendModes xrEnumerateEnvironmentBlendModes; +extern PFN_xrCreateSession xrCreateSession; +extern PFN_xrDestroySession xrDestroySession; +extern PFN_xrEnumerateReferenceSpaces xrEnumerateReferenceSpaces; +extern PFN_xrCreateReferenceSpace xrCreateReferenceSpace; +extern PFN_xrGetReferenceSpaceBoundsRect xrGetReferenceSpaceBoundsRect; +extern PFN_xrCreateActionSpace xrCreateActionSpace; +extern PFN_xrLocateSpace xrLocateSpace; +extern PFN_xrDestroySpace xrDestroySpace; +extern PFN_xrEnumerateViewConfigurations xrEnumerateViewConfigurations; +extern PFN_xrGetViewConfigurationProperties xrGetViewConfigurationProperties; +extern PFN_xrEnumerateViewConfigurationViews xrEnumerateViewConfigurationViews; +extern PFN_xrEnumerateSwapchainFormats xrEnumerateSwapchainFormats; +extern PFN_xrCreateSwapchain xrCreateSwapchain; +extern PFN_xrDestroySwapchain xrDestroySwapchain; +extern PFN_xrEnumerateSwapchainImages xrEnumerateSwapchainImages; +extern PFN_xrAcquireSwapchainImage xrAcquireSwapchainImage; +extern PFN_xrWaitSwapchainImage xrWaitSwapchainImage; +extern PFN_xrReleaseSwapchainImage xrReleaseSwapchainImage; +extern PFN_xrBeginSession xrBeginSession; +extern PFN_xrEndSession xrEndSession; +extern PFN_xrRequestExitSession xrRequestExitSession; +extern PFN_xrWaitFrame xrWaitFrame; +extern PFN_xrBeginFrame xrBeginFrame; +extern PFN_xrEndFrame xrEndFrame; +extern PFN_xrLocateViews xrLocateViews; +extern PFN_xrStringToPath xrStringToPath; +extern PFN_xrPathToString xrPathToString; +extern PFN_xrCreateActionSet xrCreateActionSet; +extern PFN_xrDestroyActionSet xrDestroyActionSet; +extern PFN_xrCreateAction xrCreateAction; +extern PFN_xrDestroyAction xrDestroyAction; +extern PFN_xrSuggestInteractionProfileBindings xrSuggestInteractionProfileBindings; +extern PFN_xrAttachSessionActionSets xrAttachSessionActionSets; +extern PFN_xrGetCurrentInteractionProfile xrGetCurrentInteractionProfile; +extern PFN_xrGetActionStateBoolean xrGetActionStateBoolean; +extern PFN_xrGetActionStateFloat xrGetActionStateFloat; +extern PFN_xrGetActionStateVector2f xrGetActionStateVector2f; +extern PFN_xrGetActionStatePose xrGetActionStatePose; +extern PFN_xrSyncActions xrSyncActions; +extern PFN_xrEnumerateBoundSourcesForAction xrEnumerateBoundSourcesForAction; +extern PFN_xrGetInputSourceLocalizedName xrGetInputSourceLocalizedName; +extern PFN_xrApplyHapticFeedback xrApplyHapticFeedback; +extern PFN_xrStopHapticFeedback xrStopHapticFeedback; + +// Dynamic loader for OpenXR on desktop platforms. +// On Quest/Pico, we use statically linked loaders provided by the platform owners. +// On Windows (and Linux etc), we're not so lucky - we could link to static libraries, but we really +// don't want to as we still want to function when one is not present. +// +// Similar to our dynamic Vulkan loader. + +bool XRLoad(); +void XRLoadInstanceFunctions(XrInstance instance); + +#else + +inline bool XRLoad() { return true; } +inline void XRLoadInstanceFunctions(XrInstance instance) {} + +#endif diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index e133ebd277..4cec7c42c9 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -1,5 +1,3 @@ -#ifdef OPENXR - #include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/GPU/Vulkan/VulkanContext.h" @@ -396,6 +394,12 @@ void* BindVRFramebuffer() { return VR_BindFramebuffer(VR_GetEngine()); } +inline float clampFloat(float x, float minValue, float maxValue) { + if (x < minValue) return minValue; + if (x > maxValue) return maxValue; + return x; +} + bool StartVRRender() { if (!VR_GetConfig(VR_CONFIG_VIEWPORT_VALID)) { VR_InitRenderer(VR_GetEngine(), IsMultiviewSupported()); @@ -430,8 +434,8 @@ bool StartVRRender() { height = 0; side = 0; } - g_Config.fCameraHeight = std::clamp(height, -10.0f, 10.0f); - g_Config.fCameraSide = std::clamp(side, -10.0f, 10.0f); + g_Config.fCameraHeight = clampFloat(height, -10.0f, 10.0f); + g_Config.fCameraSide = clampFloat(side, -10.0f, 10.0f); //right joystick controls distance and fov float dst = g_Config.fCameraDistance; @@ -445,8 +449,8 @@ bool StartVRRender() { fov = 100; dst = 0; } - g_Config.fCameraDistance = std::clamp(dst, -10.0f, 10.0f); - g_Config.fFieldOfViewPercentage = std::clamp(fov, 100.0f, 200.0f); + g_Config.fCameraDistance = clampFloat(dst, -10.0f, 10.0f); + g_Config.fFieldOfViewPercentage = clampFloat(fov, 100.0f, 200.0f); } // Set customizations @@ -599,5 +603,3 @@ void UpdateVRView(float* leftEye, float* rightEye) { memcpy(dst[index], renderView.M, 16 * sizeof(float)); } } - -#endif diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index dfb38471b1..2dd2d1c11f 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -17,8 +17,6 @@ enum VRCompatFlag { VR_COMPAT_MAX }; -#ifdef OPENXR - // VR app flow integration bool IsVREnabled(); void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name); @@ -45,34 +43,3 @@ bool Is2DVRObject(float* projMatrix, bool ortho); void UpdateVRParams(float* projMatrix); void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye); void UpdateVRView(float* leftEye, float* rightEye); - -#else //dummy integration - -// VR app flow integration -inline bool IsVREnabled() { return false; } -inline void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name) {} -inline void EnterVR(bool firstTime, void* vulkanContext) {} -inline void GetVRResolutionPerEye(int* width, int* height) {} -inline void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {} -inline void UpdateVRSpecialKeys(const KeyInput &key) {} - -// VR games compatibility -inline void PreprocessStepVR(void* step) {} -inline void SetVRCompat(VRCompatFlag flag, long value) {} - -// VR rendering integration -inline void* BindVRFramebuffer() { return nullptr; } -inline bool StartVRRender() { return false; } -inline void FinishVRRender() {} -inline void PreVRFrameRender(int fboIndex) {} -inline void PostVRFrameRender() {} -inline int GetVRFBOIndex() { return 0; } -inline int GetVRPassesCount() { return 1; } -inline bool IsMultiviewSupported() { return false; } -inline bool IsFlatVRScene() { return true; } -inline bool Is2DVRObject(float* projMatrix, bool ortho) { return false; } -inline void UpdateVRParams(float* projMatrix) {} -inline void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) {} -inline void UpdateVRView(float* leftEye, float* rightEye) {} - -#endif diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index ec4a44c703..d6ff987fc4 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -41,12 +41,14 @@ static bool vr_platform[VR_PLATFORM_MAX]; static engine_t vr_engine; int vr_initialized = 0; -#if defined(OPENXR) - void VR_Init( void* system, const char* name, int version ) { if (vr_initialized) return; + if (!XRLoad()) { + return; + } + ovrApp_Clear(&vr_engine.appState); #ifdef ANDROID @@ -68,9 +70,12 @@ void VR_Init( void* system, const char* name, int version ) { if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { extensions.push_back(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME); } else { +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES extensions.push_back(XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME); +#endif } extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME); +#ifdef ANDROID if (VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) { extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); @@ -83,6 +88,7 @@ void VR_Init( void* system, const char* name, int version ) { extensions.push_back("XR_PICO_configs_ext"); extensions.push_back("XR_PICO_reset_sensor"); } +#endif // Create the OpenXR instance. XrApplicationInfo appInfo; @@ -101,7 +107,7 @@ void VR_Init( void* system, const char* name, int version ) { instanceCreateInfo.applicationInfo = appInfo; instanceCreateInfo.enabledApiLayerCount = 0; instanceCreateInfo.enabledApiLayerNames = NULL; - instanceCreateInfo.enabledExtensionCount = extensions.size(); + instanceCreateInfo.enabledExtensionCount = (uint32_t)extensions.size(); instanceCreateInfo.enabledExtensionNames = extensions.data(); #ifdef ANDROID @@ -121,6 +127,8 @@ void VR_Init( void* system, const char* name, int version ) { exit(1); } + XRLoadInstanceFunctions(vr_engine.appState.Instance); + if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrSetEngineVersionPico", (PFN_xrVoidFunction*)(&pfnXrSetEngineVersionPico)); xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStartCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStartCVControllerThreadPico)); @@ -166,6 +174,7 @@ void VR_Init( void* system, const char* name, int version ) { graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR; OXR(pfnGetVulkanGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); } else { +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL; OXR(xrGetInstanceProcAddr( vr_engine.appState.Instance, @@ -175,15 +184,16 @@ void VR_Init( void* system, const char* name, int version ) { XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {}; graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR; OXR(pfnGetOpenGLESGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); +#endif } +#ifdef ANDROID vr_engine.appState.MainThreadTid = gettid(); +#endif vr_engine.appState.SystemId = systemId; vr_initialized = 1; } -#endif - void VR_Destroy( engine_t* engine ) { if (engine == &vr_engine) { if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 0893ac7f84..34e52908d4 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -10,36 +10,10 @@ #define ALOGV(...) printf(__VA_ARGS__) #endif -//Vulkan -#ifdef VK_USE_NATIVE_LIB -#include -#else -#include "Common/GPU/Vulkan/VulkanLoader.h" -using namespace PPSSPP_VK; -#endif +#include "Common/VR/OpenXRLoader.h" -#ifdef ANDROID -//OpenXR -#define XR_USE_PLATFORM_ANDROID 1 -#define XR_USE_GRAPHICS_API_OPENGL_ES 1 -#define XR_USE_GRAPHICS_API_VULKAN 1 -#include -#include -#include -#elif defined(_WIN32) -#include "Common/CommonWindows.h" -#include "Common/GPU/OpenGL/GLCommon.h" -#include -#define XR_USE_PLATFORM_WIN32 1 -#define XR_USE_GRAPHICS_API_OPENGL 1 -#define XR_USE_GRAPHICS_API_VULKAN 1 -#else -#define XR_USE_GRAPHICS_API_VULKAN 1 -#endif - -#include -#include -#include +#define _USE_MATH_DEFINES +#include #ifdef ANDROID diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 6895ad024f..e67d4ecd62 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -4,6 +4,7 @@ #include "VRBase.h" #include "VRInput.h" #include "VRRenderer.h" +#include "OpenXRLoader.h" #include #include diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 8913f641e5..2f3887c3e2 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -72,6 +72,7 @@ SPIRV_CROSS_FILES := \ $(SRC)/ext/SPIRV-Cross/spirv_cross_parsed_ir.cpp VR_FILES := \ + $(SRC)/Common/VR/OpenXRLoader.cpp \ $(SRC)/Common/VR/PPSSPPVR.cpp \ $(SRC)/Common/VR/VRBase.cpp \ $(SRC)/Common/VR/VRFramebuffer.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 7d858e0129..27540dc86f 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -314,6 +314,7 @@ SOURCES_CXX += \ $(COMMONDIR)/TimeUtil.cpp SOURCES_CXX += \ + $(COMMONDIR)/VR/OpenXRLoader.cpp \ $(COMMONDIR)/VR/PPSSPPVR.cpp \ $(COMMONDIR)/VR/VRBase.cpp \ $(COMMONDIR)/VR/VRMath.cpp \ From 162290147fcdac1b42504dc6fa320fe255626c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 15:50:47 +0100 Subject: [PATCH 209/715] UWP build fix. Had to reshuffle some stuff and compile some Vulkan files. --- Common/GPU/Vulkan/VulkanContext.cpp | 31 ---------------------- Common/GPU/Vulkan/VulkanContext.h | 1 - Common/GPU/Vulkan/VulkanLoader.cpp | 34 ++++++++++++++++++++++++- Common/GPU/Vulkan/VulkanLoader.h | 2 ++ Common/VR/OpenXRLoader.cpp | 8 +++--- Common/VR/OpenXRLoader.h | 10 +++++--- Common/VR/PPSSPPVR.cpp | 16 +++++++++--- Common/VR/VRBase.cpp | 6 ++--- Common/VR/VRFramebuffer.cpp | 4 +++ UWP/CommonUWP/CommonUWP.vcxproj | 4 +++ UWP/CommonUWP/CommonUWP.vcxproj.filters | 15 +++++++++++ UWP/PPSSPP_UWPMain.cpp | 4 --- 12 files changed, 85 insertions(+), 50 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 8a69c0f037..389eb6dbbe 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -1372,37 +1372,6 @@ void finalize_glslang() { glslang::FinalizeProcess(); } -const char *VulkanResultToString(VkResult res) { - switch (res) { - case VK_NOT_READY: return "VK_NOT_READY"; - case VK_TIMEOUT: return "VK_TIMEOUT"; - case VK_EVENT_SET: return "VK_EVENT_SET"; - case VK_EVENT_RESET: return "VK_EVENT_RESET"; - case VK_INCOMPLETE: return "VK_INCOMPLETE"; - case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY"; - case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; - case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED"; - case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST"; - case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED"; - case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT"; - case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT"; - case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT"; - case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER"; - case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS"; - case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED"; - case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR"; - case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR"; - case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR"; - case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; - case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR"; - - default: - return "VK_ERROR_...(unknown)"; - } -} - void VulkanDeleteList::Take(VulkanDeleteList &del) { _dbg_assert_(cmdPools_.empty()); _dbg_assert_(descPools_.empty()); diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index 7baf795717..a6f568aa5f 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -461,7 +461,6 @@ enum class GLSLVariant { bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *sourceCode, GLSLVariant variant, std::vector &spirv, std::string *errorMessage); -const char *VulkanResultToString(VkResult res); const char *VulkanColorSpaceToString(VkColorSpaceKHR colorSpace); const char *VulkanFormatToString(VkFormat format); diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index 32984494ce..c6012f001e 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -239,7 +239,6 @@ static VulkanLibraryHandle vulkanLibrary; typedef void *VulkanLibraryHandle; static VulkanLibraryHandle vulkanLibrary; #endif -const char *VulkanResultToString(VkResult res); bool g_vulkanAvailabilityChecked = false; bool g_vulkanMayBeAvailable = false; @@ -274,6 +273,8 @@ static VulkanLibraryHandle VulkanLoadLibrary(const char *logname) { #if PPSSPP_PLATFORM(SWITCH) // Always unavailable, for now. return nullptr; +#elif PPSSPP_PLATFORM(UWP) + return nullptr; #elif PPSSPP_PLATFORM(WINDOWS) return LoadLibrary(L"vulkan-1.dll"); #else @@ -724,3 +725,34 @@ void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledE void VulkanFree() { VulkanFreeLibrary(vulkanLibrary); } + +const char *VulkanResultToString(VkResult res) { + switch (res) { + case VK_NOT_READY: return "VK_NOT_READY"; + case VK_TIMEOUT: return "VK_TIMEOUT"; + case VK_EVENT_SET: return "VK_EVENT_SET"; + case VK_EVENT_RESET: return "VK_EVENT_RESET"; + case VK_INCOMPLETE: return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR"; + + default: + return "VK_ERROR_...(unknown)"; + } +} diff --git a/Common/GPU/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h index b0c14570da..4f2d97d045 100644 --- a/Common/GPU/Vulkan/VulkanLoader.h +++ b/Common/GPU/Vulkan/VulkanLoader.h @@ -254,3 +254,5 @@ bool VulkanLoad(); void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions); void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions); void VulkanFree(); + +const char *VulkanResultToString(VkResult res); diff --git a/Common/VR/OpenXRLoader.cpp b/Common/VR/OpenXRLoader.cpp index 57b39f85f1..4d5f8fb246 100644 --- a/Common/VR/OpenXRLoader.cpp +++ b/Common/VR/OpenXRLoader.cpp @@ -61,12 +61,12 @@ PFN_xrGetInputSourceLocalizedName xrGetInputSourceLocalizedName; PFN_xrApplyHapticFeedback xrApplyHapticFeedback; PFN_xrStopHapticFeedback xrStopHapticFeedback; -#ifdef _WIN32 +#ifdef XR_USE_PLATFORM_WIN32 #define dlsym(x, y) GetProcAddress(x, y) static HMODULE g_xrLibrary; #else #define dlsym(x, y) nullptr -void *xrLibrary; +void *g_xrLibrary; #endif #define LOAD_INSTANCE_FUNC(name) (PFN_ ## name)xrGetInstanceProcAddr(instance, #name, (PFN_xrVoidFunction *)(&name)) @@ -78,13 +78,13 @@ bool XRLoad() { return true; } -#ifdef _WIN32 +#ifdef XR_USE_PLATFORM_WIN32 g_xrLibrary = LoadLibrary(L"openxr_loader.dll"); if (!g_xrLibrary) { return false; } #else - void *library = nullptr; + return false; #endif // Load the three basic functions. diff --git a/Common/VR/OpenXRLoader.h b/Common/VR/OpenXRLoader.h index e8b4822d86..ab174ed50c 100644 --- a/Common/VR/OpenXRLoader.h +++ b/Common/VR/OpenXRLoader.h @@ -18,12 +18,16 @@ using namespace PPSSPP_VK; #include #elif defined(_WIN32) #include "Common/CommonWindows.h" +#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION) +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP #include "Common/GPU/OpenGL/GLCommon.h" +#define XR_USE_GRAPHICS_API_OPENGL 1 +#define XR_USE_PLATFORM_WIN32 1 +#endif +#endif +#define XR_USE_GRAPHICS_API_VULKAN 1 #include "Common/VR/OpenXRLoader.h" #include -#define XR_USE_PLATFORM_WIN32 1 -#define XR_USE_GRAPHICS_API_OPENGL 1 -#define XR_USE_GRAPHICS_API_VULKAN 1 #define XR_NO_PROTOTYPES 1 #else #define XR_USE_GRAPHICS_API_VULKAN 1 diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 4cec7c42c9..537844b073 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -1,12 +1,14 @@ -#include "Common/GPU/OpenGL/GLRenderManager.h" -#include "Common/GPU/Vulkan/VulkanContext.h" - #include "Common/VR/PPSSPPVR.h" #include "Common/VR/VRBase.h" #include "Common/VR/VRInput.h" #include "Common/VR/VRMath.h" #include "Common/VR/VRRenderer.h" +#if XR_USE_GRAPHICS_API_OPENGL +#include "Common/GPU/OpenGL/GLRenderManager.h" +#endif +#include "Common/GPU/Vulkan/VulkanContext.h" + #include "Core/HLE/sceDisplay.h" #include "Core/Config.h" #include "Core/KeyMap.h" @@ -337,6 +339,8 @@ void UpdateVRSpecialKeys(const KeyInput &key) { ================================================================================ */ +#if XR_USE_GRAPHICS_API_OPENGL + void PreprocessSkyplane(GLRStep* step) { // Do not do anything if the scene is not in VR. @@ -378,6 +382,12 @@ void PreprocessStepVR(void* step) { if (vrCompat[VR_COMPAT_SKYPLANE]) PreprocessSkyplane(glrStep); } +#else + +void PreprocessStepVR(void* step) {} + +#endif + void SetVRCompat(VRCompatFlag flag, long value) { vrCompat[flag] = value; } diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index d6ff987fc4..2855a75e1a 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -30,7 +30,7 @@ enum PxrTrackingDof { typedef XrResult (XRAPI_PTR *PFN_xrSetEngineVersionPico)(XrInstance instance,const char* version); typedef XrResult (XRAPI_PTR *PFN_xrStartCVControllerThreadPico)(XrInstance instance,int headSensorState, int handSensorState); typedef XrResult (XRAPI_PTR *PFN_xrStopCVControllerThreadPico)(XrInstance instance,int headSensorState, int handSensorState); -typedef XrResult (XRAPI_PTR *PFN_xrSetConfigPICO) (XrSession instance, enum ConfigsSetEXT configIndex, char* configData); +typedef XrResult (XRAPI_PTR *PFN_xrSetConfigPICO) (XrSession instance, enum ConfigsSetEXT configIndex, const char *configData); PFN_xrSetConfigPICO pfnXrSetConfigPICO = nullptr; PFN_xrSetEngineVersionPico pfnXrSetEngineVersionPico = nullptr; @@ -218,7 +218,7 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu XrSessionCreateInfo sessionCreateInfo = {}; #ifdef ANDROID XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingGL = {}; -#else +#elif XR_USE_GRAPHICS_API_OPENGL XrGraphicsBindingOpenGLWin32KHR graphicsBindingGL = {}; #endif memset(&sessionCreateInfo, 0, sizeof(sessionCreateInfo)); @@ -231,10 +231,10 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu graphicsBindingGL.display = eglGetCurrentDisplay(); graphicsBindingGL.config = eglGetCurrentSurface(EGL_DRAW); graphicsBindingGL.context = eglGetCurrentContext(); + sessionCreateInfo.next = &graphicsBindingGL; #else //TODO:PCVR definition #endif - sessionCreateInfo.next = &graphicsBindingGL; } sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO; sessionCreateInfo.createFlags = 0; diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 1739e1a0de..a3986ee7d4 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -137,6 +137,8 @@ static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBu #endif +#if XR_USE_GRAPHICS_API_VULKAN + static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview, void* context) { @@ -240,6 +242,8 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff return true; } +#endif + void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { for (int i = 0; i < (int)frameBuffer->TextureSwapChainLength; i++) { diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index 90a1c1649c..0415092a9d 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -387,6 +387,7 @@ + @@ -502,6 +503,7 @@ + @@ -526,6 +528,7 @@ + @@ -618,6 +621,7 @@ + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index dd2f6d6fda..15c00bcbfa 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -88,6 +88,9 @@ {a5bfc343-9c3a-43ff-a033-7b0406e13816} + + {096c3d00-fcfa-4877-8cf0-3b10d56b5d72} + @@ -396,6 +399,12 @@ VR + + VR + + + GPU\Vulkan + @@ -733,6 +742,12 @@ VR + + VR + + + GPU\Vulkan + diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index e4ed18b8f2..b734f6e3d2 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -406,10 +406,6 @@ float System_GetPropertyFloat(SystemProperty prop) { } } -bool VulkanMayBeAvailable() { - return false; -} - void System_Toast(const char *str) {} bool System_GetPropertyBool(SystemProperty prop) { From 44106ff2e793346557f22190bce2c86be288299d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 15:58:07 +0100 Subject: [PATCH 210/715] Linking fix for normal Android devices --- Common/VR/OpenXRLoader.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Common/VR/OpenXRLoader.h b/Common/VR/OpenXRLoader.h index ab174ed50c..fa783b7a58 100644 --- a/Common/VR/OpenXRLoader.h +++ b/Common/VR/OpenXRLoader.h @@ -9,13 +9,20 @@ using namespace PPSSPP_VK; #endif #ifdef ANDROID -//OpenXR +#include #define XR_USE_PLATFORM_ANDROID 1 #define XR_USE_GRAPHICS_API_OPENGL_ES 1 #define XR_USE_GRAPHICS_API_VULKAN 1 #include #include -#include + +#if OPENXR +// One of the Android-based headsets. We're linking with a static OpenXR loader. +#else +// Normal Android app, we don't have a loader so use our own dynamic loader, which won't load anything. +#define XR_NO_PROTOTYPES 1 +#endif + #elif defined(_WIN32) #include "Common/CommonWindows.h" #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION) From a5d3af9cb0e2d3f254c1a686e524fb7fcbdd754c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Nov 2022 07:59:01 -0800 Subject: [PATCH 211/715] GPU: Cleanup GetVertTypeID() usage. --- GPU/Common/DrawEngineCommon.cpp | 2 +- GPU/Common/SplineCommon.cpp | 2 +- GPU/Software/TransformUnit.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 35cfb7dfa9..bf6d7a432d 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -184,7 +184,7 @@ void DrawEngineCommon::Resized() { } u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize) { - const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); + const u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode()); VertexDecoder *dec = GetVertexDecoder(vertTypeID); if (vertexSize) *vertexSize = dec->VertexSize(); diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index b2358f401b..c5468e1203 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -507,7 +507,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic if (indices) GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound); - VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24)); + VertexDecoder *origVDecoder = GetVertexDecoder(GetVertTypeID(vertType, gstate.getUVGenMode())); *bytesRead = num_points * origVDecoder->VertexSize(); // Simplify away bones and morph before proceeding diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 043683b88c..795d39635f 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -137,7 +137,7 @@ void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVert } VertexDecoder *SoftwareDrawEngine::FindVertexDecoder(u32 vtype) { - const u32 vertTypeID = (vtype & 0xFFFFFF) | (gstate.getUVGenMode() << 24); + const u32 vertTypeID = GetVertTypeID(vtype, gstate.getUVGenMode()); return DrawEngineCommon::GetVertexDecoder(vertTypeID); } From 66472c39ce1f20089c30022f0dfd5ecc476edcef Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Nov 2022 08:09:01 -0800 Subject: [PATCH 212/715] GPU: Use skinned position always in bounding check. Meanwhile, move to a flag on decoder options instead of global check. --- GPU/Common/DrawEngineCommon.cpp | 10 ++++++++-- GPU/Common/DrawEngineCommon.h | 4 ++-- GPU/Common/SplineCommon.cpp | 4 ++-- GPU/Common/VertexDecoderCommon.cpp | 2 +- GPU/Common/VertexDecoderCommon.h | 1 + GPU/GPUCommon.cpp | 4 ++-- GPU/Software/TransformUnit.cpp | 7 ++++--- Windows/GEDebugger/TabVertices.cpp | 2 ++ unittest/TestVertexJit.cpp | 12 +++++++++--- 9 files changed, 31 insertions(+), 15 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index bf6d7a432d..b1f4ca7049 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -54,6 +54,7 @@ DrawEngineCommon::~DrawEngineCommon() { void DrawEngineCommon::Init() { useHWTransform_ = g_Config.bHardwareTransform; useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation); + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } VertexDecoder *DrawEngineCommon::GetVertexDecoder(u32 vtype) { @@ -181,10 +182,11 @@ void DrawEngineCommon::Resized() { useHWTransform_ = g_Config.bHardwareTransform; useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation); + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize) { - const u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode()); + const u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode); VertexDecoder *dec = GetVertexDecoder(vertTypeID); if (vertexSize) *vertexSize = dec->VertexSize(); @@ -232,7 +234,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex } int bytesRead; - uint32_t vertTypeID = GetVertTypeID(vtype, 0); + uint32_t vertTypeID = GetVertTypeID(vtype, 0, decOptions_.applySkinInDecode); SubmitPrim(&temp[0], nullptr, prim, vertexCount, vertTypeID, cullMode, &bytesRead); DispatchFlush(); @@ -280,7 +282,11 @@ bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *i GetIndexBounds(inds, vertexCount, vertType, &indexLowerBound, &indexUpperBound); } + // Force software skinning. + bool wasApplyingSkinInDecode = decOptions_.applySkinInDecode; + decOptions_.applySkinInDecode = true; NormalizeVertices((u8 *)corners, temp_buffer, (const u8 *)control_points, indexLowerBound, indexUpperBound, vertType); + decOptions_.applySkinInDecode = wasApplyingSkinInDecode; IndexConverter conv(vertType, inds); for (int i = 0; i < vertexCount; i++) { diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index ea14a07884..c0125b28b2 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -52,10 +52,10 @@ enum FBOTexState { FBO_TEX_READ_FRAMEBUFFER, }; -inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { +inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode, bool skinInDecode) { // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it // into the top of the verttype where there are unused bits. - return (vertType & 0xFFFFFF) | (uvGenMode << 24); + return (vertType & 0xFFFFFF) | (uvGenMode << 24) | (skinInDecode << 26); } struct SimpleVertex; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index c5468e1203..6fe6436291 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -507,7 +507,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic if (indices) GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound); - VertexDecoder *origVDecoder = GetVertexDecoder(GetVertTypeID(vertType, gstate.getUVGenMode())); + VertexDecoder *origVDecoder = GetVertexDecoder(GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode)); *bytesRead = num_points * origVDecoder->VertexSize(); // Simplify away bones and morph before proceeding @@ -572,7 +572,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic gstate_c.uv.vOff = 0; } - uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode(), decOptions_.applySkinInDecode); int generatedBytesRead; if (output.count) DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, gstate.getCullMode(), &generatedBytesRead); diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 62eb20ef84..3a77375cba 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -1089,7 +1089,7 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, DEBUG_LOG(G3D, "VTYPE: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc, col, pos, nrm, weighttype, nweights, idx, morphcount); } - skinInDecode = weighttype != 0 && g_Config.bSoftwareSkinning; + skinInDecode = weighttype != 0 && options.applySkinInDecode; if (weighttype) { // && nweights? weightoff = size; diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index d3785e13c9..e4c886cbd4 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -335,6 +335,7 @@ typedef void(*JittedVertexDecoder)(const u8 *src, u8 *dst, int count); struct VertexDecoderOptions { bool expandAllWeightsToFloat; bool expand8BitNormalsToFloat; + bool applySkinInDecode; }; class VertexDecoder { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index b8c80a76ed..ddaf02bab8 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1834,7 +1834,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { // cull mode int cullMode = gstate.getCullMode(); - uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning); drawEngineCommon_->SubmitPrim(verts, inds, prim, count, vertTypeID, cullMode, &bytesRead); // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). // Some games rely on this, they don't bother reloading VADDR and IADDR. @@ -1892,7 +1892,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { goto bail; } else { vertexType = data; - vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode()); + vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning); } break; } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 795d39635f..afd7d15920 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -72,7 +72,7 @@ void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds, } void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) { - uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), decOptions_.applySkinInDecode); int flipCull = cullMode != gstate.getCullMode() ? 1 : 0; // TODO: For now, just setting all dirty. @@ -137,7 +137,7 @@ void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVert } VertexDecoder *SoftwareDrawEngine::FindVertexDecoder(u32 vtype) { - const u32 vertTypeID = GetVertTypeID(vtype, gstate.getUVGenMode()); + const u32 vertTypeID = GetVertTypeID(vtype, gstate.getUVGenMode(), decOptions_.applySkinInDecode); return DrawEngineCommon::GetVertexDecoder(vertTypeID); } @@ -858,7 +858,7 @@ void TransformUnit::SubmitImmVertex(const ClipVertexData &vert, SoftwareDrawEngi break; } - uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), g_Config.bSoftwareSkinning); // This now processes the step with shared logic, given the existing data_. isImmDraw_ = true; SubmitPrimitive(nullptr, nullptr, GE_PRIM_KEEP_PREVIOUS, 0, vertTypeID, nullptr, drawEngine); @@ -958,6 +958,7 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vectorSetVertexType(state.vertType, options); return rowCount_; } diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp index 573247ba38..12dad2f5aa 100644 --- a/unittest/TestVertexJit.cpp +++ b/unittest/TestVertexJit.cpp @@ -545,8 +545,10 @@ static bool TestVertexColor565() { static bool TestVertex8Skin() { VertexDecoderTestHarness dec; + VertexDecoderOptions opts{}; + opts.applySkinInDecode = true; + dec.SetOptions(opts); - g_Config.bSoftwareSkinning = true; for (int i = 0; i < 8 * 12; ++i) { gstate.boneMatrix[i] = 0.0f; } @@ -575,8 +577,10 @@ static bool TestVertex8Skin() { static bool TestVertex16Skin() { VertexDecoderTestHarness dec; + VertexDecoderOptions opts{}; + opts.applySkinInDecode = true; + dec.SetOptions(opts); - g_Config.bSoftwareSkinning = true; for (int i = 0; i < 8 * 12; ++i) { gstate.boneMatrix[i] = 0.0f; } @@ -605,8 +609,10 @@ static bool TestVertex16Skin() { static bool TestVertexFloatSkin() { VertexDecoderTestHarness dec; + VertexDecoderOptions opts{}; + opts.applySkinInDecode = true; + dec.SetOptions(opts); - g_Config.bSoftwareSkinning = true; for (int i = 0; i < 8 * 12; ++i) { gstate.boneMatrix[i] = 0.0f; } From 95cb358fbf6e6f7b781a1a5f0ceca98a814c017e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 17:28:50 +0100 Subject: [PATCH 213/715] Change the "Retain changed textures" option into a compat.ini option. This option benefits so few games and can hurt others, so that it's better that we specifically enable it for known cases like Popolocrois. --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + Core/Config.cpp | 1 - Core/Config.h | 1 - GPU/Common/TextureCacheCommon.cpp | 4 ++-- UI/GameSettingsScreen.cpp | 7 ------- assets/compat.ini | 12 ++++++++++++ libretro/libretro.cpp | 9 --------- 8 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index f59a0da45b..b70d7e788b 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -117,6 +117,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "ForceLowerResolutionForEffectsOn", &flags_.ForceLowerResolutionForEffectsOn); CheckSetting(iniFile, gameID, "AllowDownloadCLUT", &flags_.AllowDownloadCLUT); CheckSetting(iniFile, gameID, "NearestFilteringOnFramebufferCreate", &flags_.NearestFilteringOnFramebufferCreate); + CheckSetting(iniFile, gameID, "SecondaryTextureCache", &flags_.SecondaryTextureCache); } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 5946f1633b..c37541ce7a 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -89,6 +89,7 @@ struct CompatFlags { bool ForceLowerResolutionForEffectsOn; bool AllowDownloadCLUT; bool NearestFilteringOnFramebufferCreate; + bool SecondaryTextureCache; }; struct VRCompat { diff --git a/Core/Config.cpp b/Core/Config.cpp index b8d1408144..0986474080 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -904,7 +904,6 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("VertexDecCache", &g_Config.bVertexCache, false, true, true), ReportedConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, true, true), - ReportedConfigSetting("TextureSecondaryCache", &g_Config.bTextureSecondaryCache, false, true, true), ReportedConfigSetting("VertexDecJit", &g_Config.bVertexDecoderJit, &DefaultCodeGen, false), #ifndef MOBILE_DEVICE diff --git a/Core/Config.h b/Core/Config.h index 1de62adf27..6dc1226858 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -199,7 +199,6 @@ public: bool bVertexCache; bool bTextureBackoffCache; - bool bTextureSecondaryCache; bool bVertexDecoderJit; bool bFullScreen; bool bFullScreenMulti; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index e660bb20f8..53962e7644 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -767,7 +767,7 @@ void TextureCacheCommon::Decimate(bool forcePressure) { } // If enabled, we also need to clear the secondary cache. - if (g_Config.bTextureSecondaryCache && (forcePressure || secondCacheSizeEstimate_ >= TEXCACHE_SECOND_MIN_PRESSURE)) { + if (PSP_CoreParameter().compat.flags().SecondaryTextureCache && (forcePressure || secondCacheSizeEstimate_ >= TEXCACHE_SECOND_MIN_PRESSURE)) { const u32 had = secondCacheSizeEstimate_; for (TexCache::iterator iter = secondCache_.begin(); iter != secondCache_.end(); ) { @@ -2409,7 +2409,7 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) { } // Don't give up just yet. Let's try the secondary cache if it's been invalidated before. - if (g_Config.bTextureSecondaryCache) { + if (PSP_CoreParameter().compat.flags().SecondaryTextureCache) { // Don't forget this one was unreliable (in case we match a secondary entry.) entry->status |= TexCacheEntry::STATUS_UNRELIABLE; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index e46311870b..cf87f56f47 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -545,13 +545,6 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_CONTINUE; }); - CheckBox *texSecondary_ = graphicsSettings->Add(new CheckBox(&g_Config.bTextureSecondaryCache, gr->T("Retain changed textures", "Retain changed textures (speedup, mem hog)"))); - texSecondary_->OnClick.Add([=](EventParams &e) { - settingInfo_->Show(gr->T("RetainChangedTextures Tip", "Makes many games slower, but some games a lot faster"), e.v); - return UI::EVENT_CONTINUE; - }); - texSecondary_->SetDisabledPtr(&g_Config.bSoftwareRendering); - // Seems solid, so we hide the setting. /*CheckBox *vtxJit = graphicsSettings->Add(new CheckBox(&g_Config.bVertexDecoderJit, gr->T("Vertex Decoder JIT"))); diff --git a/assets/compat.ini b/assets/compat.ini index 2fbe053168..bfa2165a19 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1240,3 +1240,15 @@ NPJH50366 = true [AllowDownloadCLUT] # Temporary compatibility option, while working on the GPU CLUT-from-framebuffer path. # Not required for any games now that it works, but might be useful for development. + +[SecondaryTextureCache] +# Was previously the "Retain changed textures" setting. +# See https://github.com/hrydgard/ppsspp/issues/16339#issuecomment-1304826656 + +# Popolocrois +UCJS10005 = true +UCAS40009 = true +ULUS10018 = true +UCJS18003 = true +ULES00291 = true +NPJG00033 = true diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 3716f1989e..ec07b1dc67 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -850,15 +850,6 @@ static void check_variables(CoreParameter &coreParam) g_Config.bTextureBackoffCache = true; } - var.key = "ppsspp_retain_changed_textures"; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (!strcmp(var.value, "disabled")) - g_Config.bTextureSecondaryCache = false; - else - g_Config.bTextureSecondaryCache = true; - } - var.key = "ppsspp_spline_quality"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { From ff23d67bf4e346e30ff696e22989a6ba041b5fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 17:33:42 +0100 Subject: [PATCH 214/715] Remove now-unused lang keys --- assets/lang/ar_AE.ini | 2 -- assets/lang/az_AZ.ini | 2 -- assets/lang/bg_BG.ini | 2 -- assets/lang/ca_ES.ini | 2 -- assets/lang/cz_CZ.ini | 2 -- assets/lang/da_DK.ini | 2 -- assets/lang/de_DE.ini | 2 -- assets/lang/dr_ID.ini | 2 -- assets/lang/es_ES.ini | 2 -- assets/lang/es_LA.ini | 2 -- assets/lang/fa_IR.ini | 2 -- assets/lang/fi_FI.ini | 2 -- assets/lang/fr_FR.ini | 2 -- assets/lang/gl_ES.ini | 2 -- assets/lang/gr_EL.ini | 2 -- assets/lang/he_IL.ini | 2 -- assets/lang/he_IL_invert.ini | 2 -- assets/lang/hr_HR.ini | 2 -- assets/lang/hu_HU.ini | 2 -- assets/lang/id_ID.ini | 2 -- assets/lang/it_IT.ini | 2 -- assets/lang/ja_JP.ini | 2 -- assets/lang/jv_ID.ini | 2 -- assets/lang/ko_KR.ini | 2 -- assets/lang/lo_LA.ini | 2 -- assets/lang/lt-LT.ini | 2 -- assets/lang/ms_MY.ini | 2 -- assets/lang/nl_NL.ini | 2 -- assets/lang/no_NO.ini | 2 -- assets/lang/pl_PL.ini | 2 -- assets/lang/pt_BR.ini | 2 -- assets/lang/pt_PT.ini | 2 -- assets/lang/ro_RO.ini | 2 -- assets/lang/ru_RU.ini | 2 -- assets/lang/sv_SE.ini | 2 -- assets/lang/tg_PH.ini | 2 -- assets/lang/th_TH.ini | 2 -- assets/lang/tr_TR.ini | 2 -- assets/lang/uk_UA.ini | 2 -- assets/lang/vi_VN.ini | 2 -- assets/lang/zh_CN.ini | 2 -- assets/lang/zh_TW.ini | 2 -- 42 files changed, 84 deletions(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 20d525747b..6987e7b3c7 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -550,8 +550,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = ‎وضع التصيير Rendering Resolution = ‎حجم التصيير RenderingMode NonBuffered Tip = ‎أسرع, لكن يمكن أن لا يظهر أي شئ في بعض الألعاب -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = ‎يجعل ألعاب كثيرة بطيئة, لكن بعض الألعاب أسرع Rotation = ‎الدوران Safe = ‎أمن Screen layout = Screen layout diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 26b022eb25..581e08ca3a 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 1c2ba43a4e..e8b2d60613 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 1f823575e8..dc018c04b4 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 6682c46ee5..c190a4e884 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Režim vykreslování Rendering Resolution = Rozlišení vykreslování RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Zachovat změněné textury (někdy pomalejší) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Otočení Safe = Bezpečné Screen layout = Screen layout diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 406dee1abd..de5366d8f5 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rendering tilstand Rendering Resolution = Render opløsning RenderingMode NonBuffered Tip = Hurtigere, men intet vises i nogle spil -Retain changed textures = Behold ændrede textures (nogle gange langsommere) -RetainChangedTextures Tip = Gør mange spil langsommere, men nogle spil er meget hurtigere Rotation = Rotation Safe = Sikker Screen layout = Screen layout diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 0903a464a1..a5129d922e 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Kann Framerate smoother in Spielen machen, die eine Rendering Mode = Rendermodus Rendering Resolution = Renderauflösung RenderingMode NonBuffered Tip = Schneller, aber keine Anzeige in einigen Spielen -Retain changed textures = Veränderte Texturen behalten (manchmal langsamer) -RetainChangedTextures Tip = Macht viele Spiele langsamer, aber einige andere umso schneller Rotation = Drehung Safe = Sicher Screen layout = Screen layout diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index d0176fe3a9..23346118f2 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Pa marrender i Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index a251e5cbb7..b61201985c 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Puede hacer la imagen más fluida in juegos con una Rendering Mode = Modo de renderizado Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Rápido, pero no se verá nada en algunos juegos. -Retain changed textures = Mantener texturas cambiadas -RetainChangedTextures Tip = Hace muchos juegos más lentos, pero unos pocos mucho más rápidos. Rotation = Rotación Safe = Seguro Screen layout = Diseño de pantalla diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 46ad0c39e3..6c7d42d35f 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Puede hacer que la fluidez sea más suave en juegos Rendering Mode = Modo de renderizado Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Acelera, pero no podrá generar gráficos en algunos juegos. -Retain changed textures = Mantener texturas cambiadas -RetainChangedTextures Tip = Ralentiza muchos juegos, pero acelera algunos. Rotation = Rotación Safe = Seguro Screen layout = Disposición de pantalla diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 4ea5d675dc..dba054242f 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = ‎حالت رندرینگ Rendering Resolution = ‎رزولوشن رندرینگ RenderingMode NonBuffered Tip = ‎سریع تر، اما در بعضی بازی ها ممکن است چیزی نشان ندهد -Retain changed textures = ‎کش کردن تکسچر های تغییر یافته (بعضی مواقع کندتر) -RetainChangedTextures Tip = ‎برای بسیاری از بازی ها کندتر و برای بعضی سریع تر Rotation = ‎چرخش Safe = ‎امن Screen layout = Screen layout diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 94dd50c642..8d8aafccb5 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 6c28c420e0..330ded83af 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Peut améliorer la fluidité dans les jeux qui fonct Rendering Mode = Mode de rendu Rendering Resolution = Définition du rendu RenderingMode NonBuffered Tip = Plus rapide, mais pour certains jeux rien ne s'affichera -Retain changed textures = Conserver les textures modifiées (seulement certains jeux) -RetainChangedTextures Tip = Ralentit de nombreux jeux, mais beaucoup plus rapide pour quelques autres Rotation = Rotation Safe = Prudent Screen layout = Disposition de l'écran diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index f644af1246..42c0a81859 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Modo de renderizado Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Seguro Screen layout = Screen layout diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 51df0a1cd9..3f9555e900 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Τρόπος Απεικόνισης Rendering Resolution = Ανάλυση Απεικόνισης RenderingMode NonBuffered Tip = Γρηγορότερο, αλλά σε μερικά αιχνίδια μπορεί να μην εμφανίζει τίποτα -Retain changed textures = Διατηρήστε αλλαγμένων υφών (μερικές φορές αργότερο) -RetainChangedTextures Tip = Κάνει πολλά παιχνίδια πιο αργά, αλλά κάποια άλλα πιο γρήγορα Rotation = Περιστροφή Safe = Ασφαλής Screen layout = Screen layout diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 95cda4cb26..eea8766876 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = מצב מעובד Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index ee1ed7aced..81da08b1d1 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = דבועמ בצמ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 8238d63b17..5b212cf395 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Izlgađiva frameove u igrama koje ih jako malo imaju Rendering Mode = Način prikaza Rendering Resolution = Rezolucija prikaza RenderingMode NonBuffered Tip = Brže, ali ništa može uvući neke igre -Retain changed textures = Ostavi promijenjene teksture (ponekad sporije) -RetainChangedTextures Tip = Usporava mnogo igara, ali neke igre dosta ubrzava Rotation = Rotacija Safe = Sigurno Screen layout = Screen layout diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 13078c4f7f..a18b33795f 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Simábbá teheti az alacsonyabb képkocka számon fu Rendering Mode = Renderelés módja Rendering Resolution = Renderelés felbontása RenderingMode NonBuffered Tip = Gyorsabb, de egyes játékokban nem rajzol ki semmit. -Retain changed textures = Változtatott textúrák megtartása (olykor lassabb) -RetainChangedTextures Tip = Egyes játékokat gyorsít, de sok játékot lassít. Rotation = Forgatás Safe = Biztonságos Screen layout = Screen layout diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 00af881bf1..bfc1724aa4 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Dapat membuat laju bingkai lebih lancar dalam permai Rendering Mode = Mode pelukisan Rendering Resolution = Resolusi pelukisan RenderingMode NonBuffered Tip = Lebih cepat, namun mungkin tidak ada gambar di beberapa permainan -Retain changed textures = Tahan tekstur yang berubah (adakalanya lambat) -RetainChangedTextures Tip = Membuat beberapa permainan lambat, namun beberapa lainnya sangat cepat Rotation = Rotasi Safe = Aman Screen layout = Tata letak layar diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index e52113462f..10453b2a13 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -543,8 +543,6 @@ RenderDuplicateFrames Tip = Può migliorare la fluidità nei giochi che funziona Rendering Mode = Modalità di Rendering Rendering Resolution = Rendering della Risoluzione RenderingMode NonBuffered Tip = Veloce, ma potrebbe generare dei glitch in alcuni giochi -Retain changed textures = Conserva le textures modificate (a volte è lento) -RetainChangedTextures Tip = Rallenta molti giochi, ma alcuni saranno velocizzati Rotation = Rotazione Safe = Sicuro Screen layout = Disposizione dello schermo diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 10c66c47f1..dfe1a86e3a 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = フレームレートが低いゲームでフレー Rendering Mode = レンダリングモード Rendering Resolution = レンダリング解像度 RenderingMode NonBuffered Tip = 高速ですが何も表示されなくなるゲームがあるかもしれません -Retain changed textures = 変更したテクスチャを保持する (低速化する場合がある) -RetainChangedTextures Tip = 多くのゲームが低速化しますが、かなり速くなるゲームもあります Rotation = 向き Safe = セーフ Screen layout = 画面のレイアウト diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 016ae0e857..da4130fb2b 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Mode Rendering Rendering Resolution = Rendering résolusi RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Makaryakke diganti tekstur (kadhangkala luwih alon) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotasi Safe = Aman Screen layout = Screen layout diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index d08d55dd14..0cdd1a11e3 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -541,8 +541,6 @@ RenderDuplicateFrames Tip = 낮은 프레임 속도에서 실행되는 게임에 Rendering Mode = 렌더링 모드 Rendering Resolution = 렌더링 해상도 RenderingMode NonBuffered Tip = 더 빠르지만 일부 게임에서는 아무 것도 표현되지 않을 수 있습니다. -Retain changed textures = 변경된 텍스처 유지 (때로는 느림) -RetainChangedTextures Tip = 많은 게임을 느리게 하지만 일부 게임은 훨씬 빠르게 만듭니다. Rotation = 회전 Safe = 안전 Screen layout = 화면 레이아웃 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index dad15456b5..1409815abc 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = ໂໝດການສະແດງຜົນ Rendering Resolution = ຄວາມລະອຽດຂອງການສະແດງຜົນ RenderingMode NonBuffered Tip = ໄວຂຶ້ນແທ້, ແຕ່ອາດມີອາການຈໍດຳໃນບາງເກມ -Retain changed textures = ຮັກສາການປ່ຽນແປງຂອງພື້ນຜິວ (ຊ້າບາງເທື່ອ) -RetainChangedTextures Tip = ບາງເກມໃຊ້ແລ້ວຄວາມໄວຫຼຸດລົງ ແຕ່ບາງເກມຄວາມໄວກໍເພີ່ມຂຶ້ນ Rotation = ໝຸນຈໍ Safe = ປອດໄພ Screen layout = Screen layout diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 917e171242..aff20af2e2 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rodymo režimas Rendering Resolution = Rodymo rezoliucija RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 5a6687e035..3cd85dd7c4 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Mod rendering Rendering Resolution = Resolusi rendering RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index ad38f550cb..9b8c2cef4a 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Weergavemodus Rendering Resolution = Renderresolutie RenderingMode NonBuffered Tip = Sneller, maar mogelijk wordt in sommige games niets gerenderd -Retain changed textures = Gewijzigde textures behouden (soms trager) -RetainChangedTextures Tip = Maakt vele games trager, maar sommige games veel sneller Rotation = Rotatie Safe = Veilig Screen layout = Screen layout diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 70163c25c0..132178a7e6 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index e963535aee..82a63c4757 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Tryb renderowania Rendering Resolution = Rozdzielczość renderowania RenderingMode NonBuffered Tip = Szybsze, ale niektóre gry mogą się nie wyświetlać -Retain changed textures = Zachowuj zmienione tekstury (czasem wolniejsze) -RetainChangedTextures Tip = Spowalnia wiele gier, ale mocno przyspiesza kilka innych Rotation = Obrót Safe = Bezpieczne Screen layout = Screen layout diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 6d5b63cdcf..952c540f0b 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -565,8 +565,6 @@ RenderDuplicateFrames Tip = Pode tornar a taxa dos frames mais suave em jogos qu Rendering Mode = Modo de renderização Rendering Resolution = Resolução da renderização RenderingMode NonBuffered Tip = Mais rápido, mas nada pode ser desenhado em alguns jogos -Retain changed textures = Reter texturas mudadas (as vezes mais lento) -RetainChangedTextures Tip = Torna muitos jogos mais lentos mas alguns jogos muito mais rápidos Rotation = Rotação Safe = Seguro Screen layout = Esquema da tela diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index b50d6f0d95..3027a3c81e 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -565,8 +565,6 @@ RenderDuplicateFrames Tip = Pode tornar a taxa dos quadros mais suave em jogos q Rendering Mode = Modo de renderização Rendering Resolution = Resolução da renderização RenderingMode NonBuffered Tip = Mais rápido, mas poderá não ser desenhado nada em alguns jogos -Retain changed textures = Reter texturas mudadas (as vezes mais lento) -RetainChangedTextures Tip = Torna muitos jogos mais lentos mas alguns jogos muito mais rápidos Rotation = Rotação Safe = Seguro Screen layout = Esquema da tela diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 0ec247f441..055ff8f9ff 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Mod Afișare Rendering Resolution = Rezoluție Afișare RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Sigur Screen layout = Screen layout diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 35b73386d5..d3c867b2fe 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -543,8 +543,6 @@ RenderDuplicateFrames Tip = Может сгладить частоту кадр Rendering Mode = Режим рендеринга Rendering Resolution = Разрешение рендеринга RenderingMode NonBuffered Tip = Быстрее, но ничего не отображает в некоторых играх -Retain changed textures = Сохранять измененные текстуры (иногда медленнее) -RetainChangedTextures Tip = Делает много игр медленнее, но некоторые - намного быстрее Rotation = Ориентация Safe = Безопасно Screen layout = Расположение экрана diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index fbacbb1219..d4bedc6d5f 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Renderingsläge Rendering Resolution = Renderingsupplösning RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Behåll ändrade texturer i cachen (ibland långsammare) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 5afd25561b..1dca37dcc5 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Uri ng Rendering Rendering Resolution = Resolusyon ng rendering RenderingMode NonBuffered Tip = Mabilis, pero minsan wala kang makikita sa laro, blanko -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotasyon Safe = Safe Screen layout = Screen layout diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index c63fa3125b..6cdb15874c 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = ช่วยให้ภาพดูลื่นต Rendering Mode = โหมดที่ใช้ในการแสดงผล Rendering Resolution = ความละเอียดในการแสดงผลภาพ RenderingMode NonBuffered Tip = เร็วขึ้นก็จริง แต่มีผลข้างเคียงในบางเกมอาจเกิดอาการจอดำ -Retain changed textures = รักษาความเปลี่ยนแปลงของพื้นผิว (ช้าลงในบางครั้ง) -RetainChangedTextures Tip = มีหลายเกมที่ปรับใช้แล้วความเร็วตกลง แต่ในบางเกมความเร็วก็เพิ่มขึ้น Rotation = หมุนจอ Safe = ปลอดภัย Screen layout = เค้าโครงหน้าจอ diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 4af52fed3c..4a98ecfeb9 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -545,8 +545,6 @@ RenderDuplicateFrames Tip = Daha düşük kare hızlarında çalışan oyunlarda Rendering Mode = İşleme modu Rendering Resolution = İşleme çözünürlüğü RenderingMode NonBuffered Tip = Daha hızlıdır, ancak bazı oyunlarda hiçbir şey çizilmeyebilir -Retain changed textures = Değişen dokuları koruyun (bazen daha yavaştır) -RetainChangedTextures Tip = Çoğu oyunu yavaşlatır ama bazı oyunları çok hızlandırır. Rotation = Rotasyon Safe = Güvenli Screen layout = Ekran düzeni diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index b6ec199493..b4581397ae 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Можна зробити більш плавний Rendering Mode = Режим рендерингу Rendering Resolution = Розширення рендерингу RenderingMode NonBuffered Tip = Швидше, але в деяких іграх нічого не може -Retain changed textures = Зберігати змінені текстури (іноді повільніше) -RetainChangedTextures Tip = Багато ігор робить повільніше, але деякі ігри набагато швидшими Rotation = Орієнтація: Safe = Безпечно Screen layout = Screen layout diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 40e6bb7b30..c1593c6c33 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Chế độ kết xuất Rendering Resolution = Độ phân giải kết xuất RenderingMode NonBuffered Tip = Nhanh hơn, nhưng một số trò chơi thì bị lỗi -Retain changed textures = Giữ lại textures (thỉnh thoảng sẽ bị chậm) -RetainChangedTextures Tip = Làm cho một số trò chơi chậm hơn, nhưng cũng có một số trò chơi nhanh hơn. Rotation = Xoay màn hình Safe = An toàn Screen layout = Screen layout diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 9ca27412e8..3d2682c3d6 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -542,8 +542,6 @@ RenderDuplicateFrames Tip = 在较低帧率的游戏中可以使帧速率更平 Rendering Mode = 渲染模式 Rendering Resolution = 渲染分辨率 RenderingMode NonBuffered Tip = 更快,但可能在某些游戏中丢失特效 -Retain changed textures = 保留已更改的纹理(有时更慢) -RetainChangedTextures Tip = 使较多游戏减速, 但有些游戏可能变快很多 Rotation = 旋转 Safe = 安全 Screen layout = 屏幕布局 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index e94959fd9e..7b74b3e4a3 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -541,8 +541,6 @@ RenderDuplicateFrames Tip = 可以使以較低影格速率執行的遊戲更加 Rendering Mode = 轉譯模式 Rendering Resolution = 轉譯解析度 RenderingMode NonBuffered Tip = 更快,但在某些遊戲中可能無法繪圖 -Retain changed textures = 保留變更的紋理 (有時會更慢) -RetainChangedTextures Tip = 使很多遊戲變慢,但某些遊戲會變快許多 Rotation = 旋轉 Safe = 安全 Screen layout = 螢幕版面配置 From 09c0ebd3ca4ba3caba229b1e970174527c4243ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 17:40:33 +0100 Subject: [PATCH 215/715] Windows ARM/ARM64 buildfix --- Common/VR/OpenXRLoader.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Common/VR/OpenXRLoader.h b/Common/VR/OpenXRLoader.h index fa783b7a58..ce6613ec5e 100644 --- a/Common/VR/OpenXRLoader.h +++ b/Common/VR/OpenXRLoader.h @@ -27,8 +27,10 @@ using namespace PPSSPP_VK; #include "Common/CommonWindows.h" #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION) #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP +#if defined(_M_IX86) || defined(_M_X64) #include "Common/GPU/OpenGL/GLCommon.h" #define XR_USE_GRAPHICS_API_OPENGL 1 +#endif #define XR_USE_PLATFORM_WIN32 1 #endif #endif From 6c36f03a0dc35cccf366363ceaed52b470782835 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Nov 2022 08:40:54 -0800 Subject: [PATCH 216/715] GPU: Purify vertTypeIsSkinningEnabled(). --- GPU/Common/DrawEngineCommon.cpp | 8 +++----- GPU/Common/DrawEngineCommon.h | 2 +- GPU/Common/ShaderId.cpp | 4 ++-- GPU/Common/ShaderId.h | 2 +- GPU/Common/SoftwareTransformCommon.cpp | 2 +- GPU/D3D11/DrawEngineD3D11.cpp | 10 +++++----- GPU/D3D11/DrawEngineD3D11.h | 2 +- GPU/D3D11/GPU_D3D11.cpp | 2 +- GPU/D3D11/ShaderManagerD3D11.cpp | 4 ++-- GPU/D3D11/ShaderManagerD3D11.h | 2 +- GPU/Directx9/DrawEngineDX9.cpp | 6 +++--- GPU/Directx9/GPU_DX9.cpp | 4 ++-- GPU/Directx9/ShaderManagerDX9.cpp | 6 +++--- GPU/Directx9/ShaderManagerDX9.h | 2 +- GPU/GLES/DrawEngineGLES.cpp | 4 ++-- GPU/GLES/GPU_GLES.cpp | 4 ++-- GPU/GLES/ShaderManagerGLES.cpp | 6 +++--- GPU/GLES/ShaderManagerGLES.h | 2 +- GPU/GPUState.cpp | 5 +---- GPU/Software/TransformUnit.cpp | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 8 ++++---- GPU/Vulkan/GPU_Vulkan.cpp | 2 +- GPU/Vulkan/ShaderManagerVulkan.cpp | 4 ++-- GPU/Vulkan/ShaderManagerVulkan.h | 2 +- 24 files changed, 45 insertions(+), 50 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index b1f4ca7049..e02da46179 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -52,9 +52,7 @@ DrawEngineCommon::~DrawEngineCommon() { } void DrawEngineCommon::Init() { - useHWTransform_ = g_Config.bHardwareTransform; - useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation); - decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; + NotifyConfigChanged(); } VertexDecoder *DrawEngineCommon::GetVertexDecoder(u32 vtype) { @@ -170,7 +168,7 @@ static Vec3f ScreenToDrawing(const Vec3f& coords) { return ret; } -void DrawEngineCommon::Resized() { +void DrawEngineCommon::NotifyConfigChanged() { decJitCache_->Clear(); lastVType_ = -1; dec_ = nullptr; @@ -838,7 +836,7 @@ void DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti numDrawCalls++; vertexCountInDrawCalls_ += vertexCount; - if (g_Config.bSoftwareSkinning && (vertTypeID & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (vertTypeID & GE_VTYPE_WEIGHT_MASK)) { DecodeVertsStep(decoded, decodeCounter_, decodedVerts_); decodeCounter_++; } diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index c0125b28b2..4b62f48c14 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -105,7 +105,7 @@ public: std::vector DebugGetVertexLoaderIDs(); std::string DebugGetVertexLoaderString(std::string id, DebugShaderStringType stringType); - virtual void Resized(); + virtual void NotifyConfigChanged(); bool IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index aee52476cf..0f034c7709 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -67,7 +67,7 @@ std::string VertexShaderDesc(const VShaderID &id) { return desc.str(); } -void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { +void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) { bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0; bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP); @@ -118,7 +118,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, } // Bones. - bool enableBones = vertTypeIsSkinningEnabled(vertType); + bool enableBones = !useSkinInDecode && vertTypeIsSkinningEnabled(vertType); id.SetBit(VS_BIT_ENABLE_BONES, enableBones); if (enableBones) { id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1); diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index effe330763..06b252d87d 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -275,7 +275,7 @@ namespace Draw { class Bugs; } -void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); +void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode); // Generates a compact string that describes the shader. Useful in a list to get an overview // of the current flora of shaders. std::string VertexShaderDesc(const VShaderID &id); diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 0f841d1709..dc86e9ec13 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -204,7 +204,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt vscale /= gstate_c.curTextureHeight; } - bool skinningEnabled = vertTypeIsSkinningEnabled(vertType); + bool skinningEnabled = vertTypeIsSkinningEnabled(vertType) && !g_Config.bSoftwareSkinning; const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index c5c4669ba9..2a537a83a3 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -130,8 +130,8 @@ void DrawEngineD3D11::ClearInputLayoutMap() { inputLayoutMap_.Clear(); } -void DrawEngineD3D11::Resized() { - DrawEngineCommon::Resized(); +void DrawEngineD3D11::NotifyConfigChanged() { + DrawEngineCommon::NotifyConfigChanged(); ClearInputLayoutMap(); } @@ -365,7 +365,7 @@ void DrawEngineD3D11::DoFlush() { // Cannot cache vertex data with morph enabled. bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK); // Also avoid caching when software skinning. - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) useCache = false; if (useCache) { @@ -538,7 +538,7 @@ rotateVBO: D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); @@ -648,7 +648,7 @@ rotateVBO: if (result.action == SW_DRAW_PRIMITIVES) { D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering()); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index ca7fb04dbb..03f5f47ad7 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -150,7 +150,7 @@ public: void ClearTrackedVertexArrays() override; - void Resized() override; + void NotifyConfigChanged() override; void ClearInputLayoutMap(); diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 19155b0df5..d1c5edcce3 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -176,7 +176,7 @@ void GPU_D3D11::BeginHostFrame() { if (resized_) { gstate_c.useFlags = CheckGPUFeatures(); framebufferManager_->Resized(); - drawEngine_.Resized(); + drawEngine_.NotifyConfigChanged(); textureCache_->NotifyConfigChanged(); shaderManagerD3D11_->DirtyLastShader(); resized_ = false; diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 0c9fec1817..f8788f6df5 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -179,13 +179,13 @@ void ShaderManagerD3D11::BindUniforms() { context_->PSSetConstantBuffers(0, 1, ps_cbs); } -void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { +void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) { VShaderID VSID; FShaderID FSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { VSID = lastVSID_; } diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h index 0f7a297965..d239daff8f 100644 --- a/GPU/D3D11/ShaderManagerD3D11.h +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -85,7 +85,7 @@ public: ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel); ~ShaderManagerD3D11(); - void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); + void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode); void ClearShaders(); void DirtyLastShader() override; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 8d0bac74ea..40790c1648 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -349,7 +349,7 @@ void DrawEngineDX9::DoFlush() { // Cannot cache vertex data with morph enabled. bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK); // Also avoid caching when software skinning. - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) useCache = false; if (useCache) { @@ -522,7 +522,7 @@ rotateVBO: ApplyDrawState(prim); ApplyDrawStateLate(); - VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, pipelineState_); + VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_); IDirect3DVertexDeclaration9 *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); if (pHardwareVertexDecl) { @@ -613,7 +613,7 @@ rotateVBO: ApplyDrawStateLate(); - VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, pipelineState_); + VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_); if (result.action == SW_DRAW_PRIMITIVES) { if (result.setStencil) { diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 32d9d248c4..beb701796a 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -165,9 +165,9 @@ void GPU_DX9::BeginHostFrame() { if (resized_) { gstate_c.useFlags = CheckGPUFeatures(); framebufferManager_->Resized(); - drawEngine_.Resized(); - shaderManagerDX9_->DirtyShader(); + drawEngine_.NotifyConfigChanged(); textureCache_->NotifyConfigChanged(); + shaderManagerDX9_->DirtyShader(); resized_ = false; } } diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 1e56e5ab37..0b419cfe76 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -544,11 +544,11 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays lastPShader_ = nullptr; } -VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, const ComputedPipelineState &pipelineState) { +VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) { VShaderID VSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { VSID = lastVSID_; } @@ -597,7 +597,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat } delete vs; - ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat, useSkinInDecode); // TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure // that that shader ID is not used when computing the linked shader ID below, because then IDs won't match diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index 9c7404d856..6ee812b2e6 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -78,7 +78,7 @@ public: ~ShaderManagerDX9(); void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected - VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, const ComputedPipelineState &pipelineState); + VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState); void DirtyShader(); void DirtyLastShader() override; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index dd3395abd2..318cb19a02 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -267,7 +267,7 @@ void DrawEngineGLES::DoFlush() { GEPrimitiveType prim = prevPrim_; VShaderID vsid; - Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, &vsid); + Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, &vsid); GLRBuffer *vertexBuffer = nullptr; GLRBuffer *indexBuffer = nullptr; @@ -278,7 +278,7 @@ void DrawEngineGLES::DoFlush() { int vertexCount = 0; bool useElements = true; - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { // If software skinning, we've already predecoded into "decoded". So push that content. size_t size = decodedVerts_ * dec_->GetDecVtxFmt().stride; u8 *dest = (u8 *)frameData.pushVertex->Push(size, &vertexBufferOffset, &vertexBuffer); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index b6b2b6a661..1798960b4d 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -291,9 +291,9 @@ void GPU_GLES::BeginHostFrame() { if (resized_) { gstate_c.useFlags = CheckGPUFeatures(); framebufferManager_->Resized(); - drawEngine_.Resized(); - shaderManagerGL_->DirtyShader(); + drawEngine_.NotifyConfigChanged(); textureCache_->NotifyConfigChanged(); + shaderManagerGL_->DirtyShader(); resized_ = false; } diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index e4a6350de1..c976e79b5c 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -754,10 +754,10 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { return new Shader(render_, codeBuffer_, desc, params); } -Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID) { +Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID) { if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { *VSID = lastVSID_; } @@ -788,7 +788,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess // Can still work with software transform. VShaderID vsidTemp; - ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat); + ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat, useSkinInDecode); vs = CompileVertexShader(vsidTemp); } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index a937318dd1..97ffe6c010 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -161,7 +161,7 @@ public: // This is the old ApplyShader split into two parts, because of annoying information dependencies. // If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards. - Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID); + Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID); LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, u32 vertType, bool useBufferedRendering); void DeviceLost(); diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index 374816fa76..bae93b34b1 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -261,10 +261,7 @@ void GPUgstate::Restore(u32_le *ptr) { } bool vertTypeIsSkinningEnabled(u32 vertType) { - if (g_Config.bSoftwareSkinning) - return false; - else - return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); + return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); } struct GPUStateCache_v0 { diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index afd7d15920..731e4078f3 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -257,7 +257,7 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { state->enableLighting = gstate.isLightingEnabled(); state->enableFog = gstate.isFogEnabled(); state->readUV = !gstate.isModeClear() && gstate.isTextureMapEnabled() && vreader.hasUV(); - state->readWeights = vreader.skinningEnabled() && state->enableTransform; + state->readWeights = vreader.skinningEnabled() && state->enableTransform && !g_Config.bSoftwareSkinning; state->negateNormals = gstate.areNormalsReversed(); state->uvGenMode = gstate.getUVGenMode(); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index f54afee3a9..01c356f34d 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -599,7 +599,7 @@ void DrawEngineVulkan::DoFlush() { // Also avoid caching when software skinning. VkBuffer vbuf = VK_NULL_HANDLE; VkBuffer ibuf = VK_NULL_HANDLE; - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { useCache = false; } @@ -739,7 +739,7 @@ void DrawEngineVulkan::DoFlush() { break; } } else { - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { // If software skinning, we've already predecoded into "decoded". So push that content. VkDeviceSize size = decodedVerts_ * dec_->GetDecVtxFmt().stride; u8 *dest = (u8 *)frameData.pushVertex->Push(size, &vbOffset, &vbuf); @@ -784,7 +784,7 @@ void DrawEngineVulkan::DoFlush() { VulkanFragmentShader *fshader = nullptr; VulkanGeometryShader *gshader = nullptr; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); if (!vshader) { // We're screwed. return; @@ -919,7 +919,7 @@ void DrawEngineVulkan::DoFlush() { VulkanFragmentShader *fshader = nullptr; VulkanGeometryShader *gshader = nullptr; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); // usehwtransform + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0); if (!pipeline || !pipeline->pipeline) { diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 12d0328f98..754ef6ffce 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -292,7 +292,7 @@ void GPU_Vulkan::BeginHostFrame() { // In case the GPU changed. BuildReportingInfo(); framebufferManager_->Resized(); - drawEngine_.Resized(); + drawEngine_.NotifyConfigChanged(); textureCache_->NotifyConfigChanged(); resized_ = false; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 6356f43e0a..1d478325da 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -280,11 +280,11 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) { return dirty; } -void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { +void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) { VShaderID VSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { VSID = lastVSID_; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h index 88f138d923..8e6ce2636a 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.h +++ b/GPU/Vulkan/ShaderManagerVulkan.h @@ -115,7 +115,7 @@ public: void DeviceLost(); void DeviceRestore(Draw::DrawContext *draw); - void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); + void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode); void ClearShaders(); void DirtyShader(); void DirtyLastShader() override; From 7880eb15c103ec0e95344446f2d4d296f02384e8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Nov 2022 08:44:22 -0800 Subject: [PATCH 217/715] softgpu: Always use software skinning. There's only software skinning, after all. --- GPU/Common/VertexDecoderCommon.h | 2 -- GPU/Software/TransformUnit.cpp | 34 ++++++++------------------------ GPU/Software/TransformUnit.h | 1 + 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index e4c886cbd4..7c2dcb2cfc 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -300,8 +300,6 @@ public: bool hasNormal() const { return decFmt_.nrmfmt != 0; } bool hasUV() const { return decFmt_.uvfmt != 0; } bool isThrough() const { return (vtype_ & GE_VTYPE_THROUGH) != 0; } - bool skinningEnabled() const { return vertTypeIsSkinningEnabled(vtype_); } - int numBoneWeights() const { return vertTypeGetNumBoneWeights(vtype_); } void Goto(int index) { data_ = base_ + index * decFmt_.stride; } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 731e4078f3..bc1f8679eb 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -62,6 +62,11 @@ SoftwareDrawEngine::~SoftwareDrawEngine() { FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); } +void SoftwareDrawEngine::NotifyConfigChanged() { + DrawEngineCommon::NotifyConfigChanged(); + decOptions_.applySkinInDecode = true; +} + void SoftwareDrawEngine::DispatchFlush() { transformUnit.Flush("debug"); } @@ -72,7 +77,7 @@ void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds, } void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) { - uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), decOptions_.applySkinInDecode); + uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), true); int flipCull = cullMode != gstate.getCullMode() ? 1 : 0; // TODO: For now, just setting all dirty. @@ -137,7 +142,7 @@ void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVert } VertexDecoder *SoftwareDrawEngine::FindVertexDecoder(u32 vtype) { - const u32 vertTypeID = GetVertTypeID(vtype, gstate.getUVGenMode(), decOptions_.applySkinInDecode); + const u32 vertTypeID = GetVertTypeID(vtype, gstate.getUVGenMode(), true); return DrawEngineCommon::GetVertexDecoder(vertTypeID); } @@ -245,7 +250,6 @@ struct TransformState { bool enableLighting : 1; bool enableFog : 1; bool readUV : 1; - bool readWeights : 1; bool negateNormals : 1; uint8_t uvGenMode : 2; uint8_t matrixMode : 2; @@ -257,7 +261,6 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { state->enableLighting = gstate.isLightingEnabled(); state->enableFog = gstate.isFogEnabled(); state->readUV = !gstate.isModeClear() && gstate.isTextureMapEnabled() && vreader.hasUV(); - state->readWeights = vreader.skinningEnabled() && state->enableTransform && !g_Config.bSoftwareSkinning; state->negateNormals = gstate.areNormalsReversed(); state->uvGenMode = gstate.getUVGenMode(); @@ -344,27 +347,6 @@ ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformS if (state.negateNormals) normal = -normal; - if (state.readWeights) { - float W[8] = { 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }; - vreader.ReadWeights(W); - - Vec3 tmppos(0.f, 0.f, 0.f); - Vec3 tmpnrm(0.f, 0.f, 0.f); - - for (int i = 0; i < vreader.numBoneWeights(); ++i) { - Vec3 step = Vec3ByMatrix43(pos, gstate.boneMatrix + i * 12); - tmppos += step * W[i]; - if (vreader.hasNormal()) { - step = Norm3ByMatrix43(normal, gstate.boneMatrix + i * 12); - tmpnrm += step * W[i]; - } - } - - pos = tmppos; - if (vreader.hasNormal()) - normal = tmpnrm; - } - if (vreader.hasColor0()) { vreader.ReadColor0_8888((u8 *)&vertex.v.color0); } else { @@ -858,7 +840,7 @@ void TransformUnit::SubmitImmVertex(const ClipVertexData &vert, SoftwareDrawEngi break; } - uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), g_Config.bSoftwareSkinning); + uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), true); // This now processes the step with shared logic, given the existing data_. isImmDraw_ = true; SubmitPrimitive(nullptr, nullptr, GE_PRIM_KEEP_PREVIOUS, 0, vertTypeID, nullptr, drawEngine); diff --git a/GPU/Software/TransformUnit.h b/GPU/Software/TransformUnit.h index 3c022523d2..a55c824a91 100644 --- a/GPU/Software/TransformUnit.h +++ b/GPU/Software/TransformUnit.h @@ -171,6 +171,7 @@ public: SoftwareDrawEngine(); ~SoftwareDrawEngine(); + void NotifyConfigChanged() override; void DispatchFlush() override; void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int cullMode, int *bytesRead) override; void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) override; From 3de2557ecb50aba2ea59e61c4900918a5d99b725 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Nov 2022 08:55:07 -0800 Subject: [PATCH 218/715] GPU: Always skin in decode for software transform. --- GPU/Common/SoftwareTransformCommon.cpp | 81 +++++--------------------- GPU/D3D11/DrawEngineD3D11.cpp | 2 + GPU/Directx9/DrawEngineDX9.cpp | 2 + GPU/GLES/DrawEngineGLES.cpp | 3 + GPU/Vulkan/DrawEngineVulkan.cpp | 3 + 5 files changed, 24 insertions(+), 67 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index dc86e9ec13..67ba97af4c 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -168,29 +168,6 @@ void SoftwareTransform::SetProjMatrix(float mtx[14], bool invertedX, bool invert projMatrix_.translateAndScale(trans, scale); } -static void ReadWeightedNormal(Vec3f &source, VertexReader &reader, u32 vertType, bool skinningEnabled) { - if (reader.hasNormal()) - reader.ReadNrm(source.AsArray()); - if (skinningEnabled) { - float weights[8]; - reader.ReadWeights(weights); - - // Have to recalculate this, unfortunately. Please use software skinning... - Vec3f nsum(0, 0, 0); - for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) { - if (weights[i] != 0.0f) { - Vec3f norm; - Norm3ByMatrix43(norm.AsArray(), source.AsArray(), gstate.boneMatrix + i * 12); - nsum += norm * weights[i]; - } - } - - source = nsum; - } - if (gstate.areNormalsReversed()) - source = -source; -} - void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result) { u8 *decoded = params_.decoded; TransformedVertex *transformed = params_.transformed; @@ -204,8 +181,6 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt vscale /= gstate_c.curTextureHeight; } - bool skinningEnabled = vertTypeIsSkinningEnabled(vertType) && !g_Config.bSoftwareSkinning; - const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); float widthFactor = (float) w / (float) gstate_c.curTextureWidth; @@ -296,47 +271,13 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt if (reader.hasNormal()) reader.ReadNrm(normal.AsArray()); - if (!skinningEnabled) { - Vec3ByMatrix43(out, pos, gstate.worldMatrix); - if (reader.hasNormal()) { - if (gstate.areNormalsReversed()) { - normal = -normal; - } - Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); - worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1); - } - } else { - float weights[8]; - // For flat, we need the vertex weights. - reader.Goto(index); - reader.ReadWeights(weights); - - // Skinning - Vec3f psum(0, 0, 0); - Vec3f nsum(0, 0, 0); - for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) { - if (weights[i] != 0.0f) { - Vec3ByMatrix43(out, pos, gstate.boneMatrix+i*12); - Vec3f tpos(out); - psum += tpos * weights[i]; - if (reader.hasNormal()) { - Vec3f norm; - Norm3ByMatrix43(norm.AsArray(), normal.AsArray(), gstate.boneMatrix+i*12); - nsum += norm * weights[i]; - } - } - } - - // Yes, we really must multiply by the world matrix too. - Vec3ByMatrix43(out, psum.AsArray(), gstate.worldMatrix); - if (reader.hasNormal()) { - normal = nsum; - if (gstate.areNormalsReversed()) { - normal = -normal; - } - Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); - worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1); + Vec3ByMatrix43(out, pos, gstate.worldMatrix); + if (reader.hasNormal()) { + if (gstate.areNormalsReversed()) { + normal = -normal; } + Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); + worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1); } // Perform lighting here if enabled. @@ -398,7 +339,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt source = normal.Normalized(cpu_info.bSSE4_1); } else { reader.Goto(index); - ReadWeightedNormal(source, reader, vertType, skinningEnabled); + if (reader.hasNormal()) + reader.ReadNrm(source.AsArray()); + if (gstate.areNormalsReversed()) + source = -source; source.Normalize(); } if (!reader.hasNormal()) { @@ -413,7 +357,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt } else { // Need to read the normal for this vertex and weight it again.. reader.Goto(index); - ReadWeightedNormal(source, reader, vertType, skinningEnabled); + if (reader.hasNormal()) + reader.ReadNrm(source.AsArray()); + if (gstate.areNormalsReversed()) + source = -source; } if (!reader.hasNormal()) { ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 2a537a83a3..e0c33e5d76 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -581,6 +581,7 @@ rotateVBO: } } else { PROFILE_THIS_SCOPE("soft"); + decOptions_.applySkinInDecode = true; DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -709,6 +710,7 @@ rotateVBO: framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 40790c1648..33117be1c9 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -546,6 +546,7 @@ rotateVBO: } } } else { + decOptions_.applySkinInDecode = true; DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -653,6 +654,7 @@ rotateVBO: framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 318cb19a02..e95afe57ed 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -331,7 +331,9 @@ void DrawEngineGLES::DoFlush() { } } else { PROFILE_THIS_SCOPE("soft"); + decOptions_.applySkinInDecode = true; DecodeVerts(decoded); + bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255); @@ -446,6 +448,7 @@ void DrawEngineGLES::DoFlush() { } gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied. } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 01c356f34d..d8c8b740e5 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -841,6 +841,7 @@ void DrawEngineVulkan::DoFlush() { } } else { PROFILE_THIS_SCOPE("soft"); + decOptions_.applySkinInDecode = true; DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -927,6 +928,7 @@ void DrawEngineVulkan::DoFlush() { decodedVerts_ = 0; numDrawCalls = 0; decodeCounter_ = 0; + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; return; } BindShaderBlendTex(); // This might cause copies so super important to do before BindPipeline. @@ -994,6 +996,7 @@ void DrawEngineVulkan::DoFlush() { framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, result.color); } } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; From 527947fd81c09804606b867677ab590d24d2f391 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Nov 2022 09:06:07 -0800 Subject: [PATCH 219/715] GPU: Correct softgpu curve issue. --- GPU/Common/DrawEngineCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index e02da46179..664b90823e 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -514,7 +514,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, }; // Let's have two separate loops, one for non skinning and one for skinning. - if (!g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { + if (!dec->skinInDecode && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { int numBoneWeights = vertTypeGetNumBoneWeights(vertType); for (int i = lowerBound; i <= upperBound; i++) { reader.Goto(i - lowerBound); From 200c055823eb0b5be608fd28fbb1929d495dc24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 18:55:45 +0100 Subject: [PATCH 220/715] libretro fix, more games --- assets/compat.ini | 12 ++++++++++++ libretro/libretro_core_options.h | 10 ---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/assets/compat.ini b/assets/compat.ini index bfa2165a19..7a1ac5d79f 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1252,3 +1252,15 @@ ULUS10018 = true UCJS18003 = true ULES00291 = true NPJG00033 = true + +# Fushigi no Dungeon: Fuurai no Shiren 4 Plus - Kami no Hitomi to Akuma no Heso +ULJS00547 = true +NPJH50698 = true + +# Final Fantasy Tactics +UCAS40148 = true +ULJM05194 = true +ULES00850 = true +ULUS10297 = true +ULJM05516 = true +NPJH50408 = true diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index 78cab61d7d..0ca87d8bce 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -427,16 +427,6 @@ struct retro_core_option_v2_definition option_defs_us[] = { BOOL_OPTIONS, "disabled" }, - { - "ppsspp_retain_changed_textures", - "Retain Changed Textures (Speedup, mem hog)", - NULL, - "Makes many games slower, but some games a lot faster.", - NULL, - "video", - BOOL_OPTIONS, - "disabled" - }, { "ppsspp_spline_quality", "Spline/Bezier Curves Quality", From 519db766b6a251d8d8032236c401babf29e82553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 19:20:10 +0100 Subject: [PATCH 221/715] Change "Rendering Mode" to just a "Skip buffer effects" checkbox. Reuse translations. --- Core/Config.cpp | 11 +++--- Core/Config.h | 6 ++-- Core/HLE/sceDisplay.cpp | 6 ++-- GPU/Common/FramebufferManagerCommon.cpp | 6 ++-- UI/DisplayLayoutScreen.cpp | 4 +-- UI/EmuScreen.cpp | 4 +-- UI/GameSettingsScreen.cpp | 46 ++++++++----------------- Windows/MainWindowMenu.cpp | 41 ++++++---------------- Windows/ppsspp.rc | 7 ++-- Windows/resource.h | 3 +- assets/lang/ar_AE.ini | 6 ++-- assets/lang/az_AZ.ini | 6 ++-- assets/lang/bg_BG.ini | 6 ++-- assets/lang/ca_ES.ini | 6 ++-- assets/lang/cz_CZ.ini | 6 ++-- assets/lang/da_DK.ini | 6 ++-- assets/lang/de_DE.ini | 6 ++-- assets/lang/dr_ID.ini | 6 ++-- assets/lang/en_US.ini | 6 ++-- assets/lang/es_ES.ini | 6 ++-- assets/lang/es_LA.ini | 6 ++-- assets/lang/fa_IR.ini | 6 ++-- assets/lang/fi_FI.ini | 6 ++-- assets/lang/fr_FR.ini | 6 ++-- assets/lang/gl_ES.ini | 6 ++-- assets/lang/gr_EL.ini | 6 ++-- assets/lang/he_IL.ini | 6 ++-- assets/lang/he_IL_invert.ini | 6 ++-- assets/lang/hr_HR.ini | 6 ++-- assets/lang/hu_HU.ini | 6 ++-- assets/lang/id_ID.ini | 6 ++-- assets/lang/it_IT.ini | 6 ++-- assets/lang/ja_JP.ini | 6 ++-- assets/lang/jv_ID.ini | 6 ++-- assets/lang/ko_KR.ini | 6 ++-- assets/lang/lo_LA.ini | 6 ++-- assets/lang/lt-LT.ini | 6 ++-- assets/lang/ms_MY.ini | 6 ++-- assets/lang/nl_NL.ini | 6 ++-- assets/lang/no_NO.ini | 6 ++-- assets/lang/pl_PL.ini | 6 ++-- assets/lang/pt_BR.ini | 6 ++-- assets/lang/pt_PT.ini | 6 ++-- assets/lang/ro_RO.ini | 6 ++-- assets/lang/ru_RU.ini | 6 ++-- assets/lang/sv_SE.ini | 6 ++-- assets/lang/tg_PH.ini | 6 ++-- assets/lang/th_TH.ini | 6 ++-- assets/lang/tr_TR.ini | 8 ++--- assets/lang/uk_UA.ini | 6 ++-- assets/lang/vi_VN.ini | 6 ++-- assets/lang/zh_CN.ini | 6 ++-- assets/lang/zh_TW.ini | 12 +++---- headless/Headless.cpp | 2 +- 54 files changed, 138 insertions(+), 264 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 3e095283cd..8e3c1d76d7 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -875,7 +875,7 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", true, false), ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false), ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, true, true, true), - ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, 1, true, true), + ConfigSetting("SkipBufferEffects", &g_Config.bSkipBufferEffects, false, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), ConfigSetting("SoftwareRendererJit", &g_Config.bSoftwareRenderingJit, true, true, true), ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true), @@ -1410,9 +1410,6 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (iAnisotropyLevel > 4) { iAnisotropyLevel = 4; } - if (iRenderingMode != FB_NON_BUFFERED_MODE && iRenderingMode != FB_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; - } // Check for an old dpad setting Section *control = iniFile.GetOrCreateSection("Control"); @@ -1463,8 +1460,8 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (sMACAddress.length() != 17) sMACAddress = CreateRandMAC(); - if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; + if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; } // Override ppsspp.ini JIT value to prevent crashing @@ -1985,5 +1982,5 @@ void Config::GetReportingInfo(UrlEncoder &data) { } bool Config::IsPortrait() const { - return (iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180) && iRenderingMode != FB_NON_BUFFERED_MODE; + return (iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180) && !bSkipBufferEffects; } diff --git a/Core/Config.h b/Core/Config.h index 6dc1226858..e4795bfd4b 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -162,11 +162,13 @@ public: bool bSoftwareRendering; bool bSoftwareRenderingJit; bool bHardwareTransform; // only used in the GLES backend - bool bSoftwareSkinning; // may speed up some games + bool bSoftwareSkinning; bool bVendorBugChecksEnabled; bool bUseGeometryShader; - int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering + // Speedhacks (more will be moved here): + bool bSkipBufferEffects; + int iTexFiltering; // 1 = auto , 2 = nearest , 3 = linear , 4 = auto max quality int iBufFilter; // 1 = linear, 2 = nearest int iSmallDisplayZoomType; // Used to fit display into screen 0 = stretch, 1 = partial stretch, 2 = auto scaling, 3 = manual scaling. diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index d0577d46f2..342d522627 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -544,7 +544,7 @@ void __DisplayFlip(int cyclesLate) { // non-buffered rendering. The interaction with frame skipping seems to need // some work. // But, let's flip at least once every 10 vblanks, to update fps, etc. - const bool noRecentFlip = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && numVBlanksSinceFlip >= 10; + const bool noRecentFlip = !g_Config.bSkipBufferEffects && numVBlanksSinceFlip >= 10; // Also let's always flip for animated shaders. bool postEffectRequiresFlip = false; @@ -556,7 +556,7 @@ void __DisplayFlip(int cyclesLate) { fastForwardSkipFlip = true; } - if (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) { + if (!g_Config.bSkipBufferEffects) { postEffectRequiresFlip = duplicateFrames || g_Config.bShaderChainRequires60FPS; } @@ -777,7 +777,7 @@ void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelFormat, int sync) // IMMEDIATE means that the buffer is fine. We can just flip immediately. // Doing it in non-buffered though creates problems (black screen) on occasion though // so let's not. - if (!flippedThisFrame && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) { + if (!flippedThisFrame && !g_Config.bSkipBufferEffects) { double before_flip = time_now_d(); __DisplayFlip(0); double after_flip = time_now_d(); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index f7a470bb7d..8a74467130 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -91,7 +91,9 @@ bool FramebufferManagerCommon::UpdateSize() { const int effectiveBloomHack = PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn ? 3 : g_Config.iBloomHack; - const bool newSettings = bloomHack_ != effectiveBloomHack || useBufferedRendering_ != (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE); + + bool newBuffered = !g_Config.bSkipBufferEffects; + const bool newSettings = bloomHack_ != effectiveBloomHack || useBufferedRendering_ != newBuffered; renderWidth_ = (float)PSP_CoreParameter().renderWidth; renderHeight_ = (float)PSP_CoreParameter().renderHeight; @@ -99,7 +101,7 @@ bool FramebufferManagerCommon::UpdateSize() { pixelWidth_ = PSP_CoreParameter().pixelWidth; pixelHeight_ = PSP_CoreParameter().pixelHeight; bloomHack_ = effectiveBloomHack; - useBufferedRendering_ = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + useBufferedRendering_ = newBuffered; presentation_->UpdateSize(pixelWidth_, pixelHeight_, renderWidth_, renderHeight_); diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 3e0dd6479a..e2ea500884 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -275,7 +275,7 @@ void DisplayLayoutScreen::CreateViews() { root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding - vertBoundariesHeight, NONE, NONE))); root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding + previewHeight, NONE, NONE))); - bool displayRotEnable = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) || g_Config.bSoftwareRendering; + bool displayRotEnable = !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; bRotated_ = false; if (displayRotEnable && (g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180)) { bRotated_ = true; @@ -371,7 +371,7 @@ void DisplayLayoutScreen::CreateViews() { static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, previewWidth - 200.0f, 10, NONE, bounds.h - 64 - 10)); rotation->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE || g_Config.bSoftwareRendering; + return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; }); root_->Add(rotation); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index bcf5a47a48..c046fb01d5 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -327,7 +327,7 @@ void EmuScreen::bootGame(const Path &filename) { System_SendMessage("event", "failstartgame"); } - if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { + if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.bSkipBufferEffects) { auto gr = GetI18NCategory("Graphics"); host->NotifyUserMessage(gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 15.0f); } @@ -1355,7 +1355,7 @@ void EmuScreen::preRender() { // We only bind it in FramebufferManager::CopyDisplayToOutput (unless non-buffered)... // We do, however, start the frame in other ways. - bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + bool useBufferedRendering = !g_Config.bSkipBufferEffects; if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) { // We need to clear here already so that drawing during the frame is done on a clean slate. if (Core_IsStepping() && gpuStats.numFlips != 0) { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index cf87f56f47..d92eed91a1 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -298,20 +298,16 @@ void GameSettingsScreen::CreateViews() { } } - static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering" }; - PopupMultiChoice *renderingModeChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gr->T("Mode"), renderingMode, 0, ARRAY_SIZE(renderingMode), gr->GetName(), screenManager())); - renderingModeChoice->OnChoice.Add([=](EventParams &e) { - switch (g_Config.iRenderingMode) { - case FB_NON_BUFFERED_MODE: + CheckBox *skipBufferEffects = graphicsSettings->Add(new CheckBox(&g_Config.bSkipBufferEffects, gr->T("Skip Buffer Effects"))); + skipBufferEffects->OnClick.Add([=](EventParams &e) { + if (g_Config.bSkipBufferEffects) { settingInfo_->Show(gr->T("RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games"), e.v); - break; - case FB_BUFFERED_MODE: - break; + g_Config.bAutoFrameSkip = false; } - return UI::EVENT_CONTINUE; + return UI::EVENT_DONE; }); - renderingModeChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingMode); - renderingModeChoice->SetDisabledPtr(&g_Config.bSoftwareRendering); + skipBufferEffects->SetDisabledPtr(&g_Config.bSoftwareRendering); + CheckBox *blockTransfer = graphicsSettings->Add(new CheckBox(&g_Config.bBlockTransferGPU, gr->T("Simulate Block Transfer", "Simulate Block Transfer"))); blockTransfer->OnClick.Add([=](EventParams &e) { if (!g_Config.bBlockTransferGPU) @@ -378,7 +374,7 @@ void GameSettingsScreen::CreateViews() { auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetEnabledFunc([=] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && enableStereo(); + return !g_Config.bSkipBufferEffects && enableStereo(); }); } } @@ -400,7 +396,7 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_DONE; }); postProcChoice_->SetEnabledFunc([=] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo(); + return !g_Config.bSkipBufferEffects && !enableStereo(); }); // No need for settings on the last one. @@ -423,7 +419,7 @@ void GameSettingsScreen::CreateViews() { } else { PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetEnabledFunc([=] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !enableStereo(); + return !g_Config.bSkipBufferEffects && !enableStereo(); }); } } @@ -470,7 +466,7 @@ void GameSettingsScreen::CreateViews() { resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), gr->GetName(), screenManager())); resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange); resolutionChoice_->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects; }); #if PPSSPP_PLATFORM(ANDROID) @@ -499,7 +495,7 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_CONTINUE; }); frameDuplication->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && g_Config.iFrameSkip == 0; + return !g_Config.bSkipBufferEffects && g_Config.iFrameSkip == 0; }); if (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::OPENGL) { @@ -1198,8 +1194,8 @@ UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) { if (g_Config.bAutoFrameSkip && g_Config.iFrameSkip == 0) { g_Config.iFrameSkip = 1; } - if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; + if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; } return UI::EVENT_DONE; } @@ -1243,20 +1239,6 @@ UI::EventReturn GameSettingsScreen::OnSustainedPerformanceModeChange(UI::EventPa return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnRenderingMode(UI::EventParams &e) { - // We do not want to report when rendering mode is Framebuffer to memory - so many issues - // are caused by that (framebuffer copies overwriting display lists, etc). - Reporting::UpdateConfig(); - enableReportsCheckbox_->SetEnabled(Reporting::IsSupported()); - if (!Reporting::IsSupported()) - enableReports_ = Reporting::IsEnabled(); - - if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.bAutoFrameSkip = false; - } - return UI::EVENT_DONE; -} - UI::EventReturn GameSettingsScreen::OnJitAffectingSetting(UI::EventParams &e) { NativeMessageReceived("clear jit", ""); return UI::EVENT_DONE; diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 384bb9a0f7..b8e8b10c94 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -315,8 +315,7 @@ namespace MainWindow { TranslateMenuItem(menu, ID_OPTIONS_VULKAN); TranslateMenuItem(menu, ID_OPTIONS_RENDERMODE_MENU); - TranslateMenuItem(menu, ID_OPTIONS_NONBUFFEREDRENDERING); - TranslateMenuItem(menu, ID_OPTIONS_BUFFEREDRENDERING); + TranslateMenuItem(menu, ID_OPTIONS_SKIP_BUFFER_EFFECTS); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_MENU, g_Config.bSystemControls ? L"\tF7" : L""); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_AUTO); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_0); @@ -489,21 +488,8 @@ namespace MainWindow { NativeMessageReceived("gpu_clearCache", ""); } - static void setRenderingMode(int mode) { - auto gr = GetI18NCategory("Graphics"); - - g_Config.iRenderingMode = mode; - switch (g_Config.iRenderingMode) { - case FB_NON_BUFFERED_MODE: - osm.Show(gr->T("Non-Buffered Rendering")); - g_Config.bAutoFrameSkip = false; - break; - - case FB_BUFFERED_MODE: - osm.Show(gr->T("Buffered Rendering")); - break; - } - + static void setSkipBufferEffects(bool skip) { + g_Config.bSkipBufferEffects = skip; NativeMessageReceived("gpu_resized", ""); } @@ -756,8 +742,8 @@ namespace MainWindow { case ID_OPTIONS_FRAMESKIP_AUTO: g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip; - if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; + if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; NativeMessageReceived("gpu_resized", ""); } break; @@ -802,8 +788,11 @@ namespace MainWindow { RestartApp(); break; - case ID_OPTIONS_NONBUFFEREDRENDERING: setRenderingMode(FB_NON_BUFFERED_MODE); break; - case ID_OPTIONS_BUFFEREDRENDERING: setRenderingMode(FB_BUFFERED_MODE); break; + case ID_OPTIONS_SKIP_BUFFER_EFFECTS: + g_Config.bSkipBufferEffects = !g_Config.bSkipBufferEffects; + NativeMessageReceived("gpu_resized", ""); + osm.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects); + break; case ID_DEBUG_SHOWDEBUGSTATISTICS: g_Config.bShowDebugStats = !g_Config.bShowDebugStats; @@ -1095,6 +1084,7 @@ namespace MainWindow { CHECKITEM(ID_FILE_USEFFV1, g_Config.bUseFFV1); CHECKITEM(ID_FILE_DUMP_VIDEO_OUTPUT, g_Config.bDumpVideoOutput); CHECKITEM(ID_FILE_DUMPAUDIO, g_Config.bDumpAudio); + CHECKITEM(ID_OPTIONS_SKIP_BUFFER_EFFECTS, g_Config.bSkipBufferEffects); static const int displayrotationitems[] = { ID_EMULATION_ROTATION_H, @@ -1238,15 +1228,6 @@ namespace MainWindow { CheckMenuItem(menu, bufferfilteritems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iBufFilter ? MF_CHECKED : MF_UNCHECKED)); } - static const int renderingmode[] = { - ID_OPTIONS_NONBUFFEREDRENDERING, - ID_OPTIONS_BUFFEREDRENDERING, - }; - - for (int i = 0; i < ARRAY_SIZE(renderingmode); i++) { - CheckMenuItem(menu, renderingmode[i], MF_BYCOMMAND | ((i == g_Config.iRenderingMode) ? MF_CHECKED : MF_UNCHECKED)); - } - static const int frameskipping[] = { ID_OPTIONS_FRAMESKIP_0, ID_OPTIONS_FRAMESKIP_1, diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index c04801767e..27437ef9f1 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -552,6 +552,7 @@ BEGIN MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Fullscreen", ID_OPTIONS_FULLSCREEN MENUITEM "VSync", ID_OPTIONS_VSYNC + MENUITEM "Skip Buffer Effects", ID_OPTIONS_SKIP_BUFFER_EFFECTS POPUP "Postprocessing Shader", ID_OPTIONS_SHADER_MENU BEGIN MENUITEM "", 0, MFT_SEPARATOR @@ -592,11 +593,7 @@ BEGIN MENUITEM "Vulkan", ID_OPTIONS_VULKAN END - POPUP "Rendering Mode", ID_OPTIONS_RENDERMODE_MENU - BEGIN - MENUITEM "Non-Buffered Rendering", ID_OPTIONS_NONBUFFEREDRENDERING - MENUITEM "Buffered Rendering", ID_OPTIONS_BUFFEREDRENDERING - END + POPUP "Frame Skipping", ID_OPTIONS_FRAMESKIP_MENU BEGIN MENUITEM "Auto", ID_OPTIONS_FRAMESKIP_AUTO diff --git a/Windows/resource.h b/Windows/resource.h index ab68ee494f..6bc03a9429 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -189,7 +189,7 @@ #define ID_DISASM_THREAD_KILL 40073 #define ID_FILE_SAVESTATE_NEXT_SLOT 40074 #define ID_FILE_SAVESTATE_NEXT_SLOT_HC 40075 -#define ID_OPTIONS_NONBUFFEREDRENDERING 40078 +#define ID_OPTIONS_SKIP_BUFFER_EFFECTS 40078 #define ID_OPTIONS_FRAMESKIP_0 40079 #define ID_OPTIONS_FRAMESKIP_1 40080 #define ID_OPTIONS_FRAMESKIP_2 40081 @@ -219,7 +219,6 @@ #define ID_OPTIONS_WINDOW3X 40106 #define ID_OPTIONS_WINDOW4X 40107 #define ID_OPTIONS_WINDOW5X 40108 -#define ID_OPTIONS_BUFFEREDRENDERING 40109 #define ID_DEBUG_SHOWDEBUGSTATISTICS 40110 #define ID_OPTIONS_SCREEN6X 40111 #define ID_OPTIONS_SCREEN7X 40112 diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 6987e7b3c7..8cae321f81 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -137,7 +137,6 @@ Backend = ‎&خلفية التصيير(إعادة تشغيل PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = ‎&تصيير مخفف Buy Gold = ‎إشتري النسخة الإحترافية & Control Mapping... = ‎&تخطيط التحكم... Debugging = ‎&تصحيح @@ -181,7 +180,7 @@ Log Console = ‎&سجل الكونسول Memory View... = ‎عرض الرام... More Settings... = ‎&إعدادات إضافية... Nearest = ‎&الأقرب -Non-Buffered Rendering = ‎&تخطي تأثيرات الصقل (غير مصقول, أسرع) +Skip Buffer Effects = ‎&تخطي تأثيرات الصقل (غير مصقول, أسرع) Off = ‎&مغلق Open Chat = Open Chat Open Directory... = ‎إفتح مسار&... @@ -481,7 +480,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = ‎الأثنين Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = ‎التصيير المُخفف BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -533,7 +531,7 @@ Must Restart = ‎يجب عليك إعادة تشغيل البرنامج لكي Native device resolution = ‎حجم الجهاز الأساسي Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = ‎لا شئ Number of Frames = Number of frames Off = ‎مغلق diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 581e08ca3a..88dd568f32 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Yükləyərək Aç BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = None Number of Frames = Number of frames Off = Off diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index e8b2d60613..f2a48cade1 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Купи &Gold Control Mapping... = Контроли... Debugging = &Debug @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Памет изглед... More Settings... = Още настройки... Nearest = &Най-близко -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Изключено Open Chat = Open Chat Open Directory... = Отвори директория... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = И двете Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Най-близко No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Нищо Number of Frames = Number of frames Off = Изключен diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index dc018c04b4..fab847026c 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -129,7 +129,6 @@ Backend = Motor &gràfic (requereix reiniciar) Bicubic = &Bicúbic Break = Break Break on Load = Break on load -Buffered Rendering = &Renderitzat en memòria intermèdia Buy Gold = Compreu la versió &Gold Control Mapping... = Assigneu els &botons... Debugging = &Depuració @@ -173,7 +172,7 @@ Log Console = Consola de re&gistres Memory View... = Visor de &memòria... More Settings... = Més &paràmetres... Nearest = &El més proper -Non-Buffered Rendering = &Renderitzat sense memòria intermèdia (més ràpid) +Skip Buffer Effects = &Renderitzat sense memòria intermèdia (més ràpid) Off = &No Open Chat = Open Chat Open Directory... = Obriu &directori... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Renderizat per buffer BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = None Number of Frames = Number of frames Off = Off diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index c190a4e884..08043400a9 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -129,7 +129,6 @@ Backend = V&ykreslovací Jádro (Restartuje PPSSPP) Bicubic = &Bikubická Break = Break Break on Load = Break on load -Buffered Rendering = Vykreslování &s vyrovnávací pamětí Buy Gold = &Koupit zlaté PPSSPP Control Mapping... = &Mapování ovládání... Debugging = &Ladění @@ -173,7 +172,7 @@ Log Console = &Konzole záznamu Memory View... = &Zobrazení paměti... More Settings... = D&alší nastavení... Nearest = &Nejbližší -Non-Buffered Rendering = &Přeskočit efekty vyrovnávací paměti (rychlejší, neukládá se do paměti) +Skip Buffer Effects = &Přeskočit efekty vyrovnávací paměti Off = &Vypnuto Open Chat = Open Chat Open Directory... = &Otevřít adresář... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Obojí Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Vykreslování s vyrovnávací pamětí BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Aby došlo k použití těchto změn, je nutné PPSSPP restartova Native device resolution = Původní rozlišení zařízení Nearest = Nejbližší No buffer = No buffer -Non-Buffered Rendering = Přeskočit efekty vyrovnávací paměti (rychlejší, neukládá se do paměti) +Skip Buffer Effects = Přeskočit efekty vyrovnávací paměti None = Nezobrazovat Number of Frames = Number of frames Off = Vypnuto diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index de5366d8f5..06dfd28cee 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Genstarter PPSSPP) Bicubic = &Bicubisk Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered rendering Buy Gold = Køb PPSSPP &guld Control Mapping... = &Ændre tasteplaceringen... Debugging = Fe&jlfind @@ -173,7 +172,7 @@ Log Console = &Log konsol Memory View... = Hukommelseso&versigt... More Settings... = &Flere indstillinger... Nearest = &Nærmest -Non-Buffered Rendering = &Skip buffer effekter (ikke-bufferet, hurtigere) +Skip Buffer Effects = &Skip buffer effekter Off = &Slukket Open Chat = Open Chat Open Directory... = &Åben katalog... @@ -473,7 +472,6 @@ BlockTransfer Tip = Nogle spil kræver at denne er tændt for korrekt grafik BlockTransferRequired = Advarsel: Dette spil kræver at simulerede blok overførsel tilstand er tændt. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Bufferet rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Du må genstarte PPSSPP for at aktivere denne ændring. Native device resolution = Standard enheds opløsning Nearest = Nærmest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effekter (ikke-buffered, hurtigere) +Skip Buffer Effects = Skip buffer effekter None = Ingen Number of Frames = Number of frames Off = Slukket diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index a5129d922e..4e194329bd 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -129,7 +129,6 @@ Backend = Grafik-Backend Bicubic = Bikubisch Break = Anhalten Break on Load = Anhalten beim Laden -Buffered Rendering = Gepuffertes Rendern Buy Gold = Goldversion kaufen Control Mapping... = Tastenbelegung ändern... Debugging = Debug @@ -173,7 +172,7 @@ Log Console = Logkonsole Memory View... = Speicheransicht... More Settings... = Mehr Einstellungen... Nearest = Nächster Nachbar -Non-Buffered Rendering = Überspringe Puffereffekte (ungepuffert, schneller) +Skip Buffer Effects = Überspringe Puffereffekte Off = Aus Open Chat = Öffne Chat Open Directory... = Öffne Verzeichnis... @@ -473,7 +472,6 @@ BlockTransfer Tip = Manche Spiele benötigen dies für eine korrekte Darstellung BlockTransferRequired = Warnung: Dieses Spiel benötigt "Blockübertragungseffekte simulieren". Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Gepuffertes Rendern BufferedRenderingRequired = Warnung: Bei diesem Spiel muss "Rendering Modus" auf "Gepuffert" gesetzt werden. Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Sie müssen PPSSPP neustarten, damit die Änderungen wirksam werd Native device resolution = Native Auflösung Nearest = Nächster Nachbar No buffer = No buffer -Non-Buffered Rendering = Über&springe Puffereffekte (ungepuffert, schneller) +Skip Buffer Effects = Über&springe Puffereffekte None = Keine Number of Frames = Anzahl an Frames Off = Aus diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 23346118f2..ca081a1c09 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Alli &Gold Control Mapping... = C&ontrol Mapping... Debugging = Debu&g @@ -173,7 +172,7 @@ Log Console = &Konsol log Memory View... = Pempakitan &Memory... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Mate Open Chat = Open Chat Open Directory... = Bukka' &Ngenan... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Pa jio duai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = To paling mandoppi' No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Danggo'mo Number of Frames = Number of frames Off = Mate diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index b3389a229b..b66ccc4ee1 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -153,7 +153,6 @@ Backend = Rendering &backend (restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol mapping... Debugging = &Debug @@ -197,7 +196,7 @@ Log Console = &Log console Memory View... = Memory &view... More Settings... = &More settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &directory... @@ -497,7 +496,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -548,7 +546,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = None Number of Frames = Number of frames Off = Off diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index b61201985c..30216ad2cd 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -129,7 +129,6 @@ Backend = Motor &gráfico (requiere reiniciar) Bicubic = &Bicúbico Break = Romper Break on Load = Romper en carga -Buffered Rendering = &Dibujado por búfer Buy Gold = Comprar versión &Gold Control Mapping... = Asignar &botones... Debugging = &Depuración @@ -173,7 +172,7 @@ Log Console = Consola de re&gistros... Memory View... = Visor de &memoria... More Settings... = Más &opciones... Nearest = &Cercano -Non-Buffered Rendering = &Saltar efectos del búfer (rápido) +Skip Buffer Effects = &Saltar efectos del búfer (rápido) Off = &No Open Chat = Abrir ventana de chat Open Directory... = &Abrir carpeta... @@ -473,7 +472,6 @@ BlockTransfer Tip = Algunos juegos necesitan esta opción para evitar errores gr BlockTransferRequired = AVISO: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos de búfer gráfico (puede generar input lag) -Buffered Rendering = Dibujado por búfer BufferedRenderingRequired = AVISO: este juego requiere modo de renderizado por búfer. Camera = Cámara Camera Device = Dispositivo de cámara @@ -525,7 +523,7 @@ Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa del dispositivo Nearest = Pixelado No buffer = Sin búfer -Non-Buffered Rendering = Saltar efectos del búfer +Skip Buffer Effects = Saltar efectos del búfer None = No Number of Frames = Nº de cuadros Off = No diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 6c7d42d35f..76da6dbded 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -129,7 +129,6 @@ Backend = Motor &gráfico (requiere reiniciar) Bicubic = &Bicúbico Break = Romper Break on Load = Romper en carga -Buffered Rendering = &Renderizado por búfer Buy Gold = Comprar versión &Gold Control Mapping... = Asignar &botones... Debugging = &Depuración @@ -173,7 +172,7 @@ Log Console = Consola de re&gistros... Memory View... = Visor de &memoria... More Settings... = Más &opciones... Nearest = &Cercano -Non-Buffered Rendering = &Saltar efectos por búfer (rápido) +Skip Buffer Effects = &Saltar efectos por búfer (rápido) Off = &No Open Chat = Abrir ventana de chat Open Directory... = &Abrir carpeta... @@ -473,7 +472,6 @@ BlockTransfer Tip = Algunos juegos requieren activarlo para corregir gráficos. BlockTransferRequired = Advertencia: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos gráficos de búfer (puede generar input lag) -Buffered Rendering = Renderizado con Buffer BufferedRenderingRequired = Advertencia: Este juego requiere modo de renderizado por búfer. Camera = Cámara Camera Device = Dispositivo de cámara @@ -525,7 +523,7 @@ Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa del dispositivo Nearest = Pixelado No buffer = No hay búfer -Non-Buffered Rendering = Saltar efectos por búfer (Desactiva búfer, rápido) +Skip Buffer Effects = Saltar efectos por búfer (Desactiva búfer, rápido) None = No Number of Frames = Número de Frames Off = Apagado diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index dba054242f..c082a845b9 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -129,7 +129,6 @@ Backend = ‎Rendering &Backend (ریستارت میشود PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = ‎رندر کردن از بافر Buy Gold = ‎خرید نسخه طلایی Control Mapping... = ‎...تنظیمات کنترلر Debugging = ‎دیباگ @@ -173,7 +172,7 @@ Log Console = ‎کنسول لاگ Memory View... = ‎...نمایش مموری More Settings... = ‎...تنظیمات بیشتر Nearest = ‎نزدیک ترین -Non-Buffered Rendering = ‎رد کردن اثرات بافر (سریع تر) +Skip Buffer Effects = ‎رد کردن اثرات بافر (سریع تر) Off = ‎خاموش Open Chat = Open Chat Open Directory... = ‎... بازکردن مسیر @@ -473,7 +472,6 @@ BlockTransfer Tip = ‎در بعضی بازی ها برای نشان دادن د BlockTransferRequired = ‎دارد "simulate block transfer effects" هشدار:این گزینه نیاز به روشن بودن Both = ‎سرعت + فریم بر ثانیه Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = ‎رندر کردن از بافر BufferedRenderingRequired = ‎تنظیم باشد "buffered" هشدار: برای این بازی "حالت رندرینگ" باید روی Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = ‎برای اعمال این تنظیم باید برنامه ر Native device resolution = ‎رزولوشن دستگاه Nearest = ‎نزدیک ترین No buffer = No buffer -Non-Buffered Rendering = ‎رد کردن اثر بافر (سریع تر) +Skip Buffer Effects = ‎رد کردن اثر بافر (سریع تر) None = ‎هیچ Number of Frames = Number of frames Off = ‎خاموش diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 8d8aafccb5..6e448250bc 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Molemmat Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Puskuroitu renderointi BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Lähin No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Ei mitään Number of Frames = Number of frames Off = Off diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 330ded83af..3e87cb10b8 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -129,7 +129,6 @@ Backend = Rendu &back-end (redémarre PPSSPP) Bicubic = &Bicubique Break = Arrêter Break on Load = Arrêter au lancement -Buffered Rendering = &Mise en mémoire tampon Buy Gold = Acheter la version &Gold Control Mapping... = R&éassignation des touches... Debugging = &Débogage @@ -173,7 +172,7 @@ Log Console = &Journal de débogage Memory View... = &Visionneur de mémoire More Settings... = &Plus de paramètres... Nearest = Le plus &proche -Non-Buffered Rendering = &Pas d'effets en mémoire tampon (hack de vitesse) +Skip Buffer Effects = &Pas d'effets en mémoire tampon (hack de vitesse) Off = &Désactivé Open Chat = Open Chat Open Directory... = Ouvrir &répertoire... @@ -473,7 +472,6 @@ BlockTransfer Tip = Certains jeux requièrent l'activation de ce paramètre pour BlockTransferRequired = Avertissement : Ce jeu requiert l'activation de "Simuler les effets de transfert de bloc". Both = Vitesse + FPS Buffer graphics commands (faster, input lag) = Commandes graphiques en mémoire tampon (+ rapide, + lag entrée) -Buffered Rendering = Mise en mémoire tampon BufferedRenderingRequired = Avertissement : Ce jeu requiert "mode de rendu" réglé sur "Mise en mémoire tampon". Camera = Caméra Camera Device = Caméra @@ -525,7 +523,7 @@ Must Restart = Vous devez redémarrer PPSSPP pour que cette modification prenne Native device resolution = Définition native de l'appareil Nearest = Le plus proche No buffer = 0 -Non-Buffered Rendering = Pas d'effets en mémoire tampon (hack vitesse) +Skip Buffer Effects = Pas d'effets en mémoire tampon (hack vitesse) None = Aucun Number of Frames = Nombre d'images Off = Désactivé diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 42c0a81859..0144f5cb0d 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -129,7 +129,6 @@ Backend = Motor &gráfico (require reiniciar) Bicubic = &Bicúbico Break = Break Break on Load = Break on load -Buffered Rendering = &Renderizado por búfer Buy Gold = Comprar versión &Gold Control Mapping... = Asignar &botóns... Debugging = &Depuración @@ -173,7 +172,7 @@ Log Console = Consola de re&xistros... Memory View... = Visor de &memoria... More Settings... = Máis &opcións... Nearest = &Cercano -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Non Open Chat = Open Chat Open Directory... = &Abrir carpeta... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Renderizado por búfer BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa do dispositivo Nearest = Pixelado No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Non Number of Frames = Number of frames Off = Non diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 3f9555e900..53fc6fd553 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -129,7 +129,6 @@ Backend = Σύστημα Υποστήριξης (επανεκκινεί το PPS Bicubic = &Διακυβική Break = Break Break on Load = Break on load -Buffered Rendering = Απεικόνιση με Buffer Buy Gold = Αγορά &Gold Control Mapping... = Χαρτογράφηση Κουμπιών... Debugging = Αποσφαλμάτωση @@ -173,7 +172,7 @@ Log Console = Κονσόλα Καταγραφέα Memory View... = Προβολή Μνήμης... More Settings... = Περισσότερες Ρυθμίσεις... Nearest = Κοντινότερο -Non-Buffered Rendering = &Παράκαμψη εφέ buffer (γρηγορότερο) +Skip Buffer Effects = &Παράκαμψη εφέ buffer (γρηγορότερο) Off = &Off Open Chat = Open Chat Open Directory... = Άνοιγμα Φακέλου... @@ -473,7 +472,6 @@ BlockTransfer Tip = Ορισμένα παιχνίδια απαιτούν να ε BlockTransferRequired = Προειδοποίηση: Αυτό το παιχνίδι απαιτεί τη λειτουργία προσομοίωσης εφέ μεταφοράς block να είναι ενεργοποιημένη. Both = Όλα Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Απεικόνιση με Buffer BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Πρέπει να επανεκκινήσετε το PPSSPP για Native device resolution = Χρήση ανάλυσης συσκευής Nearest = Κοντινότερο No buffer = No buffer -Non-Buffered Rendering = Παράκαμψη εφέ buffer (γρηγορότερο) +Skip Buffer Effects = Παράκαμψη εφέ buffer (γρηγορότερο) None = Καμία Number of Frames = Number of frames Off = Ανενεργό diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index eea8766876..f7878259cd 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &מאגר מעובד Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = ניפ&וי @@ -173,7 +172,7 @@ Log Console = &התחבר לקונסולה Memory View... = הצג &זיכרון... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = פתח &קובץ... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = שניהם Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = מאגר מעובד BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = הקרוב ביותר No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = אל תציג מונה Number of Frames = Number of frames Off = כבוי diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 81da08b1d1..ca5a52c0e7 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = Debu&g @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = םהינש Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = דבועמ רגאמ BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = רתויב בורקה No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = הנומ גיצת לא Number of Frames = Number of frames Off = יובכ diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 5b212cf395..50bf5487c3 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -129,7 +129,6 @@ Backend = Poslužitelj &renderanja (restarta PPSSPP) Bicubic = &Bikubično Break = Pokvari Break on Load = Pokvari na učitavanju -Buffered Rendering = &Buffano prikazivanje Buy Gold = Kupi &Gold Control Mapping... = P&ostavljanje kontroli... Debugging = &Debug @@ -173,7 +172,7 @@ Log Console = &Konzola log-a Memory View... = Pregled &memorije... More Settings... = &Više postavki... Nearest = &Najbliže -Non-Buffered Rendering = &Preskoči bufferane efekte (non-buffered, faster) +Skip Buffer Effects = &Preskoči bufferane efekte Off = &Off Open Chat = Open Chat Open Directory... = Otvori &direktorij... @@ -473,7 +472,6 @@ BlockTransfer Tip = Neke igre zahtijevaju ovo na Uključeno za točne grafike BlockTransferRequired = Upozorenje: Ova igra zahtijeva "simulirajte blok transfer efekte" da budu postavljeni na Uključeno. Both = Oboje Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Ublaživanje prikaza BufferedRenderingRequired = Upozorenje: Ova igra zahtijeva "prikazni način" da bude postavljen na "ublaženo". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Morate ponovno pokrenuti PPSSPP da bi se efekat primjenio. Native device resolution = Urođena rezolucija uređaja Nearest = Najbliže No buffer = No buffer -Non-Buffered Rendering = Preskoči efekte ublaživanja (nije ublaženo, faster) +Skip Buffer Effects = Preskoči efekte ublaživanja (nije ublaženo, faster) None = Nijedna Number of Frames = Broj frame-ova Off = Isključeno diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index a18b33795f..6be4c6ef72 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -129,7 +129,6 @@ Backend = Renderelési &backend (újraindítás szükséges) Bicubic = &Bicubic Break = Megállítás Break on Load = Megállítás betöltéskor -Buffered Rendering = &Bufferelt renderelés Buy Gold = &Gold vásárlása Control Mapping... = &Gombok beállítása… Debugging = &Hibakeresés @@ -173,7 +172,7 @@ Log Console = &Napló ablak Memory View... = Memória &nézet… More Settings... = &Egyéb beállítások… Nearest = Leg&közelebbi -Non-Buffered Rendering = Bufferelt effektek kihagyá&sa (nem bufferelt, gyorsabb) +Skip Buffer Effects = Bufferelt effektek kihagyá&sa (nem bufferelt, gyorsabb) Off = &Ki Open Chat = Open Chat Open Directory... = Ma&ppa megnyitása… @@ -473,7 +472,6 @@ BlockTransfer Tip = Néhány játék számára ezt be kell kapcsolni ahhoz, hogy BlockTransferRequired = Figyelem: Ehhez a játékhoz be kell kapcsolni a "Blokk transzfer effektek szimulálása" opciót! Both = Mindkettő Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Bufferelt renderelés BufferedRenderingRequired = Figyelem: Ehhez a játékhoz a "Renderelési mód" beállítást "Bufferelt"-re kell állítani! Camera = Kamera Camera Device = Kamera eszköz @@ -525,7 +523,7 @@ Must Restart = A beállítások érvénybeléptetéséhez újra kell indítani a Native device resolution = Natív készülék felbontás Nearest = Legközelebbi No buffer = No buffer -Non-Buffered Rendering = Buffer effektek kihagyása (nem bufferelt, gyorsabb) +Skip Buffer Effects = Buffer effektek kihagyása (nem bufferelt, gyorsabb) None = Nincs Number of Frames = Képkockák száma Off = Ki diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index bfc1724aa4..ce169cedad 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -129,7 +129,6 @@ Backend = Bangun pelukisan &penyangga grafis (mulai ulang PPSSPP) Bicubic = &Bikubik Break = Rusak Break on Load = Rusak pada pemuatan -Buffered Rendering = Pelukisan tersangga Buy Gold = Beli versi &Emas Control Mapping... = Pemetaan k&ontrol... Debugging = Awakutu @@ -173,7 +172,7 @@ Log Console = Konso&l pencatat Memory View... = Tampilan memori... More Settings... = Pengaturan lainnya... Nearest = Terdekat -Non-Buffered Rendering = Lewati efek penyangga (tak-tersangga, lebih cepat) +Skip Buffer Effects = Lewati efek penyangga (tak-tersangga, lebih cepat) Off = Mati Open Chat = Buka opsi obrolan Open Directory... = Buka &direktori... @@ -473,7 +472,6 @@ BlockTransfer Tip = Beberapa permainan memerlukan opsi ini untuk menghindari kes BlockTransferRequired = Peringatan: Permainan ini membutuhkan "Simulasikan efek transfer blok" dalam keadaan menyala. Both = Keduanya Buffer graphics commands (faster, input lag) = Perintah grafis penyangga (lebih cepat, masukan lag) -Buffered Rendering = Pelukisan tersangga BufferedRenderingRequired = Peringatan: Permainan ini membutuhkan "Mode pelukisan" yang ditetapkan "Penyangga". Camera = Kamera Camera Device = Kamera perangkat @@ -525,7 +523,7 @@ Must Restart = Anda harus memulai ulang PPSSPP agar perubahan ini berfungsi. Native device resolution = Resolusi asli Nearest = Terdekat No buffer = Tidak ada penyangga -Non-Buffered Rendering = Lewati efek penyangga (tak tersangga, lebih cepat) +Skip Buffer Effects = Lewati efek penyangga (tak tersangga, lebih cepat) None = Tidak ada Number of Frames = Nomor laju bingkai Off = Mati diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 10453b2a13..e16911851f 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -129,7 +129,6 @@ Backend = Rendering di fondo (riavvia il PPSSPP) Bicubic = Bicubico Break = Interruzione Break on Load = Fermati al caricamento -Buffered Rendering = Rendering con buffer Buy Gold = Acquista la Versione Gold Control Mapping... = Impostazioni dei Controlli... Debugging = Debug @@ -173,7 +172,7 @@ Log Console = Log Console Memory View... = Visualizzazione Memoria... More Settings... = Altre Impostazioni... Nearest = Pixel perfect -Non-Buffered Rendering = Salta effetti di buffer (niente buffer, più velocità) +Skip Buffer Effects = Salta effetti di buffer (niente buffer, più velocità) Off = Disattiva Open Chat = Apri Chat Open Directory... = Apri Cartella... @@ -473,7 +472,6 @@ BlockTransfer Tip = Alcuni giochi richiedono che quest'opzione sia attiva per co BlockTransferRequired = Attenzione: Questo gioco richiede l'attivazione di 'Simula gli effetti del blocco trasferimento'. Both = Entrambi Buffer graphics commands (faster, input lag) = Comandi grafici bufferizzati (più rapido, più lag dei comandi) -Buffered Rendering = Rendering in buffer BufferedRenderingRequired = Attenzione: Questo gioco richiede di impostare "modalità di rendering" su "buffered". Camera = Telecamera Camera Device = Dispositivo di telecamera @@ -526,7 +524,7 @@ Must Restart = Sarà necessario riavviare PPSSPP per attivare le modifiche. Native device resolution = Risoluzione nativa della periferica Nearest = Pixel perfect No buffer = Niente buffer -Non-Buffered Rendering = Salta effetti di buffer (niente buffer, più velocità) +Skip Buffer Effects = Salta effetti di buffer (niente buffer, più velocità) None = Nessuno Number of Frames = Numero di Frames Off = Disattiva diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index dfe1a86e3a..9df017b836 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -129,7 +129,6 @@ Backend = バックエンド(&B) Bicubic = Bicubic(&B) Break = ブレーク Break on Load = ロード時にブレーク -Buffered Rendering = バッファレンダリング(&B) Buy Gold = Gold版を購入(&G) Control Mapping... = キーマッピング(入力ボタン設定)(&O)... Debugging = デバッグ(&D) @@ -173,7 +172,7 @@ Log Console = ログコンソール(&L) Memory View... = メモリビュー(&V)... More Settings... = 詳細設定(&M)... Nearest = &Nearest -Non-Buffered Rendering = ノンバッファレンダリング (高速化)(&S) +Skip Buffer Effects = ノンバッファレンダリング (高速化)(&S) Off = オフ(&O) Open Chat = Open Chat Open Directory... = ディレクトリを開く(&D)... @@ -473,7 +472,6 @@ BlockTransfer Tip = オンにしないと正しく表示できないゲームが BlockTransferRequired = 警告: このゲームは「ブロック転送の効果をシミュレートする」をオンにする必要があります。 Both = 両方 Buffer graphics commands (faster, input lag) = グラフィックスコマンドをバッファする (高速, 入力ラグあり) -Buffered Rendering = バッファレンダリング BufferedRenderingRequired = 警告: このゲームは「レンダリングモード」を「バッファ」にする必要があります。 Camera = カメラの設定 Camera Device = カメラデバイスの選択 @@ -525,7 +523,7 @@ Must Restart = この変更を適用するにはPPSSPPを再起動してくだ Native device resolution = 機器のネイティブ解像度 Nearest = Nearest No buffer = バッファなし -Non-Buffered Rendering = ノンバッファレンダリング (高速化) +Skip Buffer Effects = ノンバッファレンダリング (高速化) None = なし Number of Frames = フレーム数 Off = オフ diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index da4130fb2b..79220cf2ea 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Yakuwi Rendering Buy Gold = Tuku &Gold Control Mapping... = Pemetaan Kontrol ... Debugging = Debu&g @@ -173,7 +172,7 @@ Log Console = &Konsol Log Memory View... = Tampilan &Memory... More Settings... = Setelan sing luwih ... Nearest = &Nearest -Non-Buffered Rendering = Skip efek buffer (ora yakuwi,luwih cepet) +Skip Buffer Effects = Skip efek buffer (ora yakuwi,luwih cepet) Off = &Mati Open Chat = Open Chat Open Directory... = Mbukak &Direktori... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Kelorone Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Yakuwi Rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Wiwiti maneh PPSSPP kanggo aplikasi setelan. Native device resolution = Resolusi piranti asal Nearest = Cedhak No buffer = No buffer -Non-Buffered Rendering = Skip efek buffer (non-yakuwi,luwih cepet) +Skip Buffer Effects = Skip efek buffer (non-yakuwi,luwih cepet) None = Ora ana Number of Frames = Number of frames Off = Pateni diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 0cdd1a11e3..4178d83ec4 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -129,7 +129,6 @@ Backend = 렌더링 백엔드(&B) (PPSSPP 재시작) Bicubic = 고등차수보간(&B) Break = 증딘 Break on Load = 불러오기 시 중단 -Buffered Rendering = 버퍼링된 렌더링(&B) Buy Gold = 골드 버전 구매(&G) Control Mapping... = 제어 맵핑(&O)... Debugging = 디버그(&D) @@ -173,7 +172,7 @@ Log Console = 콘솔 로그(&L) Memory View... = 메모리 보기(&V)... More Settings... = 기타 설정(&M)... Nearest = 근접 필터링(&N) -Non-Buffered Rendering = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름)(&S) +Skip Buffer Effects = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름)(&S) Off = 끔(&O) Open Chat = 채팅 열기 Open Directory... = 디렉터리 열기(&D)... @@ -473,7 +472,6 @@ BlockTransfer Tip = 일부 게임에서는 올바른 그래픽을 위해 이 기 BlockTransferRequired = 경고: 이 게임은 "블록 전송 효과 시뮬레이션"을 켬으로 설정해야 합니다. Both = 둘 다 Buffer graphics commands (faster, input lag) = 버퍼 그래픽 명령 (빠름, 입력 지연) -Buffered Rendering = 버퍼링된 렌더링 BufferedRenderingRequired = 경고: 이 게임은 "렌더링 모드"를 "버퍼링"으로 설정해야 합니다. Camera = 카메라 Camera Device = 카메라 장치 @@ -524,7 +522,7 @@ Must Restart = 이 변경 사항을 적용하려면 PPSSPP를 다시 시작해 Native device resolution = 기본 장치 해상도 Nearest = 근접 필터링 No buffer = 버퍼 없음 -Non-Buffered Rendering = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름) +Skip Buffer Effects = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름) None = 없음 Number of Frames = 프레임 수 Off = 끔 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 1409815abc..9dc2bb3fa8 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -129,7 +129,6 @@ Backend = &ການສະແດງຜົນທີ່ສະໜັບສະໜຸ Bicubic = &ປັບພາບແບບ Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = ການສະແດງຜົນແບບໃຊ້ ບັບເຟີ້ Buy Gold = & ຊື້ແບບ Gold Control Mapping... = &ແຜງຄວບຄຸມ... Debugging = &ແກ້ໄຂຈຸດບົກພ່ອງ @@ -173,7 +172,7 @@ Log Console = &ເກັບຄ່າຄອນໂຊລ Memory View... = &ມຸມມອງຄ່າຄວາມຈຳ... More Settings... = &ການຕັ້ງຄ່າອື່ນໆ... Nearest = &ພາບເປັນຮອຍຍັກໄດ້ -Non-Buffered Rendering = &ຂ້າມການໃຊ້ເອັບເຟັກບັບເຟີ້ (ບໍ່ມີບັບເຟີ້, ໄວຂຶ້ນ) +Skip Buffer Effects = &ຂ້າມການໃຊ້ເອັບເຟັກບັບເຟີ້ (ບໍ່ມີບັບເຟີ້, ໄວຂຶ້ນ) Off = &ປິດ Open Chat = Open Chat Open Directory... = &ເປີດໄດເຣກທໍຣີ... @@ -473,7 +472,6 @@ BlockTransfer Tip = ບາງເກມຕ້ອງເປີດໃຊ້ງານ BlockTransferRequired = ຄຳເຕືອນ: ເກມນີ້ຕ້ອງການໃຫ້ເປີດໂໝດ "ຈຳລອງຜົນປິດກັ້ນການສົ່ງຜ່ານຂໍ້ມູນເອັບເຟກ" ນຳ Both = ໃຊ້ທັງ FPS ແລະ Speed Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = ການສະແດງຜົນແບບໃຊ້ບັບເຟີ້ BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = ເຈົ້າຄວນເລີ່ມ PPSSPP ໃໝ່ເພື Native device resolution = ຄ່າຄວາມລະອຽດດັ້ງເດີມຂອງອຸປະກອນ Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = ຂ້າມການໃຊ້ບັບເຟີເອັບເຟກ (ບໍ່ໃຊ້ບັບເຟີ, ໄວຂຶ້ນ) +Skip Buffer Effects = ຂ້າມການໃຊ້ບັບເຟີເອັບເຟກ (ບໍ່ໃຊ້ບັບເຟີ, ໄວຂຶ້ນ) None = ບໍ່ມີ Number of Frames = Number of frames Off = ປິດ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index aff20af2e2..6d54606a83 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Nusipirkti &Gold Control Mapping... = Va&ldymo mygtukų keitimas... Debugging = &Ekspermentas @@ -173,7 +172,7 @@ Log Console = "&Statuso" konsolė Memory View... = Atminties &rodymas... More Settings... = &Daugiau parametrų... Nearest = &Arčiausias -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Išjungti Open Chat = Open Chat Open Directory... = Atidaryti &vietą... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Abu Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buferinis rodymas BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Jūs turite perkrauti "PPSSPP" programą, kad pakeisti parametrai Native device resolution = Įrenginio rezoliucija Nearest = Arčiausias No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Nieko Number of Frames = Number of frames Off = Išjungti diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 3cd85dd7c4..e785b696e3 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bikubik Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Beli ve&rsi Gold Control Mapping... = P&emetaan kawalan... Debugging = &Pepijat @@ -173,7 +172,7 @@ Log Console = &Log Konsol Memory View... = Lihat &Memori... More Settings... = &Tetapan lanjutan... Nearest = &Terdekat -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Tutup Open Chat = Open Chat Open Directory... = Buka &Penyimpanan... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Keduanya Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Terdekat No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Tiada Number of Frames = Number of frames Off = Tutup diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 9b8c2cef4a..f9b4823c0d 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -129,7 +129,6 @@ Backend = &Renderbackend (herstart PPSSPP) Bicubic = &Bicubisch Break = Break Break on Load = Break on load -Buffered Rendering = &Gebufferde weergave Buy Gold = Gold &kopen Control Mapping... = Bestur&ing toewijzen... Debugging = &Fouten opsporen @@ -173,7 +172,7 @@ Log Console = Logboek&console Memory View... = &Geheugenweergave... More Settings... = &Meer instellingen... Nearest = &Naaste buur -Non-Buffered Rendering = &Buffereffecten nalaten (niet-gebufferd, sneller) +Skip Buffer Effects = &Buffereffecten nalaten (niet-gebufferd, sneller) Off = &Uit Open Chat = Open Chat Open Directory... = &Map openen... @@ -473,7 +472,6 @@ BlockTransfer Tip = Sommige games vereisen dat deze optie aan staat voor juiste BlockTransferRequired = Waarschuwing: Deze game vereist de optie Blokoverdrachteffecten simuleren. Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Gebufferde weergave BufferedRenderingRequired = Waarschuwing: Deze game vereist een "gebufferde renderingmodus". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = U moet PPSSPP herstarten om de wijzigingen door te voeren. Native device resolution = Apparaatresolutie Nearest = Naaste buur No buffer = No buffer -Non-Buffered Rendering = Buffereffecten nalaten (niet-gebufferd, sneller) +Skip Buffer Effects = Buffereffecten nalaten (niet-gebufferd, sneller) None = Geen Number of Frames = Number of frames Off = Uit diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 132178a7e6..d18cfb601e 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffrad rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nermest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Ingen Number of Frames = Number of frames Off = Off diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 82a63c4757..3afd586155 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -129,7 +129,6 @@ Backend = &Sterownik obrazu (Restartuje PPSSPP) Bicubic = Bicubic (Dwusześcienne) Break = Zatrzymaj Break on Load = Zatrzymaj po załadowaniu -Buffered Rendering = Renderowanie buforowe Buy Gold = Kup wersję Gold Control Mapping... = Ustawienia przycisków... Debugging = &Debugowanie @@ -173,7 +172,7 @@ Log Console = Konsola dziennika zdarzeń Memory View... = Podgląd pamięci... More Settings... = Więcej ustawień... Nearest = Najbliższe -Non-Buffered Rendering = &Nie renderuj efektów z bufora (niebuforowane, szybsze) +Skip Buffer Effects = &Nie renderuj efektów z bufora (niebuforowane, szybsze) Off = Wyłącz Open Chat = Otwórz Chat Open Directory... = Otwórz katalog... @@ -473,7 +472,6 @@ BlockTransfer Tip = Niektóre gry wymagają włączenia tej opcji do poprawnego BlockTransferRequired = Uwaga: Ta gra wymaga włączonej opcji "Symuluj efekty transferu bloków". Both = Oba Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Renderowanie buforowe BufferedRenderingRequired = Uwaga: Ta gra wymaga włączonej opcji "Renderowanie buforowe". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Musisz zrestartować PPSSPP, aby zobaczyć zmiany. Native device resolution = Natywna rozdzielczość urządzenia Nearest = Najbliższe No buffer = No buffer -Non-Buffered Rendering = Nie renderuj efektów z bufora (niebuforowane, szybsze) +Skip Buffer Effects = Nie renderuj efektów z bufora (niebuforowane, szybsze) None = Wył. Number of Frames = Ilość klatek Off = Wył. diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 952c540f0b..40d08c1294 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -153,7 +153,6 @@ Backend = Backend de &renderização (Reinicia o PPSSPP) Bicubic = &Bi-cúbico Break = Parar Break on Load = Parar ao carregar -Buffered Rendering = &Renderização com buffer Buy Gold = Comprar &Gold Control Mapping... = M&apeamento dos controles... Debugging = &Debug @@ -197,7 +196,7 @@ Log Console = &Console dos logs Memory View... = Visualização da &memória... More Settings... = &Mais configurações... Nearest = &Mais próximo -Non-Buffered Rendering = &Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = &Ignorar efeitos do buffer (sem buffer, mais rápido) Off = &Desligado Open Chat = Abrir Bate-Papo Open Directory... = Abrir &diretório... @@ -497,7 +496,6 @@ BlockTransfer Tip = Alguns jogos requerem que isto esteja Ligado pros gráficos BlockTransferRequired = Aviso: Esse jogo requer que a "simulação dos efeitos de transferência dos blocos" esteja definida como Ligada. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos comandos dos gráficos (mais rápido, atraso na entrada dos dados) -Buffered Rendering = Renderização com buffer BufferedRenderingRequired = Aviso: Este jogo requer que o "modo de renderização" esteja definido "com buffer". Camera = Câmera Camera Device = Dispositivo de câmera @@ -548,7 +546,7 @@ Must Restart = Você deve reiniciar o PPSSPP pra esta mudança ter efeito. Native device resolution = Resolução nativa do dispositivo Nearest = Mais próximo No buffer = Sem buffer -Non-Buffered Rendering = Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = Ignorar efeitos do buffer (sem buffer, mais rápido) None = Nenhum Number of Frames = Número de frames Off = Desligado diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 3027a3c81e..298880849e 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -153,7 +153,6 @@ Backend = API de &renderização (Reinicia o PPSSPP) Bicubic = &Bi-cúbico Break = Parar Break on Load = Parar ao carregar -Buffered Rendering = &Renderização com buffer Buy Gold = Comprar &Gold Control Mapping... = M&apeamento dos controlos... Debugging = &Depurar @@ -197,7 +196,7 @@ Log Console = &Console dos Logs Memory View... = Visualização da &memória... More Settings... = &Mais Definições... Nearest = &Mais próximo -Non-Buffered Rendering = &Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = &Ignorar efeitos do buffer (sem buffer, mais rápido) Off = &Desligado Open Chat = Abrir Bate-Papo Open Directory... = Abrir &Diretório... @@ -497,7 +496,6 @@ BlockTransfer Tip = Alguns jogos requerem que esta opção esteja habilitada par BlockTransferRequired = Aviso: Este jogo requer que a "Simulação dos Efeitos de Transferência dos Blocos" esteja habilitada. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos Comandos Gráficos (mais rápido, atraso na entrada dos dados) -Buffered Rendering = Renderização com Buffer BufferedRenderingRequired = Aviso: Este jogo requer que o "modo de renderização" esteja definido "com buffer". Camera = Câmera Camera Device = Dispositivo de câmera @@ -548,7 +546,7 @@ Must Restart = Deverás reiniciar o PPSSPP para esta mudança ter efeito. Native device resolution = Resolução Nativa do Dispositivo Nearest = Mais próximo No buffer = Sem buffer -Non-Buffered Rendering = Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = Ignorar efeitos do buffer (sem buffer, mais rápido) None = Nenhum Number of Frames = Número de quadros Off = Desligado diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 055ff8f9ff..e6491a68e2 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambele Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Afișare cu stocare BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Trebuie să resartezi PPSSPP pt. ca această schimbare să aibă Native device resolution = Rezoluție nativă dispozitiv Nearest = Apropiată No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Fără Number of Frames = Number of frames Off = Oprit diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index d3c867b2fe..28548faa8a 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -129,7 +129,6 @@ Backend = Бэкенд &рендеринга (нужен перезапуск) Bicubic = &Бикубическое Break = Остановить Break on Load = Остановить после загрузки -Buffered Rendering = &Буферированный рендеринг Buy Gold = Купить &Gold Control Mapping... = Назначение &кнопок... Debugging = &Отладка @@ -173,7 +172,7 @@ Log Console = Консоль отладки Memory View... = Просмотрщик па&мяти... More Settings... = &Ещё настройки... Nearest = &Ближайший -Non-Buffered Rendering = &Пропускать эффекты (небуферированный, быстрее) +Skip Buffer Effects = &Пропускать эффекты (небуферированный, быстрее) Off = В&ыключено Open Chat = Открыть чат Open Directory... = Открыть &папку... @@ -473,7 +472,6 @@ BlockTransfer Tip = Требуется для корректной график BlockTransferRequired = Предупреждение: для этой игры требуется включить "Симуляцию эффектов от передачи блоков" Both = Оба Buffer graphics commands (faster, input lag) = Команды буферированной графики (быстрее, задержка ввода) -Buffered Rendering = Буферированный рендеринг BufferedRenderingRequired = Предупреждение: для этой игры требуется буферированный режим рендеринга. Camera = Камера Camera Device = Устройство камеры @@ -526,7 +524,7 @@ Must Restart = Вы должны перезапустить PPSSPP, чтобы Native device resolution = Разрешение устройства Nearest = Ближайший No buffer = Нет буфера -Non-Buffered Rendering = Пропускать эффекты (небуферированный) +Skip Buffer Effects = Пропускать эффекты (небуферированный) None = Выключено Number of Frames = Количество кадров Off = Выключено diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index d4bedc6d5f..2bf12a4af4 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -129,7 +129,6 @@ Backend = Backend Bicubic = Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = Buffrad rendering Buy Gold = Buy Gold Control Mapping... = Kontrollmappning... Debugging = Debuggning @@ -173,7 +172,7 @@ Log Console = Loggkonsol Memory View... = Minnesvy... More Settings... = Mer inställningar... Nearest = Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = Off Open Chat = Open Chat Open Directory... = Öppna mapp... @@ -473,7 +472,6 @@ BlockTransfer Tip = Vissa spel kräver att denna inställning är på. BlockTransferRequired = Varning: Detta spel kräver att "Simulera blocktransfer-effekter" är påslaget. Both = Båda Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffrad rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Kamera Camera Device = Kamera-enhet @@ -525,7 +523,7 @@ Must Restart = Starta om PPSSPP för att ändringen ska få effekt. Native device resolution = Native device resolution Nearest = Närmast No buffer = No buffer -Non-Buffered Rendering = Skippa buffereffekter (snabbare, risk för fel) +Skip Buffer Effects = Skippa buffereffekter (snabbare, risk för fel) None = Inget Number of Frames = Antal frames Off = Off diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 1dca37dcc5..63c37442f1 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = Buffered Rendering Buy Gold = Bilhin ang Gold Control Mapping... = Control Mapping... Debugging = Debug @@ -173,7 +172,7 @@ Log Console = Log Console Memory View... = Memory View... More Settings... = Karagdagang settings... Nearest = Nearest -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects Off = Off Open Chat = Open Chat Open Directory... = Buksan ang Directory... @@ -473,7 +472,6 @@ BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = BABALA: This game requires "simulate block transfer effects" to be set to On. Both = Pareho Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered Rendering BufferedRenderingRequired = BABALA: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Kailangan i-restart ang PPSSPP upang maging epiktibo ito Native device resolution = Native device resolution Nearest = Pinakamalapit No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, mabilis) +Skip Buffer Effects = Skip buffer effects (non-buffered, mabilis) None = Wala Number of Frames = Bilang ng frames Off = Patayin diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 6cdb15874c..4b0d42f964 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -129,7 +129,6 @@ Backend = การแสดงผลที่สนับสนุน (ต้ Bicubic = ไบคิวบิค Break = หยุด Break on Load = หยุดเมื่อโหลด -Buffered Rendering = การแสดงผลแบบใช้บัฟเฟอร์ Buy Gold = ซื้อแบบตัวสีทอง Control Mapping... = แผงปรับการคุมควบ... Debugging = แก้ไขจุดบกพร่อง @@ -173,7 +172,7 @@ Log Console = เก็บค่าคอนโซล Memory View... = มุมมองค่าความจำ... More Settings... = การตั้งค่าอื่นๆ... Nearest = แบบใกล้เคียง -Non-Buffered Rendering = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) +Skip Buffer Effects = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) Off = ปิด Open Chat = เปิดหน้าต่างแชท Open Directory... = เปิดแหล่งที่เก็บ... @@ -473,7 +472,6 @@ BlockTransfer Tip = บางเกมจำเป็นต้องเปิด BlockTransferRequired = คำเตือน: เกมนี้ต้องปรับใช้งาน "จำลองผลปิดกั้นการส่งผ่านข้อมูลเอฟเฟ็คท์" ด้วย Both = ใช้ทั้งคู่ Buffer graphics commands (faster, input lag) = ควบคุมกราฟิกบัฟเฟอร์ (เร็วขึ้น, อาจทำให้เกิดอินพุตแล็ก) -Buffered Rendering = การแสดงผลแบบใช้บัฟเฟอร์ BufferedRenderingRequired = คำเตือน: เกมนี้ต้องปรับใช้งานในโหมด "การแสดงผลแบบใช้บัฟเฟอร์" Camera = กล้อง Camera Device = กล้องที่พร้อมใช้งาน @@ -525,7 +523,7 @@ Must Restart = คุณควรรีสตาร์ท PPSSPP อีกคร Native device resolution = ค่าความละเอียดดั้งเดิมของอุปกรณ์ Nearest = แบบใกล้เคียง No buffer = ไม่ใช้บัฟเฟอร์ -Non-Buffered Rendering = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) +Skip Buffer Effects = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) None = ไม่มี Number of Frames = อิงจากค่าจำนวนเฟรม Off = ปิด diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 4a98ecfeb9..bcca5aeff4 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -131,7 +131,6 @@ Backend = Oluşturma &Arkaucu (PPSSPP'yi yeniden başlatır) Bicubic = &Bikübik Break = Break Break on Load = Break on load -Buffered Rendering = &Tampon bellek ile oluştur Buy Gold = Altın Sürümünü Satın Al Control Mapping... = Kontrol Ayarlama... Debugging = &Hata Ayıklama @@ -175,7 +174,7 @@ Log Console = &Günlük Konsolu Memory View... = Bellek &Görünümü... More Settings... = &Daha Fazla Ayar... Nearest = &En Yakın -Non-Buffered Rendering = &Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) +Skip Buffer Effects = &Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) Off = &Kapalı Open Chat = Open Chat Open Directory... = Dizin Aç... @@ -475,7 +474,6 @@ BlockTransfer Tip = Bazı oyunlarda doğru grafikler için bu ayarın açık olm BlockTransferRequired = Uyarı: Bu oyun Blok Aktarım Simülasyon Modunun Açık olmasını gerektirir. Both = İkisi de Buffer graphics commands (faster, input lag) = Grafik komutlarını arabellekle (daha hızlı, input lag'e sebep olabilir) -Buffered Rendering = Yükleyerek işleme BufferedRenderingRequired = Uyarı: Bu oyun "işleme modunun" "yükleyerek işleme"ye alınmasını gerektirir. Camera = Kamera Camera Device = Kamera cihazı @@ -528,7 +526,7 @@ Must Restart = Bu değişikliğin uygulanması için PPSSPP'yi yeniden başlatma Native device resolution = Yerel aygıt çözünürlüğü Nearest = En yakın No buffer = Arabellek/tampon bellek yok -Non-Buffered Rendering = Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) +Skip Buffer Effects = Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) None = Hiçbiri Number of Frames = Kare sayısı Off = Kapalı @@ -1196,7 +1194,7 @@ YYYYMMDD = YYYYAAGG [TextureShaders] Off = Off TexMMPX = TexMMPX -Tex2xBRZ = Tex2xBRZ +Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ [Themes] diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index b4581397ae..cde502baac 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -129,7 +129,6 @@ Backend = Бекенд &рендерингу (потрібне перезава Bicubic = &Бікубічний Break = Перервати Break on Load = Перервати при завантаженні -Buffered Rendering = Буферинізований рендеринг Buy Gold = Купити &Gold Control Mapping... = Призначення &кнопок... Debugging = &Налагодження @@ -173,7 +172,7 @@ Log Console = Консоль журналу (log) Memory View... = Переглядач па&м'яті... More Settings... = &Ще налаштування... Nearest = &Найближчий -Non-Buffered Rendering = &Пропустити ефекти (небуферований, швидше) +Skip Buffer Effects = &Пропустити ефекти (небуферований, швидше) Off = В&имкнено Open Chat = Open Chat Open Directory... = Відкрити &папку... @@ -473,7 +472,6 @@ BlockTransfer Tip = Потрібно для правильної графіки BlockTransferRequired = Попередження: Ця гра вимагає, щоб "імітувати ефекти передачі блоку" було встановлено на Увімкнено. Both = Обидва Buffer graphics commands (faster, input lag) = Буферні графічні команди (швидше, можливі глюки) -Buffered Rendering = Буферинізований рендеринг BufferedRenderingRequired = Попередження: Ця гра вимагає, щоб "режим візуалізації" був встановлений на "буферний". Camera = Камера Camera Device = Пристрій камери @@ -525,7 +523,7 @@ Must Restart = Ви повинні перезавантажити PPSSPP, щоб Native device resolution = Роздільна здатність пристрою Nearest = Найближчий No buffer = Без буфера -Non-Buffered Rendering = Пропускати ефекти (небуференізованний, швидше) +Skip Buffer Effects = Пропускати ефекти (небуференізованний, швидше) None = Немає Number of Frames = Кількість кадрів Off = Вимкнено diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index c1593c6c33..918bfc6e91 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -129,7 +129,6 @@ Backend = Kết xuất từ thư viện đồ họa (Khởi động lại PPSSPP Bicubic = Bicubic (mịn) Break = Break Break on Load = Hủy bỏ trong mục load -Buffered Rendering = Dựng hình có bộ nhớ đệm Buy Gold = Mua PPSSPP Gold Control Mapping... = Chỉnh nút... Debugging = Debug @@ -173,7 +172,7 @@ Log Console = Log Console Memory View... = Xem bộ nhớ... More Settings... = Các thiết lập khác... Nearest = Gần nhất -Non-Buffered Rendering = Bỏ qua hiệu ứng đệm (Không bộ nhớ đệm, nhanh hơn) +Skip Buffer Effects = Bỏ qua hiệu ứng đệm (Không bộ nhớ đệm, nhanh hơn) Off = Tắt Open Chat = Open Chat Open Directory... = Mở thư mục... @@ -473,7 +472,6 @@ BlockTransfer Tip = Một số trò chơi yêu cầu đồ họa thích hợp. BlockTransferRequired = Cảnh báo: Trò chơi này yêu cầu mở "simulate block transfer effects" Both = Cả hai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Dựng hình có bộ nhớ đệm BufferedRenderingRequired = Cảnh báo: Trò chơi này yêu cầu "chế độ kết xuất" được đặt thành "được đệm". Camera = Camera Camera Device = Camera device @@ -525,7 +523,7 @@ Must Restart = Bạn cần khởi động lại PPSSPP để những thay đổi Native device resolution = Độ phân giải tự nhiên. Nearest = Gần nhất No buffer = No buffer -Non-Buffered Rendering = Bỏ qua hiệu ứng đệm (không bộ nhớ đệm, nhanh hơn) +Skip Buffer Effects = Bỏ qua hiệu ứng đệm (không bộ nhớ đệm, nhanh hơn) None = Không Number of Frames = Number of frames Off = Tắt diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 3d2682c3d6..42e4d780da 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -129,7 +129,6 @@ Backend = 渲染引擎(需要PPSSPP重新启动) (&b) Bicubic = 双三次 (&B) Break = 停止 Break on Load = 载入后停止 -Buffered Rendering = 缓冲渲染 (&B) Buy Gold = 购买黄金版 (&G) Control Mapping... = 按键映射 (&o)... Debugging = 调试 (&D) @@ -173,7 +172,7 @@ Log Console = 控制台日志 (&L) Memory View... = 查看内存 (&V)... More Settings... = 更多设置 (&M)... Nearest = 邻近取样 (&N) -Non-Buffered Rendering = 跳过缓冲效果(非缓冲, 更快) (&S) +Skip Buffer Effects = 跳过缓冲效果(非缓冲, 更快) (&S) Off = 关闭 (&O) Open Chat = 打开聊天 Open Directory... = 打开路径(&D)... @@ -473,7 +472,6 @@ BlockTransfer Tip = 有些游戏需要将此选项设置为开以显示正确的 BlockTransferRequired = 警告:此游戏需要将"模拟块传输模式"设置为开。 Both = 全部显示 Buffer graphics commands (faster, input lag) = 缓冲图形命令(更快, 有输入延迟) -Buffered Rendering = 缓冲渲染 BufferedRenderingRequired = 警告:此游戏需要将"渲染模式"设置为"缓冲渲染"。 Camera = 摄像头 Camera Device = 摄像头设备 @@ -525,7 +523,7 @@ Must Restart = 重启PPSSPP才能使这项设置生效。 Native device resolution = 本机原生的分辨率 Nearest = 邻近取样 No buffer = 不缓冲 -Non-Buffered Rendering = 跳过缓冲(更快) +Skip Buffer Effects = 跳过缓冲(更快) None = 不显示 Number of Frames = 帧的数量 Off = 关闭 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 7b74b3e4a3..24b8553d7d 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -129,7 +129,6 @@ Backend = 轉譯後端 (需要重新啟動) (&b) Bicubic = 雙立方 (&B) Break = 中斷 Break on Load = 載入時中斷 -Buffered Rendering = 緩衝轉譯 (&B) Buy Gold = 購買黃金版 (&G) Control Mapping... = 控制對應 (&O)… Debugging = 偵錯 (&D) @@ -173,7 +172,7 @@ Log Console = 記錄主控台 (&L) Memory View... = 記憶體檢視 (&V)… More Settings... = 更多設定 (&M)… Nearest = 鄰近取樣 (&N) -Non-Buffered Rendering = 跳過緩衝區效果 (非緩衝區,更快) (&S) +Skip Buffer Effects = 跳過緩衝區效果 (非緩衝區,更快) (&S) Off = 關閉 (&O) Open Chat = 開啟聊天 Open Directory... = 開啟目錄 (&D)… @@ -473,7 +472,6 @@ BlockTransfer Tip = 部分遊戲需要開啟此項以顯示正確的圖形 BlockTransferRequired = 警告:這個遊戲需要開啟「模擬區塊傳輸效果」 Both = 全部 Buffer graphics commands (faster, input lag) = 緩衝圖形命令 (更快,有輸入延遲) -Buffered Rendering = 緩衝轉譯 BufferedRenderingRequired = 警告:這個遊戲需要將「轉譯模式」設為「緩衝轉譯」 Camera = 相機 Camera Device = 相機裝置 @@ -524,7 +522,7 @@ Must Restart = 您必須重新啟動 PPSSPP 以使這項變更生效 Native device resolution = 原生裝置解析度 Nearest = 鄰近取樣 No buffer = 無緩衝 -Non-Buffered Rendering = 跳過緩衝效果 (無緩衝,更快) +Skip Buffer Effects = 跳過緩衝效果 (無緩衝,更快) None = 無 Number of Frames = 影格數 Off = 關閉 @@ -863,9 +861,9 @@ tools = 使用的自由工具: # Add translators1-6 for up to 6 lines of translator credits. # Leave extra lines blank. 4 contributors per line seems to look best. translators1 = sum2012, xujibbs, leoxxx, Adeptus2 -translators2 = -translators3 = -translators4 = +translators2 = +translators3 = +translators4 = translators5 = translators6 = Twitter @PPSSPP_emu = Twitter @PPSSPP_emu diff --git a/headless/Headless.cpp b/headless/Headless.cpp index ff5c3f94b4..60c3baaa0f 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -420,7 +420,7 @@ int main(int argc, const char* argv[]) // Never report from tests. g_Config.sReportHost.clear(); g_Config.bAutoSaveSymbolMap = false; - g_Config.iRenderingMode = FB_BUFFERED_MODE; + g_Config.bSkipBufferEffects = false; g_Config.bHardwareTransform = true; g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this. g_Config.bVertexCache = false; From c91e7912bfc7cf9407d9d345f7143ec23497bceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 19:30:17 +0100 Subject: [PATCH 222/715] Change "Simulate block transfer" to "Skip GPU Readbacks". Group the speed hacks together --- Core/Config.cpp | 2 +- Core/Config.h | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 6 +- UI/EmuScreen.cpp | 2 +- UI/GameSettingsScreen.cpp | 90 +++++++++++-------------- assets/lang/ar_AE.ini | 1 - assets/lang/az_AZ.ini | 1 - assets/lang/bg_BG.ini | 1 - assets/lang/ca_ES.ini | 1 - assets/lang/cz_CZ.ini | 1 - assets/lang/da_DK.ini | 1 - assets/lang/de_DE.ini | 1 - assets/lang/dr_ID.ini | 1 - assets/lang/es_ES.ini | 1 - assets/lang/es_LA.ini | 1 - assets/lang/fa_IR.ini | 1 - assets/lang/fi_FI.ini | 1 - assets/lang/fr_FR.ini | 1 - assets/lang/gl_ES.ini | 1 - assets/lang/gr_EL.ini | 1 - assets/lang/he_IL.ini | 1 - assets/lang/he_IL_invert.ini | 1 - assets/lang/hr_HR.ini | 1 - assets/lang/hu_HU.ini | 1 - assets/lang/id_ID.ini | 1 - assets/lang/it_IT.ini | 1 - assets/lang/ja_JP.ini | 1 - assets/lang/jv_ID.ini | 1 - assets/lang/ko_KR.ini | 1 - assets/lang/lo_LA.ini | 1 - assets/lang/lt-LT.ini | 1 - assets/lang/ms_MY.ini | 1 - assets/lang/nl_NL.ini | 1 - assets/lang/no_NO.ini | 1 - assets/lang/pl_PL.ini | 1 - assets/lang/pt_BR.ini | 1 - assets/lang/pt_PT.ini | 1 - assets/lang/ro_RO.ini | 1 - assets/lang/ru_RU.ini | 1 - assets/lang/sv_SE.ini | 1 - assets/lang/tg_PH.ini | 1 - assets/lang/th_TH.ini | 1 - assets/lang/tr_TR.ini | 1 - assets/lang/uk_UA.ini | 1 - assets/lang/vi_VN.ini | 1 - assets/lang/zh_CN.ini | 1 - assets/lang/zh_TW.ini | 1 - headless/Headless.cpp | 2 +- 48 files changed, 47 insertions(+), 99 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 8e3c1d76d7..41804f7875 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -937,7 +937,7 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("TextureShader", &g_Config.sTextureShaderName, "Off", true, true), ConfigSetting("ShaderChainRequires60FPS", &g_Config.bShaderChainRequires60FPS, false, true, true), - ReportedConfigSetting("MemBlockTransferGPU", &g_Config.bBlockTransferGPU, true, true, true), + ReportedConfigSetting("SkipGPUReadbacks", &g_Config.bSkipGPUReadbacks, false, true, true), ConfigSetting("GfxDebugOutput", &g_Config.bGfxDebugOutput, false, false, false), ConfigSetting("LogFrameDrops", &g_Config.bLogFrameDrops, false, true, false), diff --git a/Core/Config.h b/Core/Config.h index e4795bfd4b..af20f6289e 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -235,7 +235,7 @@ public: float fCwCheatScrollPosition; float fGameListScrollPosition; int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive - bool bBlockTransferGPU; + bool bSkipGPUReadbacks; int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High bool bHardwareTessellation; bool bShaderCache; // Hidden ini-only setting, useful for debugging shader compile times. diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 8a74467130..a2e4ec05c6 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1346,7 +1346,7 @@ void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *v // Some games will draw to some memory once, and use it as a render-to-texture later. // To support this, we save the first frame to memory when we have a safe w/h. // Saving each frame would be slow. - if (g_Config.bBlockTransferGPU && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { + if (!g_Config.bSkipGPUReadbacks && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight, RASTER_COLOR); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->safeWidth = 0; @@ -1806,7 +1806,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, FlushBeforeCopy(); if (srcH == 0 || srcY + srcH > srcBuffer->bufferHeight) { WARN_LOG_ONCE(btdcpyheight, G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight); - } else if (g_Config.bBlockTransferGPU && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { + } else if (!g_Config.bSkipGPUReadbacks && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { ReadFramebufferToMemory(srcBuffer, 0, srcY, srcBuffer->width, srcH, channel); srcBuffer->usageFlags = (srcBuffer->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; } @@ -2262,7 +2262,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride, dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride); FlushBeforeCopy(); - if (g_Config.bBlockTransferGPU && !srcRect.vfb->memoryUpdated) { + if (!g_Config.bSkipGPUReadbacks && !srcRect.vfb->memoryUpdated) { const int srcBpp = BufferFormatBytesPerPixel(srcRect.vfb->fb_format); const float srcXFactor = (float)bpp / srcBpp; const bool tooTall = srcY + srcRect.h > srcRect.vfb->bufferHeight; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index c046fb01d5..896c939d12 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -332,7 +332,7 @@ void EmuScreen::bootGame(const Path &filename) { host->NotifyUserMessage(gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 15.0f); } - if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.bBlockTransferGPU == false) { + if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.bSkipGPUReadbacks) { auto gr = GetI18NCategory("Graphics"); host->NotifyUserMessage(gr->T("BlockTransferRequired", "Warning: This game requires Simulate Block Transfer Mode to be set to On."), 15.0f); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index d92eed91a1..c551d87721 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -298,24 +298,6 @@ void GameSettingsScreen::CreateViews() { } } - CheckBox *skipBufferEffects = graphicsSettings->Add(new CheckBox(&g_Config.bSkipBufferEffects, gr->T("Skip Buffer Effects"))); - skipBufferEffects->OnClick.Add([=](EventParams &e) { - if (g_Config.bSkipBufferEffects) { - settingInfo_->Show(gr->T("RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games"), e.v); - g_Config.bAutoFrameSkip = false; - } - return UI::EVENT_DONE; - }); - skipBufferEffects->SetDisabledPtr(&g_Config.bSoftwareRendering); - - CheckBox *blockTransfer = graphicsSettings->Add(new CheckBox(&g_Config.bBlockTransferGPU, gr->T("Simulate Block Transfer", "Simulate Block Transfer"))); - blockTransfer->OnClick.Add([=](EventParams &e) { - if (!g_Config.bBlockTransferGPU) - settingInfo_->Show(gr->T("BlockTransfer Tip", "Some games require this to be On for correct graphics"), e.v); - return UI::EVENT_CONTINUE; - }); - blockTransfer->SetDisabledPtr(&g_Config.bSoftwareRendering); - if (deviceType != DEVICE_TYPE_VR) { CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); softwareGPU->SetEnabled(!PSP_IsInited()); @@ -344,6 +326,46 @@ void GameSettingsScreen::CreateViews() { altSpeed2->SetFormat("%i%%"); } + graphicsSettings->Add(new ItemHeader(gr->T("Speed Hacks", "Speed Hacks (can cause rendering errors!)"))); + + CheckBox *skipBufferEffects = graphicsSettings->Add(new CheckBox(&g_Config.bSkipBufferEffects, gr->T("Skip Buffer Effects"))); + skipBufferEffects->OnClick.Add([=](EventParams &e) { + if (g_Config.bSkipBufferEffects) { + settingInfo_->Show(gr->T("RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games"), e.v); + g_Config.bAutoFrameSkip = false; + } + return UI::EVENT_DONE; + }); + skipBufferEffects->SetDisabledPtr(&g_Config.bSoftwareRendering); + + CheckBox *skipGPUReadbacks = graphicsSettings->Add(new CheckBox(&g_Config.bSkipGPUReadbacks, gr->T("Skip GPU Readbacks"))); + skipGPUReadbacks->SetDisabledPtr(&g_Config.bSoftwareRendering); + + CheckBox *vtxCache = graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gr->T("Vertex Cache"))); + vtxCache->OnClick.Add([=](EventParams &e) { + settingInfo_->Show(gr->T("VertexCache Tip", "Faster, but may cause temporary flicker"), e.v); + return UI::EVENT_CONTINUE; + }); + vtxCache->SetEnabledFunc([] { + return !g_Config.bSoftwareRendering && g_Config.bHardwareTransform && g_Config.iGPUBackend != (int)GPUBackend::OPENGL; + }); + + CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)"))); + texBackoff->SetDisabledPtr(&g_Config.bSoftwareRendering); + texBackoff->OnClick.Add([=](EventParams& e) { + settingInfo_->Show(gr->T("Lazy texture caching Tip", "Faster, but can cause text problems in a few games"), e.v); + return UI::EVENT_CONTINUE; + }); + + static const char *quality[] = { "Low", "Medium", "High" }; + PopupMultiChoice *beziersChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iSplineBezierQuality, gr->T("LowCurves", "Spline/Bezier curves quality"), quality, 0, ARRAY_SIZE(quality), gr->GetName(), screenManager())); + beziersChoice->OnChoice.Add([=](EventParams &e) { + if (g_Config.iSplineBezierQuality != 0) { + settingInfo_->Show(gr->T("LowCurves Tip", "Only used by some games, controls smoothness of curves"), e.v); + } + return UI::EVENT_CONTINUE; + }); + graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; @@ -525,38 +547,6 @@ void GameSettingsScreen::CreateViews() { }); swSkin->SetDisabledPtr(&g_Config.bSoftwareRendering); - CheckBox *vtxCache = graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gr->T("Vertex Cache"))); - vtxCache->OnClick.Add([=](EventParams &e) { - settingInfo_->Show(gr->T("VertexCache Tip", "Faster, but may cause temporary flicker"), e.v); - return UI::EVENT_CONTINUE; - }); - vtxCache->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering && g_Config.bHardwareTransform && g_Config.iGPUBackend != (int)GPUBackend::OPENGL; - }); - - CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)"))); - texBackoff->SetDisabledPtr(&g_Config.bSoftwareRendering); - texBackoff->OnClick.Add([=](EventParams& e) { - settingInfo_->Show(gr->T("Lazy texture caching Tip", "Faster, but can cause text problems in a few games"), e.v); - return UI::EVENT_CONTINUE; - }); - - // Seems solid, so we hide the setting. - /*CheckBox *vtxJit = graphicsSettings->Add(new CheckBox(&g_Config.bVertexDecoderJit, gr->T("Vertex Decoder JIT"))); - - if (PSP_IsInited()) { - vtxJit->SetEnabled(false); - }*/ - - static const char *quality[] = { "Low", "Medium", "High" }; - PopupMultiChoice *beziersChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iSplineBezierQuality, gr->T("LowCurves", "Spline/Bezier curves quality"), quality, 0, ARRAY_SIZE(quality), gr->GetName(), screenManager())); - beziersChoice->OnChoice.Add([=](EventParams &e) { - if (g_Config.iSplineBezierQuality != 0) { - settingInfo_->Show(gr->T("LowCurves Tip", "Only used by some games, controls smoothness of curves"), e.v); - } - return UI::EVENT_CONTINUE; - }); - CheckBox *tessellationHW = graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTessellation, gr->T("Hardware Tessellation"))); tessellationHW->OnClick.Add([=](EventParams &e) { settingInfo_->Show(gr->T("HardwareTessellation Tip", "Uses hardware to make curves"), e.v); diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 8cae321f81..3307ba15a3 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -476,7 +476,6 @@ Auto Scaling = ‎تكبير تلقائي Backend = ‎الخلفي Balanced = ‎متناسق Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = ‎الأثنين Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 88dd568f32..64d1778f40 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index f2a48cade1..9411fb92c5 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = И двете Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index fab847026c..2a28a4307f 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicúbic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 08043400a9..8e6fa7105d 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatické zvětšení Backend = Jádro Balanced = Vyrovnané Bicubic = Bikubická -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Obojí Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 06dfd28cee..4f93a65b05 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanceret Bicubic = Bicubisk -BlockTransfer Tip = Nogle spil kræver at denne er tændt for korrekt grafik BlockTransferRequired = Advarsel: Dette spil kræver at simulerede blok overførsel tilstand er tændt. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 4e194329bd..c51eea9b7f 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto Skalierung Backend = Grafik-Backend Balanced = Ausgeglichen Bicubic = Bikubisch -BlockTransfer Tip = Manche Spiele benötigen dies für eine korrekte Darstellung BlockTransferRequired = Warnung: Dieses Spiel benötigt "Blockübertragungseffekte simulieren". Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index ca081a1c09..52e33266ce 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Pa jio duai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 30216ad2cd..cee1d13717 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -468,7 +468,6 @@ Auto Scaling = Autoescalado Backend = Motor gráfico Balanced = Equilibrado Bicubic = Bicúbico -BlockTransfer Tip = Algunos juegos necesitan esta opción para evitar errores gráficos. BlockTransferRequired = AVISO: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos de búfer gráfico (puede generar input lag) diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 76da6dbded..b6df17ab65 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -468,7 +468,6 @@ Auto Scaling = Escalado automático Backend = Motor gráfico Balanced = Balanceado Bicubic = Bicúbico -BlockTransfer Tip = Algunos juegos requieren activarlo para corregir gráficos. BlockTransferRequired = Advertencia: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos gráficos de búfer (puede generar input lag) diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index c082a845b9..f856c6e437 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -468,7 +468,6 @@ Auto Scaling = ‎تنظیم سایز خودکار Backend = ‎گرافیکی API Balanced = ‎متعادل Bicubic = Bicubic -BlockTransfer Tip = ‎در بعضی بازی ها برای نشان دادن درست گرافیک نیاز است BlockTransferRequired = ‎دارد "simulate block transfer effects" هشدار:این گزینه نیاز به روشن بودن Both = ‎سرعت + فریم بر ثانیه Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 6e448250bc..66d6596262 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Molemmat Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 3e87cb10b8..1d010efe05 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -468,7 +468,6 @@ Auto Scaling = Mise à l'échelle auto Backend = Rendu back-end Balanced = Équilibré Bicubic = Bicubique -BlockTransfer Tip = Certains jeux requièrent l'activation de ce paramètre pour obtenir des graphismes corrects BlockTransferRequired = Avertissement : Ce jeu requiert l'activation de "Simuler les effets de transfert de bloc". Both = Vitesse + FPS Buffer graphics commands (faster, input lag) = Commandes graphiques en mémoire tampon (+ rapide, + lag entrée) diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 0144f5cb0d..0364e1feac 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Motor gráfico Balanced = Balanceado Bicubic = Bicúbico -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 53fc6fd553..0d876321b4 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -468,7 +468,6 @@ Auto Scaling = Αυτόματη Κλιμάκωση Backend = Σύστημα Υποστήριξης Balanced = Εξισορροπημένη Bicubic = Διακυβική -BlockTransfer Tip = Ορισμένα παιχνίδια απαιτούν να είναι ενεργοποιημένο για την σωστή επεικόνιση γραφικών. BlockTransferRequired = Προειδοποίηση: Αυτό το παιχνίδι απαιτεί τη λειτουργία προσομοίωσης εφέ μεταφοράς block να είναι ενεργοποιημένη. Both = Όλα Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index f7878259cd..8d559c66d8 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = שניהם Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index ca5a52c0e7..dea835df52 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = םהינש Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 50bf5487c3..6e65118dec 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto mjerenje Backend = Backend Balanced = Balansirano Bicubic = Bikubično -BlockTransfer Tip = Neke igre zahtijevaju ovo na Uključeno za točne grafike BlockTransferRequired = Upozorenje: Ova igra zahtijeva "simulirajte blok transfer efekte" da budu postavljeni na Uključeno. Both = Oboje Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 6be4c6ef72..8f2b003a41 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatikus skálázás Backend = Backend Balanced = Kiegyensúlyozott Bicubic = Bicubic -BlockTransfer Tip = Néhány játék számára ezt be kell kapcsolni ahhoz, hogy helyesen rajzolódjon ki. BlockTransferRequired = Figyelem: Ehhez a játékhoz be kell kapcsolni a "Blokk transzfer effektek szimulálása" opciót! Both = Mindkettő Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index ce169cedad..f28ff33fac 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -468,7 +468,6 @@ Auto Scaling = Penskala otomatis Backend = Penyangga grafis Balanced = Seimbang Bicubic = Bikubik -BlockTransfer Tip = Beberapa permainan memerlukan opsi ini untuk menghindari kesalahan grafis. BlockTransferRequired = Peringatan: Permainan ini membutuhkan "Simulasikan efek transfer blok" dalam keadaan menyala. Both = Keduanya Buffer graphics commands (faster, input lag) = Perintah grafis penyangga (lebih cepat, masukan lag) diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index e16911851f..68d08f8a93 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -468,7 +468,6 @@ Auto Scaling = Scaling automatico Backend = Renderer Balanced = Bilanciato Bicubic = Bicubico -BlockTransfer Tip = Alcuni giochi richiedono che quest'opzione sia attiva per correggere la grafica BlockTransferRequired = Attenzione: Questo gioco richiede l'attivazione di 'Simula gli effetti del blocco trasferimento'. Both = Entrambi Buffer graphics commands (faster, input lag) = Comandi grafici bufferizzati (più rapido, più lag dei comandi) diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 9df017b836..3d0f6eafc4 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -468,7 +468,6 @@ Auto Scaling = 自動的に拡大 Backend = バックエンド Balanced = バランス Bicubic = Bicubic -BlockTransfer Tip = オンにしないと正しく表示できないゲームがいくつかあります BlockTransferRequired = 警告: このゲームは「ブロック転送の効果をシミュレートする」をオンにする必要があります。 Both = 両方 Buffer graphics commands (faster, input lag) = グラフィックスコマンドをバッファする (高速, 入力ラグあり) diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 79220cf2ea..b522a9a4c1 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -468,7 +468,6 @@ Auto Scaling = Njongko Otomatis Backend = Backend Balanced = Imbang Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Kelorone Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 4178d83ec4..337f624cf5 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -468,7 +468,6 @@ Auto Scaling = 자동 스케일링 Backend = 백엔드 Balanced = 평형 Bicubic = 고등차수보간 -BlockTransfer Tip = 일부 게임에서는 올바른 그래픽을 위해 이 기능을 켜야 합니다. BlockTransferRequired = 경고: 이 게임은 "블록 전송 효과 시뮬레이션"을 켬으로 설정해야 합니다. Both = 둘 다 Buffer graphics commands (faster, input lag) = 버퍼 그래픽 명령 (빠름, 입력 지연) diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 9dc2bb3fa8..a5133a73ae 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -468,7 +468,6 @@ Auto Scaling = ປັບຂະໜາດສເກລອັດຕະໂນມັ Backend = ການສະໜັບສະໜູນ Balanced = ສົມດຸນ Bicubic = Bicubic -BlockTransfer Tip = ບາງເກມຕ້ອງເປີດໃຊ້ງານເພື່ອການສະແດງຜົນທີ່ຖືກຕ້ອງ BlockTransferRequired = ຄຳເຕືອນ: ເກມນີ້ຕ້ອງການໃຫ້ເປີດໂໝດ "ຈຳລອງຜົນປິດກັ້ນການສົ່ງຜ່ານຂໍ້ມູນເອັບເຟກ" ນຳ Both = ໃຊ້ທັງ FPS ແລະ Speed Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 6d54606a83..494653f8f5 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = "Bicubic" -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Abu Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index e785b696e3..801a373dfe 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bikubik -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Keduanya Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index f9b4823c0d..83a6aba047 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatisch schalen Backend = Backend Balanced = Gebalanceerd Bicubic = Bicubisch -BlockTransfer Tip = Sommige games vereisen dat deze optie aan staat voor juiste graphics BlockTransferRequired = Waarschuwing: Deze game vereist de optie Blokoverdrachteffecten simuleren. Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index d18cfb601e..cceaa22382 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 3afd586155..5b067680e3 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatyczne skalowanie Backend = Sterownik graficzny Balanced = Zbalansowane Bicubic = Bicubic (Dwusześcienne) -BlockTransfer Tip = Niektóre gry wymagają włączenia tej opcji do poprawnego działania. BlockTransferRequired = Uwaga: Ta gra wymaga włączonej opcji "Symuluj efekty transferu bloków". Both = Oba Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 40d08c1294..45d7e1b867 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -492,7 +492,6 @@ Auto Scaling = Auto-redimensionamento Backend = Backend Balanced = Balanceado Bicubic = Bi-cúbico -BlockTransfer Tip = Alguns jogos requerem que isto esteja Ligado pros gráficos estarem corretos BlockTransferRequired = Aviso: Esse jogo requer que a "simulação dos efeitos de transferência dos blocos" esteja definida como Ligada. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos comandos dos gráficos (mais rápido, atraso na entrada dos dados) diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 298880849e..054d8f0dfd 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -492,7 +492,6 @@ Auto Scaling = Auto-redimensionamento Backend = Backend Balanced = Balanceado Bicubic = Bi-cúbico -BlockTransfer Tip = Alguns jogos requerem que esta opção esteja habilitada para os gráficos estarem corretos. BlockTransferRequired = Aviso: Este jogo requer que a "Simulação dos Efeitos de Transferência dos Blocos" esteja habilitada. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos Comandos Gráficos (mais rápido, atraso na entrada dos dados) diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index e6491a68e2..38d47a05b1 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Mod intern Balanced = Balansat Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambele Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 28548faa8a..082b087730 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -468,7 +468,6 @@ Auto Scaling = Автомасштаб Backend = Бэкенд Balanced = Сбалансированно Bicubic = Бикубический -BlockTransfer Tip = Требуется для корректной графики в некоторых играх BlockTransferRequired = Предупреждение: для этой игры требуется включить "Симуляцию эффектов от передачи блоков" Both = Оба Buffer graphics commands (faster, input lag) = Команды буферированной графики (быстрее, задержка ввода) diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 2bf12a4af4..247e593a79 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balancerad Bicubic = Bicubisk -BlockTransfer Tip = Vissa spel kräver att denna inställning är på. BlockTransferRequired = Varning: Detta spel kräver att "Simulera blocktransfer-effekter" är påslaget. Both = Båda Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 63c37442f1..4815c0023c 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -468,7 +468,6 @@ Auto Scaling = Awto scaling Backend = Backend Balanced = Balanse Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics BlockTransferRequired = BABALA: This game requires "simulate block transfer effects" to be set to On. Both = Pareho Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 4b0d42f964..422f06b13f 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -468,7 +468,6 @@ Auto Scaling = สเกลอัตโนมัติ Backend = การสนับสนุนกราฟิก Balanced = สมดุล Bicubic = ไบคิวบิค -BlockTransfer Tip = บางเกมจำเป็นต้องเปิดใช้งานเพื่อการแสดงผลที่ถูกต้อง BlockTransferRequired = คำเตือน: เกมนี้ต้องปรับใช้งาน "จำลองผลปิดกั้นการส่งผ่านข้อมูลเอฟเฟ็คท์" ด้วย Both = ใช้ทั้งคู่ Buffer graphics commands (faster, input lag) = ควบคุมกราฟิกบัฟเฟอร์ (เร็วขึ้น, อาจทำให้เกิดอินพุตแล็ก) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index bcca5aeff4..3bdaf3ef39 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -470,7 +470,6 @@ Auto Scaling = Otomatik ölçekleme Backend = Arkauç Balanced = Dengeli Bicubic = Çift Kübik -BlockTransfer Tip = Bazı oyunlarda doğru grafikler için bu ayarın açık olması gerekir BlockTransferRequired = Uyarı: Bu oyun Blok Aktarım Simülasyon Modunun Açık olmasını gerektirir. Both = İkisi de Buffer graphics commands (faster, input lag) = Grafik komutlarını arabellekle (daha hızlı, input lag'e sebep olabilir) diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index cde502baac..2105606270 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -468,7 +468,6 @@ Auto Scaling = Автоматичне масштабування Backend = Бекенд Balanced = Збалансовано Bicubic = Бікубічний -BlockTransfer Tip = Потрібно для правильної графіки в деяких іграх BlockTransferRequired = Попередження: Ця гра вимагає, щоб "імітувати ефекти передачі блоку" було встановлено на Увімкнено. Both = Обидва Buffer graphics commands (faster, input lag) = Буферні графічні команди (швидше, можливі глюки) diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 918bfc6e91..2cf347c956 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -468,7 +468,6 @@ Auto Scaling = Tự động nhân rộng Backend = Thư viện đồ họa Balanced = Cân bằng Bicubic = Bicubic (mịn) -BlockTransfer Tip = Một số trò chơi yêu cầu đồ họa thích hợp. BlockTransferRequired = Cảnh báo: Trò chơi này yêu cầu mở "simulate block transfer effects" Both = Cả hai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 42e4d780da..42bdca4099 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -468,7 +468,6 @@ Auto Scaling = 自动缩放 Backend = 渲染引擎 Balanced = 均衡 Bicubic = 双三次 -BlockTransfer Tip = 有些游戏需要将此选项设置为开以显示正确的图形 BlockTransferRequired = 警告:此游戏需要将"模拟块传输模式"设置为开。 Both = 全部显示 Buffer graphics commands (faster, input lag) = 缓冲图形命令(更快, 有输入延迟) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 24b8553d7d..a1cbd6c878 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -468,7 +468,6 @@ Auto Scaling = 自動縮放 Backend = 後端 Balanced = 平衡 Bicubic = 雙立方 -BlockTransfer Tip = 部分遊戲需要開啟此項以顯示正確的圖形 BlockTransferRequired = 警告:這個遊戲需要開啟「模擬區塊傳輸效果」 Both = 全部 Buffer graphics commands (faster, input lag) = 緩衝圖形命令 (更快,有輸入延遲) diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 60c3baaa0f..eb29a26500 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -421,6 +421,7 @@ int main(int argc, const char* argv[]) g_Config.sReportHost.clear(); g_Config.bAutoSaveSymbolMap = false; g_Config.bSkipBufferEffects = false; + g_Config.bSkipGPUReadbacks = false; g_Config.bHardwareTransform = true; g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this. g_Config.bVertexCache = false; @@ -439,7 +440,6 @@ int main(int argc, const char* argv[]) g_Config.bVertexDecoderJit = true; g_Config.bSoftwareRendering = coreParameter.gpuCore == GPUCORE_SOFTWARE; g_Config.bSoftwareRenderingJit = true; - g_Config.bBlockTransferGPU = true; g_Config.iSplineBezierQuality = 2; g_Config.bHighQualityDepth = true; g_Config.bMemStickInserted = true; From f02c983a63168badf260000063815c2d4c916575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 19:40:02 +0100 Subject: [PATCH 223/715] lang: Remove obsolete keys, add new untranslated ones :( --- Tools/langtool/src/section.rs | 8 +++++--- assets/lang/ar_AE.ini | 5 +++-- assets/lang/az_AZ.ini | 5 +++-- assets/lang/bg_BG.ini | 5 +++-- assets/lang/ca_ES.ini | 5 +++-- assets/lang/cz_CZ.ini | 5 +++-- assets/lang/da_DK.ini | 5 +++-- assets/lang/de_DE.ini | 5 +++-- assets/lang/dr_ID.ini | 5 +++-- assets/lang/en_US.ini | 8 +++----- assets/lang/es_ES.ini | 5 +++-- assets/lang/es_LA.ini | 5 +++-- assets/lang/fa_IR.ini | 5 +++-- assets/lang/fi_FI.ini | 5 +++-- assets/lang/fr_FR.ini | 5 +++-- assets/lang/gl_ES.ini | 5 +++-- assets/lang/gr_EL.ini | 5 +++-- assets/lang/he_IL.ini | 5 +++-- assets/lang/he_IL_invert.ini | 5 +++-- assets/lang/hr_HR.ini | 5 +++-- assets/lang/hu_HU.ini | 5 +++-- assets/lang/id_ID.ini | 5 +++-- assets/lang/it_IT.ini | 9 ++++++--- assets/lang/ja_JP.ini | 5 +++-- assets/lang/jv_ID.ini | 5 +++-- assets/lang/ko_KR.ini | 5 +++-- assets/lang/lo_LA.ini | 5 +++-- assets/lang/lt-LT.ini | 5 +++-- assets/lang/ms_MY.ini | 5 +++-- assets/lang/nl_NL.ini | 5 +++-- assets/lang/no_NO.ini | 5 +++-- assets/lang/pl_PL.ini | 5 +++-- assets/lang/pt_BR.ini | 5 +++-- assets/lang/pt_PT.ini | 5 +++-- assets/lang/ro_RO.ini | 5 +++-- assets/lang/ru_RU.ini | 5 +++-- assets/lang/sv_SE.ini | 5 +++-- assets/lang/tg_PH.ini | 5 +++-- assets/lang/th_TH.ini | 5 +++-- assets/lang/tr_TR.ini | 8 +++++--- assets/lang/uk_UA.ini | 5 +++-- assets/lang/vi_VN.ini | 5 +++-- assets/lang/zh_CN.ini | 6 +++--- assets/lang/zh_TW.ini | 5 +++-- 44 files changed, 139 insertions(+), 95 deletions(-) diff --git a/Tools/langtool/src/section.rs b/Tools/langtool/src/section.rs index dbb097832a..f57c2e3563 100644 --- a/Tools/langtool/src/section.rs +++ b/Tools/langtool/src/section.rs @@ -96,9 +96,11 @@ impl Section { continue; } if !other.lines.iter().any(|line| line.starts_with(prefix)) { - println!("Commenting out: {}", line); - // Comment out the line. - *line = "#".to_owned() + line; + if !prefix.contains("URL") { + println!("Commenting out: {}", line); + // Comment out the line. + *line = "#".to_owned() + line; + } } } } diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 3307ba15a3..2dc5aa69f1 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -476,7 +476,6 @@ Auto Scaling = ‎تكبير تلقائي Backend = ‎الخلفي Balanced = ‎متناسق Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = ‎الأثنين Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -506,6 +505,7 @@ Frame Skipping = ‎تخطي الإطارات Frame Skipping Type = Frame skipping type FullScreen = ‎الشاشة الكاملة GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware transform @@ -553,11 +553,12 @@ Screen layout = Screen layout Screen Scaling Filter = ‎فلتر تكبير حجم الشاشة Show Debug Statistics = ‎أظهر معلومات التصحيح Show FPS Counter = ‎أظهر عداد الـFPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ‎تصيير السوفت وير (slow) Software Skinning = ‎طلاء برمجي SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = ‎السرعة +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = ‎المط Texture Filter = ‎منقي الرسوم Texture Filtering = ‎مفلتر الرسوم diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 64d1778f40..383ec9b5d4 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Kvadrat Keçid et (Sürət) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Təchizat Dönüşüm @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (experimental) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Texture filtering Texture Filtering = Texture filtering diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 9411fb92c5..853d40a580 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = И двете Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Прескачане на кадри Frame Skipping Type = Frame skipping type FullScreen = Цял екран GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware Transform @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Покажи debug инфо Show FPS Counter = Покажи брояча за кадри в сек. -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (експериментално) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Скорост +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Текстурно филтриране Texture Filtering = Текстурно филтриране diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 2a28a4307f..393796df05 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicúbic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Saltar fotogrames (skip) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Transformació per maquinari @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (experimental) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Texture filtering Texture Filtering = Texture filtering diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 8e6fa7105d..1f2dcbf436 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatické zvětšení Backend = Jádro Balanced = Vyrovnané Bicubic = Bikubická -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Obojí Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Přeskakování snímků Frame Skipping Type = Frame skipping type FullScreen = Režim celé obrazovky GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Nastavení hacků (Mohou způsobit problémy) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardwarová transformace @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Filtr změny velikosti obrazovky Show Debug Statistics = Zobrazit statistiky ladění Show FPS Counter = Zobrazit počítadlo -Simulate Block Transfer = Simulovat efekty přesunu bloků +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Softwarové vykreslování (experimentální) Software Skinning = Textury aplikuje software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Rychlost +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Roztažení Texture Filter = Filtr textur Texture Filtering = Filtrování textur diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 4f93a65b05..72f0431317 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanceret Bicubic = Bicubisk -BlockTransferRequired = Advarsel: Dette spil kræver at simulerede blok overførsel tilstand er tændt. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Frameskipping Frame Skipping Type = Frame skipping type FullScreen = Fuldskærm GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack indstillinger (kan give fejl) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware transformering @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Skærmskaleringsfilter Show Debug Statistics = Vis debugstatistik Show FPS Counter = Vis FPS -Simulate Block Transfer = Simuler blokoverførsel effekter +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (eksperiment) Software Skinning = Software skinning SoftwareSkinning Tip = Kombiner begrænset model tegning af CPU, hurtigere i fleste spil Speed = Hastighed +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Texturfilter Texture Filtering = Texturfiltrering diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index c51eea9b7f..fb0056e3dc 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto Skalierung Backend = Grafik-Backend Balanced = Ausgeglichen Bicubic = Bikubisch -BlockTransferRequired = Warnung: Dieses Spiel benötigt "Blockübertragungseffekte simulieren". Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warnung: Bei diesem Spiel muss "Rendering Modus" auf "Gepuffert" gesetzt werden. @@ -498,6 +497,7 @@ Frame Skipping = Bilder überspringen Frame Skipping Type = Typ für Bilder überspringen FullScreen = Vollbild GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hacks (kann zu Fehlern führen) Hardware Tessellation = Hardware Tessellation Hardware Transform = Hardware Transformierung @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Filter für Bildskalierung Show Debug Statistics = Debugstatistiken anzeigen Show FPS Counter = FPS anzeigen -Simulate Block Transfer = Blockübertragungseffekte simulieren +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software Renderer (experimentell) Software Skinning = Software Skinning SoftwareSkinning Tip = Reduziert Grafikbefehle und schneller in Spielen mit erweiterter Skinning-Technik, in anderen Spielen langsamer Speed = Geschwindigkeit +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Strecken Texture Filter = Texturfilter Texture Filtering = Texturfilterung diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 52e33266ce..1988cada18 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Pa jio duai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Frameskip Frame Skipping Type = Frame skipping type FullScreen = Layar pol GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Sullei Hardware @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Padenni Debugna Show FPS Counter = Padenni FPSna -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Pakeanni Software Tampilkan (dicoba-cobara) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Lassinna +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Panyaring Texture Texture Filtering = Saring i Texture diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index b66ccc4ee1..20450f8351 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -492,8 +492,7 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -563,19 +562,18 @@ RenderDuplicateFrames Tip = Can make framerate smoother in games that run at low Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (slow) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Texture filtering Texture Filtering = Texture filtering diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index cee1d13717..2f5dd72031 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -468,7 +468,6 @@ Auto Scaling = Autoescalado Backend = Motor gráfico Balanced = Equilibrado Bicubic = Bicúbico -BlockTransferRequired = AVISO: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos de búfer gráfico (puede generar input lag) BufferedRenderingRequired = AVISO: este juego requiere modo de renderizado por búfer. @@ -498,6 +497,7 @@ Frame Skipping = Saltar cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (causarán errores gráficos) Hardware Tessellation = Teselado por hardware Hardware Transform = Transformación por hardware @@ -545,11 +545,12 @@ Screen layout = Diseño de pantalla Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efectos "block transfer" +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderizado por software Software Skinning = "Skinning" por software SoftwareSkinning Tip = Reduce la carga de dibujado, rápido en juegos con técnicas de skinning avanzadas, pero lento en otros. Speed = Velocidad +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index b6df17ab65..7c789a7f75 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -468,7 +468,6 @@ Auto Scaling = Escalado automático Backend = Motor gráfico Balanced = Balanceado Bicubic = Bicúbico -BlockTransferRequired = Advertencia: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos gráficos de búfer (puede generar input lag) BufferedRenderingRequired = Advertencia: Este juego requiere modo de renderizado por búfer. @@ -498,6 +497,7 @@ Frame Skipping = Salto de cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (puede causar glitches) Hardware Tessellation = Teselado por Hardware Hardware Transform = Transformación por Hardware @@ -545,11 +545,12 @@ Screen layout = Disposición de pantalla Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efectos de transferencia de bloque +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderizado por software (experimental) Software Skinning = Skineado por software SoftwareSkinning Tip = Combina dibujados de modelo de skineado en la CPU. Acelera muchos juegos pero ralentiza otros. Speed = Velocidad +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index f856c6e437..7b7b8ca47b 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -468,7 +468,6 @@ Auto Scaling = ‎تنظیم سایز خودکار Backend = ‎گرافیکی API Balanced = ‎متعادل Bicubic = Bicubic -BlockTransferRequired = ‎دارد "simulate block transfer effects" هشدار:این گزینه نیاز به روشن بودن Both = ‎سرعت + فریم بر ثانیه Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = ‎تنظیم باشد "buffered" هشدار: برای این بازی "حالت رندرینگ" باید روی @@ -498,6 +497,7 @@ Frame Skipping = ‎ردکردن فریم Frame Skipping Type = Frame skipping type FullScreen = ‎تمام صفحه GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ‎تنظیمات هک ها (میتواند باعث باگ شود) Hardware Tessellation = Hardware tessellation Hardware Transform = ‎استفاده از سخت افزار در پردازش @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = ‎فیلتر تغییر ساز صفحه Show Debug Statistics = ‎نمایش اطلاعات دیباگ Show FPS Counter = ‎نمایش شمارنده فریم بر ثانیه -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ‎(رندر نرم افزاری (آزمایشی Software Skinning = Software skinning SoftwareSkinning Tip = ‎در اکثر بازی ها سریع تر ،CPU دار در skin ترکیب رسم مدل های Speed = ‎سرعت +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = ‎کشیدن Texture Filter = ‎فیلتر تکسچر Texture Filtering = ‎فیلتر کردن تکسچر diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 66d6596262..6d3d8eb412 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Molemmat Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Ruudun ohitus Frame Skipping Type = Frame skipping type FullScreen = Koko näyttö GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Laitteistomuunnos @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Näytä virheenkorjaustilastot Show FPS Counter = Näytä FPS-laskuri -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Ohjelmistopohjainen renderointi (kokeellinen) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Nopeus +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Tekstuurisuodatin Texture Filtering = Tekstuurin suodatus diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 1d010efe05..23b23fccd6 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -468,7 +468,6 @@ Auto Scaling = Mise à l'échelle auto Backend = Rendu back-end Balanced = Équilibré Bicubic = Bicubique -BlockTransferRequired = Avertissement : Ce jeu requiert l'activation de "Simuler les effets de transfert de bloc". Both = Vitesse + FPS Buffer graphics commands (faster, input lag) = Commandes graphiques en mémoire tampon (+ rapide, + lag entrée) BufferedRenderingRequired = Avertissement : Ce jeu requiert "mode de rendu" réglé sur "Mise en mémoire tampon". @@ -498,6 +497,7 @@ Frame Skipping = Saut d'images Frame Skipping Type = Type de saut d'images FullScreen = Plein écran GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Paramètres "hack" (crée des bugs graphiques) Hardware Tessellation = Tessellation matérielle Hardware Transform = Transformation matérielle @@ -545,11 +545,12 @@ Screen layout = Disposition de l'écran Screen Scaling Filter = Filtre de mise à l'échelle de l'écran Show Debug Statistics = Montrer les statistiques de débogage Show FPS Counter = Montrer les compteurs -Simulate Block Transfer = Simuler les effets de transfert de bloc +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Rendu logiciel (expérimental) Software Skinning = Enveloppe logicielle SoftwareSkinning Tip = Combine l'affichage des modèles enveloppés sur le CPU, plus rapide dans la plupart des jeux Speed = Vitesse +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Étirement Texture Filter = Filtre de textures Texture Filtering = Filtrage des textures diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 0364e1feac..5e8fe159d4 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Motor gráfico Balanced = Balanceado Bicubic = Bicúbico -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Saltar cadros Frame Skipping Type = Frame skipping type FullScreen = Pantalla completa GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Axustes de hacks (causarán erros gráficos) Hardware Tessellation = Hardware tessellation Hardware Transform = Transformación por hardware @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderizado por software (beta) Software Skinning = «Skinning» por software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Velocidade +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 0d876321b4..38f61cd2a0 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -468,7 +468,6 @@ Auto Scaling = Αυτόματη Κλιμάκωση Backend = Σύστημα Υποστήριξης Balanced = Εξισορροπημένη Bicubic = Διακυβική -BlockTransferRequired = Προειδοποίηση: Αυτό το παιχνίδι απαιτεί τη λειτουργία προσομοίωσης εφέ μεταφοράς block να είναι ενεργοποιημένη. Both = Όλα Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Παράκαμψη Καρέ Frame Skipping Type = Frame skipping type FullScreen = Πλήρης Οθόνη GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ρυθμίσεις Hack Hardware Tessellation = Tessellation Υλικού Hardware Transform = Μετασχηματισμός Υλικού @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Φίλτο κλιμάκωσης οθόνης Show Debug Statistics = Εμφάνιση στατιστικών αποσφαλμάτωσης Show FPS Counter = Εμφάνιση μετρητή FPS -Simulate Block Transfer = Προσομοίωση εφέ μεταφοράς block +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Απεικόνιση Λογισμικού (πειραματικό) Software Skinning = Εκδορά Λογισμικού SoftwareSkinning Tip = Συνδυασμός μοντέλου στην CPU, γρηγορότερο στα περισσότερα παιχνίδια Speed = Ταχύτητα +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Επέκταση Texture Filter = Φίλτρο Υφών Texture Filtering = Φιλτράρισμα Υφών diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 8d559c66d8..ecad06a830 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = שניהם Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = דלג על פריימים Frame Skipping Type = Frame skipping type FullScreen = מסך מלא GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = התאמת חומרה @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = הצג סטטיסטיקת באגים Show FPS Counter = הצג מונה -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = עיבוד תוכנה (ניסיוני) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = מהירות +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = קידוד טקסטורה Texture Filtering = קידוד טקסטורה diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index dea835df52..97fb5347a6 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = םהינש Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = םימיירפ לע גלד Frame Skipping Type = Frame skipping type FullScreen = אלמ ךסמ GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = הרמוח תמאתה @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = םיגאב תקיטסיטטס גצה Show FPS Counter = הנומ גצה -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = )ינויסינ( הנכות דוביע Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = תוריהמ +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = הרוטסקט דודיק Texture Filtering = הרוטסקט דודיק diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 6e65118dec..a6465719e8 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto mjerenje Backend = Backend Balanced = Balansirano Bicubic = Bikubično -BlockTransferRequired = Upozorenje: Ova igra zahtijeva "simulirajte blok transfer efekte" da budu postavljeni na Uključeno. Both = Oboje Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Upozorenje: Ova igra zahtijeva "prikazni način" da bude postavljen na "ublaženo". @@ -498,6 +497,7 @@ Frame Skipping = Preskakanje sličica Frame Skipping Type = Vrsta preskakanja sličica FullScreen = Puni zaslon GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Opcije hakiranja (može uzrokovati glitcheve) Hardware Tessellation = Hardware tesselacija Hardware Transform = Hardver mozaik @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Mjerenje filtriranje zaslona Show Debug Statistics = Pokaži statistike otklanjanja grešaka Show FPS Counter = Pokaži FPS counter -Simulate Block Transfer = Simuliraj blok transfer efekte +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Žbukanje softvera (sporo) Software Skinning = Skiniranje softvera SoftwareSkinning Tip = Kombiniraj skinirane modele crteža na CPU, brže u većini igara Speed = Brzina +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Rastezanje Texture Filter = Filtar tekstura Texture Filtering = Filtriranje tekstura diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 8f2b003a41..945b81fab2 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatikus skálázás Backend = Backend Balanced = Kiegyensúlyozott Bicubic = Bicubic -BlockTransferRequired = Figyelem: Ehhez a játékhoz be kell kapcsolni a "Blokk transzfer effektek szimulálása" opciót! Both = Mindkettő Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Figyelem: Ehhez a játékhoz a "Renderelési mód" beállítást "Bufferelt"-re kell állítani! @@ -498,6 +497,7 @@ Frame Skipping = Képkocka kihagyás Frame Skipping Type = Képkocka kihagyás típusa FullScreen = Teljes képernyő GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack beállítások (ezek HIBÁKAT OKOZHATNAK) Hardware Tessellation = Hardveres tesszeláció Hardware Transform = Hardveres transzform @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Képernyő skálázási szűrő Show Debug Statistics = Hibakeresési statisztikák mutatása Show FPS Counter = FPS számláló mutatása -Simulate Block Transfer = Blokk transzfer effektek szimulálása +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Szoftveres renderelés (lassú) Software Skinning = Szoftveres "skinning" SoftwareSkinning Tip = "Skinning" művelet elvégzése a processzoron. Sok játék esetében gyorsabb. Speed = Sebesség +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Nyújtás Texture Filter = Textúra szűrés Texture Filtering = Textúra szűrés diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index f28ff33fac..c1fe30cf77 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -468,7 +468,6 @@ Auto Scaling = Penskala otomatis Backend = Penyangga grafis Balanced = Seimbang Bicubic = Bikubik -BlockTransferRequired = Peringatan: Permainan ini membutuhkan "Simulasikan efek transfer blok" dalam keadaan menyala. Both = Keduanya Buffer graphics commands (faster, input lag) = Perintah grafis penyangga (lebih cepat, masukan lag) BufferedRenderingRequired = Peringatan: Permainan ini membutuhkan "Mode pelukisan" yang ditetapkan "Penyangga". @@ -498,6 +497,7 @@ Frame Skipping = Lewati laju bingkai Frame Skipping Type = Jenis lewati laju bingkai FullScreen = Layar penuh GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas pengaturan (menyebabkan kecacatan) Hardware Tessellation = Pengujian perangkat keras Hardware Transform = Transformasi perangkat keras @@ -545,11 +545,12 @@ Screen layout = Tata letak layar Screen Scaling Filter = Pemfilteran penskala layar Show Debug Statistics = Tampilkan statistik awakutu Show FPS Counter = Tampilkan penghitung FPS -Simulate Block Transfer = Simulasikan efek transfer blok +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Pelukisan perangkat lunak (eksperimental) Software Skinning = Pengkulitan perangkat lunak SoftwareSkinning Tip = Menggabungkan model berkulit pada CPU, lebih cepat di kebanyakan permainan Speed = Kecepatan +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Peregangan Texture Filter = Filter tekstur Texture Filtering = Pemfilteran tekstur diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 68d08f8a93..5ca9f3470e 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -468,7 +468,6 @@ Auto Scaling = Scaling automatico Backend = Renderer Balanced = Bilanciato Bicubic = Bicubico -BlockTransferRequired = Attenzione: Questo gioco richiede l'attivazione di 'Simula gli effetti del blocco trasferimento'. Both = Entrambi Buffer graphics commands (faster, input lag) = Comandi grafici bufferizzati (più rapido, più lag dei comandi) BufferedRenderingRequired = Attenzione: Questo gioco richiede di impostare "modalità di rendering" su "buffered". @@ -487,7 +486,7 @@ Deposterize Tip = Sistema i possibili problemi visivi nelle texture upscalate Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable slower effects (speedup) = Disattiva gli effetti più lenti (veloce) +#Disable slower effects (speedup) = Disattiva gli effetti più lenti (veloce) Disabled = Disabilitato Display layout editor = Editor Display Display Resolution (HW scaler) = Risoluzione Display (scaler HW) @@ -499,6 +498,7 @@ Frame Skipping = Salto frame Frame Skipping Type = Tipo di Salto frame FullScreen = Schermo Intero GPU log profiler = Log profilo GPU +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Impostazioni Hack (causerà dei problemi, sicuramente) Hardware Tessellation = Tassellazione Hardware Hardware Transform = Trasformazione Hardware @@ -546,11 +546,12 @@ Screen layout = Disposizione dello schermo Screen Scaling Filter = Filtro Scalatura Schermo Show Debug Statistics = Mostra Statistiche Debug Show FPS Counter = Mostra FPS -Simulate Block Transfer = Simula gli effetti del blocco trasferimento +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Rendering tramite Software (sperimentale) Software Skinning = Software Skinning SoftwareSkinning Tip = Combina la visualizzazione di modelli disegnati dalla CPU, più veloce nella maggior parte dei giochi Speed = Velocità +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Adatta al Display Texture Filter = Filtro delle texture Texture Filtering = Filtraggio delle texture @@ -723,6 +724,8 @@ Center Left = Al centro a sinistra Center Right = Al centro a destra Change Mac Address = Cambia indirizzo MAC Change proAdhocServer Address = Cambia indirizzo server IP PRO ad hoc (localhost = istanze multiple) +ChangeMacSaveConfirm = Generate a new MAC address? +ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Chat Chat Button Position = Posizione del pulsante chat Chat Here = Scrivi qui diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 3d0f6eafc4..d49482846e 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -468,7 +468,6 @@ Auto Scaling = 自動的に拡大 Backend = バックエンド Balanced = バランス Bicubic = Bicubic -BlockTransferRequired = 警告: このゲームは「ブロック転送の効果をシミュレートする」をオンにする必要があります。 Both = 両方 Buffer graphics commands (faster, input lag) = グラフィックスコマンドをバッファする (高速, 入力ラグあり) BufferedRenderingRequired = 警告: このゲームは「レンダリングモード」を「バッファ」にする必要があります。 @@ -498,6 +497,7 @@ Frame Skipping = フレームスキップ Frame Skipping Type = フレームスキップのタイプ FullScreen = フルスクリーン GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ハックの設定 (不具合あり) Hardware Tessellation = ハードウェアテッセレーション Hardware Transform = ハードウェアトランスフォーム @@ -545,11 +545,12 @@ Screen layout = 画面のレイアウト Screen Scaling Filter = 画像スケーリングのフィルタ Show Debug Statistics = デバッグ情報を表示する Show FPS Counter = FPSを表示する -Simulate Block Transfer = ブロック転送の効果をシミュレートする +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ソフトウェアレンダリング (実験的) Software Skinning = ソフトウェアスキニング SoftwareSkinning Tip = スキンモデルの描画をCPUでまとめて行う。ほとんどのゲームが高速化します Speed = 速度 +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = 拡大 Texture Filter = テクスチャフィルタ Texture Filtering = テクスチャフィルタリング diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index b522a9a4c1..328bb6a46f 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -468,7 +468,6 @@ Auto Scaling = Njongko Otomatis Backend = Backend Balanced = Imbang Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Kelorone Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Frame-skip Frame Skipping Type = Frame skipping type FullScreen = Layar Penuh GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas setelsn (nyebabake glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Ndandani Hardware @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Layar njongko Filter Show Debug Statistics = Tampilno statistik debug Show FPS Counter = Tampilno penghitung FPS -Simulate Block Transfer = Simulasi efek transfer pemblokiran +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (jajalan) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Kacepetan +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Penyaring Tekstur Texture Filtering = Penyaring Tekstur diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 337f624cf5..ea067713be 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -468,7 +468,6 @@ Auto Scaling = 자동 스케일링 Backend = 백엔드 Balanced = 평형 Bicubic = 고등차수보간 -BlockTransferRequired = 경고: 이 게임은 "블록 전송 효과 시뮬레이션"을 켬으로 설정해야 합니다. Both = 둘 다 Buffer graphics commands (faster, input lag) = 버퍼 그래픽 명령 (빠름, 입력 지연) BufferedRenderingRequired = 경고: 이 게임은 "렌더링 모드"를 "버퍼링"으로 설정해야 합니다. @@ -497,6 +496,7 @@ Frame Rate Control = 프레임속도 제어 Frame Skipping = 프레임 생략 Frame Skipping Type = 프레임 생략 유형 FullScreen = 전체화면 +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = 핵 설정 (결함을 일으킬 수 있음) Hardware Tessellation = 하드웨어 조각화 Hardware Transform = 하드웨어 변환 @@ -544,11 +544,12 @@ Screen layout = 화면 레이아웃 Screen Scaling Filter = 화면 크기 조정 필터 Show Debug Statistics = 디버그 통계 표시 Show FPS Counter = FPS 카운터 표시 -Simulate Block Transfer = 블록 전송 효과 시뮬레이션 +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = 소프트웨어 렌더링 (느림) Software Skinning = 소프트웨어 스키닝 SoftwareSkinning Tip = 대부분의 게임에서 더 빠르게 CPU에서 스킨 모델 드로우를 결합합니다. Speed = 속도 +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = 늘이기 Texture Filter = 텍스처 필터링 Texture Filtering = 텍스처 필터링 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index a5133a73ae..64f175d367 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -468,7 +468,6 @@ Auto Scaling = ປັບຂະໜາດສເກລອັດຕະໂນມັ Backend = ການສະໜັບສະໜູນ Balanced = ສົມດຸນ Bicubic = Bicubic -BlockTransferRequired = ຄຳເຕືອນ: ເກມນີ້ຕ້ອງການໃຫ້ເປີດໂໝດ "ຈຳລອງຜົນປິດກັ້ນການສົ່ງຜ່ານຂໍ້ມູນເອັບເຟກ" ນຳ Both = ໃຊ້ທັງ FPS ແລະ Speed Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = ຂ້າມເຟຣມ Frame Skipping Type = Frame skipping type FullScreen = ເຕັມໜ້າຈໍ GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ການຕັ້ງຄ່າແຮັກ Hardware Tessellation = Hardware tessellation Hardware Transform = ໃຊ້ຮາດແວຣ໌ປະມວນຜົນ @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = ໂຕຕອງປັບສເກລໜ້າຈໍ Show Debug Statistics = ສະແດງຄ່າທາງສະຖິຕິການແກ້ໄຂຈຸດບົກພ່ອງ Show FPS Counter = ສະແດງຄ່າເຟຣມເຣດ ແລະ ຄວາມໄວ/ວິນາທີ -Simulate Block Transfer = ຈຳລອງຜົນປິດກັ້ນການສົ່ງຜ່ານຂໍ້ມູນເອັບເຟກ +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ໃຊ້ຊອບແວຣ໌ສະແດງຜົນ (ລຸ້ນທົດລອງ) Software Skinning = ຊ໋ອບແວຣ໌ສກິນນິງ SoftwareSkinning Tip = ປະສານໂມເດລພື້ນຜິວໃຫ້ຂຽນຜ່ານ CPU, ເກມສ່ວນໃຫຍ່ໃຊ້ແລ້ວໄວຂຶ້ນ Speed = ຄວາມໄວ +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = ດຶງເຕັມຈໍ Texture Filter = ໂຕຕອງພື້ນຜິວ Texture Filtering = ຕອງພື້ນຜິວ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 494653f8f5..d01df7a0ad 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = "Bicubic" -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Abu Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Kadrų praleidimas Frame Skipping Type = Frame skipping type FullScreen = Pilnas ekranas GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Modifikavimo parametrai (gali sukelti problemų) Hardware Tessellation = Hardware tessellation Hardware Transform = Aparatūros transformacija @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Rodyti testinio režimo statistikas Show FPS Counter = Rodyti kadrų per sekundę rodmenis -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Programinės įrangos rodymas(ekspermentalus) Software Skinning = Programinės įrangos "nulupimas" SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Greitis +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Tekstūrų filtravimas Texture Filtering = Tekstūrų filtravimas diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 801a373dfe..cb7a06426d 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bikubik -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Keduanya Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Pelompatan Frame Frame Skipping Type = Frame skipping type FullScreen = Skrin penuh GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Godam tetapan (mungkin menyebabkan gangguan) Hardware Tessellation = Hardware tessellation Hardware Transform = Penukaran Alatan @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Papar statistik pepijat Show FPS Counter = Papar penghitung FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Render perisian (eksperimen) Software Skinning = Pembalutan Perisian SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Laju +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Penapis Tekstur Texture Filtering = Penapisan Tekstur diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 83a6aba047..8a4a3c3339 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatisch schalen Backend = Backend Balanced = Gebalanceerd Bicubic = Bicubisch -BlockTransferRequired = Waarschuwing: Deze game vereist de optie Blokoverdrachteffecten simuleren. Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Waarschuwing: Deze game vereist een "gebufferde renderingmodus". @@ -498,6 +497,7 @@ Frame Skipping = Frames overslaan Frame Skipping Type = Frame skipping type FullScreen = Volledig scherm GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hackinstellingen (kan glitches veroorzaken) Hardware Tessellation = Hardwarebetegeling Hardware Transform = Hardwaretransformatie @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Beeldschalingsfilter Show Debug Statistics = Foutopsporingsstatistieken weergeven Show FPS Counter = FPS-teller weergeven -Simulate Block Transfer = Blokoverdrachteffecten simuleren +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderen via software (experimenteel) Software Skinning = Skinning via software SoftwareSkinning Tip = Vermindert aantal renders en is sneller in games die de geavanceerde skinningtechniek gebruiken, maar voor sommige games trager Speed = Snelheid +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Uitrekken Texture Filter = Texturefilter Texture Filtering = Texturefilter diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index cceaa22382..5baf3a6c55 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Ramme Hoppe over Frame Skipping Type = Frame skipping type FullScreen = Fullskjerm GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Maskinvare omdanning @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Vis debugstatistik Show FPS Counter = Vis FPS-teller -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Programvare gjengivelse (eksperiment) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Tekstur filtrering Texture Filtering = Tekstur filtrering diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 5b067680e3..25c17fef2f 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -468,7 +468,6 @@ Auto Scaling = Automatyczne skalowanie Backend = Sterownik graficzny Balanced = Zbalansowane Bicubic = Bicubic (Dwusześcienne) -BlockTransferRequired = Uwaga: Ta gra wymaga włączonej opcji "Symuluj efekty transferu bloków". Both = Oba Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Uwaga: Ta gra wymaga włączonej opcji "Renderowanie buforowe". @@ -498,6 +497,7 @@ Frame Skipping = Pomijanie klatek Frame Skipping Type = Tryb pomijania klatek FullScreen = Pełny ekran GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ustawienia specjalne (powodują problemy) Hardware Tessellation = Sprzętowa teselacja Hardware Transform = Transformacja sprzętowa @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Filtrowanie skalowania ekranu Show Debug Statistics = Pokaż statystyki debugowania Show FPS Counter = Pokaż licznik FPS -Simulate Block Transfer = Symuluj efekty transferu bloków +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderowanie programowe (wolne) Software Skinning = Programowy skinning SoftwareSkinning Tip = Łączy na CPU wywołania rysujące modele z animacjami, przyspieszenie w większości gier Speed = Prędkość (procentowo) +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Rozciąganie Texture Filter = Filtrowanie tekstur Texture Filtering = Filtrowanie tekstur diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 45d7e1b867..970025ecb0 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -492,7 +492,6 @@ Auto Scaling = Auto-redimensionamento Backend = Backend Balanced = Balanceado Bicubic = Bi-cúbico -BlockTransferRequired = Aviso: Esse jogo requer que a "simulação dos efeitos de transferência dos blocos" esteja definida como Ligada. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos comandos dos gráficos (mais rápido, atraso na entrada dos dados) BufferedRenderingRequired = Aviso: Este jogo requer que o "modo de renderização" esteja definido "com buffer". @@ -521,6 +520,7 @@ Frame Rate Control = Controle da taxa dos frames Frame Skipping = Pulo dos frames Frame Skipping Type = Tipo de pulo dos frames FullScreen = Tela cheia +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Configurações dos hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por hardware Hardware Transform = Transformação por hardware @@ -568,11 +568,12 @@ Screen layout = Esquema da tela Screen Scaling Filter = Filtro do dimensionamento da tela Show Debug Statistics = Mostrar estatísticas do debug Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efeitos de transferência dos blocos +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderização por software (lento) Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Esticamento Texture Filter = Filtragem das texturas Texture Filtering = Filtragem das texturas diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 054d8f0dfd..244bc14492 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -492,7 +492,6 @@ Auto Scaling = Auto-redimensionamento Backend = Backend Balanced = Balanceado Bicubic = Bi-cúbico -BlockTransferRequired = Aviso: Este jogo requer que a "Simulação dos Efeitos de Transferência dos Blocos" esteja habilitada. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos Comandos Gráficos (mais rápido, atraso na entrada dos dados) BufferedRenderingRequired = Aviso: Este jogo requer que o "modo de renderização" esteja definido "com buffer". @@ -521,6 +520,7 @@ Frame Rate Control = Controle da taxa dos quadros Frame Skipping = Pulo dos quadros Frame Skipping Type = Tipo de pulo dos quadros FullScreen = Tela Cheia +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Definições dos Hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por Hardware Hardware Transform = Transformação por Hardware @@ -568,11 +568,12 @@ Screen layout = Esquema da tela Screen Scaling Filter = Filtro do dimensionamento da tela Show Debug Statistics = Mostrar estatísticas de depuração Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efeitos de transferência dos blocos +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderização por software (lento) Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Esticamento Texture Filter = Filtração das texturas Texture Filtering = Filtração das texturas diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 38d47a05b1..c639b659ae 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Mod intern Balanced = Balansat Bicubic = Bicubic -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambele Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Cadre Omise Frame Skipping Type = Frame skipping type FullScreen = Ecran intreg GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Setări trișare (pot cauza stricăciuni) Hardware Tessellation = Hardware tessellation Hardware Transform = Transformare pe Hardware @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Filtrul de scalare al ecranului Show Debug Statistics = Arată statistici de depanare Show FPS Counter = Arată FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Afișare cu sofware (experimental) Software Skinning = Skinning cu software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Viteză +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Filtru texturi Texture Filtering = Filtrare texturi diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 082b087730..5b02a758d1 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -468,7 +468,6 @@ Auto Scaling = Автомасштаб Backend = Бэкенд Balanced = Сбалансированно Bicubic = Бикубический -BlockTransferRequired = Предупреждение: для этой игры требуется включить "Симуляцию эффектов от передачи блоков" Both = Оба Buffer graphics commands (faster, input lag) = Команды буферированной графики (быстрее, задержка ввода) BufferedRenderingRequired = Предупреждение: для этой игры требуется буферированный режим рендеринга. @@ -499,6 +498,7 @@ Frame Skipping = Пропуск кадров Frame Skipping Type = Тип пропуска кадров FullScreen = Полноэкранный режим GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Параметры хаков (могут вызывать глюки) Hardware Tessellation = Аппаратная тесселяция Hardware Transform = Аппаратное преобразование @@ -546,11 +546,12 @@ Screen layout = Расположение экрана Screen Scaling Filter = Фильтр масштабирования экрана Show Debug Statistics = Отображать отладочную информацию Show FPS Counter = Показывать счетчик FPS -Simulate Block Transfer = Симулировать эффекты от передачи блоков +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Программный рендеринг (медленно) Software Skinning = Программная заливка SoftwareSkinning Tip = Объединяет вызовы отрисовки моделей с заливкой на ЦП, быстрее во многих играх Speed = Скорость +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Растягивание Texture Filter = Текстурный фильтр Texture Filtering = Фильтрация текстур diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 247e593a79..03a8b4d574 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -468,7 +468,6 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balancerad Bicubic = Bicubisk -BlockTransferRequired = Varning: Detta spel kräver att "Simulera blocktransfer-effekter" är påslaget. Both = Båda Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Frameskipping Frame Skipping Type = Frame skipping type FullScreen = Fullskärm GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack-inställningar (kan orsaka problem) Hardware Tessellation = Hårdvarutessellering Hardware Transform = Hårdvarutransform @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Skärmskalningsfilter Show Debug Statistics = Visa debugstatistik Show FPS Counter = Visa FPS-räknare -Simulate Block Transfer = Simulera blocktransfer-effekter +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Mjukvarurendering (experiment) Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Texturfilter Texture Filtering = Texturfiltrering diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 4815c0023c..7f90a8349d 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -468,7 +468,6 @@ Auto Scaling = Awto scaling Backend = Backend Balanced = Balanse Bicubic = Bicubic -BlockTransferRequired = BABALA: This game requires "simulate block transfer effects" to be set to On. Both = Pareho Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = BABALA: This game requires "rendering mode" to be set to "buffered". @@ -498,6 +497,7 @@ Frame Skipping = Frame Skipping Frame Skipping Type = Frame skipping type FullScreen = Isakto sa Sukat ng iyong Iskrin GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack Settings (maaring magdulot ng pagloloko sa laro) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware Transform @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Screen Scaling Filter Show Debug Statistics = Ipakita ang debug statistics Show FPS Counter = Ipakita ang FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software Rendering (Expiremental) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Bilis +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Iunat Texture Filter = Panala ng Texture Texture Filtering = Pagsala sa Texture diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 422f06b13f..d9a6d1eff6 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -468,7 +468,6 @@ Auto Scaling = สเกลอัตโนมัติ Backend = การสนับสนุนกราฟิก Balanced = สมดุล Bicubic = ไบคิวบิค -BlockTransferRequired = คำเตือน: เกมนี้ต้องปรับใช้งาน "จำลองผลปิดกั้นการส่งผ่านข้อมูลเอฟเฟ็คท์" ด้วย Both = ใช้ทั้งคู่ Buffer graphics commands (faster, input lag) = ควบคุมกราฟิกบัฟเฟอร์ (เร็วขึ้น, อาจทำให้เกิดอินพุตแล็ก) BufferedRenderingRequired = คำเตือน: เกมนี้ต้องปรับใช้งานในโหมด "การแสดงผลแบบใช้บัฟเฟอร์" @@ -498,6 +497,7 @@ Frame Skipping = ข้ามเฟรม Frame Skipping Type = รูปแบบการข้ามเฟรม FullScreen = เต็มหน้าจอ GPU log profiler = ตัวแสดงค่าโปรไฟล์ GPU +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ตั้งค่าการปรับแฮ็ค (อาจแสดงผลผิดพลาด) Hardware Tessellation = ฮาร์ดแวร์ เทสเซลเลชั่น Hardware Transform = ใช้ฮาร์ดแวร์ในการแปลงค่าประมวลผล @@ -545,11 +545,12 @@ Screen layout = เค้าโครงหน้าจอ Screen Scaling Filter = ตัวกรองปรับสเกลหน้าจอ Show Debug Statistics = แสดงค่าทางสถิติการแก้ไขจุดบกพร่อง Show FPS Counter = แสดงค่าเฟรมเรท และความเร็ว/วินาที -Simulate Block Transfer = จำลองผลปิดกั้นการส่งผ่านข้อมูลเอฟเฟ็คท์ +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ใช้ซอฟต์แวร์ในการแสดงผล (ช้า) Software Skinning = ซอฟต์แวร์ สกินนิ่ง SoftwareSkinning Tip = ผสานโมเดลพื้นผิวให้เขียนผ่านซีพียู ซึ่งเกมส่วนใหญ่ปรับใช้แล้วไวขึ้น Speed = ความเร็ว +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = ดึงเต็มจอ Texture Filter = ตัวกรองพื้นผิว Texture Filtering = การกรองพื้นผิว diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 3bdaf3ef39..96a1ccb313 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -470,7 +470,6 @@ Auto Scaling = Otomatik ölçekleme Backend = Arkauç Balanced = Dengeli Bicubic = Çift Kübik -BlockTransferRequired = Uyarı: Bu oyun Blok Aktarım Simülasyon Modunun Açık olmasını gerektirir. Both = İkisi de Buffer graphics commands (faster, input lag) = Grafik komutlarını arabellekle (daha hızlı, input lag'e sebep olabilir) BufferedRenderingRequired = Uyarı: Bu oyun "işleme modunun" "yükleyerek işleme"ye alınmasını gerektirir. @@ -489,7 +488,6 @@ Deposterize Tip = Yeniden ölçeklenen dokulardaki görsel şerit hatalarını d Device = Cihaz Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable slower effects (speedup) = Daha yavaş efektleri kapatın (daha hızlı) Disabled = Devre dışı Display layout editor = Görüntü Düzeni Düzenleyicisi Display Resolution (HW scaler) = Görüntü Çözünürlüğü (HW scaler) @@ -501,6 +499,7 @@ Frame Skipping = Kare atla Frame Skipping Type = Kare atlama türü FullScreen = Tam ekran GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack ayarları (Küçük teknik problemlere neden olabilir.) Hardware Tessellation = Donanım Mozaikleme Hardware Transform = Donanım dönüştürme @@ -548,11 +547,12 @@ Screen layout = Ekran düzeni Screen Scaling Filter = Ekran ölçekleme filtresi Show Debug Statistics = Hata ayıklama istatistiklerini göster Show FPS Counter = FPS sayacını göster -Simulate Block Transfer = Blok aktarım efektlerini simüle edin +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Yazılımsal işleme (Deneysel) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hız +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Serbest tam ekran (sünme) Texture Filter = Doku filtreleme Texture Filtering = Doku filtreleme @@ -754,6 +754,8 @@ Center Left = Sol orta Center Right = Sağ orta Change Mac Address = MAC adresini değiştir Change proAdhocServer Address = PRO Ad Hoc Server IP adresini değiştir (localhost = çoklu örnek) +ChangeMacSaveConfirm = Generate a new MAC address? +ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Chat Chat Button Position = Chat düğmesinin konumu Chat Here = Buraya yazın diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 2105606270..5c57d9af18 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -468,7 +468,6 @@ Auto Scaling = Автоматичне масштабування Backend = Бекенд Balanced = Збалансовано Bicubic = Бікубічний -BlockTransferRequired = Попередження: Ця гра вимагає, щоб "імітувати ефекти передачі блоку" було встановлено на Увімкнено. Both = Обидва Buffer graphics commands (faster, input lag) = Буферні графічні команди (швидше, можливі глюки) BufferedRenderingRequired = Попередження: Ця гра вимагає, щоб "режим візуалізації" був встановлений на "буферний". @@ -498,6 +497,7 @@ Frame Skipping = Пропуск кадрів Frame Skipping Type = Тип пропуску кадрів FullScreen = Повноекранний режим GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Параметри хаків (можуть викликати глюки) Hardware Tessellation = Апаратна тесселляція Hardware Transform = Апаратне перетворення @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Фільтр обчислення екрану Show Debug Statistics = Відоброжати зневадження Show FPS Counter = Показати FPS -Simulate Block Transfer = Симулювати ефекти від передачі блоків +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Програмний рендеринг (експериментально) Software Skinning = Програмна заливка SoftwareSkinning Tip = Комбінована модель розібраної моделі яка притягується до процесора, швидше в більшості ігор Speed = Швидкість +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Розтягнення Texture Filter = Фільтр текстур Texture Filtering = Фільтрація текстур diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 2cf347c956..6aed763937 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -468,7 +468,6 @@ Auto Scaling = Tự động nhân rộng Backend = Thư viện đồ họa Balanced = Cân bằng Bicubic = Bicubic (mịn) -BlockTransferRequired = Cảnh báo: Trò chơi này yêu cầu mở "simulate block transfer effects" Both = Cả hai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) BufferedRenderingRequired = Cảnh báo: Trò chơi này yêu cầu "chế độ kết xuất" được đặt thành "được đệm". @@ -498,6 +497,7 @@ Frame Skipping = Nhảy khuôn hình Frame Skipping Type = Frame skipping type FullScreen = Toàn màn hình GPU log profiler = GPU log profiler +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Thiết lập hack (sẽ bị lỗi) Hardware Tessellation = Lót phần cứng Hardware Transform = Chuyển đổi phần cứng @@ -545,11 +545,12 @@ Screen layout = Screen layout Screen Scaling Filter = Bộ lọc họa tiết rộng Show Debug Statistics = Hiện thông số debug Show FPS Counter = Hiện thông số FPS -Simulate Block Transfer = Mô phỏng truyền tải khối vật thể , hiệu ứng +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Dựng hình bằng phần mềm Software Skinning = phủ lớp bằng phần mềm SoftwareSkinning Tip = Mô hình kết hợp vẽ trên CPU, nhanh hơn trong hầu hết các trò chơi Speed = Tốc độ +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = Stretching Texture Filter = Bộ lọc họa tiết Texture Filtering = Lọc texture diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 42bdca4099..d5bd28529b 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -468,7 +468,6 @@ Auto Scaling = 自动缩放 Backend = 渲染引擎 Balanced = 均衡 Bicubic = 双三次 -BlockTransferRequired = 警告:此游戏需要将"模拟块传输模式"设置为开。 Both = 全部显示 Buffer graphics commands (faster, input lag) = 缓冲图形命令(更快, 有输入延迟) BufferedRenderingRequired = 警告:此游戏需要将"渲染模式"设置为"缓冲渲染"。 @@ -498,6 +497,7 @@ Frame Skipping = 跳帧 Frame Skipping Type = 跳帧方式 FullScreen = 全屏幕 GPU log profiler = GPU日志分析器 +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = 渲染修正(可能引发故障) Hardware Tessellation = 硬件曲面细分 Hardware Transform = 硬件几何变换 @@ -545,11 +545,12 @@ Screen layout = 屏幕布局 Screen Scaling Filter = 屏幕缩放滤镜 Show Debug Statistics = 显示调试信息 Show FPS Counter = 显示FPS计数器 -Simulate Block Transfer = 模拟数据块传输效果 +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = 软件渲染(慢) Software Skinning = 软件蒙皮 SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快 Speed = 运行速度 +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = 拉伸 Texture Filter = 纹理过滤方式 Texture Filtering = 纹理过滤 @@ -709,7 +710,6 @@ Up = 方向键:上 Vol + = 音量+ Vol - = 音量- Wlan = 无线网络 -Analog speed = 模拟速度 [MemStick] Already contains PSP data = 已含有PSP数据 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index a1cbd6c878..0b2ec4b154 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -468,7 +468,6 @@ Auto Scaling = 自動縮放 Backend = 後端 Balanced = 平衡 Bicubic = 雙立方 -BlockTransferRequired = 警告:這個遊戲需要開啟「模擬區塊傳輸效果」 Both = 全部 Buffer graphics commands (faster, input lag) = 緩衝圖形命令 (更快,有輸入延遲) BufferedRenderingRequired = 警告:這個遊戲需要將「轉譯模式」設為「緩衝轉譯」 @@ -497,6 +496,7 @@ Frame Rate Control = 影格速率控制 Frame Skipping = 影格跳過 Frame Skipping Type = 影格跳過類型 FullScreen = 全螢幕 +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = 駭客設定 (可能會造成故障) Hardware Tessellation = 硬體鑲嵌式 Hardware Transform = 硬體轉換 @@ -544,11 +544,12 @@ Screen layout = 螢幕版面配置 Screen Scaling Filter = 螢幕縮放濾鏡 Show Debug Statistics = 顯示偵錯統計資料 Show FPS Counter = 顯示 FPS 計數器 -Simulate Block Transfer = 模擬區塊傳輸效果 +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = 軟體轉譯 (慢) Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 +Speed Hacks = Speed Hacks (can cause rendering errors!) Stretching = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 From 9518aa09004b7730dbd326a6397dc742d1ffcf64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 20:01:03 +0100 Subject: [PATCH 224/715] Blind Qt fix --- Qt/mainwindow.cpp | 8 +++----- Qt/mainwindow.h | 12 +++--------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 2560711684..fbe4a35c84 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -89,7 +89,6 @@ void MainWindow::updateMenus() updateMenuGroupInt(saveStateGroup, g_Config.iCurrentStateSlot); updateMenuGroupInt(displayRotationGroup, g_Config.iInternalScreenRotation); updateMenuGroupInt(renderingResolutionGroup, g_Config.iInternalResolution); - updateMenuGroupInt(renderingModeGroup, g_Config.iRenderingMode); updateMenuGroupInt(frameSkippingGroup, g_Config.iFrameSkip); updateMenuGroupInt(frameSkippingTypeGroup, g_Config.iFrameSkipType); updateMenuGroupInt(textureFilteringGroup, g_Config.iTexFiltering); @@ -599,6 +598,9 @@ void MainWindow::createMenus() gameSettingsMenu->add(new MenuAction(this, SLOT(fullscrAct()), QT_TR_NOOP("Fu&llscreen"), QKeySequence::FullScreen)) #endif ->addEventChecked(&g_Config.bFullScreen); + gameSettingsMenu->add(new MenuAction(this, SLOT(bufferRenderAct()), QT_TR_NOOP("&Skip buffer effects"))) + ->addEventChecked(&g_Config.bSkipBufferEffects); + MenuTree* renderingResolutionMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("&Rendering resolution")); renderingResolutionGroup = new MenuActionGroup(this, renderingResolutionMenu, SLOT(renderingResolutionGroup_triggered(QAction *)), QStringList() << "&Auto" << "&1x" << "&2x" << "&3x" << "&4x" << "&5x" << "&6x" << "&7x" << "&8x" << "&9x" << "1&0x", @@ -609,10 +611,6 @@ void MainWindow::createMenus() QStringList() << "&1x" << "&2x" << "&3x" << "&4x" << "&5x" << "&6x" << "&7x" << "&8x" << "&9x" << "1&0x", QList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10); - MenuTree* renderingModeMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("Rendering m&ode")); - renderingModeGroup = new MenuActionGroup(this, renderingModeMenu, SLOT(renderingModeGroup_triggered(QAction *)), - QStringList() << "&Skip buffered effects (non-buffered, faster)" << "&Buffered rendering", - QList() << 0 << 1); MenuTree* frameSkippingMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("&Frame skipping")); frameSkippingMenu->add(new MenuAction(this, SLOT(autoframeskipAct()), QT_TR_NOOP("&Auto"))) ->addEventChecked(&g_Config.bAutoFrameSkip); diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 87718b51cf..864a658b58 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -119,7 +119,6 @@ private slots: void moreSettingsAct() { NativeMessageReceived("settings", ""); } void bufferRenderAct() { - g_Config.iRenderingMode = !g_Config.iRenderingMode; NativeMessageReceived("gpu_resized", ""); } void linearAct() { g_Config.iTexFiltering = (g_Config.iTexFiltering != 0) ? 0 : 3; } @@ -134,15 +133,10 @@ private slots: g_Config.iSmallDisplayZoomType = action->data().toInt(); NativeMessageReceived("gpu_resized", ""); } - void renderingModeGroup_triggered(QAction *action) { - g_Config.iRenderingMode = action->data().toInt(); - g_Config.bAutoFrameSkip = false; - NativeMessageReceived("gpu_resized", ""); - } void autoframeskipAct() { g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip; - if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; + if (g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; NativeMessageReceived("gpu_resized", ""); } } @@ -224,7 +218,7 @@ private: *textureScalingLevelGroup, *textureScalingTypeGroup, *screenScalingFilterGroup, *textureFilteringGroup, *frameSkippingTypeGroup, *frameSkippingGroup, - *renderingModeGroup, *renderingResolutionGroup, + *renderingResolutionGroup, *displayRotationGroup, *saveStateGroup; std::queue msgQueue_; From 69941c0d72ff18e1c2d9e18769fdb8a06c1de7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 20:01:22 +0100 Subject: [PATCH 225/715] Android fix --- GPU/Common/GPUStateUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 47d11afb4a..c6fcfd7007 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -1265,7 +1265,7 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl // Some Android devices (especially old Mali, it seems) composite badly if there's alpha in the backbuffer. // So in non-buffered rendering, we will simply consider the dest alpha to be zero in blending equations. #ifdef __ANDROID__ - if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { + if (g_Config.bSkipBufferEffects) { if (glBlendFuncA == BlendFactor::DST_ALPHA) glBlendFuncA = BlendFactor::ZERO; if (glBlendFuncB == BlendFactor::DST_ALPHA) glBlendFuncB = BlendFactor::ZERO; if (glBlendFuncA == BlendFactor::ONE_MINUS_DST_ALPHA) glBlendFuncA = BlendFactor::ONE; From f597b4ca51c462a9bc6b0bf1e8cbc636a323121c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 20:01:29 +0100 Subject: [PATCH 226/715] Blind libretro fix --- libretro/libretro.cpp | 24 ++++++++++++------------ libretro/libretro_core_options.h | 32 ++++++++++++++------------------ 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index ec07b1dc67..4213a72758 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -745,22 +745,22 @@ static void check_variables(CoreParameter &coreParam) g_Config.iInternalResolution = 10; } - var.key = "ppsspp_rendering_mode"; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (!strcmp(var.value, "Buffered")) - g_Config.iRenderingMode = FB_BUFFERED_MODE; - else if (!strcmp(var.value, "Skip Buffer Effects")) - g_Config.iRenderingMode = FB_NON_BUFFERED_MODE; - } - - var.key = "ppsspp_block_transfer_gpu"; + var.key = "ppsspp_skip_buffer_effects"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "disabled")) - g_Config.bBlockTransferGPU = false; + g_Config.bSkipBufferEffects = false; else - g_Config.bBlockTransferGPU = true; + g_Config.bSkipBufferEffects = true; + } + + var.key = "ppsspp_skip_gpu_readbacks"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bSkipGPUReadbacks = false; + else + g_Config.bSkipGPUReadbacks = true; } var.key = "ppsspp_frameskip"; diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index 0ca87d8bce..cc5f428268 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -284,28 +284,24 @@ struct retro_core_option_v2_definition option_defs_us[] = { "480x272" }, { - "ppsspp_rendering_mode", - "Rendering Mode", + "ppsspp_skip_buffer_effects", + "Skip Buffer Effects", NULL, - "'Skip Buffer Effects' is faster, but nothing may draw in some games.", - NULL, - "video", - { - { "Buffered", NULL }, - { "Skip Buffer Effects", NULL }, - { NULL, NULL }, - }, - "Buffered" - }, - { - "ppsspp_block_transfer_gpu", - "Block Transfer GPU", - NULL, - "Some games require this to be enabled for correct graphics.", + "Faster, but may cause major rendering issues.", NULL, "video", BOOL_OPTIONS, - "enabled" + "disabled" + }, + { + "ppsspp_skip_gpu_readbacks", + "Skip GPU Readbacks", + NULL, + "Some games require GPU readbacks, so be careful.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" }, { "ppsspp_frameskip", From c918ab5044f4d7d8f4b31f7724534728d52d697e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 20:02:34 +0100 Subject: [PATCH 227/715] Setting should be reported --- Core/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 41804f7875..4b75a46c54 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -875,7 +875,7 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", true, false), ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false), ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, true, true, true), - ConfigSetting("SkipBufferEffects", &g_Config.bSkipBufferEffects, false, true, true), + ReportedConfigSetting("SkipBufferEffects", &g_Config.bSkipBufferEffects, false, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), ConfigSetting("SoftwareRendererJit", &g_Config.bSoftwareRenderingJit, true, true, true), ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true), From 5eccf03cb9528092eaa1aee11486f5762f913cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 20:18:32 +0100 Subject: [PATCH 228/715] Partially rescue translation by copying from Hack Settings --- assets/lang/cz_CZ.ini | 2 +- assets/lang/da_DK.ini | 2 +- assets/lang/de_DE.ini | 2 +- assets/lang/es_ES.ini | 2 +- assets/lang/es_LA.ini | 2 +- assets/lang/fa_IR.ini | 2 +- assets/lang/fr_FR.ini | 2 +- assets/lang/gl_ES.ini | 2 +- assets/lang/hr_HR.ini | 2 +- assets/lang/hu_HU.ini | 2 +- assets/lang/id_ID.ini | 2 +- assets/lang/it_IT.ini | 2 +- assets/lang/ja_JP.ini | 2 +- assets/lang/jv_ID.ini | 2 +- assets/lang/ko_KR.ini | 2 +- assets/lang/lt-LT.ini | 2 +- assets/lang/ms_MY.ini | 2 +- assets/lang/nl_NL.ini | 2 +- assets/lang/pl_PL.ini | 2 +- assets/lang/pt_BR.ini | 2 +- assets/lang/pt_PT.ini | 2 +- assets/lang/ro_RO.ini | 2 +- assets/lang/ru_RU.ini | 2 +- assets/lang/sv_SE.ini | 2 +- assets/lang/tg_PH.ini | 2 +- assets/lang/th_TH.ini | 2 +- assets/lang/tr_TR.ini | 2 +- assets/lang/uk_UA.ini | 2 +- assets/lang/vi_VN.ini | 2 +- assets/lang/zh_CN.ini | 2 +- assets/lang/zh_TW.ini | 2 +- 31 files changed, 31 insertions(+), 31 deletions(-) diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 1f2dcbf436..78ce12bd2e 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -550,7 +550,7 @@ Software Rendering = Softwarové vykreslování (experimentální) Software Skinning = Textury aplikuje software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Rychlost -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (Mohou způsobit problémy) Stretching = Roztažení Texture Filter = Filtr textur Texture Filtering = Filtrování textur diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 72f0431317..02e61c6366 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -550,7 +550,7 @@ Software Rendering = Software rendering (eksperiment) Software Skinning = Software skinning SoftwareSkinning Tip = Kombiner begrænset model tegning af CPU, hurtigere i fleste spil Speed = Hastighed -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (kan give fejl) Stretching = Stretching Texture Filter = Texturfilter Texture Filtering = Texturfiltrering diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index fb0056e3dc..bb01cfeacd 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -550,7 +550,7 @@ Software Rendering = Software Renderer (experimentell) Software Skinning = Software Skinning SoftwareSkinning Tip = Reduziert Grafikbefehle und schneller in Spielen mit erweiterter Skinning-Technik, in anderen Spielen langsamer Speed = Geschwindigkeit -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (kann zu Fehlern führen) Stretching = Strecken Texture Filter = Texturfilter Texture Filtering = Texturfilterung diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 2f5dd72031..7d587aa8e3 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -550,7 +550,7 @@ Software Rendering = Renderizado por software Software Skinning = "Skinning" por software SoftwareSkinning Tip = Reduce la carga de dibujado, rápido en juegos con técnicas de skinning avanzadas, pero lento en otros. Speed = Velocidad -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (causarán errores gráficos) Stretching = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 7c789a7f75..59019321b3 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -550,7 +550,7 @@ Software Rendering = Renderizado por software (experimental) Software Skinning = Skineado por software SoftwareSkinning Tip = Combina dibujados de modelo de skineado en la CPU. Acelera muchos juegos pero ralentiza otros. Speed = Velocidad -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (puede causar glitches) Stretching = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 7b7b8ca47b..925f48c1a7 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -550,7 +550,7 @@ Software Rendering = ‎(رندر نرم افزاری (آزمایشی Software Skinning = Software skinning SoftwareSkinning Tip = ‎در اکثر بازی ها سریع تر ،CPU دار در skin ترکیب رسم مدل های Speed = ‎سرعت -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks ‎(میتواند باعث باگ شود) Stretching = ‎کشیدن Texture Filter = ‎فیلتر تکسچر Texture Filtering = ‎فیلتر کردن تکسچر diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 23b23fccd6..8f4dd25f7e 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -550,7 +550,7 @@ Software Rendering = Rendu logiciel (expérimental) Software Skinning = Enveloppe logicielle SoftwareSkinning Tip = Combine l'affichage des modèles enveloppés sur le CPU, plus rapide dans la plupart des jeux Speed = Vitesse -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (crée des bugs graphiques) Stretching = Étirement Texture Filter = Filtre de textures Texture Filtering = Filtrage des textures diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 5e8fe159d4..1ec4ad468d 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -550,7 +550,7 @@ Software Rendering = Renderizado por software (beta) Software Skinning = «Skinning» por software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Velocidade -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (causarán erros gráficos) Stretching = Stretching Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index a6465719e8..5fc79d26e0 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -550,7 +550,7 @@ Software Rendering = Žbukanje softvera (sporo) Software Skinning = Skiniranje softvera SoftwareSkinning Tip = Kombiniraj skinirane modele crteža na CPU, brže u većini igara Speed = Brzina -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (može uzrokovati glitcheve) Stretching = Rastezanje Texture Filter = Filtar tekstura Texture Filtering = Filtriranje tekstura diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 945b81fab2..c5f9433ce2 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -550,7 +550,7 @@ Software Rendering = Szoftveres renderelés (lassú) Software Skinning = Szoftveres "skinning" SoftwareSkinning Tip = "Skinning" művelet elvégzése a processzoron. Sok játék esetében gyorsabb. Speed = Sebesség -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (ezek HIBÁKAT OKOZHATNAK) Stretching = Nyújtás Texture Filter = Textúra szűrés Texture Filtering = Textúra szűrés diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index c1fe30cf77..3e75cd0a93 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -550,7 +550,7 @@ Software Rendering = Pelukisan perangkat lunak (eksperimental) Software Skinning = Pengkulitan perangkat lunak SoftwareSkinning Tip = Menggabungkan model berkulit pada CPU, lebih cepat di kebanyakan permainan Speed = Kecepatan -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (menyebabkan kecacatan) Stretching = Peregangan Texture Filter = Filter tekstur Texture Filtering = Pemfilteran tekstur diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 5ca9f3470e..ed9fda0f09 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -551,7 +551,7 @@ Software Rendering = Rendering tramite Software (sperimentale) Software Skinning = Software Skinning SoftwareSkinning Tip = Combina la visualizzazione di modelli disegnati dalla CPU, più veloce nella maggior parte dei giochi Speed = Velocità -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (causerà dei problemi) Stretching = Adatta al Display Texture Filter = Filtro delle texture Texture Filtering = Filtraggio delle texture diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index d49482846e..cc152ab6f3 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -550,7 +550,7 @@ Software Rendering = ソフトウェアレンダリング (実験的) Software Skinning = ソフトウェアスキニング SoftwareSkinning Tip = スキンモデルの描画をCPUでまとめて行う。ほとんどのゲームが高速化します Speed = 速度 -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (不具合あり) Stretching = 拡大 Texture Filter = テクスチャフィルタ Texture Filtering = テクスチャフィルタリング diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 328bb6a46f..43b9d219cb 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -550,7 +550,7 @@ Software Rendering = Software rendering (jajalan) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Kacepetan -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (nyebabake glitches) Stretching = Stretching Texture Filter = Penyaring Tekstur Texture Filtering = Penyaring Tekstur diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index ea067713be..c9074383ce 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -549,7 +549,7 @@ Software Rendering = 소프트웨어 렌더링 (느림) Software Skinning = 소프트웨어 스키닝 SoftwareSkinning Tip = 대부분의 게임에서 더 빠르게 CPU에서 스킨 모델 드로우를 결합합니다. Speed = 속도 -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (결함을 일으킬 수 있음) Stretching = 늘이기 Texture Filter = 텍스처 필터링 Texture Filtering = 텍스처 필터링 diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index d01df7a0ad..b2d3a3c81f 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -550,7 +550,7 @@ Software Rendering = Programinės įrangos rodymas(ekspermentalus) Software Skinning = Programinės įrangos "nulupimas" SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Greitis -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (gali sukelti problemų) Stretching = Stretching Texture Filter = Tekstūrų filtravimas Texture Filtering = Tekstūrų filtravimas diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index cb7a06426d..32dc995720 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -550,7 +550,7 @@ Software Rendering = Render perisian (eksperimen) Software Skinning = Pembalutan Perisian SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Laju -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (mungkin menyebabkan gangguan) Stretching = Stretching Texture Filter = Penapis Tekstur Texture Filtering = Penapisan Tekstur diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 8a4a3c3339..9ec6b9a017 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -550,7 +550,7 @@ Software Rendering = Renderen via software (experimenteel) Software Skinning = Skinning via software SoftwareSkinning Tip = Vermindert aantal renders en is sneller in games die de geavanceerde skinningtechniek gebruiken, maar voor sommige games trager Speed = Snelheid -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (kan glitches veroorzaken) Stretching = Uitrekken Texture Filter = Texturefilter Texture Filtering = Texturefilter diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 25c17fef2f..98ffd7fd04 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -550,7 +550,7 @@ Software Rendering = Renderowanie programowe (wolne) Software Skinning = Programowy skinning SoftwareSkinning Tip = Łączy na CPU wywołania rysujące modele z animacjami, przyspieszenie w większości gier Speed = Prędkość (procentowo) -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (powodują problemy) Stretching = Rozciąganie Texture Filter = Filtrowanie tekstur Texture Filtering = Filtrowanie tekstur diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 970025ecb0..7827800c21 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -573,7 +573,7 @@ Software Rendering = Renderização por software (lento) Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (pode causar erros gráficos) Stretching = Esticamento Texture Filter = Filtragem das texturas Texture Filtering = Filtragem das texturas diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 244bc14492..21262dea6e 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -573,7 +573,7 @@ Software Rendering = Renderização por software (lento) Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (pode causar erros gráficos) Stretching = Esticamento Texture Filter = Filtração das texturas Texture Filtering = Filtração das texturas diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index c639b659ae..22bc711b1d 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -550,7 +550,7 @@ Software Rendering = Afișare cu sofware (experimental) Software Skinning = Skinning cu software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Viteză -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (pot cauza stricăciuni) Stretching = Stretching Texture Filter = Filtru texturi Texture Filtering = Filtrare texturi diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 5b02a758d1..a3a421559c 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -551,7 +551,7 @@ Software Rendering = Программный рендеринг (медленно Software Skinning = Программная заливка SoftwareSkinning Tip = Объединяет вызовы отрисовки моделей с заливкой на ЦП, быстрее во многих играх Speed = Скорость -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (могут вызывать глюки) Stretching = Растягивание Texture Filter = Текстурный фильтр Texture Filtering = Фильтрация текстур diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 03a8b4d574..c55bd25529 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -550,7 +550,7 @@ Software Rendering = Mjukvarurendering (experiment) Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed-hacks (kan orsaka renderingsproblem) Stretching = Stretching Texture Filter = Texturfilter Texture Filtering = Texturfiltrering diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 7f90a8349d..624644a464 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -550,7 +550,7 @@ Software Rendering = Software Rendering (Expiremental) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Bilis -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (maaring magdulot ng pagloloko sa laro) Stretching = Iunat Texture Filter = Panala ng Texture Texture Filtering = Pagsala sa Texture diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index d9a6d1eff6..2f48108dd7 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -550,7 +550,7 @@ Software Rendering = ใช้ซอฟต์แวร์ในการแส Software Skinning = ซอฟต์แวร์ สกินนิ่ง SoftwareSkinning Tip = ผสานโมเดลพื้นผิวให้เขียนผ่านซีพียู ซึ่งเกมส่วนใหญ่ปรับใช้แล้วไวขึ้น Speed = ความเร็ว -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (อาจแสดงผลผิดพลาด) Stretching = ดึงเต็มจอ Texture Filter = ตัวกรองพื้นผิว Texture Filtering = การกรองพื้นผิว diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 96a1ccb313..6183381f8b 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -552,7 +552,7 @@ Software Rendering = Yazılımsal işleme (Deneysel) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hız -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Hız Hacks (Küçük teknik problemlere neden olabilir.) Stretching = Serbest tam ekran (sünme) Texture Filter = Doku filtreleme Texture Filtering = Doku filtreleme diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 5c57d9af18..d27fc056b1 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -550,7 +550,7 @@ Software Rendering = Програмний рендеринг (експериме Software Skinning = Програмна заливка SoftwareSkinning Tip = Комбінована модель розібраної моделі яка притягується до процесора, швидше в більшості ігор Speed = Швидкість -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (можуть викликати глюки) Stretching = Розтягнення Texture Filter = Фільтр текстур Texture Filtering = Фільтрація текстур diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 6aed763937..0aeebfb027 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -550,7 +550,7 @@ Software Rendering = Dựng hình bằng phần mềm Software Skinning = phủ lớp bằng phần mềm SoftwareSkinning Tip = Mô hình kết hợp vẽ trên CPU, nhanh hơn trong hầu hết các trò chơi Speed = Tốc độ -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Tốc độ Hacks (sẽ bị lỗi) Stretching = Stretching Texture Filter = Bộ lọc họa tiết Texture Filtering = Lọc texture diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index d5bd28529b..7b1f77592f 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -550,7 +550,7 @@ Software Rendering = 软件渲染(慢) Software Skinning = 软件蒙皮 SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快 Speed = 运行速度 -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (可能引发故障) Stretching = 拉伸 Texture Filter = 纹理过滤方式 Texture Filtering = 纹理过滤 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 0b2ec4b154..4ae22d488f 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -549,7 +549,7 @@ Software Rendering = 軟體轉譯 (慢) Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 -Speed Hacks = Speed Hacks (can cause rendering errors!) +Speed Hacks = Speed Hacks (可能會造成故障) Stretching = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 From 637bb57bc6bdcf5339b385010e3e2b3da7664758 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 6 Nov 2022 20:42:28 +0100 Subject: [PATCH 229/715] OpenXR - Get rid of ovrMatrix4f structure --- Common/VR/PPSSPPVR.cpp | 25 +-- Common/VR/VRMath.cpp | 329 ++++++++------------------------------- Common/VR/VRMath.h | 20 +-- Common/VR/VRRenderer.cpp | 71 ++++++--- Common/VR/VRRenderer.h | 2 +- 5 files changed, 136 insertions(+), 311 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 537844b073..bce2f00227 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -9,6 +9,8 @@ #endif #include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/Math/lin/matrix4x4.h" + #include "Core/HLE/sceDisplay.h" #include "Core/Config.h" #include "Core/KeyMap.h" @@ -584,15 +586,13 @@ void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { float* dst[] = {leftEye, rightEye}; VRMatrix enums[] = {VR_PROJECTION_MATRIX_LEFT_EYE, VR_PROJECTION_MATRIX_RIGHT_EYE}; for (int index = 0; index < 2; index++) { - ovrMatrix4f hmdProjection = VR_GetMatrix(enums[index]); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - if ((hmdProjection.M[i][j] > 0) != (projMatrix[i * 4 + j] > 0)) { - hmdProjection.M[i][j] *= -1.0f; - } + float* hmdProjection = VR_GetMatrix(enums[index]); + for (int i = 0; i < 16; i++) { + if ((hmdProjection[i] > 0) != (projMatrix[i] > 0)) { + hmdProjection[i] *= -1.0f; } } - memcpy(dst[index], hmdProjection.M, 16 * sizeof(float)); + memcpy(dst[index], hmdProjection, 16 * sizeof(float)); } } @@ -602,14 +602,15 @@ void UpdateVRView(float* leftEye, float* rightEye) { for (int index = 0; index < 2; index++) { // Get view matrix from the game - ovrMatrix4f gameView; - memcpy(gameView.M, dst[index], 16 * sizeof(float)); + Lin::Matrix4x4 gameView = {}; + memcpy(gameView.m, dst[index], 16 * sizeof(float)); // Get view matrix from the headset - ovrMatrix4f hmdView = VR_GetMatrix(enums[index]); + Lin::Matrix4x4 hmdView = {}; + memcpy(hmdView.m, VR_GetMatrix(enums[index]), 16 * sizeof(float)); // Combine the matrices - ovrMatrix4f renderView = ovrMatrix4f_Multiply(&hmdView, &gameView); - memcpy(dst[index], renderView.M, 16 * sizeof(float)); + Lin::Matrix4x4 renderView = hmdView * gameView; + memcpy(dst[index], renderView.m, 16 * sizeof(float)); } } diff --git a/Common/VR/VRMath.cpp b/Common/VR/VRMath.cpp index bafdff75ea..2fd7f1d538 100644 --- a/Common/VR/VRMath.cpp +++ b/Common/VR/VRMath.cpp @@ -1,6 +1,7 @@ #define _USE_MATH_DEFINES #include +#include #include "VRMath.h" @@ -15,240 +16,21 @@ float ToRadians(float deg) { /* ================================================================================ -ovrMatrix4f - -================================================================================ -*/ - -float ovrMatrix4f_Minor(const ovrMatrix4f* m, int r0, int r1, int r2, int c0, int c1, int c2) { - return m->M[r0][c0] * (m->M[r1][c1] * m->M[r2][c2] - m->M[r2][c1] * m->M[r1][c2]) - - m->M[r0][c1] * (m->M[r1][c0] * m->M[r2][c2] - m->M[r2][c0] * m->M[r1][c2]) + - m->M[r0][c2] * (m->M[r1][c0] * m->M[r2][c1] - m->M[r2][c0] * m->M[r1][c1]); -} - -ovrMatrix4f ovrMatrix4f_CreateFromQuaternion(const XrQuaternionf* q) { - const float ww = q->w * q->w; - const float xx = q->x * q->x; - const float yy = q->y * q->y; - const float zz = q->z * q->z; - - ovrMatrix4f out; - out.M[0][0] = ww + xx - yy - zz; - out.M[0][1] = 2 * (q->x * q->y - q->w * q->z); - out.M[0][2] = 2 * (q->x * q->z + q->w * q->y); - out.M[0][3] = 0; - - out.M[1][0] = 2 * (q->x * q->y + q->w * q->z); - out.M[1][1] = ww - xx + yy - zz; - out.M[1][2] = 2 * (q->y * q->z - q->w * q->x); - out.M[1][3] = 0; - - out.M[2][0] = 2 * (q->x * q->z - q->w * q->y); - out.M[2][1] = 2 * (q->y * q->z + q->w * q->x); - out.M[2][2] = ww - xx - yy + zz; - out.M[2][3] = 0; - - out.M[3][0] = 0; - out.M[3][1] = 0; - out.M[3][2] = 0; - out.M[3][3] = 1; - return out; -} - -ovrMatrix4f ovrMatrix4f_CreateProjectionFov( - const float angleLeft, - const float angleRight, - const float angleUp, - const float angleDown, - const float nearZ, - const float farZ) { - - const float tanAngleLeft = tanf(angleLeft); - const float tanAngleRight = tanf(angleRight); - - const float tanAngleDown = tanf(angleDown); - const float tanAngleUp = tanf(angleUp); - - const float tanAngleWidth = tanAngleRight - tanAngleLeft; - - // Set to tanAngleDown - tanAngleUp for a clip space with positive Y - // down (Vulkan). Set to tanAngleUp - tanAngleDown for a clip space with - // positive Y up (OpenGL / D3D / Metal). - const float tanAngleHeight = tanAngleUp - tanAngleDown; - - // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES). - // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal). - const float offsetZ = nearZ; - - ovrMatrix4f result; - if (farZ <= nearZ) { - // place the far plane at infinity - result.M[0][0] = 2 / tanAngleWidth; - result.M[0][1] = 0; - result.M[0][2] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; - result.M[0][3] = 0; - - result.M[1][0] = 0; - result.M[1][1] = 2 / tanAngleHeight; - result.M[1][2] = (tanAngleUp + tanAngleDown) / tanAngleHeight; - result.M[1][3] = 0; - - result.M[2][0] = 0; - result.M[2][1] = 0; - result.M[2][2] = -1; - result.M[2][3] = -(nearZ + offsetZ); - - result.M[3][0] = 0; - result.M[3][1] = 0; - result.M[3][2] = -1; - result.M[3][3] = 0; - } else { - // normal projection - result.M[0][0] = 2 / tanAngleWidth; - result.M[0][1] = 0; - result.M[0][2] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; - result.M[0][3] = 0; - - result.M[1][0] = 0; - result.M[1][1] = 2 / tanAngleHeight; - result.M[1][2] = (tanAngleUp + tanAngleDown) / tanAngleHeight; - result.M[1][3] = 0; - - result.M[2][0] = 0; - result.M[2][1] = 0; - result.M[2][2] = -(farZ + offsetZ) / (farZ - nearZ); - result.M[2][3] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ); - - result.M[3][0] = 0; - result.M[3][1] = 0; - result.M[3][2] = -1; - result.M[3][3] = 0; - } - return result; -} - -ovrMatrix4f ovrMatrix4f_CreateRotation(const float radiansX, const float radiansY, const float radiansZ) { - const float sinX = sinf(radiansX); - const float cosX = cosf(radiansX); - const ovrMatrix4f rotationX = { - {{1, 0, 0, 0}, {0, cosX, -sinX, 0}, {0, sinX, cosX, 0}, {0, 0, 0, 1}}}; - const float sinY = sinf(radiansY); - const float cosY = cosf(radiansY); - const ovrMatrix4f rotationY = { - {{cosY, 0, sinY, 0}, {0, 1, 0, 0}, {-sinY, 0, cosY, 0}, {0, 0, 0, 1}}}; - const float sinZ = sinf(radiansZ); - const float cosZ = cosf(radiansZ); - const ovrMatrix4f rotationZ = { - {{cosZ, -sinZ, 0, 0}, {sinZ, cosZ, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}}; - const ovrMatrix4f rotationXY = ovrMatrix4f_Multiply(&rotationY, &rotationX); - return ovrMatrix4f_Multiply(&rotationZ, &rotationXY); -} - -ovrMatrix4f ovrMatrix4f_Inverse(const ovrMatrix4f* m) { - const float rcpDet = 1.0f / - (m->M[0][0] * ovrMatrix4f_Minor(m, 1, 2, 3, 1, 2, 3) - - m->M[0][1] * ovrMatrix4f_Minor(m, 1, 2, 3, 0, 2, 3) + - m->M[0][2] * ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 3) - - m->M[0][3] * ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 2)); - ovrMatrix4f out; - out.M[0][0] = ovrMatrix4f_Minor(m, 1, 2, 3, 1, 2, 3) * rcpDet; - out.M[0][1] = -ovrMatrix4f_Minor(m, 0, 2, 3, 1, 2, 3) * rcpDet; - out.M[0][2] = ovrMatrix4f_Minor(m, 0, 1, 3, 1, 2, 3) * rcpDet; - out.M[0][3] = -ovrMatrix4f_Minor(m, 0, 1, 2, 1, 2, 3) * rcpDet; - out.M[1][0] = -ovrMatrix4f_Minor(m, 1, 2, 3, 0, 2, 3) * rcpDet; - out.M[1][1] = ovrMatrix4f_Minor(m, 0, 2, 3, 0, 2, 3) * rcpDet; - out.M[1][2] = -ovrMatrix4f_Minor(m, 0, 1, 3, 0, 2, 3) * rcpDet; - out.M[1][3] = ovrMatrix4f_Minor(m, 0, 1, 2, 0, 2, 3) * rcpDet; - out.M[2][0] = ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 3) * rcpDet; - out.M[2][1] = -ovrMatrix4f_Minor(m, 0, 2, 3, 0, 1, 3) * rcpDet; - out.M[2][2] = ovrMatrix4f_Minor(m, 0, 1, 3, 0, 1, 3) * rcpDet; - out.M[2][3] = -ovrMatrix4f_Minor(m, 0, 1, 2, 0, 1, 3) * rcpDet; - out.M[3][0] = -ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 2) * rcpDet; - out.M[3][1] = ovrMatrix4f_Minor(m, 0, 2, 3, 0, 1, 2) * rcpDet; - out.M[3][2] = -ovrMatrix4f_Minor(m, 0, 1, 3, 0, 1, 2) * rcpDet; - out.M[3][3] = ovrMatrix4f_Minor(m, 0, 1, 2, 0, 1, 2) * rcpDet; - return out; -} - -/// Use left-multiplication to accumulate transformations. -ovrMatrix4f ovrMatrix4f_Multiply(const ovrMatrix4f* a, const ovrMatrix4f* b) { - ovrMatrix4f out; - out.M[0][0] = a->M[0][0] * b->M[0][0] + a->M[0][1] * b->M[1][0] + a->M[0][2] * b->M[2][0] + - a->M[0][3] * b->M[3][0]; - out.M[1][0] = a->M[1][0] * b->M[0][0] + a->M[1][1] * b->M[1][0] + a->M[1][2] * b->M[2][0] + - a->M[1][3] * b->M[3][0]; - out.M[2][0] = a->M[2][0] * b->M[0][0] + a->M[2][1] * b->M[1][0] + a->M[2][2] * b->M[2][0] + - a->M[2][3] * b->M[3][0]; - out.M[3][0] = a->M[3][0] * b->M[0][0] + a->M[3][1] * b->M[1][0] + a->M[3][2] * b->M[2][0] + - a->M[3][3] * b->M[3][0]; - - out.M[0][1] = a->M[0][0] * b->M[0][1] + a->M[0][1] * b->M[1][1] + a->M[0][2] * b->M[2][1] + - a->M[0][3] * b->M[3][1]; - out.M[1][1] = a->M[1][0] * b->M[0][1] + a->M[1][1] * b->M[1][1] + a->M[1][2] * b->M[2][1] + - a->M[1][3] * b->M[3][1]; - out.M[2][1] = a->M[2][0] * b->M[0][1] + a->M[2][1] * b->M[1][1] + a->M[2][2] * b->M[2][1] + - a->M[2][3] * b->M[3][1]; - out.M[3][1] = a->M[3][0] * b->M[0][1] + a->M[3][1] * b->M[1][1] + a->M[3][2] * b->M[2][1] + - a->M[3][3] * b->M[3][1]; - - out.M[0][2] = a->M[0][0] * b->M[0][2] + a->M[0][1] * b->M[1][2] + a->M[0][2] * b->M[2][2] + - a->M[0][3] * b->M[3][2]; - out.M[1][2] = a->M[1][0] * b->M[0][2] + a->M[1][1] * b->M[1][2] + a->M[1][2] * b->M[2][2] + - a->M[1][3] * b->M[3][2]; - out.M[2][2] = a->M[2][0] * b->M[0][2] + a->M[2][1] * b->M[1][2] + a->M[2][2] * b->M[2][2] + - a->M[2][3] * b->M[3][2]; - out.M[3][2] = a->M[3][0] * b->M[0][2] + a->M[3][1] * b->M[1][2] + a->M[3][2] * b->M[2][2] + - a->M[3][3] * b->M[3][2]; - - out.M[0][3] = a->M[0][0] * b->M[0][3] + a->M[0][1] * b->M[1][3] + a->M[0][2] * b->M[2][3] + - a->M[0][3] * b->M[3][3]; - out.M[1][3] = a->M[1][0] * b->M[0][3] + a->M[1][1] * b->M[1][3] + a->M[1][2] * b->M[2][3] + - a->M[1][3] * b->M[3][3]; - out.M[2][3] = a->M[2][0] * b->M[0][3] + a->M[2][1] * b->M[1][3] + a->M[2][2] * b->M[2][3] + - a->M[2][3] * b->M[3][3]; - out.M[3][3] = a->M[3][0] * b->M[0][3] + a->M[3][1] * b->M[1][3] + a->M[3][2] * b->M[2][3] + - a->M[3][3] * b->M[3][3]; - return out; -} - -XrVector3f ovrMatrix4f_ToEulerAngles(const ovrMatrix4f* m) { - XrVector4f v1 = {0, 0, -1, 0}; - XrVector4f v2 = {1, 0, 0, 0}; - XrVector4f v3 = {0, 1, 0, 0}; - - XrVector4f forwardInVRSpace = XrVector4f_MultiplyMatrix4f(m, &v1); - XrVector4f rightInVRSpace = XrVector4f_MultiplyMatrix4f(m, &v2); - XrVector4f upInVRSpace = XrVector4f_MultiplyMatrix4f(m, &v3); - - XrVector3f forward = {-forwardInVRSpace.z, -forwardInVRSpace.x, forwardInVRSpace.y}; - XrVector3f right = {-rightInVRSpace.z, -rightInVRSpace.x, rightInVRSpace.y}; - XrVector3f up = {-upInVRSpace.z, -upInVRSpace.x, upInVRSpace.y}; - - XrVector3f forwardNormal = XrVector3f_Normalized(forward); - XrVector3f rightNormal = XrVector3f_Normalized(right); - XrVector3f upNormal = XrVector3f_Normalized(up); - - return XrVector3f_GetAnglesFromVectors(forwardNormal, rightNormal, upNormal); -} - -/* -================================================================================ - XrPosef ================================================================================ */ XrPosef XrPosef_Identity() { - XrPosef r; - r.orientation.x = 0; - r.orientation.y = 0; - r.orientation.z = 0; - r.orientation.w = 1; - r.position.x = 0; - r.position.y = 0; - r.position.z = 0; - return r; + XrPosef r; + r.orientation.x = 0; + r.orientation.y = 0; + r.orientation.z = 0; + r.orientation.w = 1; + r.position.x = 0; + r.position.y = 0; + r.position.z = 0; + return r; } XrPosef XrPosef_Inverse(const XrPosef a) { @@ -258,18 +40,6 @@ XrPosef XrPosef_Inverse(const XrPosef a) { return b; } -XrPosef XrPosef_Multiply(const XrPosef a, const XrPosef b) { - XrPosef c; - c.orientation = XrQuaternionf_Multiply(a.orientation, b.orientation); - c.position = XrPosef_Transform(a, b.position); - return c; -} - -XrVector3f XrPosef_Transform(const XrPosef a, const XrVector3f v) { - XrVector3f r0 = XrQuaternionf_Rotate(a.orientation, v); - return XrVector3f_Add(r0, a.position); -} - /* ================================================================================ @@ -329,8 +99,56 @@ XrVector3f XrQuaternionf_Rotate(const XrQuaternionf a, const XrVector3f v) { } XrVector3f XrQuaternionf_ToEulerAngles(const XrQuaternionf q) { - ovrMatrix4f m = ovrMatrix4f_CreateFromQuaternion( &q ); - return ovrMatrix4f_ToEulerAngles(&m); + float M[16]; + XrQuaternionf_ToMatrix4f( &q, M); + + XrVector4f v1 = {0, 0, -1, 0}; + XrVector4f v2 = {1, 0, 0, 0}; + XrVector4f v3 = {0, 1, 0, 0}; + + XrVector4f forwardInVRSpace = XrVector4f_MultiplyMatrix4f(M, &v1); + XrVector4f rightInVRSpace = XrVector4f_MultiplyMatrix4f(M, &v2); + XrVector4f upInVRSpace = XrVector4f_MultiplyMatrix4f(M, &v3); + + XrVector3f forward = {-forwardInVRSpace.z, -forwardInVRSpace.x, forwardInVRSpace.y}; + XrVector3f right = {-rightInVRSpace.z, -rightInVRSpace.x, rightInVRSpace.y}; + XrVector3f up = {-upInVRSpace.z, -upInVRSpace.x, upInVRSpace.y}; + + XrVector3f forwardNormal = XrVector3f_Normalized(forward); + XrVector3f rightNormal = XrVector3f_Normalized(right); + XrVector3f upNormal = XrVector3f_Normalized(up); + + return XrVector3f_GetAnglesFromVectors(forwardNormal, rightNormal, upNormal); +} + +void XrQuaternionf_ToMatrix4f(const XrQuaternionf* q, float* matrix) { + const float ww = q->w * q->w; + const float xx = q->x * q->x; + const float yy = q->y * q->y; + const float zz = q->z * q->z; + + float M[4][4]; + M[0][0] = ww + xx - yy - zz; + M[0][1] = 2 * (q->x * q->y - q->w * q->z); + M[0][2] = 2 * (q->x * q->z + q->w * q->y); + M[0][3] = 0; + + M[1][0] = 2 * (q->x * q->y + q->w * q->z); + M[1][1] = ww - xx + yy - zz; + M[1][2] = 2 * (q->y * q->z - q->w * q->x); + M[1][3] = 0; + + M[2][0] = 2 * (q->x * q->z - q->w * q->y); + M[2][1] = 2 * (q->y * q->z + q->w * q->x); + M[2][2] = ww - xx - yy + zz; + M[2][3] = 0; + + M[3][0] = 0; + M[3][1] = 0; + M[3][2] = 0; + M[3][3] = 1; + + memcpy(matrix, &M, sizeof(float) * 16); } /* @@ -341,22 +159,10 @@ XrVector3f, XrVector4f ================================================================================ */ -float XrVector3f_Length(const XrVector3f v) { - return sqrtf(XrVector3f_LengthSquared(v)); -} - float XrVector3f_LengthSquared(const XrVector3f v) { return v.x * v.x + v.y * v.y + v.z * v.z;; } -XrVector3f XrVector3f_Add(const XrVector3f u, const XrVector3f v) { - XrVector3f w; - w.x = u.x + v.x; - w.y = u.y + v.y; - w.z = u.z + v.z; - return w; -} - XrVector3f XrVector3f_GetAnglesFromVectors(const XrVector3f forward, const XrVector3f right, const XrVector3f up) { float sr, sp, sy, cr, cp, cy; @@ -397,7 +203,7 @@ XrVector3f XrVector3f_GetAnglesFromVectors(const XrVector3f forward, const XrVec } XrVector3f XrVector3f_Normalized(const XrVector3f v) { - float rcpLen = 1.0f / XrVector3f_Length(v); + float rcpLen = 1.0f / sqrtf(XrVector3f_LengthSquared(v)); return XrVector3f_ScalarMultiply(v, rcpLen); } @@ -409,11 +215,14 @@ XrVector3f XrVector3f_ScalarMultiply(const XrVector3f v, float scale) { return u; } -XrVector4f XrVector4f_MultiplyMatrix4f(const ovrMatrix4f* a, const XrVector4f* v) { +XrVector4f XrVector4f_MultiplyMatrix4f(const float* m, const XrVector4f* v) { + float M[4][4]; + memcpy(&M, m, sizeof(float) * 16); + XrVector4f out; - out.x = a->M[0][0] * v->x + a->M[0][1] * v->y + a->M[0][2] * v->z + a->M[0][3] * v->w; - out.y = a->M[1][0] * v->x + a->M[1][1] * v->y + a->M[1][2] * v->z + a->M[1][3] * v->w; - out.z = a->M[2][0] * v->x + a->M[2][1] * v->y + a->M[2][2] * v->z + a->M[2][3] * v->w; - out.w = a->M[3][0] * v->x + a->M[3][1] * v->y + a->M[3][2] * v->z + a->M[3][3] * v->w; + out.x = M[0][0] * v->x + M[0][1] * v->y + M[0][2] * v->z + M[0][3] * v->w; + out.y = M[1][0] * v->x + M[1][1] * v->y + M[1][2] * v->z + M[1][3] * v->w; + out.z = M[2][0] * v->x + M[2][1] * v->y + M[2][2] * v->z + M[2][3] * v->w; + out.w = M[3][0] * v->x + M[3][1] * v->y + M[3][2] * v->z + M[3][3] * v->w; return out; } diff --git a/Common/VR/VRMath.h b/Common/VR/VRMath.h index eb801ac73f..20317f4a8d 100644 --- a/Common/VR/VRMath.h +++ b/Common/VR/VRMath.h @@ -7,27 +7,12 @@ #define EPSILON 0.001f #endif -typedef struct { - float M[4][4]; -} ovrMatrix4f; - float ToDegrees(float rad); float ToRadians(float deg); -// ovrMatrix4f -float ovrMatrix4f_Minor(const ovrMatrix4f* m, int r0, int r1, int r2, int c0, int c1, int c2); -ovrMatrix4f ovrMatrix4f_CreateFromQuaternion(const XrQuaternionf* q); -ovrMatrix4f ovrMatrix4f_CreateProjectionFov(const float angleLeft, const float angleRight, const float angleUp, const float angleDown, const float nearZ, const float farZ); -ovrMatrix4f ovrMatrix4f_CreateRotation(const float radiansX, const float radiansY, const float radiansZ); -ovrMatrix4f ovrMatrix4f_Inverse(const ovrMatrix4f* m); -ovrMatrix4f ovrMatrix4f_Multiply(const ovrMatrix4f* a, const ovrMatrix4f* b); -XrVector3f ovrMatrix4f_ToEulerAngles(const ovrMatrix4f* m); - // XrPosef XrPosef XrPosef_Identity(); XrPosef XrPosef_Inverse(const XrPosef a); -XrPosef XrPosef_Multiply(const XrPosef a, const XrPosef b); -XrVector3f XrPosef_Transform(const XrPosef a, const XrVector3f v); // XrQuaternionf XrQuaternionf XrQuaternionf_CreateFromVectorAngle(const XrVector3f axis, const float angle); @@ -35,12 +20,11 @@ XrQuaternionf XrQuaternionf_Inverse(const XrQuaternionf q); XrQuaternionf XrQuaternionf_Multiply(const XrQuaternionf a, const XrQuaternionf b); XrVector3f XrQuaternionf_Rotate(const XrQuaternionf a, const XrVector3f v); XrVector3f XrQuaternionf_ToEulerAngles(const XrQuaternionf q); +void XrQuaternionf_ToMatrix4f(const XrQuaternionf* q, float* m); // XrVector3f, XrVector4f -float XrVector3f_Length(const XrVector3f v); float XrVector3f_LengthSquared(const XrVector3f v); -XrVector3f XrVector3f_Add(const XrVector3f u, const XrVector3f v); XrVector3f XrVector3f_GetAnglesFromVectors(const XrVector3f forward, const XrVector3f right, const XrVector3f up); XrVector3f XrVector3f_Normalized(const XrVector3f v); XrVector3f XrVector3f_ScalarMultiply(const XrVector3f v, float scale); -XrVector4f XrVector4f_MultiplyMatrix4f(const ovrMatrix4f* a, const XrVector4f* v); +XrVector4f XrVector4f_MultiplyMatrix4f(const float* m, const XrVector4f* v); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index e67d4ecd62..cbe69f2307 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -16,7 +16,7 @@ XrPosef invViewTransform[2]; XrFrameState frameState = {}; bool initialized = false; bool stageSupported = false; -ovrMatrix4f vrMatrix[VR_MATRIX_COUNT]; +float vrMatrix[VR_MATRIX_COUNT][16]; int vrConfig[VR_CONFIG_MAX] = {}; float vrConfigFloat[VR_CONFIG_FLOAT_MAX] = {}; @@ -306,8 +306,35 @@ bool VR_InitFrame( engine_t* engine ) { // Update matrices for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) { - float nearPlane = VR_GetConfigFloat(VR_CONFIG_FOV_SCALE) / 200.0f; - vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, nearPlane, 0.0f ); + float nearZ = VR_GetConfigFloat(VR_CONFIG_FOV_SCALE) / 200.0f; + float tanAngleLeft = tanf(fov.angleLeft); + float tanAngleRight = tanf(fov.angleRight); + float tanAngleDown = tanf(fov.angleDown); + float tanAngleUp = tanf(fov.angleUp); + + float M[4][4]; + M[0][0] = 2 / (tanAngleRight - tanAngleLeft); + M[0][1] = 0; + M[0][2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); + M[0][3] = 0; + + M[1][0] = 0; + M[1][1] = 2 / (tanAngleUp - tanAngleDown); + M[1][2] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); + M[1][3] = 0; + + // place the far plane at infinity + M[2][0] = 0; + M[2][1] = 0; + M[2][2] = -1; + M[2][3] = -(nearZ + nearZ); + + M[3][0] = 0; + M[3][1] = 0; + M[3][2] = -1; + M[3][3] = 0; + + memcpy(vrMatrix[matrix], M, sizeof(float) * 16); } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { bool flatScreen = false; XrPosef invView = invViewTransform[0]; @@ -340,36 +367,39 @@ bool VR_InitFrame( engine_t* engine ) { invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); } - vrMatrix[matrix] = ovrMatrix4f_CreateFromQuaternion(&invView.orientation); + float M[16]; + XrQuaternionf_ToMatrix4f(&invView.orientation, M); + memcpy(&M, M, sizeof(float) * 16); + float scale = VR_GetConfigFloat(VR_CONFIG_6DOF_SCALE); if (!flatScreen && vrConfig[VR_CONFIG_6DOF_ENABLED]) { - vrMatrix[matrix].M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; - vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; - vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; + M[12] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; + M[13] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; + M[14] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; } if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE)) > 0.0f) { XrVector3f forward = {0.0f, 0.0f, VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE) * scale}; forward = XrQuaternionf_Rotate(invView.orientation, forward); forward = XrVector3f_ScalarMultiply(forward, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - vrMatrix[matrix].M[0][3] += forward.x; - vrMatrix[matrix].M[1][3] += forward.y; - vrMatrix[matrix].M[2][3] += forward.z; + M[12] += forward.x; + M[13] += forward.y; + M[14] += forward.z; } if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT)) > 0.0f) { XrVector3f up = {0.0f, -VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT) * scale, 0.0f}; up = XrQuaternionf_Rotate(invView.orientation, up); up = XrVector3f_ScalarMultiply(up, vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f); - vrMatrix[matrix].M[0][3] += up.x; - vrMatrix[matrix].M[1][3] += up.y; - vrMatrix[matrix].M[2][3] += up.z; + M[12] += up.x; + M[13] += up.y; + M[14] += up.z; } if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE)) > 0.0f) { XrVector3f side = {-VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE) * scale, 0.0f, 0.0f}; side = XrQuaternionf_Rotate(invView.orientation, side); side = XrVector3f_ScalarMultiply(side, vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f); - vrMatrix[matrix].M[0][3] += side.x; - vrMatrix[matrix].M[1][3] += side.y; - vrMatrix[matrix].M[2][3] += side.z; + M[12] += side.x; + M[13] += side.y; + M[14] += side.z; } if (vrConfig[VR_CONFIG_HAS_UNIT_SCALE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); @@ -379,10 +409,11 @@ bool VR_InitFrame( engine_t* engine ) { XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; separation = XrQuaternionf_Rotate(invView.orientation, separation); separation = XrVector3f_ScalarMultiply(separation, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - vrMatrix[matrix].M[0][3] -= separation.x; - vrMatrix[matrix].M[1][3] -= separation.y; - vrMatrix[matrix].M[2][3] -= separation.z; + M[12] -= separation.x; + M[13] -= separation.y; + M[14] -= separation.z; } + memcpy(vrMatrix[matrix], M, sizeof(float) * 16); } else { assert(false); } @@ -550,6 +581,6 @@ void* VR_BindFramebuffer(engine_t *engine) { return ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]); } -ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) { +float* VR_GetMatrix( VRMatrix matrix ) { return vrMatrix[matrix]; } diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index bd041ca366..3600aec081 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -67,4 +67,4 @@ float VR_GetConfigFloat( VRConfigFloat config ); void VR_SetConfigFloat( VRConfigFloat config, float value ); void* VR_BindFramebuffer(engine_t *engine); -ovrMatrix4f VR_GetMatrix( VRMatrix matrix ); +float* VR_GetMatrix( VRMatrix matrix ); From 5c9e6968a5142c94bbb4a1da78fab80d259471d2 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 6 Nov 2022 21:21:13 +0100 Subject: [PATCH 230/715] OpenXR - Get rid of separate projection matrices --- Common/VR/PPSSPPVR.cpp | 15 ++++++--------- Common/VR/VRRenderer.cpp | 36 ++++++++++++++++++------------------ Common/VR/VRRenderer.h | 3 +-- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index bce2f00227..a548eb452f 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -583,17 +583,14 @@ void UpdateVRParams(float* projMatrix) { } void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { - float* dst[] = {leftEye, rightEye}; - VRMatrix enums[] = {VR_PROJECTION_MATRIX_LEFT_EYE, VR_PROJECTION_MATRIX_RIGHT_EYE}; - for (int index = 0; index < 2; index++) { - float* hmdProjection = VR_GetMatrix(enums[index]); - for (int i = 0; i < 16; i++) { - if ((hmdProjection[i] > 0) != (projMatrix[i] > 0)) { - hmdProjection[i] *= -1.0f; - } + float* hmdProjection = VR_GetMatrix(VR_PROJECTION_MATRIX); + for (int i = 0; i < 16; i++) { + if ((hmdProjection[i] > 0) != (projMatrix[i] > 0)) { + hmdProjection[i] *= -1.0f; } - memcpy(dst[index], hmdProjection, 16 * sizeof(float)); } + memcpy(leftEye, hmdProjection, 16 * sizeof(float)); + memcpy(rightEye, hmdProjection, 16 * sizeof(float)); } void UpdateVRView(float* leftEye, float* rightEye) { diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index cbe69f2307..d06d12867e 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -305,34 +305,34 @@ bool VR_InitFrame( engine_t* engine ) { // Update matrices for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { - if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) { + if (matrix == VR_PROJECTION_MATRIX) { float nearZ = VR_GetConfigFloat(VR_CONFIG_FOV_SCALE) / 200.0f; float tanAngleLeft = tanf(fov.angleLeft); float tanAngleRight = tanf(fov.angleRight); float tanAngleDown = tanf(fov.angleDown); float tanAngleUp = tanf(fov.angleUp); - float M[4][4]; - M[0][0] = 2 / (tanAngleRight - tanAngleLeft); - M[0][1] = 0; - M[0][2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); - M[0][3] = 0; + float M[16]; + M[0] = 2 / (tanAngleRight - tanAngleLeft); + M[1] = 0; + M[2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); + M[3] = 0; - M[1][0] = 0; - M[1][1] = 2 / (tanAngleUp - tanAngleDown); - M[1][2] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); - M[1][3] = 0; + M[4] = 0; + M[5] = 2 / (tanAngleUp - tanAngleDown); + M[6] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); + M[7] = 0; // place the far plane at infinity - M[2][0] = 0; - M[2][1] = 0; - M[2][2] = -1; - M[2][3] = -(nearZ + nearZ); + M[8] = 0; + M[9] = 0; + M[10] = -1; + M[11] = -(nearZ + nearZ); - M[3][0] = 0; - M[3][1] = 0; - M[3][2] = -1; - M[3][3] = 0; + M[12] = 0; + M[13] = 0; + M[14] = -1; + M[15]= = 0; memcpy(vrMatrix[matrix], M, sizeof(float) * 16); } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 3600aec081..fed2a9acfc 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -37,8 +37,7 @@ enum VRConfigFloat { }; enum VRMatrix { - VR_PROJECTION_MATRIX_LEFT_EYE, - VR_PROJECTION_MATRIX_RIGHT_EYE, + VR_PROJECTION_MATRIX, VR_VIEW_MATRIX_LEFT_EYE, VR_VIEW_MATRIX_RIGHT_EYE, VR_MATRIX_COUNT From 520b92aa943c78a6cf68aee75cee75dde7d657a4 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 6 Nov 2022 21:45:47 +0100 Subject: [PATCH 231/715] OpenXR - Matrix indexing fixed --- Common/VR/VRRenderer.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index d06d12867e..ab63de0084 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -332,7 +332,7 @@ bool VR_InitFrame( engine_t* engine ) { M[12] = 0; M[13] = 0; M[14] = -1; - M[15]= = 0; + M[15] = 0; memcpy(vrMatrix[matrix], M, sizeof(float) * 16); } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { @@ -381,25 +381,25 @@ bool VR_InitFrame( engine_t* engine ) { XrVector3f forward = {0.0f, 0.0f, VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE) * scale}; forward = XrQuaternionf_Rotate(invView.orientation, forward); forward = XrVector3f_ScalarMultiply(forward, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - M[12] += forward.x; - M[13] += forward.y; - M[14] += forward.z; + M[3] += forward.x; + M[7] += forward.y; + M[11] += forward.z; } if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT)) > 0.0f) { XrVector3f up = {0.0f, -VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT) * scale, 0.0f}; up = XrQuaternionf_Rotate(invView.orientation, up); up = XrVector3f_ScalarMultiply(up, vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f); - M[12] += up.x; - M[13] += up.y; - M[14] += up.z; + M[3] += up.x; + M[7] += up.y; + M[11] += up.z; } if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE)) > 0.0f) { XrVector3f side = {-VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE) * scale, 0.0f, 0.0f}; side = XrQuaternionf_Rotate(invView.orientation, side); side = XrVector3f_ScalarMultiply(side, vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f); - M[12] += side.x; - M[13] += side.y; - M[14] += side.z; + M[3] += side.x; + M[7] += side.y; + M[11] += side.z; } if (vrConfig[VR_CONFIG_HAS_UNIT_SCALE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); @@ -409,9 +409,9 @@ bool VR_InitFrame( engine_t* engine ) { XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; separation = XrQuaternionf_Rotate(invView.orientation, separation); separation = XrVector3f_ScalarMultiply(separation, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - M[12] -= separation.x; - M[13] -= separation.y; - M[14] -= separation.z; + M[3] -= separation.x; + M[7] -= separation.y; + M[11] -= separation.z; } memcpy(vrMatrix[matrix], M, sizeof(float) * 16); } else { From cd54873edbd1236fef05e2f950ad0b687e7459bf Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 6 Nov 2022 21:48:55 +0100 Subject: [PATCH 232/715] OpenXR - Simplify projection matrix creation --- Common/VR/VRRenderer.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index ab63de0084..3a2ba7e6dd 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -312,27 +312,14 @@ bool VR_InitFrame( engine_t* engine ) { float tanAngleDown = tanf(fov.angleDown); float tanAngleUp = tanf(fov.angleUp); - float M[16]; + float M[16] = {}; M[0] = 2 / (tanAngleRight - tanAngleLeft); - M[1] = 0; M[2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); - M[3] = 0; - - M[4] = 0; M[5] = 2 / (tanAngleUp - tanAngleDown); M[6] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); - M[7] = 0; - - // place the far plane at infinity - M[8] = 0; - M[9] = 0; M[10] = -1; M[11] = -(nearZ + nearZ); - - M[12] = 0; - M[13] = 0; M[14] = -1; - M[15] = 0; memcpy(vrMatrix[matrix], M, sizeof(float) * 16); } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { From 460386e3444d5a2bfd1adc7c15bb3ad1c2a5cd39 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 6 Nov 2022 22:06:27 +0100 Subject: [PATCH 233/715] OpenXR - Move matrix calculation out of VRRenderer --- Common/VR/PPSSPPVR.cpp | 129 ++++++++++++++++++++++++++++++++++++++- Common/VR/VRRenderer.cpp | 110 +-------------------------------- Common/VR/VRRenderer.h | 10 +-- 3 files changed, 129 insertions(+), 120 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index a548eb452f..5e1ad3c6d8 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -16,7 +16,15 @@ #include "Core/KeyMap.h" #include "Core/System.h" +enum VRMatrix { + VR_PROJECTION_MATRIX, + VR_VIEW_MATRIX_LEFT_EYE, + VR_VIEW_MATRIX_RIGHT_EYE, + VR_MATRIX_COUNT +}; + static long vrCompat[VR_COMPAT_MAX]; +static float vrMatrix[VR_MATRIX_COUNT][16]; /* ================================================================================ @@ -420,6 +428,121 @@ bool StartVRRender() { if (VR_InitFrame(VR_GetEngine())) { + // Get OpenXR view and fov + XrFovf fov = {}; + XrPosef invViewTransform[2]; + for (int eye = 0; eye < ovrMaxNumEyes; eye++) { + XrView view = VR_GetView(eye); + fov.angleLeft += view.fov.angleLeft / 2.0f; + fov.angleRight += view.fov.angleRight / 2.0f; + fov.angleUp += view.fov.angleUp / 2.0f; + fov.angleDown += view.fov.angleDown / 2.0f; + invViewTransform[eye] = view.pose; + } + + // Update matrices + for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { + if (matrix == VR_PROJECTION_MATRIX) { + float nearZ = VR_GetConfigFloat(VR_CONFIG_FOV_SCALE) / 200.0f; + float tanAngleLeft = tanf(fov.angleLeft); + float tanAngleRight = tanf(fov.angleRight); + float tanAngleDown = tanf(fov.angleDown); + float tanAngleUp = tanf(fov.angleUp); + + float M[16] = {}; + M[0] = 2 / (tanAngleRight - tanAngleLeft); + M[2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); + M[5] = 2 / (tanAngleUp - tanAngleDown); + M[6] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); + M[10] = -1; + M[11] = -(nearZ + nearZ); + M[14] = -1; + + memcpy(vrMatrix[matrix], M, sizeof(float) * 16); + } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + bool flatScreen = false; + XrPosef invView = invViewTransform[0]; + int vrMode = VR_GetConfig(VR_CONFIG_MODE); + if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { + invView = XrPosef_Identity(); + flatScreen = true; + } + + // get axis mirroring configuration + float mx = VR_GetConfig(VR_CONFIG_MIRROR_PITCH) ? -1.0f : 1.0f; + float my = VR_GetConfig(VR_CONFIG_MIRROR_YAW) ? -1.0f : 1.0f; + float mz = VR_GetConfig(VR_CONFIG_MIRROR_ROLL) ? -1.0f : 1.0f; + + // ensure there is maximally one axis to mirror rotation + if (mx + my + mz < 0) { + mx *= -1.0f; + my *= -1.0f; + mz *= -1.0f; + } else { + invView = XrPosef_Inverse(invView); + } + + // create updated quaternion + if (mx + my + mz < 3 - EPSILON) { + XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); + XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); + XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); + XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); + invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); + } + + float M[16]; + XrQuaternionf_ToMatrix4f(&invView.orientation, M); + memcpy(&M, M, sizeof(float) * 16); + + float scale = VR_GetConfigFloat(VR_CONFIG_6DOF_SCALE); + if (!flatScreen && VR_GetConfig(VR_CONFIG_6DOF_ENABLED)) { + M[12] -= invViewTransform[0].position.x * (VR_GetConfig(VR_CONFIG_MIRROR_AXIS_X) ? -1.0f : 1.0f) * scale; + M[13] -= invViewTransform[0].position.y * (VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Y) ? -1.0f : 1.0f) * scale; + M[14] -= invViewTransform[0].position.z * (VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Z) ? -1.0f : 1.0f) * scale; + } + if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE)) > 0.0f) { + XrVector3f forward = {0.0f, 0.0f, VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE) * scale}; + forward = XrQuaternionf_Rotate(invView.orientation, forward); + forward = XrVector3f_ScalarMultiply(forward, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Z) ? -1.0f : 1.0f); + M[3] += forward.x; + M[7] += forward.y; + M[11] += forward.z; + } + if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT)) > 0.0f) { + XrVector3f up = {0.0f, -VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT) * scale, 0.0f}; + up = XrQuaternionf_Rotate(invView.orientation, up); + up = XrVector3f_ScalarMultiply(up, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Y) ? -1.0f : 1.0f); + M[3] += up.x; + M[7] += up.y; + M[11] += up.z; + } + if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE)) > 0.0f) { + XrVector3f side = {-VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE) * scale, 0.0f, 0.0f}; + side = XrQuaternionf_Rotate(invView.orientation, side); + side = XrVector3f_ScalarMultiply(side, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_X) ? -1.0f : 1.0f); + M[3] += side.x; + M[7] += side.y; + M[11] += side.z; + } + if (VR_GetConfig(VR_CONFIG_HAS_UNIT_SCALE) && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); + float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); + float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); + float ipd = sqrt(dx * dx + dy * dy + dz * dz); + XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; + separation = XrQuaternionf_Rotate(invView.orientation, separation); + separation = XrVector3f_ScalarMultiply(separation, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Z) ? -1.0f : 1.0f); + M[3] -= separation.x; + M[7] -= separation.y; + M[11] -= separation.z; + } + memcpy(vrMatrix[matrix], M, sizeof(float) * 16); + } else { + assert(false); + } + } + // Decide if the scene is 3D or not if (g_Config.bEnableVR && !VR_GetConfig(VR_CONFIG_FORCE_2D) && (VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) > 15)) { bool stereo = VR_GetConfig(VR_CONFIG_HAS_UNIT_SCALE) && g_Config.bEnableStereo; @@ -583,7 +706,7 @@ void UpdateVRParams(float* projMatrix) { } void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { - float* hmdProjection = VR_GetMatrix(VR_PROJECTION_MATRIX); + float* hmdProjection = vrMatrix[VR_PROJECTION_MATRIX]; for (int i = 0; i < 16; i++) { if ((hmdProjection[i] > 0) != (projMatrix[i] > 0)) { hmdProjection[i] *= -1.0f; @@ -595,7 +718,7 @@ void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { void UpdateVRView(float* leftEye, float* rightEye) { float* dst[] = {leftEye, rightEye}; - VRMatrix enums[] = {VR_VIEW_MATRIX_LEFT_EYE, VR_VIEW_MATRIX_RIGHT_EYE}; + float* matrix[] = {vrMatrix[VR_VIEW_MATRIX_LEFT_EYE], vrMatrix[VR_VIEW_MATRIX_RIGHT_EYE]}; for (int index = 0; index < 2; index++) { // Get view matrix from the game @@ -604,7 +727,7 @@ void UpdateVRView(float* leftEye, float* rightEye) { // Get view matrix from the headset Lin::Matrix4x4 hmdView = {}; - memcpy(hmdView.m, VR_GetMatrix(enums[index]), 16 * sizeof(float)); + memcpy(hmdView.m, matrix[index], 16 * sizeof(float)); // Combine the matrices Lin::Matrix4x4 renderView = hmdView * gameView; diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 3a2ba7e6dd..a40d29f12a 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -16,12 +16,10 @@ XrPosef invViewTransform[2]; XrFrameState frameState = {}; bool initialized = false; bool stageSupported = false; -float vrMatrix[VR_MATRIX_COUNT][16]; int vrConfig[VR_CONFIG_MAX] = {}; float vrConfigFloat[VR_CONFIG_FLOAT_MAX] = {}; XrVector3f hmdorientation; -XrVector3f hmdposition; void VR_UpdateStageBounds(ovrApp* pappState) { XrExtent2Df stageBounds = {}; @@ -297,114 +295,10 @@ bool VR_InitFrame( engine_t* engine ) { // Update HMD and controllers hmdorientation = XrQuaternionf_ToEulerAngles(invViewTransform[0].orientation); - hmdposition = invViewTransform[0].position; IN_VRInputFrame(engine); engine->appState.LayerCount = 0; memset(engine->appState.Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount); - - // Update matrices - for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { - if (matrix == VR_PROJECTION_MATRIX) { - float nearZ = VR_GetConfigFloat(VR_CONFIG_FOV_SCALE) / 200.0f; - float tanAngleLeft = tanf(fov.angleLeft); - float tanAngleRight = tanf(fov.angleRight); - float tanAngleDown = tanf(fov.angleDown); - float tanAngleUp = tanf(fov.angleUp); - - float M[16] = {}; - M[0] = 2 / (tanAngleRight - tanAngleLeft); - M[2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); - M[5] = 2 / (tanAngleUp - tanAngleDown); - M[6] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); - M[10] = -1; - M[11] = -(nearZ + nearZ); - M[14] = -1; - - memcpy(vrMatrix[matrix], M, sizeof(float) * 16); - } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { - bool flatScreen = false; - XrPosef invView = invViewTransform[0]; - int vrMode = vrConfig[VR_CONFIG_MODE]; - if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { - invView = XrPosef_Identity(); - flatScreen = true; - } - - // get axis mirroring configuration - float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1.0f : 1.0f; - float my = vrConfig[VR_CONFIG_MIRROR_YAW] ? -1.0f : 1.0f; - float mz = vrConfig[VR_CONFIG_MIRROR_ROLL] ? -1.0f : 1.0f; - - // ensure there is maximally one axis to mirror rotation - if (mx + my + mz < 0) { - mx *= -1.0f; - my *= -1.0f; - mz *= -1.0f; - } else { - invView = XrPosef_Inverse(invView); - } - - // create updated quaternion - if (mx + my + mz < 3 - EPSILON) { - XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); - XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); - XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); - XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); - invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); - } - - float M[16]; - XrQuaternionf_ToMatrix4f(&invView.orientation, M); - memcpy(&M, M, sizeof(float) * 16); - - float scale = VR_GetConfigFloat(VR_CONFIG_6DOF_SCALE); - if (!flatScreen && vrConfig[VR_CONFIG_6DOF_ENABLED]) { - M[12] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; - M[13] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; - M[14] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; - } - if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE)) > 0.0f) { - XrVector3f forward = {0.0f, 0.0f, VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE) * scale}; - forward = XrQuaternionf_Rotate(invView.orientation, forward); - forward = XrVector3f_ScalarMultiply(forward, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - M[3] += forward.x; - M[7] += forward.y; - M[11] += forward.z; - } - if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT)) > 0.0f) { - XrVector3f up = {0.0f, -VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT) * scale, 0.0f}; - up = XrQuaternionf_Rotate(invView.orientation, up); - up = XrVector3f_ScalarMultiply(up, vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f); - M[3] += up.x; - M[7] += up.y; - M[11] += up.z; - } - if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE)) > 0.0f) { - XrVector3f side = {-VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE) * scale, 0.0f, 0.0f}; - side = XrQuaternionf_Rotate(invView.orientation, side); - side = XrVector3f_ScalarMultiply(side, vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f); - M[3] += side.x; - M[7] += side.y; - M[11] += side.z; - } - if (vrConfig[VR_CONFIG_HAS_UNIT_SCALE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { - float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); - float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); - float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); - float ipd = sqrt(dx * dx + dy * dy + dz * dz); - XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; - separation = XrQuaternionf_Rotate(invView.orientation, separation); - separation = XrVector3f_ScalarMultiply(separation, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - M[3] -= separation.x; - M[7] -= separation.y; - M[11] -= separation.z; - } - memcpy(vrMatrix[matrix], M, sizeof(float) * 16); - } else { - assert(false); - } - } return true; } @@ -568,6 +462,6 @@ void* VR_BindFramebuffer(engine_t *engine) { return ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]); } -float* VR_GetMatrix( VRMatrix matrix ) { - return vrMatrix[matrix]; +XrView VR_GetView(int eye) { + return projections[eye]; } diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index fed2a9acfc..d05e4b90b1 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -36,13 +36,6 @@ enum VRConfigFloat { VR_CONFIG_FLOAT_MAX }; -enum VRMatrix { - VR_PROJECTION_MATRIX, - VR_VIEW_MATRIX_LEFT_EYE, - VR_VIEW_MATRIX_RIGHT_EYE, - VR_MATRIX_COUNT -}; - enum VRMode { VR_MODE_MONO_SCREEN, VR_MODE_STEREO_SCREEN, @@ -61,9 +54,8 @@ void VR_FinishFrame( engine_t* engine ); int VR_GetConfig( VRConfig config ); void VR_SetConfig( VRConfig config, int value); - float VR_GetConfigFloat( VRConfigFloat config ); void VR_SetConfigFloat( VRConfigFloat config, float value ); void* VR_BindFramebuffer(engine_t *engine); -float* VR_GetMatrix( VRMatrix matrix ); +XrView VR_GetView(int eye); From c58359a3b39ffd1380306c22f2afa4445cd0a928 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 6 Nov 2022 22:30:35 +0100 Subject: [PATCH 234/715] OpenXR - Move configs out of VRRenderer --- Common/VR/PPSSPPVR.cpp | 137 ++++++++++++++++++++++------------------- Common/VR/VRRenderer.h | 16 +---- 2 files changed, 76 insertions(+), 77 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 5e1ad3c6d8..3b46301036 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -23,8 +23,23 @@ enum VRMatrix { VR_MATRIX_COUNT }; +enum VRMirroring { + VR_MIRRORING_UPDATED, + VR_MIRRORING_AXIS_X, + VR_MIRRORING_AXIS_Y, + VR_MIRRORING_AXIS_Z, + VR_MIRRORING_PITCH, + VR_MIRRORING_YAW, + VR_MIRRORING_ROLL, + VR_MIRRORING_COUNT +}; + +static int vr3DGeometryCount = 0; +static bool vrCameraControl = false; +static bool vrForce2D = false; static long vrCompat[VR_COMPAT_MAX]; static float vrMatrix[VR_MATRIX_COUNT][16]; +static bool vrMirroring[VR_MIRRORING_COUNT]; /* ================================================================================ @@ -182,7 +197,6 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con KeyInput keyInput = {}; for (int j = 0; j < 2; j++) { int status = IN_VRGetButtonState(j); - bool cameraControl = VR_GetConfig(VR_CONFIG_CAMERA_CONTROL); for (ButtonMapping& m : controllerMapping[j]) { //check if camera key was pressed @@ -208,14 +222,14 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con if (pressed && haptics) { INVR_Vibrate(100, j, 1000); } - if (!cameraControl || cameraKey) { + if (!vrCameraControl || cameraKey) { NativeKey(keyInput); } m.pressed = pressed; m.repeat = 0; } else if (pressed && (m.repeat > 30)) { keyInput.flags |= KEY_IS_REPEAT; - if (!cameraControl || cameraKey) { + if (!vrCameraControl || cameraKey) { NativeKey(keyInput); } m.repeat = 0; @@ -331,11 +345,11 @@ void UpdateVRSpecialKeys(const KeyInput &key) { for (int& nativeKey : nativeKeys) { // adjust camera parameters if (nativeKey == VIRTKEY_VR_CAMERA_ADJUST) { - VR_SetConfig(VR_CONFIG_CAMERA_CONTROL, key.flags & KEY_DOWN); + vrCameraControl = key.flags & KEY_DOWN; } // force 2D rendering else if (nativeKey == CTRL_SCREEN) { - VR_SetConfig(VR_CONFIG_FORCE_2D, key.flags & KEY_DOWN); + vrForce2D = key.flags & KEY_DOWN; } } } @@ -440,10 +454,18 @@ bool StartVRRender() { invViewTransform[eye] = view.pose; } + // Get 6DoF scale + float scale = 1.0f; + bool hasUnitScale = false; + if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) { + scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter; + hasUnitScale = true; + } + // Update matrices for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { if (matrix == VR_PROJECTION_MATRIX) { - float nearZ = VR_GetConfigFloat(VR_CONFIG_FOV_SCALE) / 200.0f; + float nearZ = g_Config.fFieldOfViewPercentage / 200.0f; float tanAngleLeft = tanf(fov.angleLeft); float tanAngleRight = tanf(fov.angleRight); float tanAngleDown = tanf(fov.angleDown); @@ -469,9 +491,9 @@ bool StartVRRender() { } // get axis mirroring configuration - float mx = VR_GetConfig(VR_CONFIG_MIRROR_PITCH) ? -1.0f : 1.0f; - float my = VR_GetConfig(VR_CONFIG_MIRROR_YAW) ? -1.0f : 1.0f; - float mz = VR_GetConfig(VR_CONFIG_MIRROR_ROLL) ? -1.0f : 1.0f; + float mx = vrMirroring[VR_MIRRORING_PITCH] ? -1.0f : 1.0f; + float my = vrMirroring[VR_MIRRORING_YAW] ? -1.0f : 1.0f; + float mz = vrMirroring[VR_MIRRORING_ROLL] ? -1.0f : 1.0f; // ensure there is maximally one axis to mirror rotation if (mx + my + mz < 0) { @@ -495,44 +517,48 @@ bool StartVRRender() { XrQuaternionf_ToMatrix4f(&invView.orientation, M); memcpy(&M, M, sizeof(float) * 16); - float scale = VR_GetConfigFloat(VR_CONFIG_6DOF_SCALE); - if (!flatScreen && VR_GetConfig(VR_CONFIG_6DOF_ENABLED)) { - M[12] -= invViewTransform[0].position.x * (VR_GetConfig(VR_CONFIG_MIRROR_AXIS_X) ? -1.0f : 1.0f) * scale; - M[13] -= invViewTransform[0].position.y * (VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Y) ? -1.0f : 1.0f) * scale; - M[14] -= invViewTransform[0].position.z * (VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Z) ? -1.0f : 1.0f) * scale; + // Apply 6Dof head movement + if (!flatScreen && g_Config.bEnable6DoF) { + M[3] -= invViewTransform[0].position.x * (vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f) * scale; + M[7] -= invViewTransform[0].position.y * (vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f) * scale; + M[11] -= invViewTransform[0].position.z * (vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f) * scale; } - if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE)) > 0.0f) { - XrVector3f forward = {0.0f, 0.0f, VR_GetConfigFloat(VR_CONFIG_CAMERA_DISTANCE) * scale}; + // Camera adjust - distance + if (fabsf(g_Config.fCameraDistance) > 0.0f) { + XrVector3f forward = {0.0f, 0.0f, g_Config.fCameraDistance * scale}; forward = XrQuaternionf_Rotate(invView.orientation, forward); - forward = XrVector3f_ScalarMultiply(forward, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Z) ? -1.0f : 1.0f); + forward = XrVector3f_ScalarMultiply(forward, vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f); M[3] += forward.x; M[7] += forward.y; M[11] += forward.z; } - if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT)) > 0.0f) { - XrVector3f up = {0.0f, -VR_GetConfigFloat(VR_CONFIG_CAMERA_HEIGHT) * scale, 0.0f}; + // Camera adjust - height + if (fabsf(g_Config.fCameraHeight) > 0.0f) { + XrVector3f up = {0.0f, -g_Config.fCameraHeight * scale, 0.0f}; up = XrQuaternionf_Rotate(invView.orientation, up); - up = XrVector3f_ScalarMultiply(up, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Y) ? -1.0f : 1.0f); + up = XrVector3f_ScalarMultiply(up, vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f); M[3] += up.x; M[7] += up.y; M[11] += up.z; } - if (fabsf(VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE)) > 0.0f) { - XrVector3f side = {-VR_GetConfigFloat(VR_CONFIG_CAMERA_SIDE) * scale, 0.0f, 0.0f}; + // Camera adjust - side + if (fabsf(g_Config.fCameraSide) > 0.0f) { + XrVector3f side = {-g_Config.fCameraSide * scale, 0.0f, 0.0f}; side = XrQuaternionf_Rotate(invView.orientation, side); - side = XrVector3f_ScalarMultiply(side, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_X) ? -1.0f : 1.0f); + side = XrVector3f_ScalarMultiply(side, vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f); M[3] += side.x; M[7] += side.y; M[11] += side.z; } - if (VR_GetConfig(VR_CONFIG_HAS_UNIT_SCALE) && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + // Stereoscopy + if (hasUnitScale && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); float ipd = sqrt(dx * dx + dy * dy + dz * dz); XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; separation = XrQuaternionf_Rotate(invView.orientation, separation); - separation = XrVector3f_ScalarMultiply(separation, VR_GetConfig(VR_CONFIG_MIRROR_AXIS_Z) ? -1.0f : 1.0f); + separation = XrVector3f_ScalarMultiply(separation, vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f); M[3] -= separation.x; M[7] -= separation.y; M[11] -= separation.z; @@ -544,19 +570,19 @@ bool StartVRRender() { } // Decide if the scene is 3D or not - if (g_Config.bEnableVR && !VR_GetConfig(VR_CONFIG_FORCE_2D) && (VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) > 15)) { - bool stereo = VR_GetConfig(VR_CONFIG_HAS_UNIT_SCALE) && g_Config.bEnableStereo; + if (g_Config.bEnableVR && !vrForce2D && (vr3DGeometryCount > 15)) { + bool stereo = hasUnitScale && g_Config.bEnableStereo; VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); } else { VR_SetConfig(VR_CONFIG_MODE, g_Config.bEnableStereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); } - VR_SetConfig(VR_CONFIG_3D_GEOMETRY_COUNT, VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) / 2); + vr3DGeometryCount /= 2; // Set compatibility vrCompat[VR_COMPAT_SKYPLANE] = PSP_CoreParameter().compat.vrCompat().Skyplane; // Camera control - if (VR_GetConfig(VR_CONFIG_CAMERA_CONTROL)) { + if (vrCameraControl) { //left joystick controls height and side float height = g_Config.fCameraHeight; float side = g_Config.fCameraSide; @@ -590,13 +616,8 @@ bool StartVRRender() { // Set customizations __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); - VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); - VR_SetConfigFloat(VR_CONFIG_CAMERA_DISTANCE, g_Config.fCameraDistance); - VR_SetConfigFloat(VR_CONFIG_CAMERA_HEIGHT, g_Config.fCameraHeight); - VR_SetConfigFloat(VR_CONFIG_CAMERA_SIDE, g_Config.fCameraSide); VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); - VR_SetConfigFloat(VR_CONFIG_FOV_SCALE, g_Config.fFieldOfViewPercentage); - VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, false); + vrMirroring[VR_MIRRORING_UPDATED] = false; return true; } return false; @@ -662,7 +683,7 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { // Update 3D geometry count if (!identity && !ortho) { - VR_SetConfig(VR_CONFIG_3D_GEOMETRY_COUNT, VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) + 1); + vr3DGeometryCount++; } return identity; } @@ -670,39 +691,29 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { void UpdateVRParams(float* projMatrix) { // Set mirroring of axes - if (!VR_GetConfig(VR_CONFIG_MIRROR_UPDATED)) { - VR_SetConfig(VR_CONFIG_MIRROR_UPDATED, true); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_X, projMatrix[0] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Y, projMatrix[5] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Z, projMatrix[10] > 0); + if (!vrMirroring[VR_MIRRORING_UPDATED]) { + vrMirroring[VR_MIRRORING_UPDATED] = true; + vrMirroring[VR_MIRRORING_AXIS_X] = projMatrix[0] < 0; + vrMirroring[VR_MIRRORING_AXIS_Y] = projMatrix[5] < 0; + vrMirroring[VR_MIRRORING_AXIS_Z] = projMatrix[10] > 0; if ((projMatrix[0] < 0) && (projMatrix[10] < 0)) { //e.g. Dante's inferno - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + vrMirroring[VR_MIRRORING_PITCH] = true; + vrMirroring[VR_MIRRORING_YAW] = true; + vrMirroring[VR_MIRRORING_ROLL] = false; } else if (projMatrix[10] < 0) { //e.g. GTA - Liberty city - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, false); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + vrMirroring[VR_MIRRORING_PITCH] = false; + vrMirroring[VR_MIRRORING_YAW] = false; + vrMirroring[VR_MIRRORING_ROLL] = false; } else if (projMatrix[5] < 0) { //e.g. PES 2014 - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); + vrMirroring[VR_MIRRORING_PITCH] = true; + vrMirroring[VR_MIRRORING_YAW] = true; + vrMirroring[VR_MIRRORING_ROLL] = false; } else { //e.g. Lego Pirates - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, true); + vrMirroring[VR_MIRRORING_PITCH] = false; + vrMirroring[VR_MIRRORING_YAW] = true; + vrMirroring[VR_MIRRORING_ROLL] = true; } } - - // Set 6DoF scale - float scale = 1.0f; - if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) { - scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter; - VR_SetConfig(VR_CONFIG_HAS_UNIT_SCALE, true); - } else { - VR_SetConfig(VR_CONFIG_HAS_UNIT_SCALE, false); - } - VR_SetConfigFloat(VR_CONFIG_6DOF_SCALE, scale); } void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index d05e4b90b1..dcd57f1f4b 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -5,14 +5,7 @@ enum VRConfig { //switching between 2D and 3D - VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, - //camera setup - VR_CONFIG_CAMERA_CONTROL, - VR_CONFIG_HAS_UNIT_SCALE, - //6DoF - VR_CONFIG_6DOF_ENABLED, VR_CONFIG_MIRROR_UPDATED, - VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, - VR_CONFIG_MIRROR_PITCH, VR_CONFIG_MIRROR_YAW, VR_CONFIG_MIRROR_ROLL, + VR_CONFIG_MODE, //mouse cursor VR_CONFIG_MOUSE_SIZE, VR_CONFIG_MOUSE_X, VR_CONFIG_MOUSE_Y, //viewport setup @@ -25,13 +18,8 @@ enum VRConfig { }; enum VRConfigFloat { - // 6dof - VR_CONFIG_6DOF_SCALE, - // camera setup - VR_CONFIG_FOV_SCALE, VR_CONFIG_CAMERA_DISTANCE, - VR_CONFIG_CAMERA_HEIGHT, VR_CONFIG_CAMERA_SIDE, VR_CONFIG_CANVAS_DISTANCE, // 2D canvas positioning - VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, + VR_CONFIG_CANVAS_DISTANCE, VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, VR_CONFIG_FLOAT_MAX }; From e96b9b4649b71fb2ba6811b1880cc8763319c587 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 6 Nov 2022 22:38:15 +0100 Subject: [PATCH 235/715] Remove unnecessary assert --- Common/VR/PPSSPPVR.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 3b46301036..eb011c6c07 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -564,8 +564,6 @@ bool StartVRRender() { M[11] -= separation.z; } memcpy(vrMatrix[matrix], M, sizeof(float) * 16); - } else { - assert(false); } } From 24451bb45d0be1eba25bd616612194d60f03a3a4 Mon Sep 17 00:00:00 2001 From: xujibbs <79200793+xujibbs@users.noreply.github.com> Date: Mon, 7 Nov 2022 12:34:27 +0800 Subject: [PATCH 236/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 7b1f77592f..f51aa2c856 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -550,7 +550,7 @@ Software Rendering = 软件渲染(慢) Software Skinning = 软件蒙皮 SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快 Speed = 运行速度 -Speed Hacks = Speed Hacks (可能引发故障) +Speed Hacks = 速度修正 (可能引发故障) Stretching = 拉伸 Texture Filter = 纹理过滤方式 Texture Filtering = 纹理过滤 From 1c356c5ae461a014ab4305181da0ef44b712d036 Mon Sep 17 00:00:00 2001 From: xujibbs <79200793+xujibbs@users.noreply.github.com> Date: Mon, 7 Nov 2022 12:35:57 +0800 Subject: [PATCH 237/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 4ae22d488f..444d6be346 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -549,7 +549,7 @@ Software Rendering = 軟體轉譯 (慢) Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 -Speed Hacks = Speed Hacks (可能會造成故障) +Speed Hacks = 速度修正 (可能會造成故障) Stretching = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 From 668904a5154ec788ccd828fd90d4b126da2e6e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 09:14:55 +0100 Subject: [PATCH 238/715] Vulkan: Use the very same view as input attachment and color attachment, not just the same image Fixes most of the new validation errors seen #16351, though one remains. I believe that to be a bug in the validation layers, will investigate later. --- Common/GPU/Vulkan/VulkanDebug.cpp | 5 +++++ Common/GPU/Vulkan/thin3d_vulkan.cpp | 7 ++----- Common/GPU/thin3d.h | 2 +- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp index 83b3d974c0..d3c018bfea 100644 --- a/Common/GPU/Vulkan/VulkanDebug.cpp +++ b/Common/GPU/Vulkan/VulkanDebug.cpp @@ -42,6 +42,11 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( // UNASSIGNED return false; } + if (messageCode == 606910136) { + // VUID-vkCmdDraw-None-02686 + // Seems to be a bug in the validation layers, in the check that the input attachment is bound to a descriptor. + return false; + } if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { message << "ERROR("; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 97e6a6c80a..167175be95 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1703,11 +1703,8 @@ uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) { return (uint64_t)(((VKTexture *)srcObject)->GetImageView()); case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS: return (uint64_t)curFramebuffer_->GetFB()->color.texAllLayersView; - case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_LAYER: { - size_t layer = (size_t)srcObject; - _dbg_assert_(layer < curFramebuffer_->Layers()); - return (uint64_t)curFramebuffer_->GetFB()->color.texLayerViews[layer]; - } + case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT: + return (uint64_t)curFramebuffer_->GetFB()->color.rtView; case NativeObject::FRAME_DATA_DESC_SET_LAYOUT: return (uint64_t)frameDescSetLayout_; case NativeObject::THIN3D_PIPELINE_LAYOUT: diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 7a2c012f89..53d35250ce 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -245,7 +245,7 @@ enum class NativeObject { BOUND_TEXTURE0_IMAGEVIEW, // Layer etc depends on how you bound it... BOUND_TEXTURE1_IMAGEVIEW, // Layer etc depends on how you bound it... BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS, - BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_LAYER, // use an int cast to void *srcObject to specify layer. + BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT, RENDER_MANAGER, TEXTURE_VIEW, NULL_IMAGEVIEW, diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 4e877d335a..b440f975d6 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -377,7 +377,7 @@ void DrawEngineVulkan::BindShaderBlendTex() { dirtyRequiresRecheck_ |= DIRTY_BLEND_STATE; } else if (fboTexBindState_ == FBO_TEX_READ_FRAMEBUFFER) { draw_->BindCurrentFramebufferForColorInput(); - boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_LAYER, (void *)0); + boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT, (void *)0); boundSecondaryIsInputAttachment_ = true; fboTexBindState_ = FBO_TEX_NONE; } else { From ad14d628b603b950b0c3dea40126649ce84fb9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 09:30:47 +0100 Subject: [PATCH 239/715] Turn off boundSecondaryIsInputAttachment_ when we don't have one. --- GPU/Vulkan/StateMappingVulkan.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index b440f975d6..9e2177b901 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -381,6 +381,7 @@ void DrawEngineVulkan::BindShaderBlendTex() { boundSecondaryIsInputAttachment_ = true; fboTexBindState_ = FBO_TEX_NONE; } else { + boundSecondaryIsInputAttachment_ = false; boundSecondary_ = VK_NULL_HANDLE; } } From c7db9a865d0ed3c395e01c2d324e95dec8ddcf16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 09:50:47 +0100 Subject: [PATCH 240/715] Disable remaining false positive. --- Common/GPU/Vulkan/VulkanDebug.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp index d3c018bfea..12bd0f4d6f 100644 --- a/Common/GPU/Vulkan/VulkanDebug.cpp +++ b/Common/GPU/Vulkan/VulkanDebug.cpp @@ -42,9 +42,10 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( // UNASSIGNED return false; } - if (messageCode == 606910136) { + if (messageCode == 606910136 || messageCode == -392708513) { // VUID-vkCmdDraw-None-02686 - // Seems to be a bug in the validation layers, in the check that the input attachment is bound to a descriptor. + // Kinda false positive, or at least very unnecessary, now that I solved the real issue. + // See https://github.com/hrydgard/ppsspp/pull/16354 return false; } From 90075040e95d72db59fdf50ebe858e3928f66127 Mon Sep 17 00:00:00 2001 From: gucio321 Date: Mon, 7 Nov 2022 13:45:02 +0100 Subject: [PATCH 241/715] pl: fix some typos --- assets/lang/pl_PL.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 9617f88cb9..b3a1c12d25 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -224,14 +224,14 @@ Allow remote debugger = Zezwól na zdalne debugowanie Backspace = Backspace Block address = Adres bloku By Address = Po adresie -Copy savestates to memstick root = Skopjuj zapisane stany do folderu głównego Karty Pamięci +Copy savestates to memstick root = Skopiuj zapisane stany do folderu głównego Karty Pamięci Create/Open textures.ini file for current game = Stwórz/otwórz plik textures.ini z bieżącej gry Current = Obecny Dev Tools = Narzędzia Developerskie DevMenu = DevMenu Disabled JIT functionality = Wyłącz funkcje JIT Draw Frametimes Graph = Draw frametimes graph -Dump Decrypted Eboot = Zachowuj odszyfrowany EBOOT.BIN przy starcieSkopjuj zapisane stany do folderu głównego Karty Pamięci +Dump Decrypted Eboot = Zachowuj odszyfrowany EBOOT.BIN przy starcie Dump Frame GPU Commands = Zrzuć klatkę komend GPU Enable driver bug workarounds = Uruchom obejścia błędów sterownika Enable Logging = Włącz dziennik zdarzeń debugera From 24d5cd087c3561537126fdebbe757613b7927e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 14:30:24 +0100 Subject: [PATCH 242/715] Experiment (Vulkan): Temporarily disable GLSL parallel compilation on Android. For #16341 investigation. --- GPU/Vulkan/ShaderManagerVulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 1d478325da..4879e58230 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -25,6 +25,7 @@ #include "Common/Profiler/Profiler.h" #include "Common/GPU/thin3d.h" #include "Common/Data/Encoding/Utf8.h" +#include "Common/TimeUtil.h" #include "Common/StringUtils.h" #include "Common/GPU/Vulkan/VulkanContext.h" @@ -92,11 +93,10 @@ static Promise *CompileShaderModuleAsync(VulkanContext *vulkan, if (tag) delete tag; } - return shaderModule; }; -#ifdef _DEBUG +#if defined(_DEBUG) || PPSSPP_PLATFORM(ANDROID) // Don't parallelize in debug mode, pathological behavior due to mutex locks in allocator which is HEAVILY used by glslang. return Promise::AlreadyDone(compile()); #else From 73ccff9ba00cdc3d3de5a83a438d36aec017a787 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Nov 2022 16:28:41 +0100 Subject: [PATCH 243/715] Restore assert --- Common/VR/PPSSPPVR.cpp | 2 ++ Common/VR/VRBase.h | 1 + Common/VR/VRRenderer.cpp | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index eb011c6c07..3b46301036 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -564,6 +564,8 @@ bool StartVRRender() { M[11] -= separation.z; } memcpy(vrMatrix[matrix], M, sizeof(float) * 16); + } else { + assert(false); } } diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 34e52908d4..395858b136 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -14,6 +14,7 @@ #define _USE_MATH_DEFINES #include +#include #ifdef ANDROID diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index a40d29f12a..78133a26a2 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -6,7 +6,6 @@ #include "VRRenderer.h" #include "OpenXRLoader.h" -#include #include #include From 90d117ce7199bbddeaf397beff6aac5651ef5f65 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Nov 2022 16:46:10 +0100 Subject: [PATCH 244/715] OpenXR - Keep status of PSP keys --- Common/VR/PPSSPPVR.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 3b46301036..73fb91f6aa 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -34,9 +34,9 @@ enum VRMirroring { VR_MIRRORING_COUNT }; +static std::map pspKeys; + static int vr3DGeometryCount = 0; -static bool vrCameraControl = false; -static bool vrForce2D = false; static long vrCompat[VR_COMPAT_MAX]; static float vrMatrix[VR_MATRIX_COUNT][16]; static bool vrMirroring[VR_MIRRORING_COUNT]; @@ -222,14 +222,14 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con if (pressed && haptics) { INVR_Vibrate(100, j, 1000); } - if (!vrCameraControl || cameraKey) { + if (!pspKeys[VIRTKEY_VR_CAMERA_ADJUST] || cameraKey) { NativeKey(keyInput); } m.pressed = pressed; m.repeat = 0; } else if (pressed && (m.repeat > 30)) { keyInput.flags |= KEY_IS_REPEAT; - if (!vrCameraControl || cameraKey) { + if (!pspKeys[VIRTKEY_VR_CAMERA_ADJUST] || cameraKey) { NativeKey(keyInput); } m.repeat = 0; @@ -343,14 +343,7 @@ void UpdateVRSpecialKeys(const KeyInput &key) { std::vector nativeKeys; if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { - // adjust camera parameters - if (nativeKey == VIRTKEY_VR_CAMERA_ADJUST) { - vrCameraControl = key.flags & KEY_DOWN; - } - // force 2D rendering - else if (nativeKey == CTRL_SCREEN) { - vrForce2D = key.flags & KEY_DOWN; - } + pspKeys[nativeKey] = key.flags & KEY_DOWN; } } } @@ -570,7 +563,7 @@ bool StartVRRender() { } // Decide if the scene is 3D or not - if (g_Config.bEnableVR && !vrForce2D && (vr3DGeometryCount > 15)) { + if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (vr3DGeometryCount > 15)) { bool stereo = hasUnitScale && g_Config.bEnableStereo; VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); } else { @@ -582,7 +575,7 @@ bool StartVRRender() { vrCompat[VR_COMPAT_SKYPLANE] = PSP_CoreParameter().compat.vrCompat().Skyplane; // Camera control - if (vrCameraControl) { + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { //left joystick controls height and side float height = g_Config.fCameraHeight; float side = g_Config.fCameraSide; From ed3a30aa1f006cbfbf50a67292cae1735c90b85a Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Mon, 7 Nov 2022 16:54:46 +0100 Subject: [PATCH 245/715] pl: update analog stick translation --- assets/lang/pl_PL.ini | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index b3a1c12d25..ac61505c92 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -18,14 +18,14 @@ Use global volume = Używaj głośności globalnej WASAPI (fast) = WASAPI (szybki) [Controls] -Analog Binding = Połączenie Gałki Analogowej -Analog Limiter = Ogranicznik Gałki Analogowej -Analog Settings = Ustawienia Gałki Analogowej -Analog Stick = Gałka analogowa -Analog Style = Styl Gałki Analogowej -AnalogLimiter Tip = Jeśli "ogranicznik Gałki Analogowej" jest aktywny +Analog Binding = Powiązanie Analoga +Analog Limiter = Ogranicznik Analoga +Analog Settings = Ustawienia Analoga +Analog Stick = Gałka Analogowa +Analog Style = Styl Analoga +AnalogLimiter Tip = Jeśli "ogranicznik Analoga" jest aktywny Auto = Automatyczny -Auto-centering analog stick = Autocentrowanie gałki analogowej +Auto-centering analog stick = Autocentrowanie analoga Auto-hide buttons after seconds = Automatyczne ukrywanie przycisków po: Auto-rotation speed = Prędkość automatycznego obracania Auto-switch = Auto-switch @@ -34,7 +34,7 @@ Binds = Powiązania Button Binding = Konfiguracja przycisków Button Opacity = Przeźroczystość przycisków Button style = Styl przycisków -Calibrate Analog Stick = Kalibracja Gałki Analogowej +Calibrate Analog Stick = Kalibracja Analoga Calibrate D-Pad = Kalibracja krzyżaka Calibrated = Skalibrowany Calibration = Kalibracja @@ -57,7 +57,7 @@ Gesture = Gesty Gesture mapping = Konfiguracja gestów Glowing borders = Świecące krawędzie HapticFeedback = Wibracje -Hide touch analog stick background circle = Ukryj obszar zasięgu Gałki Analogowej +Hide touch analog stick background circle = Ukryj obszar zasięgu Analoga Icon = Ikona Ignore gamepads when not focused = Ignoruj przyciski pada gdy okno nieaktywne Ignore Windows Key = Ignoruj klawisz Windows @@ -682,7 +682,7 @@ Record = Record Remote hold = Remote hold Rewind = Przewiń do tyłu Right = Strzałka w prawo -Right Analog Stick = Right Analog Stick +Right Analog Stick = Prawa Gałka Analogowa RightAn.Down = Pr. gałk. w dół RightAn.Left = Pr. gałk. w lewo RightAn.Right = Pr. gałk. w prawo From bd56b992eed06a794eb2e0c7c5ae01bd5afcbfab Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Mon, 7 Nov 2022 16:59:05 +0100 Subject: [PATCH 246/715] pl: fix typo --- assets/lang/pl_PL.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index ac61505c92..2bb8ee973f 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -367,8 +367,8 @@ Failed initializing CPU/Memory = Nie można zainicjować CPU lub pamięci Failed to load executable: = Nie udało się uruchomić pliku wykonywalnego: File corrupt = Uszkodzony plik Game disc read error - ISO corrupt = Nie można odczytać danych z dysku - plik ISO uszkodzony. -GenericAllStartupError = PPSSPP nie może uruchomić żadnego trybu grafiki. Sprubuj zaktualizować swoje sterowniki do karty graficznej (oraz pozostałe). -GenericBackendSwitchCrash = PPSSPP - wystąpił błąd podczas uruchamiania emulatora.\n\nMoże to oznaczać problem ze sterownikiem do karty graficznej. Sprubuj go zaktualizować.\n\nSilnik graficzny został zmieniony: +GenericAllStartupError = PPSSPP nie może uruchomić żadnego trybu grafiki. Spróbuj zaktualizować swoje sterowniki do karty graficznej (oraz pozostałe). +GenericBackendSwitchCrash = PPSSPP - wystąpił błąd podczas uruchamiania emulatora.\n\nMoże to oznaczać problem ze sterownikiem do karty graficznej. Spróbuj go zaktualizować.\n\nSilnik graficzny został zmieniony: GenericDirect3D9Error = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej i biblioteki DirectX9.\n\nCzy chcesz zmienić sterownik na OpenGL?\n\nKomunikat błędu: GenericGraphicsError = Błąd grafiki GenericOpenGLError = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej.\n\nCzy chcesz zmienić sterownik na DirectX 9?\n\nKomunikat błędu: From cd49dc6627d6933b0e70d4cca45c1b7b3d24fcda Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Nov 2022 17:13:08 +0100 Subject: [PATCH 247/715] OpenXR - Camera adjustment using PSP keys --- Common/VR/PPSSPPVR.cpp | 69 +++++++++++++++--------------------------- Common/VR/PPSSPPVR.h | 2 +- Core/KeyMap.cpp | 1 + Core/KeyMap.h | 1 + UI/NativeApp.cpp | 4 +-- 5 files changed, 30 insertions(+), 47 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 73fb91f6aa..889aecf778 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -199,18 +199,6 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con int status = IN_VRGetButtonState(j); for (ButtonMapping& m : controllerMapping[j]) { - //check if camera key was pressed - bool cameraKey = false; - std::vector nativeKeys; - if (KeyMap::KeyToPspButton(controllerIds[j], m.keycode, &nativeKeys)) { - for (int& nativeKey : nativeKeys) { - if (nativeKey == VIRTKEY_VR_CAMERA_ADJUST) { - cameraKey = true; - break; - } - } - } - //fill KeyInput structure bool pressed = status & m.ovr; keyInput.flags = pressed ? KEY_DOWN : KEY_UP; @@ -222,16 +210,12 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con if (pressed && haptics) { INVR_Vibrate(100, j, 1000); } - if (!pspKeys[VIRTKEY_VR_CAMERA_ADJUST] || cameraKey) { - NativeKey(keyInput); - } + NativeKey(keyInput); m.pressed = pressed; m.repeat = 0; } else if (pressed && (m.repeat > 30)) { keyInput.flags |= KEY_IS_REPEAT; - if (!pspKeys[VIRTKEY_VR_CAMERA_ADJUST] || cameraKey) { - NativeKey(keyInput); - } + NativeKey(keyInput); m.repeat = 0; } else { m.repeat++; @@ -339,13 +323,14 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con } } -void UpdateVRSpecialKeys(const KeyInput &key) { +bool UpdateVRSpecialKeys(const KeyInput &key) { std::vector nativeKeys; if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { pspKeys[nativeKey] = key.flags & KEY_DOWN; } } + return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; } /* @@ -577,34 +562,30 @@ bool StartVRRender() { // Camera control if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { //left joystick controls height and side - float height = g_Config.fCameraHeight; - float side = g_Config.fCameraSide; - int status = IN_VRGetButtonState(0); - if (status & ovrButton_Left) side -= 0.05f; - if (status & ovrButton_Right) side += 0.05f; - if (status & ovrButton_Down) height -= 0.05f; - if (status & ovrButton_Up) height += 0.05f; - if (status & ovrButton_LThumb) { - height = 0; - side = 0; - } - g_Config.fCameraHeight = clampFloat(height, -10.0f, 10.0f); - g_Config.fCameraSide = clampFloat(side, -10.0f, 10.0f); + if (pspKeys[CTRL_LEFT]) g_Config.fCameraSide -= 0.05f; + if (pspKeys[CTRL_RIGHT]) g_Config.fCameraSide += 0.05f; + if (pspKeys[CTRL_DOWN]) g_Config.fCameraHeight -= 0.05f; + if (pspKeys[CTRL_UP]) g_Config.fCameraHeight += 0.05f; //right joystick controls distance and fov - float dst = g_Config.fCameraDistance; - float fov = g_Config.fFieldOfViewPercentage; - status = IN_VRGetButtonState(1); - if (status & ovrButton_Left) fov -= 1.0f; - if (status & ovrButton_Right) fov += 1.0f; - if (status & ovrButton_Down) dst -= 0.1f; - if (status & ovrButton_Up) dst += 0.1f; - if (status & ovrButton_RThumb) { - fov = 100; - dst = 0; + if (pspKeys[VIRTKEY_AXIS_X_MIN]) g_Config.fFieldOfViewPercentage -= 1.0f; + if (pspKeys[VIRTKEY_AXIS_X_MAX]) g_Config.fFieldOfViewPercentage += 1.0f; + if (pspKeys[VIRTKEY_AXIS_Y_MIN]) g_Config.fCameraDistance -= 0.1f; + if (pspKeys[VIRTKEY_AXIS_Y_MAX]) g_Config.fCameraDistance += 0.1f; + + // Reset values + if (pspKeys[VIRTKEY_VR_CAMERA_RESET]) { + g_Config.fCameraHeight = 0; + g_Config.fCameraSide = 0; + g_Config.fCameraDistance = 0; + g_Config.fFieldOfViewPercentage = 100; } - g_Config.fCameraDistance = clampFloat(dst, -10.0f, 10.0f); - g_Config.fFieldOfViewPercentage = clampFloat(fov, 100.0f, 200.0f); + + // Clamp values + g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -10.0f, 10.0f); + g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -10.0f, 10.0f); + g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -10.0f, 10.0f); + g_Config.fFieldOfViewPercentage = clampFloat(g_Config.fFieldOfViewPercentage, 100.0f, 200.0f); } // Set customizations diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 2dd2d1c11f..8dd127a2cb 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -23,7 +23,7 @@ void InitVROnAndroid(void* vm, void* activity, const char* system, int version, void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); -void UpdateVRSpecialKeys(const KeyInput &key); +bool UpdateVRSpecialKeys(const KeyInput &key); // VR games compatibility void PreprocessStepVR(void* step); diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index 8c84be11e1..a853b69dfa 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -408,6 +408,7 @@ const KeyMap_IntStrPair psp_button_names[] = { #ifdef OPENXR {VIRTKEY_VR_CAMERA_ADJUST, "VR camera adjust"}, + {VIRTKEY_VR_CAMERA_RESET, "VR camera reset"}, #else {VIRTKEY_SCREEN_ROTATION_VERTICAL, "Display Portrait"}, {VIRTKEY_SCREEN_ROTATION_VERTICAL180, "Display Portrait Reversed"}, diff --git a/Core/KeyMap.h b/Core/KeyMap.h index 74859d3628..c81958ab26 100644 --- a/Core/KeyMap.h +++ b/Core/KeyMap.h @@ -69,6 +69,7 @@ enum { VIRTKEY_SCREEN_ROTATION_HORIZONTAL180 = 0x40000023, VIRTKEY_SPEED_ANALOG = 0x40000024, VIRTKEY_VR_CAMERA_ADJUST = 0x40000025, + VIRTKEY_VR_CAMERA_RESET = 0x40000026, VIRTKEY_LAST, VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST }; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index d387e7064b..92bb129f30 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1297,8 +1297,8 @@ bool NativeTouch(const TouchInput &touch) { bool NativeKey(const KeyInput &key) { // Special key VR actions - if (IsVREnabled()) { - UpdateVRSpecialKeys(key); + if (IsVREnabled() && !UpdateVRSpecialKeys(key)) { + return false; } // INFO_LOG(SYSTEM, "Key code: %i flags: %i", key.keyCode, key.flags); From 81dd95e16d9d18636bbaf4cc0d06e6492aee25c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 17:13:14 +0100 Subject: [PATCH 248/715] Fix sky plane fix (broke in my last VR refactor) --- Common/VR/PPSSPPVR.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 537844b073..77f9a2108a 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -4,7 +4,7 @@ #include "Common/VR/VRMath.h" #include "Common/VR/VRRenderer.h" -#if XR_USE_GRAPHICS_API_OPENGL +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES #include "Common/GPU/OpenGL/GLRenderManager.h" #endif #include "Common/GPU/Vulkan/VulkanContext.h" @@ -339,7 +339,7 @@ void UpdateVRSpecialKeys(const KeyInput &key) { ================================================================================ */ -#if XR_USE_GRAPHICS_API_OPENGL +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES void PreprocessSkyplane(GLRStep* step) { From 96931766cb971dacfe192996208125a60133a12d Mon Sep 17 00:00:00 2001 From: gucio321 <73652197+gucio321@users.noreply.github.com> Date: Mon, 7 Nov 2022 17:13:55 +0100 Subject: [PATCH 249/715] pl: fix a couple of typos and apply suggestions --- assets/lang/pl_PL.ini | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 2bb8ee973f..4be771ad9b 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -386,7 +386,7 @@ Not a valid disc image. = Nieprawidłowy obraz nośnika. OpenGLDriverError = Błąd sterownika OpenGL. PPSSPP doesn't support UMD Music. = PPSSPP nie wspiera UMD Music. PPSSPP doesn't support UMD Video. = PPSSPP nie wspiera UMD Video. -PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP odtwarza gry na PSP, nie na PlayStation 1/2 +PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP odtwarza gry z PSP, a nie z PlayStation 1/2 PPSSPPDoesNotSupportInternet = PPSSPP aktualnie nie obsługuje połączenia z Internetem dla DLC, PSN oraz aktualizacji gier. PS1 EBOOTs are not supported by PPSSPP. = Pliki EBOOT PS1 nie są obsługiwane przez PPSSPP. PSX game image detected. = Plik jest obrazem MODE2. PPSSPP nie obsługuje gier z PS1. @@ -612,7 +612,7 @@ Load = Otwórz... Loading... = Loading... PinPath = Przypnij PPSSPP can't load games or save right now = PPSSPP nie może teraz załadować gier ani zapisywać stanów -Recent = Ostatnio grywane +Recent = Ostatnio uruchamiane SavesAreTemporary = PPSSPP zapisuje do pamięci tymczasowej SavesAreTemporaryGuidance = Wypakuj PPSSPP, by móc trwale zapisywać SavesAreTemporaryIgnore = Ignoruj @@ -1102,8 +1102,8 @@ Change Nickname = Zmień pseudonim ChangingMemstickPath = Zapisy gier, zapisy stanu i inne dane nie zostaną skopiowane do tego folderu.\n\nZmienić ścieżkę do folderu Karty Pamięci? ChangingMemstickPathInvalid = Ta ścieżka nie może zostać użyta do zapisu plików Karty Pamięci. Cheats = Kody -Clear Recent = Wyczyść "Ostatni grywanych" -Clear Recent Games List = Wyczyść listę ostatnio grywanych +Clear Recent = Wyczyść "Ostatni uruchamiane" +Clear Recent Games List = Wyczyść listę ostatnio uruchamianych Clear UI background = Przywróć tło interfejsu Confirmation Button = Przycisk potwierdzenia Date Format = Format daty @@ -1114,7 +1114,7 @@ Developer Tools = Narzędzia programistyczne Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid Display Homebrew on a grid = Display "Homebrew && Demos" on a grid -Display Recent on a grid = Wyświetlaj "Ostatnio Grywane" w projekcji siatki +Display Recent on a grid = Wyświetlaj "Ostatnio Uruchamiane" w projekcji siatki Dynarec (JIT) = Dynarec (JIT) Emulation = Emulacja Enable Cheats = Włącz kody @@ -1178,7 +1178,7 @@ Theme = Motyw Time Format = Format czasu UI = Interfejs użytkownika UI background animation = Animacja tła -UI Sound = Dźwięki interfejsu użydkownika +UI Sound = Dźwięki interfejsu urzydkownika undo %c = backup %c USB = USB Use Lossless Video Codec (FFV1) = Używaj stratnego kodeka wideo (FFV1) From e1baa3d4241eb4fa3be58f5ce39cf1deec62fc8f Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Nov 2022 17:14:27 +0100 Subject: [PATCH 250/715] OpenXR - Camera sliders removed from settings --- UI/GameSettingsScreen.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index e46311870b..f5b6662800 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1165,9 +1165,6 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new CheckBox(&g_Config.bForce72Hz, vr->T("Force 72Hz update"))); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraDistance, -10.0f, 10.0f, vr->T("Camera distance adjust"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraHeight, -10.0f, 10.0f, vr->T("Camera height adjust"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCameraSide, -10.0f, 10.0f, vr->T("Camera side adjust"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); From e7b6fcd5130ee60b2fd0e1ebe71384930e382e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 17:36:46 +0100 Subject: [PATCH 251/715] Properly buildfix GL/VR again --- Common/VR/PPSSPPVR.cpp | 8 +++++--- Common/VR/VRBase.h | 37 ++-------------------------------- Common/VR/VRFramebuffer.cpp | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 77f9a2108a..d68d44de2d 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -1,12 +1,14 @@ #include "Common/VR/PPSSPPVR.h" + #include "Common/VR/VRBase.h" +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES +#include "Common/GPU/OpenGL/GLRenderManager.h" +#endif + #include "Common/VR/VRInput.h" #include "Common/VR/VRMath.h" #include "Common/VR/VRRenderer.h" -#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES -#include "Common/GPU/OpenGL/GLRenderManager.h" -#endif #include "Common/GPU/Vulkan/VulkanContext.h" #include "Core/HLE/sceDisplay.h" diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 34e52908d4..dfb58b7e80 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -15,42 +15,9 @@ #define _USE_MATH_DEFINES #include -#ifdef ANDROID +#if defined(_DEBUG) && (defined(XR_USE_GRAPHICS_API_OPENGL) || defined(XR_USE_GRAPHICS_API_OPENGL_ES)) -#include -#include - -#endif - -#if defined(_DEBUG) && defined(ANDROID) -static const char* GlErrorString(GLenum error) { - switch (error) { - case GL_NO_ERROR: - return "GL_NO_ERROR"; - case GL_INVALID_ENUM: - return "GL_INVALID_ENUM"; - case GL_INVALID_VALUE: - return "GL_INVALID_VALUE"; - case GL_INVALID_OPERATION: - return "GL_INVALID_OPERATION"; - case GL_INVALID_FRAMEBUFFER_OPERATION: - return "GL_INVALID_FRAMEBUFFER_OPERATION"; - case GL_OUT_OF_MEMORY: - return "GL_OUT_OF_MEMORY"; - default: - return "unknown"; - } -} - -static void GLCheckErrors(char* file, int line) { - for (int i = 0; i < 10; i++) { - const GLenum error = glGetError(); - if (error == GL_NO_ERROR) { - break; - } - ALOGE("GL error on line %s:%d %s", file, line, GlErrorString(error)); - } -} +void GLCheckErrors(char* file, int line); #define GL(func) func; GLCheckErrors(__FILE__ , __LINE__); #else diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index a3986ee7d4..b6583052ad 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -1,5 +1,12 @@ #include "VRFramebuffer.h" +#if XR_USE_GRAPHICS_API_OPENGL_ES + +#include +#include + +#endif + #include #include #include @@ -43,6 +50,39 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) { frameBuffer->Acquired = false; } +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES + +static const char* GlErrorString(GLenum error) { + switch (error) { + case GL_NO_ERROR: + return "GL_NO_ERROR"; + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + default: + return "unknown"; + } +} + +void GLCheckErrors(char* file, int line) { + for (int i = 0; i < 10; i++) { + const GLenum error = glGetError(); + if (error == GL_NO_ERROR) { + break; + } + ALOGE("GL error on line %s:%d %s", file, line, GlErrorString(error)); + } +} + +#endif + #if XR_USE_GRAPHICS_API_OPENGL_ES static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { From 81b5a38484aea67f3abb7e3bcdabc9d769c4f66a Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Nov 2022 21:34:09 +0100 Subject: [PATCH 252/715] OpenXR - GTA Liberty city stereo fixed --- assets/compatvr.ini | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/assets/compatvr.ini b/assets/compatvr.ini index bc4e1a6dd1..b54081f4f5 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -758,15 +758,15 @@ ULJM05604 = 1.0 ULUS10490 = 1.0 # Grand Theft Auto: Liberty City Stories -NPJH50825 = 1.0 -ULES00051 = 1.0 -ULES00151 = 1.0 -ULES00181 = 1.0 -ULES00182 = 1.0 -ULJM05255 = 1.0 -ULJM05359 = 1.0 -ULJM05885 = 1.0 -ULUS10041 = 1.0 +NPJH50825 = 0.5 +ULES00051 = 0.5 +ULES00151 = 0.5 +ULES00181 = 0.5 +ULES00182 = 0.5 +ULJM05255 = 0.5 +ULJM05359 = 0.5 +ULJM05885 = 0.5 +ULUS10041 = 0.5 # Grand Theft Auto: Vice City Stories NPJH50827 = 1.0 From eec414d33134d2769265ea9088446377c5c9fa14 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Nov 2022 21:40:25 +0100 Subject: [PATCH 253/715] OpenXR - Allow more extreme camera adjusts --- Common/VR/PPSSPPVR.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index b12af503db..8513500b86 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -584,9 +584,9 @@ bool StartVRRender() { } // Clamp values - g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -10.0f, 10.0f); - g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -10.0f, 10.0f); - g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -10.0f, 10.0f); + g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); + g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -50.0f, 50.0f); + g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -50.0f, 50.0f); g_Config.fFieldOfViewPercentage = clampFloat(g_Config.fFieldOfViewPercentage, 100.0f, 200.0f); } From d1dabd40eea94240fa7d9ba05ca50b8ef6b78757 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Nov 2022 22:10:12 +0100 Subject: [PATCH 254/715] OpenXR - Disable range culling properly --- GPU/Common/VertexShaderGenerator.cpp | 2 +- GPU/GPUCommon.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index fd99a52cd9..0e18ac1361 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1302,7 +1302,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " }\n"); } - if (vertexRangeCulling && !gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { + if (vertexRangeCulling) { WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n"); WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n"); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index ddaf02bab8..f27dc85c38 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3338,7 +3338,7 @@ u32 GPUCommon::CheckGPUFeatures() const { bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported; bool canDiscardVertex = draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL); - if (canClipOrCull || canDiscardVertex) { + if (!gstate_c.Use(GPU_USE_VIRTUAL_REALITY) &&(canClipOrCull || canDiscardVertex)) { // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible. features |= GPU_USE_VS_RANGE_CULLING; } From 7b09fc43b052fefa904c43b9ed02e636e1aa8954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 23:04:45 +0100 Subject: [PATCH 255/715] Warning fix in VR code --- Common/VR/VRBase.h | 2 +- Common/VR/VRFramebuffer.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 114a063a30..10c2648a2f 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -18,7 +18,7 @@ #if defined(_DEBUG) && (defined(XR_USE_GRAPHICS_API_OPENGL) || defined(XR_USE_GRAPHICS_API_OPENGL_ES)) -void GLCheckErrors(char* file, int line); +void GLCheckErrors(const char* file, int line); #define GL(func) func; GLCheckErrors(__FILE__ , __LINE__); #else diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index b6583052ad..c8bc44a972 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -71,7 +71,7 @@ static const char* GlErrorString(GLenum error) { } } -void GLCheckErrors(char* file, int line) { +void GLCheckErrors(const char* file, int line) { for (int i = 0; i < 10; i++) { const GLenum error = glGetError(); if (error == GL_NO_ERROR) { @@ -86,7 +86,6 @@ void GLCheckErrors(char* file, int line) { #if XR_USE_GRAPHICS_API_OPENGL_ES static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { - frameBuffer->Width = width; frameBuffer->Height = height; From bd40ccda51522f2c147b20351d578f7aad3c71b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 17:57:32 +0100 Subject: [PATCH 256/715] Improve VkResult logging --- Common/GPU/Vulkan/VulkanLoader.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index c6012f001e..f710330fc5 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -727,6 +727,7 @@ void VulkanFree() { } const char *VulkanResultToString(VkResult res) { + static char temp[128]{}; switch (res) { case VK_NOT_READY: return "VK_NOT_READY"; case VK_TIMEOUT: return "VK_TIMEOUT"; @@ -749,10 +750,25 @@ const char *VulkanResultToString(VkResult res) { case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR"; case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; - case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR"; - + case VK_ERROR_OUT_OF_POOL_MEMORY: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR"; + case VK_ERROR_FRAGMENTED_POOL: return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_UNKNOWN: return "VK_ERROR_UNKNOWN (-13)"; + case VK_ERROR_FRAGMENTATION: return "VK_ERROR_FRAGMENTATION"; + case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; + case VK_PIPELINE_COMPILE_REQUIRED: return "VK_PIPELINE_COMPILE_REQUIRED"; + case VK_ERROR_VALIDATION_FAILED_EXT: return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_ERROR_INVALID_SHADER_NV: return "VK_ERROR_INVALID_SHADER_NV"; + case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case VK_ERROR_NOT_PERMITTED_KHR: return "VK_ERROR_NOT_PERMITTED_KHR"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case VK_THREAD_IDLE_KHR: return "VK_THREAD_IDLE_KHR"; + case VK_THREAD_DONE_KHR: return "VK_THREAD_DONE_KHR"; + case VK_OPERATION_DEFERRED_KHR: return "VK_OPERATION_DEFERRED_KHR"; + case VK_OPERATION_NOT_DEFERRED_KHR: return "VK_OPERATION_NOT_DEFERRED_KHR"; default: - return "VK_ERROR_...(unknown)"; + // This isn't thread safe, but this should be rare, and at worst, we'll get a jumble of two messages. + snprintf(temp, sizeof(temp), "VK_ERROR_???: 0x%08x", (u32)res); + return temp; } } From 4e8f97d64dcb300ddb126ebb766ffeebb7535b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 22:25:03 +0100 Subject: [PATCH 257/715] Output shader descriptions directly in the source code --- GPU/Common/FragmentShaderGenerator.cpp | 2 ++ GPU/Common/GeometryShaderGenerator.cpp | 3 +++ GPU/Common/VertexShaderGenerator.cpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 1cfd750540..9e90a707f3 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -94,6 +94,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } ShaderWriter p(buffer, compat, ShaderStage::Fragment, extensions, flags); + p.F("// %s\n", FragmentShaderDesc(id).c_str()); + p.ApplySamplerMetadata(arrayTexture ? samplersStereo : samplersMono); bool lmode = id.Bit(FS_BIT_LMODE); diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index 1438cbb6f5..12bf25a550 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -49,6 +49,9 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP); ShaderWriter p(buffer, compat, ShaderStage::Geometry, extensions); + + p.F("// %s\n", GeometryShaderDesc(id).c_str()); + p.C("layout(triangles) in;\n"); if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { p.C("layout(triangle_strip, max_vertices = 12) out;\n"); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index fd99a52cd9..5354e82b96 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -168,6 +168,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag ShaderWriter p(buffer, compat, ShaderStage::Vertex, extensions); + p.F("// %s\n", VertexShaderDesc(id).c_str()); + bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); bool lmode = id.Bit(VS_BIT_LMODE); bool doTexture = id.Bit(VS_BIT_DO_TEXTURE); From 25547b5fe24c5b83304ba39231bdc5fe0c3ee05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 22:25:45 +0100 Subject: [PATCH 258/715] Make Mailbox handle null values. Fixes hang. --- Common/Thread/Channel.h | 8 +++++--- Common/Thread/Promise.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Common/Thread/Channel.h b/Common/Thread/Channel.h index b6b23fdebe..82772bb6f4 100644 --- a/Common/Thread/Channel.h +++ b/Common/Thread/Channel.h @@ -20,10 +20,11 @@ struct Mailbox { std::mutex mutex_; std::condition_variable condvar_; T data_{}; + bool dataReceived_ = false; T Wait() { std::unique_lock lock(mutex_); - while (!data_) { + while (!dataReceived_) { condvar_.wait(lock); } return data_; @@ -31,7 +32,7 @@ struct Mailbox { bool Poll(T *data) { std::unique_lock lock(mutex_); - if (data_) { + if (dataReceived_) { *data = data_; return true; } else { @@ -41,8 +42,9 @@ struct Mailbox { bool Send(T data) { std::unique_lock lock(mutex_); - if (!data_) { + if (!dataReceived_) { data_ = data; + dataReceived_ = true; condvar_.notify_all(); return true; } else { diff --git a/Common/Thread/Promise.h b/Common/Thread/Promise.h index 4145b4b6c1..96c36f9605 100644 --- a/Common/Thread/Promise.h +++ b/Common/Thread/Promise.h @@ -107,7 +107,7 @@ public: } } - // For outside injection of data, when not using Spawn + // For outside injection of data, when not using Spawn. void Post(T data) { rx_->Send(data); } From 90f67e91f571887fef48a135775ebcd7285aec42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 22:27:02 +0100 Subject: [PATCH 259/715] Avoid drawing with failed-to-create pipelines --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 42 +++++++++++++++---------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index ae231d63df..b154a6bc01 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1443,6 +1443,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkPipeline lastPipeline = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + bool pipelineOK = false; + int lastStencilWriteMask = -1; int lastStencilCompareMask = -1; int lastStencilReference = -1; @@ -1474,11 +1476,15 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); pipelineLayout = c.pipeline.pipelineLayout; lastGraphicsPipeline = graphicsPipeline; - // Reset dynamic state so it gets refreshed with the new pipeline. - lastStencilWriteMask = -1; - lastStencilCompareMask = -1; - lastStencilReference = -1; + pipelineOK = true; + } else { + pipelineOK = false; } + + // Reset dynamic state so it gets refreshed with the new pipeline. + lastStencilWriteMask = -1; + lastStencilCompareMask = -1; + lastStencilReference = -1; } break; } @@ -1550,7 +1556,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } case VKRRenderCommand::PUSH_CONSTANTS: - vkCmdPushConstants(cmd, pipelineLayout, c.push.stages, c.push.offset, c.push.size, c.push.data); + if (pipelineOK) { + vkCmdPushConstants(cmd, pipelineLayout, c.push.stages, c.push.offset, c.push.size, c.push.data); + } break; case VKRRenderCommand::STENCIL: @@ -1569,21 +1577,23 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c break; case VKRRenderCommand::DRAW_INDEXED: - { - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); - vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, (VkIndexType)c.drawIndexed.indexType); - VkDeviceSize voffset = c.drawIndexed.voffset; - vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &voffset); - vkCmdDrawIndexed(cmd, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0); + if (pipelineOK) { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); + vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, (VkIndexType)c.drawIndexed.indexType); + VkDeviceSize voffset = c.drawIndexed.voffset; + vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &voffset); + vkCmdDrawIndexed(cmd, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0); + } break; - } case VKRRenderCommand::DRAW: - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); - if (c.draw.vbuffer) { - vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); + if (pipelineOK) { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); + if (c.draw.vbuffer) { + vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); + } + vkCmdDraw(cmd, c.draw.count, 1, c.draw.offset, 0); } - vkCmdDraw(cmd, c.draw.count, 1, c.draw.offset, 0); break; case VKRRenderCommand::CLEAR: From 4d637342f72611224e53c076d9375eccff0bd659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 22:33:15 +0100 Subject: [PATCH 260/715] Log source code for failed pipeline creations --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 20 ++++++++++++++++++-- Common/GPU/Vulkan/VulkanRenderManager.h | 8 ++++++++ GPU/Vulkan/PipelineManagerVulkan.cpp | 5 +++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 732aa2a0fd..d4497aeb6e 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -94,10 +94,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR // // At least create a null placeholder to avoid creating over and over if something is broken. pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); + ERROR_LOG(G3D, "Failed creating graphics pipeline! VK_INCOMPLETE"); + LogCreationFailure(); success = false; } else if (result != VK_SUCCESS) { pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + LogCreationFailure(); success = false; } else { // Success! @@ -112,10 +115,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { - if (!pipeline[i]) + if (!this->pipeline[i]) continue; VkPipeline pipeline = this->pipeline[i]->BlockUntilReady(); - vulkan->Delete().QueueDeletePipeline(pipeline); + // pipeline can be nullptr here, if it failed to compile before. + if (pipeline) { + vulkan->Delete().QueueDeletePipeline(pipeline); + } } vulkan->Delete().QueueCallback([](void *p) { VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p; @@ -133,6 +139,16 @@ u32 VKRGraphicsPipeline::GetVariantsBitmask() const { return bitmask; } +void VKRGraphicsPipeline::LogCreationFailure() const { + ERROR_LOG(G3D, "vs: %s\n[END VS]", desc->vertexShaderSource.c_str()); + ERROR_LOG(G3D, "fs: %s\n[END FS]", desc->fragmentShaderSource.c_str()); + if (desc->geometryShader) { + ERROR_LOG(G3D, "gs: %s\n[END GS]", desc->geometryShaderSource.c_str()); + } + // TODO: Maybe log various other state? + ERROR_LOG(G3D, "======== END OF PIPELINE =========="); +} + bool VKRComputePipeline::Create(VulkanContext *vulkan) { if (!desc) { // Already failed to create this one. diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index f9b1f68be6..5e519f4641 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -145,6 +145,12 @@ struct VKRGraphicsPipelineDesc { Promise *fragmentShader = nullptr; Promise *geometryShader = nullptr; + // These are for pipeline creation failure logging. + // TODO: Store pointers to the string instead? Feels iffy but will probably work. + std::string vertexShaderSource; + std::string fragmentShaderSource; + std::string geometryShaderSource; + VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; VkVertexInputAttributeDescription attrs[8]{}; VkVertexInputBindingDescription ibd{}; @@ -179,6 +185,8 @@ struct VKRGraphicsPipeline { u32 GetVariantsBitmask() const; + void LogCreationFailure() const; + VKRGraphicsPipelineDesc *desc = nullptr; // not owned! Promise *pipeline[(size_t)RenderPassType::TYPE_COUNT]{}; std::string tag; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index d9ae5ddd70..d1b2da92b6 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -256,6 +256,11 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, desc->fragmentShader = fs->GetModule(); desc->vertexShader = vs->GetModule(); desc->geometryShader = gs ? gs->GetModule() : nullptr; + desc->fragmentShaderSource = fs->GetShaderString(SHADER_STRING_SOURCE_CODE); + desc->vertexShaderSource = vs->GetShaderString(SHADER_STRING_SOURCE_CODE); + if (gs) { + desc->geometryShaderSource = gs->GetShaderString(SHADER_STRING_SOURCE_CODE); + } VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly; inputAssembly.flags = 0; From ecd62e7eb223eb62fa40a74cc534807082980890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Nov 2022 22:48:39 +0100 Subject: [PATCH 261/715] Lift length limit on Android logging --- Common/LogManager.cpp | 2 +- android/jni/app-android.cpp | 50 +++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index cdcb224667..26b1ed49ec 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -56,7 +56,7 @@ void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char if (instance) { instance->Log(level, type, file, line, fmt, args); } else { - // Fall back to printf if we're before the log manager has been initialized. + // Fall back to printf or direct android logger with a small buffer if the log manager hasn't been initialized yet. #if PPSSPP_PLATFORM(ANDROID) char temp[512]; vsnprintf(temp, sizeof(temp), fmt, args); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index b74d345dc4..e6375a4b11 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -198,38 +198,44 @@ AndroidGraphicsContext *graphicsContext; #define LOG_APP_NAME "PPSSPP" #endif -#ifdef _DEBUG -#define DLOG(...) __android_log_print(ANDROID_LOG_INFO, LOG_APP_NAME, __VA_ARGS__); -#else -#define DLOG(...) -#endif - -#define ILOG(...) __android_log_print(ANDROID_LOG_INFO, LOG_APP_NAME, __VA_ARGS__); -#define WLOG(...) __android_log_print(ANDROID_LOG_WARN, LOG_APP_NAME, __VA_ARGS__); -#define ELOG(...) __android_log_print(ANDROID_LOG_ERROR, LOG_APP_NAME, __VA_ARGS__); -#define FLOG(...) __android_log_print(ANDROID_LOG_FATAL, LOG_APP_NAME, __VA_ARGS__); - #define MessageBox(a, b, c, d) __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s %s", (b), (c)); void AndroidLogger::Log(const LogMessage &message) { - // Log with simplified headers as Android already provides timestamp etc. + int mode; switch (message.level) { - case LogTypes::LVERBOSE: - case LogTypes::LDEBUG: - case LogTypes::LINFO: - ILOG("[%s] %s", message.log, message.msg.c_str()); + case LogTypes::LWARNING: + mode = ANDROID_LOG_WARN; break; case LogTypes::LERROR: - ELOG("[%s] %s", message.log, message.msg.c_str()); + mode = ANDROID_LOG_ERROR; break; - case LogTypes::LWARNING: - WLOG("[%s] %s", message.log, message.msg.c_str()); - break; - case LogTypes::LNOTICE: default: - ILOG("[%s] !!! %s", message.log, message.msg.c_str()); + mode = ANDROID_LOG_INFO; break; } + + // Long log messages need splitting up. + // Not sure what the actual limit is (seems to vary), but let's be conservative. + const size_t maxLogLength = 512; + if (message.msg.length() < maxLogLength) { + // Log with simplified headers as Android already provides timestamp etc. + __android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, message.msg.c_str()); + } else { + std::string msg = message.msg; + + // Ideally we should split at line breaks, but it's at least fairly usable anyway. + std::string first_part = msg.substr(0, maxLogLength); + __android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, first_part.c_str()); + msg = msg.substr(maxLogLength); + + while (msg.length() > maxLogLength) { + std::string first_part = msg.substr(0, maxLogLength); + __android_log_print(mode, LOG_APP_NAME, "%s", first_part.c_str()); + msg = msg.substr(maxLogLength); + } + // Print the final part. + __android_log_print(mode, LOG_APP_NAME, "%s", msg.c_str()); + } } JNIEnv* getEnv() { From 970c266b416cc5271535dea436cef0b8a77afff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 8 Nov 2022 00:30:21 +0100 Subject: [PATCH 262/715] Restore parallel GLSL builds --- GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 4879e58230..076d317442 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -96,7 +96,7 @@ static Promise *CompileShaderModuleAsync(VulkanContext *vulkan, return shaderModule; }; -#if defined(_DEBUG) || PPSSPP_PLATFORM(ANDROID) +#if defined(_DEBUG) // Don't parallelize in debug mode, pathological behavior due to mutex locks in allocator which is HEAVILY used by glslang. return Promise::AlreadyDone(compile()); #else From 04cd6c4f7db1e8ca3b7c7fd3868c1dc6f2ca52a3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 7 Nov 2022 18:15:14 -0800 Subject: [PATCH 263/715] TexCache: Align expandClut buffer, cleanup sizes. We shouldn't need larger than 2 KB CLUT buffers, since it's actually only 1 KB. We have a hack that allows 2 KB for separate mip map levels. --- GPU/Common/TextureCacheCommon.cpp | 18 +++++++++--------- GPU/Common/TextureCacheCommon.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 53962e7644..eece8ac9d5 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -105,19 +105,18 @@ inline int dimHeight(u16 dim) { return 1 << ((dim >> 8) & 0xFF); } -// Vulkan color formats: -// TODO TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw, Draw2D *draw2D) : draw_(draw), draw2D_(draw2D) { decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; - // TODO: Clamp down to 256/1KB? Need to check mipmapShareClut and clamp loadclut. - clutBufRaw_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB - clutBufConverted_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB + // It's only possible to have 1KB of palette entries, although we allow 2KB in a hack. + clutBufRaw_ = (u32 *)AllocateAlignedMemory(2048, 16); + clutBufConverted_ = (u32 *)AllocateAlignedMemory(2048, 16); + expandClut_ = (u32 *)AllocateAlignedMemory(1024, 16); // Zap so we get consistent behavior if the game fails to load some of the CLUT. - memset(clutBufRaw_, 0, 1024 * sizeof(u32)); - memset(clutBufConverted_, 0, 1024 * sizeof(u32)); + memset(clutBufRaw_, 0, 2048); + memset(clutBufConverted_, 0, 2048); clutBuf_ = clutBufConverted_; // These buffers will grow if necessary, but most won't need more than this. @@ -134,6 +133,7 @@ TextureCacheCommon::~TextureCacheCommon() { FreeAlignedMemory(clutBufConverted_); FreeAlignedMemory(clutBufRaw_); + FreeAlignedMemory(expandClut_); } // Produces a signed 1.23.8 value. @@ -1236,8 +1236,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { return; } - u32 startPos = gstate.getClutIndexStartPos(); - + _assert_(loadBytes <= 2048); clutTotalBytes_ = loadBytes; clutRenderAddress_ = 0xFFFFFFFF; @@ -1320,6 +1319,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { // It's possible for a game to load CLUT outside valid memory without crashing, should result in zeroes. u32 bytes = Memory::ValidSize(clutAddr, loadBytes); + _assert_(bytes <= 2048); bool performDownload = PSP_CoreParameter().compat.flags().AllowDownloadCLUT; if (GPURecord::IsActive()) performDownload = true; diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 889dbb85b5..bbaf0eecde 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -507,7 +507,7 @@ protected: bool isBgraBackend_ = false; - u32 expandClut_[256]; + u32 *expandClut_; }; inline bool TexCacheEntry::Matches(u16 dim2, u8 format2, u8 maxLevel2) const { From 17f6c00c3cef802cadd4253022dda28eff9eff35 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 7 Nov 2022 18:18:28 -0800 Subject: [PATCH 264/715] TexCache: Fix 16->32 colors with CLUT start pos. --- GPU/Common/TextureCacheCommon.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index eece8ac9d5..956ca56366 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -112,7 +112,8 @@ TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw, Draw2D *draw2D) // It's only possible to have 1KB of palette entries, although we allow 2KB in a hack. clutBufRaw_ = (u32 *)AllocateAlignedMemory(2048, 16); clutBufConverted_ = (u32 *)AllocateAlignedMemory(2048, 16); - expandClut_ = (u32 *)AllocateAlignedMemory(1024, 16); + // Here we need 2KB to expand a 1KB CLUT. + expandClut_ = (u32 *)AllocateAlignedMemory(2048, 16); // Zap so we get consistent behavior if the game fails to load some of the CLUT. memset(clutBufRaw_, 0, 2048); @@ -1681,7 +1682,8 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G if (expandTo32bit) { // We simply expand the CLUT to 32-bit, then we deindex as usual. Probably the fastest way. const u16 *clut = GetCurrentRawClut() + clutSharingOffset; - ConvertFormatToRGBA8888(clutformat, expandClut_, clut, 16); + const int clutStart = gstate.getClutIndexStartPos(); + ConvertFormatToRGBA8888(clutformat, expandClut_ + clutStart, clut + clutStart, 16); fullAlphaMask = 0xFF000000; for (int y = 0; y < h; ++y) { DeIndexTexture4((u32 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, expandClut_, &alphaSum); @@ -1880,7 +1882,14 @@ CheckAlphaResult TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int l if (expandTo32Bit && palFormat != GE_CMODE_32BIT_ABGR8888) { const u16 *clut16raw = (const u16 *)clutBufRaw_ + clutSharingOffset; - ConvertFormatToRGBA8888(GEPaletteFormat(palFormat), expandClut_, clut16raw, 256); + // It's possible to access the latter half of the CLUT using the start pos. + const int clutStart = gstate.getClutIndexStartPos(); + if (clutStart > 256) { + // Access wraps around when start + index goes over. + ConvertFormatToRGBA8888(GEPaletteFormat(palFormat), expandClut_, clut16raw, 512); + } else { + ConvertFormatToRGBA8888(GEPaletteFormat(palFormat), expandClut_ + clutStart, clut16raw + clutStart, 256); + } clut32 = expandClut_; palFormat = GE_CMODE_32BIT_ABGR8888; } From bc53a0d7c4479917bc1dc3a9d72b385d7fb69c18 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 7 Nov 2022 18:41:47 -0800 Subject: [PATCH 265/715] TexCache: Correct 16->32 for CLUT4 with shift. --- GPU/Common/TextureCacheCommon.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 956ca56366..8ac621ef92 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1683,7 +1683,12 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G // We simply expand the CLUT to 32-bit, then we deindex as usual. Probably the fastest way. const u16 *clut = GetCurrentRawClut() + clutSharingOffset; const int clutStart = gstate.getClutIndexStartPos(); - ConvertFormatToRGBA8888(clutformat, expandClut_ + clutStart, clut + clutStart, 16); + if (gstate.getClutIndexShift() == 0 || gstate.getClutIndexMask() <= 16) { + ConvertFormatToRGBA8888(clutformat, expandClut_ + clutStart, clut + clutStart, 16); + } else { + // To be safe for shifts and wrap around, convert the entire CLUT. + ConvertFormatToRGBA8888(clutformat, expandClut_, clut, 512); + } fullAlphaMask = 0xFF000000; for (int y = 0; y < h; ++y) { DeIndexTexture4((u32 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, expandClut_, &alphaSum); From 92384c285470a8648b517cd48c1ee46b330c8227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Von=C3=A1sek?= Date: Tue, 8 Nov 2022 07:09:27 +0100 Subject: [PATCH 266/715] Space added --- GPU/GPUCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index f27dc85c38..ef0cd2d246 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3338,7 +3338,7 @@ u32 GPUCommon::CheckGPUFeatures() const { bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported; bool canDiscardVertex = draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL); - if (!gstate_c.Use(GPU_USE_VIRTUAL_REALITY) &&(canClipOrCull || canDiscardVertex)) { + if (!gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && (canClipOrCull || canDiscardVertex)) { // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible. features |= GPU_USE_VS_RANGE_CULLING; } From d3c7fdb0db0d1c27894c8fa403ed3fb1915f5f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Tue, 8 Nov 2022 17:23:46 +0800 Subject: [PATCH 267/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 444d6be346..8f4d89d60b 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -172,7 +172,7 @@ Log Console = 記錄主控台 (&L) Memory View... = 記憶體檢視 (&V)… More Settings... = 更多設定 (&M)… Nearest = 鄰近取樣 (&N) -Skip Buffer Effects = 跳過緩衝區效果 (非緩衝區,更快) (&S) +Skip Buffer Effects = 跳過緩衝區效果 (&S) Off = 關閉 (&O) Open Chat = 開啟聊天 Open Directory... = 開啟目錄 (&D)… @@ -282,7 +282,7 @@ Back = 返回 Cancel = 取消 Center = 中心 ChangingGPUBackends = 變更 GPU 後端需要重新啟動 PPSSPP,要立即重新啟動嗎? -ChangingInflightFrames = 變更圖形命令緩衝需要重新啟動 PPSSPP,要立即重新啟動嗎? +ChangingInflightFrames = 變更圖形命令緩衝處理需要重新啟動 PPSSPP,要立即重新啟動嗎? Channel: = 頻道: Choose PPSSPP save folder = 選擇 PPSSPP 存檔資料夾 Confirm Overwrite = 要覆寫這個存檔的資料嗎? @@ -496,7 +496,7 @@ Frame Rate Control = 影格速率控制 Frame Skipping = 影格跳過 Frame Skipping Type = 影格跳過類型 FullScreen = 全螢幕 -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +GPUReadbackRequired = 警告:此遊戲需要關閉「跳過 GPU 讀回」 Hack Settings = 駭客設定 (可能會造成故障) Hardware Tessellation = 硬體鑲嵌式 Hardware Transform = 硬體轉換 @@ -513,7 +513,7 @@ Linear = 線性 Low = 低 LowCurves = 曲線/貝茲曲線品質 LowCurves Tip = 僅供少數遊戲使用,控制曲線平滑度 -Lower resolution for effects (reduces artifacts) = 降低效果解析度 (降低假影) +Lower resolution for effects (reduces artifacts) = 降低效果解析度 (降低失真) Manual Scaling = 手動縮放 Medium = 中 Mode = 模式 @@ -521,7 +521,7 @@ Must Restart = 您必須重新啟動 PPSSPP 以使這項變更生效 Native device resolution = 原生裝置解析度 Nearest = 鄰近取樣 No buffer = 無緩衝 -Skip Buffer Effects = 跳過緩衝效果 (無緩衝,更快) +Skip Buffer Effects = 跳過緩衝區效果 None = 無 Number of Frames = 影格數 Off = 關閉 @@ -544,12 +544,12 @@ Screen layout = 螢幕版面配置 Screen Scaling Filter = 螢幕縮放濾鏡 Show Debug Statistics = 顯示偵錯統計資料 Show FPS Counter = 顯示 FPS 計數器 -Skip GPU Readbacks = Skip GPU Readbacks +Skip GPU Readbacks = 跳過 GPU 讀回 Software Rendering = 軟體轉譯 (慢) Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 -Speed Hacks = 速度修正 (可能會造成故障) +Speed Hacks = 速度駭客 (可能會造成轉譯錯誤!) Stretching = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 From dd0409d68c49d864b1382a65739a938fa9b31ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 25 Jul 2022 12:22:50 +0200 Subject: [PATCH 268/715] OpenGL ES: Crash as early as possible if things are bad There's a huge variety of crash report in the Play Console of various opengl failures. Try to concentrate them to early points in initialization --- Common/GPU/OpenGL/thin3d_gl.cpp | 9 ++++++++- UI/NativeApp.cpp | 14 ++++++++++++-- android/jni/AndroidJavaGLContext.cpp | 7 ++++++- android/jni/app-android.cpp | 10 +++++++--- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index bd8a252e10..f004cbdc08 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -10,6 +10,7 @@ #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Math/math_util.h" #include "Common/Math/lin/matrix4x4.h" +#include "Common/Log.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/Shader.h" #include "Common/GPU/OpenGL/DataFormatGL.h" @@ -249,9 +250,13 @@ bool OpenGLShaderModule::Compile(GLRenderManager *render, ShaderLanguage languag if (source_.find("#version") == source_.npos) { source_ = ApplyGLSLPrelude(source_, glstage_); } + } else { + // Unsupported shader type + return false; } shader_ = render->CreateShader(glstage_, source_, tag_); + _assert_(shader_ != nullptr); // normally can't fail since we defer creation, unless there's a memory error or similar. return true; } @@ -276,7 +281,9 @@ public: for (auto &iter : shaders) { iter->Release(); } - if (program_) render_->DeleteProgram(program_); + if (program_) { + render_->DeleteProgram(program_); + } } bool LinkShaders(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index d387e7064b..757fd2d77a 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -934,6 +934,16 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { bool CreateGlobalPipelines() { using namespace Draw; + ShaderModule *vs_color_2d = g_draw->GetVshaderPreset(VS_COLOR_2D); + ShaderModule *fs_color_2d = g_draw->GetFshaderPreset(FS_COLOR_2D); + ShaderModule *vs_texture_color_2d = g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D); + ShaderModule *fs_texture_color_2d = g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D); + + if (!vs_color_2d || !fs_color_2d || !vs_texture_color_2d || !fs_texture_color_2d) { + ERROR_LOG(G3D, "Failed to get shader preset"); + return false; + } + InputLayout *inputLayout = ui_draw2d.CreateInputLayout(g_draw); BlendState *blendNormal = g_draw->CreateBlendState({ true, 0xF, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA }); DepthStencilState *depth = g_draw->CreateDepthStencilState({ false, false, Comparison::LESS }); @@ -941,12 +951,12 @@ bool CreateGlobalPipelines() { PipelineDesc colorDesc{ Primitive::TRIANGLE_LIST, - { g_draw->GetVshaderPreset(VS_COLOR_2D), g_draw->GetFshaderPreset(FS_COLOR_2D) }, + { vs_color_2d, fs_color_2d }, inputLayout, depth, blendNormal, rasterNoCull, &vsColBufDesc, }; PipelineDesc texColorDesc{ Primitive::TRIANGLE_LIST, - { g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, + { vs_texture_color_2d, fs_texture_color_2d }, inputLayout, depth, blendNormal, rasterNoCull, &vsTexColBufDesc, }; diff --git a/android/jni/AndroidJavaGLContext.cpp b/android/jni/AndroidJavaGLContext.cpp index c435ee4451..f7f7b70444 100644 --- a/android/jni/AndroidJavaGLContext.cpp +++ b/android/jni/AndroidJavaGLContext.cpp @@ -13,13 +13,18 @@ AndroidJavaEGLGraphicsContext::AndroidJavaEGLGraphicsContext() { bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { INFO_LOG(G3D, "AndroidJavaEGLGraphicsContext::InitFromRenderThread"); CheckGLExtensions(); + // OpenGL handles rotated rendering in the driver. g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); draw_ = Draw::T3DCreateGLContext(); // Can't fail renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager_->SetInflightFrames(g_Config.iInflightFrames); - draw_->CreatePresets(); + + if (!draw_->CreatePresets()) { + _assert_msg_(false, "Failed to compile preset shaders"); + return false; + } return true; } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index e6375a4b11..0ea64f935b 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -13,9 +13,8 @@ #include #include -#include - #ifndef _MSC_VER + #include #include #include @@ -286,7 +285,12 @@ static void EmuThreadFunc() { } else { INFO_LOG(SYSTEM, "Runloop: Graphics context available! %p", graphicsContext); } - NativeInitGraphics(graphicsContext); + + if (!NativeInitGraphics(graphicsContext)) { + _assert_msg_(false, "Failed to initialize graphics, might as well bail"); + emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; + return; + } INFO_LOG(SYSTEM, "Graphics initialized. Entering loop."); From 1f20e11d61c82ef8800cd783505d32bec388a5be Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 8 Nov 2022 07:29:36 -0800 Subject: [PATCH 269/715] GPU: Avoid self memcpy(). --- GPU/GPUCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index ddaf02bab8..17de04fc52 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3080,9 +3080,9 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags // Track stray copies of a framebuffer in RAM. MotoGP does this. if (framebufferManager_->MayIntersectFramebuffer(src) || framebufferManager_->MayIntersectFramebuffer(dest)) { if (!framebufferManager_->NotifyFramebufferCopy(src, dest, size, flags, gstate_c.skipDrawReason)) { - // We use a little hack for PerformReadbackToMemory/PerformWriteColorFromMemory using a VRAM mirror. + // We use matching values in PerformReadbackToMemory/PerformWriteColorFromMemory. // Since they're identical we don't need to copy. - if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) { + if (dest != src) { if (MemBlockInfoDetailed(size)) { const std::string tag = GetMemWriteTagAt("GPUMemcpy/", src, size); Memory::Memcpy(dest, src, size, tag.c_str(), tag.size()); From c6084c16c3fb2c15b48543e746fc2bfabef0929d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 8 Nov 2022 22:59:43 +0100 Subject: [PATCH 270/715] Fix GLSL compilation issues on really old Adreno drivers. They don't seem to accept unsigned integers as switch cases. Fixes some stuff in #16295 , not sure if all of it. --- GPU/Common/VertexShaderGenerator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 8b8c90a953..4b42670c81 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1054,11 +1054,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); p.C(" }\n"); p.C(" }\n"); - p.C(" switch (type) {\n"); // Attenuation - p.C(" case 1u:\n"); // GE_LIGHTTYPE_POINT + p.C(" switch (int(type)) {\n"); // Attenuation + p.C(" case 1:\n"); // GE_LIGHTTYPE_POINT p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i); p.C(" break;\n"); - p.C(" case 2u:\n"); // GE_LIGHTTYPE_SPOT + p.C(" case 2:\n"); // GE_LIGHTTYPE_SPOT p.F(" angle = length(u_lightdir%i) == 0.0 ? 0.0 : dot(normalize(u_lightdir%i), toLight);\n", i, i); p.F(" if (angle >= u_lightangle_spotCoef%i.x) {\n", i); p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (u_lightangle_spotCoef%i.y <= 0.0 ? 1.0 : pow(angle, u_lightangle_spotCoef%i.y));\n", i, i, i); From 585569c2c2affececbed9669e44d2494c0ee6e5d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 8 Nov 2022 20:01:14 -0800 Subject: [PATCH 271/715] TexCache: Cleanup BGRA flag dirtying. --- GPU/Common/TextureCacheCommon.cpp | 12 +++--------- GPU/GPUState.h | 6 ++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 8ac621ef92..5ae10bcf31 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -423,11 +423,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE; bool isBgraTexture = isBgraBackend_ && !hasClutGPU; - - if (gstate_c.bgraTexture != isBgraTexture) { - gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); - } - gstate_c.bgraTexture = isBgraTexture; + gstate_c.SetTextureIsBGRA(isBgraTexture); if (entryIter != cache_.end()) { entry = entryIter->second.get(); @@ -1093,12 +1089,10 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) gstate_c.curTextureWidth = RoundUpToPowerOf2(gstate_c.curTextureWidth); } - if (gstate_c.bgraTexture) { - gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); - } else if ((gstate_c.curTextureXOffset == 0) != (fbInfo.xOffset == 0) || (gstate_c.curTextureYOffset == 0) != (fbInfo.yOffset == 0)) { + if ((gstate_c.curTextureXOffset == 0) != (fbInfo.xOffset == 0) || (gstate_c.curTextureYOffset == 0) != (fbInfo.yOffset == 0)) { gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); } - gstate_c.bgraTexture = false; + gstate_c.SetTextureIsBGRA(false); gstate_c.curTextureXOffset = fbInfo.xOffset; gstate_c.curTextureYOffset = fbInfo.yOffset; u32 texW = (u32)gstate.getTextureWidth(0); diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 0347371212..16df77c61d 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -568,6 +568,12 @@ struct GPUStateCache { Dirty(DIRTY_FRAGMENTSHADER_STATE); } } + void SetTextureIsBGRA(bool isBGRA) { + if (bgraTexture != isBGRA) { + bgraTexture = isBGRA; + Dirty(DIRTY_FRAGMENTSHADER_STATE); + } + } u32 useFlags; From 3333f2a5aad1600d3bdca5b55552eef02fb4ce90 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 7 Nov 2022 20:07:57 -0800 Subject: [PATCH 272/715] GPU: Avoid clears for non-simple depth values. Some drivers don't round depth the same way for a clear vs for drawing, which can cause mismatches. We only do this if we see equals-style depth comparison funcs used in drawing. --- GPU/Common/DrawEngineCommon.h | 17 +++++++++++++++++ GPU/D3D11/DrawEngineD3D11.cpp | 4 ++++ GPU/D3D11/StateMappingD3D11.cpp | 1 + GPU/Directx9/DrawEngineDX9.cpp | 4 ++++ GPU/Directx9/StateMappingDX9.cpp | 1 + GPU/GLES/DrawEngineGLES.cpp | 4 ++++ GPU/GLES/StateMappingGLES.cpp | 2 ++ GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++++ GPU/Vulkan/StateMappingVulkan.cpp | 1 + 9 files changed, 38 insertions(+) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 4b62f48c14..8d6917fd6a 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -145,11 +145,28 @@ protected: return 1; } + inline void UpdateEverUsedEqualDepth(GEComparison comp) { + switch (comp) { + case GE_COMP_EQUAL: + case GE_COMP_NOTEQUAL: + case GE_COMP_LEQUAL: + case GE_COMP_GEQUAL: + everUsedEqualDepth_ = true; + break; + + default: + break; + } + } + bool useHWTransform_ = false; bool useHWTessellation_ = false; // Used to prevent unnecessary flushing in softgpu. bool flushOnParams_ = true; + // Set once a equal depth test is encountered. + bool everUsedEqualDepth_ = false; + // Vertex collector buffers u8 *decoded = nullptr; u16 *decIndex = nullptr; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index e0c33e5d76..9ef139486f 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -643,6 +643,10 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(result.setStencil, result.stencilValue); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index efbbcad31b..c840265540 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -274,6 +274,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { keys_.depthStencil.depthTestEnable = true; keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { keys_.depthStencil.depthTestEnable = false; keys_.depthStencil.depthWriteEnable = false; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 33117be1c9..1e6bd62d61 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -611,6 +611,10 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(); diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 951a401189..b6918027f8 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -232,6 +232,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { dxstate.depthTest.enable(); dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]); dxstate.depthWrite.set(gstate.isDepthWriteEnabled()); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { dxstate.depthTest.disable(); } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index e95afe57ed..2c0c54304d 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -404,6 +404,10 @@ void DrawEngineGLES::DoFlush() { swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(result.setStencil, result.stencilValue); diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index f80a3f5490..0330cdf9f6 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -254,6 +254,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) { } else { // Depth Test renderManager->SetDepth(gstate.isDepthTestEnabled(), gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]); + if (gstate.isDepthTestEnabled()) + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); // Stencil Test if (stencilState.enabled) { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index de81929a32..c1d1871140 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -899,6 +899,10 @@ void DrawEngineVulkan::DoFlush() { if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; // Only here, where we know whether to clear or to draw primitives, should we actually set the current framebuffer! Because that gives use the opportunity // to use a "pre-clear" render pass, for high efficiency on tilers. diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 9e2177b901..7c23c67126 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -278,6 +278,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag key.depthTestEnable = true; key.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; key.depthWriteEnable = gstate.isDepthWriteEnabled(); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { key.depthTestEnable = false; key.depthWriteEnable = false; From 855d16ffb3ebc54be005cd06100f40440fad7c4c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 7 Nov 2022 20:05:51 -0800 Subject: [PATCH 273/715] GPU: Prefer scaling depth to 16-bit if using 24. In most cases, this will be a lot faster than pixel depth rounding, and may avoid more issues in vertex rounding. --- GPU/D3D11/GPU_D3D11.cpp | 3 +-- GPU/GLES/GPU_GLES.cpp | 11 ++++++----- GPU/Vulkan/GPU_Vulkan.cpp | 25 ++++++++++++++++--------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index d1c5edcce3..90fb480155 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -125,8 +125,7 @@ u32 GPU_D3D11::CheckGPUFeatures() const { if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { features |= GPU_ROUND_DEPTH_TO_16BIT; } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 791fa22869..8b71b2dce1 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -181,17 +181,18 @@ u32 GPU_GLES::CheckGPUFeatures() const { // If we already have a 16-bit depth buffer, we don't need to round. bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; - if (prefer24) { + bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16; + if (!prefer16) { if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - if (!gl_extensions.IsGLES || gl_extensions.GLES3) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } else if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { // Here we can simulate a 16 bit depth buffer by scaling. // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (!gl_extensions.IsGLES || gl_extensions.GLES3) { + // Use fragment rounding on desktop and GLES3, most accurate. + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; } else { // At least do vertex rounding if nothing else. features |= GPU_ROUND_DEPTH_TO_16BIT; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 754ef6ffce..17387c3e8b 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -257,15 +257,22 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { INFO_LOG(G3D, "Deficient texture format support: 4444: %d 1555: %d 565: %d", fmt4444, fmt1555, fmt565); } - if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } - else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } - else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; + bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; + bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16; + if (!prefer16) { + if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { + if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + // Here we can simulate a 16 bit depth buffer by scaling. + // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else { + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } + } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { + features |= GPU_ROUND_DEPTH_TO_16BIT; + } } if (g_Config.bStereoRendering && draw_->GetDeviceCaps().multiViewSupported) { From 745d9ad320776030c54072e1b0e0d03188d562d4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 7 Nov 2022 20:40:14 -0800 Subject: [PATCH 274/715] GPU: Avoid enabling depth test pointlessly. See #16015. Attempting to avoid a driver bug. --- GPU/Common/GPUStateUtils.cpp | 9 +++++++++ GPU/Common/GPUStateUtils.h | 1 + GPU/D3D11/StateMappingD3D11.cpp | 2 +- GPU/Directx9/StateMappingDX9.cpp | 2 +- GPU/GLES/StateMappingGLES.cpp | 5 +++-- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index c6fcfd7007..f168fa1920 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -136,6 +136,15 @@ bool IsColorTestTriviallyTrue() { } } +bool IsDepthTestEffectivelyDisabled() { + if (!gstate.isDepthTestEnabled()) + return true; + // We can ignore stencil, because ALWAYS and disabled choose the same stencil path. + if (gstate.getDepthTestFunction() != GE_COMP_ALWAYS) + return false; + return !gstate.isDepthWriteEnabled(); +} + const bool nonAlphaSrcFactors[16] = { true, // GE_SRCBLEND_DSTCOLOR, true, // GE_SRCBLEND_INVDSTCOLOR, diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index 038091f7d8..ab524f6c3f 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -56,6 +56,7 @@ bool IsColorTestAgainstZero(); bool IsColorTestTriviallyTrue(); bool IsAlphaTestAgainstZero(); bool NeedsTestDiscard(); +bool IsDepthTestEffectivelyDisabled(); bool IsStencilTestOutputDisabled(); StencilValueType ReplaceAlphaWithStencilType(); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index c840265540..2174da2ce9 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -270,7 +270,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } else { keys_.depthStencil.value = 0; // Depth Test - if (gstate.isDepthTestEnabled()) { + if (!IsDepthTestEffectivelyDisabled()) { keys_.depthStencil.depthTestEnable = true; keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index b6918027f8..4517150daf 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -228,7 +228,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { } } else { // Depth Test - if (gstate.isDepthTestEnabled()) { + if (!IsDepthTestEffectivelyDisabled()) { dxstate.depthTest.enable(); dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]); dxstate.depthWrite.set(gstate.isDepthWriteEnabled()); diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 0330cdf9f6..1d06ac01e4 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -253,8 +253,9 @@ void DrawEngineGLES::ApplyDrawState(int prim) { renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS); } else { // Depth Test - renderManager->SetDepth(gstate.isDepthTestEnabled(), gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]); - if (gstate.isDepthTestEnabled()) + bool depthTestUsed = !IsDepthTestEffectivelyDisabled(); + renderManager->SetDepth(depthTestUsed, gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]); + if (depthTestUsed) UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); // Stencil Test diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 7c23c67126..5f75ea2863 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -274,7 +274,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag } } else { // Depth Test - if (gstate.isDepthTestEnabled()) { + if (!IsDepthTestEffectivelyDisabled()) { key.depthTestEnable = true; key.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; key.depthWriteEnable = gstate.isDepthWriteEnabled(); From 4d8eb38b3a3a0642abf6af45c4a2021912531578 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 8 Nov 2022 21:51:00 -0800 Subject: [PATCH 275/715] Mpeg: Fix ConvertToYuv420 return value. This matches some of sceJpeg, so it may fix bugs if the width/height was passed from here directly to sceJpegCsc. --- Core/HLE/sceMpeg.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 3192e443b1..9f9a19edbd 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -2199,25 +2199,17 @@ static int __MpegAvcConvertToYuv420(const void *data, u32 bufferOutputAddr, int return (width << 16) | height; } -static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 unknown1, int unknown2) -{ - if (!Memory::IsValidAddress(bufferOutputAddr)) { - ERROR_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): invalid addresses", mpeg, bufferOutputAddr, unknown1, unknown2); - return -1; - } +static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 bufferAddr, int unknown2) { + if (!Memory::IsValidAddress(bufferOutputAddr)) + return hleLogError(ME, ERROR_MPEG_INVALID_VALUE, "invalid addresses"); MpegContext *ctx = getMpegCtx(mpeg); - if (!ctx) { - WARN_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, bufferOutputAddr, unknown1, unknown2); - return -1; - } + if (!ctx) + return hleLogWarning(ME, -1, "bad mpeg handle"); - if (ctx->mediaengine->m_buffer == 0){ - WARN_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): m_buffer is zero ", mpeg, bufferOutputAddr, unknown1, unknown2); - return ERROR_MPEG_AVC_INVALID_VALUE; - } + if (ctx->mediaengine->m_buffer == 0) + return hleLogWarning(ME, ERROR_MPEG_AVC_INVALID_VALUE, "m_buffer is zero"); - DEBUG_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x)", mpeg, bufferOutputAddr, unknown1, unknown2); const u8 *data = ctx->mediaengine->getFrameImage(); int width = ctx->mediaengine->m_desWidth; int height = ctx->mediaengine->m_desHeight; @@ -2225,7 +2217,7 @@ static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 unknown if (data) { __MpegAvcConvertToYuv420(data, bufferOutputAddr, width, height); } - return 0; + return hleLogSuccessX(ME, (width << 16) | height); } static int sceMpegGetUserdataAu(u32 mpeg, u32 streamUid, u32 auAddr, u32 resultAddr) @@ -2397,7 +2389,7 @@ const HLEFunction sceMpeg[] = {0X8160A2FE, &WrapU_U, "sceMpegAvcResourceFinish", 'x', "x" }, {0XAF26BB01, &WrapU_U, "sceMpegAvcResourceGetAvcEsBuf", 'x', "x" }, {0XFCBDB5AD, &WrapU_U, "sceMpegAvcResourceInit", 'x', "x" }, - {0XF5E7EA31, &WrapI_UUUI, "sceMpegAvcConvertToYuv420", 'i', "xxxi" }, + {0XF5E7EA31, &WrapI_UUUI, "sceMpegAvcConvertToYuv420", 'x', "xxxi" }, {0X01977054, &WrapI_UUUU, "sceMpegGetUserdataAu", 'i', "xxxx" }, {0X3C37A7A6, &WrapU_UU, "sceMpegNextAvcRpAu", 'x', "xx" }, {0X11F95CF1, &WrapU_U, "sceMpegGetAvcNalAu", 'x', "x" }, From 0ae0a9b389a931436e67744f40ed18c70d63180a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 8 Nov 2022 22:26:21 -0800 Subject: [PATCH 276/715] Mpeg: Correct YUV order from decode. --- Core/HLE/sceMpeg.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 9f9a19edbd..b39b5bd8db 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -2173,28 +2173,26 @@ static int __MpegAvcConvertToYuv420(const void *data, u32 bufferOutputAddr, int u8 *Cb = Y + sizeY; u8 *Cr = Cb + sizeCb; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; x += 4) { - u32 abgr0 = imageBuffer[x + 0]; - u32 abgr1 = imageBuffer[x + 1]; - u32 abgr2 = imageBuffer[x + 2]; - u32 abgr3 = imageBuffer[x + 3]; + for (int y = 0; y < height; y += 2) { + for (int x = 0; x < width; x += 2) { + u32 abgr0 = imageBuffer[width * (y + 0) + x + 0]; + u32 abgr1 = imageBuffer[width * (y + 0) + x + 1]; + u32 abgr2 = imageBuffer[width * (y + 1) + x + 0]; + u32 abgr3 = imageBuffer[width * (y + 1) + x + 1]; u32 yCbCr0 = convertABGRToYCbCr(abgr0); u32 yCbCr1 = convertABGRToYCbCr(abgr1); u32 yCbCr2 = convertABGRToYCbCr(abgr2); u32 yCbCr3 = convertABGRToYCbCr(abgr3); - Y[x + 0] = (yCbCr0 >> 16) & 0xFF; - Y[x + 1] = (yCbCr1 >> 16) & 0xFF; - Y[x + 2] = (yCbCr2 >> 16) & 0xFF; - Y[x + 3] = (yCbCr3 >> 16) & 0xFF; + Y[width * (y + 0) + x + 0] = (yCbCr0 >> 16) & 0xFF; + Y[width * (y + 0) + x + 1] = (yCbCr1 >> 16) & 0xFF; + Y[width * (y + 1) + x + 0] = (yCbCr2 >> 16) & 0xFF; + Y[width * (y + 1) + x + 1] = (yCbCr3 >> 16) & 0xFF; - *Cb++ = (yCbCr0 >> 8) & 0xFF; - *Cr++ = yCbCr0 & 0xFF; + Cb[(width >> 1) * (y >> 1) + (x >> 1)] = (yCbCr0 >> 8) & 0xFF; + Cr[(width >> 1) * (y >> 1) + (x >> 1)] = yCbCr0 & 0xFF; } - imageBuffer += width; - Y += width ; } return (width << 16) | height; } From 1c0a37f25204dfad15a24f91a50a27368031a4a8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 9 Nov 2022 07:07:39 -0800 Subject: [PATCH 277/715] GPU: Correct vertex decoder in software transform. It was meant to flip to skin in decode. --- GPU/D3D11/DrawEngineD3D11.cpp | 8 ++++++-- GPU/Directx9/DrawEngineDX9.cpp | 8 ++++++-- GPU/GLES/DrawEngineGLES.cpp | 8 ++++++-- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 8 ++++++-- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 9ef139486f..73708c930a 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -581,7 +581,11 @@ rotateVBO: } } else { PROFILE_THIS_SCOPE("soft"); - decOptions_.applySkinInDecode = true; + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -653,7 +657,7 @@ rotateVBO: if (result.action == SW_DRAW_PRIMITIVES) { D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering()); diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 1e6bd62d61..f16d48c6a8 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -546,7 +546,11 @@ rotateVBO: } } } else { - decOptions_.applySkinInDecode = true; + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -618,7 +622,7 @@ rotateVBO: ApplyDrawStateLate(); - VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_); + VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, true, pipelineState_); if (result.action == SW_DRAW_PRIMITIVES) { if (result.setStencil) { diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 2c0c54304d..14eb57afc7 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -267,7 +267,7 @@ void DrawEngineGLES::DoFlush() { GEPrimitiveType prim = prevPrim_; VShaderID vsid; - Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, &vsid); + Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode || !CanUseHardwareTransform(prim), &vsid); GLRBuffer *vertexBuffer = nullptr; GLRBuffer *indexBuffer = nullptr; @@ -331,7 +331,11 @@ void DrawEngineGLES::DoFlush() { } } else { PROFILE_THIS_SCOPE("soft"); - decOptions_.applySkinInDecode = true; + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index aa17822d8c..1f75b7412b 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -789,7 +789,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess // Can still work with software transform. VShaderID vsidTemp; - ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat, useSkinInDecode); + ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat, true); vs = CompileVertexShader(vsidTemp); } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index c1d1871140..bc51195144 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -841,7 +841,11 @@ void DrawEngineVulkan::DoFlush() { } } else { PROFILE_THIS_SCOPE("soft"); - decOptions_.applySkinInDecode = true; + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -924,7 +928,7 @@ void DrawEngineVulkan::DoFlush() { VulkanFragmentShader *fshader = nullptr; VulkanGeometryShader *gshader = nullptr; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0); if (!pipeline || !pipeline->pipeline) { From 8716021244cb36573fc1c9287dbbd63362bd9552 Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 9 Nov 2022 17:59:14 +0100 Subject: [PATCH 278/715] OpenXR - Do not apply head rotation on identity matrix --- Common/VR/PPSSPPVR.cpp | 19 ++++++------------- Common/VR/VRMath.cpp | 14 ++++++++++++++ Common/VR/VRMath.h | 1 + 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 8513500b86..0da404125e 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -644,20 +644,8 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { return true; } - // Chceck if the projection matrix is identity - bool identity = true; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - float value = projMatrix[i * 4 + j]; - - // Other number than zero on non-diagonale - if ((i != j) && (fabs(value) > EPSILON)) identity = false; - // Other number than one on diagonale - if ((i == j) && (fabs(value - 1.0f) > EPSILON)) identity = false; - } - } - // Update 3D geometry count + bool identity = IsMatrixIdentity(projMatrix); if (!identity && !ortho) { vr3DGeometryCount++; } @@ -708,6 +696,11 @@ void UpdateVRView(float* leftEye, float* rightEye) { float* matrix[] = {vrMatrix[VR_VIEW_MATRIX_LEFT_EYE], vrMatrix[VR_VIEW_MATRIX_RIGHT_EYE]}; for (int index = 0; index < 2; index++) { + // Validate the view matrix + if (IsMatrixIdentity(dst[index])) { + return; + } + // Get view matrix from the game Lin::Matrix4x4 gameView = {}; memcpy(gameView.m, dst[index], 16 * sizeof(float)); diff --git a/Common/VR/VRMath.cpp b/Common/VR/VRMath.cpp index 2fd7f1d538..d65f13a1a7 100644 --- a/Common/VR/VRMath.cpp +++ b/Common/VR/VRMath.cpp @@ -13,6 +13,20 @@ float ToRadians(float deg) { return (float)(deg * M_PI / 180.0f); } +bool IsMatrixIdentity(float* matrix) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + float value = matrix[i * 4 + j]; + + // Other number than zero on non-diagonale + if ((i != j) && (fabs(value) > EPSILON)) return false; + // Other number than one on diagonale + if ((i == j) && (fabs(value - 1.0f) > EPSILON)) return false; + } + } + return true; +} + /* ================================================================================ diff --git a/Common/VR/VRMath.h b/Common/VR/VRMath.h index 20317f4a8d..4f6e0610c9 100644 --- a/Common/VR/VRMath.h +++ b/Common/VR/VRMath.h @@ -9,6 +9,7 @@ float ToDegrees(float rad); float ToRadians(float deg); +bool IsMatrixIdentity(float* matrix); // XrPosef XrPosef XrPosef_Identity(); From b980f55645da1d312c903806d8d36b428e7accfd Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 9 Nov 2022 19:07:45 +0100 Subject: [PATCH 279/715] OpenXR - Don't get mirroring from identity matrix --- Common/VR/PPSSPPVR.cpp | 4 ++-- Common/VR/PPSSPPVR.h | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 0da404125e..eff2c37525 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -652,10 +652,10 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { return identity; } -void UpdateVRParams(float* projMatrix) { +void UpdateVRParams(float* projMatrix, float* viewMatrix) { // Set mirroring of axes - if (!vrMirroring[VR_MIRRORING_UPDATED]) { + if (!vrMirroring[VR_MIRRORING_UPDATED] && !IsMatrixIdentity(projMatrix) && !IsMatrixIdentity(viewMatrix)) { vrMirroring[VR_MIRRORING_UPDATED] = true; vrMirroring[VR_MIRRORING_AXIS_X] = projMatrix[0] < 0; vrMirroring[VR_MIRRORING_AXIS_Y] = projMatrix[5] < 0; diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 8dd127a2cb..c47fada705 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -40,6 +40,6 @@ int GetVRPassesCount(); bool IsMultiviewSupported(); bool IsFlatVRScene(); bool Is2DVRObject(float* projMatrix, bool ortho); -void UpdateVRParams(float* projMatrix); +void UpdateVRParams(float* projMatrix, float* viewMatrix); void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye); void UpdateVRView(float* leftEye, float* rightEye); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index aa17822d8c..3ba4a94f95 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -411,7 +411,9 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } else { UpdateVRProjection(gstate.projMatrix, leftEyeMatrix.m, rightEyeMatrix.m); } - UpdateVRParams(gstate.projMatrix); + float m4x4[16]; + ConvertMatrix4x3To4x4Transposed(m4x4, gstate.viewMatrix); + UpdateVRParams(gstate.projMatrix, m4x4); FlipProjMatrix(leftEyeMatrix, useBufferedRendering); FlipProjMatrix(rightEyeMatrix, useBufferedRendering); From 307acaa9b774b8e5b801618bd880e85cbb5bed4e Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 9 Nov 2022 19:25:08 +0100 Subject: [PATCH 280/715] OpenXR - View matrix identity check breaking several games fixed --- Common/VR/PPSSPPVR.cpp | 5 +++-- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + assets/compatvr.ini | 13 +++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index eff2c37525..5cd35fc590 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -655,7 +655,8 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { void UpdateVRParams(float* projMatrix, float* viewMatrix) { // Set mirroring of axes - if (!vrMirroring[VR_MIRRORING_UPDATED] && !IsMatrixIdentity(projMatrix) && !IsMatrixIdentity(viewMatrix)) { + bool identityView = PSP_CoreParameter().compat.vrCompat().IdentityViewHack && IsMatrixIdentity(viewMatrix); + if (!vrMirroring[VR_MIRRORING_UPDATED] && !IsMatrixIdentity(projMatrix) && !identityView) { vrMirroring[VR_MIRRORING_UPDATED] = true; vrMirroring[VR_MIRRORING_AXIS_X] = projMatrix[0] < 0; vrMirroring[VR_MIRRORING_AXIS_Y] = projMatrix[5] < 0; @@ -697,7 +698,7 @@ void UpdateVRView(float* leftEye, float* rightEye) { for (int index = 0; index < 2; index++) { // Validate the view matrix - if (IsMatrixIdentity(dst[index])) { + if (PSP_CoreParameter().compat.vrCompat().IdentityViewHack && IsMatrixIdentity(dst[index])) { return; } diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 21fb578456..b09eb67c14 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -122,6 +122,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { + CheckSetting(iniFile, gameID, "IdentityViewHack", &vrCompat_.IdentityViewHack); CheckSetting(iniFile, gameID, "Skyplane", &vrCompat_.Skyplane); CheckSetting(iniFile, gameID, "UnitsPerMeter", &vrCompat_.UnitsPerMeter); diff --git a/Core/Compatibility.h b/Core/Compatibility.h index c37541ce7a..86d139a536 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -93,6 +93,7 @@ struct CompatFlags { }; struct VRCompat { + bool IdentityViewHack; bool Skyplane; float UnitsPerMeter; }; diff --git a/assets/compatvr.ini b/assets/compatvr.ini index b54081f4f5..b896196ab8 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -30,6 +30,18 @@ # ======================================================================================== +[IdentityViewHack] +# Disables head tracking for render passes where view matrix is Identity + +# Sonic Rivals 1 +ULES00622 = true +ULUS10195 = true + +# Sonic Rivals 2 +ULES00940 = true +ULUS10323 = true + + [Skyplane] # Workaround to remove the background skyplane and add clearing framebuffer with a fog color. @@ -53,6 +65,7 @@ ULJM05395 = true ULJM05884 = true ULUS10160 = true + [UnitsPerMeter] # Scale of game world to convert the world units into meters. This enables following VR features: # + 3D stereoscopy (that can work only with accurate values) From 70c3205564308264759b9d66d895099cfda73ae8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 9 Nov 2022 20:34:29 -0800 Subject: [PATCH 281/715] GPU: Correct equal depth checks. --- GPU/D3D11/DrawEngineD3D11.cpp | 8 ++++---- GPU/Directx9/DrawEngineDX9.cpp | 8 ++++---- GPU/GLES/DrawEngineGLES.cpp | 8 ++++---- GPU/Vulkan/DrawEngineVulkan.cpp | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 73708c930a..b702d15250 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -633,6 +633,10 @@ rotateVBO: swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_NOT_READY && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); } @@ -647,10 +651,6 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); - // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. - // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. - if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) - result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(result.setStencil, result.stencilValue); diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index f16d48c6a8..8a9de7ef79 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -602,6 +602,10 @@ rotateVBO: swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight > 0, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_NOT_READY; if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); } @@ -615,10 +619,6 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); - // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. - // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. - if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) - result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 14eb57afc7..8b842f1dd2 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -395,6 +395,10 @@ void DrawEngineGLES::DoFlush() { swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_NOT_READY; if (result.action == SW_NOT_READY) swTransform.DetectOffsetTexture(maxIndex); @@ -408,10 +412,6 @@ void DrawEngineGLES::DoFlush() { swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); - // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. - // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. - if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) - result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(result.setStencil, result.stencilValue); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index bc51195144..3a683f3238 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -896,6 +896,10 @@ void DrawEngineVulkan::DoFlush() { swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_NOT_READY; if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); @@ -903,10 +907,6 @@ void DrawEngineVulkan::DoFlush() { if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); - // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. - // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. - if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) - result.action = SW_DRAW_PRIMITIVES; // Only here, where we know whether to clear or to draw primitives, should we actually set the current framebuffer! Because that gives use the opportunity // to use a "pre-clear" render pass, for high efficiency on tilers. From 72d197fc47fdcbb8adbb9edc6ff2d498d832295d Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 10 Nov 2022 18:44:11 +0100 Subject: [PATCH 282/715] Revert "OpenXR - Disable range culling properly" This reverts commit d1dabd40eea94240fa7d9ba05ca50b8ef6b78757. --- GPU/Common/VertexShaderGenerator.cpp | 2 +- GPU/GPUCommon.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 4b42670c81..70fc803dd1 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1304,7 +1304,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " }\n"); } - if (vertexRangeCulling) { + if (vertexRangeCulling && !gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n"); WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n"); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 183b71c4dc..17de04fc52 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3338,7 +3338,7 @@ u32 GPUCommon::CheckGPUFeatures() const { bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported; bool canDiscardVertex = draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL); - if (!gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && (canClipOrCull || canDiscardVertex)) { + if (canClipOrCull || canDiscardVertex) { // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible. features |= GPU_USE_VS_RANGE_CULLING; } From d32b6ceff0c4243bdfe8025925feef3fd25ff712 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 10 Nov 2022 20:45:34 +0100 Subject: [PATCH 283/715] OpenXR - Get all mirroring variants --- Common/VR/PPSSPPVR.cpp | 71 ++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 5cd35fc590..92a187d390 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -485,13 +485,11 @@ bool StartVRRender() { } // create updated quaternion - if (mx + my + mz < 3 - EPSILON) { - XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); - XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); - XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); - XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); - invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); - } + XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); + XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); + XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); + XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); + invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); float M[16]; XrQuaternionf_ToMatrix4f(&invView.orientation, M); @@ -661,22 +659,49 @@ void UpdateVRParams(float* projMatrix, float* viewMatrix) { vrMirroring[VR_MIRRORING_AXIS_X] = projMatrix[0] < 0; vrMirroring[VR_MIRRORING_AXIS_Y] = projMatrix[5] < 0; vrMirroring[VR_MIRRORING_AXIS_Z] = projMatrix[10] > 0; - if ((projMatrix[0] < 0) && (projMatrix[10] < 0)) { //e.g. Dante's inferno - vrMirroring[VR_MIRRORING_PITCH] = true; - vrMirroring[VR_MIRRORING_YAW] = true; - vrMirroring[VR_MIRRORING_ROLL] = false; - } else if (projMatrix[10] < 0) { //e.g. GTA - Liberty city - vrMirroring[VR_MIRRORING_PITCH] = false; - vrMirroring[VR_MIRRORING_YAW] = false; - vrMirroring[VR_MIRRORING_ROLL] = false; - } else if (projMatrix[5] < 0) { //e.g. PES 2014 - vrMirroring[VR_MIRRORING_PITCH] = true; - vrMirroring[VR_MIRRORING_YAW] = true; - vrMirroring[VR_MIRRORING_ROLL] = false; - } else { //e.g. Lego Pirates - vrMirroring[VR_MIRRORING_PITCH] = false; - vrMirroring[VR_MIRRORING_YAW] = true; - vrMirroring[VR_MIRRORING_ROLL] = true; + + float up = 0; + for (int i = 4; i < 8; i++) { + up += viewMatrix[i]; + } + + int variant = projMatrix[0] < 0; + variant += (projMatrix[5] < 0) << 1; + variant += (projMatrix[10] < 0) << 2; + variant += (up < 0) << 3; + + switch (variant) { + case 0: + case 1: + vrMirroring[VR_MIRRORING_PITCH] = false; + vrMirroring[VR_MIRRORING_YAW] = true; + vrMirroring[VR_MIRRORING_ROLL] = true; + break; + case 2: + case 3: + case 5: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: + case 15: + vrMirroring[VR_MIRRORING_PITCH] = true; + vrMirroring[VR_MIRRORING_YAW] = true; + vrMirroring[VR_MIRRORING_ROLL] = false; + break; + case 4: + case 6: + case 12: + case 14: + vrMirroring[VR_MIRRORING_PITCH] = true; + vrMirroring[VR_MIRRORING_YAW] = false; + vrMirroring[VR_MIRRORING_ROLL] = true; + break; + default: + assert(false); + std::exit(1); } } } From 97d63a321cd3730c8ab16db81e6a3fb310f282cf Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 10 Nov 2022 21:30:15 +0100 Subject: [PATCH 284/715] OpenXR - Test mirroring over 30 various games --- Common/VR/PPSSPPVR.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 92a187d390..92e00f898a 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -661,7 +661,7 @@ void UpdateVRParams(float* projMatrix, float* viewMatrix) { vrMirroring[VR_MIRRORING_AXIS_Z] = projMatrix[10] > 0; float up = 0; - for (int i = 4; i < 8; i++) { + for (int i = 4; i < 7; i++) { up += viewMatrix[i]; } @@ -671,30 +671,30 @@ void UpdateVRParams(float* projMatrix, float* viewMatrix) { variant += (up < 0) << 3; switch (variant) { - case 0: - case 1: + case 0: //e.g. ATV + case 1: //untested vrMirroring[VR_MIRRORING_PITCH] = false; vrMirroring[VR_MIRRORING_YAW] = true; vrMirroring[VR_MIRRORING_ROLL] = true; break; - case 2: - case 3: - case 5: - case 7: - case 8: - case 9: - case 10: - case 11: - case 13: - case 15: + case 2: //e.g.PES 2014 + case 3: //untested + case 5: //e.g Dante's Inferno + case 7: //untested + case 8: //untested + case 9: //untested + case 10: //untested + case 11: //untested + case 13: //untested + case 15: //untested vrMirroring[VR_MIRRORING_PITCH] = true; vrMirroring[VR_MIRRORING_YAW] = true; vrMirroring[VR_MIRRORING_ROLL] = false; break; - case 4: - case 6: - case 12: - case 14: + case 4: //e.g. Assassins Creed + case 6: //e.g. Ghost in the shell + case 12: //e.g. GTA Vice City + case 14: //untested vrMirroring[VR_MIRRORING_PITCH] = true; vrMirroring[VR_MIRRORING_YAW] = false; vrMirroring[VR_MIRRORING_ROLL] = true; From 32c0f19df639f43b98ea7fc7a8be066babb31473 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 10 Nov 2022 22:16:36 +0100 Subject: [PATCH 285/715] OpenXR - Freezing on Pico 4 fixed --- android/src/org/ppsspp/ppsspp/CameraHelper.java | 3 +++ android/src/org/ppsspp/ppsspp/NativeActivity.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/android/src/org/ppsspp/ppsspp/CameraHelper.java b/android/src/org/ppsspp/ppsspp/CameraHelper.java index d324d50819..9fdb270606 100644 --- a/android/src/org/ppsspp/ppsspp/CameraHelper.java +++ b/android/src/org/ppsspp/ppsspp/CameraHelper.java @@ -159,6 +159,9 @@ class CameraHelper { static ArrayList getDeviceList() { ArrayList deviceList = new ArrayList<>(); + if (NativeActivity.isVRDevice()) { + return deviceList; + } int nrCam = Camera.getNumberOfCameras(); for (int index = 0; index < nrCam; index++) { try { diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 8727f39dc3..07a80dae19 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -1557,7 +1557,7 @@ public abstract class NativeActivity extends Activity { } } - private boolean isVRDevice() { + public static boolean isVRDevice() { return BuildConfig.FLAVOR.startsWith("vr_"); } } From 46182990cf3731657bfe243c4eaa88576d41f3dc Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 7 Nov 2022 19:04:32 -0800 Subject: [PATCH 286/715] GPU: Hook US version of Marvel Alliance upload. See #9852. Appears to be the same basic func, but something resulted in a different hash. Register use for from/to seems the same. --- Core/MIPS/MIPSAnalyst.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 09e9771c34..353d7605d3 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -355,6 +355,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x9f269daa6f0da803, 128, "dl_write_scissor_region", }, { 0x9f7919eeb43982b0, 208, "__fixdfsi", }, { 0xa1c9b0a2c71235bf, 1752, "marvelalliance1_copy" }, // Marvel Ultimate Alliance 1 (EU) + { 0x9b76c7f2a41aa805, 1752, "marvelalliance1_copy" }, // Marvel Ultimate alliance 1 (US) { 0xa1ca0640f11182e7, 72, "strcspn", }, { 0xa243486be51ce224, 272, "cosf", }, { 0xa2bcef60a550a3ef, 92, "matrix_rot_z", }, From 50f709500290c171838b5ca1e26abcad93d4f206 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 11 Nov 2022 21:54:58 -0800 Subject: [PATCH 287/715] GPU: Correct Marvel copy hook size check. --- Core/HLE/ReplaceTables.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 3797e660e2..65461ff902 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -1271,10 +1271,12 @@ static u32 marvelalliance1_copy_size = 0; static int Hook_marvelalliance1_copy_a1_before() { marvelalliance1_copy_src = currentMIPS->r[MIPS_REG_A1]; marvelalliance1_copy_dst = currentMIPS->r[MIPS_REG_V1]; - marvelalliance1_copy_size = currentMIPS->r[MIPS_REG_V0] - currentMIPS->r[MIPS_REG_V1]; + marvelalliance1_copy_size = currentMIPS->r[MIPS_REG_V0] - currentMIPS->r[MIPS_REG_A1]; - gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); - NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a1_before"); + if (Memory::IsValidRange(marvelalliance1_copy_src, marvelalliance1_copy_size)) { + gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); + NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a1_before"); + } return 0; } @@ -1284,15 +1286,19 @@ static int Hook_marvelalliance1_copy_a2_before() { marvelalliance1_copy_dst = currentMIPS->r[MIPS_REG_V0]; marvelalliance1_copy_size = currentMIPS->r[MIPS_REG_A1] - currentMIPS->r[MIPS_REG_A2]; - gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); - NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a2_before"); + if (Memory::IsValidRange(marvelalliance1_copy_src, marvelalliance1_copy_size)) { + gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); + NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a2_before"); + } return 0; } static int Hook_marvelalliance1_copy_after() { - gpu->PerformWriteColorFromMemory(marvelalliance1_copy_dst, marvelalliance1_copy_size); - NotifyMemInfo(MemBlockFlags::READ, marvelalliance1_copy_dst, marvelalliance1_copy_size, "marvelalliance1_copy_after"); + if (Memory::IsValidRange(marvelalliance1_copy_dst, marvelalliance1_copy_size)) { + gpu->PerformWriteColorFromMemory(marvelalliance1_copy_dst, marvelalliance1_copy_size); + NotifyMemInfo(MemBlockFlags::READ, marvelalliance1_copy_dst, marvelalliance1_copy_size, "marvelalliance1_copy_after"); + } return 0; } From 3e5d77ab463c597fd000aecaff0b4e88ad273d0e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 12 Nov 2022 10:11:11 -0800 Subject: [PATCH 288/715] SaveState: Switch from deprecated is_pod. --- Common/Serialize/SerializeFuncs.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Common/Serialize/SerializeFuncs.h b/Common/Serialize/SerializeFuncs.h index 3080749fa3..0c89450c5d 100644 --- a/Common/Serialize/SerializeFuncs.h +++ b/Common/Serialize/SerializeFuncs.h @@ -33,11 +33,7 @@ void Do(PointerWrap &p, tm &t); // This makes it a compile error if you forget to define DoState() on non-POD. // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... -#ifdef _MSC_VER -template::value, bool isPointer = std::is_pointer::value> -#else -template::value> -#endif +template::value && std::is_trivial::value, bool isPointer = std::is_pointer::value> struct DoHelper_ { static void DoArray(PointerWrap &p, T *x, int count) { for (int i = 0; i < count; ++i) From 294d028dbfec7a422bcdbb642c21cf40f4f4cb02 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 12 Nov 2022 10:21:20 -0800 Subject: [PATCH 289/715] VR: Remove unnecessary deprecated header. --- Common/VR/VRFramebuffer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index c8bc44a972..f19c6a589c 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include From c20bcc1f08ea8546e54bd874ef3ada6bbc842899 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 12 Nov 2022 10:27:19 -0800 Subject: [PATCH 290/715] UI: Avoid enum/float comparisons. --- Common/UI/View.cpp | 6 +++--- Common/UI/View.h | 10 ++++------ Common/UI/ViewGroup.cpp | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 72d3443ab0..4ca46140a2 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -19,9 +19,9 @@ namespace UI { -const float ITEM_HEIGHT = 64.f; -const float MIN_TEXT_SCALE = 0.8f; -const float MAX_ITEM_SIZE = 65535.0f; +static constexpr Size ITEM_HEIGHT = 64.f; +static constexpr float MIN_TEXT_SCALE = 0.8f; +static constexpr float MAX_ITEM_SIZE = 65535.0f; void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured) { *measured = sz; diff --git a/Common/UI/View.h b/Common/UI/View.h index 0a78433073..6e29c6bdef 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -128,10 +128,10 @@ enum FocusDirection { FOCUS_NEXT_PAGE, }; -enum { - WRAP_CONTENT = -1, - FILL_PARENT = -2, -}; +typedef float Size; // can also be WRAP_CONTENT or FILL_PARENT. + +static constexpr Size WRAP_CONTENT = -1.0f; +static constexpr Size FILL_PARENT = -2.0f; // Gravity enum Gravity { @@ -174,8 +174,6 @@ enum class BorderStyle { ITEM_DOWN_BG, }; -typedef float Size; // can also be WRAP_CONTENT or FILL_PARENT. - enum Orientation { ORIENT_HORIZONTAL, ORIENT_VERTICAL, diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f4fb73ffa3..f90f0eb1a6 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -22,7 +22,7 @@ namespace UI { -const float ITEM_HEIGHT = 64.f; +static constexpr Size ITEM_HEIGHT = 64.f; void ApplyGravity(const Bounds outer, const Margins &margins, float w, float h, int gravity, Bounds &inner) { inner.w = w; From 98758573e305fb9fe13850533f72b241861abe59 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 12 Nov 2022 17:30:00 -0800 Subject: [PATCH 291/715] GPU: Convert alphamask to FF/00 for 5551. When masking via uniform, we don't care about the lower bits of alpha. Games often use 7F / 80 to control writes of FF/00. --- GPU/Common/GPUStateUtils.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index f168fa1920..f902330528 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -1070,6 +1070,15 @@ static void ConvertMaskState(GenericMaskState &maskState, bool shaderBitOpsSuppo maskState.channelMask &= ~8; maskState.uniformMask &= ~0xFF000000; } + + // For 5551, only the top alpha bit matters. We might even want to swizzle 4444. + // Alpha should correctly read as 255 from a 5551 texture. + if (gstate.FrameBufFormat() == GE_FORMAT_5551) { + if ((maskState.uniformMask & 0x80000000) != 0) + maskState.uniformMask |= 0xFF000000; + else + maskState.uniformMask &= ~0xFF000000; + } } // Called even if AlphaBlendEnable == false - it also deals with stencil-related blend state. From 66668d4b3f409ca84a7c4a9b26652c02d1cb0abc Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 12 Nov 2022 17:31:41 -0800 Subject: [PATCH 292/715] Vulkan: Correct alpha in Adreno workaround. --- GPU/Vulkan/StateMappingVulkan.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 5f75ea2863..90d57abd9c 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -209,10 +209,11 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && g_Config.bVendorBugChecksEnabled && draw_->GetBugs().Has(Draw::Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST)) { key.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; if (!key.blendEnable) { + bool writeAlpha = maskState.channelMask & 8; key.blendEnable = true; key.blendOpAlpha = VK_BLEND_OP_ADD; - key.srcAlpha = VK_BLEND_FACTOR_ZERO; - key.destAlpha = VK_BLEND_FACTOR_ONE; + key.srcAlpha = writeAlpha ? VK_BLEND_FACTOR_ONE : VK_BLEND_FACTOR_ZERO; + key.destAlpha = writeAlpha ? VK_BLEND_FACTOR_ZERO : VK_BLEND_FACTOR_ONE; } key.blendOpColor = VK_BLEND_OP_ADD; key.srcColor = VK_BLEND_FACTOR_ZERO; From 3f875af2d71aac18a77f08b871b23a05ad9fb849 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 12 Nov 2022 17:36:37 -0800 Subject: [PATCH 293/715] Vulkan: Mark Adreno bug resolved on recent driver. Playing it safe for 5xx devices and assuming they are still affected. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 167175be95..f055ad9499 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -835,7 +835,9 @@ VKContext::VKContext(VulkanContext *vulkan) } // Color write mask not masking write in certain scenarios with a depth test, see #10421. // Known still present on driver 0x80180000 and Adreno 5xx (possibly more.) - bugs_.Infest(Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST); + // Known working on driver 0x801EA000 and Adreno 620. + if (deviceProps.driverVersion < 0x801EA000 || deviceProps.deviceID < 0x06000000) + bugs_.Infest(Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST); // Trying to follow all the rules in https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies // and https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#renderpass-feedbackloop, but still it doesn't From eae85836c9eedb0d8cf5e910af5b98d3bff0ca57 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 12 Nov 2022 20:01:46 -0800 Subject: [PATCH 294/715] GPU: Add a small error-compensation to depth clip. This was causing a depth that should've calculated as zero to be clipped, because the multiply and division resulted in a value that was off by about 2 / pow(2, 24) in the negative direction. --- GPU/Common/GeometryShaderGenerator.cpp | 6 ++++-- GPU/Common/VertexShaderGenerator.cpp | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index 12bf25a550..8c24fa9731 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -123,7 +123,8 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // This is basically the same value as gl_ClipDistance would take, z + w. if (vertexRangeCulling) { - p.C(" clip0[i] = projZ * outPos.w + outPos.w;\n"); + // We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.) + p.F(" clip0[i] = projZ * outPos.w + outPos.w + %f;\n", 0.0625 / 65536.0); } else { // Let's not complicate the code overly for this case. We'll clipClampedDepth. p.C(" clip0[i] = 0.0;\n"); @@ -290,7 +291,8 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix1); } else { // We shouldn't need to worry about rectangles-as-triangles here, since we don't use geometry shaders for that. - p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix0); + // We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.) + p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w + %f;\n", clipSuffix0, 0.0625 / 65536.0); } p.C(" gl_Position = outPos;\n"); if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 70fc803dd1..57e5e9675f 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1328,7 +1328,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]"; if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z. - WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", compat.vsOutPrefix, vertexRangeClipSuffix); + // We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.) + WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w + %f;\n", compat.vsOutPrefix, vertexRangeClipSuffix, 0.0625 / 65536.0); } if (gstate_c.Use(GPU_USE_CULL_DISTANCE)) { // Cull any triangle fully outside in the same direction when depth clamp enabled. From 4a367148e6e97f3a47f1393671995ff2515e914b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 08:04:47 -0800 Subject: [PATCH 295/715] GPU: Centralize more GPU_USE flags, like depth. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + GPU/D3D11/GPU_D3D11.cpp | 14 +---------- GPU/Directx9/GPU_DX9.cpp | 14 +---------- GPU/GLES/GPU_GLES.cpp | 40 +++++++++---------------------- GPU/GPUCommon.cpp | 29 ++++++++++++++++++++++ GPU/GPUCommon.h | 3 +++ GPU/Vulkan/GPU_Vulkan.cpp | 31 +++++------------------- 7 files changed, 52 insertions(+), 80 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 428e86fdb3..46713b53f3 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -261,6 +261,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.framebufferStencilBlitSupported = false; caps_.framebufferDepthCopySupported = true; caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw. + caps_.preferredDepthBufferFormat = DataFormat::D24_S8; caps_.textureDepthSupported = true; caps_.texture3DSupported = true; caps_.fragmentShaderInt32Supported = true; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 90fb480155..93793165ac 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -105,12 +105,8 @@ u32 GPU_D3D11::CheckGPUFeatures() const { // Accurate depth is required because the Direct3D API does not support inverse Z. // So we cannot incorrectly use the viewport transform as the depth range on Direct3D. - // TODO: Breaks text in PaRappa for some reason? features |= GPU_USE_ACCURATE_DEPTH; - if (draw_->GetDeviceCaps().depthClampSupported) - features |= GPU_USE_DEPTH_CLAMP; - features |= GPU_USE_TEXTURE_FLOAT; features |= GPU_USE_INSTANCE_RENDERING; features |= GPU_USE_TEXTURE_LOD_CONTROL; @@ -122,20 +118,12 @@ u32 GPU_D3D11::CheckGPUFeatures() const { features |= GPU_USE_16BIT_FORMATS; } - if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - // The Phantasy Star hack :( if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_USE_ACCURATE_DEPTH) == 0) { features |= GPU_USE_DEPTH_RANGE_HACK; } - return features; + return CheckGPUFeaturesLate(features); } // Needs to be called on GPU thread, not reporting thread. diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index beb701796a..6d8926e0fe 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -105,21 +105,9 @@ u32 GPU_DX9::CheckGPUFeatures() const { // Accurate depth is required because the Direct3D API does not support inverse Z. // So we cannot incorrectly use the viewport transform as the depth range on Direct3D. - // TODO: Breaks text in PaRappa for some reason? features |= GPU_USE_ACCURATE_DEPTH; - auto vendor = draw_->GetDeviceCaps().vendor; - - if (!g_Config.bHighQualityDepth) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - // Assume we always have a 24-bit depth buffer. - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - - return features; + return CheckGPUFeaturesLate(features); } GPU_DX9::~GPU_DX9() { diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 8b71b2dce1..018cd0b6c5 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -173,35 +173,6 @@ u32 GPU_GLES::CheckGPUFeatures() const { if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float) features |= GPU_USE_TEXTURE_FLOAT; - if (draw_->GetDeviceCaps().depthClampSupported) { - features |= GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH; - // Our implementation of depth texturing needs simple Z range, so can't - // use the extension hacks (yet). - } - - // If we already have a 16-bit depth buffer, we don't need to round. - bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; - bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16; - if (!prefer16) { - if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { - // Here we can simulate a 16 bit depth buffer by scaling. - // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (!gl_extensions.IsGLES || gl_extensions.GLES3) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } else { - // At least do vertex rounding if nothing else. - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - } - // The Phantasy Star hack :( if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_USE_ACCURATE_DEPTH) == 0) { features |= GPU_USE_DEPTH_RANGE_HACK; @@ -218,6 +189,17 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_USE_SINGLE_PASS_STEREO; } + features = CheckGPUFeaturesLate(features); + + // This is a bit ugly, but lets us reuse most of the depth logic in GPUCommon. + if (features & GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT) { + if (gl_extensions.IsGLES && !gl_extensions.GLES3) { + // Unsupported, switch to GPU_ROUND_DEPTH_TO_16BIT instead. + features &= ~GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + features |= GPU_ROUND_DEPTH_TO_16BIT; + } + } + return features; } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 17de04fc52..67bd4566dc 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3336,6 +3336,11 @@ u32 GPUCommon::CheckGPUFeatures() const { features |= GPU_USE_DEPTH_TEXTURE; } + if (draw_->GetDeviceCaps().depthClampSupported) { + // Some backends always do GPU_USE_ACCURATE_DEPTH, but it's required for depth clamp. + features |= GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH; + } + bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported; bool canDiscardVertex = draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL); if (canClipOrCull || canDiscardVertex) { @@ -3357,3 +3362,27 @@ u32 GPUCommon::CheckGPUFeatures() const { return features; } + +u32 GPUCommon::CheckGPUFeaturesLate(u32 features) const { + // If we already have a 16-bit depth buffer, we don't need to round. + bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; + bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16; + if (!prefer16) { + if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { + if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + // Here we can simulate a 16 bit depth buffer by scaling. + // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else { + // Use fragment rounding on where available otherwise. + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } + } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { + features |= GPU_ROUND_DEPTH_TO_16BIT; + } + } + + return features; +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 8823a52715..39519495c8 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -262,6 +262,9 @@ protected: void DeviceLost() override; void DeviceRestore() override; + // Add additional common features dependent on other features, which may be backend-determined. + u32 CheckGPUFeaturesLate(u32 features) const; + inline bool IsTrianglePrim(GEPrimitiveType prim) const { return prim != GE_PRIM_RECTANGLES && prim > GE_PRIM_LINE_STRIP; } diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 17387c3e8b..4232e3f526 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -207,12 +207,16 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || driverTooOld) { features |= GPU_USE_ACCURATE_DEPTH; + } else { + features &= ~GPU_USE_ACCURATE_DEPTH; } break; } default: if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { features |= GPU_USE_ACCURATE_DEPTH; + } else { + features &= ~GPU_USE_ACCURATE_DEPTH; } break; } @@ -227,13 +231,8 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { features |= GPU_USE_VERTEX_TEXTURE_FETCH; features |= GPU_USE_TEXTURE_FLOAT; - auto &enabledFeatures = vulkan->GetDeviceFeatures().enabled.standard; - if (enabledFeatures.depthClamp) { - features |= GPU_USE_DEPTH_CLAMP; - } - // Fall back to geometry shader culling if we can't do vertex range culling. - if (enabledFeatures.geometryShader) { + if (draw_->GetDeviceCaps().geometryShaderSupported) { const bool useGeometry = g_Config.bUseGeometryShader && !draw_->GetBugs().Has(Draw::Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN); const bool vertexSupported = draw_->GetDeviceCaps().clipDistanceSupported && draw_->GetDeviceCaps().cullDistanceSupported; if (useGeometry && (!vertexSupported || (features & GPU_USE_VS_RANGE_CULLING) == 0)) { @@ -257,24 +256,6 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { INFO_LOG(G3D, "Deficient texture format support: 4444: %d 1555: %d 565: %d", fmt4444, fmt1555, fmt565); } - bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; - bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16; - if (!prefer16) { - if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { - // Here we can simulate a 16 bit depth buffer by scaling. - // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else { - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - } - if (g_Config.bStereoRendering && draw_->GetDeviceCaps().multiViewSupported) { features |= GPU_USE_SINGLE_PASS_STEREO; features |= GPU_USE_SIMPLE_STEREO_PERSPECTIVE; @@ -287,7 +268,7 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { } } - return features; + return CheckGPUFeaturesLate(features); } void GPU_Vulkan::BeginHostFrame() { From 01d7d73438ed3699cc8435271f72e3a86aa76db0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 08:09:57 -0800 Subject: [PATCH 296/715] GPU: Remove unused GPU_USE flag. --- GPU/GLES/GPU_GLES.cpp | 3 --- GPU/GPUState.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 018cd0b6c5..16f6ad611e 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -154,9 +154,6 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_USE_16BIT_FORMATS; - if ((gl_extensions.gpuVendor == GPU_VENDOR_NVIDIA) || (gl_extensions.gpuVendor == GPU_VENDOR_AMD)) - features |= GPU_USE_REVERSE_COLOR_ORDER; - if (gl_extensions.GLES3 || !gl_extensions.IsGLES) features |= GPU_USE_TEXTURE_LOD_CONTROL; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 16df77c61d..d7b25ac911 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -490,7 +490,7 @@ enum { GPU_USE_DEPTH_TEXTURE = FLAG_BIT(16), GPU_USE_ACCURATE_DEPTH = FLAG_BIT(17), GPU_USE_GS_CULLING = FLAG_BIT(18), // Geometry shader - GPU_USE_REVERSE_COLOR_ORDER = FLAG_BIT(19), + // Bit 19 free. GPU_USE_FRAMEBUFFER_FETCH = FLAG_BIT(20), GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), From aac2faa674edbd2a66a9332ff023883132405e9a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 08:13:22 -0800 Subject: [PATCH 297/715] GPU: Automatically reduce depth range on == test. Fixes graphic issues in Blade Dancer, possibly other games. --- GPU/Common/DrawEngineCommon.h | 9 +++++++++ GPU/GPUCommon.cpp | 14 +++++++++++++- GPU/GPUCommon.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 8d6917fd6a..c5ac193c4c 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -107,6 +107,10 @@ public: virtual void NotifyConfigChanged(); + bool EverUsedExactEqualDepth() const { + return everUsedExactEqualDepth_; + } + bool IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } @@ -148,6 +152,10 @@ protected: inline void UpdateEverUsedEqualDepth(GEComparison comp) { switch (comp) { case GE_COMP_EQUAL: + everUsedExactEqualDepth_ = true; + everUsedEqualDepth_ = true; + break; + case GE_COMP_NOTEQUAL: case GE_COMP_LEQUAL: case GE_COMP_GEQUAL: @@ -166,6 +174,7 @@ protected: // Set once a equal depth test is encountered. bool everUsedEqualDepth_ = false; + bool everUsedExactEqualDepth_ = false; // Vertex collector buffers u8 *decoded = nullptr; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 67bd4566dc..9406429e58 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1188,6 +1188,11 @@ void GPUCommon::BeginFrame() { } GPUDebug::NotifyBeginFrame(); GPURecord::NotifyBeginFrame(); + + if (drawEngineCommon_->EverUsedExactEqualDepth() && !sawExactEqualDepth_) { + sawExactEqualDepth_ = true; + gstate_c.useFlags = CheckGPUFeatures(); + } } void GPUCommon::SlowRunLoop(DisplayList &list) @@ -3368,7 +3373,14 @@ u32 GPUCommon::CheckGPUFeaturesLate(u32 features) const { bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16; if (!prefer16) { - if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + if (sawExactEqualDepth_ && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + // Exact equal tests tend to have issues unless we use the PSP's depth range. + // We use 24-bit depth virtually everwhere, the fallback is just for safety. + if (prefer24) + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + else + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } else if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 39519495c8..fc2cd13888 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -356,6 +356,7 @@ protected: bool debugRecording_; bool interruptsEnabled_; bool resized_ = false; + bool sawExactEqualDepth_ = false; DrawType lastDraw_ = DRAW_UNKNOWN; GEPrimitiveType lastPrim_ = GE_PRIM_INVALID; From 21064edfca4f8299b4e288ef6f190240be12620e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 09:17:29 -0800 Subject: [PATCH 298/715] softgpu: Correct tex on fogged rectangles. --- GPU/Software/Clipper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index e9ad7ec5b4..11db812e1a 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -208,10 +208,13 @@ void ProcessRect(const ClipVertexData &v0, const ClipVertexData &v1, BinManager // TODO: Check exactness of middle. VertexData vhalf0 = v1.v; vhalf0.screenpos.x = v0.v.screenpos.x + (v1.v.screenpos.x - v0.v.screenpos.x) / 2; + vhalf0.texturecoords.x = v0.v.texturecoords.x + (v1.v.texturecoords.x - v0.v.texturecoords.x) / 2; VertexData vhalf1 = v1.v; vhalf1.screenpos.x = v0.v.screenpos.x + (v1.v.screenpos.x - v0.v.screenpos.x) / 2; vhalf1.screenpos.y = v0.v.screenpos.y; + vhalf1.texturecoords.x = v0.v.texturecoords.x + (v1.v.texturecoords.x - v0.v.texturecoords.x) / 2; + vhalf1.texturecoords.y = v0.v.texturecoords.y; VertexData vrev1 = v1.v; vrev1.fogdepth = v0.v.fogdepth; From a66056217fe548d7a84d90d95c59d14a02c41fd3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 09:23:06 -0800 Subject: [PATCH 299/715] softgpu: Avoid splitting rectangles for fog. If the fog factor would result in the same amount of fog, we're just adding more work for no reason. --- GPU/Software/Clipper.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index 11db812e1a..bae2be1881 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -203,7 +203,15 @@ void ProcessRect(const ClipVertexData &v0, const ClipVertexData &v1, BinManager else if (outsidePos >= 2 || outsideNeg >= 2) return; - if (v0.v.fogdepth != v1.v.fogdepth) { + bool splitFog = v0.v.fogdepth != v1.v.fogdepth; + if (splitFog) { + // If they match the same 1/255, we can consider the fog flat. Seen in Resistance. + // More efficient if we can avoid splitting. + static constexpr float foghalfstep = 0.5f / 255.0f; + if (v1.v.fogdepth - foghalfstep <= v0.v.fogdepth && v1.v.fogdepth + foghalfstep >= v0.v.fogdepth) + splitFog = false; + } + if (splitFog) { // Rectangles seem to always use nearest along X for fog depth, but reversed. // TODO: Check exactness of middle. VertexData vhalf0 = v1.v; From d8716b5d905208d5742c491d033040077e9ea8f5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 10:22:09 -0800 Subject: [PATCH 300/715] softgpu: Fix off-by-one rendering after half-pixel. If the X is after a half-pixel offset, the first pixel we draw is the next one. This wasn't being accounted for properly in one place. --- GPU/Software/Rasterizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index e6d4a5a84f..d86a4447ef 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -893,7 +893,7 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & #endif for (int64_t curY = minY; curY <= maxY; curY += SCREEN_SCALE_FACTOR * 2, rowST += sty) { - DrawingCoords p = TransformUnit::ScreenToDrawing(range.x1, curY); + DrawingCoords p = TransformUnit::ScreenToDrawing(minX, curY); int scissorY2 = curY + SCREEN_SCALE_FACTOR > maxY ? -1 : 0; Vec4 scissor_mask = Vec4(0, maxX - minX - SCREEN_SCALE_FACTOR, scissorY2, (maxX - minX - SCREEN_SCALE_FACTOR) | scissorY2); From db400bd31255c63130febcad4f94908915ddbb76 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 10:49:02 -0800 Subject: [PATCH 301/715] UI: Show standard back button on touch layout. This is a bit less wide, but uses common logic to render. Some are experiencing no left buttons on this screen, so this is a bit of an experiment as well as making the UI more consistent. --- UI/TouchControlLayoutScreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index b52b09f7a8..5b9b24aed0 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -620,7 +620,7 @@ void TouchControlLayoutScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10))); + ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 84))); LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); mode_ = new ChoiceStrip(ORIENT_VERTICAL); @@ -638,7 +638,7 @@ void TouchControlLayoutScreen::CreateViews() { leftColumn->Add(snap); leftColumn->Add(gridSize); leftColumn->Add(new Choice(di->T("Reset")))->OnClick.Handle(this, &TouchControlLayoutScreen::OnReset); - leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); + AddStandardBack(root_); root_->Add(new BorderView(BORDER_BOTTOM, BorderStyle::ITEM_DOWN_BG, 4.0f, new AnchorLayoutParams(leftColumnWidth + 10, bounds.h * (1.0f - layoutAreaScale), 0.0f, NONE, false))); root_->Add(new BorderView(BORDER_RIGHT, BorderStyle::ITEM_DOWN_BG, 4.0f, new AnchorLayoutParams(leftColumnWidth + 10, 0.0f, NONE, 0.0f, false))); From 7e7eabf86acb3f7fd334695731a9b2a855b09bc5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 12:34:31 -0800 Subject: [PATCH 302/715] softgpu: Use threads on self-render if safe. Some games, such as Prince of Persia, self-render 1:1 to colorize, rather than to scale or blur. We can still use threads in these cases. --- GPU/Software/BinManager.cpp | 52 +++++++++++++++++++++++++++++++++++-- GPU/Software/BinManager.h | 1 + 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 9a008e6658..6bd1e0abc8 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -27,6 +27,9 @@ #include "GPU/Software/Rasterizer.h" #include "GPU/Software/RasterizerRectangle.h" +// Sometimes useful for debugging. +static constexpr bool FORCE_SINGLE_THREAD = false; + using namespace Rasterizer; struct BinWaitable : public Waitable { @@ -215,7 +218,7 @@ void BinManager::UpdateState() { // Disallow threads when rendering to the target, even offset. bool selfRender = HasTextureWrite(state); - int newMaxTasks = selfRender ? 1 : g_threadManager.GetNumLooperThreads(); + int newMaxTasks = selfRender || FORCE_SINGLE_THREAD ? 1 : g_threadManager.GetNumLooperThreads(); if (newMaxTasks > MAX_POSSIBLE_TASKS) newMaxTasks = MAX_POSSIBLE_TASKS; // We don't want to overlap wrong, so flush any pending. @@ -254,6 +257,40 @@ bool BinManager::HasTextureWrite(const RasterizerState &state) { return false; } +bool BinManager::IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item) { + if (item.type != BinItemType::SPRITE && item.type != BinItemType::RECT) + return false; + if (state.textureProj || state.maxTexLevel > 0) + return false; + + // Only possible if the texture is 1:1. + if ((state.texaddr[0] & 0x0F1FFFFF) != (gstate.getFrameBufAddress() & 0x0F1FFFFF)) + return false; + int bufferPixelWidth = BufferFormatBytesPerPixel(state.pixelID.FBFormat()); + int texturePixelWidth = textureBitsPerPixel[state.samplerID.texfmt] / 8; + if (bufferPixelWidth != texturePixelWidth) + return false; + + Vec4f tc = Vec4f(item.v0.texturecoords.x, item.v0.texturecoords.y, item.v1.texturecoords.x, item.v1.texturecoords.y); + if (state.throughMode) { + // Already at texels, convert to screen. + tc = tc * SCREEN_SCALE_FACTOR; + } else { + // Need to also multiply by width/height in transform mode. + int w = state.samplerID.cached.sizes[0].w * SCREEN_SCALE_FACTOR; + int h = state.samplerID.cached.sizes[0].h * SCREEN_SCALE_FACTOR; + tc = tc * Vec4f(w, h, w, h); + } + + Vec4 tci = tc.Cast(); + if (tci.x != item.v0.screenpos.x || tci.y != item.v0.screenpos.y) + return false; + if (tci.z != item.v1.screenpos.x || tci.w != item.v1.screenpos.y) + return false; + + return true; +} + void BinManager::MarkPendingReads(const Rasterizer::RasterizerState &state) { if (!state.enableTextures) return; @@ -418,6 +455,14 @@ void BinManager::Drain(bool flushing) { ScreenCoords tl(0, 0, 0); ScreenCoords br(1024 * SCREEN_SCALE_FACTOR, 1024 * SCREEN_SCALE_FACTOR, 0); + if (pendingOverlap_ && maxTasks_ == 1 && flushing && queue_.Size() == 1 && !FORCE_SINGLE_THREAD) { + // If the drawing is 1:1, we can potentially use threads. It's worth checking. + const auto &item = queue_.PeekNext(); + const auto &state = states_[item.stateIndex]; + if (IsExactSelfRender(state, item)) + maxTasks_ = std::min(g_threadManager.GetNumLooperThreads(), MAX_POSSIBLE_TASKS); + } + taskRanges_.clear(); if (h2 >= 18 && w2 >= h2 * 4) { int bin_w = std::max(4, (w2 + maxTasks_ - 1) / maxTasks_) * SCREEN_SCALE_FACTOR * 2; @@ -681,6 +726,9 @@ void BinManager::Expand(const BinCoords &range) { queueRange_.y2 = std::max(queueRange_.y2, range.y2); if (maxTasks_ == 1 || (queueRange_.y2 - queueRange_.y1 >= 224 * SCREEN_SCALE_FACTOR && enqueues_ < 36 * maxTasks_)) { - Drain(); + if (pendingOverlap_) + Flush("expand"); + else + Drain(); } } diff --git a/GPU/Software/BinManager.h b/GPU/Software/BinManager.h index d874f0d3c8..3dd36d83a9 100644 --- a/GPU/Software/BinManager.h +++ b/GPU/Software/BinManager.h @@ -273,6 +273,7 @@ private: void MarkPendingReads(const Rasterizer::RasterizerState &state); void MarkPendingWrites(const Rasterizer::RasterizerState &state); bool HasTextureWrite(const Rasterizer::RasterizerState &state); + bool IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item); BinCoords Scissor(BinCoords range); BinCoords Range(const VertexData &v0, const VertexData &v1, const VertexData &v2); BinCoords Range(const VertexData &v0, const VertexData &v1); From 9482578fbb2a942579558b06a965d3a615cbd29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 13 Nov 2022 23:16:09 +0100 Subject: [PATCH 303/715] Twinbee Portable: Add config flag to avoid the system languages the game doesn't work with --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + Core/HLE/sceImpose.cpp | 6 ++++++ Core/HLE/sceUtility.cpp | 5 +++++ assets/compat.ini | 6 ++++++ 5 files changed, 19 insertions(+) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index b09eb67c14..d3d65861e0 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -119,6 +119,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "AllowDownloadCLUT", &flags_.AllowDownloadCLUT); CheckSetting(iniFile, gameID, "NearestFilteringOnFramebufferCreate", &flags_.NearestFilteringOnFramebufferCreate); CheckSetting(iniFile, gameID, "SecondaryTextureCache", &flags_.SecondaryTextureCache); + CheckSetting(iniFile, gameID, "EnglishOrJapaneseOnly", &flags_.EnglishOrJapaneseOnly); } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 86d139a536..6755afe7a9 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -90,6 +90,7 @@ struct CompatFlags { bool AllowDownloadCLUT; bool NearestFilteringOnFramebufferCreate; bool SecondaryTextureCache; + bool EnglishOrJapaneseOnly; }; struct VRCompat { diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index 086cc83c17..bd5f654bc2 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -24,6 +24,7 @@ #include "Core/MIPS/MIPS.h" #include "Core/Config.h" #include "Core/MemMap.h" +#include "Core/System.h" const int PSP_UMD_POPUP_DISABLE = 0; const int PSP_UMD_POPUP_ENABLE = 1; @@ -40,6 +41,11 @@ static u32 backlightOffTime; void __ImposeInit() { language = g_Config.iLanguage; + if (PSP_CoreParameter().compat.flags().EnglishOrJapaneseOnly) { + if (language != PSP_SYSTEMPARAM_LANGUAGE_ENGLISH && language != PSP_SYSTEMPARAM_LANGUAGE_JAPANESE) { + language = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; + } + } buttonValue = g_Config.iButtonPreference; umdPopup = PSP_UMD_POPUP_DISABLE; backlightOffTime = 0; diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index b205ed956d..35db8740fa 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -886,6 +886,11 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) break; case PSP_SYSTEMPARAM_ID_INT_LANGUAGE: param = g_Config.iLanguage; + if (PSP_CoreParameter().compat.flags().EnglishOrJapaneseOnly) { + if (param != PSP_SYSTEMPARAM_LANGUAGE_ENGLISH && param != PSP_SYSTEMPARAM_LANGUAGE_JAPANESE) { + param = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; + } + } break; case PSP_SYSTEMPARAM_ID_INT_BUTTON_PREFERENCE: param = g_Config.iButtonPreference; diff --git a/assets/compat.ini b/assets/compat.ini index 7a1ac5d79f..425164cf58 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1264,3 +1264,9 @@ ULES00850 = true ULUS10297 = true ULJM05516 = true NPJH50408 = true + +[EnglishOrJapaneseOnly] +# Twinbee Portable, see issue #16382 +ULAS42089 = true +ULJM05221 = true +ULJM05323 = true \ No newline at end of file From b0b03af50dd17ee7bb9358f368d04c326db139e0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 16:01:13 -0800 Subject: [PATCH 304/715] Debugger: Keep flag for any breakpoints. Oops, only had these checks for memchecks before. --- Core/Debugger/Breakpoints.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index ad1d37e41d..9ab4bc4901 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -31,6 +31,7 @@ #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/CoreTiming.h" +std::atomic anyBreakPoints_(false); std::atomic anyMemChecks_(false); static std::mutex breakPointsMutex_; @@ -160,6 +161,8 @@ size_t CBreakPoints::FindMemCheck(u32 start, u32 end) bool CBreakPoints::IsAddressBreakPoint(u32 addr) { + if (!anyBreakPoints_) + return false; std::lock_guard guard(breakPointsMutex_); size_t bp = FindBreakpoint(addr); return bp != INVALID_BREAKPOINT && breakPoints_[bp].result != BREAK_ACTION_IGNORE; @@ -167,6 +170,8 @@ bool CBreakPoints::IsAddressBreakPoint(u32 addr) bool CBreakPoints::IsAddressBreakPoint(u32 addr, bool* enabled) { + if (!anyBreakPoints_) + return false; std::lock_guard guard(breakPointsMutex_); size_t bp = FindBreakpoint(addr); if (bp == INVALID_BREAKPOINT) return false; @@ -184,6 +189,8 @@ bool CBreakPoints::IsTempBreakPoint(u32 addr) bool CBreakPoints::RangeContainsBreakPoint(u32 addr, u32 size) { + if (!anyBreakPoints_) + return false; std::lock_guard guard(breakPointsMutex_); const u32 end = addr + size; for (const auto &bp : breakPoints_) @@ -207,6 +214,7 @@ void CBreakPoints::AddBreakPoint(u32 addr, bool temp) pt.addr = addr; breakPoints_.push_back(pt); + anyBreakPoints_ = true; guard.unlock(); Update(addr); } @@ -232,6 +240,7 @@ void CBreakPoints::RemoveBreakPoint(u32 addr) if (bp != INVALID_BREAKPOINT) breakPoints_.erase(breakPoints_.begin() + bp); + anyBreakPoints_ = !breakPoints_.empty(); guard.unlock(); Update(addr); } @@ -267,6 +276,8 @@ void CBreakPoints::ChangeBreakPoint(u32 addr, BreakAction result) void CBreakPoints::ClearAllBreakPoints() { + if (!anyBreakPoints_) + return; std::unique_lock guard(breakPointsMutex_); if (!breakPoints_.empty()) { @@ -278,9 +289,9 @@ void CBreakPoints::ClearAllBreakPoints() void CBreakPoints::ClearTemporaryBreakPoints() { - std::unique_lock guard(breakPointsMutex_); - if (breakPoints_.empty()) + if (!anyBreakPoints_) return; + std::unique_lock guard(breakPointsMutex_); bool update = false; for (int i = (int)breakPoints_.size()-1; i >= 0; --i) @@ -342,6 +353,8 @@ void CBreakPoints::ChangeBreakPointLogFormat(u32 addr, const std::string &fmt) { } BreakAction CBreakPoints::ExecBreakPoint(u32 addr) { + if (!anyBreakPoints_) + return BREAK_ACTION_IGNORE; std::unique_lock guard(breakPointsMutex_); size_t bp = FindBreakpoint(addr, false); if (bp != INVALID_BREAKPOINT) { From 1662bd3bb80c1c278370993ac5f38f45f7048fde Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 16:03:29 -0800 Subject: [PATCH 305/715] interp: Allow resume from breakpoint. --- Core/MIPS/MIPSTables.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 6a411f42ba..08deea9e83 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -976,8 +976,7 @@ int MIPSInterpret_RunUntil(u64 globalTicks) //2: check for breakpoint (VERY SLOW) #if defined(_DEBUG) - if (CBreakPoints::IsAddressBreakPoint(curMips->pc)) - { + if (CBreakPoints::IsAddressBreakPoint(curMips->pc) && CBreakPoints::CheckSkipFirst() != curMips->pc) { auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); if (!cond || cond->Evaluate()) { From 76cf4dbf1296dc9e2704939187dad1f823487950 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 16:48:16 -0800 Subject: [PATCH 306/715] interp: Allow breakpoints in release mode. --- Core/Debugger/Breakpoints.cpp | 10 ++- Core/Debugger/Breakpoints.h | 1 + Core/MIPS/MIPSTables.cpp | 137 ++++++++++++++++++++-------------- 3 files changed, 90 insertions(+), 58 deletions(-) diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 9ab4bc4901..5ce977ec45 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -646,10 +646,12 @@ const std::vector CBreakPoints::GetBreakpoints() return breakPoints_; } -bool CBreakPoints::HasMemChecks() -{ - std::lock_guard guard(memCheckMutex_); - return !memChecks_.empty(); +bool CBreakPoints::HasBreakPoints() { + return anyBreakPoints_; +} + +bool CBreakPoints::HasMemChecks() { + return anyMemChecks_; } void CBreakPoints::Update(u32 addr) { diff --git a/Core/Debugger/Breakpoints.h b/Core/Debugger/Breakpoints.h index c2a7d81b6a..9f1a575118 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -167,6 +167,7 @@ public: static const std::vector GetMemChecks(); static const std::vector GetBreakpoints(); + static bool HasBreakPoints(); static bool HasMemChecks(); static void Update(u32 addr = 0); diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 08deea9e83..48182a37b5 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -938,8 +938,7 @@ void MIPSDisAsm(MIPSOpcode op, u32 pc, char *out, bool tabsToSpaces) { } } -void MIPSInterpret(MIPSOpcode op) { - const MIPSInstruction *instr = MIPSGetInstruction(op); +static inline void Interpret(const MIPSInstruction *instr, MIPSOpcode op) { if (instr && instr->interpret) { instr->interpret(op); } else { @@ -947,69 +946,99 @@ void MIPSInterpret(MIPSOpcode op) { // Try to disassemble it char disasm[256]; MIPSDisAsm(op, currentMIPS->pc, disasm); - _dbg_assert_msg_( 0, "%s", disasm); + _dbg_assert_msg_(0, "%s", disasm); currentMIPS->pc += 4; } } +inline int GetInstructionCycleEstimate(const MIPSInstruction *instr) { + if (instr) + return instr->flags.cycles; + return 1; +} + +void MIPSInterpret(MIPSOpcode op) { + const MIPSInstruction *instr = MIPSGetInstruction(op); + Interpret(instr, op); +} + #define _RS ((op>>21) & 0x1F) #define _RT ((op>>16) & 0x1F) #define _RD ((op>>11) & 0x1F) #define R(i) (curMips->r[i]) - -int MIPSInterpret_RunUntil(u64 globalTicks) -{ +static inline void RunUntilFast() { MIPSState *curMips = currentMIPS; - while (coreState == CORE_RUNNING) - { + // NEVER stop in a delay slot! + while (curMips->downcount >= 0 && coreState == CORE_RUNNING) { + do { + // Replacements and similar are processed here, intentionally. + MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); + + bool wasInDelaySlot = curMips->inDelaySlot; + const MIPSInstruction *instr = MIPSGetInstruction(op); + Interpret(instr, op); + curMips->downcount -= GetInstructionCycleEstimate(instr); + + // The reason we have to check this is the delay slot hack in Int_Syscall. + if (curMips->inDelaySlot && wasInDelaySlot) { + curMips->pc = curMips->nextPC; + curMips->inDelaySlot = false; + } + } while (curMips->inDelaySlot); + } +} + +static void RunUntilWithChecks(u64 globalTicks) { + MIPSState *curMips = currentMIPS; + // NEVER stop in a delay slot! + while (curMips->downcount >= 0 && coreState == CORE_RUNNING) { + do { + // Replacements and similar are processed here, intentionally. + MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); + + // Check for breakpoint + if (CBreakPoints::IsAddressBreakPoint(curMips->pc) && CBreakPoints::CheckSkipFirst() != curMips->pc) { + auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); + if (!cond || cond->Evaluate()) { + Core_EnableStepping(true, "cpu.breakpoint", curMips->pc); + if (CBreakPoints::IsTempBreakPoint(curMips->pc)) + CBreakPoints::RemoveBreakPoint(curMips->pc); + break; + } + } + + bool wasInDelaySlot = curMips->inDelaySlot; + const MIPSInstruction *instr = MIPSGetInstruction(op); + Interpret(instr, op); + curMips->downcount -= GetInstructionCycleEstimate(instr); + + // The reason we have to check this is the delay slot hack in Int_Syscall. + if (curMips->inDelaySlot && wasInDelaySlot) { + curMips->pc = curMips->nextPC; + curMips->inDelaySlot = false; + } + } while (curMips->inDelaySlot); + + if (CoreTiming::GetTicks() > globalTicks) + return; + } +} + +int MIPSInterpret_RunUntil(u64 globalTicks) { + MIPSState *curMips = currentMIPS; + while (coreState == CORE_RUNNING) { CoreTiming::Advance(); - // NEVER stop in a delay slot! - while (curMips->downcount >= 0 && coreState == CORE_RUNNING) - { - // int cycles = 0; - { - again: - MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); - //MIPSOpcode op = Memory::Read_Opcode_JIT(mipsr4k.pc); + uint64_t ticksLeft = globalTicks - CoreTiming::GetTicks(); + if (CBreakPoints::HasBreakPoints() || CBreakPoints::HasMemChecks() || ticksLeft <= curMips->downcount) + RunUntilWithChecks(globalTicks); + else + RunUntilFast(); - //2: check for breakpoint (VERY SLOW) -#if defined(_DEBUG) - if (CBreakPoints::IsAddressBreakPoint(curMips->pc) && CBreakPoints::CheckSkipFirst() != curMips->pc) { - auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); - if (!cond || cond->Evaluate()) - { - Core_EnableStepping(true, "cpu.breakpoint", curMips->pc); - if (CBreakPoints::IsTempBreakPoint(curMips->pc)) - CBreakPoints::RemoveBreakPoint(curMips->pc); - break; - } - } -#endif - - bool wasInDelaySlot = curMips->inDelaySlot; - MIPSInterpret(op); - curMips->downcount -= MIPSGetInstructionCycleEstimate(op); - - if (curMips->inDelaySlot) - { - // The reason we have to check this is the delay slot hack in Int_Syscall. - if (wasInDelaySlot) - { - curMips->pc = curMips->nextPC; - curMips->inDelaySlot = false; - continue; - } - goto again; - } - } - - if (CoreTiming::GetTicks() > globalTicks) - { - // DEBUG_LOG(CPU, "Hit the max ticks, bailing 1 : %llu, %llu", globalTicks, CoreTiming::GetTicks()); - return 1; - } + if (CoreTiming::GetTicks() > globalTicks) { + // DEBUG_LOG(CPU, "Hit the max ticks, bailing 1 : %llu, %llu", globalTicks, CoreTiming::GetTicks()); + return 1; } } @@ -1048,8 +1077,8 @@ MIPSInterpretFunc MIPSGetInterpretFunc(MIPSOpcode op) // TODO: Do something that makes sense here. int MIPSGetInstructionCycleEstimate(MIPSOpcode op) { - MIPSInfo info = MIPSGetInfo(op); - return info.cycles; + const MIPSInstruction *instr = MIPSGetInstruction(op); + return GetInstructionCycleEstimate(instr); } const char *MIPSDisasmAt(u32 compilerPC) { From f9da9e6b609add7d66a81d4376a5ea1fcf69cbe5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 17:38:53 -0800 Subject: [PATCH 307/715] interp: Centralize memory size handling. --- Core/Debugger/DisassemblyManager.cpp | 18 ++------------ Core/MIPS/MIPSAnalyst.cpp | 36 ++-------------------------- Core/MIPS/MIPSInt.h | 2 -- Core/MIPS/MIPSIntVFPU.h | 1 - Core/MIPS/MIPSTables.cpp | 21 ++++++++++++++++ Core/MIPS/MIPSTables.h | 1 + 6 files changed, 26 insertions(+), 53 deletions(-) diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp index ab0e10aa9b..b57e52610d 100644 --- a/Core/Debugger/DisassemblyManager.cpp +++ b/Core/Debugger/DisassemblyManager.cpp @@ -709,22 +709,8 @@ void DisassemblyFunction::load() case 0x2B: // sw macro = new DisassemblyMacro(opAddress); - int dataSize; - switch (nextInfo & MEMTYPE_MASK) { - case MEMTYPE_BYTE: - dataSize = 1; - break; - case MEMTYPE_HWORD: - dataSize = 2; - break; - case MEMTYPE_WORD: - case MEMTYPE_FLOAT: - dataSize = 4; - break; - case MEMTYPE_VQUAD: - dataSize = 16; - break; - default: + int dataSize = MIPSGetMemoryAccessSize(next); + if (dataSize == 0) { delete macro; return; } diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 353d7605d3..cdeaa6a169 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -611,25 +611,7 @@ namespace MIPSAnalyst { int OpMemoryAccessSize(u32 pc) { const auto op = Memory::Read_Instruction(pc, true); - MIPSInfo info = MIPSGetInfo(op); - if ((info & (IN_MEM | OUT_MEM)) == 0) { - return 0; - } - - // TODO: Verify lwl/lwr/etc.? - switch (info & MEMTYPE_MASK) { - case MEMTYPE_BYTE: - return 1; - case MEMTYPE_HWORD: - return 2; - case MEMTYPE_WORD: - case MEMTYPE_FLOAT: - return 4; - case MEMTYPE_VQUAD: - return 16; - } - - return 0; + return MIPSGetMemoryAccessSize(op); } bool IsOpMemoryWrite(u32 pc) { @@ -1553,21 +1535,7 @@ skip: // lw, sh, ... if (!IsSyscall(op) && (opInfo & (IN_MEM | OUT_MEM)) != 0) { info.isDataAccess = true; - switch (opInfo & MEMTYPE_MASK) { - case MEMTYPE_BYTE: - info.dataSize = 1; - break; - case MEMTYPE_HWORD: - info.dataSize = 2; - break; - case MEMTYPE_WORD: - case MEMTYPE_FLOAT: - info.dataSize = 4; - break; - - case MEMTYPE_VQUAD: - info.dataSize = 16; - } + info.dataSize = MIPSGetMemoryAccessSize(op); u32 rs = cpu->GetRegValue(0, (int)MIPS_GET_RS(op)); s16 imm16 = op & 0xFFFF; diff --git a/Core/MIPS/MIPSInt.h b/Core/MIPS/MIPSInt.h index cd52fc409b..039a5f597f 100644 --- a/Core/MIPS/MIPSInt.h +++ b/Core/MIPS/MIPSInt.h @@ -23,8 +23,6 @@ int MIPS_SingleStep(); namespace MIPSInt { - void Int_Unknown(MIPSOpcode op); - void Int_Unimpl(MIPSOpcode op); void Int_Syscall(MIPSOpcode op); void Int_mxc1(MIPSOpcode op); diff --git a/Core/MIPS/MIPSIntVFPU.h b/Core/MIPS/MIPSIntVFPU.h index 1d0a1ba1f1..fdd7954aa3 100644 --- a/Core/MIPS/MIPSIntVFPU.h +++ b/Core/MIPS/MIPSIntVFPU.h @@ -26,7 +26,6 @@ namespace MIPSInt void Int_SV(MIPSOpcode op); void Int_SVQ(MIPSOpcode op); void Int_Mftv(MIPSOpcode op); - void Int_MatrixSet(MIPSOpcode op); void Int_VecDo3(MIPSOpcode op); void Int_Vcst(MIPSOpcode op); void Int_VMatrixInit(MIPSOpcode op); diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 48182a37b5..5a2065074b 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -1081,6 +1081,27 @@ int MIPSGetInstructionCycleEstimate(MIPSOpcode op) return GetInstructionCycleEstimate(instr); } +int MIPSGetMemoryAccessSize(MIPSOpcode op) { + MIPSInfo info = MIPSGetInfo(op); + if ((info & (IN_MEM | OUT_MEM)) == 0) { + return 0; + } + + switch (info & MEMTYPE_MASK) { + case MEMTYPE_BYTE: + return 1; + case MEMTYPE_HWORD: + return 2; + case MEMTYPE_WORD: + case MEMTYPE_FLOAT: + return 4; + case MEMTYPE_VQUAD: + return 16; + } + + return 0; +} + const char *MIPSDisasmAt(u32 compilerPC) { static char temp[256]; MIPSDisAsm(Memory::Read_Instruction(compilerPC), 0, temp); diff --git a/Core/MIPS/MIPSTables.h b/Core/MIPS/MIPSTables.h index fd12c43a96..484eab35ea 100644 --- a/Core/MIPS/MIPSTables.h +++ b/Core/MIPS/MIPSTables.h @@ -130,5 +130,6 @@ int MIPSInterpret_RunUntil(u64 globalTicks); MIPSInterpretFunc MIPSGetInterpretFunc(MIPSOpcode op); int MIPSGetInstructionCycleEstimate(MIPSOpcode op); +int MIPSGetMemoryAccessSize(MIPSOpcode op); const char *MIPSGetName(MIPSOpcode op); const char *MIPSDisasmAt(u32 compilerPC); From 0f79afa172db43421785448143505f9d4546111e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Nov 2022 17:44:44 -0800 Subject: [PATCH 308/715] interp: Support memory breakpoints too. --- Core/Debugger/Breakpoints.h | 2 +- Core/MIPS/MIPSTables.cpp | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Core/Debugger/Breakpoints.h b/Core/Debugger/Breakpoints.h index 9f1a575118..b60858e79e 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -115,7 +115,7 @@ struct MemCheck { // BreakPoints cannot overlap, only one is allowed per address. // MemChecks can overlap, as long as their ends are different. -// WARNING: MemChecks are not used in the interpreter or HLE currently. +// WARNING: MemChecks are not always tracked in HLE currently. class CBreakPoints { public: diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 5a2065074b..996a54daf7 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -992,13 +992,16 @@ static inline void RunUntilFast() { static void RunUntilWithChecks(u64 globalTicks) { MIPSState *curMips = currentMIPS; // NEVER stop in a delay slot! + bool hasBPs = CBreakPoints::HasBreakPoints(); + bool hasMCs = CBreakPoints::HasMemChecks(); while (curMips->downcount >= 0 && coreState == CORE_RUNNING) { do { // Replacements and similar are processed here, intentionally. MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); + const MIPSInstruction *instr = MIPSGetInstruction(op); // Check for breakpoint - if (CBreakPoints::IsAddressBreakPoint(curMips->pc) && CBreakPoints::CheckSkipFirst() != curMips->pc) { + if (hasBPs && CBreakPoints::IsAddressBreakPoint(curMips->pc) && CBreakPoints::CheckSkipFirst() != curMips->pc) { auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); if (!cond || cond->Evaluate()) { Core_EnableStepping(true, "cpu.breakpoint", curMips->pc); @@ -1007,9 +1010,23 @@ static void RunUntilWithChecks(u64 globalTicks) { break; } } + if (hasMCs && (instr->flags & (IN_MEM | OUT_MEM)) != 0 && CBreakPoints::CheckSkipFirst() != curMips->pc && instr->interpret != &Int_Syscall) { + // This is common for all IN_MEM/OUT_MEM funcs. + int offset = (instr->flags & IS_VFPU) != 0 ? SignExtend16ToS32(op & 0xFFFC) : SignExtend16ToS32(op); + u32 addr = (R(_RS) + offset) & 0xFFFFFFFC; + int sz = MIPSGetMemoryAccessSize(op); + + if ((instr->flags & IN_MEM) != 0) + CBreakPoints::ExecMemCheck(addr, false, sz, curMips->pc, "interpret"); + if ((instr->flags & OUT_MEM) != 0) + CBreakPoints::ExecMemCheck(addr, true, sz, curMips->pc, "interpret"); + + // If it tripped, bail without running. + if (coreState == CORE_STEPPING) + break; + } bool wasInDelaySlot = curMips->inDelaySlot; - const MIPSInstruction *instr = MIPSGetInstruction(op); Interpret(instr, op); curMips->downcount -= GetInstructionCycleEstimate(instr); From b8bb495b8cb7e701218b88e008802e64a5ca15a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:06:09 +0800 Subject: [PATCH 309/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 8f4d89d60b..dcce9b3f26 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -140,7 +140,7 @@ Discord = Discord Display Layout Editor = 顯示版面配置編輯器… Display Rotation = 顯示旋轉 Dump Next Frame to Log = 傾印下一影格至記錄 (&U) -Emulation = 仿真 (&E) +Emulation = 模擬 (&E) Enable Cheats = 啟用密技 (&C) Enable Sound = 啟用音效 (&O) Exit = 離開 (&X) @@ -498,7 +498,7 @@ Frame Skipping Type = 影格跳過類型 FullScreen = 全螢幕 GPUReadbackRequired = 警告:此遊戲需要關閉「跳過 GPU 讀回」 Hack Settings = 駭客設定 (可能會造成故障) -Hardware Tessellation = 硬體鑲嵌式 +Hardware Tessellation = 硬體鑲嵌 Hardware Transform = 硬體轉換 hardware transform error - falling back to software = 硬體轉換錯誤,將回復到軟體轉換 HardwareTessellation Tip = 使用硬體繪製曲線 @@ -555,7 +555,7 @@ Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 Texture Scaling = 紋理縮放 Texture Shader = 紋理著色器 -Turn off Hardware Tessellation - unsupported = 關閉「硬體鑲嵌式」:不支援 +Turn off Hardware Tessellation - unsupported = 關閉「硬體鑲嵌」:不支援 Unlimited = 無限制 Up to 1 = 最多至 1 Up to 2 = 最多至 2 @@ -596,7 +596,7 @@ You can press ESC to cancel. = 您可以按下 ESC 取消 [MainMenu] Browse = 瀏覽… -Buy PPSSPP Gold = 購買 PPSSPP 黃金版 +Buy PPSSPP Gold = 購買黃金版 Choose folder = 選擇資料夾 Credits = 製作名單 PPSSPP Homebrew Store = PPSSPP 自製遊戲商店 @@ -611,13 +611,13 @@ Load = 載入… Loading... = 正在載入… PinPath = 釘選 PPSSPP can't load games or save right now = PPSSPP 目前無法載入或儲存遊戲 -Recent = Recent +Recent = 最近遊玩 SavesAreTemporary = PPSSPP 正在儲存於暫時儲存空間 SavesAreTemporaryGuidance = 將 PPSSPP 擷取至其他位置以永久儲存 SavesAreTemporaryIgnore = 忽略警告 UnpinPath = 取消釘選 UseBrowseOrLoad = 使用「瀏覽」以選擇資料夾,或載入以選擇檔案 -www.ppsspp.org = www.ppsspp.org +www.ppsspp.org = 官方網站 [MainSettings] Audio = 音訊 @@ -834,7 +834,7 @@ MitchellNetravali = 雙立方 (密契爾 - 內拉瓦利) 放大 all the forum mods = 所有論壇模組 build server = 組建伺服器 Buy Gold = 購買黃金版 -check = 同樣歡迎使用海豚模擬器,這是最棒的 Wii/GC 模擬器 +check = 同樣歡迎使用 Dolphin 模擬器,這是最棒的 Wii/GC 模擬器 CheckOutPPSSPP = 體驗 PPSSPP,一款絕佳的 PSP 模擬器:https://www.ppsspp.org/ contributors = 參與者: created = 作者 @@ -866,7 +866,7 @@ translators3 = translators4 = translators5 = translators6 = -Twitter @PPSSPP_emu = Twitter @PPSSPP_emu +Twitter @PPSSPP_emu = Twitter website = 歡迎造訪我們的網站: written = 使用 C++ 編寫,以保證建置速度和相容性 @@ -940,7 +940,7 @@ Menu/Intro = 選單/簡介 Menu/Intro Description = 無法進入遊戲 Nothing = 沒有畫面 Nothing Description = 完全損毀 -OK = 確定 +OK = 良好 Open Browser = 開啟報告網站 Overall = 整體 Perfect = 完美 @@ -1170,10 +1170,10 @@ UI background animation = UI 背景動畫 undo %c = 備份 %c USB = USB Use Lossless Video Codec (FFV1) = 使用不失真視訊轉碼器 (FFV1) -Use O to confirm = 使用 O 作為確認按鈕 +Use O to confirm = 使用 O 按鈕 Use output buffer (with overlay) for recording = 為錄製使用輸出緩衝區 (覆疊) Use system native keyboard = 使用系統原生鍵盤 -Use X to confirm = 使用 X 作為確認按鈕 +Use X to confirm = 使用 X 按鈕 VersionCheck = 檢查 PPSSPP 新版本 WARNING: Android battery save mode is on = 警告:Android 省電模式已開啟 WARNING: Battery save mode is on = 警告:省電模式已開啟 From 1ba92c795d23320378eb76f2cc1c64138aa3a3d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:11:40 +0800 Subject: [PATCH 310/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index dcce9b3f26..acaa3debe3 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -837,7 +837,7 @@ Buy Gold = 購買黃金版 check = 同樣歡迎使用 Dolphin 模擬器,這是最棒的 Wii/GC 模擬器 CheckOutPPSSPP = 體驗 PPSSPP,一款絕佳的 PSP 模擬器:https://www.ppsspp.org/ contributors = 參與者: -created = 作者 +created = 作者: Discord = Discord info1 = PPSSPP 僅適用於教育用途, info2 = 請確保您擁有遊戲的版權, @@ -853,7 +853,7 @@ Share PPSSPP = 分享 PPSSPP specialthanks = 特別感謝: specialthanksKeithGalocy = 的硬體和建議,他來自 NVIDIA specialthanksMaxim = 的出色的解碼器工作 -testing = 測試人員: +testing = 測試人員 this translation by = 正體中文翻譯: title = 快速、方便攜帶的 PSP 模擬器 tools = 使用的自由工具: From 5d908baf87c046134f849428104d991afbe676a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Mon, 14 Nov 2022 13:17:05 +0800 Subject: [PATCH 311/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index acaa3debe3..d3ecc84266 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -48,7 +48,7 @@ Customize Touch Controls = 編輯觸控控制版面配置… Customize tilt = 自訂傾斜… D-PAD = 方向鍵 Deadzone radius = 死區半徑 -Disable D-Pad diagonals (4-way touch) = 停用方向鍵對角線 (4 向觸控) +Disable D-Pad diagonals (4-way touch) = 停用方向鍵對角線 (四向觸控) Disable diagonal input = 停用對角線輸入 Double tap = 點兩下 Enable gesture control = 啟用手勢控制 @@ -73,7 +73,7 @@ Landscape Reversed = 橫向反轉 Low end radius = 低端半徑 Mouse = 滑鼠設定 Mouse sensitivity = 滑鼠敏感度 -Mouse smoothing = 滑鼠平滑 +Mouse smoothing = 滑鼠平滑度 MouseControl Tip = 您現在可以透過按下「M」圖示在控制對應畫面中對應滑鼠。 None (Disabled) = 無 (已停用) Off = 關閉 @@ -93,7 +93,7 @@ Shape = 圖形 Show Touch Pause Menu Button = 顯示暫停選單按鈕 Swipe = 滑動 Swipe sensitivity = 滑動敏感度 -Swipe smoothing = 滑動平滑 +Swipe smoothing = 滑動平滑度 Thin borders = 特細框線 Tilt Base Radius = 傾斜基準半徑 Tilt Input Type = 傾斜輸入類型 @@ -1126,7 +1126,7 @@ Interpreter = 解譯器 IO timing method = I/O 計時方法 IR Interpreter = IR 解譯器 Memory Stick Folder = 記憶棒資料夾 -Memory Stick inserted = 記憶棒已插入 +Memory Stick inserted = 記憶棒插入 MHz, 0:default = MHz,0 = 預設 MMDDYYYY = 月/日/年 Moving background = 動態背景 From 0ae1d75daffd2713148cec52456bb6ce10dd6270 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 10:22:01 +0100 Subject: [PATCH 312/715] OpenXR - Support camera adjust using joystick --- Common/VR/PPSSPPVR.cpp | 24 +++++++++++++++--------- Common/VR/PPSSPPVR.h | 3 ++- UI/NativeApp.cpp | 9 +++++++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 92e00f898a..e35066dc14 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -36,6 +36,7 @@ enum VRMirroring { VR_MIRRORING_COUNT }; +static std::map pspAxis; static std::map pspKeys; static int vr3DGeometryCount = 0; @@ -325,7 +326,12 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con } } -bool UpdateVRSpecialKeys(const KeyInput &key) { +bool UpdateVRAxis(const AxisInput &axis) { + pspAxis[axis.axisId] = axis.value; + return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; +} + +bool UpdateVRKeys(const KeyInput &key) { std::vector nativeKeys; if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { @@ -562,16 +568,16 @@ bool StartVRRender() { // Camera control if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { //left joystick controls height and side - if (pspKeys[CTRL_LEFT]) g_Config.fCameraSide -= 0.05f; - if (pspKeys[CTRL_RIGHT]) g_Config.fCameraSide += 0.05f; - if (pspKeys[CTRL_DOWN]) g_Config.fCameraHeight -= 0.05f; - if (pspKeys[CTRL_UP]) g_Config.fCameraHeight += 0.05f; + if (pspKeys[CTRL_LEFT] || (pspAxis[JOYSTICK_AXIS_X] < -0.5f)) g_Config.fCameraSide -= 0.05f; + if (pspKeys[CTRL_RIGHT] || (pspAxis[JOYSTICK_AXIS_X] > 0.5f)) g_Config.fCameraSide += 0.05f; + if (pspKeys[CTRL_DOWN] || (pspAxis[JOYSTICK_AXIS_Y] > 0.5f)) g_Config.fCameraHeight -= 0.05f; + if (pspKeys[CTRL_UP] || (pspAxis[JOYSTICK_AXIS_Y] < -0.5f)) g_Config.fCameraHeight += 0.05f; //right joystick controls distance and fov - if (pspKeys[VIRTKEY_AXIS_X_MIN]) g_Config.fFieldOfViewPercentage -= 1.0f; - if (pspKeys[VIRTKEY_AXIS_X_MAX]) g_Config.fFieldOfViewPercentage += 1.0f; - if (pspKeys[VIRTKEY_AXIS_Y_MIN]) g_Config.fCameraDistance -= 0.1f; - if (pspKeys[VIRTKEY_AXIS_Y_MAX]) g_Config.fCameraDistance += 0.1f; + if (pspKeys[VIRTKEY_AXIS_X_MIN] || (pspAxis[JOYSTICK_AXIS_Z] < -0.5f)) g_Config.fFieldOfViewPercentage -= 1.0f; + if (pspKeys[VIRTKEY_AXIS_X_MAX] || (pspAxis[JOYSTICK_AXIS_Z] > 0.5f)) g_Config.fFieldOfViewPercentage += 1.0f; + if (pspKeys[VIRTKEY_AXIS_Y_MIN] || (pspAxis[JOYSTICK_AXIS_RZ] > 0.5f)) g_Config.fCameraDistance -= 0.1f; + if (pspKeys[VIRTKEY_AXIS_Y_MAX] || (pspAxis[JOYSTICK_AXIS_RZ] < -0.5f)) g_Config.fCameraDistance += 0.1f; // Reset values if (pspKeys[VIRTKEY_VR_CAMERA_RESET]) { diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index c47fada705..f83f7e721e 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -23,7 +23,8 @@ void InitVROnAndroid(void* vm, void* activity, const char* system, int version, void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); -bool UpdateVRSpecialKeys(const KeyInput &key); +bool UpdateVRAxis(const AxisInput &axis); +bool UpdateVRKeys(const KeyInput &key); // VR games compatibility void PreprocessStepVR(void* step); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 2e8e202b8b..0bea47395a 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1306,8 +1306,8 @@ bool NativeTouch(const TouchInput &touch) { } bool NativeKey(const KeyInput &key) { - // Special key VR actions - if (IsVREnabled() && !UpdateVRSpecialKeys(key)) { + // VR actions + if (IsVREnabled() && !UpdateVRKeys(key)) { return false; } @@ -1331,6 +1331,11 @@ bool NativeKey(const KeyInput &key) { } bool NativeAxis(const AxisInput &axis) { + // VR actions + if (IsVREnabled() && !UpdateVRAxis(axis)) { + return false; + } + if (!screenManager) { // Too early. return false; From ddad6b3760acf5eee608abe68fe6e350f8bba41b Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 10:52:12 +0100 Subject: [PATCH 313/715] OpenXR - Support axis --- Common/VR/PPSSPPVR.cpp | 46 +++++++++++++++++++++++++++++-------- Common/VR/PPSSPPVR.h | 3 ++- android/jni/app-android.cpp | 2 +- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index e35066dc14..13a9c16ed3 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -36,6 +36,7 @@ enum VRMirroring { VR_MIRRORING_COUNT }; +static int pspAxisDeviceId = 0; static std::map pspAxis; static std::map pspKeys; @@ -195,7 +196,25 @@ void GetVRResolutionPerEye(int* width, int* height) { } } -void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) { +void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(const KeyInput &key), + bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) { + //axis + AxisInput axis = {}; + for (int j = 0; j < 2; j++) { + XrVector2f joystick = IN_VRGetJoystickState(j); + axis.deviceId = DEVICE_ID_DEFAULT; + + //horizontal + axis.axisId = j == 0 ? JOYSTICK_AXIS_X : JOYSTICK_AXIS_Z; + axis.value = joystick.x; + NativeAxis(axis); + + //vertical + axis.axisId = j == 0 ? JOYSTICK_AXIS_Y : JOYSTICK_AXIS_RZ; + axis.value = -joystick.y; + NativeAxis(axis); + } + //buttons KeyInput keyInput = {}; for (int j = 0; j < 2; j++) { @@ -327,7 +346,16 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con } bool UpdateVRAxis(const AxisInput &axis) { + //do not store small input if two devices used at the same time + if (pspAxisDeviceId != axis.deviceId) { + if (fabs(axis.value) < 0.5f) { + return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; + } + } + + //store axis value pspAxis[axis.axisId] = axis.value; + pspAxisDeviceId = axis.deviceId; return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; } @@ -568,16 +596,16 @@ bool StartVRRender() { // Camera control if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { //left joystick controls height and side - if (pspKeys[CTRL_LEFT] || (pspAxis[JOYSTICK_AXIS_X] < -0.5f)) g_Config.fCameraSide -= 0.05f; - if (pspKeys[CTRL_RIGHT] || (pspAxis[JOYSTICK_AXIS_X] > 0.5f)) g_Config.fCameraSide += 0.05f; - if (pspKeys[CTRL_DOWN] || (pspAxis[JOYSTICK_AXIS_Y] > 0.5f)) g_Config.fCameraHeight -= 0.05f; - if (pspKeys[CTRL_UP] || (pspAxis[JOYSTICK_AXIS_Y] < -0.5f)) g_Config.fCameraHeight += 0.05f; + if (pspAxis[JOYSTICK_AXIS_X] < -0.5f) g_Config.fCameraSide -= 0.05f; + if (pspAxis[JOYSTICK_AXIS_X] > 0.5f) g_Config.fCameraSide += 0.05f; + if (pspAxis[JOYSTICK_AXIS_Y] > 0.5f) g_Config.fCameraHeight -= 0.05f; + if (pspAxis[JOYSTICK_AXIS_Y] < -0.5f) g_Config.fCameraHeight += 0.05f; //right joystick controls distance and fov - if (pspKeys[VIRTKEY_AXIS_X_MIN] || (pspAxis[JOYSTICK_AXIS_Z] < -0.5f)) g_Config.fFieldOfViewPercentage -= 1.0f; - if (pspKeys[VIRTKEY_AXIS_X_MAX] || (pspAxis[JOYSTICK_AXIS_Z] > 0.5f)) g_Config.fFieldOfViewPercentage += 1.0f; - if (pspKeys[VIRTKEY_AXIS_Y_MIN] || (pspAxis[JOYSTICK_AXIS_RZ] > 0.5f)) g_Config.fCameraDistance -= 0.1f; - if (pspKeys[VIRTKEY_AXIS_Y_MAX] || (pspAxis[JOYSTICK_AXIS_RZ] < -0.5f)) g_Config.fCameraDistance += 0.1f; + if (pspAxis[JOYSTICK_AXIS_Z] < -0.5f) g_Config.fFieldOfViewPercentage -= 1.0f; + if (pspAxis[JOYSTICK_AXIS_Z] > 0.5f) g_Config.fFieldOfViewPercentage += 1.0f; + if (pspAxis[JOYSTICK_AXIS_RZ] > 0.5f) g_Config.fCameraDistance -= 0.1f; + if (pspAxis[JOYSTICK_AXIS_RZ] < -0.5f) g_Config.fCameraDistance += 0.1f; // Reset values if (pspKeys[VIRTKEY_VR_CAMERA_RESET]) { diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index f83f7e721e..b10902cff4 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -22,7 +22,8 @@ bool IsVREnabled(); void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); -void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); +void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(const KeyInput &key), + bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); bool UpdateVRAxis(const AxisInput &axis); bool UpdateVRKeys(const KeyInput &key); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 0ea64f935b..ccd764c002 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1079,7 +1079,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, } if (IsVREnabled()) { - UpdateVRInput(NativeKey, NativeTouch, g_Config.bHapticFeedback, dp_xscale, dp_yscale); + UpdateVRInput(NativeAxis, NativeKey, NativeTouch, g_Config.bHapticFeedback, dp_xscale, dp_yscale); FinishVRRender(); } } From 011592754fcdcc482eeb21378d4dcd1710b67fb8 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 12:19:17 +0100 Subject: [PATCH 314/715] OpenXR - Use mouse control only --- Common/UI/ViewGroup.cpp | 12 ++++- Common/VR/PPSSPPVR.cpp | 92 +++++++++++++++++++++++-------------- Common/VR/PPSSPPVR.h | 9 ++++ UI/ControlMappingScreen.cpp | 4 ++ UI/EmuScreen.cpp | 3 ++ UI/PauseScreen.cpp | 3 ++ 6 files changed, 87 insertions(+), 36 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f90f0eb1a6..556f664c9e 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -826,13 +826,21 @@ bool ScrollView::Key(const KeyInput &input) { if (visibility_ != V_VISIBLE) return ViewGroup::Key(input); + float scrollSpeed = 250; + switch (input.deviceId) { + case DEVICE_ID_XR_CONTROLLER_LEFT: + case DEVICE_ID_XR_CONTROLLER_RIGHT: + scrollSpeed = 50; + break; + } + if (input.flags & KEY_DOWN) { switch (input.keyCode) { case NKCODE_EXT_MOUSEWHEEL_UP: - ScrollRelative(-250); + ScrollRelative(-scrollSpeed); break; case NKCODE_EXT_MOUSEWHEEL_DOWN: - ScrollRelative(250); + ScrollRelative(scrollSpeed); break; } } diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 13a9c16ed3..2c74f7536e 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -36,6 +36,7 @@ enum VRMirroring { VR_MIRRORING_COUNT }; +static VRAppMode appMode = VR_MENU_MODE; static int pspAxisDeviceId = 0; static std::map pspAxis; static std::map pspKeys; @@ -67,16 +68,6 @@ struct ButtonMapping { } }; -struct MouseActivator { - bool activate; - ovrButton ovr; - - MouseActivator(bool activate, ovrButton ovr) { - this->activate = activate; - this->ovr = ovr; - } -}; - static std::vector leftControllerMapping = { ButtonMapping(NKCODE_BUTTON_X, ovrButton_X), ButtonMapping(NKCODE_BUTTON_Y, ovrButton_Y), @@ -108,16 +99,8 @@ static std::vector controllerMapping[2] = { rightControllerMapping }; static bool controllerMotion[2][5] = {}; -static int mouseController = -1; -static bool mousePressed[] = {false, false}; - -static std::vector mouseActivators = { - MouseActivator(true, ovrButton_Trigger), - MouseActivator(false, ovrButton_Up), - MouseActivator(false, ovrButton_Down), - MouseActivator(false, ovrButton_Left), - MouseActivator(false, ovrButton_Right), -}; +static int mouseController = 1; +static bool mousePressed = false; /* ================================================================================ @@ -196,6 +179,18 @@ void GetVRResolutionPerEye(int* width, int* height) { } } +/* +================================================================================ + +VR input integration + +================================================================================ +*/ + +void SetVRAppMode(VRAppMode mode) { + appMode = mode; +} + void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) { //axis @@ -245,16 +240,6 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co } } - //enable or disable mouse - for (int j = 0; j < 2; j++) { - int status = IN_VRGetButtonState(j); - for (MouseActivator& m : mouseActivators) { - if (status & m.ovr) { - mouseController = m.activate ? j : -1; - } - } - } - //motion control if (g_Config.bEnableMotions) { for (int j = 0; j < 2; j++) { @@ -307,8 +292,22 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co } } + //enable or disable mouse + for (int j = 0; j < 2; j++) { + bool pressed = IN_VRGetButtonState(j) & ovrButton_Trigger; + if (pressed) { + int lastController = mouseController; + mouseController = j; + + //prevent misclicks when changing the left/right controller + if (lastController != mouseController) { + mousePressed = true; + } + } + } + //mouse cursor - if (mouseController >= 0) { + if ((mouseController >= 0) && (appMode == VR_MENU_MODE)) { //get position on screen XrPosef pose = IN_VRGetPose(mouseController); XrVector3f angles = XrQuaternionf_ToEulerAngles(pose.orientation); @@ -331,15 +330,25 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co touch.x = x * dp_xscale; touch.y = (height - y - 1) * dp_yscale; bool pressed = IN_VRGetButtonState(mouseController) & ovrButton_Trigger; - if (mousePressed[mouseController] != pressed) { - if (!pressed) { + if (mousePressed != pressed) { + if (pressed) { touch.flags = TOUCH_DOWN; NativeTouch(touch); touch.flags = TOUCH_UP; NativeTouch(touch); } - mousePressed[mouseController] = pressed; + mousePressed = pressed; } + + //mouse wheel emulation + keyInput.deviceId = controllerIds[mouseController]; + float scroll = -IN_VRGetJoystickState(mouseController).y; + keyInput.flags = scroll < -0.5f ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_UP; + NativeKey(keyInput); + keyInput.flags = scroll > 0.5f ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN; + NativeKey(keyInput); } else { VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 0); } @@ -360,12 +369,27 @@ bool UpdateVRAxis(const AxisInput &axis) { } bool UpdateVRKeys(const KeyInput &key) { + //store key value std::vector nativeKeys; if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { pspKeys[nativeKey] = key.flags & KEY_DOWN; } } + + //block keys in the menus + if (appMode == VR_MENU_MODE) { + switch (key.keyCode) { + case NKCODE_BACK: + case NKCODE_EXT_MOUSEWHEEL_UP: + case NKCODE_EXT_MOUSEWHEEL_DOWN: + return true; + default: + return false; + } + } + + //block keys by camera adjust return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index b10902cff4..23a13ec0b4 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -17,11 +17,20 @@ enum VRCompatFlag { VR_COMPAT_MAX }; +enum VRAppMode { + VR_CONTROLL_MAPPING_MODE, + VR_GAME_MODE, + VR_MENU_MODE, +}; + // VR app flow integration bool IsVREnabled(); void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); + +// VR input integration +void SetVRAppMode(VRAppMode mode); void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); bool UpdateVRAxis(const AxisInput &axis); diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index f6255ad4e3..1415cb53be 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -27,6 +27,7 @@ #include "Common/UI/Context.h" #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/Log.h" #include "Common/Data/Color/RGBAUtil.h" @@ -279,6 +280,7 @@ void ControlMappingScreen::update() { } UIDialogScreenWithBackground::update(); + SetVRAppMode(VRAppMode::VR_MENU_MODE); } UI::EventReturn ControlMappingScreen::OnClearMapping(UI::EventParams ¶ms) { @@ -328,6 +330,7 @@ void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { std::string pspButtonName = KeyMap::GetPspButtonName(this->pspBtn_); parent->Add(new TextView(std::string(km->T("Map a new key for")) + " " + mc->T(pspButtonName), new LinearLayoutParams(Margins(10,0)))); + SetVRAppMode(VRAppMode::VR_CONTROLL_MAPPING_MODE); } bool KeyMappingNewKeyDialog::key(const KeyInput &key) { @@ -360,6 +363,7 @@ void KeyMappingNewMouseKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { auto km = GetI18NCategory("KeyMapping"); parent->Add(new TextView(std::string(km->T("You can press ESC to cancel.")), new LinearLayoutParams(Margins(10, 0)))); + SetVRAppMode(VRAppMode::VR_CONTROLL_MAPPING_MODE); } bool KeyMappingNewMouseKeyDialog::key(const KeyInput &key) { diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 896c939d12..0b247144a6 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -31,6 +31,7 @@ using namespace std::placeholders; #include "Common/UI/Context.h" #include "Common/UI/Tween.h" #include "Common/UI/View.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/Data/Text/I18n.h" #include "Common/Input/InputState.h" @@ -1475,6 +1476,8 @@ void EmuScreen::render() { screenManager()->getUIContext()->BeginFrame(); renderUI(); } + + SetVRAppMode(VRAppMode::VR_GAME_MODE); } bool EmuScreen::hasVisibleUI() { diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 748fcdf86d..7a75cd8806 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -28,6 +28,7 @@ #include "Common/Data/Text/I18n.h" #include "Common/StringUtils.h" #include "Common/System/System.h" +#include "Common/VR/PPSSPPVR.h" #include "Core/Reporting.h" #include "Core/SaveState.h" @@ -355,6 +356,8 @@ void GamePauseScreen::update() { TriggerFinish(DR_CANCEL); finishNextFrame_ = false; } + + SetVRAppMode(VRAppMode::VR_MENU_MODE); } GamePauseScreen::~GamePauseScreen() { From 14b6d75ac6f91c2383f7147187af65d9b5bd257d Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 12:22:16 +0100 Subject: [PATCH 315/715] OpenXR - Use axis integration for camera adjust only --- Common/VR/PPSSPPVR.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 2c74f7536e..c95753c480 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -194,20 +194,22 @@ void SetVRAppMode(VRAppMode mode) { void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) { //axis - AxisInput axis = {}; - for (int j = 0; j < 2; j++) { - XrVector2f joystick = IN_VRGetJoystickState(j); - axis.deviceId = DEVICE_ID_DEFAULT; + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { + AxisInput axis = {}; + for (int j = 0; j < 2; j++) { + XrVector2f joystick = IN_VRGetJoystickState(j); + axis.deviceId = DEVICE_ID_DEFAULT; - //horizontal - axis.axisId = j == 0 ? JOYSTICK_AXIS_X : JOYSTICK_AXIS_Z; - axis.value = joystick.x; - NativeAxis(axis); + //horizontal + axis.axisId = j == 0 ? JOYSTICK_AXIS_X : JOYSTICK_AXIS_Z; + axis.value = joystick.x; + NativeAxis(axis); - //vertical - axis.axisId = j == 0 ? JOYSTICK_AXIS_Y : JOYSTICK_AXIS_RZ; - axis.value = -joystick.y; - NativeAxis(axis); + //vertical + axis.axisId = j == 0 ? JOYSTICK_AXIS_Y : JOYSTICK_AXIS_RZ; + axis.value = -joystick.y; + NativeAxis(axis); + } } //buttons From 319d434acc6a22245bdb8016e8a69aff73dcf16f Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 12:51:42 +0100 Subject: [PATCH 316/715] OpenXR - Allow higher 2D canvas distance --- UI/GameSettingsScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 080d19e686..abe73f5e7a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1144,7 +1144,7 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new CheckBox(&g_Config.bForce72Hz, vr->T("Force 72Hz update"))); vrSettings->Add(new ItemHeader(vr->T("VR camera"))); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 10.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); vrSettings->Add(new ItemHeader(vr->T("VR controllers"))); From f92990a0027984271addf3cfcf2f71be6788a5cf Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 15:25:35 +0100 Subject: [PATCH 317/715] OpenXR - Better dialog support --- Common/VR/PPSSPPVR.cpp | 10 ++++++---- Common/VR/PPSSPPVR.h | 1 + UI/EmuScreen.cpp | 6 +++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index c95753c480..590a1755fa 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -309,7 +309,7 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co } //mouse cursor - if ((mouseController >= 0) && (appMode == VR_MENU_MODE)) { + if ((mouseController >= 0) && ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE))) { //get position on screen XrPosef pose = IN_VRGetPose(mouseController); XrVector3f angles = XrQuaternionf_ToEulerAngles(pose.orientation); @@ -379,8 +379,8 @@ bool UpdateVRKeys(const KeyInput &key) { } } - //block keys in the menus - if (appMode == VR_MENU_MODE) { + //block keys in the UI + if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { switch (key.keyCode) { case NKCODE_BACK: case NKCODE_EXT_MOUSEWHEEL_UP: @@ -608,7 +608,9 @@ bool StartVRRender() { } // Decide if the scene is 3D or not - if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (vr3DGeometryCount > 15)) { + if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { + VR_SetConfig(VR_CONFIG_MODE, VR_MODE_MONO_SCREEN); + } else if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (vr3DGeometryCount > 15)) { bool stereo = hasUnitScale && g_Config.bEnableStereo; VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); } else { diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 23a13ec0b4..c8c33420a3 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -19,6 +19,7 @@ enum VRCompatFlag { enum VRAppMode { VR_CONTROLL_MAPPING_MODE, + VR_DIALOG_MODE, VR_GAME_MODE, VR_MENU_MODE, }; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 0b247144a6..8c3c74a994 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1477,7 +1477,11 @@ void EmuScreen::render() { renderUI(); } - SetVRAppMode(VRAppMode::VR_GAME_MODE); + if (chatMenu_ && (chatMenu_->GetVisibility() == UI::V_VISIBLE)) { + SetVRAppMode(VRAppMode::VR_DIALOG_MODE); + } else { + SetVRAppMode(screenManager()->topScreen() == this ? VRAppMode::VR_GAME_MODE : VRAppMode::VR_DIALOG_MODE); + } } bool EmuScreen::hasVisibleUI() { From db8b159d9e6db75a1385964dd580b8520b50da7c Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 17:30:29 +0100 Subject: [PATCH 318/715] OpenXR - Force PSP menu aspect ratio --- Common/VR/PPSSPPVR.cpp | 5 +++-- Common/VR/VRRenderer.cpp | 2 +- Common/VR/VRRenderer.h | 1 + GPU/Common/PresentationCommon.cpp | 6 +----- android/jni/app-android.cpp | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 590a1755fa..cdf0b60534 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -319,7 +319,7 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co float cy = height / 2; float speed = (cx + cy) / 2; float x = cx - tan(ToRadians(angles.y - VR_GetConfigFloat(VR_CONFIG_MENU_YAW))) * speed; - float y = cy - tan(ToRadians(angles.x)) * speed; + float y = cy - tan(ToRadians(angles.x)) * speed * VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); //set renderer VR_SetConfig(VR_CONFIG_MOUSE_X, (int)x); @@ -330,7 +330,7 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co TouchInput touch; touch.id = mouseController; touch.x = x * dp_xscale; - touch.y = (height - y - 1) * dp_yscale; + touch.y = (height - y - 1) * dp_yscale / VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); bool pressed = IN_VRGetButtonState(mouseController) & ovrButton_Trigger; if (mousePressed != pressed) { if (pressed) { @@ -608,6 +608,7 @@ bool StartVRRender() { } // Decide if the scene is 3D or not + VR_SetConfigFloat(VR_CONFIG_CANVAS_ASPECT, 480.0f / 272.0f); if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { VR_SetConfig(VR_CONFIG_MODE, VR_MODE_MONO_SCREEN); } else if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (vr3DGeometryCount > 15)) { diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 78133a26a2..a410569d15 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -394,7 +394,7 @@ void VR_FinishFrame( engine_t* engine ) { cylinder_layer.pose.position = pos; cylinder_layer.radius = 12.0f; cylinder_layer.centralAngle = (float)(M_PI * 0.5); - cylinder_layer.aspectRatio = 1; + cylinder_layer.aspectRatio = VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); // Build the cylinder layer if (vrMode == VR_MODE_MONO_SCREEN) { diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index dcd57f1f4b..78de6a5ccf 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -20,6 +20,7 @@ enum VRConfig { enum VRConfigFloat { // 2D canvas positioning VR_CONFIG_CANVAS_DISTANCE, VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, + VR_CONFIG_CANVAS_ASPECT, VR_CONFIG_FLOAT_MAX }; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index aec95318ec..ce0ef039fa 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -78,11 +78,7 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f SmallDisplayZoom zoomType = (SmallDisplayZoom)g_Config.iSmallDisplayZoomType; if (IsVREnabled()) { - if (IsFlatVRScene()) { - zoomType = SmallDisplayZoom::AUTO; - } else { - zoomType = SmallDisplayZoom::STRETCH; - } + zoomType = SmallDisplayZoom::STRETCH; } if (zoomType == SmallDisplayZoom::STRETCH) { diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index ccd764c002..b144bc8dcd 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1305,7 +1305,7 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JN int width, height; GetVRResolutionPerEye(&width, &height); xres = width; - yres = height; + yres = height * 272 / 480; dpi = 320; } From 940a669107b618d3164caf955c77c5bc9a255caf Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 18:04:35 +0100 Subject: [PATCH 319/715] OpenXR - Camera adjust issues resolved --- Common/VR/PPSSPPVR.cpp | 85 +++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index cdf0b60534..8aae4928af 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -37,8 +37,6 @@ enum VRMirroring { }; static VRAppMode appMode = VR_MENU_MODE; -static int pspAxisDeviceId = 0; -static std::map pspAxis; static std::map pspKeys; static int vr3DGeometryCount = 0; @@ -102,6 +100,12 @@ static bool controllerMotion[2][5] = {}; static int mouseController = 1; static bool mousePressed = false; +inline float clampFloat(float x, float minValue, float maxValue) { + if (x < minValue) return minValue; + if (x > maxValue) return maxValue; + return x; +} + /* ================================================================================ @@ -357,16 +361,32 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co } bool UpdateVRAxis(const AxisInput &axis) { - //do not store small input if two devices used at the same time - if (pspAxisDeviceId != axis.deviceId) { - if (fabs(axis.value) < 0.5f) { - return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; + + // Camera control + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { + switch(axis.axisId) { + case JOYSTICK_AXIS_X: + if (axis.value < -0.5f) g_Config.fCameraSide -= 0.05f; + if (axis.value > 0.5f) g_Config.fCameraSide += 0.05f; + g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -50.0f, 50.0f); + break; + case JOYSTICK_AXIS_Y: + if (axis.value > 0.5f) g_Config.fCameraHeight -= 0.05f; + if (axis.value < -0.5f) g_Config.fCameraHeight += 0.05f; + g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); + break; + case JOYSTICK_AXIS_Z: + if (axis.value < -0.5f) g_Config.fFieldOfViewPercentage -= 1.0f; + if (axis.value > 0.5f) g_Config.fFieldOfViewPercentage += 1.0f; + g_Config.fFieldOfViewPercentage = clampFloat(g_Config.fFieldOfViewPercentage, 100.0f, 200.0f); + break; + case JOYSTICK_AXIS_RZ: + if (axis.value > 0.5f) g_Config.fCameraDistance -= 0.1f; + if (axis.value < -0.5f) g_Config.fCameraDistance += 0.1f; + g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -50.0f, 50.0f); + break; } } - - //store axis value - pspAxis[axis.axisId] = axis.value; - pspAxisDeviceId = axis.deviceId; return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; } @@ -379,7 +399,7 @@ bool UpdateVRKeys(const KeyInput &key) { } } - //block keys in the UI + //block keys in the UI mode if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { switch (key.keyCode) { case NKCODE_BACK: @@ -391,6 +411,14 @@ bool UpdateVRKeys(const KeyInput &key) { } } + // Reset camera adjust + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST] && pspKeys[VIRTKEY_VR_CAMERA_RESET]) { + g_Config.fCameraHeight = 0; + g_Config.fCameraSide = 0; + g_Config.fCameraDistance = 0; + g_Config.fFieldOfViewPercentage = 100; + } + //block keys by camera adjust return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; } @@ -468,12 +496,6 @@ void* BindVRFramebuffer() { return VR_BindFramebuffer(VR_GetEngine()); } -inline float clampFloat(float x, float minValue, float maxValue) { - if (x < minValue) return minValue; - if (x > maxValue) return maxValue; - return x; -} - bool StartVRRender() { if (!VR_GetConfig(VR_CONFIG_VIEWPORT_VALID)) { VR_InitRenderer(VR_GetEngine(), IsMultiviewSupported()); @@ -622,35 +644,6 @@ bool StartVRRender() { // Set compatibility vrCompat[VR_COMPAT_SKYPLANE] = PSP_CoreParameter().compat.vrCompat().Skyplane; - // Camera control - if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { - //left joystick controls height and side - if (pspAxis[JOYSTICK_AXIS_X] < -0.5f) g_Config.fCameraSide -= 0.05f; - if (pspAxis[JOYSTICK_AXIS_X] > 0.5f) g_Config.fCameraSide += 0.05f; - if (pspAxis[JOYSTICK_AXIS_Y] > 0.5f) g_Config.fCameraHeight -= 0.05f; - if (pspAxis[JOYSTICK_AXIS_Y] < -0.5f) g_Config.fCameraHeight += 0.05f; - - //right joystick controls distance and fov - if (pspAxis[JOYSTICK_AXIS_Z] < -0.5f) g_Config.fFieldOfViewPercentage -= 1.0f; - if (pspAxis[JOYSTICK_AXIS_Z] > 0.5f) g_Config.fFieldOfViewPercentage += 1.0f; - if (pspAxis[JOYSTICK_AXIS_RZ] > 0.5f) g_Config.fCameraDistance -= 0.1f; - if (pspAxis[JOYSTICK_AXIS_RZ] < -0.5f) g_Config.fCameraDistance += 0.1f; - - // Reset values - if (pspKeys[VIRTKEY_VR_CAMERA_RESET]) { - g_Config.fCameraHeight = 0; - g_Config.fCameraSide = 0; - g_Config.fCameraDistance = 0; - g_Config.fFieldOfViewPercentage = 100; - } - - // Clamp values - g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); - g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -50.0f, 50.0f); - g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -50.0f, 50.0f); - g_Config.fFieldOfViewPercentage = clampFloat(g_Config.fFieldOfViewPercentage, 100.0f, 200.0f); - } - // Set customizations __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); From c7bcfe9fe96dd8104a1d6c7dad11014c8b18d241 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 18:19:47 +0100 Subject: [PATCH 320/715] OpenXR - Accept scrolling from both controllers --- Common/VR/PPSSPPVR.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 8aae4928af..488a1528c9 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -347,14 +347,16 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co } //mouse wheel emulation - keyInput.deviceId = controllerIds[mouseController]; - float scroll = -IN_VRGetJoystickState(mouseController).y; - keyInput.flags = scroll < -0.5f ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_UP; - NativeKey(keyInput); - keyInput.flags = scroll > 0.5f ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN; - NativeKey(keyInput); + for (int j = 0; j < 2; j++) { + keyInput.deviceId = controllerIds[j]; + float scroll = -IN_VRGetJoystickState(j).y; + keyInput.flags = scroll < -0.5f ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_UP; + NativeKey(keyInput); + keyInput.flags = scroll > 0.5f ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN; + NativeKey(keyInput); + } } else { VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 0); } From c9d1da28fcb47b9b0870bf9773ad129710267270 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 18:26:18 +0100 Subject: [PATCH 321/715] OpenXR - Cursor aspect ratio --- Common/VR/VRFramebuffer.cpp | 6 +++--- Common/VR/VRFramebuffer.h | 2 +- Common/VR/VRRenderer.cpp | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index f19c6a589c..792dd5a879 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -411,14 +411,14 @@ void ovrRenderer_Destroy(ovrRenderer* renderer) { } } -void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size) { +void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy) { if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { //TODO:implement } else { #if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL GL(glEnable(GL_SCISSOR_TEST)); - GL(glScissor(x, y, size, size)); - GL(glViewport(x, y, size, size)); + GL(glScissor(x, y, sx, sy)); + GL(glViewport(x, y, sx, sy)); GL(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); GL(glClear(GL_COLOR_BUFFER_BIT)); GL(glDisable(GL_SCISSOR_TEST)); diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index 7440e49d70..07a5c19834 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -12,4 +12,4 @@ void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer); void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext); void ovrRenderer_Destroy(ovrRenderer* renderer); -void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int size); +void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index a410569d15..4d89618c17 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -311,13 +311,14 @@ void VR_EndFrame( engine_t* engine ) { VR_BindFramebuffer(engine); // Show mouse cursor - int size = vrConfig[VR_CONFIG_MOUSE_SIZE]; int vrMode = vrConfig[VR_CONFIG_MODE]; bool screenMode = (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN); - if (screenMode && (size > 0)) { + if (screenMode && (vrConfig[VR_CONFIG_MOUSE_SIZE] > 0)) { int x = vrConfig[VR_CONFIG_MOUSE_X]; int y = vrConfig[VR_CONFIG_MOUSE_Y]; - ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, size); + int sx = vrConfig[VR_CONFIG_MOUSE_SIZE]; + int sy = sx * VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); + ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, sx, sy); } ovrFramebuffer_Release(&engine->appState.Renderer.FrameBuffer[fboIndex]); From 4a770b36cf2a6437b14daebc1e2d8514a7b8be48 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 17 Nov 2022 19:13:04 +0100 Subject: [PATCH 322/715] Typo fixed --- Common/VR/PPSSPPVR.h | 2 +- UI/ControlMappingScreen.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index c8c33420a3..5b31cc7a7f 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -18,7 +18,7 @@ enum VRCompatFlag { }; enum VRAppMode { - VR_CONTROLL_MAPPING_MODE, + VR_CONTROLLER_MAPPING_MODE, VR_DIALOG_MODE, VR_GAME_MODE, VR_MENU_MODE, diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 1415cb53be..b0f0651735 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -330,7 +330,7 @@ void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { std::string pspButtonName = KeyMap::GetPspButtonName(this->pspBtn_); parent->Add(new TextView(std::string(km->T("Map a new key for")) + " " + mc->T(pspButtonName), new LinearLayoutParams(Margins(10,0)))); - SetVRAppMode(VRAppMode::VR_CONTROLL_MAPPING_MODE); + SetVRAppMode(VRAppMode::VR_CONTROLLER_MAPPING_MODE); } bool KeyMappingNewKeyDialog::key(const KeyInput &key) { @@ -363,7 +363,7 @@ void KeyMappingNewMouseKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { auto km = GetI18NCategory("KeyMapping"); parent->Add(new TextView(std::string(km->T("You can press ESC to cancel.")), new LinearLayoutParams(Margins(10, 0)))); - SetVRAppMode(VRAppMode::VR_CONTROLL_MAPPING_MODE); + SetVRAppMode(VRAppMode::VR_CONTROLLER_MAPPING_MODE); } bool KeyMappingNewMouseKeyDialog::key(const KeyInput &key) { From 47e5df384431f7622daf04f07e2a8a8015d0f97b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 17 Nov 2022 18:32:38 -0800 Subject: [PATCH 323/715] GPU: Prefer raster for depth blit if supported. This seems to work around an apparent NVIDIA driver bug. --- GPU/Common/FramebufferManagerCommon.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index a2e4ec05c6..14a0ed1980 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -944,33 +944,21 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir bool useCopy = draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || (!draw_->GetDeviceCaps().framebufferDepthBlitSupported && draw_->GetDeviceCaps().framebufferCopySupported); bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; - bool useRaster = draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported; - - // Could do an attempt at optimization - if destination already bound, draw depth using raster. - // Let's experiment later, commented out for now. Currently we fall back to raster as a last resort here. - - /* - if (currentRenderVfb_ == dst) { - useCopy = false; - useBlit = false; - } - */ + bool useRaster = draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported && draw_->GetDeviceCaps().textureDepthSupported; int w = std::min(src->renderWidth, dst->renderWidth); int h = std::min(src->renderHeight, dst->renderHeight); - // TODO: It might even be advantageous on some GPUs to do this copy using a fragment shader that writes to Z, that way upcoming commands can just continue that render pass. - // Some GPUs can copy depth but only if stencil gets to come along for the ride. We only want to use this if there is no blit functionality. - if (useCopy) { + if (useRaster) { + BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, dst->renderScaleFactor, Get2DPipeline(Draw2DShader::DRAW2D_COPY_DEPTH), "BlitDepthRaster"); + } else if (useCopy) { draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, w, h, 1, Draw::FB_DEPTH_BIT, "CopyFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); } else if (useBlit) { // We'll accept whether we get a separate depth blit or not... draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); - } else if (useRaster) { - BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, dst->renderScaleFactor, Get2DPipeline(Draw2DShader::DRAW2D_COPY_DEPTH), "BlitDepthRaster"); } draw_->InvalidateCachedState(); From 2419e5680a94b9b6f46dd00e808011ed962b2cef Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 18 Nov 2022 17:53:53 -0800 Subject: [PATCH 324/715] irjit: Correct VV2Op SIMD check. It's unlikely, but possible, uninitialized data could cause IsConsecutive4() to return true when n < 4. --- Core/MIPS/IR/IRCompVFPU.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 74b0615547..8515b6031f 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -788,7 +788,7 @@ namespace MIPSComp { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - u8 sregs[4], dregs[4]; + u8 sregs[4]{}, dregs[4]{}; GetVectorRegsPrefixS(sregs, sz, vs); GetVectorRegsPrefixD(dregs, sz, vd); @@ -809,7 +809,8 @@ namespace MIPSComp { case 0: // vmov case 1: // vabs case 2: // vneg - canSIMD = true; + // Our Vec4 ops require aligned regs and sets of 4. + canSIMD = n == 4 && (sregs[0] & 3) == 0 && (dregs[0] & 3) == 0; break; } From ada06744157a84e251c6566dedf92975535a6430 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 18 Nov 2022 17:54:58 -0800 Subject: [PATCH 325/715] irjit: Allow VV2Op SIMD with exact overlap. None of these look at other lanes. --- Core/MIPS/IR/IRCompVFPU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 8515b6031f..02f3e172e5 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -795,7 +795,7 @@ namespace MIPSComp { bool usingTemps = false; u8 tempregs[4]; for (int i = 0; i < n; ++i) { - if (!IsOverlapSafe(dregs[i], n, sregs)) { + if (!IsOverlapSafeAllowS(dregs[i], i, n, sregs)) { usingTemps = true; tempregs[i] = IRVTEMP_0 + i; } else { From c0854133261cc5f01ba2ba5d9d3517401d8c7d47 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 18 Nov 2022 19:06:50 -0800 Subject: [PATCH 326/715] irjit: Consistently check vec4 safety. Just to prevent confusion/surprises, this is clearer. --- Core/MIPS/IR/IRCompVFPU.cpp | 59 ++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 02f3e172e5..f325f006b3 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -72,6 +72,24 @@ namespace MIPSComp { regs[3] == regs[2] + 1; } + static bool IsVec4(VectorSize sz, const u8 regs[4]) { + return sz == V_Quad && IsConsecutive4(regs) && (regs[0] & 3) == 0; + } + + static bool IsMatrixVec4(MatrixSize sz, const u8 regs[16]) { + if (sz != M_4x4) + return false; + if (!IsConsecutive4(®s[0]) || (regs[0] & 3) != 0) + return false; + if (!IsConsecutive4(®s[4]) || (regs[4] & 3) != 0) + return false; + if (!IsConsecutive4(®s[8]) || (regs[8] & 3) != 0) + return false; + if (!IsConsecutive4(®s[12]) || (regs[12] & 3) != 0) + return false; + return true; + } + // Vector regs can overlap in all sorts of swizzled ways. // This does allow a single overlap in sregs[i]. static bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) { @@ -173,7 +191,7 @@ namespace MIPSComp { origV[i] = vregs[i]; // Some common vector prefixes - if (sz == V_Quad && IsConsecutive4(vregs)) { + if (IsVec4(sz, vregs)) { if (prefix == 0xF00E4) { InitRegs(vregs, tempReg); ir.Write(IROp::Vec4Neg, vregs[0], origV[0]); @@ -327,7 +345,7 @@ namespace MIPSComp { switch (op >> 26) { case 54: //lv.q - if (IsConsecutive4(vregs)) { + if (IsVec4(V_Quad, vregs)) { ir.Write(IROp::LoadVec4, vregs[0], rs, ir.AddConstant(imm)); } else { // Let's not even bother with "vertical" loads for now. @@ -341,7 +359,7 @@ namespace MIPSComp { break; case 62: //sv.q - if (IsConsecutive4(vregs)) { + if (IsVec4(V_Quad, vregs)) { ir.Write(IROp::StoreVec4, vregs[0], rs, ir.AddConstant(imm)); } else { // Let's not even bother with "vertical" stores for now. @@ -381,7 +399,7 @@ namespace MIPSComp { u8 dregs[4]; GetVectorRegsPrefixD(dregs, sz, vd); - if (sz == V_Quad && IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { ir.Write(IROp::Vec4Init, dregs[0], (int)(type == 6 ? Vec4Init::AllZERO : Vec4Init::AllONE)); } else { for (int i = 0; i < n; i++) { @@ -406,7 +424,7 @@ namespace MIPSComp { u8 dregs[4]; GetVectorRegsPrefixD(dregs, sz, vd); - if (sz == 4 && IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { int row = vd & 3; Vec4Init init = Vec4Init((int)Vec4Init::Set_1000 + row); ir.Write(IROp::Vec4Init, dregs[0], (int)init); @@ -574,7 +592,7 @@ namespace MIPSComp { GetVectorRegsPrefixT(tregs, sz, vt); GetVectorRegsPrefixD(dregs, V_Single, vd); - if (sz == V_Quad && IsConsecutive4(sregs) && IsConsecutive4(tregs) && IsOverlapSafe(dregs[0], n, sregs, n, tregs)) { + if (IsVec4(sz, sregs) && IsVec4(sz, tregs) && IsOverlapSafe(dregs[0], n, sregs, n, tregs)) { ir.Write(IROp::Vec4Dot, dregs[0], sregs[0], tregs[0]); ApplyPrefixD(dregs, V_Single); return; @@ -660,7 +678,7 @@ namespace MIPSComp { } // If all three are consecutive 4, we're safe regardless of if we use temps so we should not check that here. - if (allowSIMD && sz == V_Quad && IsConsecutive4(dregs) && IsConsecutive4(sregs) && IsConsecutive4(tregs)) { + if (allowSIMD && IsVec4(sz, dregs) && IsVec4(sz, sregs) && IsVec4(sz, tregs)) { IROp opFunc = IROp::Nop; switch (op >> 26) { case 24: //VFPU0 @@ -809,12 +827,11 @@ namespace MIPSComp { case 0: // vmov case 1: // vabs case 2: // vneg - // Our Vec4 ops require aligned regs and sets of 4. - canSIMD = n == 4 && (sregs[0] & 3) == 0 && (dregs[0] & 3) == 0; + canSIMD = true; break; } - if (canSIMD && !usingTemps && IsConsecutive4(sregs) && IsConsecutive4(dregs)) { + if (canSIMD && !usingTemps && IsVec4(sz, sregs) && IsVec4(sz, dregs)) { switch (optype) { case 0: // vmov ir.Write(IROp::Vec4Mov, dregs[0], sregs[0]); @@ -1212,7 +1229,7 @@ namespace MIPSComp { } } - if (n == 4 && IsConsecutive4(sregs) && IsConsecutive4(dregs)) { + if (IsVec4(sz, sregs) && IsVec4(sz, dregs)) { if (!overlap || (vs == vd && IsOverlapSafe(treg, n, dregs))) { ir.Write(IROp::Vec4Scale, dregs[0], sregs[0], treg); ApplyPrefixD(dregs, sz); @@ -1297,12 +1314,12 @@ namespace MIPSComp { // dregs are always consecutive, thanks to our transpose trick. // However, not sure this is always worth it. - if (sz == M_4x4 && IsConsecutive4(dregs)) { + if (IsMatrixVec4(sz, dregs)) { // TODO: The interpreter would like proper matrix ops better. Can generate those, and // expand them like this as needed on "real" architectures. int s0 = IRVTEMP_0; int s1 = IRVTEMP_PFX_T; - if (!IsConsecutive4(sregs)) { + if (!IsMatrixVec4(sz, sregs)) { // METHOD 1: Handles AbC and Abc for (int j = 0; j < 4; j++) { ir.Write(IROp::Vec4Scale, s0, sregs[0], tregs[j * 4]); @@ -1313,7 +1330,7 @@ namespace MIPSComp { ir.Write(IROp::Vec4Mov, dregs[j * 4], s0); } return; - } else if (IsConsecutive4(tregs)) { + } else if (IsMatrixVec4(sz, tregs)) { // METHOD 2: Handles ABC only. Not efficient on CPUs that don't do fast dots. // Dots only work if tregs are consecutive. // TODO: Skip this and resort to method one and transpose the output? @@ -1379,7 +1396,7 @@ namespace MIPSComp { GetVectorRegs(dregs, sz, _VD); // SIMD-optimized implementations - if sregs[0..3] is non-consecutive, it's transposed. - if (msz == M_4x4 && !IsConsecutive4(sregs)) { + if (msz == M_4x4 && !IsMatrixVec4(msz, sregs)) { int s0 = IRVTEMP_0; int s1 = IRVTEMP_PFX_S; // For this algorithm, we don't care if tregs are consecutive or not, @@ -1394,7 +1411,7 @@ namespace MIPSComp { ir.Write(IROp::Vec4Add, s0, s0, sregs[i]); } } - if (IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { ir.Write(IROp::Vec4Mov, dregs[0], s0); } else { for (int i = 0; i < 4; i++) { @@ -1402,7 +1419,7 @@ namespace MIPSComp { } } return; - } else if (msz == M_4x4 && IsConsecutive4(sregs)) { + } else if (msz == M_4x4 && IsMatrixVec4(msz, sregs)) { // Consecutive, which is harder. DISABLE; int s0 = IRVTEMP_0; @@ -1417,7 +1434,7 @@ namespace MIPSComp { ir.Write(IROp::Vec4Add, s0, s0, sregs[i]); } } - if (IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { ir.Write(IROp::Vec4Mov, dregs[0], s0); } else { for (int i = 0; i < 4; i++) { @@ -1517,8 +1534,8 @@ namespace MIPSComp { int nOut = GetNumVectorElements(outsize); - // If src registers aren't contiguous, make them. - if (sz == V_Quad && !IsConsecutive4(sregs)) { + // If src registers aren't contiguous, make them (mainly for bits == 8.) + if (sz == V_Quad && !IsVec4(sz, sregs)) { // T prefix is unused. for (int i = 0; i < 4; i++) { srcregs[i] = IRVTEMP_PFX_T + i; @@ -1624,7 +1641,7 @@ namespace MIPSComp { } } } else if (outsize == V_Quad) { - bool consecutive = IsConsecutive4(dregs); + bool consecutive = IsVec4(outsize, dregs); if (!consecutive || !IsOverlapSafe(nOut, dregs, nIn, srcregs)) { for (int i = 0; i < nOut; i++) { tempregs[i] = IRVTEMP_PFX_T + i; From 3938c0a3afeb935f406f3b0cf9aa35aae35e1d25 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 18 Nov 2022 23:11:11 -0800 Subject: [PATCH 327/715] Debugger: Combine mem info on duplicates. Gran Turismo does some churn on texture sizes, we can combine them and reduce the speed hit even when detailed. --- Core/Debugger/MemBlockInfo.cpp | 40 ++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/Core/Debugger/MemBlockInfo.cpp b/Core/Debugger/MemBlockInfo.cpp index e361b63014..909803b797 100644 --- a/Core/Debugger/MemBlockInfo.cpp +++ b/Core/Debugger/MemBlockInfo.cpp @@ -405,6 +405,29 @@ static inline uint32_t NormalizeAddress(uint32_t addr) { return addr & 0x3FFFFFFF; } +static inline bool MergeRecentMemInfo(const PendingNotifyMem &info, size_t copyLength) { + if (pendingNotifies.size() < 4) + return false; + + for (size_t i = 1; i <= 4; ++i) { + auto &prev = pendingNotifies[pendingNotifies.size() - i]; + if (prev.start >= info.start + info.size || prev.start + prev.size <= info.start) + continue; + + // This means there's overlap, but not a match, so we can't combine any. + if (prev.start != info.start || prev.size > info.size) + return false; + + memcpy(prev.tag, info.tag, copyLength + 1); + prev.size = info.size; + prev.ticks = info.ticks; + prev.pc = info.pc; + return true; + } + + return false; +} + void NotifyMemInfoPC(MemBlockFlags flags, uint32_t start, uint32_t size, uint32_t pc, const char *tagStr, size_t strLength) { if (size == 0) { return; @@ -427,14 +450,17 @@ void NotifyMemInfoPC(MemBlockFlags flags, uint32_t start, uint32_t size, uint32_ info.tag[copyLength] = 0; std::lock_guard guard(pendingMutex); - if (start < 0x08000000) { - pendingNotifyMinAddr1 = std::min(pendingNotifyMinAddr1.load(), start); - pendingNotifyMaxAddr1 = std::max(pendingNotifyMaxAddr1.load(), start + size); - } else { - pendingNotifyMinAddr2 = std::min(pendingNotifyMinAddr2.load(), start); - pendingNotifyMaxAddr2 = std::max(pendingNotifyMaxAddr2.load(), start + size); + // Sometimes we get duplicates, quickly check. + if (!MergeRecentMemInfo(info, copyLength)) { + if (start < 0x08000000) { + pendingNotifyMinAddr1 = std::min(pendingNotifyMinAddr1.load(), start); + pendingNotifyMaxAddr1 = std::max(pendingNotifyMaxAddr1.load(), start + size); + } else { + pendingNotifyMinAddr2 = std::min(pendingNotifyMinAddr2.load(), start); + pendingNotifyMaxAddr2 = std::max(pendingNotifyMaxAddr2.load(), start + size); + } + pendingNotifies.push_back(info); } - pendingNotifies.push_back(info); needFlush = pendingNotifies.size() > MAX_PENDING_NOTIFIES; } From 59d6266744b8f7a436bb0c108a5225cb1efa89c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 19 Nov 2022 20:54:26 +0100 Subject: [PATCH 328/715] Orient Save State / Load State buttons horizontally As suggested back in #7437 , this pretty much matches that screenshot. Makes it a bit harder to misclick save/load state. Part of #13016 Fixes #7437 --- UI/PauseScreen.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 7a75cd8806..4cb74d067e 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -287,9 +287,15 @@ SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams auto pa = GetI18NCategory("Pause"); - LinearLayout *buttons = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - buttons->SetSpacing(2.0); - Add(buttons); + LinearLayout *lines = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + lines->SetSpacing(2.0f); + + Add(lines); + + LinearLayout *buttons = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + buttons->SetSpacing(10.0f); + + lines->Add(buttons); saveStateButton_ = buttons->Add(new Button(pa->T("Save State"), new LinearLayoutParams(0.0, G_VCENTER))); saveStateButton_->OnClick.Handle(this, &SaveSlotView::OnSaveState); @@ -301,14 +307,8 @@ SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams loadStateButton_->OnClick.Handle(this, &SaveSlotView::OnLoadState); std::string dateStr = SaveState::GetSlotDateAsString(gamePath_, slot_); - std::vector dateStrs; - SplitString(dateStr, ' ', dateStrs); - if (!dateStrs.empty() && !dateStrs[0].empty()) { - LinearLayout *strs = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - Add(strs); - for (size_t i = 0; i < dateStrs.size(); i++) { - strs->Add(new TextView(dateStrs[i], new LinearLayoutParams(0.0, G_VCENTER)))->SetShadow(true); - } + if (!dateStr.empty()) { + lines->Add(new TextView(dateStr, new LinearLayoutParams(0.0, G_VCENTER)))->SetShadow(true); } } else { fv->SetFilename(Path()); From 6c2001d12d31bb71fc776d22554ae2a2ac2ce4a3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 19 Nov 2022 14:59:03 -0800 Subject: [PATCH 329/715] GE Debugger: Correct texture address corruption. Happened when playing back frame dumps that set bufw after specifying the texture address, but before drawing. Seen in Syphon Filter. --- GPU/Debugger/Playback.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index 03472ba834..593236889a 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -392,6 +392,11 @@ bool DumpExecute::SubmitCmds(const void *p, u32 sz) { // TODO: Unfortunate. Maybe Texture commands should contain the bufw instead. // The goal here is to realistically combine prims in dumps. Stalling for the bufw flushes. u32_le *ops = (u32_le *)Memory::GetPointerUnchecked(writePos); + + u32 lastTexHigh[8]{}; + for (int i = 0; i < 8; ++i) + lastTexHigh[i] = ((lastTex_[i] & 0xFF000000) >> 8) | ((GE_CMD_TEXBUFWIDTH0 + i) << 24); + for (u32 i = 0; i < sz / 4; ++i) { u32 cmd = ops[i] >> 24; if (cmd >= GE_CMD_TEXBUFWIDTH0 && cmd <= GE_CMD_TEXBUFWIDTH7) { @@ -402,7 +407,7 @@ bool DumpExecute::SubmitCmds(const void *p, u32 sz) { if (bufw == lastBufw_[level]) ops[i] = GE_CMD_NOP << 24; else - ops[i] = (gstate.texbufwidth[level] & 0xFFFF0000) | bufw; + ops[i] = lastTexHigh[level] | bufw; lastBufw_[level] = bufw; } From 71b4407889e7ccecf47b1e8cfcb8ab6b2680f132 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 19 Nov 2022 20:30:49 -0800 Subject: [PATCH 330/715] softgpu: Throw away all inverted polygons. This is actually incorrect in some cases, but there are a number of games affected by inversions, and they're practically always undesired. --- GPU/Software/Clipper.cpp | 52 +++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index bae2be1881..f7fb78405a 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -49,7 +49,17 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, return (vert.clippos.x * A + vert.clippos.y * B + vert.clippos.z * C + vert.clippos.w * D); } -#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \ +inline void clip_interpolate(ClipVertexData &dest, float t, const ClipVertexData &a, const ClipVertexData &b) { + dest.Lerp(t, a, b); + if (different_signs(a.clippos.w, b.clippos.w)) { + dest.v.screenpos.x = 0x7FFFFFFF; + } else { + dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos); + dest.v.clipw = dest.clippos.w; + } +} + +#define CLIP_POLY( PLANE_BIT, A, B, C, D ) \ { \ if (mask & PLANE_BIT) { \ int idxPrev = inlist[0]; \ @@ -64,15 +74,17 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, outlist[outcount++] = idxPrev; \ } \ \ - if (different_signs(dp, dpPrev)) { \ + /* Skipping w sign mismatches avoids inversions, but is incorrect. See #16131. */ \ + /* For now, it's better to avoid inversions as they usually are undesired. */ \ + if (different_signs(dp, dpPrev)) { \ + auto &vert = Vertices[numVertices++]; \ if (dp < 0) { \ float t = dp / (dp - dpPrev); \ - Vertices[numVertices++]->Lerp(t, *Vertices[idx], *Vertices[idxPrev]); \ + clip_interpolate(*vert, t, *Vertices[idx], *Vertices[idxPrev]); \ } else { \ float t = dpPrev / (dpPrev - dp); \ - Vertices[numVertices++]->Lerp(t, *Vertices[idxPrev], *Vertices[idx]); \ + clip_interpolate(*vert, t, *Vertices[idxPrev], *Vertices[idx]); \ } \ - clipped = true; \ outlist[outcount++] = numVertices - 1; \ } \ \ @@ -101,8 +113,7 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, if (mask0 & PLANE_BIT) { \ if (dp0 < 0) { \ float t = dp1 / (dp1 - dp0); \ - Vertices[0]->Lerp(t, *Vertices[1], *Vertices[0]); \ - clipped = true; \ + clip_interpolate(*Vertices[0], t, *Vertices[1], *Vertices[0]); \ } \ } \ dp0 = clip_dotprod(*Vertices[0], A, B, C, D ); \ @@ -110,8 +121,7 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, if (mask1 & PLANE_BIT) { \ if (dp1 < 0) { \ float t = dp1 / (dp1- dp0); \ - Vertices[1]->Lerp(t, *Vertices[1], *Vertices[0]); \ - clipped = true; \ + clip_interpolate(*Vertices[1], t, *Vertices[1], *Vertices[0]); \ } \ } \ } \ @@ -294,17 +304,11 @@ void ProcessLine(const ClipVertexData &v0, const ClipVertexData &v1, BinManager ClipVertexData ClippedVertices[2] = { v0, v1 }; ClipVertexData *Vertices[2] = { &ClippedVertices[0], &ClippedVertices[1] }; - bool clipped = false; CLIP_LINE(CLIP_NEG_Z_BIT, 0, 0, 1, 1); ClipVertexData data[2] = { *Vertices[0], *Vertices[1] }; - if (clipped) { - data[0].v.screenpos = TransformUnit::ClipToScreen(data[0].clippos); - data[1].v.screenpos = TransformUnit::ClipToScreen(data[1].clippos); - data[0].v.clipw = data[0].clippos.w; - data[1].v.clipw = data[1].clippos.w; - } - binner.AddLine(data[0].v, data[1].v); + if (!data[0].OutsideRange() && !data[1].OutsideRange()) + binner.AddLine(data[0].v, data[1].v); } void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const ClipVertexData &v2, const ClipVertexData &provoking, BinManager &binner) { @@ -363,7 +367,6 @@ void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const C int indices[NUM_INDICES] = { 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG }; int numIndices = 3; - bool clipped = false; for (int i = 0; i < 3; i += 3) { int vlist[2][2*6+1]; @@ -381,7 +384,7 @@ void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const C indices[2] = SKIP_FLAG; // The PSP only clips on negative Z (importantly, regardless of viewport.) - POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); + CLIP_POLY(CLIP_NEG_Z_BIT, 0, 0, 1, 1); // transform the poly in inlist into triangles indices[0] = inlist[0]; @@ -399,14 +402,9 @@ void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const C ClipVertexData &subv0 = *Vertices[indices[i + 0]]; ClipVertexData &subv1 = *Vertices[indices[i + 1]]; ClipVertexData &subv2 = *Vertices[indices[i + 2]]; - if (clipped) { - subv0.v.screenpos = TransformUnit::ClipToScreen(subv0.clippos); - subv1.v.screenpos = TransformUnit::ClipToScreen(subv1.clippos); - subv2.v.screenpos = TransformUnit::ClipToScreen(subv2.clippos); - subv0.v.clipw = subv0.clippos.w; - subv1.v.clipw = subv1.clippos.w; - subv2.v.clipw = subv2.clippos.w; - } + + if (subv0.OutsideRange() || subv1.OutsideRange() | subv2.OutsideRange()) + continue; if (gstate.getShadeMode() == GE_SHADE_FLAT) { // So that the order of clipping doesn't matter... From 1e9ddfda316ee9dccd650b767d0465cb300162a6 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 20 Nov 2022 12:22:10 +0100 Subject: [PATCH 331/715] OpenXR - 3rd party controller support fixed --- Common/VR/PPSSPPVR.cpp | 79 ++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 488a1528c9..77fcb64fb7 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -37,6 +37,7 @@ enum VRMirroring { }; static VRAppMode appMode = VR_MENU_MODE; +static std::map > pspAxis; static std::map pspKeys; static int vr3DGeometryCount = 0; @@ -298,6 +299,36 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co } } + // Camera adjust + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { + for (auto& device : pspAxis) { + for (auto& axis : device.second) { + switch(axis.first) { + case JOYSTICK_AXIS_X: + if (axis.second < -0.75f) g_Config.fCameraSide -= 0.05f; + if (axis.second > 0.75f) g_Config.fCameraSide += 0.05f; + g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -50.0f, 50.0f); + break; + case JOYSTICK_AXIS_Y: + if (axis.second > 0.75f) g_Config.fCameraHeight -= 0.05f; + if (axis.second < -0.75f) g_Config.fCameraHeight += 0.05f; + g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); + break; + case JOYSTICK_AXIS_Z: + if (axis.second < -0.75f) g_Config.fFieldOfViewPercentage -= 1.0f; + if (axis.second > 0.75f) g_Config.fFieldOfViewPercentage += 1.0f; + g_Config.fFieldOfViewPercentage = clampFloat(g_Config.fFieldOfViewPercentage, 100.0f, 200.0f); + break; + case JOYSTICK_AXIS_RZ: + if (axis.second > 0.75f) g_Config.fCameraDistance -= 0.1f; + if (axis.second < -0.75f) g_Config.fCameraDistance += 0.1f; + g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -50.0f, 50.0f); + break; + } + } + } + } + //enable or disable mouse for (int j = 0; j < 2; j++) { bool pressed = IN_VRGetButtonState(j) & ovrButton_Trigger; @@ -363,32 +394,10 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co } bool UpdateVRAxis(const AxisInput &axis) { - - // Camera control - if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { - switch(axis.axisId) { - case JOYSTICK_AXIS_X: - if (axis.value < -0.5f) g_Config.fCameraSide -= 0.05f; - if (axis.value > 0.5f) g_Config.fCameraSide += 0.05f; - g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -50.0f, 50.0f); - break; - case JOYSTICK_AXIS_Y: - if (axis.value > 0.5f) g_Config.fCameraHeight -= 0.05f; - if (axis.value < -0.5f) g_Config.fCameraHeight += 0.05f; - g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); - break; - case JOYSTICK_AXIS_Z: - if (axis.value < -0.5f) g_Config.fFieldOfViewPercentage -= 1.0f; - if (axis.value > 0.5f) g_Config.fFieldOfViewPercentage += 1.0f; - g_Config.fFieldOfViewPercentage = clampFloat(g_Config.fFieldOfViewPercentage, 100.0f, 200.0f); - break; - case JOYSTICK_AXIS_RZ: - if (axis.value > 0.5f) g_Config.fCameraDistance -= 0.1f; - if (axis.value < -0.5f) g_Config.fCameraDistance += 0.1f; - g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -50.0f, 50.0f); - break; - } + if (pspAxis.find(axis.deviceId) == pspAxis.end()) { + pspAxis[axis.deviceId] = std::map(); } + pspAxis[axis.deviceId][axis.axisId] = axis.value; return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; } @@ -401,15 +410,17 @@ bool UpdateVRKeys(const KeyInput &key) { } } - //block keys in the UI mode - if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { - switch (key.keyCode) { - case NKCODE_BACK: - case NKCODE_EXT_MOUSEWHEEL_UP: - case NKCODE_EXT_MOUSEWHEEL_DOWN: - return true; - default: - return false; + //block VR controller keys in the UI mode + if ((key.deviceId == controllerIds[0]) || (key.deviceId == controllerIds[1])) { + if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { + switch (key.keyCode) { + case NKCODE_BACK: + case NKCODE_EXT_MOUSEWHEEL_UP: + case NKCODE_EXT_MOUSEWHEEL_DOWN: + return true; + default: + return false; + } } } From 63cbd9c79bb892fb7a64a72c3107ac8371c0ff46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 20 Nov 2022 12:22:50 +0100 Subject: [PATCH 332/715] Make the pause screen "transparent" When paused (ESC or back), you now see the paused game below, darkened, instead of the usual menu background. Not enabled in VR mode for now because it could get weird. Also not trivial in skip-buffered mode (would require taking a screenshot) so disabled in that case too. --- UI/EmuScreen.cpp | 16 +++++++++++++--- UI/PauseScreen.cpp | 18 ++++++++++++++++++ UI/PauseScreen.h | 9 ++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 8c3c74a994..5d5baee855 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1105,7 +1105,6 @@ void EmuScreen::update() { } } } - } void EmuScreen::checkPowerDown() { @@ -1356,8 +1355,7 @@ void EmuScreen::preRender() { // We only bind it in FramebufferManager::CopyDisplayToOutput (unless non-buffered)... // We do, however, start the frame in other ways. - bool useBufferedRendering = !g_Config.bSkipBufferEffects; - if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) { + if ((g_Config.bSkipBufferEffects && !g_Config.bSoftwareRendering) || Core_IsStepping()) { // We need to clear here already so that drawing during the frame is done on a clean slate. if (Core_IsStepping() && gpuStats.numFlips != 0) { draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer"); @@ -1393,6 +1391,18 @@ void EmuScreen::render() { if (!thin3d) return; // shouldn't really happen but I've seen a suspicious stack trace.. + // We can still render behind the pause screen. + bool paused = screenManager()->topScreen() != this; + + if (paused) { + // If we're paused and PauseScreen is transparent (will only be in buffered rendering mode), we just copy display to output. + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Paused"); + if (PSP_IsInited()) { + gpu->CopyDisplayToOutput(true); + } + return; + } + if (invalid_) { // Loading, or after shutdown? if (loadingTextView_->GetVisibility() == UI::V_VISIBLE) diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 4cb74d067e..6e3e3d001e 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -364,6 +364,24 @@ GamePauseScreen::~GamePauseScreen() { __DisplaySetWasPaused(); } +bool GamePauseScreen::isTransparent() const { + // We don't support transparent pause screen in skipbuffereffects mode. + return !g_Config.bSkipBufferEffects && !IsVREnabled(); +} + +void GamePauseScreen::DrawBackground(UIContext &dc) { + if (isTransparent()) { + // Darken the game screen coming from below, so the UI on top stands out. + dc.Flush(); + uint32_t color = blackAlpha(0.45f); + dc.FillRect(UI::Drawable(color), dc.GetBounds()); + dc.Flush(); + return; + } + + UIDialogScreenWithGameBackground::DrawBackground(dc); +} + void GamePauseScreen::CreateViews() { static const int NUM_SAVESLOTS = 5; diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 3c66609285..6b48f7bdb2 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -31,15 +31,18 @@ public: GamePauseScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename), gamePath_(filename) {} virtual ~GamePauseScreen(); - virtual void dialogFinished(const Screen *dialog, DialogResult dr) override; + void dialogFinished(const Screen *dialog, DialogResult dr) override; const char *tag() const override { return "GamePause"; } protected: - virtual void CreateViews() override; - virtual void update() override; + void CreateViews() override; + void update() override; void CallbackDeleteConfig(bool yes); + bool isTransparent() const override; + void DrawBackground(UIContext &dc) override; + private: UI::EventReturn OnGameSettings(UI::EventParams &e); UI::EventReturn OnExitToMenu(UI::EventParams &e); From 37ec31dedd308b24d50506b5afa1485aa228b844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 20 Nov 2022 12:57:32 +0100 Subject: [PATCH 333/715] Fix resizing issue. Took some refactoring. --- GPU/D3D11/GPU_D3D11.cpp | 9 +-------- GPU/D3D11/GPU_D3D11.h | 2 +- GPU/Directx9/GPU_DX9.cpp | 9 +-------- GPU/Directx9/GPU_DX9.h | 2 +- GPU/GLES/GPU_GLES.cpp | 9 +-------- GPU/GLES/GPU_GLES.h | 2 +- GPU/GPUCommon.cpp | 14 ++++++++++++++ GPU/GPUCommon.h | 3 +++ GPU/GPUInterface.h | 1 + GPU/Software/SoftGpu.h | 2 ++ GPU/Vulkan/GPU_Vulkan.cpp | 10 +--------- GPU/Vulkan/GPU_Vulkan.h | 2 +- UI/EmuScreen.cpp | 12 ++++++++++++ 13 files changed, 40 insertions(+), 37 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 93793165ac..1f465fa54f 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -160,14 +160,7 @@ void GPU_D3D11::InitClear() { void GPU_D3D11::BeginHostFrame() { GPUCommon::BeginHostFrame(); UpdateCmdInfo(); - if (resized_) { - gstate_c.useFlags = CheckGPUFeatures(); - framebufferManager_->Resized(); - drawEngine_.NotifyConfigChanged(); - textureCache_->NotifyConfigChanged(); - shaderManagerD3D11_->DirtyLastShader(); - resized_ = false; - } + CheckResized(); } void GPU_D3D11::ReapplyGfxState() { diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index e45c1ab79d..c0d969926a 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -66,7 +66,7 @@ private: } // void ApplyDrawState(int prim); void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void BeginFrame() override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 6d8926e0fe..e3aebbc796 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -150,14 +150,7 @@ void GPU_DX9::InitClear() { void GPU_DX9::BeginHostFrame() { GPUCommon::BeginHostFrame(); UpdateCmdInfo(); - if (resized_) { - gstate_c.useFlags = CheckGPUFeatures(); - framebufferManager_->Resized(); - drawEngine_.NotifyConfigChanged(); - textureCache_->NotifyConfigChanged(); - shaderManagerDX9_->DirtyShader(); - resized_ = false; - } + CheckResized(); } void GPU_DX9::ReapplyGfxState() { diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 7c6a88d180..c877c17482 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -63,7 +63,7 @@ private: drawEngine_.Flush(); } void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void BeginFrame() override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 16f6ad611e..f0a796f543 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -268,14 +268,7 @@ void GPU_GLES::InitClear() { void GPU_GLES::BeginHostFrame() { GPUCommon::BeginHostFrame(); UpdateCmdInfo(); - if (resized_) { - gstate_c.useFlags = CheckGPUFeatures(); - framebufferManager_->Resized(); - drawEngine_.NotifyConfigChanged(); - textureCache_->NotifyConfigChanged(); - shaderManagerGL_->DirtyShader(); - resized_ = false; - } + CheckResized(); drawEngine_.BeginFrame(); } diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index 98bb1d9362..4955a3c511 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -73,7 +73,7 @@ private: drawEngine_.Flush(); } void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void BeginFrame() override; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 9406429e58..6794e0611e 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -611,6 +611,20 @@ void GPUCommon::Resized() { resized_ = true; } +// Called once per frame. Might also get called during the pause screen +// if "transparent". +void GPUCommon::CheckResized() { + if (resized_) { + gstate_c.useFlags = CheckGPUFeatures(); + BuildReportingInfo(); + framebufferManager_->Resized(); + drawEngineCommon_->NotifyConfigChanged(); + textureCache_->NotifyConfigChanged(); + shaderManager_->DirtyLastShader(); + resized_ = false; + } +} + void GPUCommon::DumpNextFrame() { dumpNextFrame_ = true; } diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index fc2cd13888..39aca24454 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -77,6 +77,7 @@ public: return draw_; } virtual u32 CheckGPUFeatures() const; + void CheckResized() override; void UpdateCmdInfo(); @@ -309,6 +310,8 @@ protected: size_t FormatGPUStatsCommon(char *buf, size_t size); + virtual void BuildReportingInfo() = 0; + FramebufferManagerCommon *framebufferManager_ = nullptr; TextureCacheCommon *textureCache_ = nullptr; DrawEngineCommon *drawEngineCommon_ = nullptr; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 5e523a955a..69260e8625 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -197,6 +197,7 @@ public: // Frame managment virtual void BeginHostFrame() = 0; virtual void EndHostFrame() = 0; + virtual void CheckResized() = 0; // Draw queue management virtual DisplayList* getList(int listid) = 0; diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 6c317d89c9..112d9af3a2 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -205,6 +205,8 @@ protected: void CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight); void ConvertTextureDescFrom16(Draw::TextureDesc &desc, int srcwidth, int srcheight, const uint16_t *overrideData = nullptr); + void BuildReportingInfo() override {} + private: void MarkDirty(uint32_t addr, uint32_t stride, uint32_t height, GEBufferFormat fmt, SoftGPUVRAMDirty value); void MarkDirty(uint32_t addr, uint32_t bytes, SoftGPUVRAMDirty value); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 4232e3f526..8f0b024a50 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -275,15 +275,7 @@ void GPU_Vulkan::BeginHostFrame() { drawEngine_.BeginFrame(); UpdateCmdInfo(); - if (resized_) { - gstate_c.useFlags = CheckGPUFeatures(); - // In case the GPU changed. - BuildReportingInfo(); - framebufferManager_->Resized(); - drawEngine_.NotifyConfigChanged(); - textureCache_->NotifyConfigChanged(); - resized_ = false; - } + CheckResized(); textureCacheVulkan_->StartFrame(); diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 3fbd329aae..ee45b43e5b 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -77,7 +77,7 @@ private: drawEngine_.Flush(); } void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void CopyDisplayToOutput(bool reallyDirty) override; void Reinitialize() override; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 5d5baee855..ea8bc74b42 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1398,8 +1398,20 @@ void EmuScreen::render() { // If we're paused and PauseScreen is transparent (will only be in buffered rendering mode), we just copy display to output. thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Paused"); if (PSP_IsInited()) { + gpu->CheckResized(); gpu->CopyDisplayToOutput(true); } + + screenManager()->getUIContext()->BeginFrame(); + DrawContext *draw = screenManager()->getDrawContext(); + Viewport viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = pixel_xres; + viewport.Height = pixel_yres; + viewport.MaxDepth = 1.0; + viewport.MinDepth = 0.0; + draw->SetViewports(1, &viewport); return; } From 5294a64828b4983d791157e2a6a6d93d1665bbb4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 20 Nov 2022 09:00:04 -0800 Subject: [PATCH 334/715] jit: Protect against write over-estimates. --- Common/CodeBlock.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index 0369c66893..82e989c4d1 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -95,15 +95,37 @@ public: // In case the last block made the current page exec/no-write, let's fix that. if (PlatformIsWXExclusive()) { writeStart_ = GetCodePtr(); + if (writeStart_ + sizeEstimate - region > (ptrdiff_t)region_size) + sizeEstimate = region_size - (writeStart_ - region); + writeEstimated_ = sizeEstimate; ProtectMemoryPages(writeStart_, sizeEstimate, MEM_PROT_READ | MEM_PROT_WRITE); } } + // In case you now know your original estimate is wrong. + void ContinueWrite(size_t sizeEstimate = 1) { + _dbg_assert_msg_(writeStart_, "Must have already called BeginWrite()"); + if (PlatformIsWXExclusive()) { + const uint8_t *pos = GetCodePtr(); + if (pos + sizeEstimate - region > (ptrdiff_t)region_size) + sizeEstimate = region_size - (pos - region); + writeEstimated_ = pos - writeStart_ + sizeEstimate; + ProtectMemoryPages(pos, sizeEstimate, MEM_PROT_READ | MEM_PROT_WRITE); + } + } + void EndWrite() { // OK, we're done. Re-protect the memory we touched. if (PlatformIsWXExclusive() && writeStart_ != nullptr) { const uint8_t *end = GetCodePtr(); - ProtectMemoryPages(writeStart_, end - writeStart_, MEM_PROT_READ | MEM_PROT_EXEC); + size_t sz = end - writeStart_; + if (sz > writeEstimated_) + WARN_LOG(JIT, "EndWrite(): Estimated %d bytes, wrote %d", (int)writeEstimated_, (int)sz); + // If we protected and wrote less, we may need to unprotect. + // Especially if we're linking blocks or similar. + if (sz < writeEstimated_) + sz = writeEstimated_; + ProtectMemoryPages(writeStart_, sz, MEM_PROT_READ | MEM_PROT_EXEC); writeStart_ = nullptr; } } @@ -150,5 +172,6 @@ private: // Note: this is a readable pointer. const uint8_t *writeStart_ = nullptr; uint8_t *writableRegion = nullptr; + size_t writeEstimated_ = 0; }; From b2798c7adacc3663e8bfeb5f2ad11ceec04f0614 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 20 Nov 2022 09:35:05 -0800 Subject: [PATCH 335/715] jit: Add more reasonable estimates for RX protect. --- Common/CodeBlock.h | 2 +- Common/Thunk.cpp | 4 ++-- Core/MIPS/ARM/ArmAsm.cpp | 2 +- Core/MIPS/ARM/ArmJit.cpp | 2 +- Core/MIPS/ARM64/Arm64Asm.cpp | 2 +- Core/MIPS/ARM64/Arm64Jit.cpp | 2 +- Core/MIPS/x86/Asm.cpp | 2 +- Core/MIPS/x86/Jit.cpp | 3 ++- Core/MIPS/x86/JitSafeMem.cpp | 2 +- GPU/Common/VertexDecoderArm.cpp | 2 +- GPU/Common/VertexDecoderArm64.cpp | 2 +- GPU/Common/VertexDecoderX86.cpp | 2 +- GPU/Software/DrawPixelX86.cpp | 3 ++- GPU/Software/RasterizerRegCache.cpp | 2 +- GPU/Software/SamplerX86.cpp | 6 +++--- 15 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index 82e989c4d1..e76bbf40ce 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -80,7 +80,7 @@ public: // If not WX Exclusive, no need to call ProtectMemoryPages because we never change the protection from RWX. PoisonMemory(offset); ResetCodePtr(offset); - if (PlatformIsWXExclusive()) { + if (PlatformIsWXExclusive() && offset != 0) { // Need to re-protect the part we didn't clear. ProtectMemoryPages(region, offset, MEM_PROT_READ | MEM_PROT_EXEC); } diff --git a/Common/Thunk.cpp b/Common/Thunk.cpp index 6248d087a0..581ce94b94 100644 --- a/Common/Thunk.cpp +++ b/Common/Thunk.cpp @@ -43,7 +43,7 @@ void ThunkManager::Init() #endif AllocCodeSpace(THUNK_ARENA_SIZE); - BeginWrite(); + BeginWrite(512); save_regs = GetCodePtr(); #if PPSSPP_ARCH(AMD64) for (int i = 2; i < ABI_GetNumXMMRegs(); i++) @@ -151,7 +151,7 @@ const void *ThunkManager::ProtectFunction(const void *function, int num_params) _assert_msg_(region != nullptr, "Can't protect functions before the emu is started."); - BeginWrite(); + BeginWrite(128); const u8 *call_point = GetCodePtr(); Enter(this, true); diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index 008d24eefe..f90dd237ec 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -71,8 +71,8 @@ namespace MIPSComp { using namespace ArmJitConstants; void ArmJit::GenerateFixedCode() { + BeginWrite(GetMemoryProtectPageSize()); const u8 *start = AlignCodePage(); - BeginWrite(); // LR == SCRATCHREG2 on ARM32 so it needs to be pushed. restoreRoundingMode = AlignCode16(); { diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 3048773bb6..238ce2e94d 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -234,7 +234,7 @@ void ArmJit::Compile(u32 em_address) { ClearCache(); } - BeginWrite(); + BeginWrite(JitBlockCache::MAX_BLOCK_INSTRUCTIONS * 16); int block_num = blocks.AllocateBlock(em_address); JitBlock *b = blocks.GetBlock(block_num); diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index bca3f535e1..9f70435a78 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -97,8 +97,8 @@ namespace MIPSComp { using namespace Arm64JitConstants; void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { + BeginWrite(GetMemoryProtectPageSize()); const u8 *start = AlignCodePage(); - BeginWrite(); if (jo.useStaticAlloc) { saveStaticRegisters = AlignCode16(); diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index f9d7e2d684..b4df4f942a 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -230,7 +230,7 @@ void Arm64Jit::Compile(u32 em_address) { ClearCache(); } - BeginWrite(4); + BeginWrite(JitBlockCache::MAX_BLOCK_INSTRUCTIONS * 16); int block_num = blocks.AllocateBlock(em_address); JitBlock *b = blocks.GetBlock(block_num); diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index fef6f0487c..471414e453 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -66,8 +66,8 @@ void ImHere() { } void Jit::GenerateFixedCode(JitOptions &jo) { + BeginWrite(GetMemoryProtectPageSize()); AlignCodePage(); - BeginWrite(); restoreRoundingMode = AlignCode16(); { STMXCSR(MIPSSTATE_VAR(temp)); diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 97f32b7b72..ec74bcfb5d 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -281,7 +281,8 @@ void Jit::Compile(u32 em_address) { return; } - BeginWrite(); + // Sometimes we compile fairly large blocks, although it's uncommon. + BeginWrite(JitBlockCache::MAX_BLOCK_INSTRUCTIONS * 16); int block_num = blocks.AllocateBlock(em_address); JitBlock *b = blocks.GetBlock(block_num); diff --git a/Core/MIPS/x86/JitSafeMem.cpp b/Core/MIPS/x86/JitSafeMem.cpp index 0fedb39882..8a6e8a6788 100644 --- a/Core/MIPS/x86/JitSafeMem.cpp +++ b/Core/MIPS/x86/JitSafeMem.cpp @@ -462,7 +462,7 @@ void JitSafeMemFuncs::Init(ThunkManager *thunks) { AllocCodeSpace(FUNCS_ARENA_SIZE); thunks_ = thunks; - BeginWrite(); + BeginWrite(1024); readU32 = GetCodePtr(); CreateReadFunc(32, (const void *)&Memory::Read_U32); readU16 = GetCodePtr(); diff --git a/GPU/Common/VertexDecoderArm.cpp b/GPU/Common/VertexDecoderArm.cpp index 2b93b563f8..e5eea51a3e 100644 --- a/GPU/Common/VertexDecoderArm.cpp +++ b/GPU/Common/VertexDecoderArm.cpp @@ -161,7 +161,7 @@ static const JitLookup jitLookup[] = { JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int32_t *jittedSize) { dec_ = &dec; - BeginWrite(); + BeginWrite(4096); const u8 *start = AlignCode16(); bool prescaleStep = false; diff --git a/GPU/Common/VertexDecoderArm64.cpp b/GPU/Common/VertexDecoderArm64.cpp index 0ad04dbe5c..4e4385a224 100644 --- a/GPU/Common/VertexDecoderArm64.cpp +++ b/GPU/Common/VertexDecoderArm64.cpp @@ -143,7 +143,7 @@ static const JitLookup jitLookup[] = { JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int32_t *jittedSize) { dec_ = &dec; - BeginWrite(); + BeginWrite(4096); const u8 *start = AlignCode16(); bool prescaleStep = false; diff --git a/GPU/Common/VertexDecoderX86.cpp b/GPU/Common/VertexDecoderX86.cpp index 3618071c76..728fafc313 100644 --- a/GPU/Common/VertexDecoderX86.cpp +++ b/GPU/Common/VertexDecoderX86.cpp @@ -164,7 +164,7 @@ static const JitLookup jitLookup[] = { JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int32_t *jittedSize) { dec_ = &dec; - BeginWrite(); + BeginWrite(4096); const u8 *start = this->AlignCode16(); #if PPSSPP_ARCH(X86) diff --git a/GPU/Software/DrawPixelX86.cpp b/GPU/Software/DrawPixelX86.cpp index c2c7ce9493..2ba334df94 100644 --- a/GPU/Software/DrawPixelX86.cpp +++ b/GPU/Software/DrawPixelX86.cpp @@ -42,11 +42,12 @@ SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) { RegCache::GEN_ARG_ID, }); - BeginWrite(); + BeginWrite(64); Describe("Init"); WriteConstantPool(id); const u8 *resetPos = AlignCode16(); + EndWrite(); bool success = true; #if PPSSPP_PLATFORM(WINDOWS) diff --git a/GPU/Software/RasterizerRegCache.cpp b/GPU/Software/RasterizerRegCache.cpp index dbd0310fe4..7806b43e03 100644 --- a/GPU/Software/RasterizerRegCache.cpp +++ b/GPU/Software/RasterizerRegCache.cpp @@ -420,7 +420,7 @@ int CodeBlock::WriteProlog(int extraStack, const std::vector &vec #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) using namespace Gen; - BeginWrite(); + BeginWrite(32768); AlignCode16(); lastPrologStart_ = GetWritableCodePtr(); diff --git a/GPU/Software/SamplerX86.cpp b/GPU/Software/SamplerX86.cpp index 7b05debdb5..290f8587f4 100644 --- a/GPU/Software/SamplerX86.cpp +++ b/GPU/Software/SamplerX86.cpp @@ -45,7 +45,7 @@ FetchFunc SamplerJitCache::CompileFetch(const SamplerID &id) { regCache_.ForceRetain(RegCache::GEN_RESULT); regCache_.ChangeReg(XMM0, RegCache::VEC_RESULT); - BeginWrite(); + BeginWrite(2048); Describe("Init"); const u8 *start = AlignCode16(); @@ -122,7 +122,7 @@ FetchFunc SamplerJitCache::CompileFetch(const SamplerID &id) { NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { _assert_msg_(!id.fetch && !id.linear, "Fetch and linear should be cleared on sampler id"); - BeginWrite(); + BeginWrite(2048); Describe("Init"); // Let's drop some helpful constants here. @@ -438,7 +438,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { _assert_msg_(id.linear && !id.fetch, "Only linear should be set on sampler id"); - BeginWrite(); + BeginWrite(2048); Describe("Init"); // We don't use stackArgPos_ here, this is just for DXT. From ce5194250882b4733ce1c3c7694c8839084b13b8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 20 Nov 2022 10:09:05 -0800 Subject: [PATCH 336/715] softgpu: Correct WX-exclusive platform hazards. Should mainly affect BSD at this point. --- GPU/Software/BinManager.cpp | 5 +- GPU/Software/DrawPixel.cpp | 24 +++++---- GPU/Software/DrawPixel.h | 5 +- GPU/Software/Rasterizer.cpp | 24 ++++++--- GPU/Software/Rasterizer.h | 3 +- GPU/Software/RasterizerRectangle.cpp | 3 +- GPU/Software/Sampler.cpp | 77 ++++++++++++++++------------ GPU/Software/Sampler.h | 12 ++--- unittest/TestSoftwareGPUJit.cpp | 8 +-- 9 files changed, 96 insertions(+), 65 deletions(-) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 9a008e6658..8eee98d2f8 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -167,7 +167,10 @@ void BinManager::UpdateState() { if (states_.Full()) Flush("states"); stateIndex_ = (uint16_t)states_.Push(RasterizerState()); - ComputeRasterizerState(&states_[stateIndex_]); + // When new funcs are compiled, we need to flush if WX exclusive. + ComputeRasterizerState(&states_[stateIndex_], [&]() { + Flush("compile"); + }); states_[stateIndex_].samplerID.cached.clut = cluts_[clutIndex_].readable; ClearDirty(SoftDirty::PIXEL_ALL | SoftDirty::SAMPLER_ALL | SoftDirty::RAST_ALL); diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index f47ea6656a..9e65f7d7d5 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -703,8 +703,8 @@ void SOFTRAST_CALL DrawSinglePixel(int x, int y, int z, int fog, Vec4IntArg colo SetPixelColor(fbFormat, pixelID.cached.framebufStride, x, y, new_color, old_color, targetWriteMask); } -SingleFunc GetSingleFunc(const PixelFuncID &id) { - SingleFunc jitted = jitCache->GetSingle(id); +SingleFunc GetSingleFunc(const PixelFuncID &id, std::function flushForCompile) { + SingleFunc jitted = jitCache->GetSingle(id, flushForCompile); if (jitted) { return jitted; } @@ -771,27 +771,31 @@ std::string PixelJitCache::DescribeCodePtr(const u8 *ptr) { return CodeBlock::DescribeCodePtr(ptr); } -SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id) { - std::lock_guard guard(jitCacheLock); +SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function flushForCompile) { + std::unique_lock guard(jitCacheLock); auto it = cache_.find(id); if (it != cache_.end()) { return it->second; } - // x64 is typically 200-500 bytes, but let's be safe. - if (GetSpaceLeft() < 65536) { - Clear(); - } + if (g_Config.bSoftwareRenderingJit) { + guard.unlock(); + flushForCompile(); + guard.lock(); + + // x64 is typically 200-500 bytes, but let's be safe. + if (GetSpaceLeft() < 65536) { + Clear(); + } #if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP) - if (g_Config.bSoftwareRenderingJit) { addresses_[id] = GetCodePointer(); SingleFunc func = CompileSingle(id); cache_[id] = func; return func; - } #endif + } return nullptr; } diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index 65f6fa1ec5..b86c23d2af 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -19,6 +19,7 @@ #include "ppsspp_config.h" +#include #include #include #include @@ -36,7 +37,7 @@ namespace Rasterizer { #endif typedef void (SOFTRAST_CALL *SingleFunc)(int x, int y, int z, int fog, Vec4IntArg color_in, const PixelFuncID &pixelID); -SingleFunc GetSingleFunc(const PixelFuncID &id); +SingleFunc GetSingleFunc(const PixelFuncID &id, std::function flushForCompile); void Init(); void Shutdown(); @@ -60,7 +61,7 @@ public: PixelJitCache(); // Returns a pointer to the code to run. - SingleFunc GetSingle(const PixelFuncID &id); + SingleFunc GetSingle(const PixelFuncID &id, std::function flushForCompile); SingleFunc GenericSingle(const PixelFuncID &id); void Clear() override; diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index d86a4447ef..36e714f310 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -93,15 +93,15 @@ static inline Vec4 Interpolate(const float &c0, const float &c1, const fl return Interpolate(c0, c1, c2, w0.Cast(), w1.Cast(), w2.Cast(), wsum_recip); } -void ComputeRasterizerState(RasterizerState *state) { +void ComputeRasterizerState(RasterizerState *state, std::function flushForCompile) { ComputePixelFuncID(&state->pixelID); - state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID); + state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID, flushForCompile); state->enableTextures = gstate.isTextureMapEnabled() && !state->pixelID.clearMode; if (state->enableTextures) { ComputeSamplerID(&state->samplerID); - state->linear = Sampler::GetLinearFunc(state->samplerID); - state->nearest = Sampler::GetNearestFunc(state->samplerID); + state->linear = Sampler::GetLinearFunc(state->samplerID, flushForCompile); + state->nearest = Sampler::GetNearestFunc(state->samplerID, flushForCompile); // Since the definitions are the same, just force this setting using the func pointer. if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { @@ -153,6 +153,11 @@ void ComputeRasterizerState(RasterizerState *state) { RasterizerState OptimizeFlatRasterizerState(RasterizerState state, const VertexData &v1) { uint8_t alpha = v1.color0 >> 24; + // TODO: Problematic to potentially execute-protect blocks at runtime. + // This might actually be a very slight risk anyway, since it could clear the codespace? + if (PlatformIsWXExclusive()) + return state; + bool changedPixelID = false; bool changedSamplerID = false; if (!state.pixelID.clearMode) { @@ -197,10 +202,10 @@ RasterizerState OptimizeFlatRasterizerState(RasterizerState state, const VertexD } if (changedPixelID) - state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID); + state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID, [] {}); if (changedSamplerID) { - state.linear = Sampler::GetLinearFunc(state.samplerID); - state.nearest = Sampler::GetNearestFunc(state.samplerID); + state.linear = Sampler::GetLinearFunc(state.samplerID, [] {}); + state.nearest = Sampler::GetNearestFunc(state.samplerID, [] {}); // Since the definitions are the same, just force this setting using the func pointer. if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) @@ -1417,7 +1422,10 @@ bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) ComputeSamplerID(&id); id.cached.clut = clut; - Sampler::FetchFunc sampler = Sampler::GetFetchFunc(id); + Sampler::FetchFunc sampler = Sampler::GetFetchFunc(id, [] { + if (gpuDebug) + gpuDebug->DispatchFlush(); + }); u8 *texptr = Memory::GetPointerWrite(texaddr); u32 *row = (u32 *)buffer.GetData(); diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index bd0b820283..6ae7122ed3 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -17,6 +17,7 @@ #pragma once +#include #include "GPU/Software/DrawPixel.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/Sampler.h" @@ -66,7 +67,7 @@ struct RasterizerState { } }; -void ComputeRasterizerState(RasterizerState *state); +void ComputeRasterizerState(RasterizerState *state, std::function flushForCompile); // Draws a triangle if its vertices are specified in counter-clockwise order void DrawTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const BinCoords &range, const RasterizerState &state); diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 445c36bc32..595632d973 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -162,7 +162,8 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran GETextureFormat texfmt = state.samplerID.TexFmt(); uint16_t texbufw = state.texbufw[0]; - Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID); + // We won't flush, since we compile all samplers together. + Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID, [] {}); auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 28d83034de..280764cfcc 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -63,9 +63,9 @@ bool DescribeCodePtr(const u8 *ptr, std::string &name) { return true; } -NearestFunc GetNearestFunc(SamplerID id) { +NearestFunc GetNearestFunc(SamplerID id, std::function flushForCompile) { id.linear = false; - NearestFunc jitted = jitCache->GetNearest(id); + NearestFunc jitted = jitCache->GetNearest(id, flushForCompile); if (jitted) { return jitted; } @@ -73,9 +73,9 @@ NearestFunc GetNearestFunc(SamplerID id) { return &SampleNearest; } -LinearFunc GetLinearFunc(SamplerID id) { +LinearFunc GetLinearFunc(SamplerID id, std::function flushForCompile) { id.linear = true; - LinearFunc jitted = jitCache->GetLinear(id); + LinearFunc jitted = jitCache->GetLinear(id, flushForCompile); if (jitted) { return jitted; } @@ -83,9 +83,9 @@ LinearFunc GetLinearFunc(SamplerID id) { return &SampleLinear; } -FetchFunc GetFetchFunc(SamplerID id) { +FetchFunc GetFetchFunc(SamplerID id, std::function flushForCompile) { id.fetch = true; - FetchFunc jitted = jitCache->GetFetch(id); + FetchFunc jitted = jitCache->GetFetch(id, flushForCompile); if (jitted) { return jitted; } @@ -138,14 +138,19 @@ std::string SamplerJitCache::DescribeCodePtr(const u8 *ptr) { return CodeBlock::DescribeCodePtr(ptr); } -NearestFunc SamplerJitCache::GetNearest(const SamplerID &id) { - std::lock_guard guard(jitCacheLock); +NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, std::function flushForCompile) { + std::unique_lock guard(jitCacheLock); auto it = cache_.find(id); if (it != cache_.end()) return (NearestFunc)it->second; - Compile(id); + if (g_Config.bSoftwareRenderingJit) { + guard.unlock(); + flushForCompile(); + guard.lock(); + Compile(id); + } // Okay, should be there now. it = cache_.find(id); @@ -154,14 +159,19 @@ NearestFunc SamplerJitCache::GetNearest(const SamplerID &id) { return nullptr; } -LinearFunc SamplerJitCache::GetLinear(const SamplerID &id) { - std::lock_guard guard(jitCacheLock); +LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, std::function flushForCompile) { + std::unique_lock guard(jitCacheLock); auto it = cache_.find(id); if (it != cache_.end()) return (LinearFunc)it->second; - Compile(id); + if (g_Config.bSoftwareRenderingJit) { + guard.unlock(); + flushForCompile(); + guard.lock(); + Compile(id); + } // Okay, should be there now. it = cache_.find(id); @@ -170,14 +180,19 @@ LinearFunc SamplerJitCache::GetLinear(const SamplerID &id) { return nullptr; } -FetchFunc SamplerJitCache::GetFetch(const SamplerID &id) { - std::lock_guard guard(jitCacheLock); +FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, std::function flushForCompile) { + std::unique_lock guard(jitCacheLock); auto it = cache_.find(id); if (it != cache_.end()) return (FetchFunc)it->second; - Compile(id); + if (g_Config.bSoftwareRenderingJit) { + guard.unlock(); + flushForCompile(); + guard.lock(); + Compile(id); + } // Okay, should be there now. it = cache_.find(id); @@ -195,25 +210,23 @@ void SamplerJitCache::Compile(const SamplerID &id) { // We compile them together so the cache can't possibly be cleared in between. // We might vary between nearest and linear, so we can't clear between. #if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP) - if (g_Config.bSoftwareRenderingJit) { - SamplerID fetchID = id; - fetchID.linear = false; - fetchID.fetch = true; - addresses_[fetchID] = GetCodePointer(); - cache_[fetchID] = (NearestFunc)CompileFetch(fetchID); + SamplerID fetchID = id; + fetchID.linear = false; + fetchID.fetch = true; + addresses_[fetchID] = GetCodePointer(); + cache_[fetchID] = (NearestFunc)CompileFetch(fetchID); - SamplerID nearestID = id; - nearestID.linear = false; - nearestID.fetch = false; - addresses_[nearestID] = GetCodePointer(); - cache_[nearestID] = (NearestFunc)CompileNearest(nearestID); + SamplerID nearestID = id; + nearestID.linear = false; + nearestID.fetch = false; + addresses_[nearestID] = GetCodePointer(); + cache_[nearestID] = (NearestFunc)CompileNearest(nearestID); - SamplerID linearID = id; - linearID.linear = true; - linearID.fetch = false; - addresses_[linearID] = GetCodePointer(); - cache_[linearID] = (NearestFunc)CompileLinear(linearID); - } + SamplerID linearID = id; + linearID.linear = true; + linearID.fetch = false; + addresses_[linearID] = GetCodePointer(); + cache_[linearID] = (NearestFunc)CompileLinear(linearID); #endif } diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 292a93527f..371131b29f 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -34,13 +34,13 @@ namespace Sampler { #endif typedef Rasterizer::Vec4IntResult(SOFTRAST_CALL *FetchFunc)(int u, int v, const u8 *tptr, int bufw, int level, const SamplerID &samplerID); -FetchFunc GetFetchFunc(SamplerID id); +FetchFunc GetFetchFunc(SamplerID id, std::function flushForCompile); typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -NearestFunc GetNearestFunc(SamplerID id); +NearestFunc GetNearestFunc(SamplerID id, std::function flushForCompile); typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -LinearFunc GetLinearFunc(SamplerID id); +LinearFunc GetLinearFunc(SamplerID id, std::function flushForCompile); void Init(); void Shutdown(); @@ -52,9 +52,9 @@ public: SamplerJitCache(); // Returns a pointer to the code to run. - NearestFunc GetNearest(const SamplerID &id); - LinearFunc GetLinear(const SamplerID &id); - FetchFunc GetFetch(const SamplerID &id); + NearestFunc GetNearest(const SamplerID &id, std::function flushForCompile); + LinearFunc GetLinear(const SamplerID &id, std::function flushForCompile); + FetchFunc GetFetch(const SamplerID &id, std::function flushForCompile); void Clear() override; std::string DescribeCodePtr(const u8 *ptr) override; diff --git a/unittest/TestSoftwareGPUJit.cpp b/unittest/TestSoftwareGPUJit.cpp index 17d0415264..d0d08ba3a2 100644 --- a/unittest/TestSoftwareGPUJit.cpp +++ b/unittest/TestSoftwareGPUJit.cpp @@ -29,17 +29,17 @@ static bool TestSamplerJit() { auto GetLinear = [&](SamplerID &id) { id.linear = true; id.fetch = false; - return cache->GetLinear(id); + return cache->GetLinear(id, [] {}); }; auto GetNearest = [&](SamplerID &id) { id.linear = false; id.fetch = false; - return cache->GetNearest(id); + return cache->GetNearest(id, [] {}); }; auto GetFetch = [&](SamplerID &id) { id.linear = false; id.fetch = true; - return cache->GetFetch(id); + return cache->GetFetch(id, [] {}); }; GMRng rng; @@ -134,7 +134,7 @@ static bool TestPixelJit() { continue; i++; - SingleFunc func = cache->GetSingle(id); + SingleFunc func = cache->GetSingle(id, [] {}); SingleFunc genericFunc = cache->GenericSingle(id); if (func != genericFunc) { successes++; From 4d064005481b53b0c6c9e50be4d361e907923f44 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 20 Nov 2022 12:04:02 -0800 Subject: [PATCH 337/715] softgpu: Fix compile hazard while running. This prevents any clearing of cache while other threads may be using previously cached funcs, and avoids wx exclusive hazards. --- GPU/Software/BinManager.cpp | 3 ++ GPU/Software/DrawPixel.cpp | 57 +++++++++++++++----- GPU/Software/DrawPixel.h | 5 ++ GPU/Software/Rasterizer.cpp | 23 ++++---- GPU/Software/RasterizerRectangle.cpp | 3 +- GPU/Software/Sampler.cpp | 81 +++++++++++++--------------- GPU/Software/Sampler.h | 6 +++ 7 files changed, 109 insertions(+), 69 deletions(-) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 8eee98d2f8..3d1ef7380d 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -513,6 +513,9 @@ void BinManager::Flush(const char *reason) { while (cluts_.Size() > 1) cluts_.SkipNext(); + Rasterizer::FlushJit(); + Sampler::FlushJit(); + queueRange_.x1 = 0x7FFFFFFF; queueRange_.y1 = 0x7FFFFFFF; queueRange_.x2 = 0; diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index 9e65f7d7d5..0cf151a83a 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -36,6 +36,10 @@ void Init() { jitCache = new PixelJitCache(); } +void FlushJit() { + jitCache->Flush(); +} + void Shutdown() { delete jitCache; jitCache = nullptr; @@ -771,7 +775,17 @@ std::string PixelJitCache::DescribeCodePtr(const u8 *ptr) { return CodeBlock::DescribeCodePtr(ptr); } +void PixelJitCache::Flush() { + std::unique_lock guard(jitCacheLock); + for (const auto &queued : compileQueue_) + Compile(queued); + compileQueue_.clear(); +} + SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function flushForCompile) { + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + std::unique_lock guard(jitCacheLock); auto it = cache_.find(id); @@ -779,24 +793,39 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function return it->second; } - if (g_Config.bSoftwareRenderingJit) { - guard.unlock(); - flushForCompile(); - guard.lock(); + if (!flushForCompile) { + // Can't compile, let's try to do it later when there's an opportunity. + compileQueue_.insert(id); + return nullptr; + } - // x64 is typically 200-500 bytes, but let's be safe. - if (GetSpaceLeft() < 65536) { - Clear(); - } + guard.unlock(); + flushForCompile(); + guard.lock(); + + for (const auto &queued : compileQueue_) + Compile(queued); + compileQueue_.clear(); + + Compile(id); + + it = cache_.find(id); + if (it != cache_.end()) + return it->second; + return nullptr; +} + +void PixelJitCache::Compile(const PixelFuncID &id) { + // x64 is typically 200-500 bytes, but let's be safe. + if (GetSpaceLeft() < 65536) { + Clear(); + } #if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP) - addresses_[id] = GetCodePointer(); - SingleFunc func = CompileSingle(id); - cache_[id] = func; - return func; + addresses_[id] = GetCodePointer(); + SingleFunc func = CompileSingle(id); + cache_[id] = func; #endif - } - return nullptr; } void ComputePixelBlendState(PixelBlendState &state, const PixelFuncID &id) { diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index b86c23d2af..02fb641680 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "GPU/Math3D.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" @@ -40,6 +41,7 @@ typedef void (SOFTRAST_CALL *SingleFunc)(int x, int y, int z, int fog, Vec4IntAr SingleFunc GetSingleFunc(const PixelFuncID &id, std::function flushForCompile); void Init(); +void FlushJit(); void Shutdown(); bool CheckDepthTestPassed(GEComparison func, int x, int y, int stride, u16 z); @@ -64,10 +66,12 @@ public: SingleFunc GetSingle(const PixelFuncID &id, std::function flushForCompile); SingleFunc GenericSingle(const PixelFuncID &id); void Clear() override; + void Flush(); std::string DescribeCodePtr(const u8 *ptr) override; private: + void Compile(const PixelFuncID &id); SingleFunc CompileSingle(const PixelFuncID &id); RegCache::Reg GetPixelID(); @@ -105,6 +109,7 @@ private: std::unordered_map cache_; std::unordered_map addresses_; + std::unordered_set compileQueue_; const u8 *constBlendHalf_11_4s_ = nullptr; const u8 *constBlendInvert_11_4s_ = nullptr; diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 36e714f310..f31799d4ef 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -150,13 +150,9 @@ void ComputeRasterizerState(RasterizerState *state, std::function flushF #endif } -RasterizerState OptimizeFlatRasterizerState(RasterizerState state, const VertexData &v1) { +RasterizerState OptimizeFlatRasterizerState(const RasterizerState &origState, const VertexData &v1) { uint8_t alpha = v1.color0 >> 24; - - // TODO: Problematic to potentially execute-protect blocks at runtime. - // This might actually be a very slight risk anyway, since it could clear the codespace? - if (PlatformIsWXExclusive()) - return state; + RasterizerState state = origState; bool changedPixelID = false; bool changedSamplerID = false; @@ -201,11 +197,18 @@ RasterizerState OptimizeFlatRasterizerState(RasterizerState state, const VertexD } } - if (changedPixelID) - state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID, [] {}); + if (changedPixelID) { + state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID, nullptr); + // Can't compile during runtime. + if (!state.drawPixel) + return origState; + } if (changedSamplerID) { - state.linear = Sampler::GetLinearFunc(state.samplerID, [] {}); - state.nearest = Sampler::GetNearestFunc(state.samplerID, [] {}); + state.linear = Sampler::GetLinearFunc(state.samplerID, nullptr); + state.nearest = Sampler::GetNearestFunc(state.samplerID, nullptr); + // Can't compile during runtime. + if (!state.linear || !state.nearest) + return origState; // Since the definitions are the same, just force this setting using the func pointer. if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 595632d973..a8713dad97 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -163,7 +163,8 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran uint16_t texbufw = state.texbufw[0]; // We won't flush, since we compile all samplers together. - Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID, [] {}); + Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID, nullptr); + _dbg_assert_msg_(fetchFunc != nullptr, "Failed to get precompiled fetch func"); auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 280764cfcc..81d4a38214 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -49,6 +49,10 @@ void Init() { jitCache = new SamplerJitCache(); } +void FlushJit() { + jitCache->Flush(); +} + void Shutdown() { delete jitCache; jitCache = nullptr; @@ -138,67 +142,56 @@ std::string SamplerJitCache::DescribeCodePtr(const u8 *ptr) { return CodeBlock::DescribeCodePtr(ptr); } -NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, std::function flushForCompile) { +void SamplerJitCache::Flush() { + std::unique_lock guard(jitCacheLock); + for (const auto &queued : compileQueue_) + Compile(queued); + compileQueue_.clear(); +} + +NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function flushForCompile) { + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + std::unique_lock guard(jitCacheLock); auto it = cache_.find(id); if (it != cache_.end()) - return (NearestFunc)it->second; + return it->second; - if (g_Config.bSoftwareRenderingJit) { - guard.unlock(); - flushForCompile(); - guard.lock(); - Compile(id); + if (!flushForCompile) { + // Can't compile, let's try to do it later when there's an opportunity. + compileQueue_.insert(id); + return nullptr; } + guard.unlock(); + flushForCompile(); + guard.lock(); + + for (const auto &queued : compileQueue_) + Compile(queued); + compileQueue_.clear(); + + Compile(id); + // Okay, should be there now. it = cache_.find(id); if (it != cache_.end()) - return (NearestFunc)it->second; + return it->second; return nullptr; } +NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, std::function flushForCompile) { + return (NearestFunc)GetByID(id, flushForCompile); +} + LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, std::function flushForCompile) { - std::unique_lock guard(jitCacheLock); - - auto it = cache_.find(id); - if (it != cache_.end()) - return (LinearFunc)it->second; - - if (g_Config.bSoftwareRenderingJit) { - guard.unlock(); - flushForCompile(); - guard.lock(); - Compile(id); - } - - // Okay, should be there now. - it = cache_.find(id); - if (it != cache_.end()) - return (LinearFunc)it->second; - return nullptr; + return (LinearFunc)GetByID(id, flushForCompile); } FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, std::function flushForCompile) { - std::unique_lock guard(jitCacheLock); - - auto it = cache_.find(id); - if (it != cache_.end()) - return (FetchFunc)it->second; - - if (g_Config.bSoftwareRenderingJit) { - guard.unlock(); - flushForCompile(); - guard.lock(); - Compile(id); - } - - // Okay, should be there now. - it = cache_.find(id); - if (it != cache_.end()) - return (FetchFunc)it->second; - return nullptr; + return (FetchFunc)GetByID(id, flushForCompile); } void SamplerJitCache::Compile(const SamplerID &id) { diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 371131b29f..bb47314ddb 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -19,7 +19,9 @@ #include "ppsspp_config.h" +#include #include +#include #include "GPU/Math3D.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" @@ -43,6 +45,7 @@ typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, LinearFunc GetLinearFunc(SamplerID id, std::function flushForCompile); void Init(); +void FlushJit(); void Shutdown(); bool DescribeCodePtr(const u8 *ptr, std::string &name); @@ -56,11 +59,13 @@ public: LinearFunc GetLinear(const SamplerID &id, std::function flushForCompile); FetchFunc GetFetch(const SamplerID &id, std::function flushForCompile); void Clear() override; + void Flush(); std::string DescribeCodePtr(const u8 *ptr) override; private: void Compile(const SamplerID &id); + NearestFunc GetByID(const SamplerID &id, std::function flushForCompile); FetchFunc CompileFetch(const SamplerID &id); NearestFunc CompileNearest(const SamplerID &id); LinearFunc CompileLinear(const SamplerID &id); @@ -123,6 +128,7 @@ private: std::unordered_map cache_; std::unordered_map addresses_; + std::unordered_set compileQueue_; }; #if defined(__clang__) || defined(__GNUC__) From e654f6937a02f4a2ac8cce3574ab4f2db99f77d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 14:29:26 +0100 Subject: [PATCH 338/715] Forgot to commit this in PR #16404 --- UI/EmuScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index ea8bc74b42..bfbc7edf8c 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1394,7 +1394,7 @@ void EmuScreen::render() { // We can still render behind the pause screen. bool paused = screenManager()->topScreen() != this; - if (paused) { + if (paused && screenManager()->topScreen()->isTransparent()) { // If we're paused and PauseScreen is transparent (will only be in buffered rendering mode), we just copy display to output. thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Paused"); if (PSP_IsInited()) { From 75967130597cb452efc0bbf45d4a471ee1db6873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 14:34:06 +0100 Subject: [PATCH 339/715] Refactor: Split up updating the display and render size. --- GPU/Common/FramebufferManagerCommon.cpp | 15 ++++++++------- GPU/Common/FramebufferManagerCommon.h | 2 +- GPU/Common/PresentationCommon.h | 4 +++- GPU/Software/SoftGpu.cpp | 3 ++- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 14a0ed1980..da70dc5750 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -86,25 +86,22 @@ void FramebufferManagerCommon::Init() { Resized(); } -bool FramebufferManagerCommon::UpdateSize() { +bool FramebufferManagerCommon::UpdateRenderSize() { const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight; const int effectiveBloomHack = PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn ? 3 : g_Config.iBloomHack; - bool newBuffered = !g_Config.bSkipBufferEffects; const bool newSettings = bloomHack_ != effectiveBloomHack || useBufferedRendering_ != newBuffered; renderWidth_ = (float)PSP_CoreParameter().renderWidth; renderHeight_ = (float)PSP_CoreParameter().renderHeight; renderScaleFactor_ = (float)PSP_CoreParameter().renderScaleFactor; - pixelWidth_ = PSP_CoreParameter().pixelWidth; - pixelHeight_ = PSP_CoreParameter().pixelHeight; + bloomHack_ = effectiveBloomHack; useBufferedRendering_ = newBuffered; - presentation_->UpdateSize(pixelWidth_, pixelHeight_, renderWidth_, renderHeight_); - + presentation_->UpdateRenderSize(renderWidth_, renderHeight_); return newRender || newSettings; } @@ -2342,7 +2339,11 @@ void FramebufferManagerCommon::Resized() { PSP_CoreParameter().renderHeight = h; PSP_CoreParameter().renderScaleFactor = scaleFactor; - if (UpdateSize()) { + pixelWidth_ = PSP_CoreParameter().pixelWidth; + pixelHeight_ = PSP_CoreParameter().pixelHeight; + presentation_->UpdateDisplaySize(pixelWidth_, pixelHeight_); + + if (UpdateRenderSize()) { DestroyAllFBOs(); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 76ad0bd8f6..58a5e81630 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -450,7 +450,7 @@ protected: void CopyToColorFromOverlappingFramebuffers(VirtualFramebuffer *dest); void CopyToDepthFromOverlappingFramebuffers(VirtualFramebuffer *dest); - bool UpdateSize(); + bool UpdateRenderSize(); void FlushBeforeCopy(); virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index d100230a46..981c707b05 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -78,9 +78,11 @@ public: PresentationCommon(Draw::DrawContext *draw); ~PresentationCommon(); - void UpdateSize(int w, int h, int rw, int rh) { + void UpdateDisplaySize(int w, int h) { pixelWidth_ = w; pixelHeight_ = h; + } + void UpdateRenderSize(int rw, int rh) { renderWidth_ = rw; renderHeight_ = rh; } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 04e3c1d5c7..4c6ff090ee 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -712,7 +712,8 @@ void SoftGPU::Resized() { } if (presentation_) { - presentation_->UpdateSize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); + presentation_->UpdateDisplaySize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + presentation_->UpdateRenderSize(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); presentation_->UpdatePostShader(); } } From eff4118769340d526bc712035afe45a7dd878b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 14:54:48 +0100 Subject: [PATCH 340/715] One more refactoring step --- Common/VR/VRRenderer.cpp | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 19 +++++++++++++------ GPU/Common/FramebufferManagerCommon.h | 4 +++- GPU/GLES/FramebufferManagerGLES.cpp | 5 +++-- GPU/GLES/FramebufferManagerGLES.h | 2 +- GPU/GPUCommon.cpp | 3 ++- GPU/GPUCommon.h | 3 +-- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 4d89618c17..5de7cb4055 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -317,7 +317,7 @@ void VR_EndFrame( engine_t* engine ) { int x = vrConfig[VR_CONFIG_MOUSE_X]; int y = vrConfig[VR_CONFIG_MOUSE_Y]; int sx = vrConfig[VR_CONFIG_MOUSE_SIZE]; - int sy = sx * VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); + int sy = (int)((float)sx * VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT)); ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, sx, sy); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index da70dc5750..7a104bc515 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -83,7 +83,8 @@ FramebufferManagerCommon::~FramebufferManagerCommon() { void FramebufferManagerCommon::Init() { // We may need to override the render size if the shader is upscaling or SSAA. - Resized(); + NotifyDisplayResized(); + NotifyRenderResized(); } bool FramebufferManagerCommon::UpdateRenderSize() { @@ -2330,7 +2331,17 @@ void FramebufferManagerCommon::SetSafeSize(u16 w, u16 h) { } } -void FramebufferManagerCommon::Resized() { +void FramebufferManagerCommon::NotifyDisplayResized() { + pixelWidth_ = PSP_CoreParameter().pixelWidth; + pixelHeight_ = PSP_CoreParameter().pixelHeight; + presentation_->UpdateDisplaySize(pixelWidth_, pixelHeight_); + + // No drawing is allowed here. This includes anything that might potentially touch a command buffer, like creating images! + // So we need to defer the post processing initialization. + updatePostShaders_ = true; +} + +void FramebufferManagerCommon::NotifyRenderResized() { gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; int w, h, scaleFactor; @@ -2339,10 +2350,6 @@ void FramebufferManagerCommon::Resized() { PSP_CoreParameter().renderHeight = h; PSP_CoreParameter().renderScaleFactor = scaleFactor; - pixelWidth_ = PSP_CoreParameter().pixelWidth; - pixelHeight_ = PSP_CoreParameter().pixelHeight; - presentation_->UpdateDisplaySize(pixelWidth_, pixelHeight_); - if (UpdateRenderSize()) { DestroyAllFBOs(); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 58a5e81630..fa41e1c272 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -398,7 +398,9 @@ public: } void SetSafeSize(u16 w, u16 h); - virtual void Resized(); + virtual void NotifyRenderResized(); + virtual void NotifyDisplayResized(); + virtual void DestroyAllFBOs(); virtual void DeviceLost(); diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 9d1dc8d3dd..a5a46ca52d 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -70,8 +70,9 @@ void FramebufferManagerGLES::DeviceLost() { } } -void FramebufferManagerGLES::Resized() { - FramebufferManagerCommon::Resized(); +void FramebufferManagerGLES::NotifyDisplayResized() { + FramebufferManagerCommon::NotifyDisplayResized(); + GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); render->Resize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 7bbfa1a510..f67ab65434 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -31,7 +31,7 @@ public: FramebufferManagerGLES(Draw::DrawContext *draw); ~FramebufferManagerGLES(); - void Resized() override; + void NotifyDisplayResized() override; void DeviceLost() override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6794e0611e..b263b72131 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -617,7 +617,8 @@ void GPUCommon::CheckResized() { if (resized_) { gstate_c.useFlags = CheckGPUFeatures(); BuildReportingInfo(); - framebufferManager_->Resized(); + framebufferManager_->NotifyDisplayResized(); + framebufferManager_->NotifyRenderResized(); drawEngineCommon_->NotifyConfigChanged(); textureCache_->NotifyConfigChanged(); shaderManager_->DirtyLastShader(); diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 39aca24454..4c9a5d323f 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -84,8 +84,7 @@ public: bool IsReady() override { return true; } - void CancelReady() override { - } + void CancelReady() override {} void Reinitialize() override; void BeginHostFrame() override; From d73196c7d6b0e9b5439ad2b35cf15d11756794b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 15:14:20 +0100 Subject: [PATCH 341/715] Split up the GPU config change notifications --- GPU/GPUCommon.cpp | 35 ++++++++++++++++++++++++++--------- GPU/GPUCommon.h | 9 +++++++-- GPU/GPUInterface.h | 5 ++++- GPU/Software/SoftGpu.cpp | 11 +++++++++-- GPU/Software/SoftGpu.h | 5 ++++- Qt/QtMain.cpp | 2 +- Qt/mainwindow.h | 17 +++++++++-------- UI/EmuScreen.cpp | 6 +++--- UI/GameSettingsScreen.cpp | 11 ++++++----- UI/NativeApp.cpp | 35 ++++++++++++++++++++++------------- UWP/App.cpp | 8 ++++---- Windows/MainWindow.cpp | 5 +++-- Windows/MainWindowMenu.cpp | 16 ++++++++-------- 13 files changed, 106 insertions(+), 59 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index b263b72131..fc94f32ab7 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -477,7 +477,7 @@ void GPUCommon::UpdateCmdInfo() { } void GPUCommon::BeginHostFrame() { - UpdateVsyncInterval(resized_); + UpdateVsyncInterval(displayResized_); ReapplyGfxState(); // TODO: Assume config may have changed - maybe move to resize. @@ -607,22 +607,39 @@ bool GPUCommon::BusyDrawing() { return false; } -void GPUCommon::Resized() { - resized_ = true; +void GPUCommon::NotifyConfigChanged() { + configChanged_ = true; +} + +void GPUCommon::NotifyRenderResized() { + renderResized_ = true; +} + +void GPUCommon::NotifyDisplayResized() { + displayResized_ = true; } // Called once per frame. Might also get called during the pause screen // if "transparent". void GPUCommon::CheckResized() { - if (resized_) { + if (configChanged_) { + ClearCacheNextFrame(); gstate_c.useFlags = CheckGPUFeatures(); - BuildReportingInfo(); - framebufferManager_->NotifyDisplayResized(); - framebufferManager_->NotifyRenderResized(); drawEngineCommon_->NotifyConfigChanged(); + shaderManager_->DirtyLastShader(); // Don't think this is needed, at all. textureCache_->NotifyConfigChanged(); - shaderManager_->DirtyLastShader(); - resized_ = false; + BuildReportingInfo(); + configChanged_ = false; + } + + if (displayResized_) { + framebufferManager_->NotifyDisplayResized(); + displayResized_ = false; + } + + if (renderResized_) { + framebufferManager_->NotifyRenderResized(); + renderResized_ = false; } } diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 4c9a5d323f..d9e7246d08 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -97,7 +97,10 @@ public: interruptsEnabled_ = enable; } - void Resized() override; + void NotifyDisplayResized() override; + void NotifyRenderResized() override; + void NotifyConfigChanged() override; + void DumpNextFrame() override; void ExecuteOp(u32 op, u32 diff) override; @@ -357,7 +360,9 @@ protected: bool dumpThisFrame_ = false; bool debugRecording_; bool interruptsEnabled_; - bool resized_ = false; + bool displayResized_ = false; + bool renderResized_ = false; + bool configChanged_ = false; bool sawExactEqualDepth_ = false; DrawType lastDraw_ = DRAW_UNKNOWN; GEPrimitiveType lastPrim_ = GE_PRIM_INVALID; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 69260e8625..8f7398aee6 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -255,7 +255,10 @@ public: virtual void DoState(PointerWrap &p) = 0; // Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*. - virtual void Resized() = 0; + virtual void NotifyDisplayResized() = 0; + virtual void NotifyRenderResized() = 0; + virtual void NotifyConfigChanged() = 0; + virtual void ClearShaderCache() = 0; virtual void CleanupBeforeUI() = 0; virtual bool FramebufferDirty() = 0; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 4c6ff090ee..2203c14ab9 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -445,7 +445,10 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) presentation_ = new PresentationCommon(draw_); presentation_->SetLanguage(draw_->GetShaderLanguageDesc().shaderLanguage); } - Resized(); + + NotifyConfigChanged(); + NotifyRenderResized(); + NotifyDisplayResized(); } void SoftGPU::DeviceLost() { @@ -701,7 +704,7 @@ bool SoftGPU::ClearDirty(uint32_t addr, uint32_t bytes, SoftGPUVRAMDirty value) return result; } -void SoftGPU::Resized() { +void SoftGPU::NotifyRenderResized() { // Force the render params to 480x272 so other things work. if (g_Config.IsPortrait()) { PSP_CoreParameter().renderWidth = 272; @@ -710,7 +713,9 @@ void SoftGPU::Resized() { PSP_CoreParameter().renderWidth = 480; PSP_CoreParameter().renderHeight = 272; } +} +void SoftGPU::NotifyDisplayResized() { if (presentation_) { presentation_->UpdateDisplaySize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); presentation_->UpdateRenderSize(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); @@ -718,6 +723,8 @@ void SoftGPU::Resized() { } } +void SoftGPU::NotifyConfigChanged() {} + void SoftGPU::FastRunLoop(DisplayList &list) { PROFILE_THIS_SCOPE("soft_runloop"); const auto *cmdInfo = softgpuCmdInfo; diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 112d9af3a2..508baa6d0e 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -149,7 +149,10 @@ public: void DeviceLost() override; void DeviceRestore() override; - void Resized() override; + void NotifyRenderResized() override; + void NotifyDisplayResized() override; + void NotifyConfigChanged() override; + void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override { primaryInfo = "Software"; fullInfo = "Software"; diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index bba1f1ae2b..f5a9300616 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -418,7 +418,7 @@ QString MainUI::InputBoxGetQString(QString title, QString defaultValue) { void MainUI::resizeGL(int w, int h) { if (UpdateScreenScale(w, h)) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); } xscale = w / this->width(); yscale = h / this->height(); diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 864a658b58..fa7d3ceb6f 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -119,25 +119,26 @@ private slots: void moreSettingsAct() { NativeMessageReceived("settings", ""); } void bufferRenderAct() { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_renderResized", ""); + NativeMessageReceived("gpu_configChanged", ""); } void linearAct() { g_Config.iTexFiltering = (g_Config.iTexFiltering != 0) ? 0 : 3; } void renderingResolutionGroup_triggered(QAction *action) { g_Config.iInternalResolution = action->data().toInt(); - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_renderResized", ""); } void windowGroup_triggered(QAction *action) { SetWindowScale(action->data().toInt()); } void displayLayoutGroup_triggered(QAction *action) { g_Config.iSmallDisplayZoomType = action->data().toInt(); - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); } void autoframeskipAct() { g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip; if (g_Config.bSkipBufferEffects) { g_Config.bSkipBufferEffects = false; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); } } void frameSkippingGroup_triggered(QAction *action) { g_Config.iFrameSkip = action->data().toInt(); } @@ -146,19 +147,19 @@ private slots: void screenScalingFilterGroup_triggered(QAction *action) { g_Config.iBufFilter = action->data().toInt(); } void textureScalingLevelGroup_triggered(QAction *action) { g_Config.iTexScalingLevel = action->data().toInt(); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } void textureScalingTypeGroup_triggered(QAction *action) { g_Config.iTexScalingType = action->data().toInt(); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } void deposterizeAct() { g_Config.bTexDeposterize = !g_Config.bTexDeposterize; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } void transformAct() { g_Config.bHardwareTransform = !g_Config.bHardwareTransform; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); } void vertexCacheAct() { g_Config.bVertexCache = !g_Config.bVertexCache; } void frameskipAct() { g_Config.iFrameSkip = !g_Config.iFrameSkip; } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index bfbc7edf8c..0ff7a9f0a9 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -660,7 +660,7 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { if (g_Config.bDumpFrames == g_Config.bDumpAudio) { g_Config.bDumpFrames = !g_Config.bDumpFrames; g_Config.bDumpAudio = !g_Config.bDumpAudio; - } else { + } else { // This hotkey should always toggle both audio and video together. // So let's make sure that's the only outcome even if video OR audio was already being dumped. if (g_Config.bDumpFrames) { @@ -705,7 +705,7 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { g_Config.bSaveNewTextures = !g_Config.bSaveNewTextures; if (g_Config.bSaveNewTextures) { osm.Show(sc->T("saveNewTextures_true", "Textures will now be saved to your storage"), 2.0); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } else { osm.Show(sc->T("saveNewTextures_false", "Texture saving was disabled"), 2.0); } @@ -716,7 +716,7 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { osm.Show(sc->T("replaceTextures_true", "Texture replacement enabled"), 2.0); else osm.Show(sc->T("replaceTextures_false", "Textures no longer are being replaced"), 2.0); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); break; case VIRTKEY_RAPID_FIRE: __CtrlSetRapidFire(true); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index abe73f5e7a..d3d2e60202 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1391,8 +1391,8 @@ void GameSettingsScreen::onFinish(DialogResult result) { KeyMap::UpdateNativeMenuKeys(); // Wipe some caches after potentially changing settings. - NativeMessageReceived("gpu_resized", ""); - NativeMessageReceived("gpu_clearCache", ""); + // Let's not send resize messages here, handled elsewhere. + NativeMessageReceived("gpu_configChanged", ""); } void GameSettingsScreen::sendMessage(const char *message, const char *value) { @@ -1717,7 +1717,8 @@ UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); + NativeMessageReceived("gpu_renderResized", ""); // To deal with shaders that can change render resolution like upscaling. NativeMessageReceived("postshader_updated", ""); return UI::EVENT_DONE; } @@ -1733,7 +1734,7 @@ UI::EventReturn GameSettingsScreen::OnTextureShader(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnTextureShaderChange(UI::EventParams &e) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); RecreateViews(); // Update setting name g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off"; return UI::EVENT_DONE; @@ -1903,7 +1904,7 @@ void DeveloperToolsScreen::CreateViews() { void DeveloperToolsScreen::onFinish(DialogResult result) { g_Config.Save("DeveloperToolsScreen::onFinish"); - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); } void GameSettingsScreen::CallbackRestoreDefaults(bool yes) { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 0bea47395a..1403515476 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1168,7 +1168,7 @@ void NativeRender(GraphicsContext *graphicsContext) { #if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID) PSP_CoreParameter().pixelWidth = pixel_xres; PSP_CoreParameter().pixelHeight = pixel_yres; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); #endif } else { // INFO_LOG(G3D, "Polling graphics context"); @@ -1189,10 +1189,10 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { if (msg == "inputDeviceConnectedID") { nextInputDeviceID = parseLong(value); } - if (msg == "inputDeviceConnected") { + else if (msg == "inputDeviceConnected") { KeyMap::NotifyPadConnected(nextInputDeviceID, value); } - if (msg == "bgImage_updated") { + else if (msg == "bgImage_updated") { if (!value.empty()) { Path dest = GetSysDirectory(DIRECTORY_SYSTEM) / (endsWithNoCase(value, ".jpg") ? "background.jpg" : "background.png"); File::Copy(Path(value), dest); @@ -1200,20 +1200,29 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { UIBackgroundShutdown(); // It will init again automatically. We can't init outside a frame on Vulkan. } - if (msg == "savestate_displayslot") { + else if (msg == "savestate_displayslot") { auto sy = GetI18NCategory("System"); std::string msg = StringFromFormat("%s: %d", sy->T("Savestate Slot"), SaveState::GetCurrentSlot() + 1); // Show for the same duration as the preview. osm.Show(msg, 2.0f, 0xFFFFFF, -1, true, "savestate_slot"); } - if (msg == "gpu_resized" || msg == "gpu_clearCache") { + else if (msg == "gpu_displayResized") { if (gpu) { - gpu->ClearCacheNextFrame(); - gpu->Resized(); + gpu->NotifyDisplayResized(); + } + } + else if (msg == "gpu_renderResized") { + if (gpu) { + gpu->NotifyRenderResized(); + } + } + else if (msg == "gpu_configChanged") { + if (gpu) { + gpu->NotifyConfigChanged(); } Reporting::UpdateConfig(); } - if (msg == "core_powerSaving") { + else if (msg == "core_powerSaving") { if (value != "false") { auto sy = GetI18NCategory("System"); #if PPSSPP_PLATFORM(ANDROID) @@ -1224,7 +1233,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { } Core_SetPowerSaving(value != "false"); } - if (msg == "permission_granted" && value == "storage") { + else if (msg == "permission_granted" && value == "storage") { #if PPSSPP_PLATFORM(ANDROID) CreateDirectoriesAndroid(); #endif @@ -1240,7 +1249,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { PostLoadConfig(); g_Config.iGPUBackend = gpuBackend; } - if (msg == "app_resumed" || msg == "got_focus") { + else if (msg == "app_resumed" || msg == "got_focus") { // Assume that the user may have modified things. MemoryStick_NotifyWrite(); } @@ -1345,7 +1354,7 @@ bool NativeAxis(const AxisInput &axis) { // only handle tilt events if tilt is enabled. if (g_Config.iTiltInputType == TILT_NULL) { - // if tilt events are disabled, then run it through the usual way. + // if tilt events are disabled, then run it through the usual way. if (screenManager) { return screenManager->axis(axis); } else { @@ -1411,7 +1420,7 @@ bool NativeAxis(const AxisInput &axis) { currentTilt.y_ = -axis.value; } break; - + case JOYSTICK_AXIS_OUYA_UNKNOWN1: case JOYSTICK_AXIS_OUYA_UNKNOWN2: case JOYSTICK_AXIS_OUYA_UNKNOWN3: @@ -1433,7 +1442,7 @@ bool NativeAxis(const AxisInput &axis) { //then a value of 70-80 is the way to go. float xSensitivity = g_Config.iTiltSensitivityX / 50.0; float ySensitivity = g_Config.iTiltSensitivityY / 50.0; - + //now transform out current tilt to the calibrated coordinate system Tilt trueTilt = GenTilt(baseTilt, currentTilt, g_Config.bInvertTiltX, g_Config.bInvertTiltY, g_Config.fDeadzoneRadius, xSensitivity, ySensitivity); diff --git a/UWP/App.cpp b/UWP/App.cpp index aa850ae81a..13611a04f2 100644 --- a/UWP/App.cpp +++ b/UWP/App.cpp @@ -57,20 +57,20 @@ void App::Initialize(CoreApplicationView^ applicationView) { CoreApplication::Resuming += ref new EventHandler(this, &App::OnResuming); - // At this point we have access to the device. + // At this point we have access to the device. // We can create the device-dependent resources. m_deviceResources = std::make_shared(); } // Called when the CoreWindow object is created (or re-created). void App::SetWindow(CoreWindow^ window) { - window->SizeChanged += + window->SizeChanged += ref new TypedEventHandler(this, &App::OnWindowSizeChanged); window->VisibilityChanged += ref new TypedEventHandler(this, &App::OnVisibilityChanged); - window->Closed += + window->Closed += ref new TypedEventHandler(this, &App::OnWindowClosed); DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView(); @@ -267,7 +267,7 @@ void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ ar PSP_CoreParameter().pixelWidth = (int)(width * scale); PSP_CoreParameter().pixelHeight = (int)(height * scale); if (UpdateScreenScale((int)width, (int)height)) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); } } diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 733e270db3..1eb68f441f 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -238,7 +238,7 @@ namespace MainWindow g_Config.iInternalResolution = 0; } - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_renderResized", ""); } void CorrectCursor() { @@ -302,7 +302,8 @@ namespace MainWindow DEBUG_LOG(SYSTEM, "Pixel width/height: %dx%d", PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); if (UpdateScreenScale(width, height)) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); + NativeMessageReceived("gpu_renderResized", ""); } // Don't save the window state if fullscreen. diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index b8e8b10c94..37c01cb3ed 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -472,7 +472,7 @@ namespace MainWindow { // not static void setTexScalingMultiplier(int level) { g_Config.iTexScalingLevel = level; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } static void setTexFiltering(int type) { @@ -485,12 +485,12 @@ namespace MainWindow { static void setTexScalingType(int type) { g_Config.iTexScalingType = type; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } static void setSkipBufferEffects(bool skip) { g_Config.bSkipBufferEffects = skip; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); } static void setFrameSkipping(int framesToSkip = -1) { @@ -744,7 +744,7 @@ namespace MainWindow { g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip; if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { g_Config.bSkipBufferEffects = false; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); } break; @@ -761,7 +761,7 @@ namespace MainWindow { case ID_TEXTURESCALING_DEPOSTERIZE: g_Config.bTexDeposterize = !g_Config.bTexDeposterize; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); break; case ID_OPTIONS_DIRECT3D9: @@ -790,7 +790,7 @@ namespace MainWindow { case ID_OPTIONS_SKIP_BUFFER_EFFECTS: g_Config.bSkipBufferEffects = !g_Config.bSkipBufferEffects; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); osm.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects); break; @@ -801,7 +801,7 @@ namespace MainWindow { case ID_OPTIONS_HARDWARETRANSFORM: g_Config.bHardwareTransform = !g_Config.bHardwareTransform; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); osm.ShowOnOff(gr->T("Hardware Transform"), g_Config.bHardwareTransform); break; @@ -1045,7 +1045,7 @@ namespace MainWindow { g_Config.vPostShaderNames.push_back(availableShaders[index]); g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_renderResized", ""); NativeMessageReceived("postshader_updated", ""); break; } From ce5a1b8b7e2d7eaec53b680db2cbb809f787f587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 17:55:30 +0100 Subject: [PATCH 342/715] Some minor "centralization" --- GPU/D3D11/GPU_D3D11.cpp | 17 ----------------- GPU/D3D11/GPU_D3D11.h | 4 ---- GPU/Directx9/GPU_DX9.cpp | 6 ------ GPU/Directx9/GPU_DX9.h | 2 -- GPU/GLES/GPU_GLES.cpp | 3 --- GPU/GPUCommon.cpp | 6 +++++- GPU/Vulkan/GPU_Vulkan.cpp | 8 +++----- 7 files changed, 8 insertions(+), 38 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 1f465fa54f..e533e524e8 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -157,23 +157,6 @@ void GPU_D3D11::InitClear() { } } -void GPU_D3D11::BeginHostFrame() { - GPUCommon::BeginHostFrame(); - UpdateCmdInfo(); - CheckResized(); -} - -void GPU_D3D11::ReapplyGfxState() { - GPUCommon::ReapplyGfxState(); - - // TODO: Dirty our caches for depth states etc -} - -void GPU_D3D11::EndHostFrame() { - // Probably not really necessary. - draw_->InvalidateCachedState(); -} - void GPU_D3D11::BeginFrame() { GPUCommon::BeginFrame(); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index c0d969926a..0cba325618 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -40,7 +40,6 @@ public: void PreExecuteOp(u32 op, u32 diff) override; void ExecuteOp(u32 op, u32 diff) override; - void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. @@ -54,9 +53,6 @@ public: std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; - void BeginHostFrame() override; - void EndHostFrame() override; - protected: void FinishDeferred() override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index e3aebbc796..e13a3b4f3d 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -147,12 +147,6 @@ void GPU_DX9::InitClear() { } } -void GPU_DX9::BeginHostFrame() { - GPUCommon::BeginHostFrame(); - UpdateCmdInfo(); - CheckResized(); -} - void GPU_DX9::ReapplyGfxState() { dxstate.Restore(); GPUCommon::ReapplyGfxState(); diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index c877c17482..0ec463e55e 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -53,8 +53,6 @@ public: std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; - void BeginHostFrame() override; - protected: void FinishDeferred() override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index f0a796f543..bee7a874f2 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -267,9 +267,6 @@ void GPU_GLES::InitClear() { void GPU_GLES::BeginHostFrame() { GPUCommon::BeginHostFrame(); - UpdateCmdInfo(); - CheckResized(); - drawEngine_.BeginFrame(); } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index fc94f32ab7..e0aa841df9 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -482,10 +482,14 @@ void GPUCommon::BeginHostFrame() { // TODO: Assume config may have changed - maybe move to resize. gstate_c.Dirty(DIRTY_ALL); + + UpdateCmdInfo(); + CheckResized(); } void GPUCommon::EndHostFrame() { - + // Probably not necessary. + draw_->InvalidateCachedState(); } void GPUCommon::Reinitialize() { diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 8f0b024a50..6ed3789152 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -272,11 +272,9 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { } void GPU_Vulkan::BeginHostFrame() { + GPUCommon::BeginHostFrame(); + drawEngine_.BeginFrame(); - UpdateCmdInfo(); - - CheckResized(); - textureCacheVulkan_->StartFrame(); VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); @@ -310,7 +308,7 @@ void GPU_Vulkan::EndHostFrame() { drawEngine_.EndFrame(); textureCacheVulkan_->EndFrame(); - draw_->InvalidateCachedState(); + GPUCommon::EndHostFrame(); } // Needs to be called on GPU thread, not reporting thread. From c3604428b93ef2c8ed441e7cc42d13a278433924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 17:59:56 +0100 Subject: [PATCH 343/715] Only check for display resized in emuscreen-under-pause-screen, not the other changes. --- GPU/GPUCommon.cpp | 10 ++++++++-- GPU/GPUCommon.h | 6 +++++- GPU/GPUInterface.h | 3 ++- UI/EmuScreen.cpp | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index e0aa841df9..9dfe4781d4 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -484,7 +484,9 @@ void GPUCommon::BeginHostFrame() { gstate_c.Dirty(DIRTY_ALL); UpdateCmdInfo(); - CheckResized(); + CheckConfigChanged(); + CheckDisplayResized(); + CheckRenderResized(); } void GPUCommon::EndHostFrame() { @@ -625,7 +627,7 @@ void GPUCommon::NotifyDisplayResized() { // Called once per frame. Might also get called during the pause screen // if "transparent". -void GPUCommon::CheckResized() { +void GPUCommon::CheckConfigChanged() { if (configChanged_) { ClearCacheNextFrame(); gstate_c.useFlags = CheckGPUFeatures(); @@ -635,12 +637,16 @@ void GPUCommon::CheckResized() { BuildReportingInfo(); configChanged_ = false; } +} +void GPUCommon::CheckDisplayResized() { if (displayResized_) { framebufferManager_->NotifyDisplayResized(); displayResized_ = false; } +} +void GPUCommon::CheckRenderResized() { if (renderResized_) { framebufferManager_->NotifyRenderResized(); renderResized_ = false; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index d9e7246d08..82ca294e07 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -77,7 +77,8 @@ public: return draw_; } virtual u32 CheckGPUFeatures() const; - void CheckResized() override; + + void CheckDisplayResized() override; void UpdateCmdInfo(); @@ -265,6 +266,9 @@ protected: void DeviceLost() override; void DeviceRestore() override; + void CheckConfigChanged(); + void CheckRenderResized(); + // Add additional common features dependent on other features, which may be backend-determined. u32 CheckGPUFeaturesLate(u32 features) const; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 8f7398aee6..8dfc89daa1 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -197,7 +197,8 @@ public: // Frame managment virtual void BeginHostFrame() = 0; virtual void EndHostFrame() = 0; - virtual void CheckResized() = 0; + + virtual void CheckDisplayResized() = 0; // Draw queue management virtual DisplayList* getList(int listid) = 0; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 0ff7a9f0a9..645f21064e 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1398,7 +1398,7 @@ void EmuScreen::render() { // If we're paused and PauseScreen is transparent (will only be in buffered rendering mode), we just copy display to output. thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Paused"); if (PSP_IsInited()) { - gpu->CheckResized(); + gpu->CheckDisplayResized(); gpu->CopyDisplayToOutput(true); } From cf44adbf5defb9442fb1f851ae38d5d83562cece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 18:09:04 +0100 Subject: [PATCH 344/715] Libretro fixes --- libretro/libretro.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 4213a72758..49f92cc989 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -1095,8 +1095,7 @@ static void check_variables(CoreParameter &coreParam) || g_Config.iTexScalingLevel != iTexScalingLevel_prev || g_Config.sTextureShaderName != sTextureShaderName_prev)) { - gpu->ClearCacheNextFrame(); - gpu->Resized(); + gpu->NotifyConfigChanged(); } if (g_Config.iLanguage < 0) @@ -1131,7 +1130,7 @@ static void check_variables(CoreParameter &coreParam) retro_get_system_av_info(&avInfo); environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avInfo); updateAvInfo = false; - gpu->Resized(); + gpu->NotifyDisplayResized(); } } From cbfa4bfc8eef3a5f0e09e0ea2c3113bb2a88a7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 18:13:13 +0100 Subject: [PATCH 345/715] Centralize ClearCacheNextFrame --- GPU/Common/TextureCacheCommon.cpp | 5 +---- GPU/Common/TextureCacheCommon.h | 1 - GPU/D3D11/GPU_D3D11.cpp | 4 ---- GPU/D3D11/GPU_D3D11.h | 1 - GPU/Directx9/GPU_DX9.cpp | 4 ---- GPU/Directx9/GPU_DX9.h | 1 - GPU/GLES/GPU_GLES.cpp | 4 ---- GPU/GLES/GPU_GLES.h | 1 - GPU/GPUCommon.cpp | 1 - GPU/GPUInterface.h | 3 --- GPU/Software/SoftGpu.h | 1 - GPU/Vulkan/GPU_Vulkan.cpp | 4 ---- GPU/Vulkan/GPU_Vulkan.h | 1 - 13 files changed, 1 insertion(+), 30 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 5ae10bcf31..03e530381e 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1200,6 +1200,7 @@ bool TextureCacheCommon::GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffe } void TextureCacheCommon::NotifyConfigChanged() { + clearCacheNextFrame_ = true; int scaleFactor = g_Config.iTexScalingLevel; if (!gstate_c.Use(GPU_USE_TEXTURE_NPOT)) { @@ -2554,10 +2555,6 @@ void TextureCacheCommon::InvalidateAll(GPUInvalidationType /*unused*/) { } } -void TextureCacheCommon::ClearNextFrame() { - clearCacheNextFrame_ = true; -} - std::string AttachCandidate::ToString() const { return StringFromFormat("[%s seq:%d rel:%d C:%08x/%d(%s) Z:%08x/%d X:%d Y:%d reint: %s]", this->channel == RASTER_COLOR ? "COLOR" : "DEPTH", diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index bbaf0eecde..4d46ff6590 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -323,7 +323,6 @@ public: bool SetOffsetTexture(u32 yOffset); void Invalidate(u32 addr, int size, GPUInvalidationType type); void InvalidateAll(GPUInvalidationType type); - void ClearNextFrame(); TextureShaderCache *GetTextureShaderCache() { return textureShaderCache_; } diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index e533e524e8..f03dca53f3 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -228,10 +228,6 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_D3D11::ClearCacheNextFrame() { - textureCacheD3D11_->ClearNextFrame(); -} - void GPU_D3D11::ClearShaderCache() { shaderManagerD3D11_->ClearShaders(); drawEngine_.ClearInputLayoutMap(); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index 0cba325618..e56acc632a 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -41,7 +41,6 @@ public: void ExecuteOp(u32 op, u32 diff) override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index e13a3b4f3d..c4053953cc 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -220,10 +220,6 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_DX9::ClearCacheNextFrame() { - textureCacheDX9_->ClearNextFrame(); -} - void GPU_DX9::ClearShaderCache() { shaderManagerDX9_->ClearCache(true); } diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 0ec463e55e..ff23b3fb23 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -41,7 +41,6 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index bee7a874f2..cec35c21d7 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -353,10 +353,6 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_GLES::ClearCacheNextFrame() { - textureCacheGL_->ClearNextFrame(); -} - void GPU_GLES::ClearShaderCache() { shaderManagerGL_->ClearCache(true); } diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index 4955a3c511..d9ac76390f 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -49,7 +49,6 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 9dfe4781d4..6222e1edb8 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -629,7 +629,6 @@ void GPUCommon::NotifyDisplayResized() { // if "transparent". void GPUCommon::CheckConfigChanged() { if (configChanged_) { - ClearCacheNextFrame(); gstate_c.useFlags = CheckGPUFeatures(); drawEngineCommon_->NotifyConfigChanged(); shaderManager_->DirtyLastShader(); // Don't think this is needed, at all. diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 8dfc89daa1..76afe301dd 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -244,9 +244,6 @@ public: virtual bool PerformWriteColorFromMemory(u32 dest, int size) = 0; virtual bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags = WriteStencil::NEEDS_CLEAR) = 0; - // Will cause the texture cache to be cleared at the start of the next frame. - virtual void ClearCacheNextFrame() = 0; - // Internal hack to avoid interrupts from "PPGe" drawing (utility UI, etc) virtual void EnableInterrupts(bool enable) = 0; diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 508baa6d0e..4ddb0fa782 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -144,7 +144,6 @@ public: bool PerformReadbackToMemory(u32 dest, int size) override; bool PerformWriteColorFromMemory(u32 dest, int size) override; bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags) override; - void ClearCacheNextFrame() override {} void DeviceLost() override; void DeviceRestore() override; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 6ed3789152..48b34baf9d 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -513,10 +513,6 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_Vulkan::ClearCacheNextFrame() { - textureCacheVulkan_->ClearNextFrame(); -} - void GPU_Vulkan::ClearShaderCache() { // TODO } diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index ee45b43e5b..1aa405e1f6 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -51,7 +51,6 @@ public: void ExecuteOp(u32 op, u32 diff) override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; From fe1446bf92e89a59df4935b55703d4d3e62fb7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 19:57:59 +0100 Subject: [PATCH 346/715] Test crashfix --- GPU/GPUCommon.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6222e1edb8..e6e7f2f25f 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -491,7 +491,9 @@ void GPUCommon::BeginHostFrame() { void GPUCommon::EndHostFrame() { // Probably not necessary. - draw_->InvalidateCachedState(); + if (draw_) { + draw_->InvalidateCachedState(); + } } void GPUCommon::Reinitialize() { From 8f103f3f4760a4a2219ee23d53f8c0fcaed3728a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Nov 2022 16:56:21 +0100 Subject: [PATCH 347/715] Extract the Vulkan descriptor binding cleanup from #16345 --- GPU/Common/FragmentShaderGenerator.cpp | 11 ++++++----- GPU/Common/VertexShaderGenerator.cpp | 13 +++++++------ GPU/Vulkan/DrawEngineVulkan.cpp | 17 ++--------------- GPU/Vulkan/DrawEngineVulkan.h | 14 ++++++++++++++ assets/lang/en_US.ini | 2 +- assets/lang/sv_SE.ini | 2 +- 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 9e90a707f3..dee1dfb431 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -31,6 +31,7 @@ #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderUniforms.h" #include "GPU/Common/FragmentShaderGenerator.h" +#include "GPU/Vulkan/DrawEngineVulkan.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -187,23 +188,23 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } - WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = %d) uniform baseUBO {\n%s};\n", DRAW_BINDING_DYNUBO_BASE, ub_baseStr); if (doTexture) { - WRITE(p, "layout (set = 1, binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); + WRITE(p, "layout (set = 1, binding = %d) uniform %s%s tex;\n", DRAW_BINDING_TEXTURE, texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); } if (readFramebufferTex) { // The framebuffer texture is always bound as an array. - p.C("layout (set = 1, binding = 1) uniform sampler2DArray fbotex;\n"); + p.F("layout (set = 1, binding = %d) uniform sampler2DArray fbotex;\n", DRAW_BINDING_2ND_TEXTURE); } else if (fetchFramebuffer) { - p.C("layout (input_attachment_index = 0, set = 1, binding = 9) uniform subpassInput inputColor;\n"); + p.F("layout (input_attachment_index = 0, set = 1, binding = %d) uniform subpassInput inputColor;\n", DRAW_BINDING_INPUT_ATTACHMENT); if (fragmentShaderFlags) { *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; } } if (shaderDepalMode != ShaderDepalMode::OFF) { - WRITE(p, "layout (set = 1, binding = 2) uniform sampler2D pal;\n"); + WRITE(p, "layout (set = 1, binding = %d) uniform sampler2D pal;\n", DRAW_BINDING_DEPAL_TEXTURE); } // Note: the precision qualifiers must match the vertex shader! diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 57e5e9675f..7e9d2cadb8 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -30,6 +30,7 @@ #include "GPU/Common/ShaderUniforms.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/VertexShaderGenerator.h" +#include "GPU/Vulkan/DrawEngineVulkan.h" #undef WRITE @@ -256,11 +257,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "layout (std140, set = 0, binding = 0) uniform frameVars {\n%s};\n", ub_frameStr); } - WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = %d) uniform baseVars {\n%s};\n", DRAW_BINDING_DYNUBO_BASE, ub_baseStr); if (enableLighting || doShadeMapping) - WRITE(p, "layout (std140, set = 1, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); + WRITE(p, "layout (std140, set = 1, binding = %d) uniform lightVars {\n%s};\n", DRAW_BINDING_DYNUBO_LIGHT, ub_vs_lightsStr); if (enableBones) - WRITE(p, "layout (std140, set = 1, binding = 5) uniform boneVars {\n%s};\n", ub_vs_bonesStr); + WRITE(p, "layout (std140, set = 1, binding = %d) uniform boneVars {\n%s};\n", DRAW_BINDING_DYNUBO_BONE, ub_vs_bonesStr); if (enableBones) { WRITE(p, "%s", boneWeightDecl[numBoneWeights]); @@ -638,7 +639,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 tex;\n"); WRITE(p, " vec4 col;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 1, binding = 6) readonly buffer s_tess_data {\n"); + WRITE(p, "layout (std430, set = 1, binding = %d) readonly buffer s_tess_data {\n", DRAW_BINDING_TESS_STORAGE_BUF); WRITE(p, " TessData tess_data[];\n"); WRITE(p, "};\n"); @@ -646,10 +647,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 basis;\n"); WRITE(p, " vec4 deriv;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 1, binding = 7) readonly buffer s_tess_weights_u {\n"); + WRITE(p, "layout (std430, set = 1, binding = %d) readonly buffer s_tess_weights_u {\n", DRAW_BINDING_TESS_STORAGE_BUF_WU); WRITE(p, " TessWeight tess_weights_u[];\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 1, binding = 8) readonly buffer s_tess_weights_v {\n"); + WRITE(p, "layout (std430, set = 1, binding = %d) readonly buffer s_tess_weights_v {\n", DRAW_BINDING_TESS_STORAGE_BUF_WV); WRITE(p, " TessWeight tess_weights_v[];\n"); WRITE(p, "};\n"); } else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 3a683f3238..a26b14320f 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -62,19 +62,6 @@ enum { enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 }; -enum { - DRAW_BINDING_TEXTURE = 0, - DRAW_BINDING_2ND_TEXTURE = 1, - DRAW_BINDING_DEPAL_TEXTURE = 2, - DRAW_BINDING_DYNUBO_BASE = 3, - DRAW_BINDING_DYNUBO_LIGHT = 4, - DRAW_BINDING_DYNUBO_BONE = 5, - DRAW_BINDING_TESS_STORAGE_BUF = 6, - DRAW_BINDING_TESS_STORAGE_BUF_WU = 7, - DRAW_BINDING_TESS_STORAGE_BUF_WV = 8, - DRAW_BINDING_INPUT_ATTACHMENT = 9, -}; - enum { TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex) }; @@ -97,7 +84,7 @@ void DrawEngineVulkan::InitDeviceObjects() { // TODO: Make things more flexible, so we at least have specialized layouts for input attachments and tess. // Note that it becomes a support matrix.. - VkDescriptorSetLayoutBinding bindings[10]{}; + VkDescriptorSetLayoutBinding bindings[DRAW_BINDING_COUNT]{}; bindings[0].descriptorCount = 1; bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; @@ -415,7 +402,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView _assert_msg_(desc != VK_NULL_HANDLE, "Ran out of descriptor space in pool. sz=%d", (int)frame.descSets.size()); // We just don't write to the slots we don't care about, which is fine. - VkWriteDescriptorSet writes[9]{}; + VkWriteDescriptorSet writes[DRAW_BINDING_COUNT]{}; // Main texture int n = 0; VkDescriptorImageInfo tex[3]{}; diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 035bc595df..7d069c4305 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -121,6 +121,20 @@ private: VkDescriptorBufferInfo bufInfo_[3]{}; }; +enum { + DRAW_BINDING_TEXTURE = 0, + DRAW_BINDING_2ND_TEXTURE = 1, + DRAW_BINDING_DEPAL_TEXTURE = 2, + DRAW_BINDING_DYNUBO_BASE = 3, + DRAW_BINDING_DYNUBO_LIGHT = 4, + DRAW_BINDING_DYNUBO_BONE = 5, + DRAW_BINDING_TESS_STORAGE_BUF = 6, + DRAW_BINDING_TESS_STORAGE_BUF_WU = 7, + DRAW_BINDING_TESS_STORAGE_BUF_WV = 8, + DRAW_BINDING_INPUT_ATTACHMENT = 9, + DRAW_BINDING_COUNT = 10, +}; + // Handles transform, lighting and drawing. class DrawEngineVulkan : public DrawEngineCommon { public: diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 20450f8351..802cf62e42 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -569,7 +569,7 @@ Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter Skip GPU Readbacks = Skip GPU Readbacks -Software Rendering = Software rendering (slow) +Software Rendering = Software rendering (slow, accurate) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index c55bd25529..2e38abbc3b 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -546,7 +546,7 @@ Screen Scaling Filter = Skärmskalningsfilter Show Debug Statistics = Visa debugstatistik Show FPS Counter = Visa FPS-räknare Skip GPU Readbacks = Skip GPU Readbacks -Software Rendering = Mjukvarurendering (experiment) +Software Rendering = Mjukvarurendering (långsam men ofta mer korrekt) Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet From ec6d330ae416a2e48b8c6460b127aebe677d4674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Nov 2022 20:15:22 +0100 Subject: [PATCH 348/715] Move AsyncImageFileView to Common, which required some more shuffling around of stuff. --- CMakeLists.txt | 6 +- Common/Common.vcxproj | 4 + Common/Common.vcxproj.filters | 12 ++ .../Render/ManagedTexture.cpp | 38 +----- .../Render/ManagedTexture.h | 15 --- Common/UI/AsyncImageFileView.cpp | 113 ++++++++++++++++++ Common/UI/AsyncImageFileView.h | 44 +++++++ Common/UI/Context.cpp | 2 +- UI/EmuScreen.cpp | 1 + UI/GameInfoCache.cpp | 2 +- UI/GameInfoCache.h | 2 +- UI/GameScreen.cpp | 1 + UI/NativeApp.cpp | 1 - UI/PauseScreen.cpp | 110 +---------------- UI/PauseScreen.h | 44 +------ UI/ReportScreen.cpp | 1 + UI/SavedataScreen.cpp | 36 ++++++ UI/SavedataScreen.h | 17 +++ UI/Store.cpp | 2 +- UI/UI.vcxproj | 2 - UI/UI.vcxproj.filters | 4 +- UWP/CommonUWP/CommonUWP.vcxproj | 4 + UWP/CommonUWP/CommonUWP.vcxproj.filters | 12 ++ UWP/UI_UWP/UI_UWP.vcxproj | 4 +- UWP/UI_UWP/UI_UWP.vcxproj.filters | 8 +- android/jni/Android.mk | 3 +- libretro/Makefile.common | 5 +- 27 files changed, 274 insertions(+), 219 deletions(-) rename UI/TextureUtil.cpp => Common/Render/ManagedTexture.cpp (83%) rename UI/TextureUtil.h => Common/Render/ManagedTexture.h (73%) create mode 100644 Common/UI/AsyncImageFileView.cpp create mode 100644 Common/UI/AsyncImageFileView.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 12c75eaff3..ac021cf474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -692,6 +692,8 @@ add_library(Common STATIC Common/Render/TextureAtlas.h Common/Render/DrawBuffer.cpp Common/Render/DrawBuffer.h + Common/Render/ManagedTexture.cpp + Common/Render/ManagedTexture.h Common/Render/Text/draw_text.cpp Common/Render/Text/draw_text.h Common/Render/Text/draw_text_android.cpp @@ -710,6 +712,8 @@ add_library(Common STATIC Common/Thread/ThreadUtil.h Common/Thread/ThreadManager.cpp Common/Thread/ThreadManager.h + Common/UI/AsyncImageFileView.cpp + Common/UI/AsyncImageFileView.h Common/UI/Root.cpp Common/UI/Root.h Common/UI/Screen.cpp @@ -1293,8 +1297,6 @@ list(APPEND NativeAppSource UI/MemStickScreen.cpp UI/ProfilerDraw.h UI/ProfilerDraw.cpp - UI/TextureUtil.h - UI/TextureUtil.cpp UI/ComboKeyMappingScreen.h UI/ComboKeyMappingScreen.cpp UI/Theme.h diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 39e804db79..d59ae3136e 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -477,6 +477,7 @@ + @@ -549,6 +550,7 @@ + @@ -905,6 +907,7 @@ + @@ -988,6 +991,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 33468b43d8..ac2fde0155 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -446,6 +446,12 @@ VR + + UI + + + Render + @@ -845,6 +851,12 @@ VR + + UI + + + Render + diff --git a/UI/TextureUtil.cpp b/Common/Render/ManagedTexture.cpp similarity index 83% rename from UI/TextureUtil.cpp rename to Common/Render/ManagedTexture.cpp index 80dfb59e1a..771d4f8a92 100644 --- a/UI/TextureUtil.cpp +++ b/Common/Render/ManagedTexture.cpp @@ -14,8 +14,7 @@ #include "Common/File/VFS/VFS.h" #include "Common/Log.h" #include "Common/TimeUtil.h" -#include "UI/TextureUtil.h" -#include "UI/GameInfoCache.h" +#include "Common/Render/ManagedTexture.h" static Draw::DataFormat ZimToT3DFormat(int zim) { switch (zim) { @@ -217,38 +216,3 @@ std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *dra return std::unique_ptr(); } } - -void GameIconView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - w = textureWidth_; - h = textureHeight_; -} - -void GameIconView::Draw(UIContext &dc) { - using namespace UI; - std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); - - if (!info->icon.texture) { - return; - } - - textureWidth_ = info->icon.texture->Width() * scale_; - textureHeight_ = info->icon.texture->Height() * scale_; - - // Fade icon with the backgrounds. - double loadTime = info->icon.timeLoaded; - auto pic = info->GetBGPic(); - if (pic) { - loadTime = std::max(loadTime, pic->timeLoaded); - } - uint32_t color = whiteAlpha(ease((time_now_d() - loadTime) * 3)); - - // Adjust size so we don't stretch the image vertically or horizontally. - // Make sure it's not wider than 144 (like Doom Legacy homebrew), ugly in the grid mode. - float nw = std::min(bounds_.h * textureWidth_ / textureHeight_, (float)bounds_.w); - - dc.Flush(); - dc.GetDrawContext()->BindTexture(0, info->icon.texture->GetTexture()); - dc.Draw()->Rect(bounds_.x, bounds_.y, nw, bounds_.h, color); - dc.Flush(); - dc.RebindTexture(); -} diff --git a/UI/TextureUtil.h b/Common/Render/ManagedTexture.h similarity index 73% rename from UI/TextureUtil.h rename to Common/Render/ManagedTexture.h index 19d9b40cb0..ed6e9918f6 100644 --- a/UI/TextureUtil.h +++ b/Common/Render/ManagedTexture.h @@ -43,18 +43,3 @@ private: std::unique_ptr CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType, bool generateMips); std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType, bool generateMips, const char *name); -class GameIconView : public UI::InertView { -public: - GameIconView(const Path &gamePath, float scale, UI::LayoutParams *layoutParams = 0) - : InertView(layoutParams), gamePath_(gamePath), scale_(scale) {} - - void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; - void Draw(UIContext &dc) override; - std::string DescribeText() const override { return ""; } - -private: - Path gamePath_; - float scale_ = 1.0f; - int textureWidth_ = 0; - int textureHeight_ = 0; -}; diff --git a/Common/UI/AsyncImageFileView.cpp b/Common/UI/AsyncImageFileView.cpp new file mode 100644 index 0000000000..925d1c9337 --- /dev/null +++ b/Common/UI/AsyncImageFileView.cpp @@ -0,0 +1,113 @@ +#include "Common/UI/View.h" +#include "Common/UI/AsyncImageFileView.h" +#include "Common/UI/Context.h" +#include "Common/Render/DrawBuffer.h" + +AsyncImageFileView::AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams) + : UI::Clickable(layoutParams), canFocus_(true), filename_(filename), color_(0xFFFFFFFF), sizeMode_(sizeMode), textureFailed_(false), fixedSizeW_(0.0f), fixedSizeH_(0.0f) {} + +AsyncImageFileView::~AsyncImageFileView() {} + +static float DesiredSize(float sz, float contentSize, UI::MeasureSpec spec) { + float measured; + UI::MeasureBySpec(sz, contentSize, spec, &measured); + return measured; +} + +void AsyncImageFileView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const { + if (texture_ && texture_->GetTexture()) { + float texw = (float)texture_->Width(); + float texh = (float)texture_->Height(); + float desiredW = DesiredSize(layoutParams_->width, w, horiz); + float desiredH = DesiredSize(layoutParams_->height, h, vert); + switch (sizeMode_) { + case UI::IS_FIXED: + w = fixedSizeW_; + h = fixedSizeH_; + break; + case UI::IS_KEEP_ASPECT: + w = texw; + h = texh; + if (desiredW != w || desiredH != h) { + float aspect = w / h; + // We need the other dimension based on the desired scale to find the best aspect. + float desiredWOther = DesiredSize(layoutParams_->height, h * (desiredW / w), vert); + float desiredHOther = DesiredSize(layoutParams_->width, w * (desiredH / h), horiz); + + float diffW = fabsf(aspect - desiredW / desiredWOther); + float diffH = fabsf(aspect - desiredH / desiredHOther); + if (diffW < diffH) { + w = desiredW; + h = desiredWOther; + } else { + w = desiredHOther; + h = desiredH; + } + } + break; + case UI::IS_DEFAULT: + default: + w = texw; + h = texh; + break; + } + } else { + w = 16; + h = 16; + } +} + +void AsyncImageFileView::SetFilename(const Path &filename) { + if (filename_ != filename) { + textureFailed_ = false; + filename_ = filename; + texture_.reset(nullptr); + } +} + +void AsyncImageFileView::DeviceLost() { + if (texture_.get()) + texture_->DeviceLost(); +} + +void AsyncImageFileView::DeviceRestored(Draw::DrawContext *draw) { + if (texture_.get()) + texture_->DeviceRestored(draw); +} + +void AsyncImageFileView::Draw(UIContext &dc) { + using namespace Draw; + if (!texture_ && !textureFailed_ && !filename_.empty()) { + texture_ = CreateTextureFromFile(dc.GetDrawContext(), filename_.c_str(), DETECT, true); + if (!texture_.get()) + textureFailed_ = true; + } + + if (HasFocus()) { + dc.FillRect(dc.theme->itemFocusedStyle.background, bounds_.Expand(3)); + } + + // TODO: involve sizemode + if (texture_ && texture_->GetTexture()) { + dc.Flush(); + dc.GetDrawContext()->BindTexture(0, texture_->GetTexture()); + dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_); + dc.Flush(); + dc.RebindTexture(); + if (!text_.empty()) { + dc.DrawText(text_.c_str(), bounds_.centerX() + 1, bounds_.centerY() + 1, 0x80000000, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + } + } else { + if (!filename_.empty()) { + // draw a black rectangle to represent the missing screenshot. + dc.FillRect(UI::Drawable(0xFF000000), GetBounds()); + } else { + // draw a dark gray rectangle to represent no save state. + dc.FillRect(UI::Drawable(0x50202020), GetBounds()); + } + if (!text_.empty()) { + dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + } + } +} diff --git a/Common/UI/AsyncImageFileView.h b/Common/UI/AsyncImageFileView.h new file mode 100644 index 0000000000..5acaca30a5 --- /dev/null +++ b/Common/UI/AsyncImageFileView.h @@ -0,0 +1,44 @@ +#pragma once + +#include "Common/UI/View.h" +#include "Common/Render/ManagedTexture.h" +#include "Common/File/Path.h" + +class UIContext; + +// AsyncImageFileView loads a texture from a file, and reloads it as necessary. +// TODO: Actually make async, doh. +class AsyncImageFileView : public UI::Clickable { +public: + AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams = 0); + ~AsyncImageFileView(); + + void GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const override; + void Draw(UIContext &dc) override; + std::string DescribeText() const override { return text_; } + + void DeviceLost() override; + void DeviceRestored(Draw::DrawContext *draw) override; + + void SetFilename(const Path &filename); + void SetColor(uint32_t color) { color_ = color; } + void SetOverlayText(std::string text) { text_ = text; } + void SetFixedSize(float fixW, float fixH) { fixedSizeW_ = fixW; fixedSizeH_ = fixH; } + void SetCanBeFocused(bool can) { canFocus_ = can; } + + bool CanBeFocused() const override { return canFocus_; } + + const Path &GetFilename() const { return filename_; } + +private: + bool canFocus_; + Path filename_; + std::string text_; + uint32_t color_; + UI::ImageSizeMode sizeMode_; + + std::unique_ptr texture_; + bool textureFailed_; + float fixedSizeW_; + float fixedSizeH_; +}; diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index 21c687bd2b..40bc95c824 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -10,9 +10,9 @@ #include "Common/UI/Context.h" #include "Common/Render/DrawBuffer.h" #include "Common/Render/Text/draw_text.h" +#include "Common/Render/ManagedTexture.h" #include "Common/Log.h" #include "Common/LogReporting.h" -#include "UI/TextureUtil.h" UIContext::UIContext() { fontStyle_ = new UI::FontStyle(); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index bfbc7edf8c..dfbb42b79a 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -31,6 +31,7 @@ using namespace std::placeholders; #include "Common/UI/Context.h" #include "Common/UI/Tween.h" #include "Common/UI/View.h" +#include "Common/UI/AsyncImageFileView.h" #include "Common/VR/PPSSPPVR.h" #include "Common/Data/Text/I18n.h" diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index ec4ea77700..b6f0a7cfb7 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -29,6 +29,7 @@ #include "Common/File/Path.h" #include "Common/StringUtils.h" #include "Common/TimeUtil.h" +#include "Common/Render/ManagedTexture.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/FileSystems/DirectoryFileSystem.h" #include "Core/FileSystems/VirtualDiscFileSystem.h" @@ -39,7 +40,6 @@ #include "Core/Util/GameManager.h" #include "Core/Config.h" #include "UI/GameInfoCache.h" -#include "UI/TextureUtil.h" GameInfoCache *g_gameInfoCache; diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index a23aa92442..1df4f64ad5 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -26,7 +26,7 @@ #include "Common/Thread/Event.h" #include "Core/ELF/ParamSFO.h" #include "Common/File/Path.h" -#include "UI/TextureUtil.h" +#include "Common/Render/ManagedTexture.h" namespace Draw { class DrawContext; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index edf519f46b..4486bbd9a3 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -43,6 +43,7 @@ #include "UI/MiscScreens.h" #include "UI/MainScreen.h" #include "UI/BackgroundAudio.h" +#include "UI/SavedataScreen.h" #include "Core/Reporting.h" GameScreen::GameScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 0bea47395a..88c27d4393 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -114,7 +114,6 @@ #include "UI/OnScreenDisplay.h" #include "UI/RemoteISOScreen.h" #include "UI/TiltEventProcessor.h" -#include "UI/TextureUtil.h" #include "UI/Theme.h" #if !defined(MOBILE_DEVICE) && defined(USING_QT_UI) diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 6e3e3d001e..68f55bcc40 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -29,6 +29,7 @@ #include "Common/StringUtils.h" #include "Common/System/System.h" #include "Common/VR/PPSSPPVR.h" +#include "Common/UI/AsyncImageFileView.h" #include "Core/Reporting.h" #include "Core/SaveState.h" @@ -49,115 +50,6 @@ #include "UI/OnScreenDisplay.h" #include "UI/GameInfoCache.h" -AsyncImageFileView::AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams) - : UI::Clickable(layoutParams), canFocus_(true), filename_(filename), color_(0xFFFFFFFF), sizeMode_(sizeMode), textureFailed_(false), fixedSizeW_(0.0f), fixedSizeH_(0.0f) {} - -AsyncImageFileView::~AsyncImageFileView() {} - -static float DesiredSize(float sz, float contentSize, UI::MeasureSpec spec) { - float measured; - UI::MeasureBySpec(sz, contentSize, spec, &measured); - return measured; -} - -void AsyncImageFileView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const { - if (texture_ && texture_->GetTexture()) { - float texw = (float)texture_->Width(); - float texh = (float)texture_->Height(); - float desiredW = DesiredSize(layoutParams_->width, w, horiz); - float desiredH = DesiredSize(layoutParams_->height, h, vert); - switch (sizeMode_) { - case UI::IS_FIXED: - w = fixedSizeW_; - h = fixedSizeH_; - break; - case UI::IS_KEEP_ASPECT: - w = texw; - h = texh; - if (desiredW != w || desiredH != h) { - float aspect = w / h; - // We need the other dimension based on the desired scale to find the best aspect. - float desiredWOther = DesiredSize(layoutParams_->height, h * (desiredW / w), vert); - float desiredHOther = DesiredSize(layoutParams_->width, w * (desiredH / h), horiz); - - float diffW = fabsf(aspect - desiredW / desiredWOther); - float diffH = fabsf(aspect - desiredH / desiredHOther); - if (diffW < diffH) { - w = desiredW; - h = desiredWOther; - } else { - w = desiredHOther; - h = desiredH; - } - } - break; - case UI::IS_DEFAULT: - default: - w = texw; - h = texh; - break; - } - } else { - w = 16; - h = 16; - } -} - -void AsyncImageFileView::SetFilename(const Path &filename) { - if (filename_ != filename) { - textureFailed_ = false; - filename_ = filename; - texture_.reset(nullptr); - } -} - -void AsyncImageFileView::DeviceLost() { - if (texture_.get()) - texture_->DeviceLost(); -} - -void AsyncImageFileView::DeviceRestored(Draw::DrawContext *draw) { - if (texture_.get()) - texture_->DeviceRestored(draw); -} - -void AsyncImageFileView::Draw(UIContext &dc) { - using namespace Draw; - if (!texture_ && !textureFailed_ && !filename_.empty()) { - texture_ = CreateTextureFromFile(dc.GetDrawContext(), filename_.c_str(), DETECT, true); - if (!texture_.get()) - textureFailed_ = true; - } - - if (HasFocus()) { - dc.FillRect(dc.theme->itemFocusedStyle.background, bounds_.Expand(3)); - } - - // TODO: involve sizemode - if (texture_ && texture_->GetTexture()) { - dc.Flush(); - dc.GetDrawContext()->BindTexture(0, texture_->GetTexture()); - dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_); - dc.Flush(); - dc.RebindTexture(); - if (!text_.empty()) { - dc.DrawText(text_.c_str(), bounds_.centerX()+1, bounds_.centerY()+1, 0x80000000, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); - dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); - } - } else { - if (!filename_.empty()) { - // draw a black rectangle to represent the missing screenshot. - dc.FillRect(UI::Drawable(0xFF000000), GetBounds()); - } else { - // draw a dark gray rectangle to represent no save state. - dc.FillRect(UI::Drawable(0x50202020), GetBounds()); - } - if (!text_.empty()) { - dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); - } - } -} - static void AfterSaveStateAction(SaveState::Status status, const std::string &message, void *) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { osm.Show(message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 6b48f7bdb2..c4180bdd9f 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -24,7 +24,11 @@ #include "Common/UI/UIScreen.h" #include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" -#include "UI/TextureUtil.h" + +enum class PauseScreenMode { + MAIN, + DISPLAY_SETTINGS, +}; class GamePauseScreen : public UIDialogScreenWithGameBackground { public: @@ -64,41 +68,5 @@ private: // hack bool finishNextFrame_ = false; Path gamePath_; -}; - -// AsyncImageFileView loads a texture from a file, and reloads it as necessary. -// TODO: Actually make async, doh. -class AsyncImageFileView : public UI::Clickable { -public: - AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams = 0); - ~AsyncImageFileView(); - - void GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const override; - void Draw(UIContext &dc) override; - std::string DescribeText() const override { return text_; } - - void DeviceLost() override; - void DeviceRestored(Draw::DrawContext *draw) override; - - void SetFilename(const Path &filename); - void SetColor(uint32_t color) { color_ = color; } - void SetOverlayText(std::string text) { text_ = text; } - void SetFixedSize(float fixW, float fixH) { fixedSizeW_ = fixW; fixedSizeH_ = fixH; } - void SetCanBeFocused(bool can) { canFocus_ = can; } - - bool CanBeFocused() const override { return canFocus_; } - - const Path &GetFilename() const { return filename_; } - -private: - bool canFocus_; - Path filename_; - std::string text_; - uint32_t color_; - UI::ImageSizeMode sizeMode_; - - std::unique_ptr texture_; - bool textureFailed_; - float fixedSizeW_; - float fixedSizeH_; + PauseScreenMode mode_ = PauseScreenMode::MAIN; }; diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index 101ec4c83b..b1d7de7326 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -20,6 +20,7 @@ // TODO: For text align flags, probably shouldn't be in gfx_es2/... #include "Common/Render/DrawBuffer.h" #include "Common/GPU/thin3d.h" +#include "Common/UI/AsyncImageFileView.h" #include "Common/UI/Context.h" #include "UI/PauseScreen.h" #include "UI/ReportScreen.h" diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 0172b6a19b..0d04ac02b9 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -29,6 +29,7 @@ #include "Common/UI/Context.h" #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "Common/UI/AsyncImageFileView.h" #include "UI/SavedataScreen.h" #include "UI/MainScreen.h" #include "UI/GameInfoCache.h" @@ -707,3 +708,38 @@ void SavedataScreen::sendMessage(const char *message, const char *value) { stateBrowser_->SetSearchFilter(searchFilter_); } } + +void GameIconView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { + w = textureWidth_; + h = textureHeight_; +} + +void GameIconView::Draw(UIContext &dc) { + using namespace UI; + std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); + + if (!info->icon.texture) { + return; + } + + textureWidth_ = info->icon.texture->Width() * scale_; + textureHeight_ = info->icon.texture->Height() * scale_; + + // Fade icon with the backgrounds. + double loadTime = info->icon.timeLoaded; + auto pic = info->GetBGPic(); + if (pic) { + loadTime = std::max(loadTime, pic->timeLoaded); + } + uint32_t color = whiteAlpha(ease((time_now_d() - loadTime) * 3)); + + // Adjust size so we don't stretch the image vertically or horizontally. + // Make sure it's not wider than 144 (like Doom Legacy homebrew), ugly in the grid mode. + float nw = std::min(bounds_.h * textureWidth_ / textureHeight_, (float)bounds_.w); + + dc.Flush(); + dc.GetDrawContext()->BindTexture(0, info->icon.texture->GetTexture()); + dc.Draw()->Rect(bounds_.x, bounds_.y, nw, bounds_.h, color); + dc.Flush(); + dc.RebindTexture(); +} diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index 1bb2f42140..10cd631250 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -27,6 +27,7 @@ #include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" +#include "UI/GameInfoCache.h" enum class SavedataSortOption { FILENAME, @@ -88,3 +89,19 @@ protected: SavedataBrowser *stateBrowser_; std::string searchFilter_; }; + +class GameIconView : public UI::InertView { +public: + GameIconView(const Path &gamePath, float scale, UI::LayoutParams *layoutParams = 0) + : InertView(layoutParams), gamePath_(gamePath), scale_(scale) {} + + void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; + void Draw(UIContext &dc) override; + std::string DescribeText() const override { return ""; } + +private: + Path gamePath_; + float scale_ = 1.0f; + int textureWidth_ = 0; + int textureHeight_ = 0; +}; diff --git a/UI/Store.cpp b/UI/Store.cpp index 86a084da95..b6000e9d3b 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -26,12 +26,12 @@ #include "Common/Data/Text/I18n.h" #include "Common/Data/Format/JSONReader.h" #include "Common/StringUtils.h" +#include "Common/Render/ManagedTexture.h" #include "Core/Config.h" #include "Core/System.h" #include "Core/Util/GameManager.h" #include "UI/EmuScreen.h" #include "UI/Store.h" -#include "UI/TextureUtil.h" const std::string storeBaseUrl = "http://store.ppsspp.org/"; diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 666e35aa02..edf77d026e 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -61,7 +61,6 @@ - @@ -96,7 +95,6 @@ - diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 2c63641535..3f03e3242f 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -67,7 +67,6 @@ Screens - Screens @@ -81,6 +80,7 @@ Screens + @@ -149,7 +149,6 @@ Screens - Screens @@ -163,6 +162,7 @@ Screens + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index 0415092a9d..930306c7f7 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -448,6 +448,7 @@ + @@ -495,6 +496,7 @@ + @@ -578,6 +580,7 @@ + @@ -613,6 +616,7 @@ + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 15c00bcbfa..954e21c236 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -405,6 +405,12 @@ GPU\Vulkan + + UI + + + Render + @@ -748,6 +754,12 @@ GPU\Vulkan + + UI + + + Render + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index c6534b2cd9..57358dde23 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -407,7 +407,6 @@ - @@ -444,7 +443,6 @@ - @@ -467,4 +465,4 @@ - + \ No newline at end of file diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index bae3799bc9..fde9770206 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -28,11 +28,12 @@ - + + @@ -63,10 +64,11 @@ - + + - + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 2f3887c3e2..a8b6090dfe 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -166,6 +166,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/GPU/Shader.cpp \ $(SRC)/Common/GPU/ShaderWriter.cpp \ $(SRC)/Common/GPU/ShaderTranslation.cpp \ + $(SRC)/Common/Render/ManagedTexture.cpp \ $(SRC)/Common/Render/DrawBuffer.cpp \ $(SRC)/Common/Render/TextureAtlas.cpp \ $(SRC)/Common/Render/Text/draw_text.cpp \ @@ -192,6 +193,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/Thread/ThreadUtil.cpp \ $(SRC)/Common/Thread/ThreadManager.cpp \ $(SRC)/Common/Thread/ParallelLoop.cpp \ + $(SRC)/Common/UI/AsyncImageFileView.cpp \ $(SRC)/Common/UI/Root.cpp \ $(SRC)/Common/UI/Screen.cpp \ $(SRC)/Common/UI/UI.cpp \ @@ -713,7 +715,6 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/OnScreenDisplay.cpp \ $(SRC)/UI/ProfilerDraw.cpp \ $(SRC)/UI/NativeApp.cpp \ - $(SRC)/UI/TextureUtil.cpp \ $(SRC)/UI/Theme.cpp \ $(SRC)/UI/ComboKeyMappingScreen.cpp diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 27540dc86f..b310680f1f 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -281,12 +281,14 @@ SOURCES_CXX += \ $(COMMONDIR)/Net/Sinks.cpp \ $(COMMONDIR)/Net/URL.cpp \ $(COMMONDIR)/Net/WebsocketServer.cpp \ + $(COMMONDIR)/Render/ManagedTexture.cpp \ $(COMMONDIR)/Render/DrawBuffer.cpp \ $(COMMONDIR)/Render/TextureAtlas.cpp \ $(COMMONDIR)/Serialize/Serializer.cpp \ $(COMMONDIR)/Thread/ThreadUtil.cpp \ $(COMMONDIR)/Thread/ParallelLoop.cpp \ $(COMMONDIR)/Thread/ThreadManager.cpp \ + $(COMMONDIR)/UI/AsyncImageFileView.cpp \ $(COMMONDIR)/UI/Root.cpp \ $(COMMONDIR)/UI/Screen.cpp \ $(COMMONDIR)/UI/UI.cpp \ @@ -616,8 +618,7 @@ SOURCES_CXX += \ $(COREDIR)/Util/PPGeDraw.cpp \ $(COREDIR)/Util/AudioFormat.cpp \ $(COREDIR)/Util/PortManager.cpp \ - $(CORE_DIR)/UI/TextureUtil.cpp \ - $(CORE_DIR)/UI/GameInfoCache.cpp + $(CORE_DIR)/UI/GameInfoCache.cpp SOURCES_CXX += $(COREDIR)/HLE/__sceAudio.cpp From 2f4e0e7d5005ebe944515310a53059b5e4ef53ad Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Nov 2022 00:12:12 -0800 Subject: [PATCH 349/715] D3D11: Remove unused hack USE flag. Only GLES uses this now, we always have accurate depth here. --- GPU/D3D11/GPU_D3D11.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 93793165ac..966cbe7e2a 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -118,11 +118,6 @@ u32 GPU_D3D11::CheckGPUFeatures() const { features |= GPU_USE_16BIT_FORMATS; } - // The Phantasy Star hack :( - if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_USE_ACCURATE_DEPTH) == 0) { - features |= GPU_USE_DEPTH_RANGE_HACK; - } - return CheckGPUFeaturesLate(features); } From 1eac95ea25f997f0f8d3ba0fd4aa2b6e236c8be6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Nov 2022 00:13:06 -0800 Subject: [PATCH 350/715] Kernel: Respect partition param in heap funcs. --- Core/HLE/sceKernelHeap.cpp | 40 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index f584684cbb..83657cfbf0 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -45,11 +45,16 @@ struct KernelHeap : public KernelObject { static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) { u32 allocSize = (size + 3) & ~3; - // TODO: partitionId should probably decide if we allocate from userMemory or kernel or whatever... - u32 addr = userMemory.Alloc(allocSize, g_fromBottom, "SysMemForKernel-Heap"); + BlockAllocator *allocator = BlockAllocatorFromAddr(partitionId); + // TODO: Validate error code. + if (!allocator) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + + // TODO: This should probably actually use flags? Name? + u32 addr = allocator->Alloc(allocSize, g_fromBottom, "SysMemForKernel-Heap"); if (addr == (u32)-1) { - ERROR_LOG(HLE, "sceKernelCreateHeap(partitionId=%d): Failed to allocate %d bytes memory", partitionId, size); - return SCE_KERNEL_ERROR_NO_MEMORY; // Blind guess + // TODO: Validate error code. + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "fFailed to allocate %d bytes of memory", size); } KernelHeap *heap = new KernelHeap(); @@ -74,7 +79,7 @@ static int sceKernelAllocHeapMemory(int heapId, int size) { u32 addr = heap->alloc.Alloc(memSize, true); return hleLogSuccessInfoX(SCEKERNEL, addr); } else { - return hleLogError(SCEKERNEL, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId); + return hleLogError(SCEKERNEL, error, "invalid heapId"); } } @@ -82,26 +87,31 @@ static int sceKernelDeleteHeap(int heapId) { u32 error; KernelHeap *heap = kernelObjects.Get(heapId, error); if (heap) { - userMemory.Free(heap->address); + // Not using heap->partitionId here for backwards compatibility with old save states. + BlockAllocator *allocator = BlockAllocatorFromAddr(heap->address); + if (allocator) + allocator->Free(heap->address); kernelObjects.Destroy(heap->uid); return hleLogSuccessInfoX(SCEKERNEL, 0); } else { - return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId); + return hleLogError(SCEKERNEL, error, "invalid heapId"); } } static u32 sceKernelPartitionTotalFreeMemSize(int partitionId) { - ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionTotalFreeMemSize(%d)", partitionId); - //Need more work #13021 - ///We ignore partitionId for now - return userMemory.GetTotalFreeBytes(); + BlockAllocator *allocator = BlockAllocatorFromID(partitionId); + // TODO: Validate error code. + if (!allocator) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + return hleLogWarning(SCEKERNEL, allocator->GetTotalFreeBytes()); } static u32 sceKernelPartitionMaxFreeMemSize(int partitionId) { - ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionMaxFreeMemSize(%d)", partitionId); - //Need more work #13021 - ///We ignore partitionId for now - return userMemory.GetLargestFreeBlockSize(); + BlockAllocator *allocator = BlockAllocatorFromID(partitionId); + // TODO: Validate error code. + if (!allocator) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + return hleLogWarning(SCEKERNEL, allocator->GetLargestFreeBlockSize()); } static u32 SysMemForKernel_536AD5E1() From d551d2a3ed6b907898e5e6b1b2af31b8d448c824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Nov 2022 12:00:40 +0100 Subject: [PATCH 351/715] Pause menu background: Remove complicated transparency tricks, instead draw game as part of background. --- Common/UI/Context.h | 7 ++++++- UI/EmuScreen.cpp | 24 ------------------------ UI/MiscScreens.cpp | 35 ++++++++++++++++++++++++++++++++--- UI/MiscScreens.h | 2 ++ UI/PauseScreen.cpp | 18 ------------------ UI/PauseScreen.h | 3 --- 6 files changed, 40 insertions(+), 49 deletions(-) diff --git a/Common/UI/Context.h b/Common/UI/Context.h index ac26ab0202..b7c6982176 100644 --- a/Common/UI/Context.h +++ b/Common/UI/Context.h @@ -71,7 +71,6 @@ public: DrawBuffer *Draw() const { return uidrawbuffer_; } DrawBuffer *DrawTop() const { return uidrawbufferTop_; } - const UI::Theme *theme; // Utility methods TextDrawer *Text() const { return textDrawer_; } @@ -94,6 +93,9 @@ public: const Bounds &GetBounds() const { return bounds_; } Bounds GetLayoutBounds() const; Draw::DrawContext *GetDrawContext() { return draw_; } + const UI::Theme &GetTheme() const { + return *theme; + } void SetCurZ(float curZ); void PushTransform(const UITransform &transform); @@ -106,6 +108,9 @@ public: screenTag_ = tag; } + // TODO: Move to private. + const UI::Theme *theme; + private: Draw::DrawContext *draw_ = nullptr; Bounds bounds_; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index a6197af965..2571e2fd23 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1392,30 +1392,6 @@ void EmuScreen::render() { if (!thin3d) return; // shouldn't really happen but I've seen a suspicious stack trace.. - // We can still render behind the pause screen. - bool paused = screenManager()->topScreen() != this; - - if (paused && screenManager()->topScreen()->isTransparent()) { - // If we're paused and PauseScreen is transparent (will only be in buffered rendering mode), we just copy display to output. - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Paused"); - if (PSP_IsInited()) { - gpu->CheckDisplayResized(); - gpu->CopyDisplayToOutput(true); - } - - screenManager()->getUIContext()->BeginFrame(); - DrawContext *draw = screenManager()->getDrawContext(); - Viewport viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = pixel_xres; - viewport.Height = pixel_yres; - viewport.MaxDepth = 1.0; - viewport.MinDepth = 0.0; - draw->SetViewports(1, &viewport); - return; - } - if (invalid_) { // Loading, or after shutdown? if (loadingTextView_->GetVisibility() == UI::V_VISIBLE) diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 7d5421d0ec..f26562157e 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -43,6 +43,7 @@ #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/HLE/sceUtility.h" #include "GPU/GPUState.h" +#include "GPU/GPUInterface.h" #include "GPU/Common/PostShader.h" #include "UI/ControlMappingScreen.h" @@ -355,7 +356,33 @@ void DrawBackground(UIContext &dc, float alpha, float x, float y, float z) { } } -void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z) { +void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z, bool darkenGame) { + using namespace Draw; + using namespace UI; + + if (PSP_IsInited() && !g_Config.bSkipBufferEffects) { + gpu->CheckDisplayResized(); + gpu->CopyDisplayToOutput(true); + + DrawContext *draw = dc.GetDrawContext(); + Viewport viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = pixel_xres; + viewport.Height = pixel_yres; + viewport.MaxDepth = 1.0; + viewport.MinDepth = 0.0; + draw->SetViewports(1, &viewport); + dc.BeginFrame(); + dc.RebindTexture(); + dc.Begin(); + + uint32_t color = colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.45f); + dc.FillRect(UI::Drawable(color), dc.GetBounds()); + dc.Flush(); + return; + } + std::shared_ptr ginfo; if (!gamePath.empty()) ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath, GAMEINFO_WANTBG); @@ -427,7 +454,7 @@ void UIScreenWithGameBackground::DrawBackground(UIContext &dc) { float x, y, z; screenManager()->getFocusPosition(x, y, z); if (!gamePath_.empty()) { - DrawGameBackground(dc, gamePath_, x, y, z); + DrawGameBackground(dc, gamePath_, x, y, z, darkenGameBackground_); } else { ::DrawBackground(dc, 1.0f, x, y, z); dc.Flush(); @@ -443,9 +470,11 @@ void UIScreenWithGameBackground::sendMessage(const char *message, const char *va } void UIDialogScreenWithGameBackground::DrawBackground(UIContext &dc) { + using namespace UI; + using namespace Draw; float x, y, z; screenManager()->getFocusPosition(x, y, z); - DrawGameBackground(dc, gamePath_, x, y, z); + DrawGameBackground(dc, gamePath_, x, y, z, true); } void UIDialogScreenWithGameBackground::sendMessage(const char *message, const char *value) { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index e799c20828..216def14f7 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -51,6 +51,8 @@ public: void sendMessage(const char *message, const char *value) override; protected: Path gamePath_; + + bool darkenGameBackground_ = false; }; class UIDialogScreenWithBackground : public UIDialogScreen { diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 68f55bcc40..929e0d1d7d 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -256,24 +256,6 @@ GamePauseScreen::~GamePauseScreen() { __DisplaySetWasPaused(); } -bool GamePauseScreen::isTransparent() const { - // We don't support transparent pause screen in skipbuffereffects mode. - return !g_Config.bSkipBufferEffects && !IsVREnabled(); -} - -void GamePauseScreen::DrawBackground(UIContext &dc) { - if (isTransparent()) { - // Darken the game screen coming from below, so the UI on top stands out. - dc.Flush(); - uint32_t color = blackAlpha(0.45f); - dc.FillRect(UI::Drawable(color), dc.GetBounds()); - dc.Flush(); - return; - } - - UIDialogScreenWithGameBackground::DrawBackground(dc); -} - void GamePauseScreen::CreateViews() { static const int NUM_SAVESLOTS = 5; diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index c4180bdd9f..1d54db7916 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -44,9 +44,6 @@ protected: void update() override; void CallbackDeleteConfig(bool yes); - bool isTransparent() const override; - void DrawBackground(UIContext &dc) override; - private: UI::EventReturn OnGameSettings(UI::EventParams &e); UI::EventReturn OnExitToMenu(UI::EventParams &e); From b80df6c36001ce8165a22813eef266d123cd099a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Nov 2022 14:16:24 +0100 Subject: [PATCH 352/715] Add transparent background to the existing Display Layout Editor. --- UI/DisplayLayoutScreen.cpp | 5 ++++- UI/DisplayLayoutScreen.h | 5 ++--- UI/EmuScreen.cpp | 2 +- UI/GameSettingsScreen.cpp | 10 ++++------ UI/GameSettingsScreen.h | 1 - UI/MiscScreens.cpp | 4 ++-- UI/MiscScreens.h | 1 + UI/PauseScreen.cpp | 9 +++++++++ 8 files changed, 23 insertions(+), 14 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index e2ea500884..881eb9b262 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -90,9 +90,12 @@ std::string DragDropDisplay::DescribeText() const { return u->T("Screen representation"); } -DisplayLayoutScreen::DisplayLayoutScreen() { +DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) { // Ignore insets - just couldn't get the logic to work. ignoreInsets_ = true; + + // Show background at full brightness + darkenGameBackground_ = false; } bool DisplayLayoutScreen::touch(const TouchInput &touch) { diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 06730742d4..6fc613f574 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -23,9 +23,9 @@ class DragDropDisplay; -class DisplayLayoutScreen : public UIDialogScreenWithBackground { +class DisplayLayoutScreen : public UIDialogScreenWithGameBackground { public: - DisplayLayoutScreen(); + DisplayLayoutScreen(const Path &filename); virtual void CreateViews() override; virtual bool touch(const TouchInput &touch) override; virtual void dialogFinished(const Screen *dialog, DialogResult result) override; @@ -49,5 +49,4 @@ private: float startScale_ = 1.0f; int offsetTouchX_ = 0; int offsetTouchY_ = 0; - }; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 2571e2fd23..a0b898663c 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -489,7 +489,7 @@ void EmuScreen::sendMessage(const char *message, const char *value) { screenManager()->push(new ControlMappingScreen()); } else if (!strcmp(message, "display layout editor") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); - screenManager()->push(new DisplayLayoutScreen()); + screenManager()->push(new DisplayLayoutScreen(gamePath_)); } else if (!strcmp(message, "settings") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); screenManager()->push(new GameSettingsScreen(gamePath_)); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index d3d2e60202..f22627e100 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -463,7 +463,10 @@ void GameSettingsScreen::CreateViews() { #endif // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor"))); - displayEditor_->OnClick.Handle(this, &GameSettingsScreen::OnDisplayLayoutEditor); + displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + screenManager()->push(new DisplayLayoutScreen(gamePath_)); + return UI::EVENT_DONE; + }); #if PPSSPP_PLATFORM(ANDROID) // Hide insets option if no insets, or OS too old. @@ -1332,11 +1335,6 @@ UI::EventReturn GameSettingsScreen::OnFullscreenMultiChange(UI::EventParams &e) return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnDisplayLayoutEditor(UI::EventParams &e) { - screenManager()->push(new DisplayLayoutScreen()); - return UI::EVENT_DONE; -}; - UI::EventReturn GameSettingsScreen::OnResolutionChange(UI::EventParams &e) { if (g_Config.iAndroidHwScale == 1) { RecreateActivity(); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 2fd7d6e59d..5dbe9a682f 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -105,7 +105,6 @@ private: UI::EventReturn OnChangeBackground(UI::EventParams &e); UI::EventReturn OnFullscreenChange(UI::EventParams &e); UI::EventReturn OnFullscreenMultiChange(UI::EventParams &e); - UI::EventReturn OnDisplayLayoutEditor(UI::EventParams &e); UI::EventReturn OnResolutionChange(UI::EventParams &e); UI::EventReturn OnHwScaleChange(UI::EventParams &e); UI::EventReturn OnRestoreDefaultSettings(UI::EventParams &e); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index f26562157e..487effe1b4 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -419,7 +419,7 @@ void HandleCommonMessages(const char *message, const char *value, ScreenManager manager->push(new ControlMappingScreen()); } else if (!strcmp(message, "display layout editor") && isActiveScreen && std::string(activeScreen->tag()) != "DisplayLayout") { UpdateUIState(UISTATE_MENU); - manager->push(new DisplayLayoutScreen()); + manager->push(new DisplayLayoutScreen(Path())); } else if (!strcmp(message, "settings") && isActiveScreen && std::string(activeScreen->tag()) != "GameSettings") { UpdateUIState(UISTATE_MENU); manager->push(new GameSettingsScreen(Path())); @@ -474,7 +474,7 @@ void UIDialogScreenWithGameBackground::DrawBackground(UIContext &dc) { using namespace Draw; float x, y, z; screenManager()->getFocusPosition(x, y, z); - DrawGameBackground(dc, gamePath_, x, y, z, true); + DrawGameBackground(dc, gamePath_, x, y, z, darkenGameBackground_); } void UIDialogScreenWithGameBackground::sendMessage(const char *message, const char *value) { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 216def14f7..2790f85c37 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -73,6 +73,7 @@ public: void sendMessage(const char *message, const char *value) override; protected: Path gamePath_; + bool darkenGameBackground_ = true; }; class PromptScreen : public UIDialogScreenWithBackground { diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 929e0d1d7d..c45d6b7920 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -49,6 +49,7 @@ #include "UI/MainScreen.h" #include "UI/OnScreenDisplay.h" #include "UI/GameInfoCache.h" +#include "UI/DisplayLayoutScreen.h" static void AfterSaveStateAction(SaveState::Status status, const std::string &message, void *) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { @@ -260,6 +261,7 @@ void GamePauseScreen::CreateViews() { static const int NUM_SAVESLOTS = 5; using namespace UI; + Margins scrollMargins(0, 20, 0, 0); Margins actionMenuMargins(0, 20, 15, 0); auto gr = GetI18NCategory("Graphics"); @@ -314,6 +316,8 @@ void GamePauseScreen::CreateViews() { root_->SetDefaultFocusView(continueChoice); continueChoice->OnClick.Handle(this, &UIScreen::OnBack); + rightColumnItems->Add(new Spacer(25.0)); + std::string gameId = g_paramSFO.GetDiscID(); if (g_Config.hasGameConfig(gameId)) { rightColumnItems->Add(new Choice(pa->T("Game Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); @@ -322,6 +326,11 @@ void GamePauseScreen::CreateViews() { rightColumnItems->Add(new Choice(pa->T("Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); rightColumnItems->Add(new Choice(pa->T("Create Game Config")))->OnClick.Handle(this, &GamePauseScreen::OnCreateConfig); } + UI::Choice *displayEditor_ = rightColumnItems->Add(new Choice(gr->T("Display layout editor"))); + displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + screenManager()->push(new DisplayLayoutScreen(gamePath_)); + return UI::EVENT_DONE; + }); if (g_Config.bEnableCheats) { rightColumnItems->Add(new Choice(pa->T("Cheats")))->OnClick.Handle(this, &GamePauseScreen::OnCwCheat); } From 59046b8f764f4acb1519926c9d1519fb6fca13cb Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 22 Nov 2022 18:51:42 +0100 Subject: [PATCH 353/715] OpenXR - 2D stereo condition fixed --- Common/VR/PPSSPPVR.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 77fcb64fb7..49d05c834f 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -643,14 +643,12 @@ bool StartVRRender() { } // Decide if the scene is 3D or not + bool stereo = hasUnitScale && g_Config.bEnableStereo; VR_SetConfigFloat(VR_CONFIG_CANVAS_ASPECT, 480.0f / 272.0f); - if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { - VR_SetConfig(VR_CONFIG_MODE, VR_MODE_MONO_SCREEN); - } else if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (vr3DGeometryCount > 15)) { - bool stereo = hasUnitScale && g_Config.bEnableStereo; + if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (appMode == VR_GAME_MODE) && (vr3DGeometryCount > 15)) { VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); } else { - VR_SetConfig(VR_CONFIG_MODE, g_Config.bEnableStereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); + VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); } vr3DGeometryCount /= 2; From 57864f62cea12a07375b47b96409538c5cb359a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Nov 2022 17:45:17 +0100 Subject: [PATCH 354/715] Rework the display layout editor to ditch the preview thing. We lose the snapping in the refactor because I ended up rewriting the whole dragging mechanism, might reintroduce later. --- CMakeLists.txt | 2 - UI/DisplayLayoutEditor.cpp | 58 ------- UI/DisplayLayoutEditor.h | 53 ------- UI/DisplayLayoutScreen.cpp | 256 +++++++++--------------------- UI/DisplayLayoutScreen.h | 29 ++-- UI/MiscScreens.cpp | 12 +- UI/UI.vcxproj | 2 - UI/UI.vcxproj.filters | 2 - UWP/UI_UWP/UI_UWP.vcxproj | 2 - UWP/UI_UWP/UI_UWP.vcxproj.filters | 2 - android/jni/Android.mk | 1 - 11 files changed, 95 insertions(+), 324 deletions(-) delete mode 100644 UI/DisplayLayoutEditor.cpp delete mode 100644 UI/DisplayLayoutEditor.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ac021cf474..2072a5d003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1247,8 +1247,6 @@ list(APPEND NativeAppSource UI/ChatScreen.cpp UI/DevScreens.cpp UI/DevScreens.h - UI/DisplayLayoutEditor.cpp - UI/DisplayLayoutEditor.h UI/DisplayLayoutScreen.cpp UI/DisplayLayoutScreen.h UI/EmuScreen.h diff --git a/UI/DisplayLayoutEditor.cpp b/UI/DisplayLayoutEditor.cpp deleted file mode 100644 index f6556ca39a..0000000000 --- a/UI/DisplayLayoutEditor.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include - -#include "Common/UI/Context.h" -#include "UI/DisplayLayoutEditor.h" - -void MultiTouchDisplay::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(img_); - if (image) { - w = image->w * scale_; - h = image->h * scale_; - } else { - w = 0.0f; - h = 0.0f; - } -} - -void MultiTouchDisplay::Touch(const TouchInput &input) { - if ((input.flags & TOUCH_DOWN) && bounds_.Contains(input.x, input.y)) { - pointerDownMask_ |= 1 << input.id; - } - if (input.flags & TOUCH_MOVE) { - if (bounds_.Contains(input.x, input.y)) - pointerDownMask_ |= 1 << input.id; - else - pointerDownMask_ &= ~(1 << input.id); - } - if (input.flags & TOUCH_UP) { - pointerDownMask_ &= ~(1 << input.id); - } - if (input.flags & TOUCH_RELEASE_ALL) { - pointerDownMask_ = 0; - } -} - - -void MultiTouchDisplay::Draw(UIContext &dc) { - float opacity = 0.5f; - float scale = scale_; - uint32_t color = colorAlpha(0xFFFFFF, opacity); - dc.Draw()->DrawImageRotated(img_, bounds_.centerX(), bounds_.centerY(), scale, angle_ * (M_PI * 2 / 360.0f), color, flipImageH_); -} diff --git a/UI/DisplayLayoutEditor.h b/UI/DisplayLayoutEditor.h deleted file mode 100644 index 6855c127ca..0000000000 --- a/UI/DisplayLayoutEditor.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "Common/Render/TextureAtlas.h" -#include "Common/Render/DrawBuffer.h" -#include "Common/UI/View.h" -#include "Common/UI/ViewGroup.h" - -class MultiTouchDisplay : public UI::View { -public: - MultiTouchDisplay(ImageID img, float scale, UI::LayoutParams *layoutParams) - : UI::View(layoutParams), pointerDownMask_(0), scale_(scale), img_(img), angle_(0.0f), flipImageH_(false) { - } - virtual void Touch(const TouchInput &input) override; - virtual void Draw(UIContext &dc) override; - virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; - // chainable - MultiTouchDisplay *FlipImageH(bool flip) { flipImageH_ = flip; return this; } - MultiTouchDisplay *SetAngle(float angle) { angle_ = angle; return this; } - -protected: - uint32_t pointerDownMask_; - float scale_; - -private: - ImageID img_; - float angle_; - bool flipImageH_; -}; - -class PSPDisplay : public MultiTouchDisplay { -public: - PSPDisplay(ImageID img, float scale, UI::LayoutParams *layoutParams) - : MultiTouchDisplay(img, scale, layoutParams) { - } -}; - diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 881eb9b262..de32079916 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -23,6 +23,8 @@ #include "Common/Render/DrawBuffer.h" #include "Common/UI/Context.h" #include "Common/UI/View.h" +#include "Common/Math/math_util.h" +#include "Common/System/Display.h" #include "Common/Data/Color/RGBAUtil.h" #include "Common/Data/Text/I18n.h" @@ -30,64 +32,24 @@ #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" -#include "DisplayLayoutEditor.h" #include "GPU/Common/FramebufferManagerCommon.h" +#include "GPU/Common/PresentationCommon.h" static const int leftColumnWidth = 200; -static const float orgRatio = 1.764706f; +static const float orgRatio = 1.764706f; // 480.0 / 272.0 -static const float UI_DISPLAY_SCALE = 8.0f; -static float ScaleSettingToUI() { - float scale = g_Config.fSmallDisplayZoomLevel * UI_DISPLAY_SCALE; - // Account for 1x display doubling dps. - if (g_dpi_scale_x > 1.0f) { - scale *= g_dpi_scale_x; - } - return scale; -} - -static void UpdateScaleSetting(float scale) { - // Account for 1x display doubling dps. - if (g_dpi_scale_x > 1.0f) { - scale /= g_dpi_scale_x; - } - g_Config.fSmallDisplayZoomLevel = scale; -} - -static void UpdateScaleSettingFromUI(float scale) { - UpdateScaleSetting(scale / UI_DISPLAY_SCALE); -} - -class DragDropDisplay : public MultiTouchDisplay { -public: - DragDropDisplay(float &x, float &y, ImageID img, float scale, const Bounds &screenBounds) - : MultiTouchDisplay(img, scale, new UI::AnchorLayoutParams(x * screenBounds.w, y * screenBounds.h, UI::NONE, UI::NONE, true)), - x_(x), y_(y), screenBounds_(screenBounds) { - UpdateScale(scale); - } - - std::string DescribeText() const override; - - void SaveDisplayPosition() { - x_ = bounds_.centerX() / screenBounds_.w; - y_ = bounds_.centerY() / screenBounds_.h; - } - - void UpdateScale(float s) { - scale_ = s; - } - float Scale() { - return scale_; - } - -private: - float &x_, &y_; - const Bounds &screenBounds_; +enum Mode { + MODE_MOVE, + MODE_RESIZE, }; -std::string DragDropDisplay::DescribeText() const { - auto u = GetI18NCategory("UI Elements"); - return u->T("Screen representation"); +static Bounds FRectToBounds(FRect rc) { + Bounds b; + b.x = rc.x * g_dpi_scale_x; + b.y = rc.y * g_dpi_scale_y; + b.w = rc.w * g_dpi_scale_x; + b.h = rc.h * g_dpi_scale_y; + return b; } DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) { @@ -98,6 +60,25 @@ DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenW darkenGameBackground_ = false; } +void DisplayLayoutScreen::DrawBackground(UIContext &dc) { + if (PSP_IsInited() && !g_Config.bSkipBufferEffects) { + // We normally rely on the PSP screen. + UIDialogScreenWithGameBackground::DrawBackground(dc); + } else { + // But if it's not present (we're not in game, or skip buffer effects is used), + // we have to draw a substitute ourselves. + + // TODO: Clean this up a bit, this GetScreenFrame/CenterDisplay combo is too common. + FRect screenFrame = GetScreenFrame(pixel_xres, pixel_yres); + FRect rc; + CenterDisplayOutputRect(&rc, 480.0f, 272.0f, screenFrame, g_Config.iInternalScreenRotation); + + dc.Flush(); + ImageID bg = ImageID("I_PSP_DISPLAY"); + dc.Draw()->DrawImageStretch(bg, FRectToBounds(rc), 0x7FFFFFFF); + } +} + bool DisplayLayoutScreen::touch(const TouchInput &touch) { UIScreen::touch(touch); @@ -108,89 +89,42 @@ bool DisplayLayoutScreen::touch(const TouchInput &touch) { mode = -1; } - const Bounds &screen_bounds = screenManager()->getUIContext()->GetBounds(); + const Bounds &screenBounds = screenManager()->getUIContext()->GetBounds(); if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { - int touchX = touch.x - offsetTouchX_; - int touchY = touch.y - offsetTouchY_; - if (mode == 0) { - const auto &prevParams = displayRepresentation_->GetLayoutParams()->As(); - Point newPos(prevParams->left, prevParams->top); + float relativeTouchX = touch.x - startX_; + float relativeTouchY = touch.y - startY_; - int limitX = g_Config.fSmallDisplayZoomLevel * 120; - int limitY = g_Config.fSmallDisplayZoomLevel * 68; - - const int quarterResX = screen_bounds.w / 4; - const int quarterResY = screen_bounds.h / 4; - - if (bRotated_) { - //swap X/Y limit for rotated display - std::swap(limitX, limitY); - } - - // Check where each edge of the screen is - const int windowLeftEdge = quarterResX; - const int windowRightEdge = windowLeftEdge * 3; - const int windowUpperEdge = quarterResY; - const int windowLowerEdge = windowUpperEdge * 3; - // And stick display when close to any edge - stickToEdgeX_ = false; - stickToEdgeY_ = false; - if (touchX > windowLeftEdge - 8 + limitX && touchX < windowLeftEdge + 8 + limitX) { touchX = windowLeftEdge + limitX; stickToEdgeX_ = true; } - if (touchX > windowRightEdge - 8 - limitX && touchX < windowRightEdge + 8 - limitX) { touchX = windowRightEdge - limitX; stickToEdgeX_ = true; } - if (touchY > windowUpperEdge - 8 + limitY && touchY < windowUpperEdge + 8 + limitY) { touchY = windowUpperEdge + limitY; stickToEdgeY_ = true; } - if (touchY > windowLowerEdge - 8 - limitY && touchY < windowLowerEdge + 8 - limitY) { touchY = windowLowerEdge - limitY; stickToEdgeY_ = true; } - - const int minX = screen_bounds.w / 2; - const int maxX = screen_bounds.w + minX; - const int minY = screen_bounds.h / 2; - const int maxY = screen_bounds.h + minY; - // Display visualization disappear outside of those bounds, so we have to limit - if (touchX < -minX) touchX = -minX; - if (touchX > maxX) touchX = maxX; - if (touchY < -minY) touchY = -minY; - if (touchY > maxY) touchY = maxY; - - // Limit small display on much larger output a bit differently - if (quarterResX > limitX) limitX = quarterResX; - if (quarterResY > limitY) limitY = quarterResY; - - // Allow moving zoomed in display freely as long as at least noticeable portion of the screen is occupied - if (touchX > minX - limitX - 10 && touchX < minX + limitX + 10) { - newPos.x = touchX; - } - if (touchY > minY - limitY - 10 && touchY < minY + limitY + 10) { - newPos.y = touchY; - } - displayRepresentation_->ReplaceLayoutParams(new AnchorLayoutParams(newPos.x, newPos.y, NONE, NONE, true)); - } else if (mode == 1) { + switch (mode) { + case MODE_MOVE: + { + g_Config.fSmallDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX * 0.5f / screenBounds.w; + g_Config.fSmallDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY * 0.5f / screenBounds.h; + break; + } + case MODE_RESIZE: + { // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction - float diffY = -(touchY - startY_); - - float movementScale = 0.5f; - float newScale = startScale_ + diffY * movementScale; - // Desired scale * 8.0 since the visualization is tiny size and multiplied by 8. - newScale = clamp_value(newScale, UI_DISPLAY_SCALE, UI_DISPLAY_SCALE * 10.0f); - displayRepresentation_->UpdateScale(newScale); - UpdateScaleSettingFromUI(newScale); + float diffYProp = -relativeTouchY * 0.007f; + g_Config.fSmallDisplayZoomLevel = startScale_ * powf(2.0f, diffYProp); + break; + } } } + if ((touch.flags & TOUCH_DOWN) != 0 && !dragging_) { dragging_ = true; - const Bounds &bounds = displayRepresentation_->GetBounds(); - startY_ = bounds.centerY(); - offsetTouchX_ = touch.x - bounds.centerX(); - offsetTouchY_ = touch.y - bounds.centerY(); - startScale_ = displayRepresentation_->Scale(); + startX_ = touch.x; + startY_ = touch.y; + startDisplayOffsetX_ = g_Config.fSmallDisplayOffsetX; + startDisplayOffsetY_ = g_Config.fSmallDisplayOffsetY; + startScale_ = g_Config.fSmallDisplayZoomLevel; } + if ((touch.flags & TOUCH_UP) != 0 && dragging_) { - displayRepresentation_->SaveDisplayPosition(); dragging_ = false; } - return true; -} -void DisplayLayoutScreen::resized() { - RecreateViews(); + return true; } void DisplayLayoutScreen::onFinish(DialogResult reason) { @@ -198,22 +132,23 @@ void DisplayLayoutScreen::onFinish(DialogResult reason) { } UI::EventReturn DisplayLayoutScreen::OnCenter(UI::EventParams &e) { - if (!stickToEdgeX_ || (stickToEdgeX_ && stickToEdgeY_)) - g_Config.fSmallDisplayOffsetX = 0.5f; - if (!stickToEdgeY_ || (stickToEdgeX_ && stickToEdgeY_)) - g_Config.fSmallDisplayOffsetY = 0.5f; + g_Config.fSmallDisplayOffsetX = 0.5f; + g_Config.fSmallDisplayOffsetY = 0.5f; RecreateViews(); return UI::EVENT_DONE; }; UI::EventReturn DisplayLayoutScreen::OnZoomTypeChange(UI::EventParams &e) { - if (g_Config.iSmallDisplayZoomType < (int)SmallDisplayZoom::MANUAL) { - const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); - float autoBound = bounds.w / 480.0f; - UpdateScaleSetting(autoBound); - displayRepresentation_->UpdateScale(ScaleSettingToUI()); + switch (g_Config.iSmallDisplayZoomType) { + case (int)SmallDisplayZoom::AUTO: + case (int)SmallDisplayZoom::PARTIAL_STRETCH: + case (int)SmallDisplayZoom::STRETCH: g_Config.fSmallDisplayOffsetX = 0.5f; g_Config.fSmallDisplayOffsetY = 0.5f; + break; + default: + // Not SmallDisplayZoom::MANUAL + break; } RecreateViews(); return UI::EVENT_DONE; @@ -223,20 +158,6 @@ void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult resu RecreateViews(); } -class Boundary : public UI::View { -public: - Boundary(UI::LayoutParams *layoutParams) : UI::View(layoutParams) { - } - - std::string DescribeText() const override { - return ""; - } - - void Draw(UIContext &dc) override { - dc.Draw()->DrawImageCenterTexel(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), dc.theme->itemDownStyle.background.color); - } -}; - // Stealing StickyChoice's layout and text rendering. class HighlightLabel : public UI::StickyChoice { public: @@ -259,25 +180,9 @@ void DisplayLayoutScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - const float previewWidth = bounds.w / 2.0f; - const float previewHeight = bounds.h / 2.0f; - - // Just visual boundaries of the screen, should be easier to use than imagination - const float horizPreviewPadding = bounds.w / 4.0f; - const float vertPreviewPadding = bounds.h / 4.0f; - const float horizBoundariesWidth = 4.0f; - // This makes it have at least 10.0f padding below at 1x. - const float vertBoundariesHeight = 52.0f; - // We manually implement insets here for the buttons. This file defied refactoring :( float leftInset = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT); - // Left side, right, top, bottom. - root_->Add(new Boundary(new AnchorLayoutParams(horizBoundariesWidth, FILL_PARENT, horizPreviewPadding - horizBoundariesWidth, 0, NONE, 0))); - root_->Add(new Boundary(new AnchorLayoutParams(horizBoundariesWidth, FILL_PARENT, horizPreviewPadding + previewWidth, 0, NONE, 0))); - root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding - vertBoundariesHeight, NONE, NONE))); - root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding + previewHeight, NONE, NONE))); - bool displayRotEnable = !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; bRotated_ = false; if (displayRotEnable && (g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180)) { @@ -305,7 +210,7 @@ void DisplayLayoutScreen::CreateViews() { } } } - UpdateScaleSetting(autoBound); + g_Config.fSmallDisplayZoomLevel = autoBound; g_Config.fSmallDisplayOffsetX = 0.5f; g_Config.fSmallDisplayOffsetY = 0.5f; } else { // Manual Scaling @@ -323,19 +228,11 @@ void DisplayLayoutScreen::CreateViews() { mode_->AddChoice(di->T("Resize")); mode_->SetSelection(0, false); } - displayRepresentation_ = new DragDropDisplay(g_Config.fSmallDisplayOffsetX, g_Config.fSmallDisplayOffsetY, ImageID("I_PSP_DISPLAY"), ScaleSettingToUI(), bounds); - displayRepresentation_->SetVisibility(V_VISIBLE); } else { // Stretching label = new HighlightLabel(gr->T("Stretching"), new AnchorLayoutParams(WRAP_CONTENT, 64.0f, bounds.w / 2.0f, bounds.h / 2.0f, NONE, NONE, true)); - displayRepresentation_ = new DragDropDisplay(g_Config.fSmallDisplayOffsetX, g_Config.fSmallDisplayOffsetY, ImageID("I_PSP_DISPLAY"), ScaleSettingToUI(), bounds); - displayRepresentation_->SetVisibility(V_INVISIBLE); - float width = previewWidth; - float height = previewHeight; - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::STRETCH) { - Choice *stretched = new Choice("", "", false, new AnchorLayoutParams(width, height, width - width / 2.0f, NONE, NONE, height - height / 2.0f)); - stretched->SetEnabled(false); - root_->Add(stretched); - } else { // Partially stretched + float width = bounds.w; + float height = bounds.h; + if (g_Config.iSmallDisplayZoomType != (int)SmallDisplayZoom::STRETCH) { float origRatio = !bRotated_ ? 480.0f / 272.0f : 272.0f / 480.0f; float frameRatio = width / height; if (origRatio > frameRatio) { @@ -349,16 +246,9 @@ void DisplayLayoutScreen::CreateViews() { width = (272.0f + height) / 2.0f; } } - Choice *stretched = new Choice("", "", false, new AnchorLayoutParams(width, height, previewWidth - width / 2.0f, NONE, NONE, previewHeight - height / 2.0f)); - stretched->SetEnabled(false); - root_->Add(stretched); } } - if (bRotated_) { - displayRepresentation_->SetAngle(90.0f); - } - root_->Add(displayRepresentation_); if (mode_) { root_->Add(mode_); } @@ -367,12 +257,12 @@ void DisplayLayoutScreen::CreateViews() { } static const char *zoomLevels[] = { "Stretching", "Partial Stretch", "Auto Scaling", "Manual Scaling" }; - auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, di->T("Options"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, previewWidth - 200.0f, NONE, NONE, 10)); + auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, di->T("Options"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, NONE, NONE, 10)); zoom->OnChoice.Handle(this, &DisplayLayoutScreen::OnZoomTypeChange); root_->Add(zoom); static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; - auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, previewWidth - 200.0f, 10, NONE, bounds.h - 64 - 10)); + auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, 10, NONE, bounds.h - 64 - 10)); rotation->SetEnabledFunc([] { return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; }); diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 6fc613f574..acf4cc51c8 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -21,16 +21,20 @@ #include "Common/UI/ViewGroup.h" #include "MiscScreens.h" -class DragDropDisplay; - class DisplayLayoutScreen : public UIDialogScreenWithGameBackground { public: DisplayLayoutScreen(const Path &filename); - virtual void CreateViews() override; - virtual bool touch(const TouchInput &touch) override; - virtual void dialogFinished(const Screen *dialog, DialogResult result) override; - virtual void onFinish(DialogResult reason) override; - virtual void resized() override; + void CreateViews() override; + bool touch(const TouchInput &touch) override; + void dialogFinished(const Screen *dialog, DialogResult result) override; + void onFinish(DialogResult reason) override; + + void DrawBackground(UIContext &dc) override; + + void resized() override { + RecreateViews(); + } + const char *tag() const override { return "DisplayLayout"; } protected: @@ -38,15 +42,14 @@ protected: virtual UI::EventReturn OnZoomTypeChange(UI::EventParams &e); private: - DragDropDisplay *displayRepresentation_ = nullptr; UI::ChoiceStrip *mode_ = nullptr; bool dragging_ = false; bool bRotated_ = false; - bool stickToEdgeX_ = false; - bool stickToEdgeY_ = false; + // Touch down state for drag to resize etc + float startX_ = 0.0f; float startY_ = 0.0f; - float startScale_ = 1.0f; - int offsetTouchX_ = 0; - int offsetTouchY_ = 0; + float startScale_ = -1.0f; + float startDisplayOffsetX_ = -1.0f; + float startDisplayOffsetY_ = -1.0f; }; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 487effe1b4..0516286f5d 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -356,7 +356,7 @@ void DrawBackground(UIContext &dc, float alpha, float x, float y, float z) { } } -void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z, bool darkenGame) { +void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z, bool darkenBackground) { using namespace Draw; using namespace UI; @@ -377,9 +377,11 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f dc.RebindTexture(); dc.Begin(); - uint32_t color = colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.45f); - dc.FillRect(UI::Drawable(color), dc.GetBounds()); - dc.Flush(); + if (darkenBackground) { + uint32_t color = colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.45f); + dc.FillRect(UI::Drawable(color), dc.GetBounds()); + dc.Flush(); + } return; } @@ -391,8 +393,6 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f GameInfoTex *pic = ginfo ? ginfo->GetBGPic() : nullptr; if (pic) { dc.GetDrawContext()->BindTexture(0, pic->texture->GetTexture()); - } - if (pic) { uint32_t color = whiteAlpha(ease((time_now_d() - pic->timeLoaded) * 3)) & 0xFFc0c0c0; dc.Draw()->DrawTexRect(dc.GetBounds(), 0,0,1,1, color); dc.Flush(); diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index edf77d026e..df884f757b 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -42,7 +42,6 @@ - @@ -75,7 +74,6 @@ - diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 3f03e3242f..3743fe242f 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -63,7 +63,6 @@ Screens - Screens @@ -144,7 +143,6 @@ Screens - Screens diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index 57358dde23..e2698447e0 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -386,7 +386,6 @@ - @@ -422,7 +421,6 @@ - diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index fde9770206..e26481b823 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -8,7 +8,6 @@ - @@ -44,7 +43,6 @@ - diff --git a/android/jni/Android.mk b/android/jni/Android.mk index a8b6090dfe..2fc73c6168 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -689,7 +689,6 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/DiscordIntegration.cpp \ $(SRC)/UI/ChatScreen.cpp \ $(SRC)/UI/DevScreens.cpp \ - $(SRC)/UI/DisplayLayoutEditor.cpp \ $(SRC)/UI/DisplayLayoutScreen.cpp \ $(SRC)/UI/EmuScreen.cpp \ $(SRC)/UI/MainScreen.cpp \ From 70d30d1cf6366cde2c7cc8a89a7e10c19db06d96 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 22 Nov 2022 21:49:52 +0100 Subject: [PATCH 355/715] OpenXR - Aspect ratio of menu background fixed --- Common/VR/PPSSPPVR.cpp | 13 +++++++++++++ Common/VR/PPSSPPVR.h | 2 ++ GPU/Common/FramebufferManagerCommon.cpp | 16 ++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 49d05c834f..423b74bd27 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -42,6 +42,7 @@ static std::map pspKeys; static int vr3DGeometryCount = 0; static long vrCompat[VR_COMPAT_MAX]; +static bool vrFlatGame = false; static float vrMatrix[VR_MATRIX_COUNT][16]; static bool vrMirroring[VR_MIRRORING_COUNT]; @@ -647,8 +648,12 @@ bool StartVRRender() { VR_SetConfigFloat(VR_CONFIG_CANVAS_ASPECT, 480.0f / 272.0f); if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (appMode == VR_GAME_MODE) && (vr3DGeometryCount > 15)) { VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); + vrFlatGame = false; } else { VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); + if (IsGameVRScene()) { + vrFlatGame = true; + } } vr3DGeometryCount /= 2; @@ -693,11 +698,19 @@ bool IsMultiviewSupported() { return false; } +bool IsFlatVRGame() { + return vrFlatGame; +} + bool IsFlatVRScene() { int vrMode = VR_GetConfig(VR_CONFIG_MODE); return (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN); } +bool IsGameVRScene() { + return (appMode == VR_GAME_MODE) || (appMode == VR_DIALOG_MODE); +} + bool Is2DVRObject(float* projMatrix, bool ortho) { // Quick analyze if the object is in 2D diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 5b31cc7a7f..dec2daaffa 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -50,7 +50,9 @@ void PostVRFrameRender(); int GetVRFBOIndex(); int GetVRPassesCount(); bool IsMultiviewSupported(); +bool IsFlatVRGame(); bool IsFlatVRScene(); +bool IsGameVRScene(); bool Is2DVRObject(float* projMatrix, bool ortho); void UpdateVRParams(float* projMatrix, float* viewMatrix); void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 7a104bc515..e931b65461 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -27,6 +27,7 @@ #include "Common/Math/lin/matrix4x4.h" #include "Common/Math/math_util.h" #include "Common/System/Display.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/CommonTypes.h" #include "Common/StringUtils.h" #include "Core/Config.h" @@ -1452,6 +1453,21 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { float u1 = (480.0f + offsetX) / (float)vfb->bufferWidth; float v1 = (272.0f + offsetY) / (float)vfb->bufferHeight; + //clip the VR framebuffer to keep the aspect ratio + if (IsVREnabled() && !IsFlatVRGame() && !IsGameVRScene()) { + float aspect = 272.0f / 480.0f; + float clipY = 272.0f * (1.0f - aspect) / 2.0f; + v0 = (clipY + offsetY) / (float)vfb->bufferHeight; + v1 = (272.0f - clipY + offsetY) / (float)vfb->bufferHeight; + + //zoom inside + float zoom = 0.1f; + u0 += zoom / aspect; + u1 -= zoom / aspect; + v0 += zoom; + v1 -= zoom; + } + textureCache_->ForgetLastTexture(); int uvRotation = useBufferedRendering_ ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL; From 575560f6797e8a3abc6c45aa3428485ad7e260d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Nov 2022 22:53:54 +0100 Subject: [PATCH 356/715] Enable game backgrounds on more screens --- UI/ComboKeyMappingScreen.h | 4 ++-- UI/ControlMappingScreen.cpp | 12 ++++++------ UI/ControlMappingScreen.h | 18 +++++++++--------- UI/CwCheatScreen.cpp | 5 ++--- UI/CwCheatScreen.h | 3 +-- UI/DevScreens.cpp | 2 +- UI/DevScreens.h | 5 ++++- UI/EmuScreen.cpp | 4 ++-- UI/GameSettingsScreen.cpp | 12 ++++++------ UI/GameSettingsScreen.h | 7 +++++-- UI/MiscScreens.cpp | 2 +- UI/NativeApp.cpp | 2 +- UI/TouchControlLayoutScreen.cpp | 4 +--- UI/TouchControlLayoutScreen.h | 4 ++-- UI/TouchControlVisibilityScreen.cpp | 22 +++++++++++----------- UI/TouchControlVisibilityScreen.h | 6 ++++-- 16 files changed, 58 insertions(+), 54 deletions(-) diff --git a/UI/ComboKeyMappingScreen.h b/UI/ComboKeyMappingScreen.h index c2ed6396d8..54cc86607c 100644 --- a/UI/ComboKeyMappingScreen.h +++ b/UI/ComboKeyMappingScreen.h @@ -24,9 +24,9 @@ namespace UI { class CheckBox; } -class ComboKeyScreen : public UIDialogScreenWithBackground { +class ComboKeyScreen : public UIDialogScreenWithGameBackground { public: - ComboKeyScreen(int id): id_(id) {} + ComboKeyScreen(const Path &gamePath, int id) : UIDialogScreenWithGameBackground(gamePath), id_(id) {} const char *tag() const override { return "ComboKey"; } diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index b0f0651735..89b2fec756 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -279,7 +279,7 @@ void ControlMappingScreen::update() { RecreateViews(); } - UIDialogScreenWithBackground::update(); + UIDialogScreenWithGameBackground::update(); SetVRAppMode(VRAppMode::VR_MENU_MODE); } @@ -309,7 +309,7 @@ UI::EventReturn ControlMappingScreen::OnAutoConfigure(UI::EventParams ¶ms) { } UI::EventReturn ControlMappingScreen::OnVisualizeMapping(UI::EventParams ¶ms) { - VisualMappingScreen *visualMapping = new VisualMappingScreen(); + VisualMappingScreen *visualMapping = new VisualMappingScreen(gamePath_); screenManager()->push(visualMapping); return UI::EVENT_DONE; } @@ -581,7 +581,7 @@ void JoystickHistoryView::Update() { } } -AnalogSetupScreen::AnalogSetupScreen() { +AnalogSetupScreen::AnalogSetupScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { mapper_.SetCallbacks([](int vkey) {}, [](int vkey) {}, [&](int stick, float x, float y) { analogX_[stick] = x; analogY_[stick] = y; @@ -673,7 +673,7 @@ UI::EventReturn AnalogSetupScreen::OnResetToDefaults(UI::EventParams &e) { } bool TouchTestScreen::touch(const TouchInput &touch) { - UIDialogScreenWithBackground::touch(touch); + UIDialogScreenWithGameBackground::touch(touch); if (touch.flags & TOUCH_DOWN) { bool found = false; for (int i = 0; i < MAX_TOUCH_POINTS; i++) { @@ -802,7 +802,7 @@ bool TouchTestScreen::axis(const AxisInput &axis) { } void TouchTestScreen::render() { - UIDialogScreenWithBackground::render(); + UIDialogScreenWithGameBackground::render(); UIContext *ui_context = screenManager()->getUIContext(); Bounds bounds = ui_context->GetLayoutBounds(); @@ -1161,7 +1161,7 @@ void VisualMappingScreen::CreateViews() { } void VisualMappingScreen::resized() { - UIDialogScreenWithBackground::resized(); + UIDialogScreenWithGameBackground::resized(); RecreateViews(); } diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index 29f1360fbe..dfb3e81ff5 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -32,9 +32,9 @@ class SingleControlMapper; -class ControlMappingScreen : public UIDialogScreenWithBackground { +class ControlMappingScreen : public UIDialogScreenWithGameBackground { public: - ControlMappingScreen() {} + ControlMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} const char *tag() const override { return "ControlMapping"; } protected: @@ -84,7 +84,7 @@ private: class KeyMappingNewMouseKeyDialog : public PopupScreen { public: - explicit KeyMappingNewMouseKeyDialog(int btn, bool replace, std::function callback, std::shared_ptr i18n) + KeyMappingNewMouseKeyDialog(int btn, bool replace, std::function callback, std::shared_ptr i18n) : PopupScreen(i18n->T("Map Mouse"), "", ""), callback_(callback), mapped_(false) { pspBtn_ = btn; } @@ -109,9 +109,9 @@ private: class JoystickHistoryView; -class AnalogSetupScreen : public UIDialogScreenWithBackground { +class AnalogSetupScreen : public UIDialogScreenWithGameBackground { public: - AnalogSetupScreen(); + AnalogSetupScreen(const Path &gamePath); bool key(const KeyInput &key) override; bool axis(const AxisInput &axis) override; @@ -136,9 +136,9 @@ private: JoystickHistoryView *stickView_[2]{}; }; -class TouchTestScreen : public UIDialogScreenWithBackground { +class TouchTestScreen : public UIDialogScreenWithGameBackground { public: - TouchTestScreen() { + TouchTestScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { for (int i = 0; i < MAX_TOUCH_POINTS; i++) { touches_[i].id = -1; } @@ -175,9 +175,9 @@ protected: class MockPSP; -class VisualMappingScreen : public UIDialogScreenWithBackground { +class VisualMappingScreen : public UIDialogScreenWithGameBackground { public: - VisualMappingScreen() {} + VisualMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} const char *tag() const override { return "VisualMapping"; } diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index dee7a11166..cd6f052ab1 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -35,8 +35,7 @@ static const int FILE_CHECK_FRAME_INTERVAL = 53; CwCheatScreen::CwCheatScreen(const Path &gamePath) - : UIDialogScreenWithBackground() { - gamePath_ = gamePath; + : UIDialogScreenWithGameBackground(gamePath) { } CwCheatScreen::~CwCheatScreen() { @@ -129,7 +128,7 @@ void CwCheatScreen::update() { fileCheckCounter_ = 0; } - UIDialogScreenWithBackground::update(); + UIDialogScreenWithGameBackground::update(); } void CwCheatScreen::onFinish(DialogResult result) { diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index 27a28a1b51..b343cbd818 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -26,7 +26,7 @@ struct CheatFileInfo; class CWCheatEngine; -class CwCheatScreen : public UIDialogScreenWithBackground { +class CwCheatScreen : public UIDialogScreenWithGameBackground { public: CwCheatScreen(const Path &gamePath); ~CwCheatScreen(); @@ -56,7 +56,6 @@ private: UI::ScrollView *rightScroll_ = nullptr; CWCheatEngine *engine_ = nullptr; std::vector fileInfo_; - Path gamePath_; std::string gameID_; int fileCheckCounter_ = 0; uint64_t fileCheckHash_; diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 5dea5e0921..9d219eb1c8 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -147,7 +147,7 @@ UI::EventReturn DevMenuScreen::OnLogConfig(UI::EventParams &e) { UI::EventReturn DevMenuScreen::OnDeveloperTools(UI::EventParams &e) { UpdateUIState(UISTATE_PAUSEMENU); - screenManager()->push(new DeveloperToolsScreen()); + screenManager()->push(new DeveloperToolsScreen(gamePath_)); return UI::EVENT_DONE; } diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 0df3d73ce3..687f5e6e11 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -30,7 +30,7 @@ class DevMenuScreen : public PopupScreen { public: - DevMenuScreen(std::shared_ptr i18n) : PopupScreen(i18n->T("Dev Tools")) {} + DevMenuScreen(const Path &gamePath, std::shared_ptr i18n) : PopupScreen(i18n->T("Dev Tools")), gamePath_(gamePath) {} const char *tag() const override { return "DevMenu"; } @@ -47,6 +47,9 @@ protected: UI::EventReturn OnDeveloperTools(UI::EventParams &e); UI::EventReturn OnToggleAudioDebug(UI::EventParams &e); UI::EventReturn OnResetLimitedLogging(UI::EventParams &e); + +private: + Path gamePath_; }; class JitDebugScreen : public UIDialogScreenWithBackground { diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index a0b898663c..8922c05ed2 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -486,7 +486,7 @@ void EmuScreen::sendMessage(const char *message, const char *value) { RecreateViews(); } else if (!strcmp(message, "control mapping") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); - screenManager()->push(new ControlMappingScreen()); + screenManager()->push(new ControlMappingScreen(gamePath_)); } else if (!strcmp(message, "display layout editor") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); screenManager()->push(new DisplayLayoutScreen(gamePath_)); @@ -968,7 +968,7 @@ void EmuScreen::CreateViews() { UI::EventReturn EmuScreen::OnDevTools(UI::EventParams ¶ms) { auto dev = GetI18NCategory("Developer"); - DevMenuScreen *devMenu = new DevMenuScreen(dev); + DevMenuScreen *devMenu = new DevMenuScreen(gamePath_, dev); if (params.v) devMenu->SetPopupOrigin(params.v); screenManager()->push(devMenu); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index f22627e100..068f80618b 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -792,7 +792,7 @@ void GameSettingsScreen::CreateViews() { style->SetEnabledPtr(&g_Config.bShowTouchControls); Choice *gesture = controlsSettings->Add(new Choice(co->T("Gesture mapping"))); gesture->OnClick.Add([=](EventParams &e) { - screenManager()->push(new GestureMappingScreen()); + screenManager()->push(new GestureMappingScreen(gamePath_)); return UI::EVENT_DONE; }); gesture->SetEnabledPtr(&g_Config.bShowTouchControls); @@ -1739,7 +1739,7 @@ UI::EventReturn GameSettingsScreen::OnTextureShaderChange(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) { - screenManager()->push(new DeveloperToolsScreen()); + screenManager()->push(new DeveloperToolsScreen(gamePath_)); return UI::EVENT_DONE; } @@ -1749,17 +1749,17 @@ UI::EventReturn GameSettingsScreen::OnRemoteISO(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnControlMapping(UI::EventParams &e) { - screenManager()->push(new ControlMappingScreen()); + screenManager()->push(new ControlMappingScreen(gamePath_)); return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnCalibrateAnalogs(UI::EventParams &e) { - screenManager()->push(new AnalogSetupScreen()); + screenManager()->push(new AnalogSetupScreen(gamePath_)); return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) { - screenManager()->push(new TouchControlLayoutScreen()); + screenManager()->push(new TouchControlLayoutScreen(gamePath_)); return UI::EVENT_DONE; } @@ -1991,7 +1991,7 @@ UI::EventReturn DeveloperToolsScreen::OnFramedumpTest(UI::EventParams &e) { } UI::EventReturn DeveloperToolsScreen::OnTouchscreenTest(UI::EventParams &e) { - screenManager()->push(new TouchTestScreen()); + screenManager()->push(new TouchTestScreen(gamePath_)); return UI::EVENT_DONE; } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 5dbe9a682f..e7ea844507 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -155,8 +155,10 @@ private: std::string oldSettingInfo_; }; -class DeveloperToolsScreen : public UIDialogScreenWithBackground { +class DeveloperToolsScreen : public UIDialogScreenWithGameBackground { public: + DeveloperToolsScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} + void update() override; void onFinish(DialogResult result) override; @@ -247,8 +249,9 @@ private: }; -class GestureMappingScreen : public UIDialogScreenWithBackground { +class GestureMappingScreen : public UIDialogScreenWithGameBackground { public: + GestureMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} void CreateViews() override; const char *tag() const override { return "GestureMapping"; } diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 0516286f5d..df75236e9a 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -416,7 +416,7 @@ void HandleCommonMessages(const char *message, const char *value, ScreenManager currentMIPS->UpdateCore((CPUCore)g_Config.iCpuCore); } else if (!strcmp(message, "control mapping") && isActiveScreen && std::string(activeScreen->tag()) != "ControlMapping") { UpdateUIState(UISTATE_MENU); - manager->push(new ControlMappingScreen()); + manager->push(new ControlMappingScreen(Path())); } else if (!strcmp(message, "display layout editor") && isActiveScreen && std::string(activeScreen->tag()) != "DisplayLayout") { UpdateUIState(UISTATE_MENU); manager->push(new DisplayLayoutScreen(Path())); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 4df138ec1e..055d1ead17 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -826,7 +826,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch screenManager->switchScreen(new LogoScreen(AfterLogoScreen::TO_GAME_SETTINGS)); } else if (gotoTouchScreenTest) { screenManager->switchScreen(new MainScreen()); - screenManager->push(new TouchTestScreen()); + screenManager->push(new TouchTestScreen(Path())); } else if (skipLogo) { screenManager->switchScreen(new EmuScreen(boot_filename)); } else { diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 2094400a42..3432d76d26 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -557,8 +557,6 @@ DragDropButton *ControlLayoutView::getPickedControl(const int x, const int y) { return bestMatch; } -TouchControlLayoutScreen::TouchControlLayoutScreen() {} - void TouchControlLayoutScreen::resized() { RecreateViews(); } @@ -568,7 +566,7 @@ void TouchControlLayoutScreen::onFinish(DialogResult reason) { } UI::EventReturn TouchControlLayoutScreen::OnVisibility(UI::EventParams &e) { - screenManager()->push(new TouchControlVisibilityScreen()); + screenManager()->push(new TouchControlVisibilityScreen(gamePath_)); return UI::EVENT_DONE; } diff --git a/UI/TouchControlLayoutScreen.h b/UI/TouchControlLayoutScreen.h index 9834f217f0..0c3f328f96 100644 --- a/UI/TouchControlLayoutScreen.h +++ b/UI/TouchControlLayoutScreen.h @@ -23,9 +23,9 @@ class ControlLayoutView; -class TouchControlLayoutScreen : public UIDialogScreenWithBackground { +class TouchControlLayoutScreen : public UIDialogScreenWithGameBackground { public: - TouchControlLayoutScreen(); + TouchControlLayoutScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} virtual void CreateViews() override; virtual void dialogFinished(const Screen *dialog, DialogResult result) override; diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index a9110810ee..8bfb3c90d5 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -84,48 +84,48 @@ void TouchControlVisibilityScreen::CreateViews() { toggles_.push_back({ "Dpad", &g_Config.touchDpad.show, ImageID::invalid(), nullptr }); toggles_.push_back({ "Analog Stick", &g_Config.touchAnalogStick.show, ImageID::invalid(), nullptr }); toggles_.push_back({ "Right Analog Stick", &g_Config.touchRightAnalogStick.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new RightAnalogMappingScreen()); + screenManager()->push(new RightAnalogMappingScreen(gamePath_)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Fast-forward", &g_Config.touchFastForwardKey.show, ImageID::invalid(), nullptr }); toggles_.push_back({ "Custom 1", &g_Config.touchCombo0.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(0)); + screenManager()->push(new ComboKeyScreen(gamePath_, 0)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 2", &g_Config.touchCombo1.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(1)); + screenManager()->push(new ComboKeyScreen(gamePath_, 1)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 3", &g_Config.touchCombo2.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(2)); + screenManager()->push(new ComboKeyScreen(gamePath_, 2)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 4", &g_Config.touchCombo3.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(3)); + screenManager()->push(new ComboKeyScreen(gamePath_, 3)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 5", &g_Config.touchCombo4.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(4)); + screenManager()->push(new ComboKeyScreen(gamePath_, 4)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 6", &g_Config.touchCombo5.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(5)); + screenManager()->push(new ComboKeyScreen(gamePath_, 5)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 7", &g_Config.touchCombo6.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(6)); + screenManager()->push(new ComboKeyScreen(gamePath_, 6)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 8", &g_Config.touchCombo7.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(7)); + screenManager()->push(new ComboKeyScreen(gamePath_, 7)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 9", &g_Config.touchCombo8.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(8)); + screenManager()->push(new ComboKeyScreen(gamePath_, 8)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 10", &g_Config.touchCombo9.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(9)); + screenManager()->push(new ComboKeyScreen(gamePath_, 9)); return UI::EVENT_DONE; }}); diff --git a/UI/TouchControlVisibilityScreen.h b/UI/TouchControlVisibilityScreen.h index 52d6d00eea..c21efbde8f 100644 --- a/UI/TouchControlVisibilityScreen.h +++ b/UI/TouchControlVisibilityScreen.h @@ -31,8 +31,9 @@ struct TouchButtonToggle { std::function handle; }; -class TouchControlVisibilityScreen : public UIDialogScreenWithBackground { +class TouchControlVisibilityScreen : public UIDialogScreenWithGameBackground { public: + TouchControlVisibilityScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} void CreateViews() override; void onFinish(DialogResult result) override; @@ -46,8 +47,9 @@ private: bool nextToggleAll_ = true; }; -class RightAnalogMappingScreen : public UIDialogScreenWithBackground { +class RightAnalogMappingScreen : public UIDialogScreenWithGameBackground { public: + RightAnalogMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} void CreateViews() override; const char *tag() const override { return "RightAnalogMapping"; } From 6d9bb1b29efbe560201f34732b3e78dd764566d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Nov 2022 23:29:50 +0100 Subject: [PATCH 357/715] Move post-processing settings to DisplayLayoutScreen --- GPU/Common/FramebufferManagerCommon.cpp | 13 ++- GPU/Common/FramebufferManagerCommon.h | 5 +- GPU/GPUCommon.cpp | 4 +- GPU/GPUCommon.h | 2 +- GPU/GPUInterface.h | 1 + UI/DisplayLayoutScreen.cpp | 117 ++++++++++++++++++++---- UI/DisplayLayoutScreen.h | 7 ++ UI/GameSettingsScreen.cpp | 79 ++-------------- UI/GameSettingsScreen.h | 2 - UI/MiscScreens.cpp | 1 + 10 files changed, 133 insertions(+), 98 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index e931b65461..a2f466da68 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -107,14 +107,15 @@ bool FramebufferManagerCommon::UpdateRenderSize() { return newRender || newSettings; } -void FramebufferManagerCommon::BeginFrame() { - DecimateFBOs(); - - // Might have a new post shader - let's compile it. +void FramebufferManagerCommon::CheckPostShaders() { if (updatePostShaders_) { presentation_->UpdatePostShader(); updatePostShaders_ = false; } +} + +void FramebufferManagerCommon::BeginFrame() { + DecimateFBOs(); currentRenderVfb_ = nullptr; } @@ -2382,6 +2383,10 @@ void FramebufferManagerCommon::NotifyRenderResized() { #endif } +void FramebufferManagerCommon::NotifyConfigChanged() { + updatePostShaders_ = true; +} + void FramebufferManagerCommon::DestroyAllFBOs() { currentRenderVfb_ = nullptr; displayFramebuf_ = nullptr; diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index fa41e1c272..676c024f7c 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -398,8 +398,11 @@ public: } void SetSafeSize(u16 w, u16 h); - virtual void NotifyRenderResized(); + void NotifyRenderResized(); virtual void NotifyDisplayResized(); + void NotifyConfigChanged(); + + void CheckPostShaders(); virtual void DestroyAllFBOs(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index e6e7f2f25f..08bd734232 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -633,11 +633,13 @@ void GPUCommon::CheckConfigChanged() { if (configChanged_) { gstate_c.useFlags = CheckGPUFeatures(); drawEngineCommon_->NotifyConfigChanged(); - shaderManager_->DirtyLastShader(); // Don't think this is needed, at all. textureCache_->NotifyConfigChanged(); + framebufferManager_->NotifyConfigChanged(); BuildReportingInfo(); configChanged_ = false; } + + framebufferManager_->CheckPostShaders(); } void GPUCommon::CheckDisplayResized() { diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 82ca294e07..bfcf47d415 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -79,6 +79,7 @@ public: virtual u32 CheckGPUFeatures() const; void CheckDisplayResized() override; + void CheckConfigChanged() override; void UpdateCmdInfo(); @@ -266,7 +267,6 @@ protected: void DeviceLost() override; void DeviceRestore() override; - void CheckConfigChanged(); void CheckRenderResized(); // Add additional common features dependent on other features, which may be backend-determined. diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 76afe301dd..625fc4487d 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -199,6 +199,7 @@ public: virtual void EndHostFrame() = 0; virtual void CheckDisplayResized() = 0; + virtual void CheckConfigChanged() = 0; // Draw queue management virtual DisplayList* getList(int listid) = 0; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index de32079916..2fd5ec49f4 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -25,6 +25,8 @@ #include "Common/UI/View.h" #include "Common/Math/math_util.h" #include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/StringUtils.h" #include "Common/Data/Color/RGBAUtil.h" #include "Common/Data/Text/I18n.h" @@ -34,6 +36,7 @@ #include "Core/System.h" #include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" +#include "GPU/Common/PostShader.h" static const int leftColumnWidth = 200; static const float orgRatio = 1.764706f; // 480.0 / 272.0 @@ -158,16 +161,36 @@ void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult resu RecreateViews(); } -// Stealing StickyChoice's layout and text rendering. -class HighlightLabel : public UI::StickyChoice { -public: - HighlightLabel(const std::string &text, UI::LayoutParams *layoutParams) - : UI::StickyChoice(text, "", layoutParams) { - Press(); - } +UI::EventReturn DisplayLayoutScreen::OnPostProcShaderChange(UI::EventParams &e) { + g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); - bool CanBeFocused() const override { return false; } -}; + NativeMessageReceived("gpu_configChanged", ""); + NativeMessageReceived("gpu_renderResized", ""); // To deal with shaders that can change render resolution like upscaling. + NativeMessageReceived("postshader_updated", ""); + + if (gpu) { + gpu->NotifyConfigChanged(); + } + return UI::EVENT_DONE; +} + +static std::string PostShaderTranslateName(const char *value) { + auto ps = GetI18NCategory("PostShaders"); + const ShaderInfo *info = GetPostShaderInfo(value); + if (info) { + return ps->T(value, info ? info->name.c_str() : value); + } else { + return value; + } +} + +void DisplayLayoutScreen::sendMessage(const char *message, const char *value) { + UIDialogScreenWithGameBackground::sendMessage(message, value); + if (!strcmp(message, "postshader_updated")) { + g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); + RecreateViews(); + } +} void DisplayLayoutScreen::CreateViews() { const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); @@ -177,9 +200,13 @@ void DisplayLayoutScreen::CreateViews() { auto di = GetI18NCategory("Dialog"); auto gr = GetI18NCategory("Graphics"); auto co = GetI18NCategory("Controls"); + auto ps = GetI18NCategory("PostShaders"); root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.0f, 10.0f, false)); + root_->Add(rightColumn); + // We manually implement insets here for the buttons. This file defied refactoring :( float leftInset = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT); @@ -189,11 +216,9 @@ void DisplayLayoutScreen::CreateViews() { bRotated_ = true; } - HighlightLabel *label = nullptr; mode_ = nullptr; if (g_Config.iSmallDisplayZoomType >= (int)SmallDisplayZoom::AUTO) { // Scaling if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - label = new HighlightLabel(gr->T("Auto Scaling"), new AnchorLayoutParams(WRAP_CONTENT, 64.0f, bounds.w / 2.0f, bounds.h / 2.0f, NONE, NONE, true)); float autoBound = bounds.h / 270.0f; // Case of screen rotated ~ only works with buffered rendering if (bRotated_) { @@ -229,7 +254,6 @@ void DisplayLayoutScreen::CreateViews() { mode_->SetSelection(0, false); } } else { // Stretching - label = new HighlightLabel(gr->T("Stretching"), new AnchorLayoutParams(WRAP_CONTENT, 64.0f, bounds.w / 2.0f, bounds.h / 2.0f, NONE, NONE, true)); float width = bounds.w; float height = bounds.h; if (g_Config.iSmallDisplayZoomType != (int)SmallDisplayZoom::STRETCH) { @@ -252,23 +276,76 @@ void DisplayLayoutScreen::CreateViews() { if (mode_) { root_->Add(mode_); } - if (label) { - root_->Add(label); - } static const char *zoomLevels[] = { "Stretching", "Partial Stretch", "Auto Scaling", "Manual Scaling" }; auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, di->T("Options"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, NONE, NONE, 10)); zoom->OnChoice.Handle(this, &DisplayLayoutScreen::OnZoomTypeChange); - root_->Add(zoom); + rightColumn->Add(zoom); static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; - auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, 10, NONE, bounds.h - 64 - 10)); + auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); rotation->SetEnabledFunc([] { return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; }); - root_->Add(rotation); + rightColumn->Add(rotation); - Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10)); + rightColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); + + Draw::DrawContext *draw = screenManager()->getDrawContext(); + + bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; + + auto enableStereo = [=]() -> bool { + return g_Config.bStereoRendering && multiViewSupported; + }; + + std::set alreadyAddedShader; + for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { + // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread + shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; + postProcChoice_ = rightColumn->Add(new ChoiceWithValueDisplay(&shaderNames_[i], StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1), &PostShaderTranslateName)); + postProcChoice_->OnClick.Add([=](EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); + procScreen->OnChoice.Handle(this, &DisplayLayoutScreen::OnPostProcShaderChange); + if (e.v) + procScreen->SetPopupOrigin(e.v); + screenManager()->push(procScreen); + return UI::EVENT_DONE; + }); + postProcChoice_->SetEnabledFunc([=] { + return !g_Config.bSkipBufferEffects && !enableStereo(); + }); + + // No need for settings on the last one. + if (i == g_Config.vPostShaderNames.size()) + continue; + + auto shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + for (auto shaderInfo : shaderChain) { + // Disable duplicated shader slider + bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end(); + alreadyAddedShader.insert(shaderInfo->section); + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; + if (duplicated) { + auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); + PopupSliderChoiceFloat *settingValue = rightColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); + settingValue->SetEnabled(false); + } else { + PopupSliderChoiceFloat *settingValue = rightColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetEnabledFunc([=] { + return !g_Config.bSkipBufferEffects && !enableStereo(); + }); + } + } + } + } + } + + Choice *back = new Choice(di->T("Back"), "", false); back->OnClick.Handle(this, &UIScreen::OnBack); - root_->Add(back); + rightColumn->Add(back); } diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index acf4cc51c8..520e2a8f6d 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -41,8 +41,15 @@ protected: virtual UI::EventReturn OnCenter(UI::EventParams &e); virtual UI::EventReturn OnZoomTypeChange(UI::EventParams &e); + UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); + + void sendMessage(const char *message, const char *value) override; + private: UI::ChoiceStrip *mode_ = nullptr; + UI::Choice *postProcChoice_ = nullptr; + std::string shaderNames_[256]; + bool dragging_ = false; bool bRotated_ = false; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 068f80618b..739c5642bb 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -145,16 +145,6 @@ static std::string TextureTranslateName(const char *value) { } } -static std::string PostShaderTranslateName(const char *value) { - auto ps = GetI18NCategory("PostShaders"); - const ShaderInfo *info = GetPostShaderInfo(value); - if (info) { - return ps->T(value, info ? info->name.c_str() : value); - } else { - return value; - } -} - static std::string *GPUDeviceNameSetting() { if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { return &g_Config.sVulkanDevice; @@ -192,6 +182,16 @@ bool PathToVisualUsbPath(Path path, std::string &outPath) { return false; } +static std::string PostShaderTranslateName(const char *value) { + auto ps = GetI18NCategory("PostShaders"); + const ShaderInfo *info = GetPostShaderInfo(value); + if (info) { + return ps->T(value, info ? info->name.c_str() : value); + } else { + return value; + } +} + void GameSettingsScreen::CreateViews() { ReloadAllPostShaderInfo(screenManager()->getDrawContext()); ReloadAllThemeInfo(); @@ -403,52 +403,6 @@ void GameSettingsScreen::CreateViews() { } } - std::set alreadyAddedShader; - for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { - // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread - shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; - postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&shaderNames_[i], StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1), &PostShaderTranslateName)); - postProcChoice_->OnClick.Add([=](EventParams &e) { - auto gr = GetI18NCategory("Graphics"); - auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); - procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange); - if (e.v) - procScreen->SetPopupOrigin(e.v); - screenManager()->push(procScreen); - return UI::EVENT_DONE; - }); - postProcChoice_->SetEnabledFunc([=] { - return !g_Config.bSkipBufferEffects && !enableStereo(); - }); - - // No need for settings on the last one. - if (i == g_Config.vPostShaderNames.size()) - continue; - - auto shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); - for (auto shaderInfo : shaderChain) { - // Disable duplicated shader slider - bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end(); - alreadyAddedShader.insert(shaderInfo->section); - for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { - auto &setting = shaderInfo->settings[i]; - if (!setting.name.empty()) { - auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; - if (duplicated) { - auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); - PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); - settingValue->SetEnabled(false); - } else { - PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); - settingValue->SetEnabledFunc([=] { - return !g_Config.bSkipBufferEffects && !enableStereo(); - }); - } - } - } - } - } - if (deviceType != DEVICE_TYPE_VR) { graphicsSettings->Add(new ItemHeader(gr->T("Screen layout"))); #if !defined(MOBILE_DEVICE) @@ -1395,10 +1349,6 @@ void GameSettingsScreen::onFinish(DialogResult result) { void GameSettingsScreen::sendMessage(const char *message, const char *value) { UIDialogScreenWithGameBackground::sendMessage(message, value); - if (!strcmp(message, "postshader_updated")) { - g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); - RecreateViews(); - } if (!strcmp(message, "gameSettings_search")) { std::string filter = value ? value : ""; searchFilter_.resize(filter.size()); @@ -1712,15 +1662,6 @@ UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { - g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); - - NativeMessageReceived("gpu_configChanged", ""); - NativeMessageReceived("gpu_renderResized", ""); // To deal with shaders that can change render resolution like upscaling. - NativeMessageReceived("postshader_updated", ""); - return UI::EVENT_DONE; -} - UI::EventReturn GameSettingsScreen::OnTextureShader(UI::EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto shaderScreen = new TextureShaderScreen(gr->T("Texture Shader")); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index e7ea844507..80e2f45b30 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -55,7 +55,6 @@ private: bool lastVertical_; UI::CheckBox *enableReportsCheckbox_; UI::Choice *layoutEditorChoice_; - UI::Choice *postProcChoice_; UI::Choice *displayEditor_; UI::Choice *backgroundChoice_ = nullptr; UI::PopupMultiChoice *resolutionChoice_; @@ -142,7 +141,6 @@ private: bool enableReportsSet_ = false; bool analogSpeedMapped_ = false; - std::string shaderNames_[256]; std::string searchFilter_; //edit the game-specific settings and restore the global settings after exiting diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index df75236e9a..2a1a418f5b 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -362,6 +362,7 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f if (PSP_IsInited() && !g_Config.bSkipBufferEffects) { gpu->CheckDisplayResized(); + gpu->CheckConfigChanged(); gpu->CopyDisplayToOutput(true); DrawContext *draw = dc.GetDrawContext(); From b42ba5b3ccf2096b8b8224ab5b8d5ca3fba87c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Nov 2022 23:49:09 +0100 Subject: [PATCH 358/715] Wording tweaks, add scroll view --- UI/DisplayLayoutScreen.cpp | 8 +++++--- UI/GameSettingsScreen.cpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 2fd5ec49f4..f1fdb89b0e 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -204,8 +204,10 @@ void DisplayLayoutScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.0f, 10.0f, false)); - root_->Add(rightColumn); + ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.0f, 10.0f, false)); + ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL); // , new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.0f, 10.0f, false)); + rightScrollView->Add(rightColumn); + root_->Add(rightScrollView); // We manually implement insets here for the buttons. This file defied refactoring :( float leftInset = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT); @@ -278,7 +280,7 @@ void DisplayLayoutScreen::CreateViews() { } static const char *zoomLevels[] = { "Stretching", "Partial Stretch", "Auto Scaling", "Manual Scaling" }; - auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, di->T("Options"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, NONE, NONE, 10)); + auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, gr->T("Mode"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, NONE, NONE, 10)); zoom->OnChoice.Handle(this, &DisplayLayoutScreen::OnZoomTypeChange); rightColumn->Add(zoom); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 739c5642bb..7ea9b204f4 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -366,7 +366,7 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_CONTINUE; }); - graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); + graphicsSettings->Add(new ItemHeader(gr->T("Stereo rendering"))); bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; From 5eb1c8eb59ced2d06cfebe1fe8ffe48468a76ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 00:01:15 +0100 Subject: [PATCH 359/715] Cleanup --- UI/DisplayLayoutScreen.cpp | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index f1fdb89b0e..57a1d28896 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -204,8 +204,8 @@ void DisplayLayoutScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.0f, 10.0f, false)); - ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL); // , new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.0f, 10.0f, false)); + ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.f, 10.f, false)); + ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL); rightScrollView->Add(rightColumn); root_->Add(rightScrollView); @@ -245,9 +245,6 @@ void DisplayLayoutScreen::CreateViews() { center->OnClick.Handle(this, &DisplayLayoutScreen::OnCenter); root_->Add(center); float minZoom = 1.0f; - if (g_dpi_scale_x > 1.0f) { - minZoom /= g_dpi_scale_x; - } PopupSliderChoiceFloat *zoomlvl = new PopupSliderChoiceFloat(&g_Config.fSmallDisplayZoomLevel, minZoom, 10.0f, di->T("Zoom"), 1.0f, screenManager(), di->T("* PSP res"), new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); root_->Add(zoomlvl); mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); @@ -255,24 +252,6 @@ void DisplayLayoutScreen::CreateViews() { mode_->AddChoice(di->T("Resize")); mode_->SetSelection(0, false); } - } else { // Stretching - float width = bounds.w; - float height = bounds.h; - if (g_Config.iSmallDisplayZoomType != (int)SmallDisplayZoom::STRETCH) { - float origRatio = !bRotated_ ? 480.0f / 272.0f : 272.0f / 480.0f; - float frameRatio = width / height; - if (origRatio > frameRatio) { - height = width / origRatio; - if (!bRotated_ && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) { - height = (272.0f + height) / 2.0f; - } - } else { - width = height * origRatio; - if (bRotated_ && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) { - width = (272.0f + height) / 2.0f; - } - } - } } if (mode_) { From 75dc856e2c093720eed7586a382a06416e9bdd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 08:52:46 +0100 Subject: [PATCH 360/715] Test fix --- GPU/GPUCommon.cpp | 5 ++++- headless/Headless.cpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 08bd734232..37654faff5 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -639,7 +639,10 @@ void GPUCommon::CheckConfigChanged() { configChanged_ = false; } - framebufferManager_->CheckPostShaders(); + // Check needed when running tests. + if (framebufferManager_) { + framebufferManager_->CheckPostShaders(); + } } void GPUCommon::CheckDisplayResized() { diff --git a/headless/Headless.cpp b/headless/Headless.cpp index eb29a26500..3b2bd96dd6 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -1,6 +1,8 @@ // Headless version of PPSSPP, for testing using http://code.google.com/p/pspautotests/ . // See headless.txt. // To build on non-windows systems, just run CMake in the SDL directory, it will build both a normal ppsspp and the headless version. +// Example command line to run a test in the VS debugger (useful to debug failures): +// > --root pspautotests/tests/../ --compare --timeout=5 --graphics=software pspautotests/tests/cpu/cpu_alu/cpu_alu.prx #include "ppsspp_config.h" #include From f4c88e0f80ead221af67beca5cf771f6cee388e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 11:13:21 +0100 Subject: [PATCH 361/715] Add trashcan icon to UI atlas, use in control mapper. Reorder a couple dev settings --- UI/ControlMappingScreen.cpp | 4 ++-- UI/GameSettingsScreen.cpp | 4 ++-- assets/ui_atlas.meta | Bin 3432 -> 1106 bytes assets/ui_atlas.zim | Bin 80730 -> 58080 bytes source_assets/image/trashcan.png | Bin 0 -> 1062 bytes ui_atlasscript.txt | 1 + 6 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 source_assets/image/trashcan.png diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index b0f0651735..1461220625 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -142,14 +142,14 @@ void SingleControlMapper::Refresh() { std::string keyName = KeyMap::GetKeyOrAxisName(mappings[i].keyCode); LinearLayout *row = rightColumn->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); - row->SetSpacing(1.0f); + row->SetSpacing(2.0f); rows_.push_back(row); Choice *c = row->Add(new Choice(deviceName + "." + keyName, new LinearLayoutParams(FILL_PARENT, itemH, 1.0f))); c->SetTag(StringFromFormat("%d_Change%d", (int)i, pspKey_)); c->OnClick.Handle(this, &SingleControlMapper::OnReplace); - Choice *d = row->Add(new Choice(" X ", new LayoutParams(WRAP_CONTENT, itemH))); + Choice *d = row->Add(new Choice(ImageID("I_TRASHCAN"), new LayoutParams(WRAP_CONTENT, itemH))); d->SetTag(StringFromFormat("%d_Del%d", (int)i, pspKey_)); d->OnClick.Handle(this, &SingleControlMapper::OnDelete); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index f22627e100..f985110613 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1863,11 +1863,11 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bShowOnScreenMessages, dev->T("Show on-screen messages"))); list->Add(new CheckBox(&g_Config.bEnableLogging, dev->T("Enable Logging")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoggingChanged); + list->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLogConfig); + list->Add(new CheckBox(&g_Config.bLogFrameDrops, dev->T("Log Dropped Frame Statistics"))); if (GetGPUBackend() == GPUBackend::VULKAN) { list->Add(new CheckBox(&g_Config.bGpuLogProfiler, gr->T("GPU log profiler"))); } - list->Add(new CheckBox(&g_Config.bLogFrameDrops, dev->T("Log Dropped Frame Statistics"))); - list->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLogConfig); list->Add(new ItemHeader(dev->T("Language"))); list->Add(new Choice(dev->T("Load language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoadLanguageIni); list->Add(new Choice(dev->T("Save language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSaveLanguageIni); diff --git a/assets/ui_atlas.meta b/assets/ui_atlas.meta index 32d31ed1323d4ae60a58c9cc428a0408a073bdd0..a1d7df260c878b94ba06cd9c41af8b2948d2b96f 100644 GIT binary patch literal 1106 zcmV-Y1g-l)R7^nu000000000!0000!1ONaiwJ-f(kPM|E00!=$OTg4kI>K%L#Oojm zU%P{W0HA>GfB%+!g(>yyI-&W)4wMImL8&7caTzA=j1GdN3Ad`g=;}Zw$v- z4_DiUV`^|;9jn4_HC(>EkmcDG(m$<*ls^c>^9Vd(kl*739A|MM`7 z`?mC~;=Y^SG)w#a-)S5QEcESwzT(814iv}I+=>71Y8ZWIh&kU+^Z}rED{W9v!_c-6 zSQi($=b6X-|FH#yQ)rC<$1>c_(DejdGQWU?n1ca(}A$ z2A`4K^Ek2AN4w>ueZ18I#yvN9CB<=9gmiW}Z3V|%S%cyvuN*Ey+D=0hKmFX~a))dC z#GH^J$4;3h+4RX)Xyb`Xi$6*nu&p>U`By z^bI?gY$<}fTW;1UPFbL>M?OSM^qq3PKO!gY$?_9xH8yeK$DS|4Qnuo)lshQekOs#N z7-k)?!#jUN(a(td-E>_UC%vy`dKQ3(AE;#f{zyXa?1F1toX zGanny%Wl012?belq-7g=WnmFckX+D(t*GwT!ZxycT$<}`tKrGO@Xb^O`kGYMb_}#m z)eE%V2bwwmff{!93aw_fuLf|Ewc5`d$J`MPPXF8nNNJNfKQr?8i+*Nx(}RgR|3q!I z7Zxg4xtbDz8K{A1W{Hg?siXrDE{Te!>H$&{rs9Z0L_h?_5CI`XFsL+0R5=J3fp1$6 zs<&RpV$BgrIPYIRqB6FT^YXyIjDjid)0_IXNcN;=p>``_8Va2rLCuXYP|MGDM~fDG zw)b*dYrp5osK%hqu(%_>*Ivm;Yq)0rHn)}puqu5mqIiYhHL2PC`Lre64!zxqJ#a%< zW^kt-&1aU}44`fHaf|_v!|45{6F;zmLnZPWwNA1Kv9ee(V9aYAzIQe76?5hc$#v$= z)J&t$6%PfwgkQj{Da9Cz;2#8-u)8PUJ(43v&PASqf`REeeb**s%1kWwo?!0s*6E%O z5O-%Ahn2xI{teYlev6`ser1Bs7!ofUS+5~!L`T|IHH_WnPR90~DKI!;zp+yvwdfj?14>IITt|gGDLw6Nxc2J(eO_r;B7hR&nnH1u*#Waz9hfwtKI4 z2(;`BgthV5`2l~OxCP#OycIIMD~QT2hxnC`(|y#_YjFR@Je#~?R(Ow%Z-dCf`r5sr YX<#%KNAdm6)L2_K-(Y!~vQKUI0T8GkWB>pF literal 3432 zcmaKuONnf+wQ~2|k0k zttVq58V{%kV%pNhC}=aTL}Tn_;&uYHNmfFZvshhmlD$g@Q*Mn6Ee6SrWm{g`S_dIhCS64EGB2HnZa* z*G)pd)o|{Z{i0RAnX_GmTy5k;eZSPBdeG&+vLT{abwDR+;Adn ze46=y-T*g&gsGn-@nZR2vMP3FXW=9kBj!$)b|PU~3lsU>HN5-r$#0zT7~HVA4ZXcc zm?m+rRdZ3SpPy0LzwG$}dk&eHmBP-X$}8mAUe1->p}hN;cW60L4UDf=lie@sf7dZd-DcmAXVh)>tCm_XIA?+tAM$QQ{~X*b^*3g2W>thdOX7CgY5KMD zs`n1!hSM|3JHkArr(mwMoaAOj-_4{RBtO4KzOdXCmTM%T($-`aNSKB}+;Tyz3zxmo=S~lB6#>ktpL{*OJb+A^J$$O@ zgL4GkUG2)Nu^)ZVI|RSZ$emckq1TocN)g7%-6i(sm$1)Pg#MD>WUfI)BupE1zcTdW z`2QzrXczOc9)h{ta<}kr#jttyRzJ^9**q(_TPq-bvfT51?oG=Tao=6dDd}gg+FF;M zCOKW~C!Vbsc0X#~*27mT?3CN3VhE=W5{D(?@tod>YGJ2z--==H74l5tulDN+RD})G zc1Hr(X-9rp_*72ZZGOhg4ZQ_s*m84`-$?hh`MY#vFX9)u|A>WmsTtsU&I%OHyNt6* z4A&2Gb-4>mhrE08A-H$pHxF`6=gleaI(ZZ1N0G5X&Uf0WPS9J(Y4!Vz%Et$}d3VW6 zUdz2HefI}F$zepobgmagogk^#%d0;7k#kW;Iqlt>Hve-;y+i3auUmPC$h%JRG@mfL z*y~!mU#AxMNkvEFez4~|4!_-82O~W+Oq=n3_h!`5BkU!8SKepa^cc*z<$V6F7`DHB zijDKc@Ml{O1t+hAijjSbAEjT@o3hVr{S}31?;E(B8DS|KUUojY1}SPP;~7*?d>E-M~!r`;+?hVC#|sMdVc-~ D3s12h diff --git a/assets/ui_atlas.zim b/assets/ui_atlas.zim index 85517eb137b9a0ece8fd9db07f38cb59155e6fad..5b8b17995c2e3a7d769c014b15f91d5673147c1f 100644 GIT binary patch literal 58080 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 PtY~?Ng9cy&z~|?Gb)!Hm literal 80730 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%0A?4C)#Qddjitx`&p9^tDCN=nsFt^shgdRH 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 #?e~@g;yFwZzPBJU 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 delta 223808 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⩔i6_RE7)!KH#%alHk9lU1w1b{o20n+pv21&e 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 Ppj)+OZ(B%DG35UMgpF9$ From 489af071b97afe40ca72bc31766681cb18dbae6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Nov 2022 15:14:54 +0100 Subject: [PATCH 471/715] TouchControlLayoutScreen: Reduce the amount of scissor calls Who knows, might help #15773... --- UI/TouchControlLayoutScreen.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 729ee5ed1f..164fc86f3a 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -55,9 +55,7 @@ public: void Draw(UIContext &dc) override { scale_ = theScale_*layoutAreaScale; // Scale down just for rendering - dc.PushScissor(screenBounds_); MultiTouchButton::Draw(dc); - dc.PopScissor(); scale_ = theScale_/layoutAreaScale; // is this is needed? } @@ -118,7 +116,6 @@ public: void Draw(UIContext &dc) override { scale_ = theScale_*layoutAreaScale; - dc.PushScissor(screenBounds_); uint32_t colorBg = colorAlpha(GetButtonColor(), GetButtonOpacity()); uint32_t color = colorAlpha(0xFFFFFF, GetButtonOpacity()); @@ -147,7 +144,6 @@ public: dc.Draw()->DrawImageRotated(roundId_, centerX - spacing, centerY, scale_, 0, colorBg, false); dc.Draw()->DrawImageRotated(squareId_, centerX - spacing, centerY, scale_, 0, color, false); } - dc.PopScissor(); scale_ = theScale_/layoutAreaScale; }; @@ -248,7 +244,6 @@ public: void Draw(UIContext &dc) override { scale_ = theScale_*layoutAreaScale; - dc.PushScissor(screenBounds_); uint32_t colorBg = colorAlpha(GetButtonColor(), GetButtonOpacity()); uint32_t color = colorAlpha(0xFFFFFF, GetButtonOpacity()); @@ -268,7 +263,6 @@ public: dc.Draw()->DrawImageRotated(dirImage, x, y, scale_, angle + PI, colorBg, false); dc.Draw()->DrawImageRotated(ImageID("I_ARROW"), x2, y2, scale_, angle + PI, color); } - dc.PopScissor(); scale_ = theScale_/layoutAreaScale; } @@ -357,6 +351,7 @@ class ControlLayoutView : public UI::AnchorLayout { public: explicit ControlLayoutView(UI::LayoutParams *layoutParams) : UI::AnchorLayout(layoutParams) { + SetClip(true); } bool Touch(const TouchInput &input) override; @@ -459,6 +454,7 @@ bool ControlLayoutView::Touch(const TouchInput &touch) { void ControlLayoutView::Draw(UIContext& dc) { using namespace UI; dc.FillRect(Drawable(0x80000000), bounds_); + dc.Flush(); UI::AnchorLayout::Draw(dc); } From b62790fd0002d07a1b1a9ac7534089c9c4ed6472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Nov 2022 23:02:11 +0100 Subject: [PATCH 472/715] Fix translatability of the string "Stereo display shader". See #16459 --- UI/GameSettingsScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index c85513f0e4..b2ad14f16e 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1793,7 +1793,7 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering"))); std::vector stereoShaderNames; - ChoiceWithValueDisplay *stereoShaderChoice = list->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, "Stereo display shader", &PostShaderTranslateName)); + ChoiceWithValueDisplay *stereoShaderChoice = list->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, gr->T("Stereo display shader"), &PostShaderTranslateName)); stereoShaderChoice->SetEnabledFunc(enableStereo); stereoShaderChoice->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); From dc962094f862eca2af2b7f58b36d3316c13650c7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 23:20:39 -0800 Subject: [PATCH 473/715] softgpu: Correctly fix inversions, matching tests. Inversions are allowed just fine, but if clipping results in coordinates outside range, the triangle should be culled. Fixes more wanted inversions. --- GPU/Software/Clipper.cpp | 15 +++++++-------- GPU/Software/TransformUnit.cpp | 25 +++++++++++-------------- GPU/Software/TransformUnit.h | 2 +- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index ccfd8f5a76..2d96b1f24c 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -50,16 +50,15 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, } inline void clip_interpolate(ClipVertexData &dest, float t, const ClipVertexData &a, const ClipVertexData &b) { - if (different_signs(a.clippos.w, b.clippos.w)) { - if (a.clippos.w < -1.0f || b.clippos.w < -1.0f) { - dest.v.screenpos.x = 0x7FFFFFFF; - return; - } - } - + bool outsideRange = false; dest.Lerp(t, a, b); - dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos); + dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos, &outsideRange); dest.v.clipw = dest.clippos.w; + + // If the clipped coordinate is outside range, then we throw it away. + // This prevents a lot of inversions that shouldn't be drawn. + if (outsideRange) + dest.v.screenpos.x = 0x7FFFFFFF; } #define CLIP_POLY( PLANE_BIT, A, B, C, D ) \ diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index bc1f8679eb..ac8ea921a8 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -162,7 +162,7 @@ ClipCoords TransformUnit::ViewToClip(const ViewCoords &coords) { return Vec3ByMatrix44(coords, gstate.projMatrix); } -template +template static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, bool *outside_range_flag) { ScreenCoords ret; @@ -173,7 +173,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, // This matches hardware tests - depth is clamped when this flag is on. if (depthClamp) { // Note: if the depth is clipped (z/w <= -1.0), the outside_range_flag should NOT be set, even for x and y. - if (writeOutsideFlag && coords.z > -coords.w && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) { + if ((alwaysCheckRange || coords.z > -coords.w) && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) { *outside_range_flag = true; } @@ -181,7 +181,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, scaled.z = 0.f; else if (scaled.z > 65535.0f) scaled.z = 65535.0f; - } else if (writeOutsideFlag && (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) { + } else if (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0) { *outside_range_flag = true; } @@ -209,17 +209,13 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords &coords, bool * float z = coords.z * zScale / coords.w + zCenter; if (gstate.isDepthClampEnabled()) { - if (outside_range_flag) - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); + return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); } - if (outside_range_flag) - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); + return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); } -ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords) { - return ClipToScreenInternal(coords, nullptr); +ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords, bool *outsideRangeFlag) { + return ClipToScreenInternal(coords, outsideRangeFlag); } ScreenCoords TransformUnit::DrawingToScreen(const DrawingCoords &coords, u16 z) { @@ -317,9 +313,9 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { } if (gstate.isDepthClampEnabled()) - state->roundToScreen = &ClipToScreenInternal; + state->roundToScreen = &ClipToScreenInternal; else - state->roundToScreen = &ClipToScreenInternal; + state->roundToScreen = &ClipToScreenInternal; } ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformState &state) { @@ -977,7 +973,8 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector coord, this is negative and force-scissors. From d763dca024fb0ac4d9ba28fa92efaa7f0332fb17 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 00:17:14 -0800 Subject: [PATCH 474/715] GPU: Correct fetch assert. --- GPU/Common/FragmentShaderGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index eba7b966da..f1e2aeb4cd 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -172,7 +172,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool fetchFramebuffer = needFramebufferRead && id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); bool readFramebufferTex = needFramebufferRead && !id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); - if (fetchFramebuffer && (compat.shaderLanguage != GLSL_VULKAN || compat.shaderLanguage != GLSL_3xx)) { + if (fetchFramebuffer && (compat.shaderLanguage != GLSL_VULKAN && compat.shaderLanguage != GLSL_3xx)) { *errorString = "framebuffer fetch requires GLSL: vulkan or 3xx"; return false; } From fc5dcd0c168f8cf6b6aa4c50b56736c63a6ca864 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 00:59:22 -0800 Subject: [PATCH 475/715] GLES: Correct unit tests for framebuffer fetch. --- GPU/Common/FragmentShaderGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index f1e2aeb4cd..93f30f3323 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -172,7 +172,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool fetchFramebuffer = needFramebufferRead && id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); bool readFramebufferTex = needFramebufferRead && !id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); - if (fetchFramebuffer && (compat.shaderLanguage != GLSL_VULKAN && compat.shaderLanguage != GLSL_3xx)) { + if (fetchFramebuffer && compat.shaderLanguage != GLSL_VULKAN && (compat.shaderLanguage != GLSL_3xx || !compat.lastFragData)) { *errorString = "framebuffer fetch requires GLSL: vulkan or 3xx"; return false; } @@ -568,7 +568,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu if (compat.shaderLanguage == GLSL_3xx) { WRITE(p, " lowp vec4 destColor = %s;\n", compat.lastFragData); } else if (compat.shaderLanguage == GLSL_VULKAN) { - WRITE(p, " lowp vec4 destColor = subpassLoad(inputColor);\n", compat.lastFragData); + WRITE(p, " lowp vec4 destColor = subpassLoad(inputColor);\n"); } else { _assert_msg_(false, "Need fetch destColor, but not a compatible language"); } From 9a108a46d462c1ca2e87387de9f6c92b26e48b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 10:17:31 +0100 Subject: [PATCH 476/715] Disable the PowerVR swapchain hack after driver version 1.386.1368. See #15773 --- Common/GPU/Vulkan/VulkanContext.cpp | 20 +++++++++++++++----- UI/DisplayLayoutScreen.cpp | 23 ++++++++++++++--------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 389eb6dbbe..19ecb40588 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -1136,11 +1136,21 @@ bool VulkanContext::InitSwapchain() { INFO_LOG(G3D, "Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str()); if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) { - INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!)"); - // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). - // To keep the size consistent even with pretransform, do this after the swap. Should be fine. - // This is fixed in newer PowerVR drivers but I don't know the cutoff. - swapChainExtent_.width &= ~31; + u32 driverVersion = physicalDeviceProperties_[physical_device_].properties.driverVersion; + // Cutoff the hack at driver version 1.386.1368 (0x00582558, see issue #15773). + if (driverVersion < 0x00582558) { + INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!) driverVersion=%08x", driverVersion); + // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). + // To keep the size consistent even with pretransform, do this after the swap. Should be fine. + // This is fixed in newer PowerVR drivers but I don't know the cutoff. + swapChainExtent_.width &= ~31; + + // TODO: Also modify display_xres/display_yres appropriately for scissors to match. + // This will get a bit messy. Ideally we should remove that logic from app-android.cpp + // and move it here, but the OpenGL code still needs it. + } else { + INFO_LOG(G3D, "PowerVR driver version new enough (%08x), not applying swapchain width hack", driverVersion); + } } VkSwapchainCreateInfoKHR swap_chain_info{ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index ed741ec6c9..18d52d8360 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -63,15 +63,14 @@ public: bool Touch(const TouchInput &touch) { int mode = mode_ ? mode_->GetSelection() : 0; - const Bounds &screenBounds = bounds_; if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { float relativeTouchX = touch.x - startX_; float relativeTouchY = touch.y - startY_; switch (mode) { case MODE_MOVE: - g_Config.fDisplayOffsetX = clamp_value(startDisplayOffsetX_ + relativeTouchX / screenBounds.w, 0.0f, 1.0f); - g_Config.fDisplayOffsetY = clamp_value(startDisplayOffsetY_ + relativeTouchY / screenBounds.h, 0.0f, 1.0f); + g_Config.fDisplayOffsetX = clamp_value(startDisplayOffsetX_ + relativeTouchX / bounds_.w, 0.0f, 1.0f); + g_Config.fDisplayOffsetY = clamp_value(startDisplayOffsetY_ + relativeTouchY / bounds_.h, 0.0f, 1.0f); break; case MODE_RESIZE: { @@ -84,12 +83,18 @@ public: } if ((touch.flags & TOUCH_DOWN) != 0 && !dragging_) { - dragging_ = true; - startX_ = touch.x; - startY_ = touch.y; - startDisplayOffsetX_ = g_Config.fDisplayOffsetX; - startDisplayOffsetY_ = g_Config.fDisplayOffsetY; - startScale_ = g_Config.fDisplayScale; + // Check that we're in the central 80% of the screen. + // If outside, it may be a drag from displaying the back button on phones + // where you have to drag from the side, etc. + if (touch.x >= bounds_.w * 0.1f && touch.x <= bounds_.w * 0.9f && + touch.y >= bounds_.h * 0.1f && touch.y <= bounds_.h * 0.9f) { + dragging_ = true; + startX_ = touch.x; + startY_ = touch.y; + startDisplayOffsetX_ = g_Config.fDisplayOffsetX; + startDisplayOffsetY_ = g_Config.fDisplayOffsetY; + startScale_ = g_Config.fDisplayScale; + } } if ((touch.flags & TOUCH_UP) != 0 && dragging_) { From 2adc18cfba331648d88987e193a106e15be245e4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 17:52:42 -0800 Subject: [PATCH 477/715] softgpu: Correct src/dst overlap in block transfer. If dest is inside src, it seems to consistently copy in blocks of 64 bytes. --- GPU/Software/SoftGpu.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 7a824fe7b0..27601247fd 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -803,7 +803,9 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); - if (srcStride == dstStride && (u32)width == srcStride) { + bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src; + + if (srcStride == dstStride && (u32)width == srcStride && !srcDstOverlap) { u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp; @@ -823,6 +825,20 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); memcpy(dstp, srcp, bytesToCopy); GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); + } else if (srcDstOverlap) { + for (int y = 0; y < height; y++) { + u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; + u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + + u32 totalToCopy = width * bpp; + for (u32 i = 0; i < totalToCopy; i += 64) { + u32 chunk = i + 64 > totalToCopy ? totalToCopy - i : 64; + memmove(dstp + i, srcp + i, chunk); + } + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, totalToCopy); + } } else { for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; From 68515aaee2ae000ae0ffff07909ae965f998b723 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 18:29:47 -0800 Subject: [PATCH 478/715] softgpu: Account for width!=stride in xfer checks. --- GPU/Software/SoftGpu.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 27601247fd..2c5874d3c7 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -792,10 +792,11 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { int bpp = gstate.getTransferBpp(); + // Use height less one to account for width, which can be greater or less than stride. const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; - const uint32_t srcSize = height * srcStride * bpp; + const uint32_t srcSize = (height - 1) * srcStride * bpp + width * bpp; const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const uint32_t dstSize = height * dstStride * bpp; + const uint32_t dstSize = (height - 1) * dstStride * bpp + width * bpp; // Need to flush both source and target, so we overwrite properly. drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height); From 1c5f0d575caa9d7c300a0531851b4c773b4219ac Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 18:40:25 -0800 Subject: [PATCH 479/715] softgpu: Improve meminfo detail on block transfer. Gaps are useful to understand. --- GPU/Software/SoftGpu.cpp | 106 +++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 2c5874d3c7..8872979b04 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -29,6 +29,7 @@ #include "Core/Core.h" #include "Core/Debugger/MemBlockInfo.h" #include "Core/MemMap.h" +#include "Core/MemMapHelpers.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceGe.h" #include "Core/MIPS/MIPS.h" @@ -792,6 +793,12 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { int bpp = gstate.getTransferBpp(); + // For VRAM, we wrap around when outside valid memory (mirrors still work.) + if ((srcBasePtr & 0x04800000) == 0x04800000) + srcBasePtr &= ~0x00800000; + if ((dstBasePtr & 0x04800000) == 0x04800000) + dstBasePtr &= ~0x00800000; + // Use height less one to account for width, which can be greater or less than stride. const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; const uint32_t srcSize = (height - 1) * srcStride * bpp + width * bpp; @@ -805,68 +812,93 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src; + bool srcValid = Memory::IsValidRange(src, srcSize); + bool dstValid = Memory::IsValidRange(dst, dstSize); + bool srcWraps = Memory::IsVRAMAddress(srcBasePtr) && !srcValid; + bool dstWraps = Memory::IsVRAMAddress(dstBasePtr) && !dstValid; - if (srcStride == dstStride && (u32)width == srcStride && !srcDstOverlap) { + // Simple case: just a straight copy, no overlap or wrapping. + if (srcStride == dstStride && (u32)width == srcStride && !srcDstOverlap && srcValid && dstValid) { u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp; - u32 bytesToCopy = width * height * bpp; - if (!Memory::IsValidRange(srcLineStartAddr, bytesToCopy)) { - // What should we do here? Memset zeroes to the dest instead? - return; - } - if (!Memory::IsValidRange(dstLineStartAddr, bytesToCopy)) { - // What should we do here? Just not do the write, or partial write if - // some part is in-range? - return; - } - const u8 *srcp = Memory::GetPointer(srcLineStartAddr); u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); memcpy(dstp, srcp, bytesToCopy); GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); - } else if (srcDstOverlap) { + + if (MemBlockInfoDetailed(bytesToCopy)) { + const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, bytesToCopy); + NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag.c_str(), tag.size()); + } + } else if (srcDstOverlap || srcWraps || dstWraps) { + u32 bytesToCopy = width * bpp; + static std::string tag; + bool notifyDetail = MemBlockInfoDetailed(bytesToCopy); + bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); + if (notifyDetail || notifyAll) { + tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); + } + + // TODO: Handle wrapping. for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; const u8 *srcp = Memory::GetPointer(srcLineStartAddr); u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - u32 totalToCopy = width * bpp; - for (u32 i = 0; i < totalToCopy; i += 64) { - u32 chunk = i + 64 > totalToCopy ? totalToCopy - i : 64; + for (u32 i = 0; i < bytesToCopy; i += 64) { + u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; memmove(dstp + i, srcp + i, chunk); } - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, totalToCopy); + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); + + // If we're tracking detail, it's useful to have the gaps illustrated properly. + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + } } - } else { + + if (notifyAll) { + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + } + } else if (srcValid && dstValid) { + u32 bytesToCopy = width * bpp; + static std::string tag; + bool notifyDetail = MemBlockInfoDetailed(bytesToCopy); + bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); + if (notifyDetail || notifyAll) { + tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); + } + for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; - u32 bytesToCopy = width * bpp; - if (!Memory::IsValidRange(srcLineStartAddr, bytesToCopy)) { - // What should we do here? Due to the y loop, in this case we might have - // performed a partial copy. Probably fine. - break; - } - if (!Memory::IsValidRange(dstLineStartAddr, bytesToCopy)) { - // What should we do here? Due to the y loop, in this case we might have - // performed a partial copy. Probably fine. - break; - } const u8 *srcp = Memory::GetPointer(srcLineStartAddr); u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - memcpy(dstp, srcp, width * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * bpp); - } - } + memcpy(dstp, srcp, bytesToCopy); + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); - if (MemBlockInfoDetailed(srcSize, dstSize)) { - const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + // If we're tracking detail, it's useful to have the gaps illustrated properly. + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + } + } + + if (notifyAll) { + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + } + } else { + // This seems to cause the GE to require a break/reset on a PSP. + // TODO: Handle that and figure out which bytes are still copied? + ERROR_LOG_REPORT(G3D, "Block transfer invalid: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); } // TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate. From 3589c1e82606dbad8758ad4efd97da7c279715d7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 19:04:52 -0800 Subject: [PATCH 480/715] softgpu: Handle block transfer VRAM wrapping. Note: mirrors still act as mirrors, swizzle and all. --- GPU/Software/SoftGpu.cpp | 105 +++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 16 deletions(-) diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 8872979b04..27c96844a5 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -833,38 +833,111 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag.c_str(), tag.size()); } - } else if (srcDstOverlap || srcWraps || dstWraps) { + } else if ((srcDstOverlap || srcWraps || dstWraps) && (srcValid || srcWraps) && (dstValid || dstWraps)) { + // This path means we have either src/dst overlap, OR one or both of src and dst wrap. + // This should be uncommon so it's the slowest path. u32 bytesToCopy = width * bpp; static std::string tag; - bool notifyDetail = MemBlockInfoDetailed(bytesToCopy); + bool notifyDetail = MemBlockInfoDetailed(srcWraps || dstWraps ? 64 : bytesToCopy); bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); if (notifyDetail || notifyAll) { tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); } - // TODO: Handle wrapping. + auto notifyingMemmove = [&](u32 d, u32 s, u32 sz) { + const u8 *srcp = Memory::GetPointer(s); + u8 *dstp = Memory::GetPointerWrite(d); + memmove(dstp, srcp, sz); + GPURecord::NotifyMemcpy(d, s, sz); + + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, s, sz, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, d, sz, tag.c_str(), tag.size()); + } + }; + for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; - const u8 *srcp = Memory::GetPointer(srcLineStartAddr); - u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + // If we already passed a wrap, we can use the quicker path. + if ((srcLineStartAddr & 0x04800000) == 0x04800000) + srcLineStartAddr &= ~0x00800000; + if ((dstLineStartAddr & 0x04800000) == 0x04800000) + dstLineStartAddr &= ~0x00800000; + // These flags mean there's a wrap inside this line. + bool srcLineWrap = !Memory::IsValidRange(srcLineStartAddr, bytesToCopy); + bool dstLineWrap = !Memory::IsValidRange(dstLineStartAddr, bytesToCopy); - for (u32 i = 0; i < bytesToCopy; i += 64) { - u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; - memmove(dstp + i, srcp + i, chunk); - } - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); + if (!srcLineWrap && !dstLineWrap) { + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + for (u32 i = 0; i < bytesToCopy; i += 64) { + u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; + memmove(dstp + i, srcp + i, chunk); + } + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); - // If we're tracking detail, it's useful to have the gaps illustrated properly. - if (notifyDetail) { - NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + // If we're tracking detail, it's useful to have the gaps illustrated properly. + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + } + } else { + // We can wrap at any point, so along with overlap this gets a bit complicated. + // We're just going to do this the slow and easy way. + u32 srcLinePos = srcLineStartAddr; + u32 dstLinePos = dstLineStartAddr; + for (u32 i = 0; i < bytesToCopy; i += 64) { + u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; + u32 srcValid = Memory::ValidSize(srcLinePos, chunk); + u32 dstValid = Memory::ValidSize(dstLinePos, chunk); + + // First chunk, for which both are valid. + u32 bothSize = std::min(srcValid, dstValid); + if (bothSize != 0) + notifyingMemmove(dstLinePos, srcLinePos, bothSize); + + // Now, whichever side has more valid (or the rest, if only one side must wrap.) + u32 exclusiveSize = std::max(srcValid, dstValid) - bothSize; + if (exclusiveSize != 0 && srcValid >= dstValid) { + notifyingMemmove(PSP_GetVidMemBase(), srcLineStartAddr + bothSize, exclusiveSize); + } else if (exclusiveSize != 0 && srcValid < dstValid) { + notifyingMemmove(dstLineStartAddr + bothSize, PSP_GetVidMemBase(), exclusiveSize); + } + + // Finally, if both src and dst wrapped, that portion. + u32 wrappedSize = chunk - bothSize - exclusiveSize; + if (wrappedSize != 0 && srcValid >= dstValid) { + notifyingMemmove(PSP_GetVidMemBase() + exclusiveSize, PSP_GetVidMemBase(), wrappedSize); + } else if (wrappedSize != 0 && srcValid < dstValid) { + notifyingMemmove(PSP_GetVidMemBase(), PSP_GetVidMemBase() + exclusiveSize, wrappedSize); + } + + srcLinePos += chunk; + dstLinePos += chunk; + if ((srcLinePos & 0x04800000) == 0x04800000) + srcLinePos &= ~0x00800000; + if ((dstLinePos & 0x04800000) == 0x04800000) + dstLinePos &= ~0x00800000; + } } } if (notifyAll) { - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + if (srcWraps) { + u32 validSize = Memory::ValidSize(src, srcSize); + NotifyMemInfo(MemBlockFlags::READ, src, validSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, PSP_GetVidMemBase(), srcSize - validSize, tag.c_str(), tag.size()); + } else { + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); + } + if (dstWraps) { + u32 validSize = Memory::ValidSize(dst, dstSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, validSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetVidMemBase(), dstSize - validSize, tag.c_str(), tag.size()); + } else { + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + } } } else if (srcValid && dstValid) { u32 bytesToCopy = width * bpp; From cbe96d37742f316b0e4e5ffa2d8e8ea9c6458b71 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 19:12:06 -0800 Subject: [PATCH 481/715] GPU: Use common block transfer logic in all cases. --- GPU/GPUCommon.cpp | 220 ++++++++++++++++++++++++++++++--------- GPU/GPUCommon.h | 2 +- GPU/Software/SoftGpu.cpp | 178 +------------------------------ 3 files changed, 176 insertions(+), 224 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 1560d3fe49..11f2caf8b6 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3057,72 +3057,192 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); - if (!Memory::IsValidAddress(srcBasePtr)) { - ERROR_LOG_REPORT(G3D, "BlockTransfer: Bad source transfer address %08x!", srcBasePtr); - return; - } + // For VRAM, we wrap around when outside valid memory (mirrors still work.) + if ((srcBasePtr & 0x04800000) == 0x04800000) + srcBasePtr &= ~0x00800000; + if ((dstBasePtr & 0x04800000) == 0x04800000) + dstBasePtr &= ~0x00800000; - if (!Memory::IsValidAddress(dstBasePtr)) { - ERROR_LOG_REPORT(G3D, "BlockTransfer: Bad destination transfer address %08x!", dstBasePtr); - return; - } + // Use height less one to account for width, which can be greater or less than stride. + const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; + const uint32_t srcSize = (height - 1) * srcStride * bpp + width * bpp; + const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; + const uint32_t dstSize = (height - 1) * dstStride * bpp + width * bpp; - // Check that the last address of both source and dest are valid addresses - - u32 srcLastAddr = srcBasePtr + ((srcY + height - 1) * srcStride + (srcX + width - 1)) * bpp; - u32 dstLastAddr = dstBasePtr + ((dstY + height - 1) * dstStride + (dstX + width - 1)) * bpp; - - if (!Memory::IsValidAddress(srcLastAddr)) { - ERROR_LOG_N_TIMES(bad_xfer_src, 5, G3D, "Bottom-right corner of source of %dx%d src=(%d, %d) block transfer from buffer at %08x is at an invalid address: %08x. Skipping.", width, height, srcX, srcY, srcBasePtr, srcLastAddr); - return; - } - if (!Memory::IsValidAddress(dstLastAddr)) { - ERROR_LOG_N_TIMES(bad_xfer_src, 5, G3D, "Bottom-right corner of destination of %dx%d dst=(%d, %d) block transfer to buffer at %08x is at an invalid address: %08x. Skipping.", width, height, dstX, dstY, dstBasePtr, srcLastAddr); - return; - } + bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src; + bool srcValid = Memory::IsValidRange(src, srcSize); + bool dstValid = Memory::IsValidRange(dst, dstSize); + bool srcWraps = Memory::IsVRAMAddress(srcBasePtr) && !srcValid; + bool dstWraps = Memory::IsVRAMAddress(dstBasePtr) && !dstValid; // Tell the framebuffer manager to take action if possible. If it does the entire thing, let's just return. - if (!framebufferManager_->NotifyBlockTransferBefore(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason)) { + if (!framebufferManager_ || !framebufferManager_->NotifyBlockTransferBefore(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason)) { // Do the copy! (Hm, if we detect a drawn video frame (see below) then we could maybe skip this?) // Can use GetPointerUnchecked because we checked the addresses above. We could also avoid them // entirely by walking a couple of pointers... - if (srcStride == dstStride && (u32)width == srcStride) { - // Common case in God of War, let's do it all in one chunk. + + // Simple case: just a straight copy, no overlap or wrapping. + if (srcStride == dstStride && (u32)width == srcStride && !srcDstOverlap && srcValid && dstValid) { u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr); - u8 *dst = Memory::GetPointerWriteUnchecked(dstLineStartAddr); - memcpy(dst, src, width * height * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * height * bpp); - } else { + u32 bytesToCopy = width * height * bpp; + + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + memcpy(dstp, srcp, bytesToCopy); + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); + + if (MemBlockInfoDetailed(bytesToCopy)) { + const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, bytesToCopy); + NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag.c_str(), tag.size()); + } + } else if ((srcDstOverlap || srcWraps || dstWraps) && (srcValid || srcWraps) && (dstValid || dstWraps)) { + // This path means we have either src/dst overlap, OR one or both of src and dst wrap. + // This should be uncommon so it's the slowest path. + u32 bytesToCopy = width * bpp; + static std::string tag; + bool notifyDetail = MemBlockInfoDetailed(srcWraps || dstWraps ? 64 : bytesToCopy); + bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); + if (notifyDetail || notifyAll) { + tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); + } + + auto notifyingMemmove = [&](u32 d, u32 s, u32 sz) { + const u8 *srcp = Memory::GetPointer(s); + u8 *dstp = Memory::GetPointerWrite(d); + memmove(dstp, srcp, sz); + GPURecord::NotifyMemcpy(d, s, sz); + + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, s, sz, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, d, sz, tag.c_str(), tag.size()); + } + }; + + for (int y = 0; y < height; y++) { + u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; + u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; + // If we already passed a wrap, we can use the quicker path. + if ((srcLineStartAddr & 0x04800000) == 0x04800000) + srcLineStartAddr &= ~0x00800000; + if ((dstLineStartAddr & 0x04800000) == 0x04800000) + dstLineStartAddr &= ~0x00800000; + // These flags mean there's a wrap inside this line. + bool srcLineWrap = !Memory::IsValidRange(srcLineStartAddr, bytesToCopy); + bool dstLineWrap = !Memory::IsValidRange(dstLineStartAddr, bytesToCopy); + + if (!srcLineWrap && !dstLineWrap) { + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + for (u32 i = 0; i < bytesToCopy; i += 64) { + u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; + memmove(dstp + i, srcp + i, chunk); + } + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); + + // If we're tracking detail, it's useful to have the gaps illustrated properly. + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + } + } else { + // We can wrap at any point, so along with overlap this gets a bit complicated. + // We're just going to do this the slow and easy way. + u32 srcLinePos = srcLineStartAddr; + u32 dstLinePos = dstLineStartAddr; + for (u32 i = 0; i < bytesToCopy; i += 64) { + u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; + u32 srcValid = Memory::ValidSize(srcLinePos, chunk); + u32 dstValid = Memory::ValidSize(dstLinePos, chunk); + + // First chunk, for which both are valid. + u32 bothSize = std::min(srcValid, dstValid); + if (bothSize != 0) + notifyingMemmove(dstLinePos, srcLinePos, bothSize); + + // Now, whichever side has more valid (or the rest, if only one side must wrap.) + u32 exclusiveSize = std::max(srcValid, dstValid) - bothSize; + if (exclusiveSize != 0 && srcValid >= dstValid) { + notifyingMemmove(PSP_GetVidMemBase(), srcLineStartAddr + bothSize, exclusiveSize); + } else if (exclusiveSize != 0 && srcValid < dstValid) { + notifyingMemmove(dstLineStartAddr + bothSize, PSP_GetVidMemBase(), exclusiveSize); + } + + // Finally, if both src and dst wrapped, that portion. + u32 wrappedSize = chunk - bothSize - exclusiveSize; + if (wrappedSize != 0 && srcValid >= dstValid) { + notifyingMemmove(PSP_GetVidMemBase() + exclusiveSize, PSP_GetVidMemBase(), wrappedSize); + } else if (wrappedSize != 0 && srcValid < dstValid) { + notifyingMemmove(PSP_GetVidMemBase(), PSP_GetVidMemBase() + exclusiveSize, wrappedSize); + } + + srcLinePos += chunk; + dstLinePos += chunk; + if ((srcLinePos & 0x04800000) == 0x04800000) + srcLinePos &= ~0x00800000; + if ((dstLinePos & 0x04800000) == 0x04800000) + dstLinePos &= ~0x00800000; + } + } + } + + if (notifyAll) { + if (srcWraps) { + u32 validSize = Memory::ValidSize(src, srcSize); + NotifyMemInfo(MemBlockFlags::READ, src, validSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, PSP_GetVidMemBase(), srcSize - validSize, tag.c_str(), tag.size()); + } else { + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); + } + if (dstWraps) { + u32 validSize = Memory::ValidSize(dst, dstSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, validSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetVidMemBase(), dstSize - validSize, tag.c_str(), tag.size()); + } else { + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + } + } + } else if (srcValid && dstValid) { + u32 bytesToCopy = width * bpp; + static std::string tag; + bool notifyDetail = MemBlockInfoDetailed(bytesToCopy); + bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); + if (notifyDetail || notifyAll) { + tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); + } + for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; - const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr); - u8 *dst = Memory::GetPointerWriteUnchecked(dstLineStartAddr); - memcpy(dst, src, width * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * bpp); + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + memcpy(dstp, srcp, bytesToCopy); + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); + + // If we're tracking detail, it's useful to have the gaps illustrated properly. + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + } } + + if (notifyAll) { + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + } + } else { + // This seems to cause the GE to require a break/reset on a PSP. + // TODO: Handle that and figure out which bytes are still copied? + ERROR_LOG_REPORT_ONCE(invalidtransfer, G3D, "Block transfer invalid: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); } - // Fixes Gran Turismo's funky text issue, since it overwrites the current texture. - textureCache_->Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT); - framebufferManager_->NotifyBlockTransferAfter(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason); - } - - const uint32_t numBytes = width * height * bpp; - const uint32_t srcSize = height * srcStride * bpp; - const uint32_t dstSize = height * dstStride * bpp; - // We do the check here on the number of bytes to avoid marking really tiny images. - // Helps perf in GT menu which does insane amounts of these, one for each text character per frame. - if (MemBlockInfoDetailed(numBytes, numBytes)) { - const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; - const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - char tag[128]; - size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize); - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize); + if (framebufferManager_) { + // Fixes Gran Turismo's funky text issue, since it overwrites the current texture. + textureCache_->Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT); + framebufferManager_->NotifyBlockTransferAfter(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason); + } } // TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate. diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index bfcf47d415..76b14bdc9e 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -301,6 +301,7 @@ protected: void UpdateState(GPURunState state); void FastLoadBoneMatrix(u32 target); void FlushImm(); + void DoBlockTransfer(u32 skipDrawReason); // TODO: Unify this. virtual void FinishDeferred() {} @@ -406,7 +407,6 @@ protected: private: void CheckDepthUsage(VirtualFramebuffer *vfb); - void DoBlockTransfer(u32 skipDrawReason); void DoExecuteCall(u32 target); void PopDLQueue(); void CheckDrawSync(); diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 27c96844a5..d7e6e3346f 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -793,12 +793,6 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { int bpp = gstate.getTransferBpp(); - // For VRAM, we wrap around when outside valid memory (mirrors still work.) - if ((srcBasePtr & 0x04800000) == 0x04800000) - srcBasePtr &= ~0x00800000; - if ((dstBasePtr & 0x04800000) == 0x04800000) - dstBasePtr &= ~0x00800000; - // Use height less one to account for width, which can be greater or less than stride. const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; const uint32_t srcSize = (height - 1) * srcStride * bpp + width * bpp; @@ -806,176 +800,14 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { const uint32_t dstSize = (height - 1) * dstStride * bpp + width * bpp; // Need to flush both source and target, so we overwrite properly. - drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height); - drawEngine_->transformUnit.FlushIfOverlap("blockxfer", true, dst, dstStride, width * bpp, height); - - DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); - - bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src; - bool srcValid = Memory::IsValidRange(src, srcSize); - bool dstValid = Memory::IsValidRange(dst, dstSize); - bool srcWraps = Memory::IsVRAMAddress(srcBasePtr) && !srcValid; - bool dstWraps = Memory::IsVRAMAddress(dstBasePtr) && !dstValid; - - // Simple case: just a straight copy, no overlap or wrapping. - if (srcStride == dstStride && (u32)width == srcStride && !srcDstOverlap && srcValid && dstValid) { - u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp; - u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp; - u32 bytesToCopy = width * height * bpp; - - const u8 *srcp = Memory::GetPointer(srcLineStartAddr); - u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - memcpy(dstp, srcp, bytesToCopy); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); - - if (MemBlockInfoDetailed(bytesToCopy)) { - const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, bytesToCopy); - NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag.c_str(), tag.size()); - } - } else if ((srcDstOverlap || srcWraps || dstWraps) && (srcValid || srcWraps) && (dstValid || dstWraps)) { - // This path means we have either src/dst overlap, OR one or both of src and dst wrap. - // This should be uncommon so it's the slowest path. - u32 bytesToCopy = width * bpp; - static std::string tag; - bool notifyDetail = MemBlockInfoDetailed(srcWraps || dstWraps ? 64 : bytesToCopy); - bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); - if (notifyDetail || notifyAll) { - tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); - } - - auto notifyingMemmove = [&](u32 d, u32 s, u32 sz) { - const u8 *srcp = Memory::GetPointer(s); - u8 *dstp = Memory::GetPointerWrite(d); - memmove(dstp, srcp, sz); - GPURecord::NotifyMemcpy(d, s, sz); - - if (notifyDetail) { - NotifyMemInfo(MemBlockFlags::READ, s, sz, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, d, sz, tag.c_str(), tag.size()); - } - }; - - for (int y = 0; y < height; y++) { - u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; - u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; - // If we already passed a wrap, we can use the quicker path. - if ((srcLineStartAddr & 0x04800000) == 0x04800000) - srcLineStartAddr &= ~0x00800000; - if ((dstLineStartAddr & 0x04800000) == 0x04800000) - dstLineStartAddr &= ~0x00800000; - // These flags mean there's a wrap inside this line. - bool srcLineWrap = !Memory::IsValidRange(srcLineStartAddr, bytesToCopy); - bool dstLineWrap = !Memory::IsValidRange(dstLineStartAddr, bytesToCopy); - - if (!srcLineWrap && !dstLineWrap) { - const u8 *srcp = Memory::GetPointer(srcLineStartAddr); - u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - for (u32 i = 0; i < bytesToCopy; i += 64) { - u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; - memmove(dstp + i, srcp + i, chunk); - } - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); - - // If we're tracking detail, it's useful to have the gaps illustrated properly. - if (notifyDetail) { - NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); - } - } else { - // We can wrap at any point, so along with overlap this gets a bit complicated. - // We're just going to do this the slow and easy way. - u32 srcLinePos = srcLineStartAddr; - u32 dstLinePos = dstLineStartAddr; - for (u32 i = 0; i < bytesToCopy; i += 64) { - u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; - u32 srcValid = Memory::ValidSize(srcLinePos, chunk); - u32 dstValid = Memory::ValidSize(dstLinePos, chunk); - - // First chunk, for which both are valid. - u32 bothSize = std::min(srcValid, dstValid); - if (bothSize != 0) - notifyingMemmove(dstLinePos, srcLinePos, bothSize); - - // Now, whichever side has more valid (or the rest, if only one side must wrap.) - u32 exclusiveSize = std::max(srcValid, dstValid) - bothSize; - if (exclusiveSize != 0 && srcValid >= dstValid) { - notifyingMemmove(PSP_GetVidMemBase(), srcLineStartAddr + bothSize, exclusiveSize); - } else if (exclusiveSize != 0 && srcValid < dstValid) { - notifyingMemmove(dstLineStartAddr + bothSize, PSP_GetVidMemBase(), exclusiveSize); - } - - // Finally, if both src and dst wrapped, that portion. - u32 wrappedSize = chunk - bothSize - exclusiveSize; - if (wrappedSize != 0 && srcValid >= dstValid) { - notifyingMemmove(PSP_GetVidMemBase() + exclusiveSize, PSP_GetVidMemBase(), wrappedSize); - } else if (wrappedSize != 0 && srcValid < dstValid) { - notifyingMemmove(PSP_GetVidMemBase(), PSP_GetVidMemBase() + exclusiveSize, wrappedSize); - } - - srcLinePos += chunk; - dstLinePos += chunk; - if ((srcLinePos & 0x04800000) == 0x04800000) - srcLinePos &= ~0x00800000; - if ((dstLinePos & 0x04800000) == 0x04800000) - dstLinePos &= ~0x00800000; - } - } - } - - if (notifyAll) { - if (srcWraps) { - u32 validSize = Memory::ValidSize(src, srcSize); - NotifyMemInfo(MemBlockFlags::READ, src, validSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::READ, PSP_GetVidMemBase(), srcSize - validSize, tag.c_str(), tag.size()); - } else { - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); - } - if (dstWraps) { - u32 validSize = Memory::ValidSize(dst, dstSize); - NotifyMemInfo(MemBlockFlags::WRITE, dst, validSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetVidMemBase(), dstSize - validSize, tag.c_str(), tag.size()); - } else { - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); - } - } - } else if (srcValid && dstValid) { - u32 bytesToCopy = width * bpp; - static std::string tag; - bool notifyDetail = MemBlockInfoDetailed(bytesToCopy); - bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); - if (notifyDetail || notifyAll) { - tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); - } - - for (int y = 0; y < height; y++) { - u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; - u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; - - const u8 *srcp = Memory::GetPointer(srcLineStartAddr); - u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - memcpy(dstp, srcp, bytesToCopy); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); - - // If we're tracking detail, it's useful to have the gaps illustrated properly. - if (notifyDetail) { - NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); - } - } - - if (notifyAll) { - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); - } + if (Memory::IsValidRange(src, srcSize) && Memory::IsValidRange(dst, dstSize)) { + drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height); + drawEngine_->transformUnit.FlushIfOverlap("blockxfer", true, dst, dstStride, width * bpp, height); } else { - // This seems to cause the GE to require a break/reset on a PSP. - // TODO: Handle that and figure out which bytes are still copied? - ERROR_LOG_REPORT(G3D, "Block transfer invalid: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); + drawEngine_->transformUnit.Flush("blockxfer_wrap"); } - // TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate. - cyclesExecuted += ((height * width * bpp) * 16) / 10; + DoBlockTransfer(gstate_c.skipDrawReason); // Could theoretically dirty the framebuffer. MarkDirty(dst, dstSize, SoftGPUVRAMDirty::DIRTY | SoftGPUVRAMDirty::REALLY_DIRTY); From 73489349cc0161753f078da47c4dc2ba663df22a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 19:20:52 -0800 Subject: [PATCH 482/715] GPU: Oops, simplify an expression. --- GPU/GPUCommon.cpp | 4 ++-- GPU/Software/SoftGpu.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 11f2caf8b6..0af26587eb 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3065,9 +3065,9 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { // Use height less one to account for width, which can be greater or less than stride. const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; - const uint32_t srcSize = (height - 1) * srcStride * bpp + width * bpp; + const uint32_t srcSize = (height - 1) * (srcStride + width) * bpp; const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const uint32_t dstSize = (height - 1) * dstStride * bpp + width * bpp; + const uint32_t dstSize = (height - 1) * (dstStride + width) * bpp; bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src; bool srcValid = Memory::IsValidRange(src, srcSize); diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index d7e6e3346f..6ed1bb3af1 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -795,9 +795,9 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { // Use height less one to account for width, which can be greater or less than stride. const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; - const uint32_t srcSize = (height - 1) * srcStride * bpp + width * bpp; + const uint32_t srcSize = (height - 1) * (srcStride + width) * bpp; const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const uint32_t dstSize = (height - 1) * dstStride * bpp + width * bpp; + const uint32_t dstSize = (height - 1) * (dstStride + width) * bpp; // Need to flush both source and target, so we overwrite properly. if (Memory::IsValidRange(src, srcSize) && Memory::IsValidRange(dst, dstSize)) { From 5bc51cb01d9f32f46502acf40f2e5cedcb20e351 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 30 Nov 2022 22:16:33 -0800 Subject: [PATCH 483/715] GE Debugger: Remove dup block transfer record. We already record it as a block transfer, we don't need to also do it as a memcpy. --- GPU/GPUCommon.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 0af26587eb..cd3aaeb9d7 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3090,7 +3090,6 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { const u8 *srcp = Memory::GetPointer(srcLineStartAddr); u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); memcpy(dstp, srcp, bytesToCopy); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); if (MemBlockInfoDetailed(bytesToCopy)) { const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, bytesToCopy); @@ -3112,7 +3111,6 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { const u8 *srcp = Memory::GetPointer(s); u8 *dstp = Memory::GetPointerWrite(d); memmove(dstp, srcp, sz); - GPURecord::NotifyMemcpy(d, s, sz); if (notifyDetail) { NotifyMemInfo(MemBlockFlags::READ, s, sz, tag.c_str(), tag.size()); @@ -3139,7 +3137,6 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; memmove(dstp + i, srcp + i, chunk); } - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); // If we're tracking detail, it's useful to have the gaps illustrated properly. if (notifyDetail) { @@ -3219,7 +3216,6 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { const u8 *srcp = Memory::GetPointer(srcLineStartAddr); u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); memcpy(dstp, srcp, bytesToCopy); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); // If we're tracking detail, it's useful to have the gaps illustrated properly. if (notifyDetail) { From f18afc5f51051133d5fcbdb3b0ab52f19c0eb525 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 01:09:50 -0800 Subject: [PATCH 484/715] headless: Update tests. --- pspautotests | 2 +- test.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pspautotests b/pspautotests index a886587cc2..4606502750 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit a886587cc29ffadc93f5533a0f8dc329ae355b9a +Subproject commit 46065027500cd781ce7c15c051c8b0c4751ad1fa diff --git a/test.py b/test.py index dbfe4d1ad7..7b55c8a692 100755 --- a/test.py +++ b/test.py @@ -191,6 +191,9 @@ tests_good = [ "gpu/texfunc/replace", "gpu/textures/mipmap", "gpu/textures/rotate", + "gpu/transfer/invalid", + "gpu/transfer/mirrors", + "gpu/transfer/overlap", "gpu/vertices/colors", "gpu/vertices/morph", "gpu/vertices/texcoords", From c05ec8b520893e8367800c3131b8f9f34df685c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 11:39:20 +0100 Subject: [PATCH 485/715] Remove std::string from VulkanProfiler (the scope profiler for uploads) --- Common/GPU/Vulkan/VulkanProfiler.cpp | 11 ++++------- Common/GPU/Vulkan/VulkanProfiler.h | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanProfiler.cpp b/Common/GPU/Vulkan/VulkanProfiler.cpp index fccea843b8..6e3a959f30 100644 --- a/Common/GPU/Vulkan/VulkanProfiler.cpp +++ b/Common/GPU/Vulkan/VulkanProfiler.cpp @@ -40,7 +40,7 @@ void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstComm // Log it all out. for (auto &scope : scopes_) { if (scope.endQueryId == -1) { - WARN_LOG(G3D, "Unclosed scope: %s", scope.name.c_str()); + WARN_LOG(G3D, "Unclosed scope: %s", scope.name); continue; } uint64_t startTime = results[scope.startQueryId]; @@ -50,7 +50,7 @@ void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstComm double milliseconds = (double)delta * timestampConversionFactor; - INFO_LOG(G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name.c_str(), milliseconds); + INFO_LOG(G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name, milliseconds); } scopes_.clear(); @@ -73,14 +73,11 @@ void VulkanProfiler::Begin(VkCommandBuffer cmdBuf, VkPipelineStageFlagBits stage return; } + ProfilerScope scope; va_list args; va_start(args, fmt); - char temp[512]; - vsnprintf(temp, sizeof(temp), fmt, args); + vsnprintf(scope.name, sizeof(scope.name), fmt, args); va_end(args); - - ProfilerScope scope; - scope.name = temp; scope.startQueryId = numQueries_; scope.endQueryId = -1; scope.level = (int)scopeStack_.size(); diff --git a/Common/GPU/Vulkan/VulkanProfiler.h b/Common/GPU/Vulkan/VulkanProfiler.h index d7b08d6738..e3d21c2021 100644 --- a/Common/GPU/Vulkan/VulkanProfiler.h +++ b/Common/GPU/Vulkan/VulkanProfiler.h @@ -13,7 +13,7 @@ // Put the whole thing in a FrameData to allow for overlap. struct ProfilerScope { - std::string name; + char name[52]; // to make a struct size of 64, just because int startQueryId; int endQueryId; int level; From 40ae99073be32b5ce4cb0d121a5bb97ba1bf068f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 11:58:16 +0100 Subject: [PATCH 486/715] Remove std::string from VulkanTexture --- Common/GPU/Vulkan/VulkanImage.cpp | 12 +++++++++--- Common/GPU/Vulkan/VulkanImage.h | 13 ++++--------- Common/GPU/Vulkan/thin3d_vulkan.cpp | 8 ++------ GPU/Vulkan/TextureCacheVulkan.cpp | 9 ++++----- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp index 47b1432360..8efcb69834 100644 --- a/Common/GPU/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -5,9 +5,15 @@ #include "Common/GPU/Vulkan/VulkanAlloc.h" #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/StringUtils.h" using namespace PPSSPP_VK; +VulkanTexture::VulkanTexture(VulkanContext *vulkan, const char *tag) + : vulkan_(vulkan) { + truncate_cpy(tag_, tag); +} + void VulkanTexture::Wipe() { if (view_ != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteImageView(view_); @@ -80,7 +86,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i VkResult res = vmaCreateImage(vulkan_->Allocator(), &image_create_info, &allocCreateInfo, &image_, &allocation_, &allocInfo); // Apply the tag - vulkan_->SetDebugName(image_, VK_OBJECT_TYPE_IMAGE, tag_.c_str()); + vulkan_->SetDebugName(image_, VK_OBJECT_TYPE_IMAGE, tag_); // Write a command to transition the image to the requested layout, if it's not already that layout. if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { @@ -123,14 +129,14 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } - vulkan_->SetDebugName(view_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_.c_str()); + vulkan_->SetDebugName(view_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_); // Additionally, create an array view, but only if it's a 2D texture. if (view_info.viewType == VK_IMAGE_VIEW_TYPE_2D) { view_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &arrayView_); _assert_(res == VK_SUCCESS); - vulkan_->SetDebugName(arrayView_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_.c_str()); + vulkan_->SetDebugName(arrayView_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_); } return true; diff --git a/Common/GPU/Vulkan/VulkanImage.h b/Common/GPU/Vulkan/VulkanImage.h index e0aa32d385..e4835059ed 100644 --- a/Common/GPU/Vulkan/VulkanImage.h +++ b/Common/GPU/Vulkan/VulkanImage.h @@ -1,6 +1,5 @@ #pragma once -#include #include "VulkanLoader.h" class VulkanContext; @@ -12,9 +11,7 @@ VK_DEFINE_HANDLE(VmaAllocation); // ALWAYS use an allocator when calling CreateDirect. class VulkanTexture { public: - VulkanTexture(VulkanContext *vulkan) - : vulkan_(vulkan) { - } + VulkanTexture(VulkanContext *vulkan, const char *tag); ~VulkanTexture() { Destroy(); } @@ -37,12 +34,10 @@ public: void Destroy(); - void SetTag(const char *tag) { - tag_ = tag; - } - const std::string &Tag() const { + const char *Tag() const { return tag_; } + void Touch() {} // Used in image copies, etc. @@ -74,5 +69,5 @@ private: int16_t depth_ = 1; VkFormat format_ = VK_FORMAT_UNDEFINED; - std::string tag_; + char tag_[64]; }; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 46be4cf00b..ae6808d87c 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -652,8 +652,7 @@ static inline VkSamplerAddressMode AddressModeToVulkan(Draw::TextureAddressMode VulkanTexture *VKContext::GetNullTexture() { if (!nullTexture_) { VkCommandBuffer cmdInit = renderManager_.GetInitCmd(); - nullTexture_ = new VulkanTexture(vulkan_); - nullTexture_->SetTag("Null"); + nullTexture_ = new VulkanTexture(vulkan_, "Null"); int w = 8; int h = 8; nullTexture_->CreateDirect(cmdInit, w, h, 1, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -737,10 +736,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur width_ = desc.width; height_ = desc.height; depth_ = desc.depth; - vkTex_ = new VulkanTexture(vulkan_); - if (desc.tag) { - vkTex_->SetTag(desc.tag); - } + vkTex_ = new VulkanTexture(vulkan_, desc.tag); VkFormat vulkanFormat = DataFormatToVulkan(format_); int bpp = GetBpp(vulkanFormat); int bytesPerPixel = bpp / 8; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index d536bedabd..f060b47c54 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -482,7 +482,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); delete entry->vkTex; - entry->vkTex = new VulkanTexture(vulkan); + + char texName[64]{}; + snprintf(texName, sizeof(texName), "tex_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format, gstate.getClutPaletteFormat())); + entry->vkTex = new VulkanTexture(vulkan, texName); VulkanTexture *image = entry->vkTex; const VkComponentMapping *mapping; @@ -513,10 +516,6 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { actualFmt = VULKAN_8888_FORMAT; } - char texName[128]{}; - snprintf(texName, sizeof(texName), "tex_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format, gstate.getClutPaletteFormat())); - image->SetTag(texName); - bool allocSuccess = image->CreateDirect(cmdInit, plan.createW, plan.createH, plan.depth, plan.levelsToCreate, actualFmt, imageLayout, usage, mapping); if (!allocSuccess && !lowMemoryMode_) { WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode"); From 2073eed7b76b72bfac2e334cfbfb7cb5f710e411 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Thu, 1 Dec 2022 15:20:10 +0300 Subject: [PATCH 487/715] Update Russian translation --- assets/lang/ru_RU.ini | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index aced6ead7b..4537365dd0 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -82,7 +82,7 @@ Portrait = Портретная Portrait Reversed = Портретная (перевернутая) PSP Action Buttons = Кнопки действий PSP Raw input = Прямой ввод -Repeat mode = Repeat mode +Repeat mode = Режим повтора Reset to defaults = По умолчанию Screen aligned to ground = Экран повёрнут к земле Screen at right angle to ground = Экран повёрнут под прямым углом к земле @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Тест дампов кадров Frame Profiler = Профайлер кадров GPU Driver Test = Проверка драйвера ГП -GPU log profiler = GPU log profiler +GPU log profiler = Профилировщик логов ГП GPU Profile = Профиль ГП Jit Compare = Сравнение с JIT JIT debug tools = Инструменты отладки JIT @@ -456,7 +456,7 @@ Aggressive = Принудительно Alternative Speed = Другая скорость (в %, 0 = без ограничений) Alternative Speed 2 = Другая скорость 2 (в %, 0 = без ограничений) Anisotropic Filtering = Анизотропная фильтрация -Aspect Ratio = Aspect Ratio +Aspect Ratio = Соотношение сторон Auto = Авто Auto (1:1) = Авто (1:1) Auto (same as Rendering) = Авто (как разрешение рендеринга) @@ -488,14 +488,13 @@ Disabled = Отключено Display Layout && Effects = Редактор расположения экрана Display Resolution (HW scaler) = Разрешение экрана (аппаратное) Enable Cardboard VR = Включить Cardboard VR -#Features = Возможности FPS = FPS Frame Rate Control = Управление частотой кадров Frame Skipping = Пропуск кадров Frame Skipping Type = Тип пропуска кадров FullScreen = Полноэкранный режим -Geometry shader culling = Geometry shader culling -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +Geometry shader culling = Вызов геометрических шейдеров +GPUReadbackRequired = Внимание: Для данной игры нужно отключить настройку "Пропускать чтение данных ГП". Hack Settings = Параметры хаков (могут вызывать глюки) Hardware Tessellation = Аппаратная тесселяция Hardware Transform = Аппаратное преобразование @@ -542,20 +541,20 @@ Safe = Безопасно Screen Scaling Filter = Фильтр масштабирования экрана Show Debug Statistics = Отображать отладочную информацию Show FPS Counter = Показывать счетчик FPS -Skip GPU Readbacks = Skip GPU Readbacks +Skip GPU Readbacks = Пропускать чтение данных ГП Software Rendering = Программный рендеринг (медленно) Software Skinning = Программная заливка SoftwareSkinning Tip = Объединяет вызовы отрисовки моделей с заливкой на ЦП, быстрее во многих играх Speed = Скорость Speed Hacks = Speed Hacks (могут вызывать глюки) -Stereo display shader = Stereo display shader -Stereo rendering = Stereo rendering +Stereo display shader = Шейдер стереодисплея +Stereo rendering = Стереорендеринг Stretch = Растягивание Texture Filter = Текстурный фильтр Texture Filtering = Фильтрация текстур Texture Scaling = Масштабирование текстур Texture Shader = Текстурный шейдер -Turn off Hardware Tessellation - unsupported = Выключите "аппаратную тесселяцию": не поддерживается +Turn off Hardware Tessellation - unsupported = Выключите настройку "Аппаратная тесселяция": не поддерживается Unlimited = Без ограничений Up to 1 = До 1 Up to 2 = До 2 @@ -581,8 +580,8 @@ Zip archive corrupt = ZIP-архив повреждён Zip file does not contain PSP software = В ZIP-файле отсутсвует ПО для PSP [KeyMapping] -Autoconfigure = Авто конфиг -Autoconfigure for device = Авто конфиг для устройства +Autoconfigure = Автоконфиг +Autoconfigure for device = Автоконфиг для устройства Bind All = Настроить всё Clear All = Очистить все Default All = По умолчанию @@ -722,8 +721,8 @@ Center Left = В центре слева Center Right = В центре справа Change Mac Address = Изменить MAC-адрес Change proAdhocServer Address = Изменить IP-адрес ad-hoc сервера (localhost = множество экземпляров) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +ChangeMacSaveConfirm = Сгенерировать новый MAC-адрес? +ChangeMacSaveWarning = Некоторые игры проверяют MAC-адрес при загрузке сохранений, из-за этого старые сохранения могут быть испорчены. Chat = Чат Chat Button Position = Позиция кнопки чата Chat Here = Чат здесь @@ -747,7 +746,7 @@ Failed to Bind Localhost IP = Не удалось привязать адрес Failed to Bind Port = Не удалось привязать порт Failed to connect to Adhoc Server = Не удалось подключиться к ad-hoc серверу Forced First Connect = Принудительное первое подключение (быстрое подключение) -GM: Data from Unknown Port = GM: Данные от неизвестного порта +GM: Data from Unknown Port = GM: Данные с неизвестного порта Hostname = Имя хоста Invalid IP or hostname = Некорректный IP или имя хоста Minimum Timeout = Минимальный таймаут (задержка в мс, 0 = по умолчанию) @@ -804,9 +803,9 @@ Black border = Черные рамки Bloom = Свечение Brightness = Яркость Cartoon = Мультипликация -CatmullRom = Бикубический (Catmull-Rom) Апскейлер +CatmullRom = Бикубический (Catmull-Rom) апскейлер ColorCorrection = Цветокоррекция -ColorPreservation = Color preservation +ColorPreservation = Сохранение цвета Contrast = Контрастность CRT = ЭЛТ-развертка FXAA = Сглаживание FXAA @@ -815,13 +814,13 @@ Grayscale = Оттенки серого GreenLevel = GreenLevel Intensity = Интенсивность InverseColors = Инвертированные цвета -MitchellNetravali = Бикубический (Mitchell-Netravali) Апскейлер +MitchellNetravali = Бикубический (Mitchell-Netravali) апскейлер Natural = Естественные цвета NaturalA = Естественные цвета (без размытия) Off = Выключена Power = Сила PSPColor = Цвета PSP -RedBlue = Red/Blue glasses +RedBlue = Красно-синие очки Saturation = Насыщенность Scanlines = Строки развертки (ЭЛТ) Sharpen = Резкость @@ -1043,10 +1042,10 @@ CPU Name = Название D3DCompiler Version = Версия D3DCompiler Debug = Отладочная Debugger Present = Отладчик присутствует -#Depth buffer format = Формат буфера глубины +Depth buffer format = Формат буфера глубины Device Info = Устройство Directories = Директории -Display Color Formats = Display Color Formats +Display Color Formats = Форматы цветов дисплея Display Information = Информация о дисплее Driver bugs = Ошибки драйвера Driver Version = Версия драйвера @@ -1096,7 +1095,7 @@ Cache ISO in RAM = Кэшировать ISO в ОЗУ Change CPU Clock = Эмулируемая частота ЦП PSP (нестабильно) Color Saturation = Насыщенность Color Tint = Оттенок цвета -Game crashed = Game crashed +Game crashed = Игра вылетела Language = Язык Memory Stick folder = Изменить папку с картой памяти Memory Stick size = Изменить размер карты памяти (Гб) From 9d9a64be8b3dc64bcf3eb8992206453d1233c41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 13:38:35 +0100 Subject: [PATCH 488/715] Fix Aspect Ratio translation category --- UI/DisplayLayoutScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 18d52d8360..5152965179 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -213,7 +213,7 @@ void DisplayLayoutScreen::CreateViews() { auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); leftColumn->Add(stretch); - PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); + PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, gr->T("Aspect Ratio"), screenManager()); leftColumn->Add(aspectRatio); aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch); aspectRatio->SetHasDropShadow(false); From 14e75071456ae656b56be9184bd82fad284c815e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 14:11:37 +0100 Subject: [PATCH 489/715] Temporarily disable the UWP github CI job --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4e7c10155..6a21c78623 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,6 +69,7 @@ jobs: path: ppsspp/ build-uwp: + if: ${{false}} # Temporarily disable runs-on: windows-latest steps: - uses: actions/checkout@v3 From 7f7af003ce5c5d4ae6ac8002ed2054da1a32cd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 15:06:46 +0100 Subject: [PATCH 490/715] UI: Darken game-as-background a bit more for UI legibility --- UI/MiscScreens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 85b04a4717..769fb2f01f 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -379,7 +379,7 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f dc.Begin(); if (darkenBackground) { - uint32_t color = colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.45f); + uint32_t color = colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.65f); dc.FillRect(UI::Drawable(color), dc.GetBounds()); dc.Flush(); } From 6560123257aae271228143a21bb1382a8b36d6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 15:39:22 +0100 Subject: [PATCH 491/715] Restore optimization of memory info strings, avoiding allocations --- GPU/GPUCommon.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index cd3aaeb9d7..17692b1cf0 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3075,6 +3075,9 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { bool srcWraps = Memory::IsVRAMAddress(srcBasePtr) && !srcValid; bool dstWraps = Memory::IsVRAMAddress(dstBasePtr) && !dstValid; + char tag[128]; + size_t tagSize; + // Tell the framebuffer manager to take action if possible. If it does the entire thing, let's just return. if (!framebufferManager_ || !framebufferManager_->NotifyBlockTransferBefore(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason)) { // Do the copy! (Hm, if we detect a drawn video frame (see below) then we could maybe skip this?) @@ -3100,11 +3103,10 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { // This path means we have either src/dst overlap, OR one or both of src and dst wrap. // This should be uncommon so it's the slowest path. u32 bytesToCopy = width * bpp; - static std::string tag; bool notifyDetail = MemBlockInfoDetailed(srcWraps || dstWraps ? 64 : bytesToCopy); bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); if (notifyDetail || notifyAll) { - tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); + tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize); } auto notifyingMemmove = [&](u32 d, u32 s, u32 sz) { @@ -3113,8 +3115,8 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { memmove(dstp, srcp, sz); if (notifyDetail) { - NotifyMemInfo(MemBlockFlags::READ, s, sz, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, d, sz, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, s, sz, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, d, sz, tag, tagSize); } }; @@ -3140,8 +3142,8 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { // If we're tracking detail, it's useful to have the gaps illustrated properly. if (notifyDetail) { - NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag, tagSize); } } else { // We can wrap at any point, so along with overlap this gets a bit complicated. @@ -3187,26 +3189,25 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { if (notifyAll) { if (srcWraps) { u32 validSize = Memory::ValidSize(src, srcSize); - NotifyMemInfo(MemBlockFlags::READ, src, validSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::READ, PSP_GetVidMemBase(), srcSize - validSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, src, validSize, tag, tagSize); + NotifyMemInfo(MemBlockFlags::READ, PSP_GetVidMemBase(), srcSize - validSize, tag, tagSize); } else { - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize); } if (dstWraps) { u32 validSize = Memory::ValidSize(dst, dstSize); - NotifyMemInfo(MemBlockFlags::WRITE, dst, validSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetVidMemBase(), dstSize - validSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dst, validSize, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetVidMemBase(), dstSize - validSize, tag, tagSize); } else { - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize); } } } else if (srcValid && dstValid) { u32 bytesToCopy = width * bpp; - static std::string tag; bool notifyDetail = MemBlockInfoDetailed(bytesToCopy); bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); if (notifyDetail || notifyAll) { - tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); + tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize); } for (int y = 0; y < height; y++) { @@ -3219,14 +3220,14 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { // If we're tracking detail, it's useful to have the gaps illustrated properly. if (notifyDetail) { - NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag, tagSize); } } if (notifyAll) { - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize); } } else { // This seems to cause the GE to require a break/reset on a PSP. From 423fa6d8485b5c853a8d1fe3d0721be8dbf88f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 16:00:31 +0100 Subject: [PATCH 492/715] Couple more FormatMemWriteTagAt --- Core/MemMapHelpers.h | 3 +-- GPU/GPUCommon.cpp | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Core/MemMapHelpers.h b/Core/MemMapHelpers.h index fdee215d03..56a950728c 100644 --- a/Core/MemMapHelpers.h +++ b/Core/MemMapHelpers.h @@ -71,9 +71,8 @@ inline void Memcpy(const u32 to_address, const u32 from_address, const u32 len, if (MemBlockInfoDetailed(len)) { char tagData[128]; if (!tag) { - const std::string srcTag = GetMemWriteTagAt("Memcpy/", from_address, len); + tagLen = FormatMemWriteTagAt(tagData, sizeof(tagData), "Memcpy/", from_address, len); tag = tagData; - tagLen = truncate_cpy(tagData, srcTag.c_str()); } NotifyMemInfo(MemBlockFlags::READ, from_address, len, tag, tagLen); NotifyMemInfo(MemBlockFlags::WRITE, to_address, len, tag, tagLen); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 17692b1cf0..03d80c3c45 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3095,9 +3095,9 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { memcpy(dstp, srcp, bytesToCopy); if (MemBlockInfoDetailed(bytesToCopy)) { - const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, bytesToCopy); - NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag.c_str(), tag.size()); + tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, bytesToCopy); + NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag, tagSize); } } else if ((srcDstOverlap || srcWraps || dstWraps) && (srcValid || srcWraps) && (dstValid || dstWraps)) { // This path means we have either src/dst overlap, OR one or both of src and dst wrap. @@ -3254,8 +3254,9 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags // Since they're identical we don't need to copy. if (dest != src) { if (MemBlockInfoDetailed(size)) { - const std::string tag = GetMemWriteTagAt("GPUMemcpy/", src, size); - Memory::Memcpy(dest, src, size, tag.c_str(), tag.size()); + char tag[128]; + size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUMemcpy/", src, size); + Memory::Memcpy(dest, src, size, tag, tagSize); } else { Memory::Memcpy(dest, src, size, "GPUMemcpy"); } @@ -3266,9 +3267,10 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags } if (MemBlockInfoDetailed(size)) { - const std::string tag = GetMemWriteTagAt("GPUMemcpy/", src, size); - NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dest, size, tag.c_str(), tag.size()); + char tag[128]; + size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUMemcpy/", src, size); + NotifyMemInfo(MemBlockFlags::READ, src, size, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dest, size, tag, tagSize); } InvalidateCache(dest, size, GPU_INVALIDATE_HINT); if (!(flags & GPUCopyFlag::DEBUG_NOTIFIED)) From d02f46cb27b0d91d59101a44afab0c1b1e0ab8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 15:47:29 +0100 Subject: [PATCH 493/715] Minor VertexReader optimizations --- GPU/Common/SoftwareTransformCommon.cpp | 12 ++++++++---- GPU/Common/VertexDecoderCommon.h | 7 +------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 8a3cbb50dd..88dd7c9d3c 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -205,6 +205,9 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt VertexReader reader(decoded, decVtxFormat, vertType); if (throughmode) { + const u32 materialAmbientRGBA = gstate.getMaterialAmbientRGBA(); + const bool hasColor = reader.hasColor0(); + const bool hasUV = reader.hasUV(); for (int index = 0; index < maxIndex; index++) { // Do not touch the coordinates or the colors. No lighting. reader.Goto(index); @@ -213,7 +216,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt reader.ReadPos(vert.pos); vert.pos_w = 1.0f; - if (reader.hasColor0()) { + if (hasColor) { if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) { reader.Goto(index + provokeIndOffset); reader.ReadColor0_8888(vert.color0); @@ -222,10 +225,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt reader.ReadColor0_8888(vert.color0); } } else { - vert.color0_32 = gstate.getMaterialAmbientRGBA(); + vert.color0_32 = materialAmbientRGBA; } - if (reader.hasUV()) { + if (hasUV) { reader.ReadUV(vert.uv); vert.u *= uscale; @@ -240,6 +243,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt // The w of uv is also never used (hardcoded to 1.0.) } } else { + const Vec4f materialAmbientRGBA = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); // Okay, need to actually perform the full transform. for (int index = 0; index < maxIndex; index++) { reader.Goto(index); @@ -267,7 +271,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt if (reader.hasColor0()) reader.ReadColor0(unlitColor.AsArray()); else - unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); + unlitColor = materialAmbientRGBA; if (reader.hasNormal()) reader.ReadNrm(normal.AsArray()); diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index f23db789cc..355343a879 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -166,7 +166,6 @@ public: } break; default: - ERROR_LOG_REPORT_ONCE(fmtnrm, G3D, "Reader: Unsupported Nrm Format %d", decFmt_.nrmfmt); memset(nrm, 0, sizeof(float) * 3); break; } @@ -188,7 +187,6 @@ public: memcpy(color, data_ + decFmt_.c0off, 16); break; default: - ERROR_LOG_REPORT_ONCE(fmtc0, G3D, "Reader: Unsupported C0 Format %d", decFmt_.c0fmt); memset(color, 0, sizeof(float) * 4); break; } @@ -199,8 +197,7 @@ public: case DEC_U8_4: { const u8 *b = (const u8 *)(data_ + decFmt_.c0off); - for (int i = 0; i < 4; i++) - color[i] = b[i]; + memcpy(color, b, 4); } break; case DEC_FLOAT_4: @@ -211,7 +208,6 @@ public: } break; default: - ERROR_LOG_REPORT_ONCE(fmtc0_8888, G3D, "Reader: Unsupported C0 Format %d", decFmt_.c0fmt); memset(color, 0, sizeof(u8) * 4); break; } @@ -231,7 +227,6 @@ public: memcpy(color, data_ + decFmt_.c1off, 12); break; default: - ERROR_LOG_REPORT_ONCE(fmtc1, G3D, "Reader: Unsupported C1 Format %d", decFmt_.c1fmt); memset(color, 0, sizeof(float) * 3); break; } From e6f0f84a45168323a4c878e812aa06b74c9e51c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 16:21:27 +0100 Subject: [PATCH 494/715] SSE optimize Float4ToUint8x4, some uses --- Common/Data/Convert/SmallDataConvert.cpp | 1 + Common/Data/Convert/SmallDataConvert.h | 24 ++++++++++++++++++++++++ GPU/Common/DrawEngineCommon.cpp | 4 ++-- GPU/Common/SoftwareTransformCommon.cpp | 4 ++-- GPU/Common/VertexDecoderCommon.h | 14 ++++++-------- GPU/Software/TransformUnit.cpp | 2 +- 6 files changed, 36 insertions(+), 13 deletions(-) diff --git a/Common/Data/Convert/SmallDataConvert.cpp b/Common/Data/Convert/SmallDataConvert.cpp index 4f0d65ea11..ee2673aba1 100644 --- a/Common/Data/Convert/SmallDataConvert.cpp +++ b/Common/Data/Convert/SmallDataConvert.cpp @@ -1,3 +1,4 @@ #include "Common/Data/Convert/SmallDataConvert.h" alignas(16) const float one_over_255_x4[4] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, }; +alignas(16) const float exactly_255_x4[4] = { 255.0f, 255.0f, 255.0f, 255.0f, }; diff --git a/Common/Data/Convert/SmallDataConvert.h b/Common/Data/Convert/SmallDataConvert.h index 740193e739..1bc6540907 100644 --- a/Common/Data/Convert/SmallDataConvert.h +++ b/Common/Data/Convert/SmallDataConvert.h @@ -18,6 +18,7 @@ #endif extern const float one_over_255_x4[4]; +extern const float exactly_255_x4[4]; // Utilities useful for filling in std140-layout uniform buffers, and similar. // NEON intrinsics: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491f/BABDCGGF.html @@ -46,6 +47,12 @@ inline void Uint8x4ToFloat4(float f[4], uint32_t u) { // Could be SSE optimized. inline uint32_t Float4ToUint8x4(const float f[4]) { +#ifdef _M_SSE + __m128i zero = _mm_setzero_si128(); + __m128 value = _mm_mul_ps(_mm_loadu_ps(f), _mm_load_ps(exactly_255_x4)); + __m128i ivalue = _mm_packus_epi16(_mm_packs_epi32(_mm_cvtps_epi32(value), zero), zero); + return _mm_cvtsi128_si32(ivalue); +#else int i4[4]; for (int i = 0; i < 4; i++) { if (f[i] > 1.0f) { @@ -57,6 +64,23 @@ inline uint32_t Float4ToUint8x4(const float f[4]) { } } return i4[0] | (i4[1] << 8) | (i4[2] << 16) | (i4[3] << 24); +#endif +} + +inline uint32_t Float4ToUint8x4_NoClamp(const float f[4]) { +#ifdef _M_SSE + // Does actually clamp, no way to avoid it with the pack ops! + __m128i zero = _mm_setzero_si128(); + __m128 value = _mm_mul_ps(_mm_loadu_ps(f), _mm_load_ps(exactly_255_x4)); + __m128i ivalue = _mm_packus_epi16(_mm_packs_epi32(_mm_cvtps_epi32(value), zero), zero); + return _mm_cvtsi128_si32(ivalue); +#else + u32 i4[4]; + for (int i = 0; i < 4; i++) { + i4[i] = (int)(f[i] * 255.0f); + } + return i4[0] | (i4[1] << 8) | (i4[2] << 16) | (i4[3] << 24); +#endif } inline void Uint8x3ToFloat4_AlphaUint8(float f[4], uint32_t u, uint8_t alpha) { diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 664b90823e..f5579de741 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -524,7 +524,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, } if (vertType & GE_VTYPE_COL_MASK) { - reader.ReadColor0_8888(sv.color); + sv.color_32 = reader.ReadColor0_8888(); } else { memcpy(sv.color, defaultColor, 4); } @@ -573,7 +573,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, sv.uv[1] = 0.0f; } if (vertType & GE_VTYPE_COL_MASK) { - reader.ReadColor0_8888(sv.color); + sv.color_32 = reader.ReadColor0_8888(); } else { memcpy(sv.color, defaultColor, 4); } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 88dd7c9d3c..b85dc342d7 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -219,10 +219,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt if (hasColor) { if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) { reader.Goto(index + provokeIndOffset); - reader.ReadColor0_8888(vert.color0); + vert.color0_32 = reader.ReadColor0_8888(); reader.Goto(index); } else { - reader.ReadColor0_8888(vert.color0); + vert.color0_32 = reader.ReadColor0_8888(); } } else { vert.color0_32 = materialAmbientRGBA; diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 355343a879..6ebad221d3 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -192,28 +192,27 @@ public: } } - void ReadColor0_8888(u8 color[4]) const { + u32 ReadColor0_8888() const { switch (decFmt_.c0fmt) { case DEC_U8_4: { const u8 *b = (const u8 *)(data_ + decFmt_.c0off); - memcpy(color, b, 4); + u32 value; + memcpy(&value, b, 4); + return value; } break; case DEC_FLOAT_4: { const float *f = (const float *)(data_ + decFmt_.c0off); - for (int i = 0; i < 4; i++) - color[i] = f[i] * 255.0f; + return Float4ToUint8x4_NoClamp(f); } break; default: - memset(color, 0, sizeof(u8) * 4); - break; + return 0; } } - void ReadColor1(float color[3]) const { switch (decFmt_.c1fmt) { case DEC_U8_4: @@ -281,7 +280,6 @@ public: case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; default: - ERROR_LOG_REPORT_ONCE(fmtw1, G3D, "Reader: Unsupported W1 Format %d", decFmt_.w1fmt); memset(weights + 4, 0, sizeof(float) * 4); break; } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index ac8ea921a8..0119250316 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -344,7 +344,7 @@ ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformS normal = -normal; if (vreader.hasColor0()) { - vreader.ReadColor0_8888((u8 *)&vertex.v.color0); + vertex.v.color0 = vreader.ReadColor0_8888(); } else { vertex.v.color0 = gstate.getMaterialAmbientRGBA(); } From d0e8cfa36518ba69fa9f6f550b7e26b9aaca0529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 17:09:54 +0100 Subject: [PATCH 495/715] Add NEON impl too, mostly for exercise purposes --- Common/Data/Convert/SmallDataConvert.h | 14 ++++++++++++++ unittest/UnitTest.cpp | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/Common/Data/Convert/SmallDataConvert.h b/Common/Data/Convert/SmallDataConvert.h index 1bc6540907..05f92759c7 100644 --- a/Common/Data/Convert/SmallDataConvert.h +++ b/Common/Data/Convert/SmallDataConvert.h @@ -52,6 +52,13 @@ inline uint32_t Float4ToUint8x4(const float f[4]) { __m128 value = _mm_mul_ps(_mm_loadu_ps(f), _mm_load_ps(exactly_255_x4)); __m128i ivalue = _mm_packus_epi16(_mm_packs_epi32(_mm_cvtps_epi32(value), zero), zero); return _mm_cvtsi128_si32(ivalue); +#elif PPSSPP_ARCH(ARM_NEON) + const float32x4_t value = vmulq_f32(vld1q_f32(f), vdupq_n_f32(255.0f)); + uint32x4_t ivalue32 = vcvtq_u32_f32(value); + uint16x4_t ivalue16 = vqmovn_u32(ivalue32); + uint8x8_t ivalue8 = vqmovn_u16(vcombine_u16(ivalue16, ivalue16)); // Is there no way to avoid the combine here? + uint32x2_t outValue32 = vreinterpret_u8_u32(ivalue8); + return vget_lane_u32(outValue32, 0); #else int i4[4]; for (int i = 0; i < 4; i++) { @@ -74,6 +81,13 @@ inline uint32_t Float4ToUint8x4_NoClamp(const float f[4]) { __m128 value = _mm_mul_ps(_mm_loadu_ps(f), _mm_load_ps(exactly_255_x4)); __m128i ivalue = _mm_packus_epi16(_mm_packs_epi32(_mm_cvtps_epi32(value), zero), zero); return _mm_cvtsi128_si32(ivalue); +#elif PPSSPP_ARCH(ARM_NEON) + const float32x4_t value = vmulq_f32(vld1q_f32(f), vdupq_n_f32(255.0f)); + uint32x4_t ivalue32 = vcvtq_u32_f32(value); + uint16x4_t ivalue16 = vqmovn_u32(ivalue32); + uint8x8_t ivalue8 = vqmovn_u16(vcombine_u16(ivalue16, ivalue16)); // Is there no way to avoid the combine here? + uint32x2_t outValue32 = vreinterpret_u8_u32(ivalue8); + return vget_lane_u32(outValue32, 0); #else u32 i4[4]; for (int i = 0; i < 4; i++) { diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index bb3d9d112b..1284584607 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -41,6 +41,7 @@ #endif #include "Common/Data/Collections/TinySet.h" +#include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Data/Text/Parsers.h" #include "Common/Data/Text/WrapText.h" #include "Common/Data/Encoding/Utf8.h" @@ -782,6 +783,15 @@ static bool TestWrapText() { return true; } +static bool TestSmallDataConvert() { + float f[4] = { 1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.f }; + uint32_t result = Float4ToUint8x4_NoClamp(f); + EXPECT_EQ_HEX(result, 0x04030201); + result = Float4ToUint8x4(f); + EXPECT_EQ_HEX(result, 0x04030201); + return true; +} + typedef bool (*TestFunc)(); struct TestItem { const char *name; @@ -832,6 +842,7 @@ TestItem availableTests[] = { TEST_ITEM(ThreadManager), TEST_ITEM(WrapText), TEST_ITEM(TinySet), + TEST_ITEM(SmallDataConvert), }; int main(int argc, const char *argv[]) { From 331d024a8c074896862b59cc1222f48a8c5dba06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 19:15:38 +0100 Subject: [PATCH 496/715] Add a flags parameter to InvalidateCachedState and rename it Invalidate. Also rename the old InvalidationFlags enum to InvalidateCallbackFlags. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 28 ++++++++++++----------- Common/GPU/D3D9/thin3d_d3d9.cpp | 10 ++++---- Common/GPU/MiscTypes.h | 11 ++++++--- Common/GPU/OpenGL/GLRenderManager.cpp | 2 +- Common/GPU/OpenGL/thin3d_gl.cpp | 22 ++++++++++-------- Common/GPU/Vulkan/VulkanRenderManager.cpp | 4 ++-- Common/GPU/Vulkan/VulkanRenderManager.h | 2 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 26 +++++++++++---------- Common/GPU/thin3d.h | 2 +- GPU/Common/Draw2D.cpp | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 14 ++++++------ GPU/Common/PresentationCommon.cpp | 4 ++-- GPU/Common/StencilCommon.cpp | 2 +- GPU/Common/TextureCacheCommon.cpp | 6 ++--- GPU/D3D11/DrawEngineD3D11.cpp | 4 ++-- GPU/D3D11/DrawEngineD3D11.h | 2 +- GPU/D3D11/GPU_D3D11.cpp | 2 +- GPU/Directx9/DrawEngineDX9.cpp | 4 ++-- GPU/Directx9/DrawEngineDX9.h | 2 +- GPU/GLES/DrawEngineGLES.cpp | 4 ++-- GPU/GLES/DrawEngineGLES.h | 2 +- GPU/GPUCommon.cpp | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 6 ++--- GPU/Vulkan/DrawEngineVulkan.h | 2 +- 24 files changed, 89 insertions(+), 76 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index c4d4c11f0a..25cb495d0b 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -99,7 +99,7 @@ public: void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; - void InvalidateCachedState() override; + void Invalidate(InvalidationFlags flags) override; void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int index, void *nativeTexture) override; @@ -1080,17 +1080,19 @@ void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { context_->Unmap(curPipeline_->dynamicUniforms, 0); } -void D3D11DrawContext::InvalidateCachedState() { - // This is a signal to forget all our state caching. - curBlend_ = nullptr; - curDepthStencil_ = nullptr; - curRaster_ = nullptr; - curPS_ = nullptr; - curVS_ = nullptr; - curGS_ = nullptr; - curInputLayout_ = nullptr; - curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; - curPipeline_ = nullptr; +void D3D11DrawContext::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + // This is a signal to forget all our state caching. + curBlend_ = nullptr; + curDepthStencil_ = nullptr; + curRaster_ = nullptr; + curPS_ = nullptr; + curVS_ = nullptr; + curGS_ = nullptr; + curInputLayout_ = nullptr; + curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + curPipeline_ = nullptr; + } } void D3D11DrawContext::BindPipeline(Pipeline *pipeline) { @@ -1698,7 +1700,7 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren } if (invalidationCallback_) { - invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); } } diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 26f3abfe90..8b4fb80312 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -610,7 +610,7 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - void InvalidateCachedState() override; + void Invalidate(InvalidationFlags flags) override; void SetInvalidationCallback(InvalidationCallback callback) override { invalidationCallback_ = callback; @@ -650,8 +650,10 @@ private: InvalidationCallback invalidationCallback_; }; -void D3D9Context::InvalidateCachedState() { - curPipeline_ = nullptr; +void D3D9Context::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + curPipeline_ = nullptr; + } } // TODO: Move this detection elsewhere when it's needed elsewhere, not before. It's ugly. @@ -1323,7 +1325,7 @@ void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPa dxstate.viewport.restore(); if (invalidationCallback_) { - invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); } } diff --git a/Common/GPU/MiscTypes.h b/Common/GPU/MiscTypes.h index fd3d90dbb5..0db111a73d 100644 --- a/Common/GPU/MiscTypes.h +++ b/Common/GPU/MiscTypes.h @@ -3,9 +3,14 @@ #include "Common/Common.h" enum class InvalidationFlags { - RENDER_PASS_STATE = 1, - COMMAND_BUFFER_STATE = 2, + CACHED_RENDER_STATE = 1, }; ENUM_CLASS_BITOPS(InvalidationFlags); -typedef std::function InvalidationCallback; +enum class InvalidationCallbackFlags { + RENDER_PASS_STATE = 1, + COMMAND_BUFFER_STATE = 2, +}; +ENUM_CLASS_BITOPS(InvalidationCallbackFlags); + +typedef std::function InvalidationCallback; diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index 034f4c672e..f66b9b78fc 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -356,7 +356,7 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende } if (invalidationCallback_) { - invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); } } diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 0c9afd6869..2842e7bffd 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -467,7 +467,7 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override {} - void InvalidateCachedState() override; + void Invalidate(InvalidationFlags flags) override; void SetInvalidationCallback(InvalidationCallback callback) override { renderManager_.SetInvalidationCallback(callback); @@ -761,18 +761,20 @@ void OpenGLContext::EndFrame() { renderManager_.EndPushBuffer(frameData.push); // upload the data! renderManager_.Finish(); - InvalidateCachedState(); + Invalidate(InvalidationFlags::CACHED_RENDER_STATE); } -void OpenGLContext::InvalidateCachedState() { - // Unbind stuff. - for (auto &texture : boundTextures_) { - texture = nullptr; +void OpenGLContext::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + // Unbind stuff. + for (auto &texture : boundTextures_) { + texture = nullptr; + } + for (auto &sampler : boundSamplers_) { + sampler = nullptr; + } + curPipeline_ = nullptr; } - for (auto &sampler : boundSamplers_) { - sampler = nullptr; - } - curPipeline_ = nullptr; } InputLayout *OpenGLContext::CreateInputLayout(const InputLayoutDesc &desc) { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 2b67cbfeb9..98fb8a3edf 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -752,7 +752,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR } if (invalidationCallback_) { - invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); } } @@ -1213,7 +1213,7 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { // Called from main thread. void VulkanRenderManager::FlushSync() { if (invalidationCallback_) { - invalidationCallback_(InvalidationFlags::COMMAND_BUFFER_STATE); + invalidationCallback_(InvalidationCallbackFlags::COMMAND_BUFFER_STATE); } int curFrame = vulkan_->GetCurFrame(); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index de36633c67..fcc843535a 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -526,5 +526,5 @@ private: SimpleStat totalGPUTimeMs_; SimpleStat renderCPUTimeMs_; - std::function invalidationCallback_; + std::function invalidationCallback_; }; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 46be4cf00b..0fc2acbf17 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -498,7 +498,7 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - void InvalidateCachedState() override; + void Invalidate(InvalidationFlags flags) override; void InvalidateFramebuffer(FBInvalidationStage stage, uint32_t channels) override; @@ -1021,20 +1021,22 @@ void VKContext::EndFrame() { push_ = nullptr; // Unbind stuff, to avoid accidentally relying on it across frames (and provide some protection against forgotten unbinds of deleted things). - InvalidateCachedState(); + Invalidate(InvalidationFlags::CACHED_RENDER_STATE); } -void VKContext::InvalidateCachedState() { - curPipeline_ = nullptr; +void VKContext::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + curPipeline_ = nullptr; - for (auto &view : boundImageView_) { - view = VK_NULL_HANDLE; - } - for (auto &sampler : boundSamplers_) { - sampler = nullptr; - } - for (auto &texture : boundTextures_) { - texture = nullptr; + for (auto &view : boundImageView_) { + view = VK_NULL_HANDLE; + } + for (auto &sampler : boundSamplers_) { + sampler = nullptr; + } + for (auto &texture : boundTextures_) { + texture = nullptr; + } } } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 6d58a10298..f36e0cf872 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -737,7 +737,7 @@ public: // Clear state cached within thin3d. Must be called after directly calling API functions. // Note that framebuffer state (which framebuffer is bounds) may not be cached. // Must not actually perform any API calls itself since this can be called when no framebuffer is bound for rendering. - virtual void InvalidateCachedState() = 0; + virtual void Invalidate(InvalidationFlags flags) = 0; virtual void BindPipeline(Pipeline *pipeline) = 0; diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 2b81178233..b8b3722610 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -330,7 +330,7 @@ void Draw2D::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCoun draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, linearFilter ? &draw2DSamplerLinear_ : &draw2DSamplerNearest_); draw_->DrawUP(verts, vertexCount); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE | DIRTY_VERTEXSHADER_STATE); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 7a18fc127c..05521c047e 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -664,7 +664,7 @@ void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFra // for (auto &source : sources) { if (!sources.empty()) { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); auto &source = sources.back(); if (source.channel == RASTER_DEPTH) { @@ -804,7 +804,7 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra std::sort(sources.begin(), sources.end()); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); bool tookActions = false; @@ -961,7 +961,7 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir RebindFramebuffer("After BlitFramebufferDepth"); } - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); } void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) { @@ -1137,7 +1137,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int gpuStats.numUploads++; pixelsTex->Release(); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } @@ -2777,7 +2777,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, } } - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); textureCache_->ForgetLastTexture(); RebindFramebuffer("RebindFramebuffer - ReadFramebufferToMemory"); } @@ -2840,7 +2840,7 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo } void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); shaderManager_->DirtyLastShader(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); @@ -3064,7 +3064,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false, dst->renderScaleFactor, pipeline, tag); } - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 0c3030b63c..5980bbb95e 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -605,7 +605,7 @@ void PresentationCommon::UpdateUniforms(bool hasVideo) { } void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); // TODO: If shader objects have been created by now, we might have received errors. // GLES can have the shader fail later, shader->failed / shader->error. @@ -869,7 +869,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u DoRelease(srcTexture_); // Unbinds all textures and samplers too, needed since sometimes a MakePixelTexture is deleted etc. - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); previousUniforms_ = uniforms; } diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index c879154e46..31c10ecaba 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -357,7 +357,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, } tex->Release(); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); return true; } diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index a6c1582606..f5e7bc2889 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -2187,7 +2187,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer CheckAlphaResult alphaStatus = CheckCLUTAlpha((const uint8_t *)clutBufRaw_, clutFormat, clutTotalColors); gstate_c.SetTextureFullAlpha(alphaStatus == CHECKALPHA_FULL); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); InvalidateLastTexture(); return; } @@ -2262,7 +2262,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer CheckAlphaResult alphaStatus = CheckCLUTAlpha((const uint8_t *)clutBufRaw_, clutFormat, clutTotalColors); gstate_c.SetTextureFullAlpha(alphaStatus == CHECKALPHA_FULL); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); shaderManager_->DirtyLastShader(); } else { framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); @@ -2363,7 +2363,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { // We don't know about alpha at all. gstate_c.SetTextureFullAlpha(false); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); shaderManager_->DirtyLastShader(); SamplerCacheKey samplerKey = GetFramebufferSamplingParams(texWidth, texHeight); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 3d66b8c37d..304d325ea9 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -327,8 +327,8 @@ VertexArrayInfoD3D11::~VertexArrayInfoD3D11() { } // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. -void DrawEngineD3D11::Invalidate(InvalidationFlags flags) { - if (flags & InvalidationFlags::RENDER_PASS_STATE) { +void DrawEngineD3D11::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); } } diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 8245cae6a4..468c8cd3bb 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -155,7 +155,7 @@ public: void ClearInputLayoutMap(); private: - void Invalidate(InvalidationFlags flags); + void Invalidate(InvalidationCallbackFlags flags); void DoFlush(); diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 734e703dfc..8259d9fb5c 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -131,7 +131,7 @@ void GPU_D3D11::BuildReportingInfo() { } void GPU_D3D11::DeviceLost() { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); // Simply drop all caches and textures. // FBOs appear to survive? Or no? shaderManagerD3D11_->ClearShaders(); diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index e22d5577d2..c1123b05d5 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -312,8 +312,8 @@ void DrawEngineDX9::BeginFrame() { } // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. -void DrawEngineDX9::Invalidate(InvalidationFlags flags) { - if (flags & InvalidationFlags::RENDER_PASS_STATE) { +void DrawEngineDX9::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); } } diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index aa2baf5cfc..3bc7222a67 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -144,7 +144,7 @@ protected: void DecimateTrackedVertexArrays(); private: - void Invalidate(InvalidationFlags flags); + void Invalidate(InvalidationCallbackFlags flags); void DoFlush(); void ApplyDrawState(int prim); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 56051f6a35..2907929f12 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -247,8 +247,8 @@ void *DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bind // A new render step means we need to flush any dynamic state. Really, any state that is reset in // GLQueueRunner::PerformRenderPass. -void DrawEngineGLES::Invalidate(InvalidationFlags flags) { - if (flags & InvalidationFlags::RENDER_PASS_STATE) { +void DrawEngineGLES::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { // Dirty everything that has dynamic state that will need re-recording. gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); } diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index ed8e18f292..a1a8adce97 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -116,7 +116,7 @@ protected: bool UpdateUseHWTessellation(bool enable) override; private: - void Invalidate(InvalidationFlags flags); + void Invalidate(InvalidationCallbackFlags flags); void InitDeviceObjects(); void DestroyDeviceObjects(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index cd3aaeb9d7..b807018464 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -492,7 +492,7 @@ void GPUCommon::BeginHostFrame() { void GPUCommon::EndHostFrame() { // Probably not necessary. if (draw_) { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); } } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 8256ea8916..fdb9c263f7 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -544,11 +544,11 @@ void MarkUnreliable(VertexArrayInfoVulkan *vai) { // For now we just leave it in the pushbuffer. } -void DrawEngineVulkan::Invalidate(InvalidationFlags flags) { - if (flags & InvalidationFlags::COMMAND_BUFFER_STATE) { +void DrawEngineVulkan::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::COMMAND_BUFFER_STATE) { GetCurFrame().frameDescSetUpdated = false; } - if (flags & InvalidationFlags::RENDER_PASS_STATE) { + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { // If have a new render pass, dirty our dynamic state so it gets re-set. // // Dirty everything that has dynamic state that will need re-recording. diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index d9f1339e5b..239be55390 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -209,7 +209,7 @@ public: } private: - void Invalidate(InvalidationFlags flags); + void Invalidate(InvalidationCallbackFlags flags); struct FrameData; void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant); From 6daecb4e2b797c3711b6eaa9d95b81755e0f9976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 10:13:05 +0100 Subject: [PATCH 497/715] Add check for tiling GPUs. We'll use this to inform on what MSAA modes to support. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 2 ++ Common/GPU/D3D9/thin3d_d3d9.cpp | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 4 ++++ Common/GPU/Vulkan/VulkanContext.cpp | 20 ++++++++++---------- Common/GPU/Vulkan/VulkanContext.h | 7 ++++++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 8 ++++++++ Common/GPU/thin3d.h | 1 + 7 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 25cb495d0b..c0b527fa2b 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -309,6 +309,8 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de dxgiDevice->Release(); } + caps_.isTilingGPU = false; + // Temp texture for read-back of small images. Custom textures are created on demand for larger ones. // TODO: Should really benchmark if this extra complexity has any benefit. D3D11_TEXTURE2D_DESC packDesc{}; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 8b4fb80312..dce9f66335 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -763,6 +763,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.fragmentShaderDepthWriteSupported = true; caps_.fragmentShaderStencilWriteSupported = false; caps_.blendMinMaxSupported = true; + caps_.isTilingGPU = false; if ((caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && caps.MaxAnisotropy > 1) { caps_.anisoSupported = true; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 2842e7bffd..61df0bdaee 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -601,6 +601,10 @@ OpenGLContext::OpenGLContext() { caps_.vendor = GPUVendor::VENDOR_UNKNOWN; break; } + + // Very rough heuristic! + caps_.isTilingGPU = gl_extensions.IsGLES && caps_.vendor != GPUVendor::VENDOR_NVIDIA && caps_.vendor != GPUVendor::VENDOR_INTEL; + for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { frameData_[i].push = renderManager_.CreatePushBuffer(i, GL_ARRAY_BUFFER, 64 * 1024); } diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 19ecb40588..6c121adf66 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -329,7 +329,7 @@ bool VulkanContext::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirem for (uint32_t i = 0; i < 32; i++) { if ((typeBits & 1) == 1) { // Type is available, does it match user properties? - if ((memory_properties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { + if ((memory_properties_.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { *typeIndex = i; return true; } @@ -569,17 +569,17 @@ void VulkanContext::ChooseDevice(int physical_device) { } // This is as good a place as any to do this. - vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties); - INFO_LOG(G3D, "Memory Types (%d):", memory_properties.memoryTypeCount); - for (int i = 0; i < (int)memory_properties.memoryTypeCount; i++) { + vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties_); + INFO_LOG(G3D, "Memory Types (%d):", memory_properties_.memoryTypeCount); + for (int i = 0; i < (int)memory_properties_.memoryTypeCount; i++) { // Don't bother printing dummy memory types. - if (!memory_properties.memoryTypes[i].propertyFlags) + if (!memory_properties_.memoryTypes[i].propertyFlags) continue; - INFO_LOG(G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL " : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE " : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED " : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT " : ""); + INFO_LOG(G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties_.memoryTypes[i].heapIndex, + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL " : "", + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE " : "", + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED " : "", + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT " : ""); } // Optional features diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index a6f568aa5f..003546a59d 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -283,6 +283,10 @@ public: return device_extensions_enabled_; } + const VkPhysicalDeviceMemoryProperties &GetMemoryProperties() const { + return memory_properties_; + } + struct PhysicalDeviceFeatures { AllPhysicalDeviceFeatures available{}; AllPhysicalDeviceFeatures enabled{}; @@ -401,7 +405,8 @@ private: uint32_t graphics_queue_family_index_ = -1; std::vector physicalDeviceProperties_; std::vector queueFamilyProperties_; - VkPhysicalDeviceMemoryProperties memory_properties{}; + + VkPhysicalDeviceMemoryProperties memory_properties_{}; // Custom collection of things that are good to know VulkanPhysicalDeviceInfo deviceInfo_{}; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index f52cc51ab4..74ec191570 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -845,6 +845,14 @@ VKContext::VKContext(VulkanContext *vulkan) default: caps_.vendor = GPUVendor::VENDOR_UNKNOWN; break; } + bool hasLazyMemory = false; + for (u32 i = 0; i < vulkan->GetMemoryProperties().memoryTypeCount; i++) { + if (vulkan->GetMemoryProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) { + hasLazyMemory = true; + } + } + caps_.isTilingGPU = hasLazyMemory; + if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { // Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off. // See: https://github.com/hrydgard/ppsspp/pull/11684 diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index f36e0cf872..e49411bc6f 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -576,6 +576,7 @@ struct DeviceCaps { bool textureDepthSupported; bool blendMinMaxSupported; bool multiViewSupported; + bool isTilingGPU; // This means that it benefits from correct store-ops, msaa without backing memory, etc. std::string deviceName; // The device name to use when creating the thin3d context, to get the same one. }; From 06af304c8dd670eafa0618de0b5683b9ad1745ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 11:39:44 +0100 Subject: [PATCH 498/715] Multisampling groundwork --- Common/GPU/Vulkan/VulkanFramebuffer.cpp | 133 ++++++++++++++++------ Common/GPU/Vulkan/VulkanFramebuffer.h | 20 +++- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 10 +- Common/GPU/Vulkan/VulkanRenderManager.cpp | 12 +- Common/GPU/Vulkan/VulkanRenderManager.h | 2 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 11 +- Common/GPU/thin3d.h | 1 + Core/Config.cpp | 1 + Core/Config.h | 1 + GPU/Common/FramebufferManagerCommon.cpp | 10 +- GPU/Common/PresentationCommon.cpp | 4 +- GPU/Common/TextureCacheCommon.cpp | 1 + GPU/Vulkan/PipelineManagerVulkan.cpp | 9 +- 13 files changed, 157 insertions(+), 58 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 8f277cf676..0de8f76a3c 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -2,14 +2,41 @@ #include "Common/GPU/Vulkan/VulkanFramebuffer.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" -VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag) +VkSampleCountFlagBits SampleCountToFlagBits(int count) { + // TODO: Check hardware support here, or elsewhere? + // Some hardware only supports 4x. + switch (count) { + case 1: return VK_SAMPLE_COUNT_1_BIT; + case 2: return VK_SAMPLE_COUNT_2_BIT; + case 4: return VK_SAMPLE_COUNT_4_BIT; + case 8: return VK_SAMPLE_COUNT_8_BIT; + case 16: return VK_SAMPLE_COUNT_16_BIT; // rare + default: + _assert_(false); + return VK_SAMPLE_COUNT_1_BIT; + } +} + +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _numSamples, bool createDepthStencilBuffer, const char *tag) : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { _dbg_assert_(tag); - CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); if (createDepthStencilBuffer) { - CreateImage(vulkan_, initCmd, depth, width, height, numLayers, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + CreateImage(vulkan_, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + } + + if (_numSamples > 1) { + sampleCount = SampleCountToFlagBits(_numSamples); + + // TODO: Create a different tag for these? + CreateImage(vulkan_, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + if (createDepthStencilBuffer) { + CreateImage(vulkan_, initCmd, depth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + } + } else { + sampleCount = VK_SAMPLE_COUNT_1_BIT; } UpdateTag(tag); @@ -55,7 +82,7 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas } views[1] = depth.rtView; } - fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); + fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType, sampleCount); fbci.attachmentCount = hasDepth ? 2 : 1; fbci.pAttachments = views; fbci.width = width; @@ -108,7 +135,7 @@ VKRFramebuffer::~VKRFramebuffer() { // NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. // This requires a different sampling path! -void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { +void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { // We don't support more exotic layer setups for now. Mono or stereo. _dbg_assert_(numLayers == 1 || numLayers == 2); @@ -120,7 +147,7 @@ void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKR ici.extent.depth = 1; ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; ici.imageType = VK_IMAGE_TYPE_2D; - ici.samples = VK_SAMPLE_COUNT_1_BIT; + ici.samples = sampleCount; ici.tiling = VK_IMAGE_TILING_OPTIMAL; ici.format = format; // Strictly speaking we don't yet need VK_IMAGE_USAGE_SAMPLED_BIT for depth buffers since we do not yet sample depth buffers. @@ -226,45 +253,76 @@ static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) { // Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 // Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies -VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) { +VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType, VkSampleCountFlagBits sampleCount) { bool selfDependency = RenderPassTypeHasInput(rpType); bool isBackbuffer = rpType == RenderPassType::BACKBUFFER; bool hasDepth = RenderPassTypeHasDepth(rpType); bool multiview = RenderPassTypeHasMultiView(rpType); + bool multisample = rpType & RenderPassType::MULTISAMPLE; if (multiview) { // TODO: Assert that the device has multiview support enabled. } - VkAttachmentDescription attachments[2] = {}; - attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = ConvertLoadAction(key.colorLoadAction); - attachments[0].storeOp = ConvertStoreAction(key.colorStoreAction); - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].flags = 0; + int colorAttachmentIndex = 0; + int depthAttachmentIndex = 1; + + int attachmentCount = 0; + VkAttachmentDescription attachments[4]{}; + attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; + attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.colorLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction); + attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[attachmentCount].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentCount++; if (hasDepth) { - attachments[1].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; - attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[1].loadOp = ConvertLoadAction(key.depthLoadAction); - attachments[1].storeOp = ConvertStoreAction(key.depthStoreAction); - attachments[1].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); - attachments[1].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); - attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].flags = 0; + attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; + attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.depthLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction); + attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); + attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); + attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachmentCount++; + } + + if (multisample) { + colorAttachmentIndex = attachmentCount; + attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; + attachments[attachmentCount].samples = sampleCount; + attachments[attachmentCount].loadOp = ConvertLoadAction(key.colorLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction); + attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentCount++; + + if (hasDepth) { + depthAttachmentIndex = attachmentCount; + attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; + attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[attachmentCount].loadOp = ConvertLoadAction(key.depthLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction); + attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); + attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); + attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachmentCount++; + } } VkAttachmentReference color_reference{}; - color_reference.attachment = 0; + color_reference.attachment = colorAttachmentIndex; color_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentReference depth_reference{}; - depth_reference.attachment = 1; + depth_reference.attachment = depthAttachmentIndex; depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass{}; @@ -279,7 +337,14 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas } subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_reference; - subpass.pResolveAttachments = nullptr; + + VkAttachmentReference resolve_references[2]; + if (multisample) { + resolve_references[0].attachment = 0; // the non-msaa color buffer. + subpass.pResolveAttachments = resolve_references; + } else { + subpass.pResolveAttachments = nullptr; + } if (hasDepth) { subpass.pDepthStencilAttachment = &depth_reference; } @@ -291,7 +356,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas size_t numDeps = 0; VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; - rp.attachmentCount = hasDepth ? 2 : 1; + rp.attachmentCount = attachmentCount; rp.pAttachments = attachments; rp.subpassCount = 1; rp.pSubpasses = &subpass; @@ -342,12 +407,16 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas return pass; } -VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType) { +VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount) { // When we create a render pass, we create all "types" of it immediately, // practical later when referring to it. Could change to on-demand if it feels motivated // but I think the render pass objects are cheap. + + // WARNING: We don't include sampleCount in the key, there's only the distinction multisampled or not + // which comes from the rpType. + // So you CAN NOT mix and match different non-one sample counts. if (!pass[(int)rpType]) { - pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType); + pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType, sampleCount); } return pass[(int)rpType]; } diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.h b/Common/GPU/Vulkan/VulkanFramebuffer.h index c52e933640..0247410df9 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.h +++ b/Common/GPU/Vulkan/VulkanFramebuffer.h @@ -15,12 +15,13 @@ enum class RenderPassType { HAS_DEPTH = 1, COLOR_INPUT = 2, // input attachment MULTIVIEW = 4, + MULTISAMPLE = 8, // This is the odd one out, and gets special handling in MergeRPTypes. // If this flag is set, none of the other flags can be set. // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible // so we don't bother with a non-depth version. - BACKBUFFER = 8, + BACKBUFFER = 16, TYPE_COUNT = BACKBUFFER + 1, }; @@ -54,7 +55,7 @@ struct VKRImage { class VKRFramebuffer { public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag); + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _numSamples, bool createDepthStencilBuffer, const char *tag); ~VKRFramebuffer(); VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); @@ -62,10 +63,15 @@ public: int width = 0; int height = 0; int numLayers = 0; + VkSampleCountFlagBits sampleCount; VKRImage color{}; // color.image is always there. VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE. + // These are only initialized and used if numSamples > 1. + VKRImage msaaColor{}; + VKRImage msaaDepth{}; + const char *Tag() const { return tag_.c_str(); } @@ -76,13 +82,13 @@ public: return depth.image != VK_NULL_HANDLE; } - // TODO: Hide. - VulkanContext *vulkan_; + VulkanContext *Vulkan() const { return vulkan_; } private: - static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); + static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{}; + VulkanContext *vulkan_; std::string tag_; }; @@ -98,6 +104,8 @@ inline bool RenderPassTypeHasMultiView(RenderPassType type) { return (type & RenderPassType::MULTIVIEW) != 0; } +VkSampleCountFlagBits SampleCountToFlagBits(int count); + // Must be the same order as Draw::RPAction enum class VKRRenderPassLoadAction : uint8_t { KEEP, // default. avoid when possible. @@ -124,7 +132,7 @@ class VKRRenderPass { public: VKRRenderPass(const RPKey &key) : key_(key) {} - VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType); + VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount); void Destroy(VulkanContext *vulkan) { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (pass[i]) { diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 617c349b79..7f7d9e8717 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -198,7 +198,7 @@ bool VulkanQueueRunner::InitBackbufferFramebuffers(int width, int height) { VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view }; VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RenderPassType::BACKBUFFER); + fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT); fb_info.attachmentCount = 2; fb_info.pAttachments = attachments; fb_info.width = width; @@ -1323,7 +1323,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c // Maybe a middle pass. But let's try to just block and compile here for now, this doesn't // happen all that much. graphicsPipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); - graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType), rpType); + graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType, step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT), rpType); } VkPipeline pipeline = graphicsPipeline->pipeline[(size_t)rpType]->BlockUntilReady(); @@ -1523,6 +1523,8 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR bool hasDepth = RenderPassTypeHasDepth(step.render.renderPassType); + VkSampleCountFlagBits sampleCount; + if (step.render.framebuffer) { _dbg_assert_(step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED); _dbg_assert_(step.render.finalDepthStencilLayout != VK_IMAGE_LAYOUT_UNDEFINED); @@ -1535,6 +1537,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR VKRFramebuffer *fb = step.render.framebuffer; framebuf = fb->Get(renderPass, step.render.renderPassType); + sampleCount = fb->sampleCount; _dbg_assert_(framebuf != VK_NULL_HANDLE); w = fb->width; h = fb->height; @@ -1590,10 +1593,11 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR numClearVals = hasDepth ? 2 : 1; // We might do depth-less backbuffer in the future, though doubtful of the value. clearVal[1].depthStencil.depth = 0.0f; clearVal[1].depthStencil.stencil = 0; + sampleCount = VK_SAMPLE_COUNT_1_BIT; } VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; - rp_begin.renderPass = renderPass->Get(vulkan_, step.render.renderPassType); + rp_begin.renderPass = renderPass->Get(vulkan_, step.render.renderPassType, sampleCount); rp_begin.framebuffer = framebuf; VkRect2D rc = step.render.renderArea; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 98fb8a3edf..294f8d40d5 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -481,7 +481,7 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { return frameData_[curFrame].GetInitCmd(vulkan_); } -VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, const char *tag) { +VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag) { VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(); _dbg_assert_(desc->vertexShader); _dbg_assert_(desc->fragmentShader); @@ -523,7 +523,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe } pipeline->pipeline[i] = Promise::CreateEmpty(); - compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType), rpType)); + compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType, sampleCount), rpType)); needsCompile = true; } if (needsCompile) @@ -575,17 +575,23 @@ void VulkanRenderManager::EndCurRenderStep() { if (curRenderStep_->render.framebuffer->numLayers > 1) { rpType = (RenderPassType)(rpType | RenderPassType::MULTIVIEW); } + + if (curRenderStep_->render.framebuffer->sampleCount != VK_SAMPLE_COUNT_1_BIT) { + rpType = (RenderPassType)(rpType | RenderPassType::MULTISAMPLE); + } } VKRRenderPass *renderPass = queueRunner_.GetRenderPass(key); curRenderStep_->render.renderPassType = rpType; + VkSampleCountFlagBits sampleCount = curRenderStep_->render.framebuffer ? curRenderStep_->render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; + compileMutex_.lock(); bool needsCompile = false; for (VKRGraphicsPipeline *pipeline : pipelinesToCheck_) { if (!pipeline->pipeline[(size_t)rpType]) { pipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); - compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType), rpType)); + compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType, sampleCount), rpType)); needsCompile = true; } } diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index fcc843535a..2e5cc1a1a5 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -217,7 +217,7 @@ public: // We delay creating pipelines until the end of the current render pass, so we can create the right type immediately. // Unless a variantBitmask is passed in, in which case we can just go ahead. // WARNING: desc must stick around during the lifetime of the pipeline! It's not enough to build it on the stack and drop it. - VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, const char *tag); + VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag); VKRComputePipeline *CreateComputePipeline(VKRComputePipelineDesc *desc); void NudgeCompilerThread() { diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 74ec191570..b944a1962c 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1210,7 +1210,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; raster->ToVulkan(&gDesc.rs); - pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, tag ? tag : "thin3d"); + pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, tag ? tag : "thin3d"); if (desc.uniformDesc) { pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize; @@ -1569,7 +1569,7 @@ public: } ~VKFramebuffer() { _assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?"); - buf_->vulkan_->Delete().QueueCallback([](void *fb) { + buf_->Vulkan()->Delete().QueueCallback([](void *fb) { VKRFramebuffer *vfb = static_cast(fb); delete vfb; }, buf_); @@ -1584,8 +1584,13 @@ private: }; Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { + _assert_(desc.numSamples > 0); + _assert_(desc.numLayers > 0); + _assert_(desc.width > 0); + _assert_(desc.height > 0); + VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.z_stencil, desc.tag); + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.numSamples, desc.z_stencil, desc.tag); return new VKFramebuffer(vkrfb); } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index e49411bc6f..9cc732b86a 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -300,6 +300,7 @@ struct FramebufferDesc { int height; int depth; int numLayers; + int numSamples; bool z_stencil; const char *tag; // For graphics debuggers }; diff --git a/Core/Config.cpp b/Core/Config.cpp index 40e3478d3f..e7b10013af 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -901,6 +901,7 @@ static ConfigSetting graphicsSettings[] = { // Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine. ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, true, true), + ConfigSetting("MultiSampleLevel", &g_Config.iMultiSampleLevel, 1, true, true), ReportedConfigSetting("VertexDecCache", &g_Config.bVertexCache, false, true, true), ReportedConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, true, true), diff --git a/Core/Config.h b/Core/Config.h index 6e8a6e808d..342b5c3450 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -210,6 +210,7 @@ public: int iForceFullScreen = -1; // -1 = nope, 0 = force off, 1 = force on (not saved.) int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on. int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso + int iMultiSampleLevel; int bHighQualityDepth; bool bReplaceTextures; bool bSaveNewTextures; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 05521c047e..e8f3139a10 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1652,7 +1652,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, shaderManager_->DirtyLastShader(); char tag[128]; size_t len = FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, tag }); if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) { NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len); } @@ -2019,7 +2019,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd char name[64]; snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address); textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, name }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, name }); vfbs_.push_back(vfb); u32 byteSize = ColorBufferByteSize(vfb); @@ -2072,7 +2072,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram snprintf(name, sizeof(name), "download_temp"); // TODO: We don't have a way to create a depth-only framebuffer yet. // Also, at least on Vulkan we always create both depth and color, need to rework how we handle renderpasses. - nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, channel == RASTER_DEPTH ? true : false, name }); + nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 1, channel == RASTER_DEPTH ? true : false, name }); if (!nvfb->fbo) { ERROR_LOG(FRAMEBUF, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight); delete nvfb; @@ -2466,7 +2466,7 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u char name[128]; snprintf(name, sizeof(name), "tempfbo_%s_%dx%d", TempFBOReasonToString(reason), w / renderScaleFactor_, h / renderScaleFactor_); - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), z_stencil, name }); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), 1, z_stencil, name }); if (!fbo) { return nullptr; } @@ -3156,7 +3156,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi char tag[128]; FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, tag }); vfbs_.push_back(vfb); } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 5980bbb95e..b94ba7d202 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -270,7 +270,7 @@ bool PresentationCommon::UpdatePostShader() { previousIndex_ = 0; for (int i = 0; i < FRAMES; ++i) { - previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, false, "inter_presentation" }); + previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, 1, false, "inter_presentation" }); if (!previousFramebuffers_[i]) { DestroyPostShader(); return false; @@ -386,7 +386,7 @@ bool PresentationCommon::AllocateFramebuffer(int w, int h) { } // No depth/stencil for post processing - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, "presentation" }); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, 1, false, "presentation" }); if (!fbo) { return false; } diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index f5e7bc2889..308bcbd490 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1299,6 +1299,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { desc.depth = 1; desc.z_stencil = false; desc.numLayers = 1; + desc.numSamples = 1; desc.tag = "dynamic_clut"; dynamicClutFbo_ = draw_->CreateFramebuffer(desc); desc.tag = "dynamic_clut_temp"; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index d1b2da92b6..61ff24fb2c 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -8,6 +8,7 @@ #include "Common/Log.h" #include "Common/StringUtils.h" #include "Common/GPU/Vulkan/VulkanContext.h" +#include "Core/Config.h" #include "GPU/Vulkan/VulkanUtil.h" #include "GPU/Vulkan/PipelineManagerVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" @@ -171,7 +172,7 @@ static std::string CutFromMain(std::string str) { } static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache, - VkPipelineLayout layout, PipelineFlags pipelineFlags, const VulkanPipelineRasterStateKey &key, + VkPipelineLayout layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) { VulkanPipeline *vulkanPipeline = new VulkanPipeline(); VKRGraphicsPipelineDesc *desc = &vulkanPipeline->desc; @@ -307,7 +308,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, tag = FragmentShaderDesc(fs->GetID()) + " VS " + VertexShaderDesc(vs->GetID()); #endif - VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, tag.c_str()); + VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, sampleCount, tag.c_str()); vulkanPipeline->pipeline = pipeline; if (useBlendConstant) { @@ -351,8 +352,10 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * pipelineFlags |= PipelineFlags::USES_MULTIVIEW; } + VkSampleCountFlagBits sampleCount = SampleCountToFlagBits(g_Config.iMultiSampleLevel); + VulkanPipeline *pipeline = CreateVulkanPipeline( - renderManager, pipelineCache_, layout, pipelineFlags, + renderManager, pipelineCache_, layout, pipelineFlags, sampleCount, rasterKey, decFmt, vs, fs, gs, useHwTransform, variantBitmask); pipelines_.Insert(key, pipeline); From 4dfce4f6bca03c752f8ac0ec9431193a1fbb4da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 11:50:28 +0100 Subject: [PATCH 499/715] Basically working MSAA on desktop GPUs! Some glitches remain. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + Common/GPU/D3D9/thin3d_d3d9.cpp | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 1 + Common/GPU/Vulkan/VulkanFramebuffer.cpp | 90 +++++++++++++---------- Common/GPU/Vulkan/VulkanFramebuffer.h | 17 ++++- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 39 +++++++--- Common/GPU/Vulkan/VulkanRenderManager.cpp | 13 ++-- Common/GPU/Vulkan/VulkanRenderManager.h | 10 +-- Common/GPU/Vulkan/thin3d_vulkan.cpp | 14 +++- Common/GPU/thin3d.h | 1 + Core/Config.cpp | 3 +- Core/Config.h | 1 + GPU/Common/FramebufferManagerCommon.cpp | 5 +- GPU/Vulkan/GPU_Vulkan.cpp | 6 ++ GPU/Vulkan/PipelineManagerVulkan.cpp | 8 +- UI/GameSettingsScreen.cpp | 15 ++++ 16 files changed, 153 insertions(+), 72 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index c0b527fa2b..9b59852c88 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -271,6 +271,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.fragmentShaderDepthWriteSupported = true; caps_.fragmentShaderStencilWriteSupported = false; caps_.blendMinMaxSupported = true; + caps_.multiSampleLevelsMask = 1; // More could be supported with some work. D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options)); diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index dce9f66335..e50eb3b1c8 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -764,6 +764,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.fragmentShaderStencilWriteSupported = false; caps_.blendMinMaxSupported = true; caps_.isTilingGPU = false; + caps_.multiSampleLevelsMask = 1; // More could be supported with some work. if ((caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && caps.MaxAnisotropy > 1) { caps_.anisoSupported = true; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 61df0bdaee..b107f2f194 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -557,6 +557,7 @@ OpenGLContext::OpenGLContext() { caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported; caps_.depthClampSupported = gl_extensions.ARB_depth_clamp || gl_extensions.EXT_depth_clamp; caps_.blendMinMaxSupported = gl_extensions.EXT_blend_minmax; + caps_.multiSampleLevelsMask = 1; // More could be supported with some work. if (gl_extensions.IsGLES) { caps_.clipDistanceSupported = gl_extensions.EXT_clip_cull_distance || gl_extensions.APPLE_clip_distance; diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 0de8f76a3c..c3bdcb4ae5 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -2,21 +2,39 @@ #include "Common/GPU/Vulkan/VulkanFramebuffer.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" -VkSampleCountFlagBits SampleCountToFlagBits(int count) { +VkSampleCountFlagBits MultiSampleLevelToFlagBits(int count) { // TODO: Check hardware support here, or elsewhere? // Some hardware only supports 4x. switch (count) { - case 1: return VK_SAMPLE_COUNT_1_BIT; - case 2: return VK_SAMPLE_COUNT_2_BIT; - case 4: return VK_SAMPLE_COUNT_4_BIT; - case 8: return VK_SAMPLE_COUNT_8_BIT; - case 16: return VK_SAMPLE_COUNT_16_BIT; // rare + case 0: return VK_SAMPLE_COUNT_1_BIT; + case 1: return VK_SAMPLE_COUNT_2_BIT; + case 2: return VK_SAMPLE_COUNT_4_BIT; // The only non-1 level supported on some mobile chips. + case 3: return VK_SAMPLE_COUNT_8_BIT; + case 4: return VK_SAMPLE_COUNT_16_BIT; // rare but exists, on Intel for example default: _assert_(false); return VK_SAMPLE_COUNT_1_BIT; } } +void VKRImage::Delete(VulkanContext *vulkan) { + // Get rid of the views first, feels cleaner (but in reality doesn't matter). + if (rtView) + vulkan->Delete().QueueDeleteImageView(rtView); + if (texAllLayersView) + vulkan->Delete().QueueDeleteImageView(texAllLayersView); + for (int i = 0; i < 2; i++) { + if (texLayerViews[i]) { + vulkan->Delete().QueueDeleteImageView(texLayerViews[i]); + } + } + + if (image) { + _dbg_assert_(alloc); + vulkan->Delete().QueueDeleteImageAllocation(image, alloc); + } +} + VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _numSamples, bool createDepthStencilBuffer, const char *tag) : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { @@ -28,12 +46,12 @@ VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRe } if (_numSamples > 1) { - sampleCount = SampleCountToFlagBits(_numSamples); + sampleCount = MultiSampleLevelToFlagBits(_numSamples); // TODO: Create a different tag for these? CreateImage(vulkan_, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); if (createDepthStencilBuffer) { - CreateImage(vulkan_, initCmd, depth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + CreateImage(vulkan_, initCmd, msaaDepth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); } } else { sampleCount = VK_SAMPLE_COUNT_1_BIT; @@ -71,19 +89,27 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas } VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - VkImageView views[2]{}; + VkImageView views[4]{}; bool hasDepth = RenderPassTypeHasDepth(rpType); - views[0] = color.rtView; // 2D array texture if multilayered. + int attachmentCount = 0; + views[attachmentCount++] = color.rtView; // 2D array texture if multilayered. if (hasDepth) { if (!depth.rtView) { WARN_LOG(G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", depth.image, depth.texAllLayersView, depth.format, tag_.c_str(), width, height); // Will probably crash, depending on driver. } - views[1] = depth.rtView; + views[attachmentCount++] = depth.rtView; } + if (rpType & RenderPassType::MULTISAMPLE) { + views[attachmentCount++] = msaaColor.rtView; + if (hasDepth) { + views[attachmentCount++] = msaaDepth.rtView; + } + } + fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType, sampleCount); - fbci.attachmentCount = hasDepth ? 2 : 1; + fbci.attachmentCount = attachmentCount; fbci.pAttachments = views; fbci.width = width; fbci.height = height; @@ -100,32 +126,11 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas } VKRFramebuffer::~VKRFramebuffer() { - // Get rid of the views first, feels cleaner (but in reality doesn't matter). - if (color.rtView) - vulkan_->Delete().QueueDeleteImageView(color.rtView); - if (depth.rtView) - vulkan_->Delete().QueueDeleteImageView(depth.rtView); - if (color.texAllLayersView) - vulkan_->Delete().QueueDeleteImageView(color.texAllLayersView); - if (depth.texAllLayersView) - vulkan_->Delete().QueueDeleteImageView(depth.texAllLayersView); - for (int i = 0; i < 2; i++) { - if (color.texLayerViews[i]) { - vulkan_->Delete().QueueDeleteImageView(color.texLayerViews[i]); - } - if (depth.texLayerViews[i]) { - vulkan_->Delete().QueueDeleteImageView(depth.texLayerViews[i]); - } - } + color.Delete(vulkan_); + depth.Delete(vulkan_); + msaaColor.Delete(vulkan_); + msaaDepth.Delete(vulkan_); - if (color.image) { - _dbg_assert_(color.alloc); - vulkan_->Delete().QueueDeleteImageAllocation(color.image, color.alloc); - } - if (depth.image) { - _dbg_assert_(depth.alloc); - vulkan_->Delete().QueueDeleteImageAllocation(depth.image, depth.alloc); - } for (auto &fb : framebuf) { if (fb) { vulkan_->Delete().QueueDeleteFramebuffer(fb); @@ -229,6 +234,7 @@ void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKR 0, dstAccessMask); img.layout = initialLayout; img.format = format; + img.sampleCount = sampleCount; img.tag = tag ? tag : "N/A"; img.numLayers = numLayers; } @@ -258,7 +264,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas bool isBackbuffer = rpType == RenderPassType::BACKBUFFER; bool hasDepth = RenderPassTypeHasDepth(rpType); bool multiview = RenderPassTypeHasMultiView(rpType); - bool multisample = rpType & RenderPassType::MULTISAMPLE; + bool multisample = RenderPassTypeHasMultisample(rpType); if (multiview) { // TODO: Assert that the device has multiview support enabled. @@ -306,7 +312,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas if (hasDepth) { depthAttachmentIndex = attachmentCount; attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; - attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[attachmentCount].samples = sampleCount; attachments[attachmentCount].loadOp = ConvertLoadAction(key.depthLoadAction); attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction); attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); @@ -338,9 +344,10 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_reference; - VkAttachmentReference resolve_references[2]; + VkAttachmentReference resolve_references[2]{}; if (multisample) { resolve_references[0].attachment = 0; // the non-msaa color buffer. + resolve_references[0].layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; subpass.pResolveAttachments = resolve_references; } else { subpass.pResolveAttachments = nullptr; @@ -415,6 +422,9 @@ VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType, Vk // WARNING: We don't include sampleCount in the key, there's only the distinction multisampled or not // which comes from the rpType. // So you CAN NOT mix and match different non-one sample counts. + + _dbg_assert_(!((rpType & RenderPassType::MULTISAMPLE) && sampleCount == VK_SAMPLE_COUNT_1_BIT)); + if (!pass[(int)rpType]) { pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType, sampleCount); } diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.h b/Common/GPU/Vulkan/VulkanFramebuffer.h index 0247410df9..8ee9e84235 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.h +++ b/Common/GPU/Vulkan/VulkanFramebuffer.h @@ -43,6 +43,7 @@ struct VKRImage { VmaAllocation alloc; VkFormat format; + VkSampleCountFlagBits sampleCount; // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. VkImageLayout layout; @@ -51,6 +52,8 @@ struct VKRImage { // For debugging. std::string tag; + + void Delete(VulkanContext *vulkan); }; class VKRFramebuffer { @@ -82,6 +85,14 @@ public: return depth.image != VK_NULL_HANDLE; } + VkImageView GetRTView() { + if (sampleCount == VK_SAMPLE_COUNT_1_BIT) { + return color.rtView; + } else { + return msaaColor.rtView; + } + } + VulkanContext *Vulkan() const { return vulkan_; } private: static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); @@ -104,7 +115,11 @@ inline bool RenderPassTypeHasMultiView(RenderPassType type) { return (type & RenderPassType::MULTIVIEW) != 0; } -VkSampleCountFlagBits SampleCountToFlagBits(int count); +inline bool RenderPassTypeHasMultisample(RenderPassType type) { + return (type & RenderPassType::MULTISAMPLE) != 0; +} + +VkSampleCountFlagBits MultiSampleLevelToFlagBits(int count); // Must be the same order as Draw::RPAction enum class VKRRenderPassLoadAction : uint8_t { diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 7f7d9e8717..ee5a7ec4ed 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -762,6 +762,14 @@ static const char *rpTypeDebugNames[] = { "MV_RENDER_DEPTH", "MV_RENDER_INPUT", "MV_RENDER_DEPTH_INPUT", + "MS_RENDER", + "MS_RENDER_DEPTH", + "MS_RENDER_INPUT", + "MS_RENDER_DEPTH_INPUT", + "MS_MV_RENDER", + "MS_MV_RENDER_DEPTH", + "MS_MV_RENDER_INPUT", + "MS_MV_RENDER_DEPTH_INPUT", "BACKBUF", }; @@ -1323,7 +1331,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c // Maybe a middle pass. But let's try to just block and compile here for now, this doesn't // happen all that much. graphicsPipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); - graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType, step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT), rpType); + VkSampleCountFlagBits sampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; + graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType, sampleCount), rpType, sampleCount); } VkPipeline pipeline = graphicsPipeline->pipeline[(size_t)rpType]->BlockUntilReady(); @@ -1405,7 +1414,12 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c { _assert_(step.render.pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT); VulkanBarrier barrier; - SelfDependencyBarrier(step.render.framebuffer->color, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + if (step.render.framebuffer->sampleCount != VK_SAMPLE_COUNT_1_BIT) { + // Rendering is happening to the multisample buffer, not the color buffer. + SelfDependencyBarrier(step.render.framebuffer->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + } else { + SelfDependencyBarrier(step.render.framebuffer->color, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + } barrier.Flush(cmd); break; } @@ -1516,7 +1530,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step, VkCommandBuffer cmd) { VKRRenderPass *renderPass; int numClearVals = 0; - VkClearValue clearVal[2]{}; + VkClearValue clearVal[4]{}; VkFramebuffer framebuf; int w; int h; @@ -1563,15 +1577,22 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR // The transition from the optimal format happens after EndRenderPass, now that we don't // do it as part of the renderpass itself anymore. + if (sampleCount != VK_SAMPLE_COUNT_1_BIT) { + // We don't initialize values for these. + numClearVals = hasDepth ? 2 : 1; // Skip the resolve buffers, don't need to clear those. + } if (step.render.colorLoad == VKRRenderPassLoadAction::CLEAR) { - Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor); - numClearVals = 1; + Uint8x4ToFloat4(clearVal[numClearVals].color.float32, step.render.clearColor); } - if (hasDepth && (step.render.depthLoad == VKRRenderPassLoadAction::CLEAR || step.render.stencilLoad == VKRRenderPassLoadAction::CLEAR)) { - clearVal[1].depthStencil.depth = step.render.clearDepth; - clearVal[1].depthStencil.stencil = step.render.clearStencil; - numClearVals = 2; + numClearVals++; + if (hasDepth) { + if (step.render.depthLoad == VKRRenderPassLoadAction::CLEAR || step.render.stencilLoad == VKRRenderPassLoadAction::CLEAR) { + clearVal[numClearVals].depthStencil.depth = step.render.clearDepth; + clearVal[numClearVals].depthStencil.stencil = step.render.clearStencil; + } + numClearVals++; } + _dbg_assert_(numClearVals != 3); } else { RPKey key{ VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 294f8d40d5..4a8c8c7227 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -27,7 +27,7 @@ using namespace PPSSPP_VK; // renderPass is an example of the "compatibility class" or RenderPassType type. -bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType) { +bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount) { // Fill in the last part of the desc since now it's time to block. VkShaderModule vs = desc->vertexShader->BlockUntilReady(); VkShaderModule fs = desc->fragmentShader->BlockUntilReady(); @@ -69,13 +69,16 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR pipe.pDepthStencilState = &desc->dss; pipe.pRasterizationState = &desc->rs; + VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + ms.rasterizationSamples = sampleCount; + // We will use dynamic viewport state. pipe.pVertexInputState = &desc->vis; pipe.pViewportState = &desc->views; pipe.pTessellationState = nullptr; pipe.pDynamicState = &desc->ds; pipe.pInputAssemblyState = &desc->inputAssembly; - pipe.pMultisampleState = &desc->ms; + pipe.pMultisampleState = &ms; pipe.layout = desc->pipelineLayout; pipe.basePipelineHandle = VK_NULL_HANDLE; pipe.basePipelineIndex = 0; @@ -332,7 +335,7 @@ void VulkanRenderManager::CompileThreadFunc() { for (auto &entry : toCompile) { switch (entry.type) { case CompileQueueEntry::Type::GRAPHICS: - entry.graphics->Create(vulkan_, entry.compatibleRenderPass, entry.renderPassType); + entry.graphics->Create(vulkan_, entry.compatibleRenderPass, entry.renderPassType, entry.sampleCount); break; case CompileQueueEntry::Type::COMPUTE: entry.compute->Create(vulkan_); @@ -523,7 +526,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe } pipeline->pipeline[i] = Promise::CreateEmpty(); - compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType, sampleCount), rpType)); + compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType, sampleCount), rpType, sampleCount)); needsCompile = true; } if (needsCompile) @@ -591,7 +594,7 @@ void VulkanRenderManager::EndCurRenderStep() { for (VKRGraphicsPipeline *pipeline : pipelinesToCheck_) { if (!pipeline->pipeline[(size_t)rpType]) { pipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); - compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType, sampleCount), rpType)); + compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType, sampleCount), rpType, sampleCount)); needsCompile = true; } } diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 2e5cc1a1a5..a2c9abf9b4 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -82,7 +82,6 @@ struct VKRGraphicsPipelineDesc { VkDynamicState dynamicStates[6]{}; VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; - VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; // Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish. Promise *vertexShader = nullptr; @@ -122,7 +121,7 @@ struct VKRGraphicsPipeline { } } - bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType); + bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount); // This deletes the whole VKRGraphicsPipeline, you must remove your last pointer to it when doing this. void QueueForDeletion(VulkanContext *vulkan); @@ -151,9 +150,9 @@ struct VKRComputePipeline { }; struct CompileQueueEntry { - CompileQueueEntry(VKRGraphicsPipeline *p, VkRenderPass _compatibleRenderPass, RenderPassType _renderPassType) - : type(Type::GRAPHICS), graphics(p), compatibleRenderPass(_compatibleRenderPass), renderPassType(_renderPassType) {} - CompileQueueEntry(VKRComputePipeline *p) : type(Type::COMPUTE), compute(p), renderPassType(RenderPassType::HAS_DEPTH) {} // renderpasstype here shouldn't matter + CompileQueueEntry(VKRGraphicsPipeline *p, VkRenderPass _compatibleRenderPass, RenderPassType _renderPassType, VkSampleCountFlagBits _sampleCount) + : type(Type::GRAPHICS), graphics(p), compatibleRenderPass(_compatibleRenderPass), renderPassType(_renderPassType), sampleCount(_sampleCount) {} + CompileQueueEntry(VKRComputePipeline *p) : type(Type::COMPUTE), compute(p), renderPassType(RenderPassType::HAS_DEPTH), sampleCount(VK_SAMPLE_COUNT_1_BIT) {} // renderpasstype here shouldn't matter enum class Type { GRAPHICS, COMPUTE, @@ -163,6 +162,7 @@ struct CompileQueueEntry { RenderPassType renderPassType; VKRGraphicsPipeline *graphics = nullptr; VKRComputePipeline *compute = nullptr; + VkSampleCountFlagBits sampleCount; }; class VulkanRenderManager { diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index b944a1962c..b7a0bb2ed1 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -832,6 +832,7 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.blendMinMaxSupported = true; caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0; caps_.multiViewSupported = vulkan->GetDeviceFeatures().enabled.multiview.multiview != 0; + const auto &limits = vulkan->GetPhysicalDeviceProperties().properties.limits; auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties; @@ -853,6 +854,14 @@ VKContext::VKContext(VulkanContext *vulkan) } caps_.isTilingGPU = hasLazyMemory; + // VkSampleCountFlagBits is arranged correctly for our purposes. + // Only support MSAA levels that have support for all three of color, depth, stencil. + if (!caps_.isTilingGPU) { + caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); + } else { + caps_.multiSampleLevelsMask = 1; + } + if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { // Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off. // See: https://github.com/hrydgard/ppsspp/pull/11684 @@ -1197,9 +1206,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char } gDesc.ds.pDynamicStates = gDesc.dynamicStates; - gDesc.ms.pSampleMask = nullptr; - gDesc.ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - gDesc.views.viewportCount = 1; gDesc.views.scissorCount = 1; gDesc.views.pViewports = nullptr; // dynamic @@ -1741,7 +1747,7 @@ uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) { case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS: return (uint64_t)curFramebuffer_->GetFB()->color.texAllLayersView; case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT: - return (uint64_t)curFramebuffer_->GetFB()->color.rtView; + return (uint64_t)curFramebuffer_->GetFB()->GetRTView(); case NativeObject::FRAME_DATA_DESC_SET_LAYOUT: return (uint64_t)frameDescSetLayout_; case NativeObject::THIN3D_PIPELINE_LAYOUT: diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 9cc732b86a..cfe4af4b34 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -579,6 +579,7 @@ struct DeviceCaps { bool multiViewSupported; bool isTilingGPU; // This means that it benefits from correct store-ops, msaa without backing memory, etc. + u32 multiSampleLevelsMask; // Bit n is set if (1 << n) is a valid multisample level. Bit 0 is always set. std::string deviceName; // The device name to use when creating the thin3d context, to get the same one. }; diff --git a/Core/Config.cpp b/Core/Config.cpp index e7b10013af..bd3e2dccf2 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -901,7 +901,8 @@ static ConfigSetting graphicsSettings[] = { // Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine. ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, true, true), - ConfigSetting("MultiSampleLevel", &g_Config.iMultiSampleLevel, 1, true, true), + ConfigSetting("MultiSampleLevel", &g_Config.iMultiSampleLevel, 0, true, true), // Number of samples is 1 << iMultiSampleLevel + ConfigSetting("MultiSampleQuality", &g_Config.iMultiSampleQuality, 0, true, true), // 0 = multisampling, 1 = halfway to SGSSAA, 2 = SGSSAA. ReportedConfigSetting("VertexDecCache", &g_Config.bVertexCache, false, true, true), ReportedConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, true, true), diff --git a/Core/Config.h b/Core/Config.h index 342b5c3450..05244592be 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -211,6 +211,7 @@ public: int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on. int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso int iMultiSampleLevel; + int iMultiSampleQuality; int bHighQualityDepth; bool bReplaceTextures; bool bSaveNewTextures; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index e8f3139a10..4fc69de515 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1652,7 +1652,10 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, shaderManager_->DirtyLastShader(); char tag[128]; size_t len = FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, tag }); + + int msaaLevel = g_Config.iMultiSampleLevel; + + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), msaaLevel, true, tag }); if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) { NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len); } diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 0c50c361bd..f735f3267f 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -269,6 +269,12 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { } } + // We need to turn off framebuffer fetch through input attachments if MSAA is on for now. + // This is fixable, just needs some shader generator work (subpassInputMS). + if (g_Config.iMultiSampleLevel != 0) { + features &= ~GPU_USE_FRAMEBUFFER_FETCH; + } + return CheckGPUFeaturesLate(features); } diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 61ff24fb2c..e52df37028 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -250,17 +250,13 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, rs.polygonMode = VK_POLYGON_MODE_FILL; rs.depthClampEnable = key.depthClampEnable; - VkPipelineMultisampleStateCreateInfo &ms = desc->ms; - ms.pSampleMask = nullptr; - ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - desc->fragmentShader = fs->GetModule(); desc->vertexShader = vs->GetModule(); desc->geometryShader = gs ? gs->GetModule() : nullptr; desc->fragmentShaderSource = fs->GetShaderString(SHADER_STRING_SOURCE_CODE); desc->vertexShaderSource = vs->GetShaderString(SHADER_STRING_SOURCE_CODE); if (gs) { - desc->geometryShaderSource = gs->GetShaderString(SHADER_STRING_SOURCE_CODE); + desc->geometryShaderSource = gs->GetShaderString(SHADER_STRING_SOURCE_CODE); } VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly; @@ -352,7 +348,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * pipelineFlags |= PipelineFlags::USES_MULTIVIEW; } - VkSampleCountFlagBits sampleCount = SampleCountToFlagBits(g_Config.iMultiSampleLevel); + VkSampleCountFlagBits sampleCount = MultiSampleLevelToFlagBits(g_Config.iMultiSampleLevel); VulkanPipeline *pipeline = CreateVulkanPipeline( renderManager, pipelineCache_, layout, pipelineFlags, sampleCount, diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index b2ad14f16e..89ff1b49d7 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -305,6 +305,21 @@ void GameSettingsScreen::CreateViews() { return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects; }); + if (draw->GetDeviceCaps().multiSampleLevelsMask != 1) { + static const char *msaaModes[] = { "Off", "2xMSAA", "4xMSAA", "8xMSAA", "16xMSAA" }; + auto msaaChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iMultiSampleLevel, gr->T("Antialiasing (MSAA)"), msaaModes, 0, ARRAY_SIZE(msaaModes), gr->GetName(), screenManager())); + msaaChoice->OnChoice.Add([&](UI::EventParams &) -> UI::EventReturn { + NativeMessageReceived("gpu_renderResized", ""); + return UI::EVENT_DONE; + }); + // Hide unsupported levels. + for (int i = 1; i < 5; i++) { + if ((draw->GetDeviceCaps().multiSampleLevelsMask & (1 << i)) == 0) { + msaaChoice->HideChoice(i); + } + } + } + #if PPSSPP_PLATFORM(ANDROID) if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) { static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" }; From e3679df6cfe44c470175c6eba8d77739bfc6c774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 18:20:30 +0100 Subject: [PATCH 500/715] Fix switching between MSAA levels --- Common/GPU/Vulkan/VulkanFramebuffer.cpp | 12 +++++++---- Common/GPU/Vulkan/VulkanFramebuffer.h | 3 ++- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 13 ++++++++++-- Common/GPU/Vulkan/VulkanRenderManager.cpp | 26 +++++++++++++++++------ Common/GPU/Vulkan/VulkanRenderManager.h | 9 +++++++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 4 ++-- Common/GPU/thin3d.h | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 11 +++++----- GPU/Common/FramebufferManagerCommon.h | 1 + GPU/Common/PresentationCommon.cpp | 4 ++-- GPU/Common/TextureCacheCommon.cpp | 2 +- 11 files changed, 62 insertions(+), 25 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index c3bdcb4ae5..a7a93e208d 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -35,7 +35,7 @@ void VKRImage::Delete(VulkanContext *vulkan) { } } -VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _numSamples, bool createDepthStencilBuffer, const char *tag) +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag) : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { _dbg_assert_(tag); @@ -45,8 +45,8 @@ VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRe CreateImage(vulkan_, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); } - if (_numSamples > 1) { - sampleCount = MultiSampleLevelToFlagBits(_numSamples); + if (_multiSampleLevel > 0) { + sampleCount = MultiSampleLevelToFlagBits(_multiSampleLevel); // TODO: Create a different tag for these? CreateImage(vulkan_, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); @@ -425,8 +425,12 @@ VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType, Vk _dbg_assert_(!((rpType & RenderPassType::MULTISAMPLE) && sampleCount == VK_SAMPLE_COUNT_1_BIT)); - if (!pass[(int)rpType]) { + if (!pass[(int)rpType] || sampleCounts[(int)rpType] != sampleCount) { + if (pass[(int)rpType]) { + vulkan->Delete().QueueDeleteRenderPass(pass[(int)rpType]); + } pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType, sampleCount); + sampleCounts[(int)rpType] = sampleCount; } return pass[(int)rpType]; } diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.h b/Common/GPU/Vulkan/VulkanFramebuffer.h index 8ee9e84235..fc584f4b8c 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.h +++ b/Common/GPU/Vulkan/VulkanFramebuffer.h @@ -58,7 +58,7 @@ struct VKRImage { class VKRFramebuffer { public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _numSamples, bool createDepthStencilBuffer, const char *tag); + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag); ~VKRFramebuffer(); VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); @@ -159,5 +159,6 @@ public: private: // TODO: Might be better off with a hashmap once the render pass type count grows really large.. VkRenderPass pass[(size_t)RenderPassType::TYPE_COUNT]{}; + VkSampleCountFlagBits sampleCounts[(size_t)RenderPassType::TYPE_COUNT]; RPKey key_; }; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index ee5a7ec4ed..7f7585c28e 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1324,6 +1324,15 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c { VKRGraphicsPipeline *graphicsPipeline = c.graphics_pipeline.pipeline; if (graphicsPipeline != lastGraphicsPipeline) { + VkSampleCountFlagBits fbSampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; + + if (RenderPassTypeHasMultisample(rpType) && fbSampleCount != graphicsPipeline->SampleCount()) { + // Sample count might have started mismatching if the user changed multisampling mode. Let's get rid of all variants + // and start over. + // (We could avoid this if sample count was baked into the rpType, but I don't want that to grow too big). + graphicsPipeline->DestroyAllVariants(vulkan_); + } + if (!graphicsPipeline->pipeline[(size_t)rpType]) { // NOTE: If render steps got merged, it can happen that, as they ended during recording, // they didn't know their final render pass type so they created the wrong pipelines in EndCurRenderStep(). @@ -1331,11 +1340,11 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c // Maybe a middle pass. But let's try to just block and compile here for now, this doesn't // happen all that much. graphicsPipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); - VkSampleCountFlagBits sampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; - graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType, sampleCount), rpType, sampleCount); + graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType, fbSampleCount), rpType, fbSampleCount); } VkPipeline pipeline = graphicsPipeline->pipeline[(size_t)rpType]->BlockUntilReady(); + if (pipeline != VK_NULL_HANDLE) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); pipelineLayout = c.pipeline.pipelineLayout; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 4a8c8c7227..0fed2b71a8 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -28,6 +28,15 @@ using namespace PPSSPP_VK; // renderPass is an example of the "compatibility class" or RenderPassType type. bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount) { + bool multisample = RenderPassTypeHasMultisample(rpType); + if (multisample) { + if (sampleCount_ != VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM) { + _assert_(sampleCount == sampleCount_); + } else { + sampleCount_ = sampleCount; + } + } + // Fill in the last part of the desc since now it's time to block. VkShaderModule vs = desc->vertexShader->BlockUntilReady(); VkShaderModule fs = desc->fragmentShader->BlockUntilReady(); @@ -70,7 +79,7 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR pipe.pRasterizationState = &desc->rs; VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; - ms.rasterizationSamples = sampleCount; + ms.rasterizationSamples = multisample ? sampleCount : VK_SAMPLE_COUNT_1_BIT; // We will use dynamic viewport state. pipe.pVertexInputState = &desc->vis; @@ -107,8 +116,8 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR success = false; } else { // Success! - if (!tag.empty()) { - vulkan->SetDebugName(vkpipeline, VK_OBJECT_TYPE_PIPELINE, tag.c_str()); + if (!tag_.empty()) { + vulkan->SetDebugName(vkpipeline, VK_OBJECT_TYPE_PIPELINE, tag_.c_str()); } pipeline[(size_t)rpType]->Post(vkpipeline); } @@ -116,7 +125,7 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR return success; } -void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { +void VKRGraphicsPipeline::DestroyAllVariants(VulkanContext *vulkan) { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (!this->pipeline[i]) continue; @@ -125,7 +134,13 @@ void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { if (pipeline) { vulkan->Delete().QueueDeletePipeline(pipeline); } + this->pipeline[i] = nullptr; } + sampleCount_ = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM; +} + +void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { + DestroyAllVariants(vulkan); vulkan->Delete().QueueCallback([](void *p) { VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p; delete pipeline; @@ -485,11 +500,10 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { } VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag) { - VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(); + VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(tag); _dbg_assert_(desc->vertexShader); _dbg_assert_(desc->fragmentShader); pipeline->desc = desc; - pipeline->tag = tag; if (curRenderStep_) { // The common case pipelinesToCheck_.push_back(pipeline); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index a2c9abf9b4..218e87524c 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -115,6 +115,7 @@ struct VKRComputePipelineDesc { // Wrapped pipeline. Doesn't own desc. struct VKRGraphicsPipeline { + VKRGraphicsPipeline(const char *tag) : tag_(tag) {} ~VKRGraphicsPipeline() { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { delete pipeline[i]; @@ -123,6 +124,8 @@ struct VKRGraphicsPipeline { bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount); + void DestroyAllVariants(VulkanContext *vulkan); + // This deletes the whole VKRGraphicsPipeline, you must remove your last pointer to it when doing this. void QueueForDeletion(VulkanContext *vulkan); @@ -132,7 +135,11 @@ struct VKRGraphicsPipeline { VKRGraphicsPipelineDesc *desc = nullptr; // not owned! Promise *pipeline[(size_t)RenderPassType::TYPE_COUNT]{}; - std::string tag; + + VkSampleCountFlagBits SampleCount() const { return sampleCount_; } +private: + std::string tag_; + VkSampleCountFlagBits sampleCount_ = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM; }; struct VKRComputePipeline { diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index b7a0bb2ed1..a215ff4528 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1590,13 +1590,13 @@ private: }; Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { - _assert_(desc.numSamples > 0); + _assert_(desc.multiSampleLevel >= 0); _assert_(desc.numLayers > 0); _assert_(desc.width > 0); _assert_(desc.height > 0); VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.numSamples, desc.z_stencil, desc.tag); + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag); return new VKFramebuffer(vkrfb); } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index cfe4af4b34..da3cc0a35f 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -300,7 +300,7 @@ struct FramebufferDesc { int height; int depth; int numLayers; - int numSamples; + int multiSampleLevel; // 0 = 1xaa, 1 = 2xaa, and so on. bool z_stencil; const char *tag; // For graphics debuggers }; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 4fc69de515..724d123cb7 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -89,7 +89,7 @@ void FramebufferManagerCommon::Init() { } bool FramebufferManagerCommon::UpdateRenderSize() { - const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight; + const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight || msaaLevel_ != g_Config.iMultiSampleLevel; const int effectiveBloomHack = PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn ? 3 : g_Config.iBloomHack; @@ -99,6 +99,7 @@ bool FramebufferManagerCommon::UpdateRenderSize() { renderWidth_ = (float)PSP_CoreParameter().renderWidth; renderHeight_ = (float)PSP_CoreParameter().renderHeight; renderScaleFactor_ = (float)PSP_CoreParameter().renderScaleFactor; + msaaLevel_ = g_Config.iMultiSampleLevel; bloomHack_ = effectiveBloomHack; useBufferedRendering_ = newBuffered; @@ -2022,7 +2023,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd char name[64]; snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address); textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, name }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, name }); vfbs_.push_back(vfb); u32 byteSize = ColorBufferByteSize(vfb); @@ -2075,7 +2076,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram snprintf(name, sizeof(name), "download_temp"); // TODO: We don't have a way to create a depth-only framebuffer yet. // Also, at least on Vulkan we always create both depth and color, need to rework how we handle renderpasses. - nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 1, channel == RASTER_DEPTH ? true : false, name }); + nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 0, channel == RASTER_DEPTH ? true : false, name }); if (!nvfb->fbo) { ERROR_LOG(FRAMEBUF, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight); delete nvfb; @@ -2469,7 +2470,7 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u char name[128]; snprintf(name, sizeof(name), "tempfbo_%s_%dx%d", TempFBOReasonToString(reason), w / renderScaleFactor_, h / renderScaleFactor_); - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), 1, z_stencil, name }); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), 0, z_stencil, name }); if (!fbo) { return nullptr; } @@ -3159,7 +3160,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi char tag[128]; FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, tag }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, tag }); vfbs_.push_back(vfb); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 676c024f7c..0a22fdb366 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -545,6 +545,7 @@ protected: float renderWidth_ = 0.0f; float renderHeight_ = 0.0f; + int msaaLevel_ = 0; int renderScaleFactor_ = 1; int pixelWidth_ = 0; int pixelHeight_ = 0; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index b94ba7d202..e07eec1499 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -270,7 +270,7 @@ bool PresentationCommon::UpdatePostShader() { previousIndex_ = 0; for (int i = 0; i < FRAMES; ++i) { - previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, 1, false, "inter_presentation" }); + previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, 0, false, "inter_presentation" }); if (!previousFramebuffers_[i]) { DestroyPostShader(); return false; @@ -386,7 +386,7 @@ bool PresentationCommon::AllocateFramebuffer(int w, int h) { } // No depth/stencil for post processing - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, 1, false, "presentation" }); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, 0, false, "presentation" }); if (!fbo) { return false; } diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 308bcbd490..cd6899cacb 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1299,7 +1299,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { desc.depth = 1; desc.z_stencil = false; desc.numLayers = 1; - desc.numSamples = 1; + desc.multiSampleLevel = 0; desc.tag = "dynamic_clut"; dynamicClutFbo_ = draw_->CreateFramebuffer(desc); desc.tag = "dynamic_clut_temp"; From 8b9b80f04445b6b2758ac42c0d6d0bbe63b303e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 20:34:51 +0100 Subject: [PATCH 501/715] Add path that uses CreateRenderpass2, we're gonna need it for depth resolve. --- Common/GPU/Vulkan/VulkanContext.cpp | 6 ++ Common/GPU/Vulkan/VulkanContext.h | 1 + Common/GPU/Vulkan/VulkanFramebuffer.cpp | 85 +++++++++++++++++++++++-- Common/GPU/Vulkan/VulkanLoader.cpp | 4 ++ Common/GPU/Vulkan/VulkanLoader.h | 1 + Common/GPU/Vulkan/thin3d_vulkan.cpp | 10 ++- 6 files changed, 101 insertions(+), 6 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 6c121adf66..7f7688081b 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -253,15 +253,21 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { VkPhysicalDeviceProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; VkPhysicalDevicePushDescriptorPropertiesKHR pushProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR}; VkPhysicalDeviceExternalMemoryHostPropertiesEXT extHostMemProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT}; + VkPhysicalDeviceDepthStencilResolveProperties depthStencilResolveProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES}; + props2.pNext = &pushProps; pushProps.pNext = &extHostMemProps; + extHostMemProps.pNext = &depthStencilResolveProps; vkGetPhysicalDeviceProperties2KHR(physical_devices_[i], &props2); // Don't want bad pointers sitting around. props2.pNext = nullptr; pushProps.pNext = nullptr; + extHostMemProps.pNext = nullptr; + depthStencilResolveProps.pNext = nullptr; physicalDeviceProperties_[i].properties = props2.properties; physicalDeviceProperties_[i].pushDescriptorProperties = pushProps; physicalDeviceProperties_[i].externalMemoryHostProperties = extHostMemProps; + physicalDeviceProperties_[i].depthStencilResolve = depthStencilResolveProps; } } else { for (uint32_t i = 0; i < gpu_count; i++) { diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index 003546a59d..f30b1ee0a8 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -253,6 +253,7 @@ public: VkPhysicalDeviceProperties properties; VkPhysicalDevicePushDescriptorPropertiesKHR pushDescriptorProperties; VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProperties; + VkPhysicalDeviceDepthStencilResolveProperties depthStencilResolve; }; struct AllPhysicalDeviceFeatures { diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index a7a93e208d..228ab956e3 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -344,11 +344,11 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_reference; - VkAttachmentReference resolve_references[2]{}; + VkAttachmentReference color_resolve_reference; if (multisample) { - resolve_references[0].attachment = 0; // the non-msaa color buffer. - resolve_references[0].layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - subpass.pResolveAttachments = resolve_references; + color_resolve_reference.attachment = 0; // the non-msaa color buffer. + color_resolve_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + subpass.pResolveAttachments = &color_resolve_reference; } else { subpass.pResolveAttachments = nullptr; } @@ -408,7 +408,82 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas } VkRenderPass pass; - VkResult res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass); + VkResult res; + if (vulkan->Extensions().KHR_create_renderpass2) { + // It's a bit unfortunate that we can't rely on vkCreateRenderPass2, because here we now have + // to do a bunch of struct conversion, just to not have to repeat the logic from above. + VkAttachmentDescription2KHR attachments2[4]{}; + for (int i = 0; i < attachmentCount; i++) { + attachments2[i].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; + attachments2[i].format = attachments[i].format; + attachments2[i].samples = attachments[i].samples; + attachments2[i].loadOp = attachments[i].loadOp; + attachments2[i].storeOp = attachments[i].storeOp; + attachments2[i].stencilLoadOp = attachments[i].stencilLoadOp; + attachments2[i].stencilStoreOp = attachments[i].stencilStoreOp; + attachments2[i].initialLayout = attachments[i].initialLayout; + attachments2[i].finalLayout = attachments[i].finalLayout; + } + + VkAttachmentReference2KHR colorReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + colorReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorReference2.attachment = color_reference.attachment; + colorReference2.layout = color_reference.layout; + + VkAttachmentReference2KHR depthReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + depthReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthReference2.attachment = depth_reference.attachment; + depthReference2.layout = depth_reference.layout; + + VkSubpassDependency2KHR deps2[2]{}; + for (int i = 0; i < numDeps; i++) { + deps2[i].sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR; + deps2[i].dependencyFlags = deps[i].dependencyFlags; + deps2[i].srcAccessMask = deps[i].srcAccessMask; + deps2[i].dstAccessMask = deps[i].dstAccessMask; + deps2[i].srcStageMask = deps[i].srcStageMask; + deps2[i].dstStageMask = deps[i].dstStageMask; + deps2[i].srcSubpass = deps[i].srcSubpass; + deps2[i].dstSubpass = deps[i].dstSubpass; + deps2[i].dependencyFlags = deps[i].dependencyFlags; + deps2[i].viewOffset = 0; + } + + VkAttachmentReference2KHR colorResolveReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + + VkSubpassDescription2KHR subpass2{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR }; + subpass2.colorAttachmentCount = subpass.colorAttachmentCount; + subpass2.flags = subpass.flags; + subpass2.inputAttachmentCount = subpass.inputAttachmentCount; + subpass2.pColorAttachments = &colorReference2; + if (hasDepth) { + subpass2.pDepthStencilAttachment = &depthReference2; + } + subpass2.pipelineBindPoint = subpass.pipelineBindPoint; + subpass2.viewMask = multiview ? viewMask : 0; + if (multisample) { + colorResolveReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorResolveReference2.attachment = color_resolve_reference.attachment; // the non-msaa color buffer. + colorResolveReference2.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + subpass2.pResolveAttachments = &colorResolveReference2; + } else { + subpass2.pResolveAttachments = nullptr; + } + + VkRenderPassCreateInfo2KHR rp2{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR }; + rp2.pAttachments = attachments2; + rp2.pDependencies = deps2; + rp2.attachmentCount = rp.attachmentCount; + rp2.dependencyCount = rp.dependencyCount; + rp2.correlatedViewMaskCount = multiview ? 1 : 0; + rp2.pCorrelatedViewMasks = multiview ? &viewMask : nullptr; + rp2.pSubpasses = &subpass2; + rp2.subpassCount = 1; + res = vkCreateRenderPass2KHR(vulkan->GetDevice(), &rp2, nullptr, &pass); + } else { + res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass); + } + _assert_(res == VK_SUCCESS); _assert_(pass != VK_NULL_HANDLE); return pass; diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index f710330fc5..94092b2166 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -223,6 +223,7 @@ PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; } // namespace PPSSPP_VK using namespace PPSSPP_VK; @@ -720,6 +721,9 @@ void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledE LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); } + if (enabledExtensions.KHR_create_renderpass2) { + LOAD_DEVICE_FUNC(device, vkCreateRenderPass2KHR); + } } void VulkanFree() { diff --git a/Common/GPU/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h index 4f2d97d045..caaef0d597 100644 --- a/Common/GPU/Vulkan/VulkanLoader.h +++ b/Common/GPU/Vulkan/VulkanLoader.h @@ -224,6 +224,7 @@ extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; } // namespace PPSSPP_VK // For fast extension-enabled checks. diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index a215ff4528..dc8f3ab9d8 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -857,7 +857,15 @@ VKContext::VKContext(VulkanContext *vulkan) // VkSampleCountFlagBits is arranged correctly for our purposes. // Only support MSAA levels that have support for all three of color, depth, stencil. if (!caps_.isTilingGPU) { - caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); + // Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess + // of compatibility reports, so we'll just disable stencil in this case for now. + // There are potential workarounds for devices that don't support it, but those are nearly non-existent now. + const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve; + if (vulkan->Extensions().KHR_depth_stencil_resolve) { + caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); + } else { + caps_.multiSampleLevelsMask = 1; + } } else { caps_.multiSampleLevelsMask = 1; } From a0f27c74426dc3c41810fa4eefa14d1eb1a35943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 20:45:06 +0100 Subject: [PATCH 502/715] Implement depth/stencil resolve. (We probably only need depth resolve since we don't texture from stencil, but whatever). --- Common/GPU/Vulkan/VulkanFramebuffer.cpp | 49 ++++++++++++++++--------- UI/GameSettingsScreen.cpp | 2 +- headless/Headless.cpp | 2 + 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 228ab956e3..8933a5470c 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -323,37 +323,37 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas } } - VkAttachmentReference color_reference{}; - color_reference.attachment = colorAttachmentIndex; - color_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentReference colorReference{}; + colorReference.attachment = colorAttachmentIndex; + colorReference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentReference depth_reference{}; - depth_reference.attachment = depthAttachmentIndex; - depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkAttachmentReference depthReference{}; + depthReference.attachment = depthAttachmentIndex; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass{}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.flags = 0; if (selfDependency) { subpass.inputAttachmentCount = 1; - subpass.pInputAttachments = &color_reference; + subpass.pInputAttachments = &colorReference; } else { subpass.inputAttachmentCount = 0; subpass.pInputAttachments = nullptr; } subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_reference; + subpass.pColorAttachments = &colorReference; - VkAttachmentReference color_resolve_reference; + VkAttachmentReference colorResolveReference; if (multisample) { - color_resolve_reference.attachment = 0; // the non-msaa color buffer. - color_resolve_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - subpass.pResolveAttachments = &color_resolve_reference; + colorResolveReference.attachment = 0; // the non-msaa color buffer. + colorResolveReference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + subpass.pResolveAttachments = &colorResolveReference; } else { subpass.pResolveAttachments = nullptr; } if (hasDepth) { - subpass.pDepthStencilAttachment = &depth_reference; + subpass.pDepthStencilAttachment = &depthReference; } subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = nullptr; @@ -427,13 +427,13 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas VkAttachmentReference2KHR colorReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; colorReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - colorReference2.attachment = color_reference.attachment; - colorReference2.layout = color_reference.layout; + colorReference2.attachment = colorReference.attachment; + colorReference2.layout = colorReference.layout; VkAttachmentReference2KHR depthReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; depthReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - depthReference2.attachment = depth_reference.attachment; - depthReference2.layout = depth_reference.layout; + depthReference2.attachment = depthReference.attachment; + depthReference2.layout = depthReference.layout; VkSubpassDependency2KHR deps2[2]{}; for (int i = 0; i < numDeps; i++) { @@ -463,13 +463,26 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas subpass2.viewMask = multiview ? viewMask : 0; if (multisample) { colorResolveReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - colorResolveReference2.attachment = color_resolve_reference.attachment; // the non-msaa color buffer. + colorResolveReference2.attachment = colorResolveReference.attachment; // the non-msaa color buffer. colorResolveReference2.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; subpass2.pResolveAttachments = &colorResolveReference2; } else { subpass2.pResolveAttachments = nullptr; } + VkAttachmentReference2KHR depthResolveReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + VkSubpassDescriptionDepthStencilResolveKHR depthStencilResolve{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR }; + if (hasDepth && multisample) { + subpass2.pNext = &depthStencilResolve; + depthResolveReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthResolveReference2.attachment = 1; + depthResolveReference2.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + // TODO: Some games might benefit from the other depth resolve modes when depth texturing. + depthStencilResolve.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + depthStencilResolve.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + depthStencilResolve.pDepthStencilResolveAttachment = &depthResolveReference2; + } + VkRenderPassCreateInfo2KHR rp2{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR }; rp2.pAttachments = attachments2; rp2.pDependencies = deps2; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 89ff1b49d7..9bb4f69995 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -306,7 +306,7 @@ void GameSettingsScreen::CreateViews() { }); if (draw->GetDeviceCaps().multiSampleLevelsMask != 1) { - static const char *msaaModes[] = { "Off", "2xMSAA", "4xMSAA", "8xMSAA", "16xMSAA" }; + static const char *msaaModes[] = { "Off", "2x", "4x", "8x", "16x" }; auto msaaChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iMultiSampleLevel, gr->T("Antialiasing (MSAA)"), msaaModes, 0, ARRAY_SIZE(msaaModes), gr->GetName(), screenManager())); msaaChoice->OnChoice.Add([&](UI::EventParams &) -> UI::EventReturn { NativeMessageReceived("gpu_renderResized", ""); diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 3b2bd96dd6..fbea58e036 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -426,6 +426,8 @@ int main(int argc, const char* argv[]) g_Config.bSkipGPUReadbacks = false; g_Config.bHardwareTransform = true; g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this. + g_Config.iMultiSampleLevel = 0; + g_Config.iMultiSampleQuality = 0; g_Config.bVertexCache = false; g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR; From 8208768c151a8947ad1673ac46abbfa92e07963b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 22:59:42 +0100 Subject: [PATCH 503/715] Add a pipeline flag for USES_DISCARD. Will be used for the MSAA quality setting. --- Common/GPU/Vulkan/VulkanQueueRunner.h | 1 + GPU/Common/FragmentShaderGenerator.cpp | 4 ++++ GPU/Common/FragmentShaderGenerator.h | 1 + GPU/Vulkan/PipelineManagerVulkan.cpp | 3 +++ GPU/Vulkan/PipelineManagerVulkan.h | 1 + 5 files changed, 10 insertions(+) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 0f844bbd88..0d5f5053ae 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -51,6 +51,7 @@ enum class PipelineFlags : u8 { USES_INPUT_ATTACHMENT = (1 << 3), USES_GEOMETRY_SHADER = (1 << 4), USES_MULTIVIEW = (1 << 5), // Inherited from the render pass it was created with. + USES_DISCARD = (1 << 6), }; ENUM_CLASS_BITOPS(PipelineFlags); diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 93f30f3323..8ed019b9e1 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -922,6 +922,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu const char *discardStatement = testForceToZero ? "v.a = 0.0;" : "DISCARD;"; if (enableAlphaTest) { + *fragmentShaderFlags |= FragmentShaderFlags::USES_DISCARD; + if (alphaTestAgainstZero) { // When testing against 0 (extremely common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. @@ -959,6 +961,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } if (enableColorTest) { + *fragmentShaderFlags |= FragmentShaderFlags::USES_DISCARD; + if (colorTestAgainstZero) { // When testing against 0 (common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. diff --git a/GPU/Common/FragmentShaderGenerator.h b/GPU/Common/FragmentShaderGenerator.h index 8f358fa7ff..88c2c3f9d6 100644 --- a/GPU/Common/FragmentShaderGenerator.h +++ b/GPU/Common/FragmentShaderGenerator.h @@ -43,6 +43,7 @@ struct FShaderID; // Can technically be deduced from the fragment shader ID, but this is safer. enum class FragmentShaderFlags : u32 { INPUT_ATTACHMENT = 1, + USES_DISCARD = 2, }; ENUM_CLASS_BITOPS(FragmentShaderFlags); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index e52df37028..6b8941be07 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -344,6 +344,9 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * if (fs->Flags() & FragmentShaderFlags::INPUT_ATTACHMENT) { pipelineFlags |= PipelineFlags::USES_INPUT_ATTACHMENT; } + if (fs->Flags() & FragmentShaderFlags::USES_DISCARD) { + pipelineFlags |= PipelineFlags::USES_DISCARD; + } if (vs->Flags() & VertexShaderFlags::MULTI_VIEW) { pipelineFlags |= PipelineFlags::USES_MULTIVIEW; } diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 32e45c3faf..831136c955 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -62,6 +62,7 @@ struct VulkanPipeline { bool UsesDepthStencil() const { return (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) != 0; } bool UsesInputAttachment() const { return (pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) != 0; } bool UsesGeometryShader() const { return (pipelineFlags & PipelineFlags::USES_GEOMETRY_SHADER) != 0; } + bool UsesDiscard() const { return (pipelineFlags & PipelineFlags::USES_DISCARD) != 0; } u32 GetVariantsBitmask() const; }; From b9ea8de135e011b7f4560d5b911da75ba40a259b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 23:30:35 +0100 Subject: [PATCH 504/715] Use raster copies to work around lack of working copy support in MSAA mode. --- Common/GPU/thin3d.h | 3 ++- GPU/Common/FramebufferManagerCommon.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index da3cc0a35f..edab98e69e 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -437,10 +437,11 @@ public: int Width() { return width_; } int Height() { return height_; } int Layers() { return layers_; } + int MultiSampleLevel() { return multiSampleLevel_; } virtual void UpdateTag(const char *tag) {} protected: - int width_ = -1, height_ = -1, layers_ = 1; + int width_ = -1, height_ = -1, layers_ = 1, multiSampleLevel_ = 0; }; class Buffer : public RefCountedObject { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 724d123cb7..ec68cb15c4 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -3002,9 +3002,9 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX bool useBlit = channel == RASTER_COLOR ? draw_->GetDeviceCaps().framebufferBlitSupported : false; bool useCopy = channel == RASTER_COLOR ? draw_->GetDeviceCaps().framebufferCopySupported : false; - if (dst == currentRenderVfb_) { + if (dst == currentRenderVfb_ || dst->fbo->MultiSampleLevel() != 0 || src->fbo->MultiSampleLevel() != 0) { // If already bound, using either a blit or a copy is unlikely to be an optimization. - // So we're gonna use a raster draw instead. + // So we're gonna use a raster draw instead. Also multisampling has problems with copies currently. useBlit = false; useCopy = false; } From 4990683cf2e421d9860eb1a36917f6200ba88351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 23:56:55 +0100 Subject: [PATCH 505/715] Implement "enhanced" multisample quality setting --- Common/GPU/Vulkan/VulkanContext.cpp | 1 + Common/GPU/Vulkan/VulkanRenderManager.cpp | 7 ++++++- Common/GPU/Vulkan/VulkanRenderManager.h | 3 ++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 7 +++++-- Common/GPU/thin3d.h | 1 + 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 7f7688081b..a3459ec5f6 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -612,6 +612,7 @@ void VulkanContext::ChooseDevice(int physical_device) { deviceFeatures_.enabled.standard.shaderClipDistance = deviceFeatures_.available.standard.shaderClipDistance; deviceFeatures_.enabled.standard.shaderCullDistance = deviceFeatures_.available.standard.shaderCullDistance; deviceFeatures_.enabled.standard.geometryShader = deviceFeatures_.available.standard.geometryShader; + deviceFeatures_.enabled.standard.sampleRateShading = deviceFeatures_.available.standard.sampleRateShading; deviceFeatures_.enabled.multiview = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; deviceFeatures_.enabled.multiview.multiview = deviceFeatures_.available.multiview.multiview; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 0fed2b71a8..a8d8e5db42 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -80,6 +80,11 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; ms.rasterizationSamples = multisample ? sampleCount : VK_SAMPLE_COUNT_1_BIT; + if (multisample && (flags_ & PipelineFlags::USES_DISCARD)) { + // Extreme quality + ms.sampleShadingEnable = true; + ms.minSampleShading = 1.0f; + } // We will use dynamic viewport state. pipe.pVertexInputState = &desc->vis; @@ -500,7 +505,7 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { } VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag) { - VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(tag); + VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(pipelineFlags, tag); _dbg_assert_(desc->vertexShader); _dbg_assert_(desc->fragmentShader); pipeline->desc = desc; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 218e87524c..b729b6b09c 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -115,7 +115,7 @@ struct VKRComputePipelineDesc { // Wrapped pipeline. Doesn't own desc. struct VKRGraphicsPipeline { - VKRGraphicsPipeline(const char *tag) : tag_(tag) {} + VKRGraphicsPipeline(PipelineFlags flags, const char *tag) : flags_(flags), tag_(tag) {} ~VKRGraphicsPipeline() { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { delete pipeline[i]; @@ -139,6 +139,7 @@ struct VKRGraphicsPipeline { VkSampleCountFlagBits SampleCount() const { return sampleCount_; } private: std::string tag_; + PipelineFlags flags_; VkSampleCountFlagBits sampleCount_ = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM; }; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index dc8f3ab9d8..ac75040629 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -832,6 +832,8 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.blendMinMaxSupported = true; caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0; caps_.multiViewSupported = vulkan->GetDeviceFeatures().enabled.multiview.multiview != 0; + caps_.sampleRateShadingSupported = vulkan->GetDeviceFeatures().enabled.standard.sampleRateShading != 0; + const auto &limits = vulkan->GetPhysicalDeviceProperties().properties.limits; auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties; @@ -1575,11 +1577,12 @@ uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const { // use this frame's init command buffer. class VKFramebuffer : public Framebuffer { public: - VKFramebuffer(VKRFramebuffer *fb) : buf_(fb) { + VKFramebuffer(VKRFramebuffer *fb, int multiSampleLevel) : buf_(fb) { _assert_msg_(fb, "Null fb in VKFramebuffer constructor"); width_ = fb->width; height_ = fb->height; layers_ = fb->numLayers; + multiSampleLevel_ = multiSampleLevel; } ~VKFramebuffer() { _assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?"); @@ -1605,7 +1608,7 @@ Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { VkCommandBuffer cmd = renderManager_.GetInitCmd(); VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag); - return new VKFramebuffer(vkrfb); + return new VKFramebuffer(vkrfb, desc.multiSampleLevel); } void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) { diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index edab98e69e..78ae3375b8 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -579,6 +579,7 @@ struct DeviceCaps { bool blendMinMaxSupported; bool multiViewSupported; bool isTilingGPU; // This means that it benefits from correct store-ops, msaa without backing memory, etc. + bool sampleRateShadingSupported; u32 multiSampleLevelsMask; // Bit n is set if (1 << n) is a valid multisample level. Bit 0 is always set. std::string deviceName; // The device name to use when creating the thin3d context, to get the same one. From f758cc0de4797d111ecc40c79fb4d524882ffa3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 00:06:05 +0100 Subject: [PATCH 506/715] Remove quality setting for now, we default to a balanced setting. --- Core/Config.cpp | 1 - Core/Config.h | 1 - 2 files changed, 2 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index bd3e2dccf2..b053500bf1 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -902,7 +902,6 @@ static ConfigSetting graphicsSettings[] = { // Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine. ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, true, true), ConfigSetting("MultiSampleLevel", &g_Config.iMultiSampleLevel, 0, true, true), // Number of samples is 1 << iMultiSampleLevel - ConfigSetting("MultiSampleQuality", &g_Config.iMultiSampleQuality, 0, true, true), // 0 = multisampling, 1 = halfway to SGSSAA, 2 = SGSSAA. ReportedConfigSetting("VertexDecCache", &g_Config.bVertexCache, false, true, true), ReportedConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, true, true), diff --git a/Core/Config.h b/Core/Config.h index 05244592be..342b5c3450 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -211,7 +211,6 @@ public: int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on. int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso int iMultiSampleLevel; - int iMultiSampleQuality; int bHighQualityDepth; bool bReplaceTextures; bool bSaveNewTextures; From 7950a00c14d7081c6abd01b8a2fbc6cdf512e1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 00:17:21 +0100 Subject: [PATCH 507/715] Headless buildfix. Crashfix in shader generator test. --- GPU/Common/FragmentShaderGenerator.cpp | 8 ++------ GPU/Common/VertexShaderGenerator.cpp | 4 +--- headless/Headless.cpp | 1 - unittest/TestShaderGenerators.cpp | 24 ++++++++++++++---------- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 8ed019b9e1..2d85308a92 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -51,9 +51,7 @@ static const SamplerDef samplersStereo[3] = { bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint64_t *uniformMask, FragmentShaderFlags *fragmentShaderFlags, std::string *errorString) { *uniformMask = 0; - if (fragmentShaderFlags) { - *fragmentShaderFlags = (FragmentShaderFlags)0; - } + *fragmentShaderFlags = (FragmentShaderFlags)0; errorString->clear(); bool useStereo = id.Bit(FS_BIT_STEREO); @@ -203,9 +201,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu p.F("layout (set = 1, binding = %d) uniform sampler2DArray fbotex;\n", DRAW_BINDING_2ND_TEXTURE); } else if (fetchFramebuffer) { p.F("layout (input_attachment_index = 0, set = 1, binding = %d) uniform subpassInput inputColor;\n", DRAW_BINDING_INPUT_ATTACHMENT); - if (fragmentShaderFlags) { - *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; - } + *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; } if (shaderDepalMode != ShaderDepalMode::OFF) { diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index b797e78b64..b7d430fa59 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -130,9 +130,7 @@ static const char * const boneWeightDecl[9] = { bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, VertexShaderFlags *vertexShaderFlags, std::string *errorString) { *attrMask = 0; *uniformMask = 0; - if (vertexShaderFlags) { - *vertexShaderFlags = (VertexShaderFlags)0; - } + *vertexShaderFlags = (VertexShaderFlags)0; bool highpFog = false; bool highpTexcoord = false; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index fbea58e036..98aefd31e7 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -427,7 +427,6 @@ int main(int argc, const char* argv[]) g_Config.bHardwareTransform = true; g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this. g_Config.iMultiSampleLevel = 0; - g_Config.iMultiSampleQuality = 0; g_Config.bVertexCache = false; g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR; diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index 7722c9f947..89e0eaafec 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -30,32 +30,34 @@ static constexpr size_t CODE_BUFFER_SIZE = 32768; bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { buffer[0] = '\0'; + FragmentShaderFlags flags; + uint64_t uniformMask; switch (lang) { case ShaderLanguage::GLSL_VULKAN: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_1xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_3xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D9: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D11: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } default: return false; @@ -65,33 +67,35 @@ bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { buffer[0] = '\0'; + VertexShaderFlags flags; + uint32_t attrMask; uint64_t uniformMask; switch (lang) { case ShaderLanguage::GLSL_VULKAN: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_1xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_3xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D9: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D11: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } default: return false; From 29a2157485f7b0da67b33e196a17735ceceac16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 15:22:14 +0100 Subject: [PATCH 508/715] Correctly handle input attachments with CreateRenderpass2. But also don't use it while not multisampling. --- Common/GPU/Vulkan/VulkanFramebuffer.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 8933a5470c..78e80f7c9d 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -409,7 +409,11 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas VkRenderPass pass; VkResult res; - if (vulkan->Extensions().KHR_create_renderpass2) { + + // We could always use renderpass2, but I think it'll get both paths better tested if we + // only use it with multisample enabled. + // if (vulkan->Extensions().KHR_create_renderpass2) { + if (multisample) { // It's a bit unfortunate that we can't rely on vkCreateRenderPass2, because here we now have // to do a bunch of struct conversion, just to not have to repeat the logic from above. VkAttachmentDescription2KHR attachments2[4]{}; @@ -454,7 +458,10 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas VkSubpassDescription2KHR subpass2{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR }; subpass2.colorAttachmentCount = subpass.colorAttachmentCount; subpass2.flags = subpass.flags; - subpass2.inputAttachmentCount = subpass.inputAttachmentCount; + if (selfDependency) { + subpass2.inputAttachmentCount = subpass.inputAttachmentCount; + subpass2.pInputAttachments = &colorReference2; + } subpass2.pColorAttachments = &colorReference2; if (hasDepth) { subpass2.pDepthStencilAttachment = &depthReference2; From 28e1b532bd981e13a1b1c18d450fa38dc3e8fa19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 18:15:13 +0100 Subject: [PATCH 509/715] Detect Apple/MoltenVK and allow multisampling. Unfortunately no support for sample rate shading. --- Common/GPU/Vulkan/VulkanContext.cpp | 2 +- Common/GPU/Vulkan/VulkanContext.h | 1 + Common/GPU/Vulkan/thin3d_vulkan.cpp | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index a3459ec5f6..33d27b40fb 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -57,7 +57,7 @@ std::string VulkanVendorString(uint32_t vendorId) { case VULKAN_VENDOR_ARM: return "ARM"; case VULKAN_VENDOR_QUALCOMM: return "Qualcomm"; case VULKAN_VENDOR_IMGTEC: return "Imagination"; - + case VULKAN_VENDOR_APPLE: return "Apple"; default: return StringFromFormat("%08x", vendorId); } diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index f30b1ee0a8..464b78a47d 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -35,6 +35,7 @@ enum { VULKAN_VENDOR_ARM = 0x000013B5, // Mali VULKAN_VENDOR_QUALCOMM = 0x00005143, VULKAN_VENDOR_IMGTEC = 0x00001010, // PowerVR + VULKAN_VENDOR_APPLE = 0x0000106b, // Apple through MoltenVK }; VK_DEFINE_HANDLE(VmaAllocator); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index ac75040629..da58b35215 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -845,7 +845,11 @@ VKContext::VKContext(VulkanContext *vulkan) case VULKAN_VENDOR_NVIDIA: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break; case VULKAN_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::VENDOR_QUALCOMM; break; case VULKAN_VENDOR_INTEL: caps_.vendor = GPUVendor::VENDOR_INTEL; break; - default: caps_.vendor = GPUVendor::VENDOR_UNKNOWN; break; + case VULKAN_VENDOR_APPLE: caps_.vendor = GPUVendor::VENDOR_APPLE; break; + default: + WARN_LOG(G3D, "Unknown vendor ID %08x", deviceProps.vendorID); + caps_.vendor = GPUVendor::VENDOR_UNKNOWN; + break; } bool hasLazyMemory = false; @@ -854,7 +858,7 @@ VKContext::VKContext(VulkanContext *vulkan) hasLazyMemory = true; } } - caps_.isTilingGPU = hasLazyMemory; + caps_.isTilingGPU = hasLazyMemory && caps_.vendor != GPUVendor::VENDOR_APPLE; // VkSampleCountFlagBits is arranged correctly for our purposes. // Only support MSAA levels that have support for all three of color, depth, stencil. From a1f6a40d1052369d7abacd13703f93ef82c34107 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 14:39:19 -0800 Subject: [PATCH 510/715] softgpu: Interpolate Z for 3D lines. Important for Me & My Katamari, see #16131. --- GPU/Software/Rasterizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index f31799d4ef..9677078805 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1253,7 +1253,7 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const BinCoords void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state) { // TODO: Use a proper line drawing algorithm that handles fractional endpoints correctly. Vec3 a(v0.screenpos.x, v0.screenpos.y, v0.screenpos.z); - Vec3 b(v1.screenpos.x, v1.screenpos.y, v0.screenpos.z); + Vec3 b(v1.screenpos.x, v1.screenpos.y, v1.screenpos.z); int dx = b.x - a.x; int dy = b.y - a.y; From 8a3e92aa387291471f4e224e520365c65ebc1df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 23:41:31 +0100 Subject: [PATCH 511/715] Not pretty, but with this, you can switch MSAA level at runtime. --- Common/Data/Convert/SmallDataConvert.h | 2 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 6 ++---- Common/GPU/Vulkan/VulkanRenderManager.cpp | 7 +++++-- Common/GPU/Vulkan/VulkanRenderManager.h | 4 +++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 13 ++++++++----- GPU/Common/FramebufferManagerCommon.h | 2 ++ GPU/GPUCommon.h | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 8 ++++++++ GPU/Vulkan/GPU_Vulkan.h | 1 + GPU/Vulkan/PipelineManagerVulkan.cpp | 6 ++++++ GPU/Vulkan/PipelineManagerVulkan.h | 2 ++ 12 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Common/Data/Convert/SmallDataConvert.h b/Common/Data/Convert/SmallDataConvert.h index 05f92759c7..e1aee3226b 100644 --- a/Common/Data/Convert/SmallDataConvert.h +++ b/Common/Data/Convert/SmallDataConvert.h @@ -21,7 +21,7 @@ extern const float one_over_255_x4[4]; extern const float exactly_255_x4[4]; // Utilities useful for filling in std140-layout uniform buffers, and similar. -// NEON intrinsics: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491f/BABDCGGF.html +// NEON intrinsics: https://developer.arm.com/documentation/den0018/a/NEON-Intrinsics?lang=en // LSBs in f[0], etc. inline void Uint8x4ToFloat4(float f[4], uint32_t u) { diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 7f7585c28e..644f019dc0 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1327,10 +1327,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkSampleCountFlagBits fbSampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; if (RenderPassTypeHasMultisample(rpType) && fbSampleCount != graphicsPipeline->SampleCount()) { - // Sample count might have started mismatching if the user changed multisampling mode. Let's get rid of all variants - // and start over. - // (We could avoid this if sample count was baked into the rpType, but I don't want that to grow too big). - graphicsPipeline->DestroyAllVariants(vulkan_); + // Shouldn't happen, pipeline invalidation after render resized should have taken care of this. + _assert_(false); } if (!graphicsPipeline->pipeline[(size_t)rpType]) { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index a8d8e5db42..4f95a24458 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -130,10 +130,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR return success; } -void VKRGraphicsPipeline::DestroyAllVariants(VulkanContext *vulkan) { +void VKRGraphicsPipeline::DestroyVariants(VulkanContext *vulkan, bool msaaOnly) { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (!this->pipeline[i]) continue; + if (msaaOnly && (i & (int)RenderPassType::MULTISAMPLE) == 0) + continue; + VkPipeline pipeline = this->pipeline[i]->BlockUntilReady(); // pipeline can be nullptr here, if it failed to compile before. if (pipeline) { @@ -145,7 +148,7 @@ void VKRGraphicsPipeline::DestroyAllVariants(VulkanContext *vulkan) { } void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { - DestroyAllVariants(vulkan); + DestroyVariants(vulkan, false); vulkan->Delete().QueueCallback([](void *p) { VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p; delete pipeline; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index b729b6b09c..c15d9027a2 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -124,7 +124,7 @@ struct VKRGraphicsPipeline { bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount); - void DestroyAllVariants(VulkanContext *vulkan); + void DestroyVariants(VulkanContext *vulkan, bool msaaOnly); // This deletes the whole VKRGraphicsPipeline, you must remove your last pointer to it when doing this. void QueueForDeletion(VulkanContext *vulkan); @@ -458,6 +458,8 @@ public: return outOfDateFrames_ > VulkanContext::MAX_INFLIGHT_FRAMES; } + void Invalidate(InvalidationFlags flags); + void ResetStats(); private: diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index da58b35215..258e014910 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -242,7 +242,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con #endif VkShaderModule shaderModule = VK_NULL_HANDLE; - if (vulkan->CreateShaderModule(spirv, &shaderModule, vkstage_ == VK_SHADER_STAGE_VERTEX_BIT ? "thin3d_vs" : "thin3d_fs")) { + if (vulkan->CreateShaderModule(spirv, &shaderModule, tag_.c_str())) { module_ = Promise::AlreadyDone(shaderModule); ok_ = true; } else { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index ec68cb15c4..175d36d0bc 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2878,11 +2878,7 @@ static void DoRelease(T *&obj) { obj = nullptr; } -void FramebufferManagerCommon::DeviceLost() { - DestroyAllFBOs(); - - presentation_->DeviceLost(); - +void FramebufferManagerCommon::ReleasePipelines() { for (int i = 0; i < ARRAY_SIZE(reinterpretFromTo_); i++) { for (int j = 0; j < ARRAY_SIZE(reinterpretFromTo_); j++) { DoRelease(reinterpretFromTo_[i][j]); @@ -2899,9 +2895,16 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(draw2DPipelineDepth_); DoRelease(draw2DPipeline565ToDepth_); DoRelease(draw2DPipeline565ToDepthDeswizzle_); +} +void FramebufferManagerCommon::DeviceLost() { + DestroyAllFBOs(); + + presentation_->DeviceLost(); draw2D_.DeviceLost(); + ReleasePipelines(); + draw_ = nullptr; } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 0a22fdb366..27380df454 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -443,6 +443,8 @@ public: int scaleFactor, // usually unused, except for swizzle... Draw2DPipeline *pipeline, const char *tag); + void ReleasePipelines(); + protected: virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); // Used for when a shader is required, such as GLES. diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 76b14bdc9e..7d2cde8b12 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -267,7 +267,7 @@ protected: void DeviceLost() override; void DeviceRestore() override; - void CheckRenderResized(); + virtual void CheckRenderResized(); // Add additional common features dependent on other features, which may be backend-determined. u32 CheckGPUFeaturesLate(u32 features) const; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index f735f3267f..1606073ee9 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -465,6 +465,14 @@ void GPU_Vulkan::DestroyDeviceObjects() { } } +void GPU_Vulkan::CheckRenderResized() { + if (renderResized_) { + GPUCommon::CheckRenderResized(); + pipelineManager_->InvalidateMSAAPipelines(); + framebufferManager_->ReleasePipelines(); + } +} + void GPU_Vulkan::DeviceLost() { CancelReady(); while (!IsReady()) { diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 1aa405e1f6..f4b56c27e4 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -70,6 +70,7 @@ public: protected: void FinishDeferred() override; + void CheckRenderResized() override; private: void Flush() { diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 6b8941be07..0c081c3f78 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -49,6 +49,12 @@ void PipelineManagerVulkan::Clear() { pipelines_.Clear(); } +void PipelineManagerVulkan::InvalidateMSAAPipelines() { + pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) { + value->pipeline->DestroyVariants(vulkan_, true); + }); +} + void PipelineManagerVulkan::DeviceLost() { Clear(); if (pipelineCache_ != VK_NULL_HANDLE) diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 831136c955..dcd13c54c5 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -88,6 +88,8 @@ public: void DeviceLost(); void DeviceRestore(VulkanContext *vulkan); + void InvalidateMSAAPipelines(); + std::string DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType); std::vector DebugGetObjectIDs(DebugShaderType type); From 5610734d40332584682c97f9c5616db847df1e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 00:30:06 +0100 Subject: [PATCH 512/715] Assert improvement --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 644f019dc0..2089ec59d7 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1327,8 +1327,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkSampleCountFlagBits fbSampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; if (RenderPassTypeHasMultisample(rpType) && fbSampleCount != graphicsPipeline->SampleCount()) { - // Shouldn't happen, pipeline invalidation after render resized should have taken care of this. - _assert_(false); + // should have been invalidated. + _assert_msg_(graphicsPipeline->SampleCount() == VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM, + "expected %d sample count, got %d", fbSampleCount, graphicsPipeline->SampleCount()); } if (!graphicsPipeline->pipeline[(size_t)rpType]) { From c5a98e62dd0f30b152d0609f821c52816f5678fb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 21:56:05 -0800 Subject: [PATCH 513/715] softgpu: Cull verts outside post-viewport Z. Shouldn't have removed this before, points are still culled when depth clamp is off and throughmode is off. Fixes Crazy Taxi graphics glitches. --- GPU/Software/TransformUnit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 0119250316..ffe1119157 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -181,7 +181,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, scaled.z = 0.f; else if (scaled.z > 65535.0f) scaled.z = 65535.0f; - } else if (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0) { + } else if (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0 || scaled.z < 0.0f || scaled.z >= 65536.0f) { *outside_range_flag = true; } From 9fcc6857f6486580565874466cf52f7d03d8d85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Henrique?= Date: Fri, 2 Dec 2022 03:10:57 -0300 Subject: [PATCH 514/715] Fix wrong vreinterpret neon intrinsic usage. This fixes a compilation failure introduced on d0e8cfa36518b. --- Common/Data/Convert/SmallDataConvert.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/Data/Convert/SmallDataConvert.h b/Common/Data/Convert/SmallDataConvert.h index 05f92759c7..c388eb9eb7 100644 --- a/Common/Data/Convert/SmallDataConvert.h +++ b/Common/Data/Convert/SmallDataConvert.h @@ -57,7 +57,7 @@ inline uint32_t Float4ToUint8x4(const float f[4]) { uint32x4_t ivalue32 = vcvtq_u32_f32(value); uint16x4_t ivalue16 = vqmovn_u32(ivalue32); uint8x8_t ivalue8 = vqmovn_u16(vcombine_u16(ivalue16, ivalue16)); // Is there no way to avoid the combine here? - uint32x2_t outValue32 = vreinterpret_u8_u32(ivalue8); + uint32x2_t outValue32 = vreinterpret_u32_u8(ivalue8); return vget_lane_u32(outValue32, 0); #else int i4[4]; @@ -86,7 +86,7 @@ inline uint32_t Float4ToUint8x4_NoClamp(const float f[4]) { uint32x4_t ivalue32 = vcvtq_u32_f32(value); uint16x4_t ivalue16 = vqmovn_u32(ivalue32); uint8x8_t ivalue8 = vqmovn_u16(vcombine_u16(ivalue16, ivalue16)); // Is there no way to avoid the combine here? - uint32x2_t outValue32 = vreinterpret_u8_u32(ivalue8); + uint32x2_t outValue32 = vreinterpret_u32_u8(ivalue8); return vget_lane_u32(outValue32, 0); #else u32 i4[4]; From d7224a84019aaeaa4bc53c0af2fe4ae6c3a6414d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 23:12:14 -0800 Subject: [PATCH 515/715] GE Debugger: Cleanup logspam on game exit. If you're stopped on a frame and quit, it was previously logging every command as it exited, thinking it was waiting on each. --- GPU/Debugger/Debugger.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index fa55ec6b8e..16143b882f 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -134,6 +134,11 @@ bool NotifyCommand(u32 pc) { if (IsBreakpoint(pc, op)) { GPUBreakpoints::ClearTempBreakpoints(); + if (coreState == CORE_POWERDOWN || !gpuDebug) { + breakNext = BreakNext::NONE; + return process; + } + auto info = gpuDebug->DissassembleOp(pc); if (lastStepTime >= 0.0) { NOTICE_LOG(G3D, "Waiting at %08x, %s (%fms)", pc, info.desc.c_str(), (time_now_d() - lastStepTime) * 1000.0); From 33abbca464114925dc06f8238726e07cc0dec264 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 23:13:20 -0800 Subject: [PATCH 516/715] softgpu: Optimize out texture proj for UVs. Seen in NFS Most Wanted 5-1-0. --- GPU/Software/Rasterizer.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 9677078805..18244fc105 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -132,7 +132,12 @@ void ComputeRasterizerState(RasterizerState *state, std::function flushF state->textureProj = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; if (state->textureProj) { // We may be able to optimize this off. This is actually kinda common. - if (gstate.tgenMatrix[2] == 0.0f && gstate.tgenMatrix[5] == 0.0f && gstate.tgenMatrix[8] == 0.0f && gstate.tgenMatrix[11] == 1.0f) { + const bool qZeroST = gstate.tgenMatrix[2] == 0.0f && gstate.tgenMatrix[5] == 0.0f; + const bool qZeroQ = gstate.tgenMatrix[8] == 0.0f; + + // Two common cases: the source q factor is zero, OR source is UV. + const bool qFactorZero = gstate.getUVProjMode() == GE_PROJMAP_UV; + if (qZeroST && (qZeroQ || qFactorZero) && gstate.tgenMatrix[11] == 1.0f) { state->textureProj = false; } } From 106d730a2053f0ea1ea7e0819c20dfa3c77d6948 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Dec 2022 23:20:25 -0800 Subject: [PATCH 517/715] GPU: Optimize out common case texture proj. NFS Most Wanted 5-1-0 uses this when it could use uv scale/offset. --- GPU/Common/ShaderId.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index e572f721de..cb9b10af75 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -173,8 +173,9 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, static const char *alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" }; -static bool MatrixNeedsProjection(const float m[12]) { - return m[2] != 0.0f || m[5] != 0.0f || m[8] != 0.0f || m[11] != 1.0f; +static bool MatrixNeedsProjection(const float m[12], GETexProjMapMode mode) { + // For GE_PROJMAP_UV, we can ignore m[8] since it multiplies to zero. + return m[2] != 0.0f || m[5] != 0.0f || (m[8] != 0.0f && mode != GE_PROJMAP_UV) || m[11] != 1.0f; } std::string FragmentShaderDesc(const FShaderID &id) { @@ -283,7 +284,7 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue(); bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue(); bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled(); - bool doTextureProjection = (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX && MatrixNeedsProjection(gstate.tgenMatrix)); + bool doTextureProjection = (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX && MatrixNeedsProjection(gstate.tgenMatrix, gstate.getUVProjMode())); bool doTextureAlpha = gstate.isTextureAlphaUsed(); bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT; From cd0acec3f01e22c1d15b77357e3b95f8a9a05750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 13:49:28 +0100 Subject: [PATCH 518/715] Crashfix the other backends --- GPU/D3D11/ShaderManagerD3D11.cpp | 6 ++++-- GPU/Directx9/ShaderManagerDX9.cpp | 8 +++++--- GPU/GLES/ShaderManagerGLES.cpp | 6 ++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index f8788f6df5..72668fc718 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -212,7 +212,8 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString); + VertexShaderFlags flags; + GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform); vsCache_[VSID] = vs; @@ -227,7 +228,8 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** // Fragment shader not in cache. Let's compile it. std::string genErrorString; uint64_t uniformMask; - GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, nullptr, &genErrorString); + FragmentShaderFlags flags; + GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &genErrorString); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); fs = new D3D11FragmentShader(device_, featureLevel_, FSID, codeBuffer_, useHWTransform); fsCache_[FSID] = fs; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 0b419cfe76..d7f31b8852 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -581,7 +581,8 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString)) { + VertexShaderFlags flags; + if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString)) { vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform); } if (!vs || vs->Failed()) { @@ -606,7 +607,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // Can still work with software transform. uint32_t attrMask; uint64_t uniformMask; - bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString); + bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString); _assert_(success); vs = new VSShader(device_, VSID, codeBuffer_, false); } @@ -623,7 +624,8 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // Fragment shader not in cache. Let's compile it. std::string errorString; uint64_t uniformMask; - bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, nullptr, &errorString); + FragmentShaderFlags flags; + bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString); // We're supposed to handle all possible cases. _assert_(success); fs = new PSShader(device_, FSID, codeBuffer_); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index d36a68fe7a..3f70c1d243 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -751,7 +751,8 @@ void ShaderManagerGLES::DirtyLastShader() { Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) { uint64_t uniformMask; std::string errorString; - if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, nullptr, &errorString)) { + FragmentShaderFlags flags; + if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString)) { ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } @@ -766,7 +767,8 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { uint32_t attrMask; uint64_t uniformMask; std::string errorString; - if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &errorString)) { + VertexShaderFlags flags; + if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &errorString)) { ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } From b41a782fcd0a2468f4ccf76fc049cc9453d713ed Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 2 Dec 2022 14:32:27 +0100 Subject: [PATCH 519/715] Revert "Centralize ClearCacheNextFrame" This reverts commit cbfa4bfc8eef3a5f0e09e0ea2c3113bb2a88a7d5. --- GPU/Common/TextureCacheCommon.cpp | 5 ++++- GPU/Common/TextureCacheCommon.h | 1 + GPU/D3D11/GPU_D3D11.cpp | 4 ++++ GPU/D3D11/GPU_D3D11.h | 1 + GPU/Directx9/GPU_DX9.cpp | 4 ++++ GPU/Directx9/GPU_DX9.h | 1 + GPU/GLES/GPU_GLES.cpp | 4 ++++ GPU/GLES/GPU_GLES.h | 1 + GPU/GPUCommon.cpp | 1 + GPU/GPUInterface.h | 3 +++ GPU/Software/SoftGpu.h | 1 + GPU/Vulkan/GPU_Vulkan.cpp | 4 ++++ GPU/Vulkan/GPU_Vulkan.h | 1 + 13 files changed, 30 insertions(+), 1 deletion(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index f5e7bc2889..893772c31b 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1197,7 +1197,6 @@ bool TextureCacheCommon::GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffe } void TextureCacheCommon::NotifyConfigChanged() { - clearCacheNextFrame_ = true; int scaleFactor = g_Config.iTexScalingLevel; if (!gstate_c.Use(GPU_USE_TEXTURE_NPOT)) { @@ -2579,6 +2578,10 @@ void TextureCacheCommon::InvalidateAll(GPUInvalidationType /*unused*/) { } } +void TextureCacheCommon::ClearNextFrame() { + clearCacheNextFrame_ = true; +} + std::string AttachCandidate::ToString() const { return StringFromFormat("[%s seq:%d rel:%d C:%08x/%d(%s) Z:%08x/%d X:%d Y:%d reint: %s]", this->channel == RASTER_COLOR ? "COLOR" : "DEPTH", diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 4d46ff6590..bbaf0eecde 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -323,6 +323,7 @@ public: bool SetOffsetTexture(u32 yOffset); void Invalidate(u32 addr, int size, GPUInvalidationType type); void InvalidateAll(GPUInvalidationType type); + void ClearNextFrame(); TextureShaderCache *GetTextureShaderCache() { return textureShaderCache_; } diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 8259d9fb5c..6e3eb0d740 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -223,6 +223,10 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) { ); } +void GPU_D3D11::ClearCacheNextFrame() { + textureCacheD3D11_->ClearNextFrame(); +} + void GPU_D3D11::ClearShaderCache() { shaderManagerD3D11_->ClearShaders(); drawEngine_.ClearInputLayoutMap(); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index e56acc632a..0cba325618 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -41,6 +41,7 @@ public: void ExecuteOp(u32 op, u32 diff) override; void GetStats(char *buffer, size_t bufsize) override; + void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index c4053953cc..e13a3b4f3d 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -220,6 +220,10 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) { ); } +void GPU_DX9::ClearCacheNextFrame() { + textureCacheDX9_->ClearNextFrame(); +} + void GPU_DX9::ClearShaderCache() { shaderManagerDX9_->ClearCache(true); } diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index ff23b3fb23..0ec463e55e 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -41,6 +41,7 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; + void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index c110380c91..00f5eb43cf 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -362,6 +362,10 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) { ); } +void GPU_GLES::ClearCacheNextFrame() { + textureCacheGL_->ClearNextFrame(); +} + void GPU_GLES::ClearShaderCache() { shaderManagerGL_->ClearCache(true); } diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index d9ac76390f..4955a3c511 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -49,6 +49,7 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; + void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d11cd7921a..62112f899e 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -631,6 +631,7 @@ void GPUCommon::NotifyDisplayResized() { // if "transparent". void GPUCommon::CheckConfigChanged() { if (configChanged_) { + ClearCacheNextFrame(); gstate_c.useFlags = CheckGPUFeatures(); drawEngineCommon_->NotifyConfigChanged(); textureCache_->NotifyConfigChanged(); diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 625fc4487d..1c859b786e 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -245,6 +245,9 @@ public: virtual bool PerformWriteColorFromMemory(u32 dest, int size) = 0; virtual bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags = WriteStencil::NEEDS_CLEAR) = 0; + // Will cause the texture cache to be cleared at the start of the next frame. + virtual void ClearCacheNextFrame() = 0; + // Internal hack to avoid interrupts from "PPGe" drawing (utility UI, etc) virtual void EnableInterrupts(bool enable) = 0; diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 4ddb0fa782..508baa6d0e 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -144,6 +144,7 @@ public: bool PerformReadbackToMemory(u32 dest, int size) override; bool PerformWriteColorFromMemory(u32 dest, int size) override; bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags) override; + void ClearCacheNextFrame() override {} void DeviceLost() override; void DeviceRestore() override; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 0c50c361bd..aed306b4c2 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -514,6 +514,10 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { ); } +void GPU_Vulkan::ClearCacheNextFrame() { + textureCacheVulkan_->ClearNextFrame(); +} + void GPU_Vulkan::ClearShaderCache() { // TODO } diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 1aa405e1f6..ee45b43e5b 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -51,6 +51,7 @@ public: void ExecuteOp(u32 op, u32 diff) override; void GetStats(char *buffer, size_t bufsize) override; + void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; From 75b558eb5f945581ac27f6773ffd837c09018e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 14:35:43 +0100 Subject: [PATCH 520/715] Address feedback --- Common/GPU/Vulkan/VulkanFramebuffer.cpp | 2 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 78e80f7c9d..20b6fa2ea7 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -290,7 +290,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT; attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.depthLoadAction); attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction); - attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); + attachments[attachmentCount].stencilLoadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.stencilLoadAction); attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 258e014910..802bde6bf3 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -864,7 +864,7 @@ VKContext::VKContext(VulkanContext *vulkan) // Only support MSAA levels that have support for all three of color, depth, stencil. if (!caps_.isTilingGPU) { // Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess - // of compatibility reports, so we'll just disable stencil in this case for now. + // of compatibility reports, so we'll just disable multisampling in this case for now. // There are potential workarounds for devices that don't support it, but those are nearly non-existent now. const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve; if (vulkan->Extensions().KHR_depth_stencil_resolve) { From 1e2cf07c6b650d1a8a605ab3bd8271e79cfedc2d Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 2 Dec 2022 15:16:41 +0100 Subject: [PATCH 521/715] OpenXR - Monster Hunter HUD fixed --- GPU/GLES/ShaderManagerGLES.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 0f730a3101..35f0a631c5 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -366,12 +366,12 @@ static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { else if (gstate.isClearModeColorMask()) hud = false; //HUD cannot be rendered with depth color mask else if (gstate.isClearModeDepthMask()) hud = false; - //HUD cannot be rendered with fog on - else if (gstate.isFogEnabled()) hud = false; //HUD texture has to contain alpha channel else if (!gstate.isTextureAlphaUsed()) hud = false; - //HUD cannot have full alpha + //HUD cannot have full texture alpha else if (gstate_c.textureFullAlpha) hud = false; + //HUD must have full vertex alpha + else if (!gstate_c.vertexFullAlpha) hud = false; //HUD cannot render FB screenshot else if (gstate_c.curTextureHeight == 272) hud = false; From 2d6c632bfec687ff4c59fd74216c784acff33c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 15:19:06 +0100 Subject: [PATCH 522/715] Check resolve mode, just to be safe. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 802bde6bf3..8381256640 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -867,7 +867,8 @@ VKContext::VKContext(VulkanContext *vulkan) // of compatibility reports, so we'll just disable multisampling in this case for now. // There are potential workarounds for devices that don't support it, but those are nearly non-existent now. const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve; - if (vulkan->Extensions().KHR_depth_stencil_resolve) { + if (vulkan->Extensions().KHR_depth_stencil_resolve && + ((resolveProperties.supportedDepthResolveModes & resolveProperties.supportedStencilResolveModes) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) { caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); } else { caps_.multiSampleLevelsMask = 1; From d554085388ef4730bfbcb3b15299bcf48d467101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 15:25:02 +0100 Subject: [PATCH 523/715] Implement copy operation properly for the multisampled case --- Common/GPU/Vulkan/VulkanBarrier.cpp | 1 + Common/GPU/Vulkan/VulkanFramebuffer.cpp | 11 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 130 ++++++++++++++++++++---- 3 files changed, 117 insertions(+), 25 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanBarrier.cpp b/Common/GPU/Vulkan/VulkanBarrier.cpp index e4f2d09089..d47f506845 100644 --- a/Common/GPU/Vulkan/VulkanBarrier.cpp +++ b/Common/GPU/Vulkan/VulkanBarrier.cpp @@ -9,4 +9,5 @@ void VulkanBarrier::Flush(VkCommandBuffer cmd) { imageBarriers_.clear(); srcStageMask_ = 0; dstStageMask_ = 0; + dependencyFlags_ = 0; } diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 20b6fa2ea7..ec50e3f7a4 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -155,10 +155,15 @@ void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKR ici.samples = sampleCount; ici.tiling = VK_IMAGE_TILING_OPTIMAL; ici.format = format; - // Strictly speaking we don't yet need VK_IMAGE_USAGE_SAMPLED_BIT for depth buffers since we do not yet sample depth buffers. - ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + ici.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + if (sampleCount == VK_SAMPLE_COUNT_1_BIT) { + ici.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + } if (color) { - ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (sampleCount == VK_SAMPLE_COUNT_1_BIT) { + ici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + } } else { ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 2089ec59d7..7b260c72e7 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1666,30 +1666,45 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { // First source barriers. if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - if (src->color.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } - if (dst->color.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } + SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); } // We can't copy only depth or only stencil unfortunately - or can we?. if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { _dbg_assert_(src->depth.image != VK_NULL_HANDLE); - if (src->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - } + SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); if (dst->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); _dbg_assert_(dst->depth.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } else { - // Kingdom Hearts: Subsequent copies to the same depth buffer without any other use. + // Kingdom Hearts: Subsequent copies twice to the same depth buffer without any other use. // Not super sure how that happens, but we need a barrier to pass sync validation. SetupTransferDstWriteAfterWrite(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); } } + recordBarrier_.Flush(cmd); + + bool multisampled = src->sampleCount != VK_SAMPLE_COUNT_1_BIT && dst->sampleCount != VK_SAMPLE_COUNT_1_BIT; + if (multisampled) { + // If both the targets are multisampled, copy the msaa targets too. + // For that, we need to transition them from their normally permanent VK_*_ATTACHMENT_OPTIMAL layouts, and then back. + if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + SetupTransitionToTransferSrc(src->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + SetupTransitionToTransferDst(dst->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + } + if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + // Kingdom Hearts: Subsequent copies to the same depth buffer without any other use. + // Not super sure how that happens, but we need a barrier to pass sync validation. + SetupTransitionToTransferSrc(src->msaaDepth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + SetupTransitionToTransferDst(dst->msaaDepth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + } + } recordBarrier_.Flush(cmd); @@ -1712,6 +1727,10 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; vkCmdCopyImage(cmd, src->color.image, src->color.layout, dst->color.image, dst->color.layout, 1, ©); + + if (multisampled) { + vkCmdCopyImage(cmd, src->msaaColor.image, src->msaaColor.layout, dst->msaaColor.image, dst->msaaColor.layout, 1, ©); + } } if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { _dbg_assert_(src->depth.image != VK_NULL_HANDLE); @@ -1719,6 +1738,75 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { copy.srcSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); copy.dstSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); vkCmdCopyImage(cmd, src->depth.image, src->depth.layout, dst->depth.image, dst->depth.layout, 1, ©); + + if (multisampled) { + vkCmdCopyImage(cmd, src->msaaDepth.image, src->msaaDepth.layout, dst->msaaDepth.image, dst->msaaDepth.layout, 1, ©); + } + } + + if (multisampled) { + // Transition the MSAA surfaces back to optimal. + if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + recordBarrier_.TransitionImage( + src->msaaColor.image, + 0, + 1, + src->msaaColor.numLayers, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + ); + recordBarrier_.TransitionImage( + dst->msaaColor.image, + 0, + 1, + dst->msaaColor.numLayers, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + ); + src->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + dst->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + recordBarrier_.TransitionImage( + src->msaaDepth.image, + 0, + 1, + src->msaaDepth.numLayers, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT + ); + recordBarrier_.TransitionImage( + dst->msaaDepth.image, + 0, + 1, + dst->msaaDepth.numLayers, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT + ); + src->msaaDepth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + dst->msaaDepth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + recordBarrier_.Flush(cmd); } } @@ -1734,12 +1822,8 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { // First source barriers. if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - if (src->color.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } - if (dst->color.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } + SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); } // We can't copy only depth or only stencil unfortunately. @@ -1747,12 +1831,8 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { _dbg_assert_(src->depth.image != VK_NULL_HANDLE); _dbg_assert_(dst->depth.image != VK_NULL_HANDLE); - if (src->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - } - if (dst->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - } + SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); } recordBarrier_.Flush(cmd); @@ -1801,6 +1881,9 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { } void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrier *recordBarrier) { + if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { + return; + } VkImageAspectFlags imageAspect = aspect; VkAccessFlags srcAccessMask = 0; VkPipelineStageFlags srcStageMask = 0; @@ -1850,6 +1933,9 @@ void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspec } void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrier *recordBarrier) { + if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + return; + } VkImageAspectFlags imageAspect = aspect; VkAccessFlags srcAccessMask = 0; VkPipelineStageFlags srcStageMask = 0; From 35777d5eef6ad49e238d997261f78200151deb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 15:26:29 +0100 Subject: [PATCH 524/715] Use proper copies for depth blits between multisampled framebuffers. Needed to keep all the information. --- GPU/Common/FramebufferManagerCommon.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 175d36d0bc..5bf2cdc9de 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -947,6 +947,14 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir bool useRaster = draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported && draw_->GetDeviceCaps().textureDepthSupported; + if (src->fbo->MultiSampleLevel() > 0 && dst->fbo->MultiSampleLevel() > 0) { + // If multisampling, we want to copy depth properly so we get all the samples, to avoid aliased edges. + // Can be seen in the fire in Jeanne D'arc, for example. + if (useRaster && useCopy) { + useRaster = false; + } + } + int w = std::min(src->renderWidth, dst->renderWidth); int h = std::min(src->renderHeight, dst->renderHeight); From 66cbe55ffc23a4615ceaa45fe65502450c6f093b Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 2 Dec 2022 16:47:26 +0100 Subject: [PATCH 525/715] OpenXR - Tony Hawk HUD fixed --- GPU/GLES/ShaderManagerGLES.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 35f0a631c5..fed2c9d505 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -371,7 +371,7 @@ static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { //HUD cannot have full texture alpha else if (gstate_c.textureFullAlpha) hud = false; //HUD must have full vertex alpha - else if (!gstate_c.vertexFullAlpha) hud = false; + else if (!gstate_c.vertexFullAlpha && gstate.getDepthTestFunction() == GE_COMP_NEVER) hud = false; //HUD cannot render FB screenshot else if (gstate_c.curTextureHeight == 272) hud = false; From 769b1d7342e1c6454124fe85777a93a2e8b3e5e7 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 2 Dec 2022 17:45:29 +0100 Subject: [PATCH 526/715] OpenXR - Assasins Creed rendering fixed --- GPU/GLES/ShaderManagerGLES.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index fed2c9d505..a8f919700d 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -374,6 +374,10 @@ static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { else if (!gstate_c.vertexFullAlpha && gstate.getDepthTestFunction() == GE_COMP_NEVER) hud = false; //HUD cannot render FB screenshot else if (gstate_c.curTextureHeight == 272) hud = false; + //HUD cannot be rendered with replace function + else if (gstate.getTextureFunction() == GETexFunc::GE_TEXFUNC_REPLACE) hud = false; + //HUD cannot be rendered with full clear color mask + else if ((gstate.getClearModeColorMask() == 0xFFFFFF) && (gstate.getColorMask() == 0xFFFFFF)) hud = false; return hud; } From 39c399df4712b7713513622136c8511189af3275 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 2 Dec 2022 17:53:03 +0100 Subject: [PATCH 527/715] OpenXR - GTA Chinatown wars rendering fixed --- GPU/GLES/ShaderManagerGLES.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index a8f919700d..61cf889311 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -373,7 +373,7 @@ static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { //HUD must have full vertex alpha else if (!gstate_c.vertexFullAlpha && gstate.getDepthTestFunction() == GE_COMP_NEVER) hud = false; //HUD cannot render FB screenshot - else if (gstate_c.curTextureHeight == 272) hud = false; + else if (gstate_c.curTextureHeight % 136 <= 1) hud = false; //HUD cannot be rendered with replace function else if (gstate.getTextureFunction() == GETexFunc::GE_TEXFUNC_REPLACE) hud = false; //HUD cannot be rendered with full clear color mask From 6619da2a0dd61ed84291439fce09b62741b33349 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 10:13:32 -0800 Subject: [PATCH 528/715] Debugger: Add decimal constants. For the GE debugger and CPU debugger, it's annoying sometimes to express everything in hex. This allows using an i or u prefix to get decimal. --- Common/Math/expression_parser.cpp | 67 ++++++++++++++++++------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/Common/Math/expression_parser.cpp b/Common/Math/expression_parser.cpp index 970c9c4a20..75e0720c60 100644 --- a/Common/Math/expression_parser.cpp +++ b/Common/Math/expression_parser.cpp @@ -59,45 +59,54 @@ const ExpressionOpcode ExpressionOpcodes[] = { { "", 0, 0, 0, false } // EXOP_NONE }; -bool parseNumber(char* str, int defaultrad, int len, uint32_t& result) -{ +static int radixFromZeroPrefix(char c) { + switch (tolower(c)) { + case 'b': return 2; + case 'o': return 8; + case 'x': return 16; + // Inventing a prefix since we default to hex. + case 'd': return 10; + } + + return -1; +} + +static int radixFromSuffix(char c, int defaultrad) { + switch (tolower(c)) { + case 'o': return 8; + case 'h': return 16; + case 'i': return 10; + case 'u': return 10; + case 'b': return defaultrad == 16 ? -1 : 2; + } + + return -1; +} + +bool parseNumber(char *str, int defaultrad, int len, uint32_t &result) { int val = 0; int r = 0; - if (len == 0) len = (int) strlen(str); + if (len == 0) + len = (int)strlen(str); - if (str[0] == '0' && tolower(str[1]) == 'x') - { - r = 16; - str+=2; - len-=2; - } else if (str[0] == '$') - { + if (str[0] == '0' && radixFromZeroPrefix(str[1]) != -1) { + r = radixFromZeroPrefix(str[1]); + str += 2; + len -= 2; + } else if (str[0] == '$') { r = 16; str++; len--; - } else if (str[0] == '0' && tolower(str[1]) == 'o') - { - r = 8; - str+=2; - len-=2; - } else { - if (!(str[0] >= '0' && str[0] <= '9')) return false; - - if (tolower(str[len-1]) == 'b' && defaultrad != 16) - { - r = 2; - len--; - } else if (tolower(str[len-1]) == 'o') - { - r = 8; - len--; - } else if (tolower(str[len-1]) == 'h') - { - r = 16; + } else if (str[0] >= '0' && str[0] <= '9') { + int suffix = radixFromSuffix(str[len - 1], defaultrad); + if (suffix != -1) { + r = suffix; len--; } else { r = defaultrad; } + } else { + return false; } switch (r) From c5844c41742c6425465b6e7311e3069df804ccf8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 10:14:36 -0800 Subject: [PATCH 529/715] GE Debugger: Add breakpoint symbol for prim count. This way you can break when a register is changed and prim count is in a certain range, which can be convenient. --- GPU/Common/GPUDebugInterface.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp index 4d80d4b83c..618c958a1f 100644 --- a/GPU/Common/GPUDebugInterface.cpp +++ b/GPU/Common/GPUDebugInterface.cpp @@ -19,6 +19,7 @@ #include "Common/Math/expression_parser.h" #include "Core/Debugger/SymbolMap.h" #include "GPU/Common/GPUDebugInterface.h" +#include "GPU/Debugger/Debugger.h" #include "GPU/Debugger/GECommandTable.h" #include "GPU/GPUState.h" @@ -34,6 +35,8 @@ enum class GEReferenceIndex : uint32_t { CLUTADDR, TRANSFERSRC, TRANSFERDST, + PRIMCOUNT, + LASTPRIMCOUNT, TEXADDR0, TEXADDR1, @@ -74,6 +77,8 @@ static constexpr ReferenceName referenceNames[] = { { GEReferenceIndex::CLUTADDR, "clutaddr" }, { GEReferenceIndex::TRANSFERSRC, "transfersrc" }, { GEReferenceIndex::TRANSFERDST, "transferdst" }, + { GEReferenceIndex::PRIMCOUNT, "primcount" }, + { GEReferenceIndex::LASTPRIMCOUNT, "lastprimcount" }, { GEReferenceIndex::TEXADDR0, "texaddr0" }, { GEReferenceIndex::TEXADDR1, "texaddr1" }, { GEReferenceIndex::TEXADDR2, "texaddr2" }, @@ -695,6 +700,12 @@ uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) { case GEReferenceIndex::TRANSFERDST: return state.getTransferDstAddress(); + case GEReferenceIndex::PRIMCOUNT: + return GPUDebug::PrimsThisFrame(); + + case GEReferenceIndex::LASTPRIMCOUNT: + return GPUDebug::PrimsLastFrame(); + case GEReferenceIndex::TEXADDR0: case GEReferenceIndex::TEXADDR1: case GEReferenceIndex::TEXADDR2: From 38de2f11af9cf9cc8b4fa166605b4823bb3b7b93 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 10:15:15 -0800 Subject: [PATCH 530/715] softgpu: Handle infnan fog coefficients better. If we ended up with a dot product that had opposing inf signs, the add would result in NAN and cause problems. --- GPU/Software/TransformUnit.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 0119250316..9f82d85116 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -295,17 +295,30 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { if (state->enableFog) { float fogEnd = getFloat24(gstate.fog1); float fogSlope = getFloat24(gstate.fog2); - // Same fixup as in ShaderManagerGLES.cpp - if (my_isnanorinf(fogEnd)) { - fogEnd = std::signbit(fogEnd) ? -INFINITY : INFINITY; - } - if (my_isnanorinf(fogSlope)) { - fogSlope = std::signbit(fogSlope) ? -INFINITY : INFINITY; - } // We bake fog end and slope into the dot product. state->posToFog = Vec4f(worldview[2], worldview[6], worldview[10], worldview[14] + fogEnd); - state->posToFog *= fogSlope; + + // If either are NAN/INF, we simplify so there's no inf + -inf muddying things. + // This is required for Outrun to render proper skies, for example. + // The PSP treats these exponents as if they were valid. + if (my_isnanorinf(fogEnd)) { + bool sign = std::signbit(fogEnd); + // The multiply would reverse it. + if (my_isnanorinf(fogSlope) && std::signbit(fogSlope)) + sign = !sign; + + // Since this is constant for the entire draw, we don't even use infinity. + float forced = sign ? 0.0f : 1.0f; + state->posToFog = Vec4f(0.0f, 0.0f, 0.0f, forced); + } else if (my_isnanorinf(fogSlope)) { + // We can't have signs differ with infinities, so we use a large value. + // Anything outside [0, 1] will clamp, so this essentially forces extremes. + fogSlope = std::signbit(fogSlope) ? -262144.0f : 262144.0f; + state->posToFog *= fogSlope; + } else { + state->posToFog *= fogSlope; + } } state->screenScale = Vec3f(gstate.getViewportXScale(), gstate.getViewportYScale(), gstate.getViewportZScale()); From 1121a6fb6896dc2929fcdccd337ee38732c42373 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 10:20:30 -0800 Subject: [PATCH 531/715] softgpu: Handle inf-end + negative constant slope. --- GPU/Software/TransformUnit.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 9f82d85116..1369dcdf25 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -304,9 +304,13 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { // The PSP treats these exponents as if they were valid. if (my_isnanorinf(fogEnd)) { bool sign = std::signbit(fogEnd); - // The multiply would reverse it. - if (my_isnanorinf(fogSlope) && std::signbit(fogSlope)) + // The multiply would reverse it if it wasn't infinity (doesn't matter if it's infnan.) + if (std::signbit(fogSlope)) sign = !sign; + // Also allow a multiply by zero (slope) to result in zero, regardless of sign. + // Act like it was negative and clamped to zero. + if (fogSlope == 0.0f) + sign = true; // Since this is constant for the entire draw, we don't even use infinity. float forced = sign ? 0.0f : 1.0f; From 0060a14fa78f9c5a7d860aa2b0946e3613af7d65 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 2 Dec 2022 20:48:35 +0100 Subject: [PATCH 532/715] OpenXR - Adjust the render resolution for VR --- GPU/Common/PresentationCommon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 5980bbb95e..5e495c44bd 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -914,7 +914,10 @@ void PresentationCommon::CalculateRenderResolution(int *width, int *height, int } } - if (g_Config.IsPortrait()) { + if (IsVREnabled()) { + *width = 480 * zoom; + *height = 480 * zoom; + } else if (g_Config.IsPortrait()) { *width = 272 * zoom; *height = 480 * zoom; } else { From 353bdc2d3d3d46406d92e30f7c01765f04701cfb Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 2 Dec 2022 20:57:50 +0100 Subject: [PATCH 533/715] OpenXR - Default config updated --- Core/Config.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 40e3478d3f..5f8cf990d9 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -644,6 +644,9 @@ static int DefaultInternalResolution() { #if defined(USING_WIN_UI) || defined(USING_QT_UI) return 0; #else + if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { + return 4; + } int longestDisplaySide = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)); int scale = longestDisplaySide >= 1000 ? 2 : 1; INFO_LOG(G3D, "Longest display side: %d pixels. Choosing scale %d", longestDisplaySide, scale); @@ -887,7 +890,7 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, true, true), ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true), ReportedConfigSetting("FrameSkipType", &g_Config.iFrameSkipType, 0, true, true), - ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), + ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, IsVREnabled(), true, true), ConfigSetting("StereoRendering", &g_Config.bStereoRendering, false, true, true), ConfigSetting("StereoToMonoShader", &g_Config.sStereoToMonoShader, "RedBlue", true, true), ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), @@ -1214,7 +1217,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f), ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f), ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), - ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), + ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 12.0f), ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), ConfigSetting("VRHeadUpDisplayScale", &g_Config.fHeadUpDisplayScale, 0.3f), ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f), From 237fbca979f6c48382f175f4df7645a743859880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 10:55:03 +0100 Subject: [PATCH 534/715] Savestate: Prepare some sanity checks --- Common/Serialize/Serializer.cpp | 45 +++++++++++++++++++++++++++++++-- Common/Serialize/Serializer.h | 44 +++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index 6b36fb2167..135bef6bce 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -33,8 +33,25 @@ enum class SerializeCompressType { static constexpr SerializeCompressType SAVE_TYPE = SerializeCompressType::ZSTD; -PointerWrapSection PointerWrap::Section(const char *title, int ver) { - return Section(title, ver, ver); +void PointerWrap::RewindForWrite(u8 *writePtr) { + _assert_(mode == MODE_MEASURE); + // Switch to writing mode and + mode = MODE_WRITE; + *ptr = writePtr; + ptrStart_ = writePtr; +} + +bool PointerWrap::CheckAfterWrite() { + _assert_(mode == MODE_WRITE); + if (measuredSize_ != 0 && Offset() != measuredSize_) { + WARN_LOG(SAVESTATE, "CheckAfterWrite: Size mismatch! %d vs %d", (int)Offset(), (int)measuredSize_); + return false; + } + if (!checkpoints_.empty() && curCheckpoint_ != checkpoints_.size()) { + WARN_LOG(SAVESTATE, "Checkpoint count mismatch!"); + return false; + } + return true; } PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) { @@ -44,6 +61,30 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) // This is strncpy because we rely on its weird non-null-terminating zero-filling truncation behaviour. // Can't replace it with the more sensible truncate_cpy because that would break savestates. strncpy(marker, title, sizeof(marker)); + + // Compare the measure and write passes. Sanity check to catch bugs, doesn't do anything for output. + if (mode == MODE_MEASURE) { + checkpoints_.emplace_back(marker, Offset()); + } else if (mode == MODE_WRITE) { + if (!checkpoints_.empty()) { + if (checkpoints_.size() <= curCheckpoint_) { + WARN_LOG(SAVESTATE, "Write: Not enough checkpoints from measure pass (%d). cur section: %s", (int)checkpoints_.size(), title); + SetError(ERROR_FAILURE); + return PointerWrapSection(*this, -1, title); + } + if (!checkpoints_[curCheckpoint_].Matches(marker, Offset())) { + WARN_LOG(SAVESTATE, "Checkpoint mismatch during write! Section %s vs %s, offset %d vs %d", title, marker, (int)Offset(), (int)checkpoints_[curCheckpoint_].offset); + if (curCheckpoint_ > 1) { + WARN_LOG(SAVESTATE, "Previous checkpoint: %s (%d)", checkpoints_[curCheckpoint_ - 1].title, (int)checkpoints_[curCheckpoint_ - 1].offset); + } + SetError(ERROR_FAILURE); + return PointerWrapSection(*this, -1, title); + } + } else { + WARN_LOG(SAVESTATE, "Writing savestate without checkpoints. This is OK but should be fixed."); + } + } + if (!ExpectVoid(marker, sizeof(marker))) { // Might be before we added name markers for safety. if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) { diff --git a/Common/Serialize/Serializer.h b/Common/Serialize/Serializer.h index cdf8bd4f06..5db52f4347 100644 --- a/Common/Serialize/Serializer.h +++ b/Common/Serialize/Serializer.h @@ -30,6 +30,7 @@ // - Serialization code for anything complex has to be manually written. #include +#include #include #include @@ -52,8 +53,7 @@ class PointerWrap; class PointerWrapSection { public: - PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { - } + PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) {} ~PointerWrapSection(); bool operator == (const int &v) const { return ver_ == v; } @@ -73,6 +73,22 @@ private: const char *title_; }; +// For measure vs write detailed verification +struct SerializeCheckpoint { + char title[17]; // 16-byte section header, plus a zero terminator for debug printing. + size_t offset; + + SerializeCheckpoint(char _title[16], size_t off) { + memcpy(title, _title, 16); + title[16] = 0; + offset = off; + } + + bool Matches(const char *_title, size_t off) const { + return memcmp(title, _title, 16) == 0 && off == offset; + } +}; + // Wrapper class class PointerWrap { @@ -94,19 +110,23 @@ public: Mode mode; Error error = ERROR_NONE; - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_) {} + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), ptrStart_(*ptr), mode(mode_) {} + PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), ptrStart_(*ptr), mode((Mode)mode_) {} - PointerWrapSection Section(const char *title, int ver); + void RewindForWrite(u8 *writePtr); + bool CheckAfterWrite(); // The returned object can be compared against the version that was loaded. // This can be used to support versions as old as minVer. // Version = 0 means the section was not found. PointerWrapSection Section(const char *title, int minVer, int ver); + PointerWrapSection Section(const char *title, int ver) { + return Section(title, ver, ver); + } - void SetMode(Mode mode_) {mode = mode_;} - Mode GetMode() const {return mode;} - u8 **GetPPtr() {return ptr;} + void SetMode(Mode mode_) { mode = mode_; } + Mode GetMode() const { return mode; } + u8 **GetPPtr() { return ptr; } void SetError(Error error_); const char *GetBadSectionTitle() const { @@ -120,7 +140,13 @@ public: void DoMarker(const char *prevName, u32 arbitraryNumber = 0x42); private: + size_t Offset() const { return *ptr - ptrStart_; } + const char *firstBadSectionTitle_ = nullptr; + u8 *ptrStart_; + std::vector checkpoints_; + size_t curCheckpoint_ = 0; + size_t measuredSize_ = 0; }; class CChunkFileReader @@ -204,7 +230,7 @@ public: return ERROR_BAD_ALLOC; Error error = SavePtr(buffer, _class, sz); - // SaveFile takes ownership of buffer + // SaveFile takes ownership of buffer (malloc/free) if (error == ERROR_NONE) error = SaveFile(filename, title, gitVersion, buffer, sz); return error; From 52a684644db59f79b4a7eb0f1def66363e714cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 11:29:59 +0100 Subject: [PATCH 535/715] Verify that the Measure and Save passes match accurately through checkpointing Adding this after seeing some very suspicious behavior in Ratchet & Clank. --- Common/Serialize/Serializer.cpp | 16 +++++++----- Common/Serialize/Serializer.h | 44 +++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index 135bef6bce..54d47c0158 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -36,15 +36,17 @@ static constexpr SerializeCompressType SAVE_TYPE = SerializeCompressType::ZSTD; void PointerWrap::RewindForWrite(u8 *writePtr) { _assert_(mode == MODE_MEASURE); // Switch to writing mode and + measuredSize_ = Offset(); mode = MODE_WRITE; *ptr = writePtr; ptrStart_ = writePtr; } bool PointerWrap::CheckAfterWrite() { - _assert_(mode == MODE_WRITE); - if (measuredSize_ != 0 && Offset() != measuredSize_) { - WARN_LOG(SAVESTATE, "CheckAfterWrite: Size mismatch! %d vs %d", (int)Offset(), (int)measuredSize_); + _assert_(error != ERROR_NONE || mode == MODE_WRITE); + size_t offset = Offset(); + if (measuredSize_ != 0 && offset != measuredSize_) { + WARN_LOG(SAVESTATE, "CheckAfterWrite: Size mismatch! %d but expected %d", (int)offset, (int)measuredSize_); return false; } if (!checkpoints_.empty() && curCheckpoint_ != checkpoints_.size()) { @@ -63,8 +65,9 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) strncpy(marker, title, sizeof(marker)); // Compare the measure and write passes. Sanity check to catch bugs, doesn't do anything for output. + size_t offset = Offset(); if (mode == MODE_MEASURE) { - checkpoints_.emplace_back(marker, Offset()); + checkpoints_.emplace_back(marker, offset); } else if (mode == MODE_WRITE) { if (!checkpoints_.empty()) { if (checkpoints_.size() <= curCheckpoint_) { @@ -72,8 +75,8 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) SetError(ERROR_FAILURE); return PointerWrapSection(*this, -1, title); } - if (!checkpoints_[curCheckpoint_].Matches(marker, Offset())) { - WARN_LOG(SAVESTATE, "Checkpoint mismatch during write! Section %s vs %s, offset %d vs %d", title, marker, (int)Offset(), (int)checkpoints_[curCheckpoint_].offset); + if (!checkpoints_[curCheckpoint_].Matches(marker, offset)) { + WARN_LOG(SAVESTATE, "Checkpoint mismatch during write! Section %s but expected %s, offset %d but expected %d", title, marker, offset, (int)checkpoints_[curCheckpoint_].offset); if (curCheckpoint_ > 1) { WARN_LOG(SAVESTATE, "Previous checkpoint: %s (%d)", checkpoints_[curCheckpoint_ - 1].title, (int)checkpoints_[curCheckpoint_ - 1].offset); } @@ -83,6 +86,7 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) } else { WARN_LOG(SAVESTATE, "Writing savestate without checkpoints. This is OK but should be fixed."); } + curCheckpoint_++; } if (!ExpectVoid(marker, sizeof(marker))) { diff --git a/Common/Serialize/Serializer.h b/Common/Serialize/Serializer.h index 5db52f4347..2c5a43ab4d 100644 --- a/Common/Serialize/Serializer.h +++ b/Common/Serialize/Serializer.h @@ -139,9 +139,10 @@ public: void DoMarker(const char *prevName, u32 arbitraryNumber = 0x42); -private: size_t Offset() const { return *ptr - ptrStart_; } +private: + const char *firstBadSectionTitle_ = nullptr; u8 *ptrStart_; std::vector checkpoints_; @@ -178,7 +179,7 @@ public: template static size_t MeasurePtr(T &_class) { - u8 *ptr = 0; + u8 *ptr = nullptr; PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); _class.DoState(p); return (size_t)ptr; @@ -192,13 +193,39 @@ public: PointerWrap p(&ptr, PointerWrap::MODE_WRITE); _class.DoState(p); - if (p.error != p.ERROR_FAILURE && (expected_end == ptr || expected_size == 0)) { + if (p.error != PointerWrap::ERROR_FAILURE && (expected_end == ptr || expected_size == 0)) { return ERROR_NONE; } else { return ERROR_BROKEN_STATE; } } + template + static Error MeasureAndSavePtr(T &_class, u8 **saved, size_t *savedSize) + { + u8 *ptr = nullptr; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + _assert_(p.error == PointerWrap::ERROR_NONE); + + size_t measuredSize = p.Offset(); + u8 *data = (u8 *)malloc(measuredSize); + if (!data) + return ERROR_BAD_ALLOC; + + p.RewindForWrite(data); + _class.DoState(p); + + if (p.CheckAfterWrite()) { + *saved = data; + *savedSize = measuredSize; + return ERROR_NONE; + } else { + free(data); + return ERROR_BROKEN_STATE; + } + } + // Load file template template static Error Load(const Path &filename, std::string *gitVersion, T& _class, std::string *failureReason) @@ -223,19 +250,16 @@ public: template static Error Save(const Path &filename, const std::string &title, const char *gitVersion, T& _class) { - // Get data - size_t const sz = MeasurePtr(_class); - u8 *buffer = (u8 *)malloc(sz); - if (!buffer) - return ERROR_BAD_ALLOC; - Error error = SavePtr(buffer, _class, sz); + u8 *buffer; + size_t sz; + Error error = MeasureAndSavePtr(_class, &buffer, &sz); // SaveFile takes ownership of buffer (malloc/free) if (error == ERROR_NONE) error = SaveFile(filename, title, gitVersion, buffer, sz); return error; } - + template static Error Verify(T& _class) { From f5a7661c51e5de81bf8d646c74884849a8b040f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 13:28:06 +0100 Subject: [PATCH 536/715] Add a NOOP state to reduce logspam after error --- Common/Serialize/SerializeFuncs.h | 3 ++- Common/Serialize/SerializeMap.h | 12 ++++++++---- Common/Serialize/Serializer.cpp | 11 +++++++---- Common/Serialize/Serializer.h | 7 ++++--- Core/Dialog/SavedataParam.cpp | 4 ++-- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Common/Serialize/SerializeFuncs.h b/Common/Serialize/SerializeFuncs.h index 0c89450c5d..c2919de799 100644 --- a/Common/Serialize/SerializeFuncs.h +++ b/Common/Serialize/SerializeFuncs.h @@ -85,7 +85,8 @@ template void DoVector(PointerWrap &p, std::vector &x, T &default_val) { u32 vec_size = (u32)x.size(); Do(p, vec_size); - x.resize(vec_size, default_val); + if (vec_size != x.size()) + x.resize(vec_size, default_val); if (vec_size > 0) DoArray(p, &x[0], vec_size); } diff --git a/Common/Serialize/SerializeMap.h b/Common/Serialize/SerializeMap.h index 9190f5067e..4e5619bdbe 100644 --- a/Common/Serialize/SerializeMap.h +++ b/Common/Serialize/SerializeMap.h @@ -38,8 +38,8 @@ void DoMap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { x[first] = second; --number; } + break; } - break; case PointerWrap::MODE_WRITE: case PointerWrap::MODE_MEASURE: case PointerWrap::MODE_VERIFY: @@ -52,8 +52,10 @@ void DoMap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { --number; ++itr; } + break; } - break; + case PointerWrap::MODE_NOOP: + break; } } @@ -109,8 +111,8 @@ void DoMultimap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { x.insert(std::make_pair(first, second)); --number; } + break; } - break; case PointerWrap::MODE_WRITE: case PointerWrap::MODE_MEASURE: case PointerWrap::MODE_VERIFY: @@ -122,8 +124,10 @@ void DoMultimap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { --number; ++itr; } + break; } - break; + case PointerWrap::MODE_NOOP: + break; } } diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index 54d47c0158..1070dd7a66 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -105,8 +105,10 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) if (!firstBadSectionTitle_) { firstBadSectionTitle_ = title; } - WARN_LOG(SAVESTATE, "Savestate failure: wrong version %d found for section '%s'", foundVersion, title); - SetError(ERROR_FAILURE); + if (mode != MODE_NOOP) { + WARN_LOG(SAVESTATE, "Savestate failure: wrong version %d found for section '%s'", foundVersion, title); + SetError(ERROR_FAILURE); + } return PointerWrapSection(*this, -1, title); } return PointerWrapSection(*this, foundVersion, title); @@ -117,8 +119,9 @@ void PointerWrap::SetError(Error error_) { error = error_; } if (error > ERROR_WARNING) { - // For the rest of this run, just measure. - mode = PointerWrap::MODE_MEASURE; + // For the rest of this run, do nothing, to avoid running off the end of memory or something, + // and also not logspam like MEASURE will do in an error case. + mode = PointerWrap::MODE_NOOP; } } diff --git a/Common/Serialize/Serializer.h b/Common/Serialize/Serializer.h index 2c5a43ab4d..ab8500bf28 100644 --- a/Common/Serialize/Serializer.h +++ b/Common/Serialize/Serializer.h @@ -95,9 +95,10 @@ class PointerWrap public: enum Mode { MODE_READ = 1, // load - MODE_WRITE, // save - MODE_MEASURE, // calculate size - MODE_VERIFY, // compare + MODE_WRITE, // save + MODE_MEASURE, // calculate size + MODE_VERIFY, // compare + MODE_NOOP, // don't do anything. Useful to cleanly doing stuff once we've hit an error. }; enum Error { diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 3c6c545baa..f2c7b1758c 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -1890,13 +1890,13 @@ void SavedataParam::DoState(PointerWrap &p) { Do(p, saveDataListCount); Do(p, saveNameListDataCount); if (p.mode == p.MODE_READ) { - if (saveDataList != NULL) + if (saveDataList) delete [] saveDataList; if (saveDataListCount != 0) { saveDataList = new SaveFileInfo[saveDataListCount]; DoArray(p, saveDataList, saveDataListCount); } else { - saveDataList = NULL; + saveDataList = nullptr; } } else From f954013d0be24b4e53a8a747b0b2157241253b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 13:45:17 +0100 Subject: [PATCH 537/715] Fix (?) the savestate bug in PSPSaveDialog/SaveDataParam PSPSaveDialog::DoState called SetPspParam in non-READ modes, which could modify it. --- Core/Dialog/PSPSaveDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index ea600d5669..a857f53a44 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -1255,7 +1255,7 @@ void PSPSaveDialog::DoState(PointerWrap &p) { // Just reset it. bool hasParam = param.GetPspParam() != NULL; Do(p, hasParam); - if (hasParam) { + if (hasParam && p.mode == p.MODE_READ) { param.SetPspParam(&request); } Do(p, requestAddr); From c7041d6e97c20b2073cf36bc9a072fa1cceda64a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 22:45:28 +0100 Subject: [PATCH 538/715] Reserve some space in the checkpoints vector --- Common/Serialize/Serializer.cpp | 2 +- Common/Serialize/Serializer.h | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index 1070dd7a66..ebe0e10d68 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -35,7 +35,7 @@ static constexpr SerializeCompressType SAVE_TYPE = SerializeCompressType::ZSTD; void PointerWrap::RewindForWrite(u8 *writePtr) { _assert_(mode == MODE_MEASURE); - // Switch to writing mode and + // Switch to writing mode, save the size for later checking and start again. measuredSize_ = Offset(); mode = MODE_WRITE; *ptr = writePtr; diff --git a/Common/Serialize/Serializer.h b/Common/Serialize/Serializer.h index ab8500bf28..5169e4a120 100644 --- a/Common/Serialize/Serializer.h +++ b/Common/Serialize/Serializer.h @@ -111,8 +111,11 @@ public: Mode mode; Error error = ERROR_NONE; - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), ptrStart_(*ptr), mode(mode_) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), ptrStart_(*ptr), mode((Mode)mode_) {} + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), ptrStart_(*ptr), mode(mode_) { + if (mode == MODE_MEASURE) { + checkpoints_.reserve(750); + } + } void RewindForWrite(u8 *writePtr); bool CheckAfterWrite(); @@ -143,7 +146,6 @@ public: size_t Offset() const { return *ptr - ptrStart_; } private: - const char *firstBadSectionTitle_ = nullptr; u8 *ptrStart_; std::vector checkpoints_; From 778a0487cbf39b5d3005e8104eec8181590f93f1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 20:59:13 -0800 Subject: [PATCH 539/715] softjit: Switch to DenseHashMap. --- GPU/Software/DrawPixel.cpp | 34 ++++++++++++++++++++-------------- GPU/Software/DrawPixel.h | 3 ++- GPU/Software/Sampler.cpp | 38 ++++++++++++++++++++++---------------- GPU/Software/Sampler.h | 3 ++- 4 files changed, 46 insertions(+), 32 deletions(-) diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index 0cf151a83a..12dcc9cfe8 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -744,12 +744,12 @@ SingleFunc PixelJitCache::GenericSingle(const PixelFuncID &id) { } // 256k should be plenty of space for plenty of variations. -PixelJitCache::PixelJitCache() : CodeBlock(1024 * 64 * 4) { +PixelJitCache::PixelJitCache() : CodeBlock(1024 * 64 * 4), cache_(64) { } void PixelJitCache::Clear() { CodeBlock::Clear(); - cache_.clear(); + cache_.Clear(); addresses_.clear(); constBlendHalf_11_4s_ = nullptr; @@ -777,8 +777,12 @@ std::string PixelJitCache::DescribeCodePtr(const u8 *ptr) { void PixelJitCache::Flush() { std::unique_lock guard(jitCacheLock); - for (const auto &queued : compileQueue_) - Compile(queued); + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } compileQueue_.clear(); } @@ -787,10 +791,11 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function return nullptr; std::unique_lock guard(jitCacheLock); + const size_t key = std::hash()(id); - auto it = cache_.find(id); - if (it != cache_.end()) { - return it->second; + auto it = cache_.Get(key); + if (it != nullptr) { + return it; } if (!flushForCompile) { @@ -803,16 +808,17 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function flushForCompile(); guard.lock(); - for (const auto &queued : compileQueue_) - Compile(queued); + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } compileQueue_.clear(); Compile(id); - it = cache_.find(id); - if (it != cache_.end()) - return it->second; - return nullptr; + return cache_.Get(key); } void PixelJitCache::Compile(const PixelFuncID &id) { @@ -824,7 +830,7 @@ void PixelJitCache::Compile(const PixelFuncID &id) { #if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP) addresses_[id] = GetCodePointer(); SingleFunc func = CompileSingle(id); - cache_[id] = func; + cache_.Insert(std::hash()(id), func); #endif } diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index 02fb641680..e9d2715da4 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -24,6 +24,7 @@ #include #include #include +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/Math3D.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" @@ -107,7 +108,7 @@ private: bool Jit_ConvertFrom5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); bool Jit_ConvertFrom4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); - std::unordered_map cache_; + DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 81d4a38214..1f7eaefaf2 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -98,12 +98,12 @@ FetchFunc GetFetchFunc(SamplerID id, std::function flushForCompile) { } // 256k should be enough. -SamplerJitCache::SamplerJitCache() : Rasterizer::CodeBlock(1024 * 64 * 4) { +SamplerJitCache::SamplerJitCache() : Rasterizer::CodeBlock(1024 * 64 * 4), cache_(64) { } void SamplerJitCache::Clear() { CodeBlock::Clear(); - cache_.clear(); + cache_.Clear(); addresses_.clear(); const10All16_ = nullptr; @@ -144,8 +144,12 @@ std::string SamplerJitCache::DescribeCodePtr(const u8 *ptr) { void SamplerJitCache::Flush() { std::unique_lock guard(jitCacheLock); - for (const auto &queued : compileQueue_) - Compile(queued); + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } compileQueue_.clear(); } @@ -154,10 +158,11 @@ NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function return nullptr; std::unique_lock guard(jitCacheLock); + const size_t key = std::hash()(id); - auto it = cache_.find(id); - if (it != cache_.end()) - return it->second; + auto it = cache_.Get(key); + if (it != nullptr) + return it; if (!flushForCompile) { // Can't compile, let's try to do it later when there's an opportunity. @@ -169,17 +174,18 @@ NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function flushForCompile(); guard.lock(); - for (const auto &queued : compileQueue_) - Compile(queued); + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } compileQueue_.clear(); Compile(id); // Okay, should be there now. - it = cache_.find(id); - if (it != cache_.end()) - return it->second; - return nullptr; + return cache_.Get(key); } NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, std::function flushForCompile) { @@ -207,19 +213,19 @@ void SamplerJitCache::Compile(const SamplerID &id) { fetchID.linear = false; fetchID.fetch = true; addresses_[fetchID] = GetCodePointer(); - cache_[fetchID] = (NearestFunc)CompileFetch(fetchID); + cache_.Insert(std::hash()(fetchID), (NearestFunc)CompileFetch(fetchID)); SamplerID nearestID = id; nearestID.linear = false; nearestID.fetch = false; addresses_[nearestID] = GetCodePointer(); - cache_[nearestID] = (NearestFunc)CompileNearest(nearestID); + cache_.Insert(std::hash()(nearestID), (NearestFunc)CompileNearest(nearestID)); SamplerID linearID = id; linearID.linear = true; linearID.fetch = false; addresses_[linearID] = GetCodePointer(); - cache_[linearID] = (NearestFunc)CompileLinear(linearID); + cache_.Insert(std::hash()(linearID), (NearestFunc)CompileLinear(linearID)); #endif } diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index bb47314ddb..0d14ae12d2 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -22,6 +22,7 @@ #include #include #include +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/Math3D.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" @@ -126,7 +127,7 @@ private: const u8 *const5551Swizzle_ = nullptr; const u8 *const5650Swizzle_ = nullptr; - std::unordered_map cache_; + DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; }; From a04b7cf3b3e26910a55dec22c60b8b6ce640d4b3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 21:19:54 -0800 Subject: [PATCH 540/715] softgpu: Force shading flag off in clearMode. Probably fixes a line shading bug, and clearer anyway. --- GPU/Software/Rasterizer.cpp | 4 ++-- GPU/Software/SoftGpu.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 18244fc105..8a0263238e 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -143,7 +143,7 @@ void ComputeRasterizerState(RasterizerState *state, std::function flushF } } - state->shadeGouraud = gstate.getShadeMode() == GE_SHADE_GOURAUD; + state->shadeGouraud = !gstate.isModeClear() && gstate.getShadeMode() == GE_SHADE_GOURAUD; state->throughMode = gstate.isModeThrough(); state->antialiasLines = gstate.isAntiAliasEnabled(); @@ -602,7 +602,7 @@ void DrawTriangleSlice( // All the z values are the same, no interpolation required. // This is common, and when we interpolate, we lose accuracy. const bool flatZ = v0.screenpos.z == v1.screenpos.z && v0.screenpos.z == v2.screenpos.z; - const bool flatColorAll = clearMode || !state.shadeGouraud; + const bool flatColorAll = !state.shadeGouraud; const bool flatColor0 = flatColorAll || (v0.color0 == v1.color0 && v0.color0 == v2.color0); const bool flatColor1 = flatColorAll || (v0.color1 == v1.color1 && v0.color1 == v2.color1); const bool noFog = clearMode || !pixelID.applyFog || (v0.fogdepth >= 1.0f && v1.fogdepth >= 1.0f && v2.fogdepth >= 1.0f); diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 6ed1bb3af1..9f70441692 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -107,7 +107,7 @@ const SoftwareCommandTableEntry softgpuCommandTable[] = { { GE_CMD_FOG1, 0, SoftDirty::TRANSFORM_FOG }, { GE_CMD_FOG2, 0, SoftDirty::TRANSFORM_FOG }, - { GE_CMD_CLEARMODE, 0, SoftDirty::TRANSFORM_BASIC | SoftDirty::RAST_TEX | SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::PIXEL_BASIC | SoftDirty::PIXEL_ALPHA | SoftDirty::PIXEL_STENCIL | SoftDirty::PIXEL_CACHED | SoftDirty::BINNER_RANGE | SoftDirty::BINNER_OVERLAP }, + { GE_CMD_CLEARMODE, 0, SoftDirty::TRANSFORM_BASIC | SoftDirty::RAST_BASIC | SoftDirty::RAST_TEX | SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::PIXEL_BASIC | SoftDirty::PIXEL_ALPHA | SoftDirty::PIXEL_STENCIL | SoftDirty::PIXEL_CACHED | SoftDirty::BINNER_RANGE | SoftDirty::BINNER_OVERLAP }, { GE_CMD_TEXTUREMAPENABLE, 0, SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::RAST_TEX | SoftDirty::TRANSFORM_BASIC | SoftDirty::BINNER_OVERLAP }, { GE_CMD_FOGENABLE, 0, SoftDirty::PIXEL_BASIC | SoftDirty::PIXEL_CACHED | SoftDirty::TRANSFORM_BASIC | SoftDirty::TRANSFORM_FOG | SoftDirty::TRANSFORM_MATRIX }, { GE_CMD_TEXMODE, 0, SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::RAST_TEX }, From 6bd0eec54d5e2d6e7d0b52072c1aca20fe049b6e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 21:27:22 -0800 Subject: [PATCH 541/715] softgpu: Calc flags on state as we queue verts. Might be some other ways, like doing this directly in a vertex reader. Also am thinking about doing things regarding UVs or positions. Flags not yet used, keeping separate for perf checks. --- GPU/Software/BinManager.cpp | 6 ++++++ GPU/Software/Rasterizer.cpp | 27 +++++++++++++++++++++++++++ GPU/Software/Rasterizer.h | 14 ++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index c6c752ae73..1a23e2622a 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -388,6 +388,7 @@ void BinManager::AddTriangle(const VertexData &v0, const VertexData &v1, const V if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::TRIANGLE, stateIndex_, range, v0, v1, v2 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, v2); Expand(range); } @@ -399,6 +400,7 @@ void BinManager::AddClearRect(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::CLEAR_RECT, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, true); Expand(range); } @@ -410,6 +412,7 @@ void BinManager::AddRect(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::RECT, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, true); Expand(range); } @@ -421,6 +424,7 @@ void BinManager::AddSprite(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::SPRITE, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, true); Expand(range); } @@ -432,6 +436,7 @@ void BinManager::AddLine(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::LINE, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, false); Expand(range); } @@ -443,6 +448,7 @@ void BinManager::AddPoint(const VertexData &v0) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::POINT, stateIndex_, range, v0 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0); Expand(range); } diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 8a0263238e..fc535a5779 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -155,6 +155,33 @@ void ComputeRasterizerState(RasterizerState *state, std::function flushF #endif } +static inline void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, bool useColor) { + if (useColor) { + if ((v0.color0 & 0x00FFFFFF) != 0x00FFFFFF) + state->flags |= RasterizerStateFlags::VERTEX_NON_FULL_WHITE; + uint8_t alpha = v0.color0 >> 24; + if (alpha != 0) + state->flags |= RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO; + if (alpha != 0xFF) + state->flags |= RasterizerStateFlags::VERTEX_ALPHA_NON_FULL; + } +} + +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0) { + CalculateRasterStateFlags(state, v0, true); +} + +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, bool forceFlat) { + CalculateRasterStateFlags(state, v0, !forceFlat && state->shadeGouraud); + CalculateRasterStateFlags(state, v1, true); +} + +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, const VertexData &v2) { + CalculateRasterStateFlags(state, v0, state->shadeGouraud); + CalculateRasterStateFlags(state, v1, state->shadeGouraud); + CalculateRasterStateFlags(state, v2, true); +} + RasterizerState OptimizeFlatRasterizerState(const RasterizerState &origState, const VertexData &v1) { uint8_t alpha = v1.color0 >> 24; RasterizerState state = origState; diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 6ae7122ed3..f933d8ae8e 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -33,6 +33,16 @@ struct BinCoords; namespace Rasterizer { +enum class RasterizerStateFlags { + NONE = 0, + VERTEX_NON_FULL_WHITE = 0x0001, + VERTEX_ALPHA_NON_ZERO = 0x0002, + VERTEX_ALPHA_NON_FULL = 0x0004, + + INVALID = 0x7FFFFFFF, +}; +ENUM_CLASS_BITOPS(RasterizerStateFlags); + struct RasterizerState { PixelFuncID pixelID; SamplerID samplerID; @@ -43,6 +53,7 @@ struct RasterizerState { uint16_t texbufw[8]{}; const u8 *texptr[8]{}; float textureLodSlope; + RasterizerStateFlags flags = RasterizerStateFlags::NONE; struct { uint8_t maxTexLevel : 3; @@ -68,6 +79,9 @@ struct RasterizerState { }; void ComputeRasterizerState(RasterizerState *state, std::function flushForCompile); +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0); +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, bool forceFlat); +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, const VertexData &v2); // Draws a triangle if its vertices are specified in counter-clockwise order void DrawTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const BinCoords &range, const RasterizerState &state); From 4d925339073b4c26e66421a4492a711d9772beb6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 21:30:53 -0800 Subject: [PATCH 542/715] softgpu: Apply optimizations to states generically. This is for optimizations we can only do when we know the vertex values. --- GPU/Software/BinManager.cpp | 22 ++++ GPU/Software/BinManager.h | 3 + GPU/Software/Rasterizer.cpp | 220 ++++++++++++++++++++++++++---------- GPU/Software/Rasterizer.h | 11 ++ 4 files changed, 195 insertions(+), 61 deletions(-) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 1a23e2622a..ac50f4c5a3 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -169,12 +169,14 @@ void BinManager::UpdateState() { if (HasDirty(SoftDirty::PIXEL_ALL | SoftDirty::SAMPLER_ALL | SoftDirty::RAST_ALL)) { if (states_.Full()) Flush("states"); + creatingState_ = true; stateIndex_ = (uint16_t)states_.Push(RasterizerState()); // When new funcs are compiled, we need to flush if WX exclusive. ComputeRasterizerState(&states_[stateIndex_], [&]() { Flush("compile"); }); states_[stateIndex_].samplerID.cached.clut = cluts_[clutIndex_].readable; + creatingState_ = false; ClearDirty(SoftDirty::PIXEL_ALL | SoftDirty::SAMPLER_ALL | SoftDirty::RAST_ALL); } @@ -492,6 +494,10 @@ void BinManager::Drain(bool flushing) { tasksSplit_ = true; } + // Let's try to optimize states, if we can. + OptimizePendingStates(pendingStateIndex_, stateIndex_); + pendingStateIndex_ = stateIndex_; + if (taskRanges_.size() <= 1) { PROFILE_THIS_SCOPE("bin_drain_single"); while (!queue_.Empty()) { @@ -590,6 +596,22 @@ void BinManager::Flush(const char *reason) { } } +void BinManager::OptimizePendingStates(uint16_t first, uint16_t last) { + // We can sometimes hit this when compiling new funcs while creating a state. + // At that point, the state isn't loaded fully yet, so don't touch it. + if (creatingState_ && last == stateIndex_) { + if (first == last) + return; + last--; + } + + int count = (QUEUED_STATES + last - first) % QUEUED_STATES + 1; + for (int i = 0; i < count; ++i) { + size_t pos = (first + i) % QUEUED_STATES; + OptimizeRasterState(&states_[pos]); + } +} + bool BinManager::HasPendingWrite(uint32_t start, uint32_t stride, uint32_t w, uint32_t h) { // We can only write to VRAM. if (!Memory::IsVRAMAddress(start)) diff --git a/GPU/Software/BinManager.h b/GPU/Software/BinManager.h index 3dd36d83a9..9252d835cc 100644 --- a/GPU/Software/BinManager.h +++ b/GPU/Software/BinManager.h @@ -261,6 +261,8 @@ private: std::unordered_map pendingReads_; bool pendingOverlap_ = false; + bool creatingState_ = false; + uint16_t pendingStateIndex_ = 0; std::unordered_map flushReasonTimes_; std::unordered_map lastFlushReasonTimes_; @@ -274,6 +276,7 @@ private: void MarkPendingWrites(const Rasterizer::RasterizerState &state); bool HasTextureWrite(const Rasterizer::RasterizerState &state); bool IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item); + void OptimizePendingStates(uint16_t first, uint16_t last); BinCoords Scissor(BinCoords range); BinCoords Range(const VertexData &v0, const VertexData &v1, const VertexData &v2); BinCoords Range(const VertexData &v0, const VertexData &v1); diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index fc535a5779..4866f3df86 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -182,74 +182,172 @@ void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, con CalculateRasterStateFlags(state, v2, true); } +static inline int OptimizePixelIDFlags(const RasterizerStateFlags &flags) { + return (int)flags & (int)RasterizerStateFlags::OPTIMIZED_PIXELID; +} + +static inline int OptimizeSamplerIDFlags(const RasterizerStateFlags &flags) { + return (int)flags & (int)RasterizerStateFlags::OPTIMIZED_SAMPLERID; +} + +static inline int OptimizeAllFlags(const RasterizerStateFlags &flags) { + return OptimizePixelIDFlags(flags) | OptimizeSamplerIDFlags(flags); +} + +static inline RasterizerStateFlags ClearFlags(const RasterizerStateFlags &flags, const RasterizerStateFlags &mask) { + int clearBits = (int)flags & (int)mask; + return (RasterizerStateFlags)((int)flags & ~clearBits); +} + +static inline RasterizerStateFlags ReplacePixelIDFlags(const RasterizerStateFlags &flags, const RasterizerStateFlags &replace) { + RasterizerStateFlags updated = ClearFlags(flags, RasterizerStateFlags::OPTIMIZED_PIXELID); + return updated | (RasterizerStateFlags)OptimizePixelIDFlags(replace); +} + +static inline RasterizerStateFlags ReplaceSamplerIDFlags(const RasterizerStateFlags &flags, const RasterizerStateFlags &replace) { + RasterizerStateFlags updated = ClearFlags(flags, RasterizerStateFlags::OPTIMIZED_SAMPLERID); + return updated | (RasterizerStateFlags)OptimizeSamplerIDFlags(replace); +} + +static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { + // Note: all optimizations must be undoable. + RasterizerStateFlags optimize = RasterizerStateFlags::NONE; + + if (!state->pixelID.clearMode) { + auto &pixelID = state->pixelID; + auto &cached = pixelID.cached; + + bool useTextureAlpha = state->enableTextures && state->samplerID.useTextureAlpha; + if (pixelID.alphaBlend && !useTextureAlpha) { + bool canZero = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO); + bool canFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); + // Okay, we may be able to convert this to a fixed value. + if (canZero || canFull) { + // If it was already set and we still can, set it again. + if (pixelID.AlphaBlendSrc() == PixelBlendFactor::SRCALPHA || (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC)) + optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_SRC; + if (pixelID.AlphaBlendDst() == PixelBlendFactor::INVSRCALPHA || (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST)) + optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_DST; + } + if (canFull && (pixelID.AlphaBlendSrc() == PixelBlendFactor::SRCALPHA || pixelID.AlphaBlendSrc() == PixelBlendFactor::ONE) && (pixelID.AlphaBlendDst() == PixelBlendFactor::INVSRCALPHA || pixelID.AlphaBlendDst() == PixelBlendFactor::ZERO)) { + optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_OFF; + } + } else if (!pixelID.alphaBlend && (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_OFF)) { + bool canFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); + if (canFull) + optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_OFF; + } + } + + if (state->enableTextures) { + bool useTextureAlpha = state->samplerID.useTextureAlpha; + bool alphaFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); + bool colorFull = !(state->flags & RasterizerStateFlags::VERTEX_NON_FULL_WHITE); + if (colorFull && (!useTextureAlpha || alphaFull)) { + // Modulate is common, sometimes even with a fixed color. Replace is cheaper. + if (state->samplerID.TexFunc() == GE_TEXFUNC_MODULATE || (state->flags & RasterizerStateFlags::OPTIMIZED_TEXREPLACE)) + optimize |= RasterizerStateFlags::OPTIMIZED_TEXREPLACE; + } + } + + return optimize; +} + +static bool ApplyStateOptimizations(RasterizerState *state, const RasterizerStateFlags &optimize) { + bool changed = false; + + // Check if we can compile the new funcs before replacing. + if (OptimizePixelIDFlags(state->flags) != OptimizePixelIDFlags(optimize)) { + bool canFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); + + PixelFuncID pixelID = state->pixelID; + if (optimize & RasterizerStateFlags::OPTIMIZED_BLEND_OFF) + pixelID.alphaBlend = false; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_OFF) + pixelID.alphaBlend = true; + if (optimize & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + pixelID.alphaBlendSrc = (uint8_t)(canFull ? PixelBlendFactor::ONE : PixelBlendFactor::ZERO); + else if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + pixelID.alphaBlendSrc = (uint8_t)PixelBlendFactor::SRCALPHA; + if (optimize & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + pixelID.alphaBlendDst = (uint8_t)(canFull ? PixelBlendFactor::ZERO : PixelBlendFactor::ONE); + else if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + pixelID.alphaBlendDst = (uint8_t)PixelBlendFactor::INVSRCALPHA; + + SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID, nullptr); + // Can't compile during runtime. This failing is a bit of a problem when undoing... + if (drawPixel) { + state->drawPixel = drawPixel; + memcpy(&state->pixelID, &pixelID, sizeof(PixelFuncID)); + state->flags = ReplacePixelIDFlags(state->flags, optimize) | RasterizerStateFlags::OPTIMIZED; + changed = true; + } + } + + if (OptimizeSamplerIDFlags(state->flags) != OptimizeSamplerIDFlags(optimize)) { + SamplerID samplerID = state->samplerID; + if (optimize & RasterizerStateFlags::OPTIMIZED_TEXREPLACE) + samplerID.texFunc = (uint8_t)GE_TEXFUNC_REPLACE; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_TEXREPLACE) + samplerID.texFunc = (uint8_t)GE_TEXFUNC_MODULATE; + + Sampler::LinearFunc linear = Sampler::GetLinearFunc(samplerID, nullptr); + Sampler::LinearFunc nearest = Sampler::GetNearestFunc(samplerID, nullptr); + // Can't compile during runtime. This failing is a bit of a problem when undoing... + if (linear && nearest) { + // Since the definitions are the same, just force this setting using the func pointer. + if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { + state->nearest = linear; + state->linear = linear; + } else if (g_Config.iTexFiltering == TEX_FILTER_FORCE_NEAREST) { + state->nearest = nearest; + state->linear = nearest; + } else { + state->nearest = nearest; + state->linear = linear; + } + memcpy(&state->samplerID, &samplerID, sizeof(SamplerID)); + state->flags = ReplaceSamplerIDFlags(state->flags, optimize) | RasterizerStateFlags::OPTIMIZED; + changed = true; + } + } + + state->lastFlags = state->flags; + return changed; +} + +bool OptimizeRasterState(RasterizerState *state) { + if (state->flags == state->lastFlags) + return false; + + RasterizerStateFlags optimize = DetectStateOptimizations(state); + + // If it was optimized before, just revert and don't churn. + if ((state->flags & RasterizerStateFlags::OPTIMIZED) && OptimizeAllFlags(state->flags) != OptimizeAllFlags(optimize)) { + optimize = RasterizerStateFlags::NONE; + } else if (optimize == RasterizerStateFlags::NONE && !(state->flags & RasterizerStateFlags::OPTIMIZED)) { + state->lastFlags = state->flags; + return false; + } + + return ApplyStateOptimizations(state, optimize); +} + RasterizerState OptimizeFlatRasterizerState(const RasterizerState &origState, const VertexData &v1) { uint8_t alpha = v1.color0 >> 24; RasterizerState state = origState; - bool changedPixelID = false; - bool changedSamplerID = false; - if (!state.pixelID.clearMode) { - auto &pixelID = state.pixelID; - auto &cached = pixelID.cached; + // Sometimes, a particular draw can do better than the overall state. + state.flags = ClearFlags(state.flags, RasterizerStateFlags::VERTEX_NON_FULL_WHITE | RasterizerStateFlags::VERTEX_ALPHA_NON_FULL | RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO); + CalculateRasterStateFlags(&state, v1, true); - bool useTextureAlpha = state.enableTextures && state.samplerID.useTextureAlpha; - if (pixelID.alphaBlend && pixelID.AlphaBlendSrc() == PixelBlendFactor::SRCALPHA && !useTextureAlpha) { - // Okay, we may be able to convert this to a fixed value. - if (alpha == 0) { - pixelID.alphaBlendSrc = (uint8_t)PixelBlendFactor::ZERO; - changedPixelID = true; - } else if (alpha == 0xFF) { - pixelID.alphaBlendSrc = (uint8_t)PixelBlendFactor::ONE; - changedPixelID = true; - } - } - if (pixelID.alphaBlend && pixelID.AlphaBlendDst() == PixelBlendFactor::INVSRCALPHA && !useTextureAlpha) { - if (alpha == 0) { - pixelID.alphaBlendDst = (uint8_t)PixelBlendFactor::ONE; - changedPixelID = true; - } else if (alpha == 0xFF) { - pixelID.alphaBlendDst = (uint8_t)PixelBlendFactor::ZERO; - changedPixelID = true; - } - } - if (pixelID.alphaBlend && pixelID.AlphaBlendSrc() == PixelBlendFactor::ONE && pixelID.AlphaBlendDst() == PixelBlendFactor::ZERO) { - if (pixelID.AlphaBlendEq() == GE_BLENDMODE_MUL_AND_ADD) { - pixelID.alphaBlend = false; - changedPixelID = true; - } - } - } - if (state.enableTextures) { - if (v1.color0 == 0xFFFFFFFF) { - // Modulate is common, sometimes even with a fixed color. Replace is cheaper. - if (state.samplerID.TexFunc() == GE_TEXFUNC_MODULATE) { - state.samplerID.texFunc = (uint8_t)GE_TEXFUNC_REPLACE; - changedSamplerID = true; - } - } + RasterizerStateFlags optimize = DetectStateOptimizations(&state); + if (OptimizeAllFlags(state.flags) != OptimizeAllFlags(optimize)) { + ApplyStateOptimizations(&state, optimize); + return state; } - if (changedPixelID) { - state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID, nullptr); - // Can't compile during runtime. - if (!state.drawPixel) - return origState; - } - if (changedSamplerID) { - state.linear = Sampler::GetLinearFunc(state.samplerID, nullptr); - state.nearest = Sampler::GetNearestFunc(state.samplerID, nullptr); - // Can't compile during runtime. - if (!state.linear || !state.nearest) - return origState; - - // Since the definitions are the same, just force this setting using the func pointer. - if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) - state.nearest = state.linear; - else if (g_Config.iTexFiltering == TEX_FILTER_FORCE_NEAREST) - state.linear = state.nearest; - } - - return state; + return origState; } static inline u8 ClampFogDepth(float fogdepth) { diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index f933d8ae8e..2a7a3171c2 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -39,6 +39,15 @@ enum class RasterizerStateFlags { VERTEX_ALPHA_NON_ZERO = 0x0002, VERTEX_ALPHA_NON_FULL = 0x0004, + OPTIMIZED = 0x0001'0000, + OPTIMIZED_BLEND_SRC = 0x0002'0000, + OPTIMIZED_BLEND_DST = 0x0004'0000, + OPTIMIZED_BLEND_OFF = 0x0008'0000, + OPTIMIZED_TEXREPLACE = 0x0010'0000, + + OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF, + OPTIMIZED_SAMPLERID = OPTIMIZED_TEXREPLACE, + INVALID = 0x7FFFFFFF, }; ENUM_CLASS_BITOPS(RasterizerStateFlags); @@ -54,6 +63,7 @@ struct RasterizerState { const u8 *texptr[8]{}; float textureLodSlope; RasterizerStateFlags flags = RasterizerStateFlags::NONE; + RasterizerStateFlags lastFlags = RasterizerStateFlags::INVALID; struct { uint8_t maxTexLevel : 3; @@ -82,6 +92,7 @@ void ComputeRasterizerState(RasterizerState *state, std::function flushF void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0); void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, bool forceFlat); void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, const VertexData &v2); +bool OptimizeRasterState(RasterizerState *state); // Draws a triangle if its vertices are specified in counter-clockwise order void DrawTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const BinCoords &range, const RasterizerState &state); From 0c42e45e928deaa17086c69fd7e53e019e36ba13 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 21:42:57 -0800 Subject: [PATCH 543/715] softgpu: Cleanup reapply logic. This makes more sense to read. --- GPU/Software/Rasterizer.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 4866f3df86..5508b10d3b 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -218,24 +218,28 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { auto &cached = pixelID.cached; bool useTextureAlpha = state->enableTextures && state->samplerID.useTextureAlpha; - if (pixelID.alphaBlend && !useTextureAlpha) { + bool alphaBlend = pixelID.alphaBlend || (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_OFF); + if (alphaBlend && !useTextureAlpha) { + PixelBlendFactor src = pixelID.AlphaBlendSrc(); + PixelBlendFactor dst = pixelID.AlphaBlendDst(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + src = PixelBlendFactor::SRCALPHA; + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + dst = PixelBlendFactor::INVSRCALPHA; + bool canZero = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO); bool canFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); // Okay, we may be able to convert this to a fixed value. if (canZero || canFull) { // If it was already set and we still can, set it again. - if (pixelID.AlphaBlendSrc() == PixelBlendFactor::SRCALPHA || (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC)) + if (src == PixelBlendFactor::SRCALPHA) optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_SRC; - if (pixelID.AlphaBlendDst() == PixelBlendFactor::INVSRCALPHA || (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST)) + if (dst == PixelBlendFactor::INVSRCALPHA) optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_DST; } - if (canFull && (pixelID.AlphaBlendSrc() == PixelBlendFactor::SRCALPHA || pixelID.AlphaBlendSrc() == PixelBlendFactor::ONE) && (pixelID.AlphaBlendDst() == PixelBlendFactor::INVSRCALPHA || pixelID.AlphaBlendDst() == PixelBlendFactor::ZERO)) { + if (canFull && (src == PixelBlendFactor::SRCALPHA || src == PixelBlendFactor::ONE) && (dst == PixelBlendFactor::INVSRCALPHA || dst == PixelBlendFactor::ZERO)) { optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_OFF; } - } else if (!pixelID.alphaBlend && (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_OFF)) { - bool canFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); - if (canFull) - optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_OFF; } } @@ -245,7 +249,11 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { bool colorFull = !(state->flags & RasterizerStateFlags::VERTEX_NON_FULL_WHITE); if (colorFull && (!useTextureAlpha || alphaFull)) { // Modulate is common, sometimes even with a fixed color. Replace is cheaper. - if (state->samplerID.TexFunc() == GE_TEXFUNC_MODULATE || (state->flags & RasterizerStateFlags::OPTIMIZED_TEXREPLACE)) + GETexFunc texFunc = state->samplerID.TexFunc(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_TEXREPLACE) + texFunc = GE_TEXFUNC_MODULATE; + + if (texFunc == GE_TEXFUNC_MODULATE) optimize |= RasterizerStateFlags::OPTIMIZED_TEXREPLACE; } } From 204789a27fe977cef7e783aabc0563c0ea216f27 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 2 Dec 2022 21:55:49 -0800 Subject: [PATCH 544/715] softgpu: Skip fog when no verts have fog. --- GPU/Software/Rasterizer.cpp | 15 ++++++++++++++- GPU/Software/Rasterizer.h | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 5508b10d3b..b2c2a1e104 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -165,6 +165,8 @@ static inline void CalculateRasterStateFlags(RasterizerState *state, const Verte if (alpha != 0xFF) state->flags |= RasterizerStateFlags::VERTEX_ALPHA_NON_FULL; } + if (!(v0.fogdepth >= 1.0f)) + state->flags |= RasterizerStateFlags::VERTEX_HAS_FOG; } void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0) { @@ -241,6 +243,13 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_OFF; } } + + bool applyFog = pixelID.applyFog || (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF); + if (applyFog) { + bool hasFog = state->flags & RasterizerStateFlags::VERTEX_HAS_FOG; + if (!hasFog) + optimize |= RasterizerStateFlags::OPTIMIZED_FOG_OFF; + } } if (state->enableTextures) { @@ -281,6 +290,10 @@ static bool ApplyStateOptimizations(RasterizerState *state, const RasterizerStat pixelID.alphaBlendDst = (uint8_t)(canFull ? PixelBlendFactor::ZERO : PixelBlendFactor::ONE); else if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) pixelID.alphaBlendDst = (uint8_t)PixelBlendFactor::INVSRCALPHA; + if (optimize & RasterizerStateFlags::OPTIMIZED_FOG_OFF) + pixelID.applyFog = false; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF) + pixelID.applyFog = true; SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID, nullptr); // Can't compile during runtime. This failing is a bit of a problem when undoing... @@ -346,7 +359,7 @@ RasterizerState OptimizeFlatRasterizerState(const RasterizerState &origState, co RasterizerState state = origState; // Sometimes, a particular draw can do better than the overall state. - state.flags = ClearFlags(state.flags, RasterizerStateFlags::VERTEX_NON_FULL_WHITE | RasterizerStateFlags::VERTEX_ALPHA_NON_FULL | RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO); + state.flags = ClearFlags(state.flags, RasterizerStateFlags::VERTEX_FLAT_RESET); CalculateRasterStateFlags(&state, v1, true); RasterizerStateFlags optimize = DetectStateOptimizations(&state); diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 2a7a3171c2..ed14d7ca12 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -38,14 +38,19 @@ enum class RasterizerStateFlags { VERTEX_NON_FULL_WHITE = 0x0001, VERTEX_ALPHA_NON_ZERO = 0x0002, VERTEX_ALPHA_NON_FULL = 0x0004, + VERTEX_HAS_FOG = 0x0008, + + VERTEX_FLAT_RESET = VERTEX_NON_FULL_WHITE | VERTEX_ALPHA_NON_FULL | VERTEX_ALPHA_NON_ZERO | VERTEX_HAS_FOG, OPTIMIZED = 0x0001'0000, OPTIMIZED_BLEND_SRC = 0x0002'0000, OPTIMIZED_BLEND_DST = 0x0004'0000, OPTIMIZED_BLEND_OFF = 0x0008'0000, OPTIMIZED_TEXREPLACE = 0x0010'0000, + OPTIMIZED_FOG_OFF = 0x0020'0000, - OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF, + // Anything that changes the actual pixel or sampler func. + OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF, OPTIMIZED_SAMPLERID = OPTIMIZED_TEXREPLACE, INVALID = 0x7FFFFFFF, From 92df6b832c241706fcecae942d963cd755736986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 11:14:08 +0100 Subject: [PATCH 545/715] Safer and simpler alternative to cbfa4bf. See #16483 --- GPU/D3D11/GPU_D3D11.cpp | 4 ---- GPU/D3D11/GPU_D3D11.h | 1 - GPU/Directx9/GPU_DX9.cpp | 4 ---- GPU/Directx9/GPU_DX9.h | 1 - GPU/GLES/GPU_GLES.cpp | 4 ---- GPU/GLES/GPU_GLES.h | 1 - GPU/GPUCommon.cpp | 4 ++++ GPU/GPUCommon.h | 2 ++ GPU/Vulkan/GPU_Vulkan.cpp | 4 ---- GPU/Vulkan/GPU_Vulkan.h | 1 - 10 files changed, 6 insertions(+), 20 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 6e3eb0d740..8259d9fb5c 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -223,10 +223,6 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_D3D11::ClearCacheNextFrame() { - textureCacheD3D11_->ClearNextFrame(); -} - void GPU_D3D11::ClearShaderCache() { shaderManagerD3D11_->ClearShaders(); drawEngine_.ClearInputLayoutMap(); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index 0cba325618..e56acc632a 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -41,7 +41,6 @@ public: void ExecuteOp(u32 op, u32 diff) override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index e13a3b4f3d..c4053953cc 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -220,10 +220,6 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_DX9::ClearCacheNextFrame() { - textureCacheDX9_->ClearNextFrame(); -} - void GPU_DX9::ClearShaderCache() { shaderManagerDX9_->ClearCache(true); } diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 0ec463e55e..ff23b3fb23 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -41,7 +41,6 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 00f5eb43cf..c110380c91 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -362,10 +362,6 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_GLES::ClearCacheNextFrame() { - textureCacheGL_->ClearNextFrame(); -} - void GPU_GLES::ClearShaderCache() { shaderManagerGL_->ClearCache(true); } diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index 4955a3c511..d9ac76390f 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -49,7 +49,6 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 62112f899e..20d97649df 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -627,6 +627,10 @@ void GPUCommon::NotifyDisplayResized() { displayResized_ = true; } +void GPUCommon::ClearCacheNextFrame() { + textureCache_->ClearNextFrame(); +} + // Called once per frame. Might also get called during the pause screen // if "transparent". void GPUCommon::CheckConfigChanged() { diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 7d2cde8b12..96481a9c01 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -267,6 +267,8 @@ protected: void DeviceLost() override; void DeviceRestore() override; + void ClearCacheNextFrame(); + virtual void CheckRenderResized(); // Add additional common features dependent on other features, which may be backend-determined. diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index f91ed4df80..1606073ee9 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -528,10 +528,6 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_Vulkan::ClearCacheNextFrame() { - textureCacheVulkan_->ClearNextFrame(); -} - void GPU_Vulkan::ClearShaderCache() { // TODO } diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 7b83f4d583..f4b56c27e4 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -51,7 +51,6 @@ public: void ExecuteOp(u32 op, u32 diff) override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; From 0f12d44e5976c38431243a538ab81c9f529e851f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 11:20:00 +0100 Subject: [PATCH 546/715] Remove some unused/unnecessary code --- Core/System.cpp | 1 - GPU/D3D11/GPU_D3D11.cpp | 5 ----- GPU/D3D11/GPU_D3D11.h | 2 -- GPU/Directx9/GPU_DX9.cpp | 4 ---- GPU/Directx9/GPU_DX9.h | 2 -- GPU/GLES/GPU_GLES.cpp | 9 --------- GPU/GLES/GPU_GLES.h | 3 --- GPU/GPUCommon.h | 2 -- GPU/GPUInterface.h | 2 -- GPU/Vulkan/GPU_Vulkan.cpp | 4 ---- GPU/Vulkan/GPU_Vulkan.h | 2 -- 11 files changed, 36 deletions(-) diff --git a/Core/System.cpp b/Core/System.cpp index cb6fc34fa8..35da73d353 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -599,7 +599,6 @@ void PSP_RunLoopUntil(u64 globalticks) { } mipsr4k.RunLoopUntil(globalticks); - gpu->CleanupBeforeUI(); } void PSP_RunLoopFor(int cycles) { diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 8259d9fb5c..86340fc6d8 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -223,11 +223,6 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_D3D11::ClearShaderCache() { - shaderManagerD3D11_->ClearShaders(); - drawEngine_.ClearInputLayoutMap(); -} - void GPU_D3D11::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index e56acc632a..a4bcbd670f 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -46,8 +46,6 @@ public: void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index c4053953cc..c5559f379a 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -220,10 +220,6 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_DX9::ClearShaderCache() { - shaderManagerDX9_->ClearCache(true); -} - void GPU_DX9::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index ff23b3fb23..058e1b75d2 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -46,8 +46,6 @@ public: void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index c110380c91..a707915eb1 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -362,15 +362,6 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_GLES::ClearShaderCache() { - shaderManagerGL_->ClearCache(true); -} - -void GPU_GLES::CleanupBeforeUI() { - // Clear any enabled vertex arrays. - shaderManagerGL_->DirtyLastShader(); -} - void GPU_GLES::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index d9ac76390f..afb1de0f42 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -54,9 +54,6 @@ public: void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - void CleanupBeforeUI() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 96481a9c01..4b47c65570 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -243,8 +243,6 @@ public: return dlQueue; } std::vector GetFramebufferList() const override; - void ClearShaderCache() override {} - void CleanupBeforeUI() override {} s64 GetListTicks(int listid) const override { if (listid >= 0 && listid < DisplayListMaxCount) { diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 1c859b786e..9dc7d82886 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -261,8 +261,6 @@ public: virtual void NotifyRenderResized() = 0; virtual void NotifyConfigChanged() = 0; - virtual void ClearShaderCache() = 0; - virtual void CleanupBeforeUI() = 0; virtual bool FramebufferDirty() = 0; virtual bool FramebufferReallyDirty() = 0; virtual bool BusyDrawing() = 0; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 1606073ee9..bd4b4f0204 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -528,10 +528,6 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_Vulkan::ClearShaderCache() { - // TODO -} - void GPU_Vulkan::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index f4b56c27e4..8c970948bd 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -56,8 +56,6 @@ public: void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; From 954bd69e30aaad3090b1f85e48b12c821c7bed6d Mon Sep 17 00:00:00 2001 From: Johan Mattsson <39247600+mjunix@users.noreply.github.com> Date: Sat, 3 Dec 2022 15:26:31 +0100 Subject: [PATCH 547/715] Fix progress computation --- Core/Util/GameManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index 63952a5d81..7ae0bdb5ef 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -652,7 +652,7 @@ bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const P if (fwrite(buffer, readSize, 1, outf) != 1) break; bytesCopied += readSize; - installProgress_ = (float)allBytes / (float)allBytes; + installProgress_ = (float)bytesCopied / (float)allBytes; } delete[] buffer; From 2b1d57257a63787339cde3e72e443367819df8b1 Mon Sep 17 00:00:00 2001 From: Johan Mattsson <39247600+mjunix@users.noreply.github.com> Date: Sat, 3 Dec 2022 15:28:22 +0100 Subject: [PATCH 548/715] Fix comparison --- Common/Thread/ThreadManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/Thread/ThreadManager.cpp b/Common/Thread/ThreadManager.cpp index 5fca697635..4f60b5b764 100644 --- a/Common/Thread/ThreadManager.cpp +++ b/Common/Thread/ThreadManager.cpp @@ -113,7 +113,7 @@ bool ThreadManager::TeardownTask(Task *task, bool enqueue) { if (task->Type() == TaskType::CPU_COMPUTE) { global_->compute_queue.push_back(task); global_->compute_queue_size++; - } else if (task->Type() == TaskType::CPU_COMPUTE) { + } else if (task->Type() == TaskType::IO_BLOCKING) { global_->io_queue.push_back(task); global_->io_queue_size++; } else { From e260ba40625df6bb7727b101f456e96c2a280345 Mon Sep 17 00:00:00 2001 From: Johan Mattsson <39247600+mjunix@users.noreply.github.com> Date: Sat, 3 Dec 2022 15:29:14 +0100 Subject: [PATCH 549/715] Fix missing 'else' --- UI/ReportScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index b1d7de7326..ca09054c28 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -485,7 +485,7 @@ void ReportFinishScreen::ShowSuggestions() { const char *suggestion = nullptr; if (item == "Upgrade") { suggestion = rp->T("SuggestionUpgrade", "Upgrade to a newer PPSSPP build"); - } if (item == "Downgrade") { + } else if (item == "Downgrade") { suggestion = rp->T("SuggestionDowngrade", "Downgrade to an older PPSSPP version (please report this bug)"); } else if (item == "VerifyDisc") { suggestion = rp->T("SuggestionVerifyDisc", "Check your ISO is a good copy of your disc"); From e50eae1bfbb46dd0922f62e57bbb38a9f47725ee Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 07:17:12 -0800 Subject: [PATCH 550/715] GPU: Cleanup some bounds checks, assignments. --- Common/GPU/Vulkan/VulkanFrameData.cpp | 2 +- GPU/Directx9/StateMappingDX9.cpp | 2 +- GPU/Vulkan/VulkanUtil.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanFrameData.cpp b/Common/GPU/Vulkan/VulkanFrameData.cpp index ab74478396..4503ea1c82 100644 --- a/Common/GPU/Vulkan/VulkanFrameData.cpp +++ b/Common/GPU/Vulkan/VulkanFrameData.cpp @@ -121,7 +121,7 @@ VkCommandBuffer FrameData::GetInitCmd(VulkanContext *vulkan) { } void FrameData::SubmitPending(VulkanContext *vulkan, FrameSubmitType type, FrameDataShared &sharedData) { - VkCommandBuffer cmdBufs[2]; + VkCommandBuffer cmdBufs[3]; int numCmdBufs = 0; VkFence fenceToTrigger = VK_NULL_HANDLE; diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 4517150daf..3a39a9b27e 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -99,7 +99,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { if (!gstate.isModeClear()) { textureCache_->ApplyTexture(); - if (fboTexBindState_ = FBO_TEX_COPY_BIND_TEX) { + if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) { // Note that this is positions, not UVs, that we need the copy from. framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0); // If we are rendering at a higher resolution, linear is probably best for the dest color. diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index fbfb8ad3fa..d878bff579 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -141,7 +141,7 @@ VkDescriptorSet VulkanComputeShaderManager::GetDescriptorSet(VkImageView image, VkDescriptorSet desc = frameData.descPool.Allocate(1, &descriptorSetLayout_, "compute_descset"); _assert_(desc != VK_NULL_HANDLE); - VkWriteDescriptorSet writes[2]{}; + VkWriteDescriptorSet writes[3]{}; int n = 0; VkDescriptorImageInfo imageInfo = {}; VkDescriptorBufferInfo bufferInfo[2] = {}; From 2b58ac7e95d63289a4658d713e876f8e76e4297a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 07:17:27 -0800 Subject: [PATCH 551/715] Psmf: Fix pointer check. --- Core/HLE/scePsmf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/scePsmf.cpp b/Core/HLE/scePsmf.cpp index eebac79bfa..f4bcb09166 100644 --- a/Core/HLE/scePsmf.cpp +++ b/Core/HLE/scePsmf.cpp @@ -751,7 +751,7 @@ static void DelayPsmfStateChange(u32 psmfPlayer, u32 newState, s64 delayUs) { } static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) { - if (!Memory::IsValidAddress(psmfData) || !Memory::IsValidAddress(psmfData)) { + if (!Memory::IsValidAddress(psmfStruct) || !Memory::IsValidAddress(psmfData)) { // Crashes on a PSP. return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); } From f651f365b060c926c925de55979b25b0afda2169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 17:42:29 +0100 Subject: [PATCH 552/715] Disable the MSAA selector if software rendering is selected. Move software rendering up. --- UI/GameSettingsScreen.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 9bb4f69995..d64a42d5d0 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -305,6 +305,11 @@ void GameSettingsScreen::CreateViews() { return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects; }); + if (deviceType != DEVICE_TYPE_VR) { + CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); + softwareGPU->SetEnabled(!PSP_IsInited()); + } + if (draw->GetDeviceCaps().multiSampleLevelsMask != 1) { static const char *msaaModes[] = { "Off", "2x", "4x", "8x", "16x" }; auto msaaChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iMultiSampleLevel, gr->T("Antialiasing (MSAA)"), msaaModes, 0, ARRAY_SIZE(msaaModes), gr->GetName(), screenManager())); @@ -312,6 +317,8 @@ void GameSettingsScreen::CreateViews() { NativeMessageReceived("gpu_renderResized", ""); return UI::EVENT_DONE; }); + msaaChoice->SetDisabledPtr(&g_Config.bSoftwareRendering); + // Hide unsupported levels. for (int i = 1; i < 5; i++) { if ((draw->GetDeviceCaps().multiSampleLevelsMask & (1 << i)) == 0) { @@ -332,11 +339,6 @@ void GameSettingsScreen::CreateViews() { } #endif - if (deviceType != DEVICE_TYPE_VR) { - CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); - softwareGPU->SetEnabled(!PSP_IsInited()); - } - if (deviceType != DEVICE_TYPE_VR) { #if !defined(MOBILE_DEVICE) graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); From f5c0dc717a5347c4090182df2235fb1736f82a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 18:58:47 +0100 Subject: [PATCH 553/715] Sort post-shaders alphabetically in the list. --- GPU/Common/PostShader.cpp | 28 ++++++++++++++++------------ GPU/Common/PostShader.h | 6 ++++++ UI/DisplayLayoutScreen.cpp | 1 + 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 6b0b94387a..0c525f766e 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -50,18 +50,6 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } shaderInfo.clear(); - ShaderInfo off{}; - off.visible = true; - off.name = "Off"; - off.section = "Off"; - for (size_t i = 0; i < ARRAY_SIZE(off.settings); ++i) { - off.settings[i].name.clear(); - off.settings[i].value = 0.0f; - off.settings[i].minValue = -1.0f; - off.settings[i].maxValue = 1.0f; - off.settings[i].step = 0.01f; - } - shaderInfo.push_back(off); textureShaderInfo.clear(); TextureShaderInfo textureOff{}; @@ -231,6 +219,22 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } } + // Sort shaders alphabetically. + std::sort(shaderInfo.begin(), shaderInfo.end()); + + ShaderInfo off{}; + off.visible = true; + off.name = "Off"; + off.section = "Off"; + for (size_t i = 0; i < ARRAY_SIZE(off.settings); ++i) { + off.settings[i].name.clear(); + off.settings[i].value = 0.0f; + off.settings[i].minValue = -1.0f; + off.settings[i].maxValue = 1.0f; + off.settings[i].step = 0.01f; + } + shaderInfo.insert(shaderInfo.begin(), off); + // We always want the not visible ones at the end. Makes menus easier. for (const auto &info : notVisible) { appendShader(info); diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index 849ac884f3..befa5847ce 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -66,6 +66,12 @@ struct ShaderInfo { bool operator == (const ShaderInfo &other) { return name == other.name; } + + bool operator < (const ShaderInfo &other) { + if (name < other.name) return true; + if (name > other.name) return false; + return false; + } }; struct TextureShaderInfo { diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 5152965179..82ee390b7c 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -267,6 +267,7 @@ void DisplayLayoutScreen::CreateViews() { postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); + procScreen->SetHasDropShadow(false); procScreen->OnChoice.Handle(this, &DisplayLayoutScreen::OnPostProcShaderChange); if (e.v) procScreen->SetPopupOrigin(e.v); From fb5474115c3108933a1b28248b4a1058bcdf049e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 19:07:38 +0100 Subject: [PATCH 554/715] Align the version number better on the main screen --- UI/MainScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index cdd1fc4a0c..53d77213c2 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -1128,7 +1128,7 @@ void MainScreen::CreateViews() { #endif rightColumnItems->Add(logos); - TextView *ver = rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -6, 0, 0)))); + TextView *ver = rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -10, 0, 4)))); ver->SetSmall(true); ver->SetClip(false); From b938992da47d905d76434ab432cdc16d0d9384bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 19:13:21 +0100 Subject: [PATCH 555/715] Add a new centering capability to AnchorLayout --- Common/UI/ViewGroup.cpp | 6 ++++++ Common/UI/ViewGroup.h | 1 + 2 files changed, 7 insertions(+) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 9b7dac87bd..eefb93d82f 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1272,6 +1272,9 @@ void AnchorLayout::Layout() { if (center) { vBounds.x += vBounds.w * 0.5f; } + } else { + // Both left and right are NONE. Center. + vBounds.x = (bounds_.w - vBounds.w) / 2.0f + bounds_.x; } if (top > NONE) { @@ -1282,6 +1285,9 @@ void AnchorLayout::Layout() { vBounds.y = bounds_.y2() - bottom - vBounds.h; if (center) vBounds.y += vBounds.h * 0.5f; + } else { + // Both top and bottom are NONE. Center. + vBounds.y = (bounds_.h - vBounds.h) / 2.0f + bounds_.y; } views_[i]->SetBounds(vBounds); diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 5a10704a23..05fe046681 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -123,6 +123,7 @@ public: // These are not bounds, but distances from the container edges. // Set to NONE to not attach this edge to the container. + // If two opposite edges are NONE, centering will happen. float left, top, right, bottom; bool center; // If set, only two "sides" can be set, and they refer to the center, not the edge, of the view being layouted. From e46b0364820d5934b13bdc76ae71c0fe5dc00aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 19:13:39 +0100 Subject: [PATCH 556/715] Reorganize the DisplayLayoutScreen again - flip left/right sides, move mode switch to bottom. --- UI/DisplayLayoutScreen.cpp | 40 ++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 82ee390b7c..c7286acf62 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -208,31 +208,31 @@ void DisplayLayoutScreen::CreateViews() { rightScrollView->Add(rightColumn); root_->Add(rightScrollView); + LinearLayout *bottomControls = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, NONE, NONE, 10.0f, false)); + root_->Add(bottomControls); if (!IsVREnabled()) { auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); - leftColumn->Add(stretch); + rightColumn->Add(stretch); PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, gr->T("Aspect Ratio"), screenManager()); - leftColumn->Add(aspectRatio); + rightColumn->Add(aspectRatio); aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch); aspectRatio->SetHasDropShadow(false); aspectRatio->SetLiveUpdate(true); - mode_ = new ChoiceStrip(ORIENT_VERTICAL); + mode_ = new ChoiceStrip(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); mode_->AddChoice(di->T("Move")); mode_->AddChoice(di->T("Resize")); mode_->SetSelection(0, false); - leftColumn->Add(mode_); + bottomControls->Add(mode_); static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); rotation->SetEnabledFunc([] { return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; }); - leftColumn->Add(rotation); - - leftColumn->Add(new Spacer(12.0f)); + rightColumn->Add(rotation); Choice *center = new Choice(di->T("Reset")); center->OnClick.Add([&](UI::EventParams &) { @@ -242,13 +242,19 @@ void DisplayLayoutScreen::CreateViews() { g_Config.fDisplayOffsetY = 0.5f; return UI::EVENT_DONE; }); - leftColumn->Add(center); + rightColumn->Add(center); + + rightColumn->Add(new Spacer(12.0f)); } - static const char *bufFilters[] = { "Linear", "Nearest", }; - rightColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); + Choice *back = new Choice(di->T("Back"), "", false); + back->OnClick.Handle(this, &UIScreen::OnBack); + rightColumn->Add(back); - rightColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); + static const char *bufFilters[] = { "Linear", "Nearest", }; + leftColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); + + leftColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); Draw::DrawContext *draw = screenManager()->getDrawContext(); @@ -262,8 +268,8 @@ void DisplayLayoutScreen::CreateViews() { for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; - rightColumn->Add(new ItemHeader(StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1))); - postProcChoice_ = rightColumn->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName)); + leftColumn->Add(new ItemHeader(StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1))); + postProcChoice_ = leftColumn->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName)); postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); @@ -293,10 +299,10 @@ void DisplayLayoutScreen::CreateViews() { auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; if (duplicated) { auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); - PopupSliderChoiceFloat *settingValue = rightColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); + PopupSliderChoiceFloat *settingValue = leftColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); settingValue->SetEnabled(false); } else { - PopupSliderChoiceFloat *settingValue = rightColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + PopupSliderChoiceFloat *settingValue = leftColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetLiveUpdate(true); settingValue->SetHasDropShadow(false); settingValue->SetEnabledFunc([=] { @@ -308,9 +314,5 @@ void DisplayLayoutScreen::CreateViews() { } } - Choice *back = new Choice(di->T("Back"), "", false); - back->OnClick.Handle(this, &UIScreen::OnBack); - rightColumn->Add(back); - root_->Add(new DisplayLayoutBackground(mode_, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, 0.0f, 0.0f, 0.0f, 0.0f))); } From f3ba8fb334613f98e6264b648f260dfd8957c685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 19:30:50 +0100 Subject: [PATCH 557/715] Address feedback, also sort texture shaders --- Common/File/Path.h | 3 +++ GPU/Common/PostShader.cpp | 13 +++++++------ GPU/Common/PostShader.h | 22 +++++++++++++++++----- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Common/File/Path.h b/Common/File/Path.h index ab49fb10cf..aded7b5bde 100644 --- a/Common/File/Path.h +++ b/Common/File/Path.h @@ -118,6 +118,9 @@ public: bool operator <(const Path &other) const { return path_ < other.path_; } + bool operator >(const Path &other) const { + return path_ > other.path_; + } private: // The internal representation is currently always the plain string. diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 0c525f766e..c282d541c1 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -51,12 +51,6 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct shaderInfo.clear(); - textureShaderInfo.clear(); - TextureShaderInfo textureOff{}; - textureOff.name = "Off"; - textureOff.section = "Off"; - textureShaderInfo.push_back(textureOff); - auto appendShader = [&](const ShaderInfo &info) { auto beginErase = std::remove(shaderInfo.begin(), shaderInfo.end(), info.name); if (beginErase != shaderInfo.end()) { @@ -221,6 +215,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct // Sort shaders alphabetically. std::sort(shaderInfo.begin(), shaderInfo.end()); + std::sort(textureShaderInfo.begin(), textureShaderInfo.end()); ShaderInfo off{}; off.visible = true; @@ -235,6 +230,12 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } shaderInfo.insert(shaderInfo.begin(), off); + textureShaderInfo.clear(); + TextureShaderInfo textureOff{}; + textureOff.name = "Off"; + textureOff.section = "Off"; + textureShaderInfo.push_back(textureOff); + // We always want the not visible ones at the end. Makes menus easier. for (const auto &info : notVisible) { appendShader(info); diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index befa5847ce..ef4e2c83b5 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -60,16 +60,19 @@ struct ShaderInfo { // TODO: Add support for all kinds of fun options like mapping the depth buffer, // SRGB texture reads, etc. prev shader? - bool operator == (const std::string &other) { + bool operator == (const std::string &other) const { return name == other; } - bool operator == (const ShaderInfo &other) { + bool operator == (const ShaderInfo &other) const { return name == other.name; } - bool operator < (const ShaderInfo &other) { + bool operator < (const ShaderInfo &other) const { if (name < other.name) return true; if (name > other.name) return false; + // Tie breaker + if (iniFile < other.iniFile) return true; + if (iniFile > other.iniFile) return false; return false; } }; @@ -84,12 +87,21 @@ struct TextureShaderInfo { // Upscaling shaders have a fixed scale factor. int scaleFactor; - bool operator == (const std::string &other) { + bool operator == (const std::string &other) const { return name == other; } - bool operator == (const TextureShaderInfo &other) { + bool operator == (const TextureShaderInfo &other) const { return name == other.name; } + + bool operator < (const TextureShaderInfo &other) const { + if (name < other.name) return true; + if (name > other.name) return false; + // Tie breaker + if (iniFile < other.iniFile) return true; + if (iniFile > other.iniFile) return false; + return false; + } }; void ReloadAllPostShaderInfo(Draw::DrawContext *draw); From 6acbd1f9e3bbd430caf833c8f3d7fc21745ca40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 20:37:58 +0100 Subject: [PATCH 558/715] Fix loading of texture shaders --- GPU/Common/PostShader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index c282d541c1..636c1b39e8 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -50,6 +50,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } shaderInfo.clear(); + textureShaderInfo.clear(); auto appendShader = [&](const ShaderInfo &info) { auto beginErase = std::remove(shaderInfo.begin(), shaderInfo.end(), info.name); @@ -230,11 +231,10 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } shaderInfo.insert(shaderInfo.begin(), off); - textureShaderInfo.clear(); TextureShaderInfo textureOff{}; textureOff.name = "Off"; textureOff.section = "Off"; - textureShaderInfo.push_back(textureOff); + textureShaderInfo.insert(textureShaderInfo.begin(), textureOff); // We always want the not visible ones at the end. Makes menus easier. for (const auto &info : notVisible) { From 38eb0a7a8293ea73bd1d649b8f1e87608b44a51b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 12:15:58 -0800 Subject: [PATCH 559/715] softgpu: Check for queued compile. Rarely, we could have queued compiling the same one, which would crash on a double insert. --- GPU/Software/DrawPixel.cpp | 4 +++- GPU/Software/Sampler.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index 12dcc9cfe8..2f4ea23b17 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -816,7 +816,9 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function } compileQueue_.clear(); - Compile(id); + // Might've been in the queue. + if (!cache_.Get(key)) + Compile(id); return cache_.Get(key); } diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 1f7eaefaf2..66022fa53b 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -182,7 +182,8 @@ NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function } compileQueue_.clear(); - Compile(id); + if (!cache_.Get(key)) + Compile(id); // Okay, should be there now. return cache_.Get(key); From 0aba5ff3c18d75fe9d08991cf7c7269a73cdd7ed Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 12:38:01 -0800 Subject: [PATCH 560/715] TexCache: Correct alpha mask checks for SSE2. Should have been shifts by byte (4/8), but let's just switch to shuffles anyway. These were always shifting in zeros and failing. --- GPU/Common/TextureDecoder.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index d7788077a6..22e45b151b 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -641,16 +641,12 @@ void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int height) { #ifdef _M_SSE inline u32 SSEReduce32And(__m128i value) { - // TODO: Should use a shuffle instead of slri, probably. - value = _mm_and_si128(value, _mm_srli_si128(value, 64)); - value = _mm_and_si128(value, _mm_srli_si128(value, 32)); + value = _mm_and_si128(value, _mm_shuffle_epi32(value, _MM_SHUFFLE(1, 0, 3, 2))); + value = _mm_and_si128(value, _mm_shuffle_epi32(value, _MM_SHUFFLE(1, 1, 1, 1))); return _mm_cvtsi128_si32(value); } inline u32 SSEReduce16And(__m128i value) { - // TODO: Should use a shuffle instead of slri, probably. - value = _mm_and_si128(value, _mm_srli_si128(value, 64)); - value = _mm_and_si128(value, _mm_srli_si128(value, 32)); - u32 mask = _mm_cvtsi128_si32(value); + u32 mask = SSEReduce32And(value); return mask & (mask >> 16); } #endif From adc94b19508eb20f76d707238b778ed3aaf8eb9f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 12:44:02 -0800 Subject: [PATCH 561/715] softgpu: Use CLUT to optimize out blending more. This actually happens relatively often. --- GPU/Software/Rasterizer.cpp | 68 ++++++++++++++++++++++++++++++------- GPU/Software/Rasterizer.h | 3 ++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index b2c2a1e104..b9af632aa9 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -211,17 +211,65 @@ static inline RasterizerStateFlags ReplaceSamplerIDFlags(const RasterizerStateFl return updated | (RasterizerStateFlags)OptimizeSamplerIDFlags(replace); } +static bool CheckClutAlphaFull(RasterizerState *state) { + // We only need to check it once. + if (state->flags & RasterizerStateFlags::CLUT_ALPHA_CHECKED) + return !(state->flags & RasterizerStateFlags::CLUT_ALPHA_NON_FULL); + // For now, let's keep things simple. + const SamplerID &samplerID = state->samplerID; + if (samplerID.hasClutOffset || !samplerID.useSharedClut) + return false; + + uint32_t count = samplerID.TexFmt() == GE_TFMT_CLUT4 ? 16 : 256; + if (samplerID.hasClutMask) + count = std::min(count, ((samplerID.cached.clutFormat >> 8) & 0xFF) + 1); + + bool onlyFull = true; + switch (samplerID.ClutFmt()) { + case GE_CMODE_16BIT_BGR5650: + break; + + case GE_CMODE_16BIT_ABGR5551: + onlyFull = CheckAlpha16((const uint16_t *)samplerID.cached.clut, count, 0x8000) == CHECKALPHA_FULL; + break; + + case GE_CMODE_16BIT_ABGR4444: + onlyFull = CheckAlpha16((const uint16_t *)samplerID.cached.clut, count, 0xF000) == CHECKALPHA_FULL; + break; + + case GE_CMODE_32BIT_ABGR8888: + onlyFull = CheckAlpha32((const uint32_t *)samplerID.cached.clut, count, 0xFF000000) == CHECKALPHA_FULL; + break; + } + + if (!onlyFull) + state->flags |= RasterizerStateFlags::CLUT_ALPHA_NON_FULL; + state->flags |= RasterizerStateFlags::CLUT_ALPHA_CHECKED; + + return onlyFull; +} + static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { // Note: all optimizations must be undoable. RasterizerStateFlags optimize = RasterizerStateFlags::NONE; + auto &pixelID = state->pixelID; + auto &samplerID = state->samplerID; - if (!state->pixelID.clearMode) { - auto &pixelID = state->pixelID; + bool alphaZero = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO); + bool alphaFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); + bool needTextureAlpha = state->enableTextures && samplerID.useTextureAlpha; + + if (!pixelID.clearMode) { auto &cached = pixelID.cached; - bool useTextureAlpha = state->enableTextures && state->samplerID.useTextureAlpha; bool alphaBlend = pixelID.alphaBlend || (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_OFF); - if (alphaBlend && !useTextureAlpha) { + if (needTextureAlpha && alphaBlend && alphaFull) { + bool usesClut = (samplerID.texfmt & 4) != 0; + if (usesClut && CheckClutAlphaFull(state)) + needTextureAlpha = false; + } + + if (alphaBlend && !needTextureAlpha) { PixelBlendFactor src = pixelID.AlphaBlendSrc(); PixelBlendFactor dst = pixelID.AlphaBlendDst(); if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) @@ -229,17 +277,15 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) dst = PixelBlendFactor::INVSRCALPHA; - bool canZero = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO); - bool canFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); // Okay, we may be able to convert this to a fixed value. - if (canZero || canFull) { + if (alphaZero || alphaFull) { // If it was already set and we still can, set it again. if (src == PixelBlendFactor::SRCALPHA) optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_SRC; if (dst == PixelBlendFactor::INVSRCALPHA) optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_DST; } - if (canFull && (src == PixelBlendFactor::SRCALPHA || src == PixelBlendFactor::ONE) && (dst == PixelBlendFactor::INVSRCALPHA || dst == PixelBlendFactor::ZERO)) { + if (alphaFull && (src == PixelBlendFactor::SRCALPHA || src == PixelBlendFactor::ONE) && (dst == PixelBlendFactor::INVSRCALPHA || dst == PixelBlendFactor::ZERO)) { optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_OFF; } } @@ -253,12 +299,10 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { } if (state->enableTextures) { - bool useTextureAlpha = state->samplerID.useTextureAlpha; - bool alphaFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); bool colorFull = !(state->flags & RasterizerStateFlags::VERTEX_NON_FULL_WHITE); - if (colorFull && (!useTextureAlpha || alphaFull)) { + if (colorFull && (!needTextureAlpha || alphaFull)) { // Modulate is common, sometimes even with a fixed color. Replace is cheaper. - GETexFunc texFunc = state->samplerID.TexFunc(); + GETexFunc texFunc = samplerID.TexFunc(); if (state->flags & RasterizerStateFlags::OPTIMIZED_TEXREPLACE) texFunc = GE_TEXFUNC_MODULATE; diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index ed14d7ca12..859f01f655 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -40,6 +40,9 @@ enum class RasterizerStateFlags { VERTEX_ALPHA_NON_FULL = 0x0004, VERTEX_HAS_FOG = 0x0008, + CLUT_ALPHA_CHECKED = 0x0010, + CLUT_ALPHA_NON_FULL = 0x0020, + VERTEX_FLAT_RESET = VERTEX_NON_FULL_WHITE | VERTEX_ALPHA_NON_FULL | VERTEX_ALPHA_NON_ZERO | VERTEX_HAS_FOG, OPTIMIZED = 0x0001'0000, From eb19e2439990fdbd0e6739636cdcad05216b404a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 12:44:35 -0800 Subject: [PATCH 562/715] softgpu: Skip non-zero alpha test if impossible. --- GPU/Software/Rasterizer.cpp | 14 ++++++++++++++ GPU/Software/Rasterizer.h | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index b9af632aa9..0dbda3e2ba 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -309,6 +309,16 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { if (texFunc == GE_TEXFUNC_MODULATE) optimize |= RasterizerStateFlags::OPTIMIZED_TEXREPLACE; } + + bool usesClut = (samplerID.texfmt & 4) != 0; + if (usesClut && alphaFull && samplerID.useTextureAlpha) { + bool alphaTest = pixelID.AlphaTestFunc() == GE_COMP_NOTEQUAL && pixelID.alphaTestRef == 0 && !state->pixelID.hasAlphaTestMask; + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF) + alphaTest = true; + + if (alphaTest && CheckClutAlphaFull(state)) + optimize |= RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF; + } } return optimize; @@ -338,6 +348,10 @@ static bool ApplyStateOptimizations(RasterizerState *state, const RasterizerStat pixelID.applyFog = false; else if (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF) pixelID.applyFog = true; + if (optimize & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF) + pixelID.alphaTestFunc = GE_COMP_ALWAYS; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF) + pixelID.alphaTestFunc = GE_COMP_NOTEQUAL; SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID, nullptr); // Can't compile during runtime. This failing is a bit of a problem when undoing... diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 859f01f655..067d8fe058 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -51,9 +51,10 @@ enum class RasterizerStateFlags { OPTIMIZED_BLEND_OFF = 0x0008'0000, OPTIMIZED_TEXREPLACE = 0x0010'0000, OPTIMIZED_FOG_OFF = 0x0020'0000, + OPTIMIZED_ALPHATEST_OFF = 0x0040'0000, // Anything that changes the actual pixel or sampler func. - OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF, + OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF, OPTIMIZED_SAMPLERID = OPTIMIZED_TEXREPLACE, INVALID = 0x7FFFFFFF, From 00e76b11b631ff0f174f1139183508e245c0aed9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 12:55:38 -0800 Subject: [PATCH 563/715] softgpu: Optimize > non-zero alpha tests as well. These are fairly common, especially in 3D games. --- GPU/Software/Rasterizer.cpp | 19 +++++++++++++------ GPU/Software/Rasterizer.h | 5 +++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 0dbda3e2ba..7059d52973 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -312,12 +312,17 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { bool usesClut = (samplerID.texfmt & 4) != 0; if (usesClut && alphaFull && samplerID.useTextureAlpha) { - bool alphaTest = pixelID.AlphaTestFunc() == GE_COMP_NOTEQUAL && pixelID.alphaTestRef == 0 && !state->pixelID.hasAlphaTestMask; - if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF) - alphaTest = true; + GEComparison alphaTestFunc = pixelID.AlphaTestFunc(); + // We optimize > 0 to != 0, so this is especially common. + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE) + alphaTestFunc = GE_COMP_NOTEQUAL; + // > 16, 8, or similar are also very common. + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) + alphaTestFunc = GE_COMP_GREATER; + bool alphaTest = (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) && pixelID.alphaTestRef < 0xFF && !state->pixelID.hasAlphaTestMask; if (alphaTest && CheckClutAlphaFull(state)) - optimize |= RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF; + optimize |= alphaTestFunc == GE_COMP_NOTEQUAL ? RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE : RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT; } } @@ -348,10 +353,12 @@ static bool ApplyStateOptimizations(RasterizerState *state, const RasterizerStat pixelID.applyFog = false; else if (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF) pixelID.applyFog = true; - if (optimize & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF) + if (optimize & (RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT)) pixelID.alphaTestFunc = GE_COMP_ALWAYS; - else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF) + else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE) pixelID.alphaTestFunc = GE_COMP_NOTEQUAL; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) + pixelID.alphaTestFunc = GE_COMP_GREATER; SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID, nullptr); // Can't compile during runtime. This failing is a bit of a problem when undoing... diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 067d8fe058..d4386c4ba3 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -51,10 +51,11 @@ enum class RasterizerStateFlags { OPTIMIZED_BLEND_OFF = 0x0008'0000, OPTIMIZED_TEXREPLACE = 0x0010'0000, OPTIMIZED_FOG_OFF = 0x0020'0000, - OPTIMIZED_ALPHATEST_OFF = 0x0040'0000, + OPTIMIZED_ALPHATEST_OFF_NE = 0x0040'0000, + OPTIMIZED_ALPHATEST_OFF_GT = 0x0080'0000, // Anything that changes the actual pixel or sampler func. - OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF, + OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT, OPTIMIZED_SAMPLERID = OPTIMIZED_TEXREPLACE, INVALID = 0x7FFFFFFF, From 8567416be6f341f9692f987c406250997af9fc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 2 Dec 2022 00:35:28 +0100 Subject: [PATCH 564/715] Force "Lower resolution for effects" off in Ratchet & Clank and a few other games It breaks or just makes things look terrible in these games, so no reason to allow it. An alternative for this would be to remove the option entirely, and only use it though the ForceLowerResolutionForEffectsOn flag instead. --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + GPU/Common/FramebufferManagerCommon.cpp | 7 +++++- assets/compat.ini | 30 +++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 8db5e81112..deba3981bd 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -116,6 +116,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "DeswizzleDepth", &flags_.DeswizzleDepth); CheckSetting(iniFile, gameID, "SplitFramebufferMargin", &flags_.SplitFramebufferMargin); CheckSetting(iniFile, gameID, "ForceLowerResolutionForEffectsOn", &flags_.ForceLowerResolutionForEffectsOn); + CheckSetting(iniFile, gameID, "ForceLowerResolutionForEffectsOff", &flags_.ForceLowerResolutionForEffectsOff); CheckSetting(iniFile, gameID, "AllowDownloadCLUT", &flags_.AllowDownloadCLUT); CheckSetting(iniFile, gameID, "NearestFilteringOnFramebufferCreate", &flags_.NearestFilteringOnFramebufferCreate); CheckSetting(iniFile, gameID, "SecondaryTextureCache", &flags_.SecondaryTextureCache); diff --git a/Core/Compatibility.h b/Core/Compatibility.h index aeb6b6996c..29ad3a701a 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -87,6 +87,7 @@ struct CompatFlags { bool DeswizzleDepth; bool SplitFramebufferMargin; bool ForceLowerResolutionForEffectsOn; + bool ForceLowerResolutionForEffectsOff; bool AllowDownloadCLUT; bool NearestFilteringOnFramebufferCreate; bool SecondaryTextureCache; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 5bf2cdc9de..88c27b03a3 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -91,7 +91,12 @@ void FramebufferManagerCommon::Init() { bool FramebufferManagerCommon::UpdateRenderSize() { const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight || msaaLevel_ != g_Config.iMultiSampleLevel; - const int effectiveBloomHack = PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn ? 3 : g_Config.iBloomHack; + int effectiveBloomHack = g_Config.iBloomHack; + if (PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn) { + effectiveBloomHack = 3; + } else if (PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOff) { + effectiveBloomHack = 0; + } bool newBuffered = !g_Config.bSkipBufferEffects; const bool newSettings = bloomHack_ != effectiveBloomHack || useBufferedRendering_ != newBuffered; diff --git a/assets/compat.ini b/assets/compat.ini index feaa62da0e..d228419771 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -622,6 +622,8 @@ ULJM05570 = true # Cars Race-o-rama ULUS10428 = true +ULES01333 = true + # MX vs ATV Reflex ULES01375 = true ULUS10429 = true @@ -1231,6 +1233,34 @@ UCKS45124 = true UCJS10104 = true NPJG00047 = true +[ForceLowerResolutionForEffectsOff] +# Some games really don't work with this. Ratchet & Clank looks terrible. +UCUS98633 = true +UCAS40145 = true +UCES00420 = true +UCJS10052 = true +UCKS45048 = true +UCES00420 = true +UCJS18030 = true +UCJS18047 = true +NPJG00015 = true + +# The various Tantalus games will not work with this. + +# Cars Race-o-rama +ULUS10428 = true +ULES01333 = true + +# MX vs ATV Reflex +ULES01375 = true +ULUS10429 = true + +# Spongebob: The Yellow Avenger +ULES00280 = true +ULUS10092 = true + +# Also, it's a really bad idea in Kurohyou + [NearestFilteringOnFramebufferCreate] # Ridge Racer speedometer dynamic CLUT problem - they rely on some palette entries # from memory, and render to the rest of the palette. The palette entries loaded from memory From 53eedf06e37cc544b094bfbe466518afbbaa0b62 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 14:52:06 -0800 Subject: [PATCH 565/715] Vulkan: Track pipeline desc using a refcount. Not very safe to not allow deletes, and don't want to force Draw objects on the deleter (this is referenced by them.) --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 1 + Common/GPU/Vulkan/VulkanRenderManager.h | 7 +++++-- Common/GPU/Vulkan/thin3d_vulkan.cpp | 6 ++++-- GPU/Vulkan/PipelineManagerVulkan.cpp | 3 ++- GPU/Vulkan/PipelineManagerVulkan.h | 6 +++++- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 4f95a24458..56a293c70e 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -512,6 +512,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe _dbg_assert_(desc->vertexShader); _dbg_assert_(desc->fragmentShader); pipeline->desc = desc; + pipeline->desc->AddRef(); if (curRenderStep_) { // The common case pipelinesToCheck_.push_back(pipeline); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index c15d9027a2..e4845f9924 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -22,6 +22,7 @@ #include "Common/GPU/MiscTypes.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" #include "Common/GPU/Vulkan/VulkanFramebuffer.h" +#include "Common/GPU/thin3d.h" // Forward declaration VK_DEFINE_HANDLE(VmaAllocation); @@ -74,7 +75,7 @@ struct BoundingRect { }; // All the data needed to create a graphics pipeline. -struct VKRGraphicsPipelineDesc { +struct VKRGraphicsPipelineDesc : Draw::RefCountedObject { VkPipelineCache pipelineCache = VK_NULL_HANDLE; VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; VkPipelineColorBlendAttachmentState blend0{}; @@ -120,6 +121,8 @@ struct VKRGraphicsPipeline { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { delete pipeline[i]; } + if (desc) + desc->Release(); } bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount); @@ -133,7 +136,7 @@ struct VKRGraphicsPipeline { void LogCreationFailure() const; - VKRGraphicsPipelineDesc *desc = nullptr; // not owned! + VKRGraphicsPipelineDesc *desc = nullptr; Promise *pipeline[(size_t)RenderPassType::TYPE_COUNT]{}; VkSampleCountFlagBits SampleCount() const { return sampleCount_; } diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 8381256640..1edf619f3d 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -264,6 +264,7 @@ public: VKPipeline(VulkanContext *vulkan, size_t size, PipelineFlags _flags, const char *tag) : vulkan_(vulkan), flags(_flags), tag_(tag) { uboSize_ = (int)size; ubo_ = new uint8_t[uboSize_]; + vkrDesc = new VKRGraphicsPipelineDesc(); } ~VKPipeline() { DEBUG_LOG(G3D, "Queueing %s (pipeline) for release", tag_.c_str()); @@ -274,6 +275,7 @@ public: dep->Release(); } delete[] ubo_; + vkrDesc->Release(); } void SetDynamicUniformData(const void *data, size_t size) { @@ -291,7 +293,7 @@ public: } VKRGraphicsPipeline *pipeline = nullptr; - VKRGraphicsPipelineDesc vkrDesc; + VKRGraphicsPipelineDesc *vkrDesc = nullptr; PipelineFlags flags; std::vector deps; @@ -1163,7 +1165,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char VKPipeline *pipeline = new VKPipeline(vulkan_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float), pipelineFlags, tag); - VKRGraphicsPipelineDesc &gDesc = pipeline->vkrDesc; + VKRGraphicsPipelineDesc &gDesc = *pipeline->vkrDesc; std::vector stages; stages.resize(desc.shaders.size()); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 0c081c3f78..f5ba269229 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -181,7 +181,8 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) { VulkanPipeline *vulkanPipeline = new VulkanPipeline(); - VKRGraphicsPipelineDesc *desc = &vulkanPipeline->desc; + vulkanPipeline->desc = new VKRGraphicsPipelineDesc(); + VKRGraphicsPipelineDesc *desc = vulkanPipeline->desc; desc->pipelineCache = pipelineCache; PROFILE_THIS_SCOPE("pipelinebuild"); diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index dcd13c54c5..5b5400ff1b 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -54,8 +54,12 @@ struct VulkanPipelineKey { // Simply wraps a Vulkan pipeline, providing some metadata. struct VulkanPipeline { + ~VulkanPipeline() { + desc->Release(); + } + VKRGraphicsPipeline *pipeline; - VKRGraphicsPipelineDesc desc; + VKRGraphicsPipelineDesc *desc; PipelineFlags pipelineFlags; // PipelineFlags enum above. bool UsesBlendConstant() const { return (pipelineFlags & PipelineFlags::USES_BLEND_CONSTANT) != 0; } From 78ed8d45a7cd96ac0af8a9fdda5f6185730a5ae3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 14:53:10 -0800 Subject: [PATCH 566/715] Vulkan: Defer deletion of shader module promises. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 5 ++++- GPU/Vulkan/ShaderManagerVulkan.cpp | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 1edf619f3d..08aed9a332 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -203,7 +203,10 @@ public: DEBUG_LOG(G3D, "Queueing %s (shmodule %p) for release", tag_.c_str(), module_); VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } Promise *Get() const { return module_; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index e895e21af6..89e3744f4a 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -120,7 +120,10 @@ VulkanFragmentShader::~VulkanFragmentShader() { if (module_) { VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } @@ -150,7 +153,10 @@ VulkanVertexShader::~VulkanVertexShader() { if (module_) { VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } @@ -180,7 +186,10 @@ VulkanGeometryShader::~VulkanGeometryShader() { if (module_) { VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } From 3f620dba58da1e07d9da445e52e7ada956530c77 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Dec 2022 14:56:58 -0800 Subject: [PATCH 567/715] Vulkan: Reduce some logging when things are fast. On startup especially this spams sometimes. --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 56a293c70e..fab538a0a4 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -101,8 +101,12 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR double start = time_now_d(); VkPipeline vkpipeline; VkResult result = vkCreateGraphicsPipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &pipe, nullptr, &vkpipeline); + double taken_ms = (time_now_d() - start) * 1000.0; - INFO_LOG(G3D, "Pipeline creation time: %0.2f ms", (time_now_d() - start) * 1000.0); + if (taken_ms < 0.1) + DEBUG_LOG(G3D, "Pipeline creation time: %0.2f ms (fast)", taken_ms); + else + INFO_LOG(G3D, "Pipeline creation time: %0.2f ms", taken_ms); bool success = true; if (result == VK_INCOMPLETE) { From 5381086996899333a3328c11486f867e6ecc32a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 23:57:06 +0100 Subject: [PATCH 568/715] Don't ignore insets for UI on the display layout screen (no longer needed) --- UI/DisplayLayoutScreen.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index c7286acf62..34a4d3d3f4 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -117,9 +117,6 @@ private: }; DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) { - // Ignore insets - just couldn't get the logic to work. - ignoreInsets_ = true; - // Show background at full brightness darkenGameBackground_ = false; } From 8e50eb31fbca9ea64d130310fbee0451ee160c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 4 Dec 2022 00:06:28 +0100 Subject: [PATCH 569/715] Add missing IDs --- assets/compat.ini | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/assets/compat.ini b/assets/compat.ini index d228419771..9315b3db70 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1259,7 +1259,18 @@ ULUS10429 = true ULES00280 = true ULUS10092 = true -# Also, it's a really bad idea in Kurohyou +# Also, it's a really bad idea in Kurohyou. + +# Kurohyou: Ryu ga Gotoku Shinshou +ULJM05713 = true +NPJH50333 = true +ULAS42244 = true +UCKS45159 = true +ULJM08047 = true + +# Kurohyou 2: Ryu ga Gotoku Ashura Hen (Japan) +NPJH50562 = true +NPJH50333 = true [NearestFilteringOnFramebufferCreate] # Ridge Racer speedometer dynamic CLUT problem - they rely on some palette entries From a8939f456a7d425f35d0b7c3c6181192e26b7384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 4 Dec 2022 00:48:32 +0100 Subject: [PATCH 570/715] Remove dead code, validation fix in GE debugger See #16490 --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 1 + GPU/Common/TextureCacheCommon.cpp | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 7b260c72e7..d28871e8c7 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -2080,6 +2080,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe VKRImage srcImage{}; srcImage.image = step.readback_image.image; srcImage.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcImage.numLayers = 1; SetupTransitionToTransferSrc(srcImage, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); recordBarrier_.Flush(cmd); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 9aa9e25c52..9d0b46db2e 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1017,12 +1017,9 @@ bool TextureCacheCommon::MatchFramebuffer( } // Note the check for texHeight - we really don't care about a stride mismatch if texHeight == 1. + // This also takes care of the 4x1 texture check we used to have here for Burnout Dominator. if (fb_stride_in_bytes != tex_stride_in_bytes && texHeight > 1) { - // Probably irrelevant. Although, as we shall see soon, there are exceptions. - // Burnout Dominator lens flare trick special case. - if (fb_format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT8 && texWidth == 4 && texHeight == 1) { - return true; - } + // Probably irrelevant. return false; } From 4378de6aa08176b264a238206a729a378644fb6b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 07:29:21 -0800 Subject: [PATCH 571/715] Build: Use Windows 2019 for UWP builds. --- .github/workflows/build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a21c78623..48937e2874 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,8 +69,7 @@ jobs: path: ppsspp/ build-uwp: - if: ${{false}} # Temporarily disable - runs-on: windows-latest + runs-on: windows-2019 steps: - uses: actions/checkout@v3 with: From 9e019a3a1a7a155f2dc99116b9ebe093c8d38d77 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 07:53:15 -0800 Subject: [PATCH 572/715] Build: Silence SFMT warning. --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07e462e59d..bda50b1f2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1369,7 +1369,8 @@ add_library(sfmt19937 STATIC ext/sfmt19937/SFMT-params.h ext/sfmt19937/SFMT-params19937.h ) -include_directories(ext/sfmt19937) +target_compile_definitions(sfmt19937 PRIVATE SFMT_MEXP=19937) +target_include_directories(sfmt19937 PRIVATE ext/sfmt19937) add_library(xbrz STATIC ext/xbrz/xbrz.cpp From 0556ee67fc96284ec2a850f2c2085d5c73e689ba Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 07:57:09 -0800 Subject: [PATCH 573/715] SaveState: Fix a format type error. --- Common/Serialize/Serializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index ebe0e10d68..c9fb6457c2 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -76,7 +76,7 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) return PointerWrapSection(*this, -1, title); } if (!checkpoints_[curCheckpoint_].Matches(marker, offset)) { - WARN_LOG(SAVESTATE, "Checkpoint mismatch during write! Section %s but expected %s, offset %d but expected %d", title, marker, offset, (int)checkpoints_[curCheckpoint_].offset); + WARN_LOG(SAVESTATE, "Checkpoint mismatch during write! Section %s but expected %s, offset %d but expected %d", title, marker, (int)offset, (int)checkpoints_[curCheckpoint_].offset); if (curCheckpoint_ > 1) { WARN_LOG(SAVESTATE, "Previous checkpoint: %s (%d)", checkpoints_[curCheckpoint_ - 1].title, (int)checkpoints_[curCheckpoint_ - 1].offset); } From e49668eea72eadb604ec3ed60ff2637cf7f43d6c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 07:57:30 -0800 Subject: [PATCH 574/715] SaveState: Correct missing switch case warnings. --- Common/Serialize/SerializeSet.h | 5 ++--- Common/Serialize/Serializer.cpp | 3 +++ Core/MemMap.cpp | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Common/Serialize/SerializeSet.h b/Common/Serialize/SerializeSet.h index 7e22f21e56..642b0dc6bb 100644 --- a/Common/Serialize/SerializeSet.h +++ b/Common/Serialize/SerializeSet.h @@ -46,9 +46,8 @@ void DoSet(PointerWrap &p, std::set &x) { Do(p, *itr++); } break; - - default: - ERROR_LOG(SAVESTATE, "Savestate error: invalid mode %d.", p.mode); + case PointerWrap::MODE_NOOP: + break; } } diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index c9fb6457c2..71f5168c3b 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -171,6 +171,7 @@ void Do(PointerWrap &p, std::string &x) { case PointerWrap::MODE_READ: x = (char*)*p.ptr; break; case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_NOOP: break; case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(!strcmp(x.c_str(), (char*)*p.ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char *)*p.ptr, p.ptr); break; } (*p.ptr) += stringLen; @@ -198,6 +199,7 @@ void Do(PointerWrap &p, std::wstring &x) { case PointerWrap::MODE_READ: x = read(); break; case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_NOOP: break; case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(x == read(), "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), read().c_str(), p.ptr); break; } (*p.ptr) += stringLen; @@ -225,6 +227,7 @@ void Do(PointerWrap &p, std::u16string &x) { case PointerWrap::MODE_READ: x = read(); break; case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_NOOP: break; case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(x == read(), "Savestate verification failure: (at %p).\n", p.ptr); break; } (*p.ptr) += stringLen; diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 52ef9ff5f9..50a2d564fa 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -335,6 +335,8 @@ static void DoMemoryVoid(PointerWrap &p, uint32_t start, uint32_t size) { _dbg_assert_msg_(d[i] == storage[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", d[i], d[i], &d[i], storage[i], storage[i], &storage[i]); }, 0, size, 128); break; + case PointerWrap::MODE_NOOP: + break; } storage += size; } From 8c378c4557ee187e53b1d9136b8f023b22a23397 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 07:57:45 -0800 Subject: [PATCH 575/715] GPU: Avoid an override warning. --- GPU/GPUCommon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 4b47c65570..c15afe508f 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -265,7 +265,7 @@ protected: void DeviceLost() override; void DeviceRestore() override; - void ClearCacheNextFrame(); + void ClearCacheNextFrame() override; virtual void CheckRenderResized(); From e09a1a32a3464cdfaeee3b27325bbf98bb0dfd0b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 08:07:53 -0800 Subject: [PATCH 576/715] Build: Reduce include spam in CMake. This makes it more like other platforms, which don't globally include these directories. --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bda50b1f2c..6f087427d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -884,7 +884,7 @@ add_library(cityhash STATIC ext/cityhash/city.h ext/cityhash/citycrc.h ) -include_directories(ext/cityhash) +target_include_directories(cityhash PRIVATE ext/cityhash) if(NOT MSVC) # These can be fast even for debug. @@ -1360,7 +1360,7 @@ add_library(kirk STATIC ext/libkirk/kirk_engine.c ext/libkirk/kirk_engine.h ) -include_directories(ext/libkirk) +target_include_directories(kirk PRIVATE ext/libkirk) add_library(sfmt19937 STATIC ext/sfmt19937/SFMT.c @@ -1376,13 +1376,13 @@ add_library(xbrz STATIC ext/xbrz/xbrz.cpp ext/xbrz/xbrz.h ) -include_directories(ext/xbrz) +target_include_directories(xbrz PRIVATE ext/xbrz) add_library(xxhash STATIC ext/xxhash.c ext/xxhash.h ) -include_directories(ext/xxhash) +target_include_directories(xxhash PRIVATE ext/xxhash) set(CoreExtra) set(CoreExtraLibs) From 6c6133a3c1073e6a5b6fc5716e2c7acb119fd16b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 08:08:20 -0800 Subject: [PATCH 577/715] Build: Get rid of legacy zstd support. This refers to old versions of zstd we never used, and the code also generates warnings when it's built. --- CMakeLists.txt | 1 + ext/libzstd.vcxproj | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f087427d0..4a9173ed37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2068,6 +2068,7 @@ if(USE_SYSTEM_ZSTD) target_link_libraries(${CoreLibName} ${ZSTD_LIBRARY}) else() set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "we don't need zstd programs" FORCE) + set(ZSTD_LEGACY_SUPPORT OFF CACHE BOOL "we don't use any old zstd files" FORCE) add_subdirectory(ext/zstd/build/cmake EXCLUDE_FROM_ALL) set(CoreExtraLibs ${CoreExtraLibs} libzstd_static) include_directories(ext/zstd/lib) diff --git a/ext/libzstd.vcxproj b/ext/libzstd.vcxproj index 7cd642f51c..68dadeded9 100644 --- a/ext/libzstd.vcxproj +++ b/ext/libzstd.vcxproj @@ -231,7 +231,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -250,7 +250,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug true @@ -267,7 +267,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug true @@ -284,7 +284,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug true @@ -304,7 +304,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false MultiThreaded true @@ -330,7 +330,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded @@ -356,7 +356,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded @@ -382,7 +382,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded From 3342d5ecb3032b1bd5b604a74810ad746a09a763 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 08:17:05 -0800 Subject: [PATCH 578/715] softgpu: Remove an unused case. --- GPU/Software/TransformUnit.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 53d2cb12c1..b7c9401219 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -569,10 +569,9 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G // Some games send rectangles as a series of regular triangles. // We look for this, but only in throughmode. ClipVertexData buf[6]; - int buf_index = data_index_; - for (int i = 0; i < data_index_; ++i) { - buf[i] = data_[i]; - } + // Could start at data_index_ and copy to buf, but there's little reason. + int buf_index = 0; + _assert_(data_index_ == 0); for (int vtx = 0; vtx < vertex_count; ++vtx) { buf[buf_index++] = vreader.Read(vtx); From 38c4774f4a28b9b1d66804edea04a676a2141661 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 4 Dec 2022 18:14:05 +0100 Subject: [PATCH 579/715] Change package of the Android VR builds --- android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 3ee429208b..94dfd3bf80 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -151,7 +151,7 @@ android { } } vr_pico { - applicationId 'org.ppsspp.ppsspp' + applicationId 'org.ppsspp.ppssppvr' dimension "variant" externalNativeBuild { cmake { @@ -171,7 +171,7 @@ android { } } vr_quest { - applicationId 'org.ppsspp.ppsspp' + applicationId 'org.ppsspp.ppssppvr' dimension "variant" externalNativeBuild { cmake { From 2c90dafe644f62fc829f44af15a5a3f44b0dc490 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 16:30:12 -0800 Subject: [PATCH 580/715] softgpu: Force alpha test off in more scenarios. Since we're already checking the CLUT, we can tell if it doesn't contain zero alpha, in which case a != 0 test will never fail. This is actually pretty common, even when texture alpha is not always FF. --- GPU/Software/Rasterizer.cpp | 25 ++++++++++++++++++++----- GPU/Software/Rasterizer.h | 1 + 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 7059d52973..6e347dabcf 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -224,24 +224,34 @@ static bool CheckClutAlphaFull(RasterizerState *state) { if (samplerID.hasClutMask) count = std::min(count, ((samplerID.cached.clutFormat >> 8) & 0xFF) + 1); + u32 alphaSum = 0xFFFFFFFF; + if (samplerID.ClutFmt() == GE_CMODE_32BIT_ABGR8888) { + CheckMask32((const uint32_t *)samplerID.cached.clut, count, &alphaSum); + } else { + CheckMask16((const uint16_t *)samplerID.cached.clut, count, &alphaSum); + } + bool onlyFull = true; switch (samplerID.ClutFmt()) { case GE_CMODE_16BIT_BGR5650: break; case GE_CMODE_16BIT_ABGR5551: - onlyFull = CheckAlpha16((const uint16_t *)samplerID.cached.clut, count, 0x8000) == CHECKALPHA_FULL; + onlyFull = (alphaSum & 0x8000) != 0; break; case GE_CMODE_16BIT_ABGR4444: - onlyFull = CheckAlpha16((const uint16_t *)samplerID.cached.clut, count, 0xF000) == CHECKALPHA_FULL; + onlyFull = (alphaSum & 0xF000) == 0xF000; break; case GE_CMODE_32BIT_ABGR8888: - onlyFull = CheckAlpha32((const uint32_t *)samplerID.cached.clut, count, 0xFF000000) == CHECKALPHA_FULL; + onlyFull = (alphaSum & 0xFF000000) == 0xFF000000; break; } + // Might just be different patterns, but if alphaSum != 0, it can't contain zero. + if (alphaSum != 0) + state->flags |= RasterizerStateFlags::CLUT_ALPHA_NON_ZERO; if (!onlyFull) state->flags |= RasterizerStateFlags::CLUT_ALPHA_NON_FULL; state->flags |= RasterizerStateFlags::CLUT_ALPHA_CHECKED; @@ -321,8 +331,13 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { alphaTestFunc = GE_COMP_GREATER; bool alphaTest = (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) && pixelID.alphaTestRef < 0xFF && !state->pixelID.hasAlphaTestMask; - if (alphaTest && CheckClutAlphaFull(state)) - optimize |= alphaTestFunc == GE_COMP_NOTEQUAL ? RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE : RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT; + if (alphaTest) { + bool canSkipAlphaTest = CheckClutAlphaFull(state); + if ((state->flags & RasterizerStateFlags::CLUT_ALPHA_NON_ZERO) && pixelID.alphaTestRef == 0) + canSkipAlphaTest = true; + if (canSkipAlphaTest) + optimize |= alphaTestFunc == GE_COMP_NOTEQUAL ? RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE : RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT; + } } } diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index d4386c4ba3..7b63c09f91 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -42,6 +42,7 @@ enum class RasterizerStateFlags { CLUT_ALPHA_CHECKED = 0x0010, CLUT_ALPHA_NON_FULL = 0x0020, + CLUT_ALPHA_NON_ZERO = 0x0040, VERTEX_FLAT_RESET = VERTEX_NON_FULL_WHITE | VERTEX_ALPHA_NON_FULL | VERTEX_ALPHA_NON_ZERO | VERTEX_HAS_FOG, From d6750993d731c761cb61145f7e88464200250fa0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 16:36:45 -0800 Subject: [PATCH 581/715] softgpu: Force alpha test when it could skip blend. Blending is slow, and often games do effects like smoke, sun, etc. that has a lot of zero alpha in them. Many games do this with alpha testing off, which is cheap compared to blending. --- GPU/Software/Rasterizer.cpp | 40 +++++++++++++++++++++++++++++++++++++ GPU/Software/Rasterizer.h | 3 ++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 6e347dabcf..d608518869 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -300,6 +300,37 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { } } + if (alphaBlend && (needTextureAlpha || !alphaFull)) { + // Okay, we're blending, and we need to. Are we alpha testing? + GEComparison alphaTestFunc = pixelID.AlphaTestFunc(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE) + alphaTestFunc = GE_COMP_NOTEQUAL; + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) + alphaTestFunc = GE_COMP_GREATER; + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) + alphaTestFunc = GE_COMP_ALWAYS; + + PixelBlendFactor src = pixelID.AlphaBlendSrc(); + PixelBlendFactor dst = pixelID.AlphaBlendDst(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + src = PixelBlendFactor::SRCALPHA; + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + dst = PixelBlendFactor::INVSRCALPHA; + + if (alphaTestFunc == GE_COMP_ALWAYS && src == PixelBlendFactor::SRCALPHA && dst == PixelBlendFactor::INVSRCALPHA) { + bool usesClut = (samplerID.texfmt & 4) != 0; + bool couldHaveZeroTexAlpha = true; + if (usesClut && CheckClutAlphaFull(state)) + couldHaveZeroTexAlpha = false; + if (state->flags & RasterizerStateFlags::CLUT_ALPHA_NON_ZERO) + couldHaveZeroTexAlpha = false; + + // Blending is expensive, since we read the target. Force alpha testing on. + if (!pixelID.depthWrite && !pixelID.stencilTest && couldHaveZeroTexAlpha) + optimize |= RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON; + } + } + bool applyFog = pixelID.applyFog || (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF); if (applyFog) { bool hasFog = state->flags & RasterizerStateFlags::VERTEX_HAS_FOG; @@ -329,6 +360,8 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { // > 16, 8, or similar are also very common. if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) alphaTestFunc = GE_COMP_GREATER; + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) + alphaTestFunc = GE_COMP_ALWAYS; bool alphaTest = (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) && pixelID.alphaTestRef < 0xFF && !state->pixelID.hasAlphaTestMask; if (alphaTest) { @@ -374,6 +407,13 @@ static bool ApplyStateOptimizations(RasterizerState *state, const RasterizerStat pixelID.alphaTestFunc = GE_COMP_NOTEQUAL; else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) pixelID.alphaTestFunc = GE_COMP_GREATER; + else if (optimize & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) { + pixelID.alphaTestFunc = GE_COMP_NOTEQUAL; + pixelID.alphaTestRef = 0; + pixelID.hasAlphaTestMask = false; + } else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) { + pixelID.alphaTestFunc = GE_COMP_ALWAYS; + } SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID, nullptr); // Can't compile during runtime. This failing is a bit of a problem when undoing... diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 7b63c09f91..aad5b648ef 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -54,9 +54,10 @@ enum class RasterizerStateFlags { OPTIMIZED_FOG_OFF = 0x0020'0000, OPTIMIZED_ALPHATEST_OFF_NE = 0x0040'0000, OPTIMIZED_ALPHATEST_OFF_GT = 0x0080'0000, + OPTIMIZED_ALPHATEST_ON = 0x0100'0000, // Anything that changes the actual pixel or sampler func. - OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT, + OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | OPTIMIZED_ALPHATEST_OFF_NE | OPTIMIZED_ALPHATEST_OFF_GT | OPTIMIZED_ALPHATEST_ON, OPTIMIZED_SAMPLERID = OPTIMIZED_TEXREPLACE, INVALID = 0x7FFFFFFF, From 07c276c32d2b8b300147ab8779771286813cac26 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 17:17:58 -0800 Subject: [PATCH 582/715] softgpu: Fix double rectangle drawing at halfpixel. There seems to be some odd behavior with the X start pos, but at least the end pos should not be drawn twice when using 0.5 - 0.5. --- GPU/Software/Rasterizer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 7059d52973..052ccbfd1f 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1116,7 +1116,7 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & std::string ztag = StringFromFormat("DisplayListRZ_%08x", state.listPC); #endif - for (int64_t curY = minY; curY <= maxY; curY += SCREEN_SCALE_FACTOR * 2, rowST += sty) { + for (int64_t curY = minY; curY < maxY; curY += SCREEN_SCALE_FACTOR * 2, rowST += sty) { DrawingCoords p = TransformUnit::ScreenToDrawing(minX, curY); int scissorY2 = curY + SCREEN_SCALE_FACTOR > maxY ? -1 : 0; @@ -1124,7 +1124,7 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & Vec4 scissor_step = Vec4(0, -(SCREEN_SCALE_FACTOR * 2), 0, -(SCREEN_SCALE_FACTOR * 2)); Vec2f st = rowST; - for (int64_t curX = minX; curX <= maxX; curX += SCREEN_SCALE_FACTOR * 2, + for (int64_t curX = minX; curX < maxX; curX += SCREEN_SCALE_FACTOR * 2, st += stx, scissor_mask += scissor_step, p.x = (p.x + 2) & 0x3FF) { @@ -1292,7 +1292,8 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const BinCoords minY += SCREEN_SCALE_FACTOR; const DrawingCoords pprime = TransformUnit::ScreenToDrawing(minX, minY); - const DrawingCoords pend = TransformUnit::ScreenToDrawing(maxX, maxY); + // Only include the end pixel when it's >= 0.5. + const DrawingCoords pend = TransformUnit::ScreenToDrawing(maxX - SCREEN_SCALE_FACTOR / 2, maxY - SCREEN_SCALE_FACTOR / 2); auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; From 77e510bd907dcf83b8b403e1ee8e689837f4c72d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Dec 2022 19:27:23 -0800 Subject: [PATCH 583/715] GPU: Use accurate depth for depth range hack. This should be easier to ensure stays well tested. --- GPU/GLES/GPU_GLES.cpp | 5 ----- GPU/GLES/ShaderManagerGLES.cpp | 32 -------------------------------- GPU/GPUCommon.cpp | 5 +++++ GPU/GPUState.cpp | 6 +++--- GPU/GPUState.h | 2 +- 5 files changed, 9 insertions(+), 41 deletions(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index a707915eb1..380fe2d2c7 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -173,11 +173,6 @@ u32 GPU_GLES::CheckGPUFeatures() const { if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float) features |= GPU_USE_TEXTURE_FLOAT; - // The Phantasy Star hack :( - if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_USE_ACCURATE_DEPTH) == 0) { - features |= GPU_USE_DEPTH_RANGE_HACK; - } - if (!draw_->GetShaderLanguageDesc().bitwiseOps) { features |= GPU_USE_FRAGMENT_TEST_CACHE; } diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 7e4ae0f881..cc5211a19f 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -319,38 +319,6 @@ static inline void FlipProjMatrix(Matrix4x4 &in, bool useBufferedRendering) { in[8] = -in[8]; in[12] = -in[12]; } - - // In Phantasy Star Portable 2, depth range sometimes goes negative and is clamped by glDepthRange to 0, - // causing graphics clipping glitch (issue #1788). This hack modifies the projection matrix to work around it. - if (gstate_c.Use(GPU_USE_DEPTH_RANGE_HACK)) { - float zScale = gstate.getViewportZScale() / 65535.0f; - float zCenter = gstate.getViewportZCenter() / 65535.0f; - - // if far depth range < 0 - if (zCenter + zScale < 0.0f) { - // if perspective projection - if (in[11] < 0.0f) { - float depthMax = gstate.getDepthRangeMax() / 65535.0f; - float depthMin = gstate.getDepthRangeMin() / 65535.0f; - - float a = in[10]; - float b = in[14]; - - float n = b / (a - 1.0f); - float f = b / (a + 1.0f); - - f = (n * f) / (n + ((zCenter + zScale) * (n - f) / (depthMax - depthMin))); - - a = (n + f) / (n - f); - b = (2.0f * n * f) / (n - f); - - if (!my_isnan(a) && !my_isnan(b)) { - in[10] = a; - in[14] = b; - } - } - } - } } static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 20d97649df..bbfa7f3090 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3537,6 +3537,11 @@ u32 GPUCommon::CheckGPUFeatures() const { features |= GPU_USE_CLEAR_RAM_HACK; } + // Even without depth clamp, force accurate depth on for some games that break without it. + if (PSP_CoreParameter().compat.flags().DepthRangeHack) { + features |= GPU_USE_ACCURATE_DEPTH; + } + return features; } diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index 95568e1e93..ba0e650bb6 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -375,7 +375,7 @@ static const char *const gpuUseFlagNames[32] = { "GPU_USE_VS_RANGE_CULLING", "GPU_USE_BLEND_MINMAX", "GPU_USE_LOGIC_OP", - "GPU_USE_DEPTH_RANGE_HACK", + "N/A", "GPU_USE_TEXTURE_NPOT", "GPU_USE_ANISOTROPY", "GPU_USE_CLEAR_RAM_HACK", @@ -388,7 +388,7 @@ static const char *const gpuUseFlagNames[32] = { "GPU_USE_DEPTH_TEXTURE", "GPU_USE_ACCURATE_DEPTH", "GPU_USE_GS_CULLING", - "GPU_USE_REVERSE_COLOR_ORDER", + "N/A", "GPU_USE_FRAMEBUFFER_FETCH", "GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT", "GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT", @@ -409,4 +409,4 @@ const char *GpuUseFlagToString(int useFlag) { } else { return "N/A"; } -} \ No newline at end of file +} diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 02fba9c309..e5acb39a18 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -478,7 +478,7 @@ enum { GPU_USE_VS_RANGE_CULLING = FLAG_BIT(3), GPU_USE_BLEND_MINMAX = FLAG_BIT(4), GPU_USE_LOGIC_OP = FLAG_BIT(5), - GPU_USE_DEPTH_RANGE_HACK = FLAG_BIT(6), + // Bit 6 is free. GPU_USE_TEXTURE_NPOT = FLAG_BIT(7), GPU_USE_ANISOTROPY = FLAG_BIT(8), GPU_USE_CLEAR_RAM_HACK = FLAG_BIT(9), From 70f18f56218ed51644256f97cb4fc71f2bd6d527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Nov 2022 22:59:43 +0100 Subject: [PATCH 584/715] Turn language popup thing into a lambda --- UI/GameSettingsScreen.cpp | 34 ++++++++++++++-------------------- UI/GameSettingsScreen.h | 4 ---- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index d64a42d5d0..1219c43236 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -846,7 +846,20 @@ void GameSettingsScreen::CreateViews() { LinearLayout *systemSettings = AddTab("GameSettingsSystem", ms->T("System")); systemSettings->Add(new ItemHeader(sy->T("UI"))); - systemSettings->Add(new Choice(sy->T("Language")))->OnClick.Handle(this, &GameSettingsScreen::OnLanguage); + systemSettings->Add(new Choice(sy->T("Language")))->OnClick.Add([&](UI::EventParams &e) { + auto sy = GetI18NCategory("System"); + auto langScreen = new NewLanguageScreen(sy->T("Language")); + langScreen->OnChoice.Add([&](UI::EventParams &e) { + screenManager()->RecreateAllViews(); + if (host) + host->UpdateUI(); + return UI::EVENT_DONE; + }); + if (e.v) + langScreen->SetPopupOrigin(e.v); + screenManager()->push(langScreen); + return UI::EVENT_DONE; + }); systemSettings->Add(new CheckBox(&g_Config.bUISound, sy->T("UI Sound"))); const Path bgPng = GetSysDirectory(DIRECTORY_SYSTEM) / "background.png"; const Path bgJpg = GetSysDirectory(DIRECTORY_SYSTEM) / "background.jpg"; @@ -1609,25 +1622,6 @@ UI::EventReturn GameSettingsScreen::OnChangeMacAddress(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnLanguage(UI::EventParams &e) { - auto sy = GetI18NCategory("System"); - auto langScreen = new NewLanguageScreen(sy->T("Language")); - langScreen->OnChoice.Handle(this, &GameSettingsScreen::OnLanguageChange); - if (e.v) - langScreen->SetPopupOrigin(e.v); - screenManager()->push(langScreen); - return UI::EVENT_DONE; -} - -UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) { - screenManager()->RecreateAllViews(); - - if (host) { - host->UpdateUI(); - } - return UI::EVENT_DONE; -} - UI::EventReturn GameSettingsScreen::OnTextureShader(UI::EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto shaderScreen = new TextureShaderScreen(gr->T("Texture Shader")); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index a3fcd0ddc3..5b51ee101d 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -80,15 +80,11 @@ private: UI::EventReturn OnControlMapping(UI::EventParams &e); UI::EventReturn OnCalibrateAnalogs(UI::EventParams &e); UI::EventReturn OnTouchControlLayout(UI::EventParams &e); - UI::EventReturn OnDumpNextFrameToLog(UI::EventParams &e); UI::EventReturn OnTiltTypeChange(UI::EventParams &e); UI::EventReturn OnTiltCustomize(UI::EventParams &e); // Global settings handlers - UI::EventReturn OnLanguage(UI::EventParams &e); - UI::EventReturn OnLanguageChange(UI::EventParams &e); UI::EventReturn OnAutoFrameskip(UI::EventParams &e); - UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); UI::EventReturn OnTextureShader(UI::EventParams &e); UI::EventReturn OnTextureShaderChange(UI::EventParams &e); UI::EventReturn OnDeveloperTools(UI::EventParams &e); From 4233e8deceadd70b2805b9dd7100c2fed9a3e54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Nov 2022 23:00:17 +0100 Subject: [PATCH 585/715] Swedish translation improvements --- assets/lang/sv_SE.ini | 90 +++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 8b0532f46e..6d085d23d8 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -1,7 +1,7 @@ [Audio] Alternate speed volume = Volym vid alternativ hastighet Audio backend = Uppspelningsteknik (ändring kräver omstart!) -Audio Error = Audio Error +Audio Error = Ljudfel AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Enhet @@ -31,12 +31,12 @@ Auto-rotation speed = Auto-rotation speed Auto-switch = Auto-switch Base tilt position = Base tilt position Binds = Binds -Button Binding = Button Binding +Button Binding = Knapp-bindning Button Opacity = Knappgenomskinlighet Button style = Knappstil Calibrate Analog Stick = Kalibrera analog styrspak Calibrate D-Pad = Kalibrera D-pad -Calibrated = Calibrated +Calibrated = Kalibrerad Calibration = Kalibrering Circular stick input = Circular stick input Classic = Klassisk @@ -49,13 +49,13 @@ Customize tilt = Anpassa tilt... D-PAD = D-Pad Deadzone radius = Deadzone-radie Disable D-Pad diagonals (4-way touch) = Slå av D-Pad-diagonaler (4-vägs touch) -Disable diagonal input = Disable diagonal input +Disable diagonal input = Blockera diagonal input Double tap = Double tap -Enable gesture control = Enable gesture control +Enable gesture control = Get-kontroll Enable standard shortcut keys = Enable standard shortcut keys Gesture = Gesture -Gesture mapping = Gesture mapping -Glowing borders = Glowing borders +Gesture mapping = Gest-mappning +Glowing borders = Lysande kanter HapticFeedback = Haptic feedback (vibration) Hide touch analog stick background circle = Hide touch analog stick background circle Icon = Icon @@ -83,7 +83,7 @@ Portrait Reversed = Porträtt omvänt PSP Action Buttons = PSP action-knappar Raw input = Raw input Repeat mode = Repeat mode -Reset to defaults = Reset to defaults +Reset to defaults = Återställ till standardvärden Screen aligned to ground = Screen aligned to ground Screen at right angle to ground = Screen at right angle to ground Screen Rotation = Skärmrotation @@ -93,8 +93,8 @@ Sensitivity = Känslighet Shape = Shape Show Touch Pause Menu Button = Show Touch Pause Menu Button Swipe = Swipe -Swipe sensitivity = Swipe sensitivity -Swipe smoothing = Swipe smoothing +Swipe sensitivity = Swipe-känslighet +Swipe smoothing = Swipe-utjämning Thin borders = Tunna kanter Tilt Base Radius = Tilt base radius Tilt Input Type = Lutningstyp @@ -139,7 +139,7 @@ Disassembly = Disassemblera Discord = Discord Display Layout && Effects = Skärmlayout && effekter... Display Rotation = Skärmrotation -Dump Next Frame to Log = Dump Next Frame to Log +Dump Next Frame to Log = Dumpa nästa frame till loggen Emulation = Emulering Enable Cheats = Fusk Enable Sound = Ljud @@ -147,7 +147,7 @@ Exit = Avsluta Extract File... = Extrahera fil... File = Arkiv Frame Skipping = Frameskipping -Frame Skipping Type = Frame skipping type +Frame Skipping Type = Typ av frame-skippning Fullscreen = Fullskärm Game Settings = Inställningar GE Debugger... = GE Debugger... @@ -172,9 +172,9 @@ Log Console = Loggkonsol Memory View... = Minnesvy... More Settings... = Mer inställningar... Nearest = Nearest -Skip Buffer Effects = &Skip buffer effects +Skip Buffer Effects = &Skippa buffereffekter Off = Off -Open Chat = Open Chat +Open Chat = Öppna chat Open Directory... = Öppna mapp... Open from MS:/PSP/GAME... = Öppna från MS:/PSP/GAME... Open Memory Stick = Öppna Memory Stick @@ -229,11 +229,11 @@ Create/Open textures.ini file for current game = Create/Open textures.ini file f Current = Aktuellt Dev Tools = Development tools DevMenu = DevMenu -Disabled JIT functionality = Disabled JIT functionality -Draw Frametimes Graph = Draw frametimes graph +Disabled JIT functionality = Avstängd JIT-funktionalitet +Draw Frametimes Graph = Rita upp graf över frame-tider Dump Decrypted Eboot = Dumpa decrypterad EBOOT.BIN när spelet startar Dump next frame to log = Dumpa nästa frame till log -Enable driver bug workarounds = Enable driver bug workarounds +Enable driver bug workarounds = Tillåt workarounds för drivrutins-buggar Enable Logging = Debugloggning Enter address = Address FPU = FPU @@ -269,7 +269,7 @@ Texture ini file created = Texture ini file created Texture Replacement = Ersätt texturer Toggle Audio Debug = Toggla audio debug Toggle Freeze = Toggla freeze -Touchscreen Test = Touchscreen test +Touchscreen Test = Touchskärm-test VFPU = VFPU [Dialog] @@ -285,10 +285,10 @@ Choose PPSSPP save folder = Välj folder att spara i Confirm Overwrite = Vill du skriva över datan? Confirm Save = Vill du spara denna data? ConfirmLoad = Ladda denna data? -ConnectingAP = Connecting to the access point.\nPlease wait... -ConnectingPleaseWait = Connecting.\nPlease wait... -ConnectionName = Connection name -Corrupted Data = Corrupted data +ConnectingAP = Kopplar upp till acceesspunkten.\nVänta... +ConnectingPleaseWait = Kopplar upp.\nVänta... +ConnectionName = Uppkopplingsnamn +Corrupted Data = Korrupt data Delete = Ta bort Delete all = Ta bort allt Delete completed = Borttaget. @@ -307,8 +307,8 @@ Filter = Filter Finish = Färdig GE Frame Dumps = GE Frame Dumps Grid = Grid -Inactive = Inactive -InternalError = An internal error has occurred. +Inactive = Inaktiv +InternalError = Ett internt fel har upptäckts. Load = Ladda Load completed = Laddat. Loading = Laddar\nVänta... @@ -319,7 +319,7 @@ NEW DATA = NY DATA No = Nej ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK -Old savedata detected = Old savedata detected +Old savedata detected = Gammal savedata upptäckt Options = Options Reset = Återställ Resize = Ändra storlek @@ -328,7 +328,7 @@ Save = Spara Save completed = Sparat. Saving = Sparar\nVänta... SavingFailed = Kunde inte spara data. -Search = Search +Search = Sök Select = Välj Shift = Skift Skip = Skip @@ -336,20 +336,20 @@ Snap = Snap Space = Mellanslag SSID = SSID Submit = Skicka -Supported = Supported +Supported = Stödd There is no data = Det finns ingen data. Toggle All = Vänd alla Toggle List = Toggle list -Unsupported = Unsupported +Unsupported = Stöds ej When you save, it will load on a PSP, but not an older PPSSPP = When you save, it will load on a PSP, but not an older PPSSPP When you save, it will not work on outdated PSP Firmware anymore = When you save, it will not work on outdated PSP firmware anymore Yes = Ja -Zoom = Zoom +Zoom = Zooma [Error] 7z file detected (Require 7-Zip) = file is compressed (7z).\nPlease decompress first (try 7-Zip or WinRAR). -A PSP game couldn't be found on the disc. = A PSP game couldn't be found on the disc. -Cannot boot ELF located outside mountRoot. = Cannot boot ELF located outside mountRoot. +A PSP game couldn't be found on the disc. = Kunde inte hitta ett PSP-spel på skivavbildningen. +Cannot boot ELF located outside mountRoot. = Kan inte boota en ELF som ligger utanför mountRoot. Could not save screenshot file = Misslyckades spara skärmdump. D3D9or11 = Direct3D 9? (or "no" for Direct3D 11) D3D11CompilerMissing = D3DCompiler_47.dll saknas. Installera, eller tryck Ja för att försöka igen med Direct3D 9 istället. @@ -372,7 +372,7 @@ GenericOpenGLError = Failed initializing graphics. Try upgrading your graphics d GenericVulkanError = Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to OpenGL?\n\nError message: InsufficientOpenGLDriver = Otillräckligt OpenGL-stöd detekterat!\n\nYour GPU reports that it does not support OpenGL 2.0. Would you like to try using DirectX instead?\n\nDirectX is currently compatible with less games, but on your GPU it may be the only choice.\n\nVisit the forums at https://forums.ppsspp.org for more information.\n\n Just a directory. = Endast en katalog. -Missing key = Missing key +Missing key = Nyckel saknas MsgErrorCode = Error code: MsgErrorSavedataDataBroken = Save data was corrupt. MsgErrorSavedataMSFull = Memory Stick full. Check your storage space. @@ -405,7 +405,7 @@ ZIP file detected (Require WINRAR) = file is compressed (ZIP).\nPlease decompres [Game] Asia = Asia -Calculate CRC = Calculate CRC +Calculate CRC = Räkna ut CRC ConfirmDelete = Ta bort Create Game Config = Skapa spelconfig Create Shortcut = Skapa genväg @@ -490,11 +490,11 @@ Display Resolution (HW scaler) = Skärmupplösning (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate-kontroll -Frame Skipping = Frameskipping +Frame Skipping = Frame-skipping Frame Skipping Type = Frame skipping type FullScreen = Fullskärm Geometry shader culling = Geoshader-klippning -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +GPUReadbackRequired = Varning: Detta spel kräver att 'Skippa dataläsningar från GPU:n' är avstängt. Hack Settings = Hack-inställningar (kan orsaka problem) Hardware Tessellation = Hårdvarutessellering Hardware Transform = Hårdvarutransform @@ -535,7 +535,7 @@ Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Renderingsläge Rendering Resolution = Renderingsupplösning -RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games +RenderingMode NonBuffered Tip = Snabbare, men grafik kan gå sönder Rotation = Rotation Safe = Safe Screen Scaling Filter = Skärmskalningsfilter @@ -622,7 +622,7 @@ Audio = Ljud Controls = Kontroll Graphics = Grafik Networking = Nätverk -Search = Search +Search = Sök System = System Tools = Verktyg @@ -994,15 +994,15 @@ LoadStateWrongVersion = Misslyckades ladda state: Savestate is for an older vers norewind = No rewind save states available. Playing = Playing PressESC = Tryck ESC för att öppna pausemenyn. -replaceTextures_false = Textures no longer are being replaced. -replaceTextures_true = Texture replacement is enabled. +replaceTextures_false = Texturer ersätts inte längre. +replaceTextures_true = Textur-ersättning är igång. Save State Failed = Misslyckades spara state! Saved State = State sparat saveNewTextures_false = Texture saving was disabled. saveNewTextures_true = Textures will now be saved to your storage. -SpeedCustom2 = Speed: alternate 2 +SpeedCustom2 = Speed: alternativ 2 standard = Hastighet: standard -State load undone = State load undone +State load undone = State load ogjort Untitled PSP game = Untitled PSP game [Search] @@ -1096,7 +1096,7 @@ Color Saturation = Färgmättnad Color Tint = Färgförskjutning Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. -Floating symbols = Floating symbols +Floating symbols = Flytande symboler Game crashed = Game crashed Memory Stick folder = Memory Stick-mapp Memory Stick size = Memory Stick-storlek @@ -1139,7 +1139,7 @@ IO timing method = IO-timingsmetod IR Interpreter = IR interpreter Language = Språk Memory Stick Folder = Memory Stick-mapp -Memory Stick inserted = Memory Stick insatt +Memory Stick inserted = Memory Stick isatt MHz, 0:default = MHz, 0 = standard MMDDYYYY = MMDDYYYY Moving background = Rörlig bakgrund @@ -1180,7 +1180,7 @@ Sustained performance mode = Sustained performance mode Theme = Tema Time Format = Tidsformat UI = Användargränssnitt -UI background animation = UI background animation +UI background animation = Bakgrundsanimering UI Sound = Ljud i användargränssnittet undo %c = backup %c USB = USB @@ -1192,7 +1192,7 @@ Use X to confirm = Använd X för att bekräfta VersionCheck = Kolla efter nya versioner av PPSSPP WARNING: Android battery save mode is on = WARNING: Android battery save mode is On WARNING: Battery save mode is on = WARNING: Battery save mode is on -Waves = Waves +Waves = Vågor YYYYMMDD = YYYYMMDD [TextureShaders] From 93e50601379b9e68deec9c22aa45ba69dd36253e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 5 Dec 2022 11:55:23 +0100 Subject: [PATCH 586/715] Load and cache langValuesMapping on demand --- Common/Data/Format/IniFile.cpp | 29 +++++++++++++++++++++-------- Common/Data/Format/IniFile.h | 20 +++++++++++--------- Core/Config.cpp | 21 +++++++++++++-------- Core/Config.h | 5 ++++- Core/Dialog/PSPOskDialog.cpp | 2 +- UI/MiscScreens.cpp | 14 +++++++++----- UI/MiscScreens.h | 1 - 7 files changed, 59 insertions(+), 33 deletions(-) diff --git a/Common/Data/Format/IniFile.cpp b/Common/Data/Format/IniFile.cpp index cd2a658e5c..72aeee6f89 100644 --- a/Common/Data/Format/IniFile.cpp +++ b/Common/Data/Format/IniFile.cpp @@ -174,6 +174,19 @@ std::string* Section::GetLine(const char* key, std::string* valueOut, std::strin return 0; } +const std::string* Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut) const +{ + for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) + { + const std::string& line = *iter; + std::string lineKey; + ParseLine(line, &lineKey, valueOut, commentOut); + if (!strcasecmp(lineKey.c_str(), key)) + return &line; + } + return 0; +} + void Section::Set(const char* key, uint32_t newValue) { Set(key, StringFromFormat("0x%08x", newValue).c_str()); } @@ -218,7 +231,7 @@ void Section::Set(const char* key, const std::string& newValue, const std::strin Delete(key); } -bool Section::Get(const char* key, std::string* value, const char* defaultValue) +bool Section::Get(const char* key, std::string* value, const char* defaultValue) const { const std::string* line = GetLine(key, value, 0); if (!line) @@ -275,7 +288,7 @@ void Section::AddComment(const std::string &comment) { lines.emplace_back("# " + comment); } -bool Section::Get(const char* key, std::vector& values) +bool Section::Get(const char* key, std::vector& values) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -303,7 +316,7 @@ bool Section::Get(const char* key, std::vector& values) return true; } -bool Section::Get(const char* key, int* value, int defaultValue) +bool Section::Get(const char* key, int* value, int defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -313,7 +326,7 @@ bool Section::Get(const char* key, int* value, int defaultValue) return false; } -bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) +bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -323,7 +336,7 @@ bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) return false; } -bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) +bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -333,7 +346,7 @@ bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) return false; } -bool Section::Get(const char* key, bool* value, bool defaultValue) +bool Section::Get(const char* key, bool* value, bool defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -343,7 +356,7 @@ bool Section::Get(const char* key, bool* value, bool defaultValue) return false; } -bool Section::Get(const char* key, float* value, float defaultValue) +bool Section::Get(const char* key, float* value, float defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -353,7 +366,7 @@ bool Section::Get(const char* key, float* value, float defaultValue) return false; } -bool Section::Get(const char* key, double* value, double defaultValue) +bool Section::Get(const char* key, double* value, double defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); diff --git a/Common/Data/Format/IniFile.h b/Common/Data/Format/IniFile.h index 87bd1d1830..707f0ab3eb 100644 --- a/Common/Data/Format/IniFile.h +++ b/Common/Data/Format/IniFile.h @@ -25,14 +25,16 @@ public: std::map ToMap() const; - std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut); + std::string *GetLine(const char* key, std::string* valueOut, std::string* commentOut); + const std::string *GetLine(const char* key, std::string* valueOut, std::string* commentOut) const; + void Set(const char* key, const char* newValue); void Set(const char* key, const std::string& newValue, const std::string& defaultValue); void Set(const std::string &key, const std::string &value) { Set(key.c_str(), value.c_str()); } - bool Get(const char* key, std::string* value, const char* defaultValue); + bool Get(const char* key, std::string* value, const char* defaultValue) const; void Set(const char* key, uint32_t newValue); void Set(const char* key, uint64_t newValue); @@ -57,13 +59,13 @@ public: void AddComment(const std::string &comment); - bool Get(const char* key, int* value, int defaultValue = 0); - bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0); - bool Get(const char* key, uint64_t* value, uint64_t defaultValue = 0); - bool Get(const char* key, bool* value, bool defaultValue = false); - bool Get(const char* key, float* value, float defaultValue = false); - bool Get(const char* key, double* value, double defaultValue = false); - bool Get(const char* key, std::vector& values); + bool Get(const char* key, int* value, int defaultValue = 0) const; + bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0) const; + bool Get(const char* key, uint64_t* value, uint64_t defaultValue = 0) const; + bool Get(const char* key, bool* value, bool defaultValue = false) const; + bool Get(const char* key, float* value, float defaultValue = false) const; + bool Get(const char* key, double* value, double defaultValue = false) const; + bool Get(const char* key, std::vector& values) const; bool operator < (const Section& other) const { return name_ < other.name_; diff --git a/Core/Config.cpp b/Core/Config.cpp index b053500bf1..24497fc89a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1124,9 +1124,10 @@ static int DefaultSystemParamLanguage() { int defaultLang = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; if (g_Config.bFirstRun) { // TODO: Be smart about same language, different country - auto langValuesMapping = GetLangValuesMapping(); - if (langValuesMapping.find(g_Config.sLanguageIni) != langValuesMapping.end()) { - defaultLang = langValuesMapping[g_Config.sLanguageIni].second; + auto &langValuesMapping = g_Config.GetLangValuesMapping(); + auto iter = langValuesMapping.find(g_Config.sLanguageIni); + if (iter != langValuesMapping.end()) { + defaultLang = iter->second.second; } } return defaultLang; @@ -1273,14 +1274,12 @@ Config::~Config() { delete private_; } -std::map> GetLangValuesMapping() { - std::map> langValuesMapping; +void Config::LoadLangValuesMapping() { IniFile mapping; mapping.LoadFromVFS("langregion.ini"); std::vector keys; mapping.GetKeys("LangRegionNames", keys); - std::map langCodeMapping; langCodeMapping["JAPANESE"] = PSP_SYSTEMPARAM_LANGUAGE_JAPANESE; langCodeMapping["ENGLISH"] = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; @@ -1306,9 +1305,15 @@ std::map> GetLangValuesMapping() { int iLangCode = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; if (langCodeMapping.find(langCode) != langCodeMapping.end()) iLangCode = langCodeMapping[langCode]; - langValuesMapping[keys[i]] = std::make_pair(langName, iLangCode); + langValuesMapping_[keys[i]] = std::make_pair(langName, iLangCode); } - return langValuesMapping; +} + +const std::map> &Config::GetLangValuesMapping() { + if (langValuesMapping_.empty()) { + LoadLangValuesMapping(); + } + return langValuesMapping_; } void Config::Reload() { diff --git a/Core/Config.h b/Core/Config.h index 342b5c3450..64d17da3a1 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -568,21 +568,24 @@ public: bool HasRecentIsos() const; void ClearRecentIsos(); + const std::map> &GetLangValuesMapping(); + protected: void LoadStandardControllerIni(); + void LoadLangValuesMapping(); private: bool reload_ = false; std::string gameId_; std::string gameIdTitle_; std::vector recentIsos; + std::map> langValuesMapping_; Path iniFilename_; Path controllerIniFilename_; Path searchPath_; ConfigPrivate *private_ = nullptr; }; -std::map> GetLangValuesMapping(); std::string CreateRandMAC(); // TODO: Find a better place for this. diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 36574f3522..54f2ea723d 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -346,7 +346,7 @@ int PSPOskDialog::Init(u32 oskPtr) { inputChars += c; } - languageMapping = GetLangValuesMapping(); + languageMapping = g_Config.GetLangValuesMapping(); // Eat any keys pressed before the dialog inited. UpdateButtons(); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 769fb2f01f..505897dba6 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -619,7 +619,7 @@ NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen #ifdef _MSC_VER #pragma warning(disable:4566) #endif - langValuesMapping = GetLangValuesMapping(); + auto &langValuesMapping = g_Config.GetLangValuesMapping(); std::vector tempLangs; VFSGetFileListing("lang", &tempLangs, "ini"); @@ -655,11 +655,12 @@ NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen std::string buttonTitle = lang.name; if (!code.empty()) { - if (langValuesMapping.find(code) == langValuesMapping.end()) { + auto iter = langValuesMapping.find(code); + if (iter == langValuesMapping.end()) { // No title found, show locale code buttonTitle = code; } else { - buttonTitle = langValuesMapping[code].first; + buttonTitle = iter->second.first; } } if (g_Config.sLanguageIni == code) @@ -700,11 +701,14 @@ void NewLanguageScreen::OnCompleted(DialogResult result) { if (iniLoadedSuccessfully) { // Dunno what else to do here. - if (langValuesMapping.find(code) == langValuesMapping.end()) { + auto &langValuesMapping = g_Config.GetLangValuesMapping(); + + auto iter = langValuesMapping.find(code); + if (iter == langValuesMapping.end()) { // Fallback to English g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; } else { - g_Config.iLanguage = langValuesMapping[code].second; + g_Config.iLanguage = iter->second.second; } RecreateViews(); } else { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 341e3b7915..6166fdb94a 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -106,7 +106,6 @@ public: private: void OnCompleted(DialogResult result) override; bool ShowButtons() const override { return true; } - std::map> langValuesMapping; std::map titleCodeMapping; std::vector langs_; }; From dd22ec6fa7e15ff43c346f0dce7cb10c6bda7c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 5 Dec 2022 12:07:07 +0100 Subject: [PATCH 587/715] Show the name of the chosen language on the choice button. Looks weird not to. --- Core/Config.cpp | 4 ++-- UI/GameSettingsScreen.cpp | 12 +++++++++++- UI/MiscScreens.h | 1 - 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 24497fc89a..ebc731cbd2 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1294,8 +1294,8 @@ void Config::LoadLangValuesMapping() { langCodeMapping["CHINESE_TRADITIONAL"] = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL; langCodeMapping["CHINESE_SIMPLIFIED"] = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED; - Section *langRegionNames = mapping.GetOrCreateSection("LangRegionNames"); - Section *systemLanguage = mapping.GetOrCreateSection("SystemLanguage"); + const Section *langRegionNames = mapping.GetOrCreateSection("LangRegionNames"); + const Section *systemLanguage = mapping.GetOrCreateSection("SystemLanguage"); for (size_t i = 0; i < keys.size(); i++) { std::string langName; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 1219c43236..15d1987f02 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -846,7 +846,17 @@ void GameSettingsScreen::CreateViews() { LinearLayout *systemSettings = AddTab("GameSettingsSystem", ms->T("System")); systemSettings->Add(new ItemHeader(sy->T("UI"))); - systemSettings->Add(new Choice(sy->T("Language")))->OnClick.Add([&](UI::EventParams &e) { + + auto langCodeToName = [](const char *value) -> std::string { + auto &mapping = g_Config.GetLangValuesMapping(); + auto iter = mapping.find(value); + if (iter != mapping.end()) { + return iter->second.first; + } + return value; + }; + + systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.sLanguageIni, sy->T("Language"), langCodeToName))->OnClick.Add([&](UI::EventParams &e) { auto sy = GetI18NCategory("System"); auto langScreen = new NewLanguageScreen(sy->T("Language")); langScreen->OnChoice.Add([&](UI::EventParams &e) { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 6166fdb94a..f0eca81ff5 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -106,7 +106,6 @@ public: private: void OnCompleted(DialogResult result) override; bool ShowButtons() const override { return true; } - std::map titleCodeMapping; std::vector langs_; }; From f3be5717e880a3e400fa5c6451fe052ee8f84b45 Mon Sep 17 00:00:00 2001 From: Felipe Date: Mon, 5 Dec 2022 12:12:06 -0300 Subject: [PATCH 588/715] Updated brazilian portuguese --- assets/lang/pt_BR.ini | 59 +++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 0cbb4a0b42..285d76402d 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -161,7 +161,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout && Effects = Exibir o editor do esquema... +Display Layout Editor = Exibir o editor do esquema... Display Rotation = Rotação da exibição Dump Next Frame to Log = D&umpar o frame seguinte no log Emulation = &Emulação @@ -196,7 +196,7 @@ Log Console = &Console dos logs Memory View... = Visualização da &memória... More Settings... = &Mais configurações... Nearest = &Mais próximo -Skip Buffer Effects = &Ignorar efeitos do buffer (sem buffer, mais rápido) +Non-Buffered Rendering = &Ignorar efeitos do buffer (sem buffer, mais rápido) Off = &Desligado Open Chat = Abrir Bate-Papo Open Directory... = Abrir &diretório... @@ -256,7 +256,7 @@ DevMenu = Menu do DEV Disabled JIT functionality = Funcionalidade do JIT desativada Draw Frametimes Graph = Desenhar gráfico dos tempos dos frames Dump Decrypted Eboot = Dumpar EBOOT.BIN decriptado no boot do jogo -Dump next frame to log = Dumpa o próximo frame no log +Dump next frame to log = Dumpar o frame seguinte no registro Enable driver bug workarounds = Ativar soluções alternativas pros bugs dos drivers Enable Logging = Ativar log do debug Enter address = Inserir endereço @@ -265,7 +265,7 @@ Framedump tests = Testes dos dumps dos frames Frame Profiler = Analista dos frames GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU -GPU log profiler = Criador do Perfil do Registro da GPU +GPU Log Profiler = Criador do Perfil do Registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de debug do JIT Log Dropped Frame Statistics = Pôr no log as estátisticas da queda dos frames @@ -480,7 +480,7 @@ Aggressive = Agressivo Alternative Speed = Velocidade alternativa (em %, 0 = ilimitada) Alternative Speed 2 = Velocidade alternativa 2 (em %, 0 = ilimitada) Anisotropic Filtering = Filtragem anisotrópica -Aspect Ratio = Aspect Ratio +Aspect Ratio = Proporção do Aspecto Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (a mesma que a da resolução de renderização) @@ -490,6 +490,7 @@ Auto Scaling = Auto-redimensionamento Backend = Backend Balanced = Balanceado Bicubic = Bi-cúbico +GPUReadbackRequired = Aviso: Este jogo requer "Ignorar Leituras da GPU" pra ser configurado como Desligado. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos comandos dos gráficos (mais rápido, atraso na entrada dos dados) BufferedRenderingRequired = Aviso: Este jogo requer que o "modo de renderização" esteja definido "com buffer". @@ -500,7 +501,7 @@ Cardboard Screen X Shift = Deslocamento do X (em % do espaço vazio) Cardboard Screen Y Shift = Deslocamento do Y (em % do espaço vazio) Cardboard VR Settings = Configurações do Google VR Cardboard Cheats = Trapaças -CPU Core = Core da CPU +CPU Core = Núcleo da CPU Debugging = Debugging DefaultCPUClockRequired = Aviso: Este jogo requer que o clock da CPU esteja definido como padrão. Deposterize = Deposterizar @@ -509,7 +510,7 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desativado -Display Layout && Effects = Exibe o editor dos esquemas +Display layout editor = Exibe o editor dos esquemas Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) Enable Cardboard VR = Ativa o VR Cardboard FPS = FPS @@ -517,9 +518,8 @@ Frame Rate Control = Controle da taxa dos frames Frame Skipping = Pulo dos frames Frame Skipping Type = Tipo de pulo dos frames FullScreen = Tela cheia -Geometry shader culling = Geometry shader culling -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. -Hack Settings = Configurações dos hacks (pode causar erros gráficos) +Geometry shader culling = Abate do shader da geometria +Hack Settings = Configurações dos hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por hardware Hardware Transform = Transformação por hardware hardware transform error - falling back to software = Erro de transformação pelo hardware, retrocedendo pro software. @@ -543,7 +543,7 @@ Must Restart = Você deve reiniciar o PPSSPP pra esta mudança ter efeito. Native device resolution = Resolução nativa do dispositivo Nearest = Mais próximo No buffer = Sem buffer -Skip Buffer Effects = Ignorar efeitos do buffer (sem buffer, mais rápido) +Non-Buffered Rendering = Ignorar efeitos do buffer (sem buffer, mais rápido) None = Nenhum Number of Frames = Número de frames Off = Desligado @@ -565,15 +565,15 @@ Safe = Seguro Screen Scaling Filter = Filtro do dimensionamento da tela Show Debug Statistics = Mostrar estatísticas do debug Show FPS Counter = Mostrar contador de FPS -Skip GPU Readbacks = Skip GPU Readbacks +Skip GPU Readbacks = Ignorar Leituras da GPU Software Rendering = Renderização por software (lento) Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade -Speed Hacks = Speed Hacks (pode causar erros gráficos) -Stereo display shader = Stereo display shader -Stereo rendering = Stereo rendering -Stretch = Esticamento +Speed Hacks = Hacks de Velocidade (podem causar erros de renderização!) +Stereo display shader = Shader de exbição do estéreo +Stereo rendering = Renderização do estéreo +Stretch = Esticar Texture Filter = Filtragem das texturas Texture Filtering = Filtragem das texturas Texture Scaling = Dimensionamento das texturas @@ -744,9 +744,9 @@ Bottom Right = A direita do rodapé Center Left = Centralizar a esquerda Center Right = Centralizar a direita Change Mac Address = Mudar o endereço do MAC +ChangeMacSaveConfirm = Gerar um novo endereço pro MAC? +ChangeMacSaveWarning = Alguns jogos verificam o endereço do MAC quando carregam os dados do save então isto pode quebrar os saves antigos. Change proAdhocServer Address = Mudar o endereço de IP do servidor Ad Hoc PRO (localhost = múltiplas instâncias) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Bate-papo Chat Button Position = Posição do botão de bate-papo Chat Here = Bata-papo aqui @@ -827,13 +827,13 @@ Bloom = Bloom Brightness = Brilho Cartoon = Cartoon ColorCorrection = Correção das cores -ColorPreservation = Color preservation +ColorPreservation = Preservação das cores Contrast = Contraste CRT = Scanlines do CRT FXAA = Anti-aliasing do FXAA Gamma = Gama Grayscale = Tons de cinza -GreenLevel = GreenLevel +GreenLevel = Nível verde Intensity = Intensidade InverseColors = Cores invertidas Natural = Cores naturais @@ -841,11 +841,11 @@ NaturalA = Cores naturais (sem borrão) Off = Desligado Power = Energia PSPColor = Cor do PSP -RedBlue = Red/Blue glasses +RedBlue = Óculos Vermelhos/Azuis Saturation = Saturação Scanlines = Scanlines (CRT) Sharpen = Aprimorado -SideBySide = Side by side (SBS) +SideBySide = Lado a lado (SBS) SSAA(Gauss) = Super-amostragem do AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -888,10 +888,10 @@ tools = Ferramentas grátis usadas: # Leave extra lines blank. 4 contributors per line seems to look best. translators1 = Papel, gabrielmop, Efraim Lopes, AkiraJkr translators2 = Felipe -translators3 = -translators4 = -translators5 = -translators6 = +translators3 = +translators4 = +translators5 = +translators6 = Twitter @PPSSPP_emu = Twitter @PPSSPP_emu website = Verifique o site da web: written = Escrito em C++ pela velocidade e portabilidade @@ -992,7 +992,7 @@ View Feedback = Visualizar todos os feedbacks Date = Data Filename = Nome do arquivo No screenshot = Sem screenshot -None yet. Things will appear here after you save. = Nada ainda. As coisas aparecerão aqui após você salvar. +None yet. Things will appear here after you save. = Nada ainda. As coisas aparecerão aqui após você salvar. Nothing matching '%1' was found. = Nada combinando com o '%1' foi achado. Save Data = Dados salvos Save States = States salvos @@ -1062,7 +1062,6 @@ Debugger Present = Debugger presente Device Info = Informação do dispositivo Directories = Diretórios Display Information = Informação da tela -Driver bugs = Driver bugs Driver Version = Versão do driver Driver Version = Versão do driver EGL Extensions = Extensões do EGL @@ -1110,8 +1109,6 @@ AVI Dump started. = Dump do AVI iniciado AVI Dump stopped. = Dump do AVI parado Cache ISO in RAM = Pôr a ISO inteira na RAM Change CPU Clock = Mudar o clock da CPU do PSP emulado (instável) -Game crashed = Game crashed -Language = Idioma Memory Stick folder = Pasta do cartão de memória Memory Stick size = Tamanho do cartão de memória Change Nickname = Mudar apelido @@ -1144,6 +1141,7 @@ Fast Memory = Memória rápida (instável) Floating symbols = Símbolos flutuantes Force real clock sync (slower, less lag) = Forçar sincronização com o relógio real (mais lento, menos atrasos) frames, 0:off = frames, 0 = Desligado +Game crashed = O jogo teve um crash Games list settings = Configurações da lista de jogos General = Geral Grid icon size = Tamanho do ícone da grade @@ -1154,6 +1152,7 @@ Increase size = Aumentar tamanho Interpreter = Interpretador IO timing method = Método de cronometragem da E/S IR Interpreter = Interpretador do IR +Language = Idioma Memory Stick Folder = Pasta do cartão de memória Memory Stick inserted = Cartão de memória inserido MHz, 0:default = MHz, 0 = padrão From 657ac6dd568184d776f5db4fbecd8a297e5527f9 Mon Sep 17 00:00:00 2001 From: Felipe Date: Mon, 5 Dec 2022 15:25:25 -0300 Subject: [PATCH 589/715] Fixed omissions Fixed mistakes i did found by unknownbrackets. --- assets/lang/pt_BR.ini | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 285d76402d..0c2f988711 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -149,7 +149,7 @@ Refresh Rate = Taxa de atualização About PPSSPP... = &Sobre o PPSSPP... Auto = &Auto Auto Max Quality = Auto-maximizar a &qualidade -Backend = Backend de &renderização (Reinicia o PPSSPP) +Backend = Backend da &renderização (Reinicia o PPSSPP) Bicubic = &Bi-cúbico Break = Parar Break on Load = Parar ao carregar @@ -159,11 +159,11 @@ Debugging = &Debug Deposterize = &Deposterizar Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 -Disassembly = &Disassembly... +Disassembly = &Fazer Disassembly... Discord = Discord -Display Layout Editor = Exibir o editor do esquema... +Display Layout && Effects = Exibir esquema && efeitos... Display Rotation = Rotação da exibição -Dump Next Frame to Log = D&umpar o frame seguinte no log +Dump Next Frame to Log = D&umpar o frame seguinte no registro Emulation = &Emulação Enable Cheats = Ativar &trapaças Enable Sound = Ativar s&om @@ -188,7 +188,7 @@ Landscape reversed = Paisagem invertida Language... = Id&ioma... Linear = &Linear Load = &Carregar... -Load .sym File... = Carreg&ar arquivo .sym +Load .sym File... = Carreg&ar arquivo .sym... Load Map File... = Carregar &arquivo do mapa... Load State = C&arregar o state Load State File... = &Carregar arquivo do state... @@ -196,7 +196,7 @@ Log Console = &Console dos logs Memory View... = Visualização da &memória... More Settings... = &Mais configurações... Nearest = &Mais próximo -Non-Buffered Rendering = &Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = &Ignorar efeitos do buffer Off = &Desligado Open Chat = Abrir Bate-Papo Open Directory... = Abrir &diretório... @@ -254,31 +254,31 @@ Current = Atual Dev Tools = Ferramentas de desenvolvimento DevMenu = Menu do DEV Disabled JIT functionality = Funcionalidade do JIT desativada -Draw Frametimes Graph = Desenhar gráfico dos tempos dos frames -Dump Decrypted Eboot = Dumpar EBOOT.BIN decriptado no boot do jogo +Draw Frametimes Graph = Desenhar o gráfico dos tempos dos frames +Dump Decrypted Eboot = Dumpar o EBOOT.BIN decriptado na inicialização do jogo Dump next frame to log = Dumpar o frame seguinte no registro Enable driver bug workarounds = Ativar soluções alternativas pros bugs dos drivers -Enable Logging = Ativar log do debug +Enable Logging = Ativar o registro do debug Enter address = Inserir endereço FPU = FPU Framedump tests = Testes dos dumps dos frames Frame Profiler = Analista dos frames GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU -GPU Log Profiler = Criador do Perfil do Registro da GPU +GPU log profiler = Criador do perfil do registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de debug do JIT -Log Dropped Frame Statistics = Pôr no log as estátisticas da queda dos frames -Log Level = Nível do log -Log View = Visualização do log -Logging Channels = Canais do log +Log Dropped Frame Statistics = Pôr no registro as estátisticas da queda dos frames +Log Level = Nível do registro +Log View = Visualização do registro +Logging Channels = Canais do registro Next = Próximo No block = Nenhum bloco Prev = Anterior Random = Aleatório Replace textures = Substituir texturas Reset = Resetar -Reset limited logging = Resetar o log limitado +Reset limited logging = Resetar o registro limitado RestoreDefaultSettings = Você tem certeza que você quer restaurar todas as configurações de volta aos padrões delas?\nAs configurações do mapeamento dos controles não são mudadas.\nVocê não pode desfazer isto.\nPor favor reinicie o PPSSPP para as mudanças terem efeito. RestoreGameDefaultSettings = Você tem certeza que você quer restaurar as configurações específicas do jogo\nde volta para os padrões do PPSSPP? Resume = Resumo @@ -510,7 +510,7 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desativado -Display layout editor = Exibe o editor dos esquemas +Display Layout && Effects = Exibir esquema && efeitos Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) Enable Cardboard VR = Ativa o VR Cardboard FPS = FPS @@ -543,7 +543,7 @@ Must Restart = Você deve reiniciar o PPSSPP pra esta mudança ter efeito. Native device resolution = Resolução nativa do dispositivo Nearest = Mais próximo No buffer = Sem buffer -Non-Buffered Rendering = Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = Ignorar efeitos do buffer None = Nenhum Number of Frames = Número de frames Off = Desligado @@ -587,7 +587,7 @@ Upscale Type = Tipo de ampliação UpscaleLevel Tip = Pesado pra CPU - alguns dimensionamentos podem ser atrasados pra evitar travamentos Use all displays = Usar todas as telas Vertex Cache = Cache do vértice -VertexCache Tip = Mais rápido, mas pode causar tremulação temporária +VertexCache Tip = Mais rápido mas pode causar tremulação temporária VSync = VSync Vulkan = Vulkan Window Size = Tamanho da janela @@ -621,7 +621,7 @@ Browse = Procurar... Buy PPSSPP Gold = Comprar o PPSSPP Gold Choose folder = Escolher pasta Credits = Créditos -PPSSPP Homebrew Store = Armazém dos Homebrews do PPSSPP +PPSSPP Homebrew Store = Loja dos Homebrews do PPSSPP Exit = Sair Game Settings = Configurações Games = Jogos From d9501cb0ad2056df545fb9ce41c2f1156e7d1394 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 5 Dec 2022 23:09:55 -0800 Subject: [PATCH 590/715] softgpu: Fix w culling of triangle rects. --- GPU/Software/RasterizerRectangle.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index a8713dad97..2ce43cba89 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -413,6 +413,9 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli if (data1.clippos.w - halftexel > data0.clippos.w || data1.clippos.w + halftexel < data0.clippos.w) return false; } + // We might need to cull this if all verts have negative w, which doesn't seem to happen for rectangles. + if (data0.clippos.w < 0.0f && data1.clippos.w < 0.0f) + return false; // If we're projecting textures, only allow an exact match for simplicity. if (state.enableTextures && data1.v.texturecoords.q() != data0.v.texturecoords.q()) return false; From 5d6b213fa7c22b8b6b24c709f01dc3091ea3deb1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 5 Dec 2022 23:14:41 -0800 Subject: [PATCH 591/715] softgpu: Avoid tri combine to rect if clipping. --- GPU/Software/RasterizerRectangle.cpp | 35 ++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 2ce43cba89..d81c0fd403 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -392,6 +392,19 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b return false; } +static bool IsCoordRectangleCompatible(const RasterizerState &state, const ClipVertexData &data) { + if (!state.throughMode) { + // See AreCoordsRectangleCompatible() for most of these, this just checks the main vert. + if (data.OutsideRange()) + return false; + if (data.clippos.w < 0.0f) + return false; + if (data.clippos.z < -data.clippos.w) + return false; + } + return true; +} + static bool AreCoordsRectangleCompatible(const RasterizerState &state, const ClipVertexData &data0, const ClipVertexData &data1) { if (data1.v.color0 != data0.v.color0) return false; @@ -404,7 +417,7 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli if (data1.v.color1 != data0.v.color1) return false; // This means it should be culled, outside range. - if (data1.OutsideRange() || data0.OutsideRange()) + if (data1.OutsideRange()) return false; // Do we have to think about perspective correction or slope mip level? if (state.enableTextures && data1.clippos.w != data0.clippos.w) { @@ -414,7 +427,10 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli return false; } // We might need to cull this if all verts have negative w, which doesn't seem to happen for rectangles. - if (data0.clippos.w < 0.0f && data1.clippos.w < 0.0f) + if (data1.clippos.w < 0.0f) + return false; + // And we also may need to clip, even if flat. + if (data1.clippos.z < -data1.clippos.w) return false; // If we're projecting textures, only allow an exact match for simplicity. if (state.enableTextures && data1.v.texturecoords.q() != data0.v.texturecoords.q()) @@ -430,10 +446,13 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli } bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData data[4], int *tlIndex, int *brIndex) { + if (!IsCoordRectangleCompatible(state, data[0])) + return false; + // Color and Z must be flat. Also find the TL and BR meanwhile. int tl = 0, br = 0; for (int i = 1; i < 4; ++i) { - if (!AreCoordsRectangleCompatible(state, data[i], data[0])) + if (!AreCoordsRectangleCompatible(state, data[0], data[i])) return false; if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) @@ -486,10 +505,13 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData } bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex) { + if (!IsCoordRectangleCompatible(state, data[0])) + return false; + // Color and Z must be flat. int tl = 0, br = 0; for (int i = 1; i < 4; ++i) { - if (!AreCoordsRectangleCompatible(state, data[i], data[0])) + if (!AreCoordsRectangleCompatible(state, data[0], data[i])) return false; if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) @@ -537,10 +559,13 @@ bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData * } bool DetectRectangleFromPair(const RasterizerState &state, const ClipVertexData data[6], int *tlIndex, int *brIndex) { + if (!IsCoordRectangleCompatible(state, data[0])) + return false; + // Color and Z must be flat. Also find the TL and BR meanwhile. int tl = 0, br = 0; for (int i = 1; i < 6; ++i) { - if (!AreCoordsRectangleCompatible(state, data[i], data[0])) + if (!AreCoordsRectangleCompatible(state, data[0], data[i])) return false; if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) From 264a81913dd866c954e94f0b0f8cd42ca69adda9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:11:38 -0800 Subject: [PATCH 592/715] softgpu: Avoid checking UVs for sprites w/o tex. --- GPU/Software/RasterizerRectangle.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index d81c0fd403..0263e06433 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -349,16 +349,18 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b int ydiff = v1.screenpos.y - v0.screenpos.y; int udiff = (v1.texturecoords.x - v0.texturecoords.x) * (float)SCREEN_SCALE_FACTOR; int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * (float)SCREEN_SCALE_FACTOR; - bool coord_check = - (xdiff == udiff || xdiff == -udiff) && - (ydiff == vdiff || ydiff == -vdiff); // Currently only works for TL/BR, which is the most common but not required. bool orient_check = xdiff >= 0 && ydiff >= 0; // We already have a fast path for clear in ClearRectangle. - bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); + bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && !state.textureProj; + bool coord_check = true; + if (state.enableTextures) { + state_check = state_check && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); + coord_check = (xdiff == udiff || xdiff == -udiff) && (ydiff == vdiff || ydiff == -vdiff); + } // This doesn't work well with offset drawing, see #15876. Through never has a subpixel offset. bool subpixel_check = ((v0.screenpos.x | v0.screenpos.y | v1.screenpos.x | v1.screenpos.y) & 0xF) == 0; - if ((coord_check || !state.enableTextures) && orient_check && state_check && subpixel_check) { + if (coord_check && orient_check && state_check && subpixel_check) { binner.AddSprite(v0, v1); return true; } From c291bd78ef2fd290590d2c7ca1f74db99b720cff Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:26:02 -0800 Subject: [PATCH 593/715] softgpu: Use a template for 5551 fast path. Just refactoring here, should be the same. --- GPU/Software/RasterizerRectangle.cpp | 88 +++++++++++++++------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 0263e06433..ecbb851645 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -156,6 +156,50 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I return ToVec4IntResult(out); } +template +static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { + const u8 *texptr = state.texptr[0]; + uint16_t texbufw = state.texbufw[0]; + + int t = t_start; + const Vec4 c0 = Vec4::FromRGBA(color0); + for (int y = pos0.y; y < pos1.y; y++) { + int s = s_start; + u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); + if (isWhite) { + u32 tex_color32 = Vec4(tex_color).ToRGBA(); + if (tex_color32 & 0xFF000000) { + DrawSinglePixel5551(pixel, tex_color32); + } + } else { + Vec4 prim_color = c0; + prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); + if (prim_color.a() > 0) { + DrawSinglePixel5551(pixel, prim_color.ToRGBA()); + } + } + s += ds; + pixel++; + } + t += dt; + } +} + +static void DrawSpriteNoTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { + if (Vec4::FromRGBA(color0).a() == 0) + return; + + for (int y = pos0.y; y < pos1.y; y++) { + u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + DrawSinglePixel5551(pixel, color0); + pixel++; + } + } +} + void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state) { const u8 *texptr = state.texptr[0]; @@ -213,38 +257,9 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (UseDrawSinglePixel5551(pixelID) && samplerID.TexFunc() == GE_TEXFUNC_MODULATE && samplerID.useTextureAlpha) { if (isWhite) { - int t = t_start; - for (int y = pos0.y; y < pos1.y; y++) { - int s = s_start; - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - u32 tex_color = Vec4(fetchFunc(s, t, texptr, texbufw, 0, state.samplerID)).ToRGBA(); - if (tex_color & 0xFF000000) { - DrawSinglePixel5551(pixel, tex_color); - } - s += ds; - pixel++; - } - t += dt; - } + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { - int t = t_start; - const Vec4 c0 = Vec4::FromRGBA(v1.color0); - for (int y = pos0.y; y < pos1.y; y++) { - int s = s_start; - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - Vec4 prim_color = c0; - Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); - prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); - if (prim_color.a() > 0) { - DrawSinglePixel5551(pixel, prim_color.ToRGBA()); - } - s += ds; - pixel++; - } - t += dt; - } + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } } else { float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); @@ -287,16 +302,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; if (UseDrawSinglePixel5551(pixelID)) { - if (Vec4::FromRGBA(v1.color0).a() == 0) - return; - - for (int y = pos0.y; y < pos1.y; y++) { - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - DrawSinglePixel5551(pixel, v1.color0); - pixel++; - } - } + DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); } else if (pixelID.earlyZChecks) { const Vec4 prim_color = Vec4::FromRGBA(v1.color0); for (int y = pos0.y; y < pos1.y; y++) { From 60c129c52f9ee9c1924ff2d7e4ab34a7b552e1bd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:31:30 -0800 Subject: [PATCH 594/715] softgpu: Use no-modulate fast path for REPLACE. --- GPU/Software/RasterizerRectangle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index ecbb851645..c8cdcd0149 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -255,8 +255,8 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran pos0.y = scissorTL.y; } - if (UseDrawSinglePixel5551(pixelID) && samplerID.TexFunc() == GE_TEXFUNC_MODULATE && samplerID.useTextureAlpha) { - if (isWhite) { + if (UseDrawSinglePixel5551(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { + if (isWhite || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) { DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); From 51fa931e46ae53cee903ea1f3fab1ffba9beadca Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:37:51 -0800 Subject: [PATCH 595/715] softgpu: Allow no alpha blend in 5551 fast path. --- GPU/Software/RasterizerRectangle.cpp | 45 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index c8cdcd0149..d42f685e2d 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -72,10 +72,11 @@ static uint32_t StandardAlphaBlend(uint32_t source, uint32_t dst) { } // Through mode, with the specific Darkstalker settings. +template inline void DrawSinglePixel5551(u16 *pixel, const u32 color_in) { u32 new_color; // Because of this check, we only support src.a / 1-src.a blending. - if ((color_in >> 24) == 255) { + if ((color_in >> 24) == 255 || !alphaBlend) { new_color = color_in & 0xFFFFFF; } else { const u32 old_color = RGBA5551ToRGBA8888(*pixel); @@ -113,13 +114,15 @@ bool UseDrawSinglePixel5551(const PixelFuncID &pixelID) { return false; if (!AlphaTestIsNeedless(pixelID) || pixelID.DepthTestFunc() != GE_COMP_ALWAYS) return false; - if (pixelID.FBFormat() != GE_FORMAT_5551 || !pixelID.alphaBlend) + if (pixelID.FBFormat() != GE_FORMAT_5551) return false; // We skip blending when alpha = FF, so we can't allow other blend modes. - if (pixelID.AlphaBlendEq() != GE_BLENDMODE_MUL_AND_ADD || pixelID.AlphaBlendSrc() != PixelBlendFactor::SRCALPHA) - return false; - if (pixelID.AlphaBlendDst() != PixelBlendFactor::INVSRCALPHA) - return false; + if (pixelID.alphaBlend) { + if (pixelID.AlphaBlendEq() != GE_BLENDMODE_MUL_AND_ADD || pixelID.AlphaBlendSrc() != PixelBlendFactor::SRCALPHA) + return false; + if (pixelID.AlphaBlendDst() != PixelBlendFactor::INVSRCALPHA) + return false; + } if (pixelID.dithering || pixelID.applyLogicOp || pixelID.applyColorWriteMask) return false; @@ -156,7 +159,7 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I return ToVec4IntResult(out); } -template +template static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { const u8 *texptr = state.texptr[0]; uint16_t texbufw = state.texbufw[0]; @@ -170,14 +173,14 @@ static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &po Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); if (isWhite) { u32 tex_color32 = Vec4(tex_color).ToRGBA(); - if (tex_color32 & 0xFF000000) { - DrawSinglePixel5551(pixel, tex_color32); + if (!alphaBlend || tex_color32 & 0xFF000000) { + DrawSinglePixel5551(pixel, tex_color32); } } else { Vec4 prim_color = c0; prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); - if (prim_color.a() > 0) { - DrawSinglePixel5551(pixel, prim_color.ToRGBA()); + if (!alphaBlend || prim_color.a() > 0) { + DrawSinglePixel5551(pixel, prim_color.ToRGBA()); } } s += ds; @@ -187,14 +190,15 @@ static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &po } } +template static void DrawSpriteNoTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { - if (Vec4::FromRGBA(color0).a() == 0) + if (alphaBlend && Vec4::FromRGBA(color0).a() == 0) return; for (int y = pos0.y; y < pos1.y; y++) { u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); for (int x = pos0.x; x < pos1.x; x++) { - DrawSinglePixel5551(pixel, color0); + DrawSinglePixel5551(pixel, color0); pixel++; } } @@ -257,9 +261,15 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (UseDrawSinglePixel5551(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { if (isWhite || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) { - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + if (pixelID.alphaBlend) + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + else + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + if (pixelID.alphaBlend) + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + else + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } } else { float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); @@ -302,7 +312,10 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; if (UseDrawSinglePixel5551(pixelID)) { - DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); + if (pixelID.alphaBlend) + DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); + else + DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); } else if (pixelID.earlyZChecks) { const Vec4 prim_color = Vec4::FromRGBA(v1.color0); for (int y = pos0.y; y < pos1.y; y++) { From abb4aa92f1b8d5897210bfc46bdcbc2da96548ea Mon Sep 17 00:00:00 2001 From: Xu Zhen Date: Tue, 6 Dec 2022 23:17:35 +0800 Subject: [PATCH 596/715] Fix window icon path --- Qt/mainwindow.cpp | 8 ++++++++ SDL/SDLMain.cpp | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index ff0947f573..26707a76e2 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,14 @@ MainWindow::MainWindow(QWidget *parent, bool fullscreen) : nextState(CORE_POWERDOWN), lastUIState(UISTATE_MENU) { +#if defined(ASSETS_DIR) + if (QFile::exists(ASSETS_DIR "icon_regular_72.png")) + setWindowIcon(QIcon(ASSETS_DIR "icon_regular_72.png")); + else + setWindowIcon(QIcon(qApp->applicationDirPath() + "/assets/icon_regular_72.png")); +#else setWindowIcon(QIcon(qApp->applicationDirPath() + "/assets/icon_regular_72.png")); +#endif SetGameTitle(""); emugl = new MainUI(this); diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index b09a64d5dd..526935f64c 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -770,7 +770,13 @@ int main(int argc, char *argv[]) { SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str()); char iconPath[PATH_MAX]; +#if defined(ASSETS_DIR) + snprintf(iconPath, PATH_MAX, "%sicon_regular_72.png", ASSETS_DIR); + if (access(iconPath, F_OK) != 0) + snprintf(iconPath, PATH_MAX, "%sassets/icon_regular_72.png", SDL_GetBasePath() ? SDL_GetBasePath() : ""); +#else snprintf(iconPath, PATH_MAX, "%sassets/icon_regular_72.png", SDL_GetBasePath() ? SDL_GetBasePath() : ""); +#endif int width = 0, height = 0; unsigned char *imageData; if (pngLoad(iconPath, &width, &height, &imageData) == 1) { From 10eafe2e02ddffe4803cb403d5db1ee0eb46df22 Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 6 Dec 2022 11:15:33 -0500 Subject: [PATCH 597/715] Libretro: Set Interpreter as default CPU and get CPU from setting --- libretro/libretro.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 49f92cc989..ce0de12639 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -1389,6 +1389,9 @@ bool retro_load_game(const struct retro_game_info *game) useEmuThread = ctx->GetGPUCore() == GPUCORE_GLES; + // default to interpreter to allow startup in platforms w/o JIT capability + g_Config.iCpuCore = (int)CPUCore::INTERPRETER; + CoreParameter coreParam = {}; coreParam.enableSound = true; coreParam.fileToStart = Path(std::string(game->path)); @@ -1398,9 +1401,11 @@ bool retro_load_game(const struct retro_game_info *game) coreParam.headLess = true; coreParam.graphicsContext = ctx; coreParam.gpuCore = ctx->GetGPUCore(); - coreParam.cpuCore = (CPUCore)g_Config.iCpuCore; check_variables(coreParam); + // set cpuCore from libretro setting variable + coreParam.cpuCore = (CPUCore)g_Config.iCpuCore; + std::string error_string; if (!PSP_InitStart(coreParam, &error_string)) { From 4de64666d030ab2f0243cc49bde79122711bc0a4 Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 6 Dec 2022 12:23:09 -0500 Subject: [PATCH 598/715] feat(libretro): ios compile settings --- CMakeLists.txt | 4 ++++ libretro/CMakeLists.txt | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a9173ed37..90cd57ace1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1316,6 +1316,10 @@ if(ANDROID) endif() endif() +if (IOS) + set(nativeExtra ${nativeExtra} ${NativeAppSource}) +endif() + add_library(native STATIC ${nativeExtra} Common/Render/Text/draw_text_qt.cpp diff --git a/libretro/CMakeLists.txt b/libretro/CMakeLists.txt index 69efea8980..d04cc155e5 100644 --- a/libretro/CMakeLists.txt +++ b/libretro/CMakeLists.txt @@ -22,6 +22,10 @@ if(ANDROID) endif() if(NOT MSVC) - target_link_libraries(ppsspp_libretro "-Wl,-Bsymbolic") + if (IOS) + target_link_libraries(ppsspp_libretro "-Wl") + else() + target_link_libraries(ppsspp_libretro "-Wl,-Bsymbolic") + endif() endif() target_link_libraries(ppsspp_libretro ${LinkCommon}) From 70b6733d0ac5e65660a1229a0bfacf69215b9537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 01:50:15 +0100 Subject: [PATCH 599/715] Minor alpha bit optimization in Darkstalkers rectangle code --- Common/Data/Convert/ColorConv.h | 8 ++++++++ GPU/Software/RasterizerRectangle.cpp | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Common/Data/Convert/ColorConv.h b/Common/Data/Convert/ColorConv.h index 077533171b..65a917beff 100644 --- a/Common/Data/Convert/ColorConv.h +++ b/Common/Data/Convert/ColorConv.h @@ -101,6 +101,14 @@ inline u16 RGBA8888ToRGBA5551(u32 value) { return (u16)(r | g | b | a); } +// Used in fast sprite path. +inline u16 RGBA8888ToRGBA555X(u32 value) { + u32 r = (value >> 3) & 0x1F; + u32 g = (value >> 6) & (0x1F << 5); + u32 b = (value >> 9) & (0x1F << 10); + return (u16)(r | g | b); +} + inline u16 RGBA8888ToRGBA4444(u32 value) { const u32 c = value >> 4; const u16 r = (c >> 0) & 0x000F; diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index d42f685e2d..59bc18fb6a 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -82,8 +82,8 @@ inline void DrawSinglePixel5551(u16 *pixel, const u32 color_in) { const u32 old_color = RGBA5551ToRGBA8888(*pixel); new_color = StandardAlphaBlend(color_in, old_color); } - new_color |= (*pixel & 0x8000) ? 0xff000000 : 0x00000000; - *pixel = RGBA8888ToRGBA5551(new_color); + u16 value = RGBA8888ToRGBA555X(new_color) | (*pixel & 0x8000); + *pixel = value; } // Check if we can safely ignore the alpha test, assuming standard alpha blending. @@ -173,7 +173,7 @@ static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &po Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); if (isWhite) { u32 tex_color32 = Vec4(tex_color).ToRGBA(); - if (!alphaBlend || tex_color32 & 0xFF000000) { + if (!alphaBlend || (tex_color32 & 0xFF000000)) { DrawSinglePixel5551(pixel, tex_color32); } } else { From b51422c18b4dcef2f196f74312645af72c706f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 01:50:48 +0100 Subject: [PATCH 600/715] Ordering fix, should fix elimination of the DarkStalkers software blit --- GPU/Software/RasterizerRectangle.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 59bc18fb6a..1103dce76e 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -377,12 +377,6 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b state_check = state_check && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); coord_check = (xdiff == udiff || xdiff == -udiff) && (ydiff == vdiff || ydiff == -vdiff); } - // This doesn't work well with offset drawing, see #15876. Through never has a subpixel offset. - bool subpixel_check = ((v0.screenpos.x | v0.screenpos.y | v1.screenpos.x | v1.screenpos.y) & 0xF) == 0; - if (coord_check && orient_check && state_check && subpixel_check) { - binner.AddSprite(v0, v1); - return true; - } // Eliminate the stretch blit in DarkStalkers. // We compensate for that when blitting the framebuffer in SoftGpu.cpp. @@ -410,6 +404,13 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b g_needsClearAfterDialog = true; } } + + // This doesn't work well with offset drawing, see #15876. Through never has a subpixel offset. + bool subpixel_check = ((v0.screenpos.x | v0.screenpos.y | v1.screenpos.x | v1.screenpos.y) & 0xF) == 0; + if (coord_check && orient_check && state_check && subpixel_check) { + binner.AddSprite(v0, v1); + return true; + } return false; } From 50fdf67fd0fea9bc6077c53bc850469c4c908ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 01:51:20 +0100 Subject: [PATCH 601/715] Software rect raster: Speed up memory tracking in debug mode (ztag unused, remove allocations) --- GPU/Software/RasterizerRectangle.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 1103dce76e..a7159f0c36 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -338,12 +338,14 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran #if defined(SOFTGPU_MEMORY_TAGGING_BASIC) || defined(SOFTGPU_MEMORY_TAGGING_DETAILED) uint32_t bpp = pixelID.FBFormat() == GE_FORMAT_8888 ? 4 : 2; - std::string tag = StringFromFormat("DisplayListR_%08x", state.listPC); - std::string ztag = StringFromFormat("DisplayListRZ_%08x", state.listPC); + char tag[64]{}; + // char ztag[64]{}; + int tagLen = snprintf(tag, sizeof(tag), "DisplayListR_%08x", state.listPC); + // int ztagLen = snprintf(ztag, sizeof(ztag), "DisplayListRZ_%08x", state.listPC); for (int y = pos0.y; y < pos1.y; y++) { uint32_t row = gstate.getFrameBufAddress() + y * pixelID.cached.framebufStride * bpp; - NotifyMemInfo(MemBlockFlags::WRITE, row + pos0.x * bpp, (pos1.x - pos0.x) * bpp, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, row + pos0.x * bpp, (pos1.x - pos0.x) * bpp, tag, tagLen); } #endif } @@ -508,6 +510,7 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData // There's the other vertex order too... if (data[0].v.screenpos.x == data[2].v.screenpos.x && data[0].v.screenpos.y == data[1].v.screenpos.y && + data[1].v.screenpos.x == data[3].v.screenpos.x && data[2].v.screenpos.y == data[3].v.screenpos.y) { // Okay, this is in the shape of a rectangle, but what about texture? From 49f8f96a984259fc630915f82794764a167ed644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 02:08:48 +0100 Subject: [PATCH 602/715] Couple more microoptimizations --- GPU/Software/RasterizerRectangle.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index a7159f0c36..a735751e90 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -76,7 +76,8 @@ template inline void DrawSinglePixel5551(u16 *pixel, const u32 color_in) { u32 new_color; // Because of this check, we only support src.a / 1-src.a blending. - if ((color_in >> 24) == 255 || !alphaBlend) { + // We take advantage of short circuiting by checking the constant (template) value first. + if (!alphaBlend || (color_in >> 24) == 255) { new_color = color_in & 0xFFFFFF; } else { const u32 old_color = RGBA5551ToRGBA8888(*pixel); @@ -172,8 +173,8 @@ static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &po for (int x = pos0.x; x < pos1.x; x++) { Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); if (isWhite) { - u32 tex_color32 = Vec4(tex_color).ToRGBA(); - if (!alphaBlend || (tex_color32 & 0xFF000000)) { + if (!alphaBlend || tex_color.a() != 0) { + u32 tex_color32 = tex_color.ToRGBA(); DrawSinglePixel5551(pixel, tex_color32); } } else { From 77c98441f467fe9135e21894f6fcd1b7e7537f2a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 18:43:21 -0800 Subject: [PATCH 603/715] softgpu: Expand fast path to all fb formats. This should speed up 2D games not using 5551, and make it mroe likely any regression is caught for Darkstalkers. --- Common/Data/Convert/ColorConv.h | 8 ++ GPU/Software/RasterizerRectangle.cpp | 184 ++++++++++++++++++++------- 2 files changed, 149 insertions(+), 43 deletions(-) diff --git a/Common/Data/Convert/ColorConv.h b/Common/Data/Convert/ColorConv.h index 65a917beff..a7355dbb9d 100644 --- a/Common/Data/Convert/ColorConv.h +++ b/Common/Data/Convert/ColorConv.h @@ -118,6 +118,14 @@ inline u16 RGBA8888ToRGBA4444(u32 value) { return r | g | b | a; } +inline u16 RGBA8888ToRGBA444X(u32 value) { + const u32 c = value >> 4; + const u16 r = (c >> 0) & 0x000F; + const u16 g = (c >> 4) & 0x00F0; + const u16 b = (c >> 8) & 0x0F00; + return r | g | b; +} + // convert image to 8888, parallelizable // TODO: Implement these in terms of the conversion functions below. void convert4444_gl(u16* data, u32* out, int width, int l, int u); diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index a735751e90..d7925a66a1 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -72,19 +72,59 @@ static uint32_t StandardAlphaBlend(uint32_t source, uint32_t dst) { } // Through mode, with the specific Darkstalker settings. -template -inline void DrawSinglePixel5551(u16 *pixel, const u32 color_in) { +template +static inline void DrawSinglePixel(u16 *pixel, const u32 color_in) { u32 new_color; // Because of this check, we only support src.a / 1-src.a blending. // We take advantage of short circuiting by checking the constant (template) value first. if (!alphaBlend || (color_in >> 24) == 255) { new_color = color_in & 0xFFFFFF; } else { - const u32 old_color = RGBA5551ToRGBA8888(*pixel); + u32 old_color; + switch (fmt) { + case GE_FORMAT_565: + old_color = RGB565ToRGBA8888(*pixel); + break; + case GE_FORMAT_5551: + old_color = RGBA5551ToRGBA8888(*pixel); + break; + case GE_FORMAT_4444: + old_color = RGBA4444ToRGBA8888(*pixel); + break; + default: + break; + } + new_color = StandardAlphaBlend(color_in, old_color); } - u16 value = RGBA8888ToRGBA555X(new_color) | (*pixel & 0x8000); - *pixel = value; + + switch (fmt) { + case GE_FORMAT_565: + *pixel = RGBA8888ToRGB565(new_color); + break; + case GE_FORMAT_5551: + *pixel = RGBA8888ToRGBA555X(new_color) | (*pixel & 0x8000); + break; + case GE_FORMAT_4444: + *pixel = RGBA8888ToRGBA444X(new_color) | (*pixel & 0xF000); + break; + default: + break; + } +} + +template +static inline void DrawSinglePixel32(u32 *pixel, const u32 color_in) { + u32 new_color; + // Because of this check, we only support src.a / 1-src.a blending. + if ((color_in >> 24) == 255 || !alphaBlend) { + new_color = color_in & 0xFFFFFF; + } else { + const u32 old_color = *pixel; + new_color = StandardAlphaBlend(color_in, old_color); + } + new_color |= *pixel & 0xFF000000; + *pixel = new_color; } // Check if we can safely ignore the alpha test, assuming standard alpha blending. @@ -110,13 +150,11 @@ static inline bool AlphaTestIsNeedless(const PixelFuncID &pixelID) { return false; } -bool UseDrawSinglePixel5551(const PixelFuncID &pixelID) { +static bool UseDrawSinglePixel(const PixelFuncID &pixelID) { if (pixelID.clearMode || pixelID.colorTest || pixelID.stencilTest) return false; if (!AlphaTestIsNeedless(pixelID) || pixelID.DepthTestFunc() != GE_COMP_ALWAYS) return false; - if (pixelID.FBFormat() != GE_FORMAT_5551) - return false; // We skip blending when alpha = FF, so we can't allow other blend modes. if (pixelID.alphaBlend) { if (pixelID.AlphaBlendEq() != GE_BLENDMODE_MUL_AND_ADD || pixelID.AlphaBlendSrc() != PixelBlendFactor::SRCALPHA) @@ -160,8 +198,8 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I return ToVec4IntResult(out); } -template -static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { +template +static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { const u8 *texptr = state.texptr[0]; uint16_t texbufw = state.texbufw[0]; @@ -169,42 +207,102 @@ static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &po const Vec4 c0 = Vec4::FromRGBA(color0); for (int y = pos0.y; y < pos1.y; y++) { int s = s_start; - u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + u16 *pixel16 = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + u32 *pixel32 = fb.Get32Ptr(pos0.x, y, state.pixelID.cached.framebufStride); for (int x = pos0.x; x < pos1.x; x++) { Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); if (isWhite) { if (!alphaBlend || tex_color.a() != 0) { u32 tex_color32 = tex_color.ToRGBA(); - DrawSinglePixel5551(pixel, tex_color32); + if (fmt == GE_FORMAT_8888) + DrawSinglePixel32(pixel32, tex_color32); + else + DrawSinglePixel(pixel16, tex_color32); } } else { Vec4 prim_color = c0; prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); if (!alphaBlend || prim_color.a() > 0) { - DrawSinglePixel5551(pixel, prim_color.ToRGBA()); + if (fmt == GE_FORMAT_8888) + DrawSinglePixel32(pixel32, prim_color.ToRGBA()); + else + DrawSinglePixel(pixel16, prim_color.ToRGBA()); } } s += ds; - pixel++; + if (fmt == GE_FORMAT_8888) + pixel32++; + else + pixel16++; } t += dt; } } -template -static void DrawSpriteNoTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { +template +static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { + switch (state.pixelID.FBFormat()) { + case GE_FORMAT_565: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + case GE_FORMAT_5551: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + case GE_FORMAT_4444: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + case GE_FORMAT_8888: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + default: + // Invalid, don't draw anything... + break; + } +} + +template +static void DrawSpriteNoTex(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { if (alphaBlend && Vec4::FromRGBA(color0).a() == 0) return; for (int y = pos0.y; y < pos1.y; y++) { - u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - DrawSinglePixel5551(pixel, color0); - pixel++; + if (fmt == GE_FORMAT_8888) { + u32 *pixel = fb.Get32Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + DrawSinglePixel32(pixel, color0); + pixel++; + } + } else { + u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + DrawSinglePixel(pixel, color0); + pixel++; + } } } } +template +static void DrawSpriteNoTex(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { + switch (state.pixelID.FBFormat()) { + case GE_FORMAT_565: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + case GE_FORMAT_5551: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + case GE_FORMAT_4444: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + case GE_FORMAT_8888: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + default: + // Invalid, don't draw anything... + break; + } +} + void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state) { const u8 *texptr = state.texptr[0]; @@ -260,17 +358,17 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran pos0.y = scissorTL.y; } - if (UseDrawSinglePixel5551(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { + if (UseDrawSinglePixel(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { if (isWhite || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) { if (pixelID.alphaBlend) - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); else - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { if (pixelID.alphaBlend) - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); else - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } } else { float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); @@ -312,11 +410,11 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (pos1.y > scissorBR.y) pos1.y = scissorBR.y + 1; if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; - if (UseDrawSinglePixel5551(pixelID)) { + if (UseDrawSinglePixel(pixelID)) { if (pixelID.alphaBlend) - DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); + DrawSpriteNoTex(pos0, pos1, v1.color0, state); else - DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); + DrawSpriteNoTex(pos0, pos1, v1.color0, state); } else if (pixelID.earlyZChecks) { const Vec4 prim_color = Vec4::FromRGBA(v1.color0); for (int y = pos0.y; y < pos1.y; y++) { @@ -366,20 +464,6 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b const RasterizerState &state = binner.State(); g_DarkStalkerStretch = DSStretch::Off; - // Check for 1:1 texture mapping. In that case we can call DrawSprite. - int xdiff = v1.screenpos.x - v0.screenpos.x; - int ydiff = v1.screenpos.y - v0.screenpos.y; - int udiff = (v1.texturecoords.x - v0.texturecoords.x) * (float)SCREEN_SCALE_FACTOR; - int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * (float)SCREEN_SCALE_FACTOR; - // Currently only works for TL/BR, which is the most common but not required. - bool orient_check = xdiff >= 0 && ydiff >= 0; - // We already have a fast path for clear in ClearRectangle. - bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && !state.textureProj; - bool coord_check = true; - if (state.enableTextures) { - state_check = state_check && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); - coord_check = (xdiff == udiff || xdiff == -udiff) && (ydiff == vdiff || ydiff == -vdiff); - } // Eliminate the stretch blit in DarkStalkers. // We compensate for that when blitting the framebuffer in SoftGpu.cpp. @@ -408,6 +492,21 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b } } + // Check for 1:1 texture mapping. In that case we can call DrawSprite. + int xdiff = v1.screenpos.x - v0.screenpos.x; + int ydiff = v1.screenpos.y - v0.screenpos.y; + int udiff = (v1.texturecoords.x - v0.texturecoords.x) * (float)SCREEN_SCALE_FACTOR; + int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * (float)SCREEN_SCALE_FACTOR; + + // Currently only works for TL/BR, which is the most common but not required. + bool orient_check = xdiff >= 0 && ydiff >= 0; + // We already have a fast path for clear in ClearRectangle. + bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && !state.textureProj; + bool coord_check = true; + if (state.enableTextures) { + state_check = state_check && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); + coord_check = (xdiff == udiff || xdiff == -udiff) && (ydiff == vdiff || ydiff == -vdiff); + } // This doesn't work well with offset drawing, see #15876. Through never has a subpixel offset. bool subpixel_check = ((v0.screenpos.x | v0.screenpos.y | v1.screenpos.x | v1.screenpos.y) & 0xF) == 0; if (coord_check && orient_check && state_check && subpixel_check) { @@ -511,7 +610,6 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData // There's the other vertex order too... if (data[0].v.screenpos.x == data[2].v.screenpos.x && data[0].v.screenpos.y == data[1].v.screenpos.y && - data[1].v.screenpos.x == data[3].v.screenpos.x && data[2].v.screenpos.y == data[3].v.screenpos.y) { // Okay, this is in the shape of a rectangle, but what about texture? From 87fb9eef37bbdf219d9a4c46f90c698ec4a5a8a8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 19:07:43 -0800 Subject: [PATCH 604/715] softgpu: Remove std::function usage. Wanted to avoid coupling these, but don't like the std::function construct/destructs showing in profiles... --- GPU/Software/BinManager.cpp | 4 +--- GPU/Software/DrawPixel.cpp | 11 ++++++----- GPU/Software/DrawPixel.h | 7 ++++--- GPU/Software/Rasterizer.cpp | 20 ++++++++++++-------- GPU/Software/Rasterizer.h | 3 ++- GPU/Software/Sampler.cpp | 31 ++++++++++++++++--------------- GPU/Software/Sampler.h | 17 +++++++++-------- unittest/TestSoftwareGPUJit.cpp | 11 +++++++---- 8 files changed, 57 insertions(+), 47 deletions(-) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index ac50f4c5a3..7906cbe79f 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -172,9 +172,7 @@ void BinManager::UpdateState() { creatingState_ = true; stateIndex_ = (uint16_t)states_.Push(RasterizerState()); // When new funcs are compiled, we need to flush if WX exclusive. - ComputeRasterizerState(&states_[stateIndex_], [&]() { - Flush("compile"); - }); + ComputeRasterizerState(&states_[stateIndex_], this); states_[stateIndex_].samplerID.cached.clut = cluts_[clutIndex_].readable; creatingState_ = false; diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index 2f4ea23b17..341ba80f7b 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -20,6 +20,7 @@ #include "Common/Data/Convert/ColorConv.h" #include "Core/Config.h" #include "GPU/GPUState.h" +#include "GPU/Software/BinManager.h" #include "GPU/Software/DrawPixel.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/Rasterizer.h" @@ -707,8 +708,8 @@ void SOFTRAST_CALL DrawSinglePixel(int x, int y, int z, int fog, Vec4IntArg colo SetPixelColor(fbFormat, pixelID.cached.framebufStride, x, y, new_color, old_color, targetWriteMask); } -SingleFunc GetSingleFunc(const PixelFuncID &id, std::function flushForCompile) { - SingleFunc jitted = jitCache->GetSingle(id, flushForCompile); +SingleFunc GetSingleFunc(const PixelFuncID &id, BinManager *binner) { + SingleFunc jitted = jitCache->GetSingle(id, binner); if (jitted) { return jitted; } @@ -786,7 +787,7 @@ void PixelJitCache::Flush() { compileQueue_.clear(); } -SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function flushForCompile) { +SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { if (!g_Config.bSoftwareRenderingJit) return nullptr; @@ -798,14 +799,14 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function return it; } - if (!flushForCompile) { + if (!binner) { // Can't compile, let's try to do it later when there's an opportunity. compileQueue_.insert(id); return nullptr; } guard.unlock(); - flushForCompile(); + binner->Flush("compile"); guard.lock(); for (const auto &queued : compileQueue_) { diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index e9d2715da4..1e100c81be 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -19,7 +19,6 @@ #include "ppsspp_config.h" -#include #include #include #include @@ -29,6 +28,8 @@ #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" +class BinManager; + namespace Rasterizer { // Our std::unordered_map argument will ignore the alignment attribute, but that doesn't matter. @@ -39,7 +40,7 @@ namespace Rasterizer { #endif typedef void (SOFTRAST_CALL *SingleFunc)(int x, int y, int z, int fog, Vec4IntArg color_in, const PixelFuncID &pixelID); -SingleFunc GetSingleFunc(const PixelFuncID &id, std::function flushForCompile); +SingleFunc GetSingleFunc(const PixelFuncID &id, BinManager *binner); void Init(); void FlushJit(); @@ -64,7 +65,7 @@ public: PixelJitCache(); // Returns a pointer to the code to run. - SingleFunc GetSingle(const PixelFuncID &id, std::function flushForCompile); + SingleFunc GetSingle(const PixelFuncID &id, BinManager *binner); SingleFunc GenericSingle(const PixelFuncID &id); void Clear() override; void Flush(); diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 176e2a8199..4b9ed61d27 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -93,15 +93,15 @@ static inline Vec4 Interpolate(const float &c0, const float &c1, const fl return Interpolate(c0, c1, c2, w0.Cast(), w1.Cast(), w2.Cast(), wsum_recip); } -void ComputeRasterizerState(RasterizerState *state, std::function flushForCompile) { +void ComputeRasterizerState(RasterizerState *state, BinManager *binner) { ComputePixelFuncID(&state->pixelID); - state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID, flushForCompile); + state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID, binner); state->enableTextures = gstate.isTextureMapEnabled() && !state->pixelID.clearMode; if (state->enableTextures) { ComputeSamplerID(&state->samplerID); - state->linear = Sampler::GetLinearFunc(state->samplerID, flushForCompile); - state->nearest = Sampler::GetNearestFunc(state->samplerID, flushForCompile); + state->linear = Sampler::GetLinearFunc(state->samplerID, binner); + state->nearest = Sampler::GetNearestFunc(state->samplerID, binner); // Since the definitions are the same, just force this setting using the func pointer. if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { @@ -1697,10 +1697,14 @@ bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) ComputeSamplerID(&id); id.cached.clut = clut; - Sampler::FetchFunc sampler = Sampler::GetFetchFunc(id, [] { - if (gpuDebug) - gpuDebug->DispatchFlush(); - }); + // Slight annoyance, we may have to force a compile. + Sampler::FetchFunc sampler = Sampler::GetFetchFunc(id, nullptr); + if (!sampler) { + Sampler::FlushJit(); + sampler = Sampler::GetFetchFunc(id, nullptr); + if (!sampler) + return false; + } u8 *texptr = Memory::GetPointerWrite(texaddr); u32 *row = (u32 *)buffer.GetData(); diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index aad5b648ef..d4e4ebe17c 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -30,6 +30,7 @@ struct GPUDebugBuffer; struct BinCoords; +class BinManager; namespace Rasterizer { @@ -100,7 +101,7 @@ struct RasterizerState { } }; -void ComputeRasterizerState(RasterizerState *state, std::function flushForCompile); +void ComputeRasterizerState(RasterizerState *state, BinManager *binner); void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0); void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, bool forceFlat); void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, const VertexData &v2); diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 66022fa53b..97a47933cc 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -25,6 +25,7 @@ #include "Core/Reporting.h" #include "GPU/Common/TextureDecoder.h" #include "GPU/GPUState.h" +#include "GPU/Software/BinManager.h" #include "GPU/Software/Rasterizer.h" #include "GPU/Software/RasterizerRegCache.h" #include "GPU/Software/Sampler.h" @@ -67,9 +68,9 @@ bool DescribeCodePtr(const u8 *ptr, std::string &name) { return true; } -NearestFunc GetNearestFunc(SamplerID id, std::function flushForCompile) { +NearestFunc GetNearestFunc(SamplerID id, BinManager *binner) { id.linear = false; - NearestFunc jitted = jitCache->GetNearest(id, flushForCompile); + NearestFunc jitted = jitCache->GetNearest(id, binner); if (jitted) { return jitted; } @@ -77,9 +78,9 @@ NearestFunc GetNearestFunc(SamplerID id, std::function flushForCompile) return &SampleNearest; } -LinearFunc GetLinearFunc(SamplerID id, std::function flushForCompile) { +LinearFunc GetLinearFunc(SamplerID id, BinManager *binner) { id.linear = true; - LinearFunc jitted = jitCache->GetLinear(id, flushForCompile); + LinearFunc jitted = jitCache->GetLinear(id, binner); if (jitted) { return jitted; } @@ -87,9 +88,9 @@ LinearFunc GetLinearFunc(SamplerID id, std::function flushForCompile) { return &SampleLinear; } -FetchFunc GetFetchFunc(SamplerID id, std::function flushForCompile) { +FetchFunc GetFetchFunc(SamplerID id, BinManager *binner) { id.fetch = true; - FetchFunc jitted = jitCache->GetFetch(id, flushForCompile); + FetchFunc jitted = jitCache->GetFetch(id, binner); if (jitted) { return jitted; } @@ -153,7 +154,7 @@ void SamplerJitCache::Flush() { compileQueue_.clear(); } -NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function flushForCompile) { +NearestFunc SamplerJitCache::GetByID(const SamplerID &id, BinManager *binner) { if (!g_Config.bSoftwareRenderingJit) return nullptr; @@ -164,14 +165,14 @@ NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function if (it != nullptr) return it; - if (!flushForCompile) { + if (!binner) { // Can't compile, let's try to do it later when there's an opportunity. compileQueue_.insert(id); return nullptr; } guard.unlock(); - flushForCompile(); + binner->Flush("compile"); guard.lock(); for (const auto &queued : compileQueue_) { @@ -189,16 +190,16 @@ NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function return cache_.Get(key); } -NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, std::function flushForCompile) { - return (NearestFunc)GetByID(id, flushForCompile); +NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, BinManager *binner) { + return (NearestFunc)GetByID(id, binner); } -LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, std::function flushForCompile) { - return (LinearFunc)GetByID(id, flushForCompile); +LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, BinManager *binner) { + return (LinearFunc)GetByID(id, binner); } -FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, std::function flushForCompile) { - return (FetchFunc)GetByID(id, flushForCompile); +FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, BinManager *binner) { + return (FetchFunc)GetByID(id, binner); } void SamplerJitCache::Compile(const SamplerID &id) { diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 0d14ae12d2..0f8f413453 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -19,7 +19,6 @@ #include "ppsspp_config.h" -#include #include #include #include "Common/Data/Collections/Hashmaps.h" @@ -27,6 +26,8 @@ #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" +class BinManager; + namespace Sampler { // Our std::unordered_map argument will ignore the alignment attribute, but that doesn't matter. @@ -37,13 +38,13 @@ namespace Sampler { #endif typedef Rasterizer::Vec4IntResult(SOFTRAST_CALL *FetchFunc)(int u, int v, const u8 *tptr, int bufw, int level, const SamplerID &samplerID); -FetchFunc GetFetchFunc(SamplerID id, std::function flushForCompile); +FetchFunc GetFetchFunc(SamplerID id, BinManager *binner); typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -NearestFunc GetNearestFunc(SamplerID id, std::function flushForCompile); +NearestFunc GetNearestFunc(SamplerID id, BinManager *binner); typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -LinearFunc GetLinearFunc(SamplerID id, std::function flushForCompile); +LinearFunc GetLinearFunc(SamplerID id, BinManager *binner); void Init(); void FlushJit(); @@ -56,9 +57,9 @@ public: SamplerJitCache(); // Returns a pointer to the code to run. - NearestFunc GetNearest(const SamplerID &id, std::function flushForCompile); - LinearFunc GetLinear(const SamplerID &id, std::function flushForCompile); - FetchFunc GetFetch(const SamplerID &id, std::function flushForCompile); + NearestFunc GetNearest(const SamplerID &id, BinManager *binner); + LinearFunc GetLinear(const SamplerID &id, BinManager *binner); + FetchFunc GetFetch(const SamplerID &id, BinManager *binner); void Clear() override; void Flush(); @@ -66,7 +67,7 @@ public: private: void Compile(const SamplerID &id); - NearestFunc GetByID(const SamplerID &id, std::function flushForCompile); + NearestFunc GetByID(const SamplerID &id, BinManager *binner); FetchFunc CompileFetch(const SamplerID &id); NearestFunc CompileNearest(const SamplerID &id); LinearFunc CompileLinear(const SamplerID &id); diff --git a/unittest/TestSoftwareGPUJit.cpp b/unittest/TestSoftwareGPUJit.cpp index d0d08ba3a2..5d7c6946d4 100644 --- a/unittest/TestSoftwareGPUJit.cpp +++ b/unittest/TestSoftwareGPUJit.cpp @@ -18,6 +18,7 @@ #include "Common/Data/Random/Rng.h" #include "Common/StringUtils.h" #include "Core/Config.h" +#include "GPU/Software/BinManager.h" #include "GPU/Software/DrawPixel.h" #include "GPU/Software/Sampler.h" #include "GPU/Software/SoftGpu.h" @@ -25,21 +26,22 @@ static bool TestSamplerJit() { using namespace Sampler; SamplerJitCache *cache = new SamplerJitCache(); + BinManager binner; auto GetLinear = [&](SamplerID &id) { id.linear = true; id.fetch = false; - return cache->GetLinear(id, [] {}); + return cache->GetLinear(id, &binner); }; auto GetNearest = [&](SamplerID &id) { id.linear = false; id.fetch = false; - return cache->GetNearest(id, [] {}); + return cache->GetNearest(id, &binner); }; auto GetFetch = [&](SamplerID &id) { id.linear = false; id.fetch = true; - return cache->GetFetch(id, [] {}); + return cache->GetFetch(id, &binner); }; GMRng rng; @@ -111,6 +113,7 @@ static bool TestSamplerJit() { static bool TestPixelJit() { using namespace Rasterizer; PixelJitCache *cache = new PixelJitCache(); + BinManager binner; GMRng rng; int successes = 0; @@ -134,7 +137,7 @@ static bool TestPixelJit() { continue; i++; - SingleFunc func = cache->GetSingle(id, [] {}); + SingleFunc func = cache->GetSingle(id, &binner); SingleFunc genericFunc = cache->GenericSingle(id); if (func != genericFunc) { successes++; From 400f6abf9a441332551b123c7ac8aa3b6ce88494 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 19:16:19 -0800 Subject: [PATCH 605/715] softgpu: Optimize lookup of last jit func. This is common (for example, maybe a pixel state is updated but sampler is not), and reduces time spent in ComputeRasterizerState() quite a bit in Darkstalkers, where jits are available (i.e. Intel currently.) --- GPU/Software/DrawPixel.cpp | 10 +++++++-- GPU/Software/DrawPixel.h | 7 +++++++ GPU/Software/Sampler.cpp | 43 ++++++++++++++++++++++++++++++-------- GPU/Software/Sampler.h | 11 +++++++++- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index 341ba80f7b..60a96b8450 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -791,11 +791,15 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { if (!g_Config.bSoftwareRenderingJit) return nullptr; - std::unique_lock guard(jitCacheLock); const size_t key = std::hash()(id); + auto last = lastSingle_.load(); + if (last.key == key) + return last.func; + std::unique_lock guard(jitCacheLock); auto it = cache_.Get(key); if (it != nullptr) { + lastSingle_ = { key, it }; return it; } @@ -821,7 +825,9 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { if (!cache_.Get(key)) Compile(id); - return cache_.Get(key); + it = cache_.Get(key); + lastSingle_ = { key, it }; + return it; } void PixelJitCache::Compile(const PixelFuncID &id) { diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index 1e100c81be..bafde030aa 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -19,6 +19,7 @@ #include "ppsspp_config.h" +#include #include #include #include @@ -109,9 +110,15 @@ private: bool Jit_ConvertFrom5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); bool Jit_ConvertFrom4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); + struct LastEntry { + size_t key; + SingleFunc func; + }; + DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; + std::atomic lastSingle_; const u8 *constBlendHalf_11_4s_ = nullptr; const u8 *constBlendInvert_11_4s_ = nullptr; diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 97a47933cc..f2a80fddc6 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -154,13 +154,8 @@ void SamplerJitCache::Flush() { compileQueue_.clear(); } -NearestFunc SamplerJitCache::GetByID(const SamplerID &id, BinManager *binner) { - if (!g_Config.bSoftwareRenderingJit) - return nullptr; - +NearestFunc SamplerJitCache::GetByID(const SamplerID &id, size_t key, BinManager *binner) { std::unique_lock guard(jitCacheLock); - const size_t key = std::hash()(id); - auto it = cache_.Get(key); if (it != nullptr) return it; @@ -191,15 +186,45 @@ NearestFunc SamplerJitCache::GetByID(const SamplerID &id, BinManager *binner) { } NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, BinManager *binner) { - return (NearestFunc)GetByID(id, binner); + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + + const size_t key = std::hash()(id); + auto last = lastNearest_.load(); + if (last.key == key) + return (NearestFunc)last.func; + + auto func = GetByID(id, key, binner); + lastNearest_ = { key, func }; + return (NearestFunc)func; } LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, BinManager *binner) { - return (LinearFunc)GetByID(id, binner); + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + + const size_t key = std::hash()(id); + auto last = lastLinear_.load(); + if (last.key == key) + return (LinearFunc)last.func; + + auto func = GetByID(id, key, binner); + lastLinear_ = { key, func }; + return (LinearFunc)func; } FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, BinManager *binner) { - return (FetchFunc)GetByID(id, binner); + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + + const size_t key = std::hash()(id); + auto last = lastFetch_.load(); + if (last.key == key) + return (FetchFunc)last.func; + + auto func = GetByID(id, key, binner); + lastFetch_ = { key, func }; + return (FetchFunc)func; } void SamplerJitCache::Compile(const SamplerID &id) { diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 0f8f413453..96e9d4c4a8 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -19,6 +19,7 @@ #include "ppsspp_config.h" +#include #include #include #include "Common/Data/Collections/Hashmaps.h" @@ -67,7 +68,7 @@ public: private: void Compile(const SamplerID &id); - NearestFunc GetByID(const SamplerID &id, BinManager *binner); + NearestFunc GetByID(const SamplerID &id, size_t key, BinManager *binner); FetchFunc CompileFetch(const SamplerID &id); NearestFunc CompileNearest(const SamplerID &id); LinearFunc CompileLinear(const SamplerID &id); @@ -128,9 +129,17 @@ private: const u8 *const5551Swizzle_ = nullptr; const u8 *const5650Swizzle_ = nullptr; + struct LastEntry { + size_t key; + NearestFunc func; + }; + DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; + std::atomic lastFetch_; + std::atomic lastNearest_; + std::atomic lastLinear_; }; #if defined(__clang__) || defined(__GNUC__) From eda3ce556e5f3571b59c18575eef4dfadc0d8df7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 20:26:24 -0800 Subject: [PATCH 606/715] softgpu: Avoid atomic structs. Apparently we don't link libatomic and rather than fighting that, I'll just use thread local values. --- GPU/Software/DrawPixel.cpp | 11 ++++++----- GPU/Software/DrawPixel.h | 10 +++++++--- GPU/Software/Sampler.cpp | 25 +++++++++++++------------ GPU/Software/Sampler.h | 14 +++++++++----- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index 60a96b8450..306522312d 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -744,6 +744,8 @@ SingleFunc PixelJitCache::GenericSingle(const PixelFuncID &id) { return nullptr; } +thread_local PixelJitCache::LastCache PixelJitCache::lastSingle_; + // 256k should be plenty of space for plenty of variations. PixelJitCache::PixelJitCache() : CodeBlock(1024 * 64 * 4), cache_(64) { } @@ -792,14 +794,13 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { return nullptr; const size_t key = std::hash()(id); - auto last = lastSingle_.load(); - if (last.key == key) - return last.func; + if (lastSingle_.key == key) + return lastSingle_.func; std::unique_lock guard(jitCacheLock); auto it = cache_.Get(key); if (it != nullptr) { - lastSingle_ = { key, it }; + lastSingle_.Set(key, it); return it; } @@ -826,7 +827,7 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { Compile(id); it = cache_.Get(key); - lastSingle_ = { key, it }; + lastSingle_.Set(key, it); return it; } diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index bafde030aa..4bcbf3e834 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -19,7 +19,6 @@ #include "ppsspp_config.h" -#include #include #include #include @@ -110,15 +109,20 @@ private: bool Jit_ConvertFrom5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); bool Jit_ConvertFrom4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); - struct LastEntry { + struct LastCache { size_t key; SingleFunc func; + + void Set(size_t k, SingleFunc f) { + key = k; + func = f; + } }; DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; - std::atomic lastSingle_; + static thread_local LastCache lastSingle_; const u8 *constBlendHalf_11_4s_ = nullptr; const u8 *constBlendInvert_11_4s_ = nullptr; diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index f2a80fddc6..9ad7e9a169 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -98,6 +98,10 @@ FetchFunc GetFetchFunc(SamplerID id, BinManager *binner) { return &SampleFetch; } +thread_local SamplerJitCache::LastCache SamplerJitCache::lastFetch_; +thread_local SamplerJitCache::LastCache SamplerJitCache::lastNearest_; +thread_local SamplerJitCache::LastCache SamplerJitCache::lastLinear_; + // 256k should be enough. SamplerJitCache::SamplerJitCache() : Rasterizer::CodeBlock(1024 * 64 * 4), cache_(64) { } @@ -190,12 +194,11 @@ NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, BinManager *binner) return nullptr; const size_t key = std::hash()(id); - auto last = lastNearest_.load(); - if (last.key == key) - return (NearestFunc)last.func; + if (lastNearest_.key == key) + return (NearestFunc)lastNearest_.func; auto func = GetByID(id, key, binner); - lastNearest_ = { key, func }; + lastNearest_.Set(key, func); return (NearestFunc)func; } @@ -204,12 +207,11 @@ LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, BinManager *binner) { return nullptr; const size_t key = std::hash()(id); - auto last = lastLinear_.load(); - if (last.key == key) - return (LinearFunc)last.func; + if (lastLinear_.key == key) + return (LinearFunc)lastLinear_.func; auto func = GetByID(id, key, binner); - lastLinear_ = { key, func }; + lastLinear_.Set(key, func); return (LinearFunc)func; } @@ -218,12 +220,11 @@ FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, BinManager *binner) { return nullptr; const size_t key = std::hash()(id); - auto last = lastFetch_.load(); - if (last.key == key) - return (FetchFunc)last.func; + if (lastFetch_.key == key) + return (FetchFunc)lastFetch_.func; auto func = GetByID(id, key, binner); - lastFetch_ = { key, func }; + lastFetch_.Set(key, func); return (FetchFunc)func; } diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 96e9d4c4a8..cb989e6a32 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -19,7 +19,6 @@ #include "ppsspp_config.h" -#include #include #include #include "Common/Data/Collections/Hashmaps.h" @@ -129,17 +128,22 @@ private: const u8 *const5551Swizzle_ = nullptr; const u8 *const5650Swizzle_ = nullptr; - struct LastEntry { + struct LastCache { size_t key; NearestFunc func; + + void Set(size_t k, NearestFunc f) { + key = k; + func = f; + } }; DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; - std::atomic lastFetch_; - std::atomic lastNearest_; - std::atomic lastLinear_; + static thread_local LastCache lastFetch_; + static thread_local LastCache lastNearest_; + static thread_local LastCache lastLinear_; }; #if defined(__clang__) || defined(__GNUC__) From d9522a7ac5cfdae225ccfbe0baf87e15272f3454 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 20:55:52 -0800 Subject: [PATCH 607/715] softgpu: Avoid clear hazard for last cached funcs. --- GPU/Software/DrawPixel.cpp | 8 +++++--- GPU/Software/DrawPixel.h | 9 ++++++++- GPU/Software/Sampler.cpp | 16 ++++++++++------ GPU/Software/Sampler.h | 9 ++++++++- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index 306522312d..97e84b6807 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -748,9 +748,11 @@ thread_local PixelJitCache::LastCache PixelJitCache::lastSingle_; // 256k should be plenty of space for plenty of variations. PixelJitCache::PixelJitCache() : CodeBlock(1024 * 64 * 4), cache_(64) { + lastSingle_.gen = -1; } void PixelJitCache::Clear() { + clearGen_++; CodeBlock::Clear(); cache_.Clear(); addresses_.clear(); @@ -794,13 +796,13 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { return nullptr; const size_t key = std::hash()(id); - if (lastSingle_.key == key) + if (lastSingle_.Match(key, clearGen_)) return lastSingle_.func; std::unique_lock guard(jitCacheLock); auto it = cache_.Get(key); if (it != nullptr) { - lastSingle_.Set(key, it); + lastSingle_.Set(key, it, clearGen_); return it; } @@ -827,7 +829,7 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { Compile(id); it = cache_.Get(key); - lastSingle_.Set(key, it); + lastSingle_.Set(key, it, clearGen_); return it; } diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index 4bcbf3e834..d72c04a744 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -112,16 +112,23 @@ private: struct LastCache { size_t key; SingleFunc func; + int gen = -1; - void Set(size_t k, SingleFunc f) { + bool Match(size_t k, int g) const { + return key == k && gen == g; + } + + void Set(size_t k, SingleFunc f, int g) { key = k; func = f; + gen = g; } }; DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; + int clearGen_ = 0; static thread_local LastCache lastSingle_; const u8 *constBlendHalf_11_4s_ = nullptr; diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 9ad7e9a169..c748260dd4 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -104,9 +104,13 @@ thread_local SamplerJitCache::LastCache SamplerJitCache::lastLinear_; // 256k should be enough. SamplerJitCache::SamplerJitCache() : Rasterizer::CodeBlock(1024 * 64 * 4), cache_(64) { + lastFetch_.gen = -1; + lastNearest_.gen = -1; + lastLinear_.gen = -1; } void SamplerJitCache::Clear() { + clearGen_++; CodeBlock::Clear(); cache_.Clear(); addresses_.clear(); @@ -194,11 +198,11 @@ NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, BinManager *binner) return nullptr; const size_t key = std::hash()(id); - if (lastNearest_.key == key) + if (lastNearest_.Match(key, clearGen_)) return (NearestFunc)lastNearest_.func; auto func = GetByID(id, key, binner); - lastNearest_.Set(key, func); + lastNearest_.Set(key, func, clearGen_); return (NearestFunc)func; } @@ -207,11 +211,11 @@ LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, BinManager *binner) { return nullptr; const size_t key = std::hash()(id); - if (lastLinear_.key == key) + if (lastLinear_.Match(key, clearGen_)) return (LinearFunc)lastLinear_.func; auto func = GetByID(id, key, binner); - lastLinear_.Set(key, func); + lastLinear_.Set(key, func, clearGen_); return (LinearFunc)func; } @@ -220,11 +224,11 @@ FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, BinManager *binner) { return nullptr; const size_t key = std::hash()(id); - if (lastFetch_.key == key) + if (lastFetch_.Match(key, clearGen_)) return (FetchFunc)lastFetch_.func; auto func = GetByID(id, key, binner); - lastFetch_.Set(key, func); + lastFetch_.Set(key, func, clearGen_); return (FetchFunc)func; } diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index cb989e6a32..fbe606b110 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -131,16 +131,23 @@ private: struct LastCache { size_t key; NearestFunc func; + int gen = -1; - void Set(size_t k, NearestFunc f) { + bool Match(size_t k, int g) const { + return key == k && gen == g; + } + + void Set(size_t k, NearestFunc f, int g) { key = k; func = f; + gen = g; } }; DenseHashMap cache_; std::unordered_map addresses_; std::unordered_set compileQueue_; + int clearGen_ = 0; static thread_local LastCache lastFetch_; static thread_local LastCache lastNearest_; static thread_local LastCache lastLinear_; From 64396a5108da90c95514de2313457fdd1ed71932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Dec 2022 20:49:02 +0100 Subject: [PATCH 608/715] Few more icons More icons --- assets/ui_atlas.meta | Bin 1106 -> 1250 bytes assets/ui_atlas.zim | Bin 58080 -> 65218 bytes source_assets/image/arrow_down.png | Bin 0 -> 1490 bytes source_assets/image/arrow_left.png | Bin 0 -> 1593 bytes source_assets/image/arrow_right.png | Bin 0 -> 1567 bytes source_assets/image/arrow_up.png | Bin 0 -> 1561 bytes source_assets/image/buttons.svg | 235 +++++++++++++++++++++++++-- source_assets/image/plus.png | Bin 0 -> 1548 bytes source_assets/image/rotate_left.png | Bin 0 -> 1142 bytes source_assets/image/rotate_right.png | Bin 0 -> 1114 bytes source_assets/image/sliders.png | Bin 0 -> 1915 bytes source_assets/image/three_dots.png | Bin 0 -> 1005 bytes ui_atlasscript.txt | 11 +- 13 files changed, 234 insertions(+), 12 deletions(-) create mode 100644 source_assets/image/arrow_down.png create mode 100644 source_assets/image/arrow_left.png create mode 100644 source_assets/image/arrow_right.png create mode 100644 source_assets/image/arrow_up.png create mode 100644 source_assets/image/plus.png create mode 100644 source_assets/image/rotate_left.png create mode 100644 source_assets/image/rotate_right.png create mode 100644 source_assets/image/sliders.png create mode 100644 source_assets/image/three_dots.png diff --git a/assets/ui_atlas.meta b/assets/ui_atlas.meta index a1d7df260c878b94ba06cd9c41af8b2948d2b96f..88c386e49193d5c77ed88392508cb5a494771029 100644 GIT binary patch literal 1250 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 YX<#%KNAdm6)L2_K-(Y!~vQKUI0T8GkWB>pF diff --git a/assets/ui_atlas.zim b/assets/ui_atlas.zim index 5b8b17995c2e3a7d769c014b15f91d5673147c1f..465d54e6f0a413267f9fe947899151ae11d2a0e9 100644 GIT binary patch delta 63843 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 delta 56608 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 %`J{eO)U2?shrQU0IkbWF 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 literal 0 HcmV?d00001 diff --git a/source_assets/image/arrow_right.png b/source_assets/image/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..5181723f989773483a14896177eab6cbc14980af GIT binary patch literal 1567 zcmV+)2H^RLP)q+axUt;zjXP zC0Ppr(~BTMlpcyuy!5#D9twho2$D91f_rIoqYw~8Jp@u44J8C5(%Lqf5KXc>yR$Qy z+28BI#BO5}vu4vC>K6uv_nUdY&%EF7z26()t=_6KF|!yR9+ za*d3P7%eR=ZB0#0T>xq>T)1Ft#b4C{rIe~|+wWPH^=VH}&-nuf4m73H>ByV=nPC{lhXBN(Lx*U`jvf8U zWO6>4OuCi$t9k?hKv9&JehtIuuq>;4@7}#S}9i>zkRGiKJ4g*DiO}0S&{@N~Kas2(dbA2>>FI zNT+34$4{R=eg5#_!%dk?rsm%U6aXYM^BTkdh-4y>IBi+h&W%b?wE<~vZY~f)M3`Bw z_Y44-rr8mVMw9LB?VojZb?scQn7>j7Q>m2Lw{M@>+}vC*rBox42<39Q5CCGan3m0E zgXIY{RaIp^pDzg^$hK{Dc6K&U6eTKzhzlV$+FwLOFbtyu03AGdkf*1oFQ?P#C%wJB zOB(_L5N&O3AI0PGj{!6RpyuZ0B`Ku1P!y$A z2w`mixDrV=4C8}nG+Giu;O^bKU!~J<a?$w}yv@YZHk?PhDNzm#V5ZEN>-R{^}9{ zg_)U%7yw?}5&%fN*fK;!8W9;pw3(BN0l@eDU-J2U=Fy`^mmfcVJk#6TTU;}O@pxP% zB3;+@79y(M(;H{$dM!AD@pS7>C+$x0t&PfX(==99HNIJ&*m@Kh06fnd za~$XD`1ts>(a}+NO+d$SO7->iK@bFgDvHur20-{b5txXWnODFFfTR~j5<;i|bRtq# z`(F>v_x%U?e17QR!-s>quIEyzRJbM}08dK!d$Cx|5YfBLtPoKVfRIvJL{wNV!X^<( zX7-6lV`h_x3IKFfRd+`sk@tz{b)|*@aIsh%a~x;r%9Sf$&(F_$sZ{D^nRx~9_U+qp zX=&-Fcs%|G0F8(!pU;Pyrg1D5)3e#^QV;}W+qNd9l!Zc}WSS-!hM_GiEcm8rMtAMn z^@*lwXLViQ2#^7=@B0rN$GJ8&H8r>z?scNFtK7EUH~|ppbUHRYJ^i`w`@iw}l2Xdh zb=`Zjv$LtISFgUaUi-CC7IWEEZd-4h0m%CLdQD2X(y*@U*Ymvl`F#F|@$vCX*RNln z@9XRHDg}Ha`Mxg!h?V1IEjZuz#|wqR(B$Og;Ns%q!lg@>f;FB6unj*=zV8Q$q9{_z z)sr#+EGI!1j0II4= zK@fP$jRgQOGqdmeW4T;zD3i%tbX~V_?%X+lQ~s(An9JpsOw(LxSXUx9md$2=oSdBe zc64;q*-YfN4KNmqF*Co6Ua?qw;5g3E#Kgom&!0b^uLN#e0Cip0T-S9JMPbkLe$M4` z*Y4c8(|_~k&BaRLwgphrv{G$tt?s(+xbOS-CnhGoD-;S9Eo-?pbC_48qeqV_b#-+h zq9+3b1K*pbxp4C2$xS81TBeL%W?ydee`U_<%u6_x_ R#E}31002ovPDHLkV1iUn=IsCg literal 0 HcmV?d00001 diff --git a/source_assets/image/arrow_up.png b/source_assets/image/arrow_up.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9fb9714d434bfd1d12412cb38038e8594dfbb6 GIT binary patch literal 1561 zcmV+!2Il#RP)JR6Gs%s-`iR5?Aq&HvxXD|O>zi1L%W0p)T+L4!APyrUJylcE>SKC32HzTP}HW-Cb%YX9J0UX z^((thpU(%|;kzw> zrBX@tJkQ8vG6MiWckbNzsambp1_uZ2sNO89K|Y^Xy1Tpg_Vn~zPNh;8RaNazr_+Y- z`w!dO+wGB&k#NTV^ZC4DS(bY8JFJsI|BogtNnVIpUM~_le$StW< zDygHRqaEdPIqx{mBoT?m%W<6B^YimxkB*LZ6bc1(tMhEBg1KBScHqE)R5qLaRM+*h zs;c(YA7T9hS(f)ol9beSU48oW>9lE@-o(U&XmzfZLsBdjwRAdd9X@>cax$45;GAa~ z!5TyWK(6af)oQgLCnqPrSzKIPXf-%3RWO&!#f}|2*4ES0^Rce$=jxSf1_$tOCHEns zVObWpZTpd;D0VBA+%({oD_3|rosOSAefslcGC82CY8DaKgIf*x7GumbO*3KJ_T+^N z7sU1J*S9Y?g+f6c8yo8^m&;$du6w&744ai8qR?@iiTU~YFUQBn+l$4bvYEMGTftl| z7qcuYdE&&0%gJQ&Ea&{4`lD9%@5|sY#*&(*spI40Q~mw@!N|zShReO-B*kJ;Gfi`M zHkSjCKxr-BYJd-M4LfMv^31*LA;A zslc8+dt$EZilwEckaHf3$K&k5g9l-6Z|~a&4<76!qMp_3M?`_|`!kOpKmLAdYU;P{ z?ryfSvJ$$k>l=o_IOkHiT=vuHG!T)Dh=K3>{=IwmywzS?6_!e+&V_}AZ-XFMSpDh< zf}pyvuyD0hDs{oCz21tp{6zo&%d&VFhAIH8>0yW{03hDh)}}zcL2pG-0Lk+_pE2e( z^C2P$5gpI-{G9?sAp{XoSO;i?AVefY^p}>F03x)hNJ}isG9#iFr;kByj4Y7V#6?G z0N~IBkca>gRnB<~cB&878@1Q~K*+KjsfzOJhpa0?L?03V41!=@k|ZSvf@c5#vMgI+ z7|sbH{_uT2(*J}}0O84#C*@Qsbz^yX`JpV!F(Cv307#NVK@bF<=lx!(ROTQ;NFo7F zOiVbsu8#r0 + + + + + + + + x="-2.726912" + y="-3.7985277" /> + inkscape:export-ydpi="135" + transform="translate(34.285714,-2.1428571)"> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source_assets/image/plus.png b/source_assets/image/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..f65fb9c48c0354ae2f5a82459edfbf6bf89e28fb GIT binary patch literal 1548 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 IM6N<$f)vpnK>z>% literal 0 HcmV?d00001 diff --git a/source_assets/image/rotate_right.png b/source_assets/image/rotate_right.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd4933fd682b396152fe55041a17b197f26309d GIT binary patch literal 1114 zcmV-g1f~0lP)^qHa4D#Mx%2>B|kho{K7QNmOXJlNs_dk zNF-ji$BRTF*Q(WOj%C@`&IKR{!dk1 z6NJy_3wS)9mwG`q8jYiJx%{mx%dDnpC4wND2qE9p)YQWC^z~@QkkO51kx}#bS)(xT}Kz zI+e*}K5Vz!W-o|TDzyS&Ylq+OzfY3n6ZT-DD2C?e=U0XS003~gTr)V16TR%FX?EK} zq0p?;K2WdMf1zpm%CG>tySpDFgsgt;*xcNFyUS^BZ|_rwbygygxHBxk&d$#JmSwdE zy%Wh~@*RMVc2E@csy$exQrTTxTx5m;KnP)(Oy=oaF82ul06`E_7=}5v#4wDXx*QF| z_}fk@2*O9h09;f!06;t*_fJeroO$zWwc6L?fB*mhmSu0-tI%$@4TR80NBwz)0|1aD zdChLnbzQ+Q42=y!*LBTqaJgJ=gb+S92+OicXAC$_FbwnTI3NH303n1w_OAoOFze*x z-RSjt7g(0PJq{260Ek2)zRNs2I>qz+U6y5EIM?EXgM%-f z_V_}fuyIjy<{~ij3W;@qAZp)%5els^Wx7;g9qtW=a zTrPhn%W^_h)e=dP4{;oS&h2(TPf^qgMNtdAh8a~=<#amz%F@zOzVAQzucmE9Q68`? zduvc7ABm>vE1h?QQ6s zJkP&5QgSDlY&LsOlBATPC}(cvhGD4ndVPO?fB*AgdOy<85)1~fPfkwGn5Ic8it^{` g>Z&wKyvM4403a-cF#X&OZU6uP07*qoM6N<$f-vO++5i9m literal 0 HcmV?d00001 diff --git a/source_assets/image/sliders.png b/source_assets/image/sliders.png new file mode 100644 index 0000000000000000000000000000000000000000..2ec872f0ff88f1e8d62d31ec5ec888d2b952cb45 GIT binary patch literal 1915 zcmV->2ZZ>EP){0RM`>!>YUT}(bw(nw%sO;J;TFD2qEPG3s__( zA<8VmBGQP6$vYS>tf%kZi|5MPrjyFF)?@dfhl*h-%%TW{!jWPD( z#f!bOXV3EgjM&1$g7G|WcK`nUztCFOthF}FvfHgzYvIU|Bki||Wp;S~HiQX)0FZXO zT{?dJ`1dN6$|=wDevoC^N|GcOZ{50e`5R)&3vpf{Mpv(1ZA?y1*4Nh7@=m9d?cTjR z0DzU1m8j8ZxSr=ZPoF*=q-knrW@g5$wf6Dj$MNj!tn0ci9zA*#T5F-To+cuvR4Pp; zNisD)K0fuu7hh1j-PV(nlYvr7EiW&JwOY+gOiXy4PA86{sJpST5uQGMI^9O>&Ye5o znVz2h)EM*QX0w?CU=i^F@Z8*7N<>OT+2M%OJR3f6hUax=N>-9na zIRFw70#NciuRc3F`}4WExdS2+05EfNa|01k0KDD1cXzF|H}2fIGY{Yy0NEl&L=|Jq z(MqNABLJR=fQUxHd2$*n) zc%#yfVls0y7z~W#IDaXKZDoww?RI}=W@a2fSt&L44d?0=F!Mlb?OAKL-9Duhf*=?d z5u>%90H9v>rA;(ywVFSAHzFpDMx&DFd7GKLA~F;aCL&#AEC-;AjL8exQ~+`!(#+gv z=6;rCeIgo>QzGIfNs)AZdv&qRx4*=HI)?&wToLa4B zo<4n=5Rq*(8h)PVyt=xY?%K7hQ4~EWO6!-) zWoozEL*MuH*w~m8hG80pVdVS%;7yJV?eM&#ZDC=-yM6oi592ugTaqMSrfGVw)9L(f zX=&-e8^qj(of<6gLbH46c}H8j-Oj4j>ci#b<=;4tGo7aChSs|C)mL9Vd4rhS@UCYi z=I7@%0O!e*Cw%bWL1V4WPo6xPyz715<7IrSQeL@or6RI9HGJRa8#itY&YU@uy-Q;H zZ5^&%yEfizHjh>+mG3qhjqi_*jm;Wkp6%JQC%$y)(pzb+ufx~fN?^MbApjBtLA6?~ zeij75M@p%hwf0GpBvG^3yoAjO@otGNEG(FfjSauqYzD>{x7BK;%$!e8Py5U)&z?Pt zeczW>tEKkt-PU1zB_fk$*}ePs@BdmUl}t@d9VH@f)*>RdAYO4@*CnEg*1ASSzSi0s zRYPm-^oAZ)s^MDs0b%;`;jfaAs!aS+Ph8xibn#0AeD_l~Qc2B_h&= z^yw!_k{V+YW)7Lz15he_b8PA_Rb)m0m_lggM5K$-_C;h+tyZ^g^%gP5ak_CF|BIO| zfObKm#9R;!i7ahx}s&A?jA-EMa|Q4rK*)mg&#b4@b_M?_YbYL&huP}h?Ght84ic+x^9Vxav~yT*2ND)nx-(u zXlrd^jET>kJ2x8k&ofs1JLv#e!_E^yu3x|Yp|!S?W!bV)s>;l(%-j#duyx|Zi2+{I z`(E(h$@cQPR~oFm^!*CbG!5f8{$m)1w;acDM5MF2x_WzMWhHx!?;FXb*X{SMX64PB zH|vAJzzM?;wOY-#TCM)clPA;HZSWrN@g8r9{{oehvC@3kbx!~Q002ovPDHLkV1h*- BxPAZt literal 0 HcmV?d00001 diff --git a/source_assets/image/three_dots.png b/source_assets/image/three_dots.png new file mode 100644 index 0000000000000000000000000000000000000000..9001c4fc1799530e3fe4838bd6ac5e917cf99979 GIT binary patch literal 1005 zcmVK>10`~_p2jXX(Yp@3FMi?kPf$SH~t zH;(o(zaUcn0rEXJBz^*yxmqHTbKu4S36ikV!UhC!4hAiXy)0vUx~IE32kZ&9QN9jQ z-er19^?K@6z3B${KL7!M0RXGjYJ9ZDr;?KO!NGwigeX)hl~2Mj9Gsn<-L9^#egpt= zYisLOtya_ZdRwzt(Fn-W81c$KdQzs#y)TyX8{0g0FW@M9{>Or7Zkr1!0u5>z`&KP3^0GLNP1`!MSeBN;!C#fXSxU{qcaUB0fL|rLm8vrasRK^%a zM88TY@B00|njwZ^sP69WE-lOY#&MjoQc6Wp6lJs7j4|fj`T6;eQp#i$6N3$c!1g@P z4Z{#!*JVV+g%I)l{Jgroy_NNPT|PHpe*d`HY&x5pn}Z2rrBY!;#5w0B&UtPW&Hw;tt%q?Or#hWZ zA}b;C2OwkY*|c^d>NCcy>+9>JtBG^;0}K(p9d+;zUow^@B2_MzXaA0NyG_Oz(pvWr z@!4ooInu~dsg&}4f40ck+-E#m?Gjn`|f9{;Uy}fjyP_P+esli}?N-3k1GR0yMTdmf+ zMx&85Eg=R$z*kmQe9!Yf2Y?J?42Q#^|2(#VB2;{Yt4)?5$D`Ej$^l4twYcA#LV3>#-kgG)oL|9ddKOH b{P*}BtG3BTapgXY00000NkvXXu0mjfa-_@F literal 0 HcmV?d00001 diff --git a/ui_atlasscript.txt b/ui_atlasscript.txt index 14d0cd2ac9..eead48f3f2 100644 --- a/ui_atlasscript.txt +++ b/ui_atlasscript.txt @@ -60,4 +60,13 @@ image I_SQUARE_SHAPE source_assets/image/square_shape.png copy image I_SQUARE_SHAPE_LINE source_assets/image/square_shape_line.png copy image I_FOLDER_OPEN source_assets/image/folder_open_line.png copy image I_WARNING source_assets/image/warning.png copy -image I_TRASHCAN source_assets/image/trashcan.png copy \ No newline at end of file +image I_TRASHCAN source_assets/image/trashcan.png copy +image I_PLUS source_assets/image/plus.png copy +image I_ROTATE_LEFT source_assets/image/rotate_left.png copy +image I_ROTATE_RIGHT source_assets/image/rotate_right.png copy +image I_ARROW_LEFT source_assets/image/arrow_left.png copy +image I_ARROW_RIGHT source_assets/image/arrow_right.png copy +image I_ARROW_UP source_assets/image/arrow_up.png copy +image I_ARROW_DOWN source_assets/image/arrow_down.png copy +image I_SLIDERS source_assets/image/sliders.png copy +image I_THREE_DOTS source_assets/image/three_dots.png copy From 82680633e7ef451273fb2161e787579df42c737c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 5 Dec 2022 13:19:22 +0100 Subject: [PATCH 609/715] More usability tweaks --- Common/UI/ViewGroup.cpp | 6 +++++- Common/UI/ViewGroup.h | 2 ++ UI/DisplayLayoutScreen.cpp | 15 +++++++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index eefb93d82f..00d5c41f34 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -100,7 +100,11 @@ bool ViewGroup::Touch(const TouchInput &input) { } } } - return any; + if (clickableBackground_) { + return any || bounds_.Contains(input.x, input.y); + } else { + return any; + } } void ViewGroup::Query(float x, float y, std::vector &list) { diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 05fe046681..78c42e84b1 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -78,6 +78,7 @@ public: void SetHasDropShadow(bool has) { hasDropShadow_ = has; } void SetDropShadowExpand(float s) { dropShadowExpand_ = s; } void SetExclusiveTouch(bool exclusive) { exclusiveTouch_ = exclusive; } + void SetClickableBackground(bool clickableBackground) { clickableBackground_ = clickableBackground; } void Lock() { modifyLock_.lock(); } void Unlock() { modifyLock_.unlock(); } @@ -96,6 +97,7 @@ protected: Drawable bg_; float dropShadowExpand_ = 0.0f; bool hasDropShadow_ = false; + bool clickableBackground_ = false; bool clip_ = false; bool exclusiveTouch_ = false; }; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 34a4d3d3f4..24d0c87301 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -43,8 +43,9 @@ static const int leftColumnWidth = 200; static const float orgRatio = 1.764706f; // 480.0 / 272.0 enum Mode { - MODE_MOVE, - MODE_RESIZE, + MODE_INACTIVE = 0, + MODE_MOVE = 1, + MODE_RESIZE = 2, }; static Bounds FRectToBounds(FRect rc) { @@ -198,11 +199,13 @@ void DisplayLayoutScreen::CreateViews() { ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL); leftScrollView->Add(leftColumn); + leftScrollView->SetClickableBackground(true); root_->Add(leftScrollView); ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.f, 10.f, false)); ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL); rightScrollView->Add(rightColumn); + rightScrollView->SetClickableBackground(true); root_->Add(rightScrollView); LinearLayout *bottomControls = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, NONE, NONE, 10.0f, false)); @@ -219,6 +222,7 @@ void DisplayLayoutScreen::CreateViews() { aspectRatio->SetLiveUpdate(true); mode_ = new ChoiceStrip(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + mode_->AddChoice(di->T("Inactive")); mode_->AddChoice(di->T("Move")); mode_->AddChoice(di->T("Resize")); mode_->SetSelection(0, false); @@ -290,16 +294,19 @@ void DisplayLayoutScreen::CreateViews() { // Disable duplicated shader slider bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end(); alreadyAddedShader.insert(shaderInfo->section); + + LinearLayout *settingContainer = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT, UI::Margins(24.0f, 0.0f, 0.0f, 0.0f))); + leftColumn->Add(settingContainer); for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { auto &setting = shaderInfo->settings[i]; if (!setting.name.empty()) { auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; if (duplicated) { auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); - PopupSliderChoiceFloat *settingValue = leftColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); + PopupSliderChoiceFloat *settingValue = settingContainer->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); settingValue->SetEnabled(false); } else { - PopupSliderChoiceFloat *settingValue = leftColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + PopupSliderChoiceFloat *settingValue = settingContainer->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetLiveUpdate(true); settingValue->SetHasDropShadow(false); settingValue->SetEnabledFunc([=] { From aed5d76fbc944ce5bcb968b680e149e6a3b53eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 5 Dec 2022 17:04:16 +0100 Subject: [PATCH 610/715] Make the post shader list more editable --- Common/UI/View.cpp | 6 +- Common/UI/View.h | 5 ++ Common/UI/ViewGroup.cpp | 1 + GPU/Common/PostShader.h | 4 +- UI/DisplayLayoutScreen.cpp | 109 ++++++++++++++++++++++++++++++++++--- UI/DisplayLayoutScreen.h | 21 +++++++ UI/MiscScreens.cpp | 39 ------------- UI/MiscScreens.h | 17 ------ 8 files changed, 135 insertions(+), 67 deletions(-) diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index cf741f5884..87ae8a640a 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -16,6 +16,7 @@ #include "Common/System/System.h" #include "Common/TimeUtil.h" #include "Common/StringUtils.h" +#include "Common/Log.h" namespace UI { @@ -24,7 +25,6 @@ static constexpr float MIN_TEXT_SCALE = 0.8f; static constexpr float MAX_ITEM_SIZE = 65535.0f; void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured) { - *measured = sz; if (sz == WRAP_CONTENT) { if (spec.type == UNSPECIFIED) *measured = contentWidth; @@ -40,6 +40,8 @@ void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measure *measured = spec.size; } else if (spec.type == EXACTLY || (spec.type == AT_MOST && *measured > spec.size)) { *measured = spec.size; + } else { + *measured = sz; } } @@ -412,7 +414,7 @@ void ClickableItem::GetContentDimensions(const UIContext &dc, float &w, float &h } ClickableItem::ClickableItem(LayoutParams *layoutParams) : Clickable(layoutParams) { - if (!layoutParams) { + if (!layoutParams && autoExpand_) { if (layoutParams_->width == WRAP_CONTENT) layoutParams_->width = FILL_PARENT; } diff --git a/Common/UI/View.h b/Common/UI/View.h index 64c9cdacf8..fb26db156f 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -692,6 +692,11 @@ public: // Draws the item background. void Draw(UIContext &dc) override; + + void SetAutoExpand(bool autoExpand) { autoExpand_ = autoExpand; } + +private: + bool autoExpand_ = true; }; // Use to trigger something or open a submenu screen. diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 00d5c41f34..9c7960f2fe 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1593,6 +1593,7 @@ StickyChoice *ChoiceStrip::Choice(int index) { return static_cast(views_[index]); return nullptr; } + ListView::ListView(ListAdaptor *a, std::set hidden, LayoutParams *layoutParams) : ScrollView(ORIENT_VERTICAL, layoutParams), adaptor_(a), maxHeight_(0), hidden_(hidden) { diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index ef4e2c83b5..06fc69a159 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -19,11 +19,11 @@ // Postprocessing shader manager // For FXAA, "Natural", bloom, B&W, cross processing and whatnot. +#pragma once + #include #include -#include "Common/Data/Format/IniFile.h" - struct ShaderInfo { Path iniFile; // which ini file was this definition in? So we can write settings back later std::string section; // ini file section. This is saved. diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 24d0c87301..fd80fa8daf 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -37,7 +37,6 @@ #include "Core/System.h" #include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" -#include "GPU/Common/PostShader.h" static const int leftColumnWidth = 200; static const float orgRatio = 1.764706f; // 480.0 / 272.0 @@ -196,7 +195,7 @@ void DisplayLayoutScreen::CreateViews() { // impossible. root_->SetExclusiveTouch(true); - ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); + ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(400.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL); leftScrollView->Add(leftColumn); leftScrollView->SetClickableBackground(true); @@ -255,8 +254,6 @@ void DisplayLayoutScreen::CreateViews() { static const char *bufFilters[] = { "Linear", "Nearest", }; leftColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); - leftColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); - Draw::DrawContext *draw = screenManager()->getDrawContext(); bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; @@ -265,12 +262,22 @@ void DisplayLayoutScreen::CreateViews() { return g_Config.bStereoRendering && multiViewSupported; }; + leftColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); + std::set alreadyAddedShader; + settingsVisible_.resize(g_Config.vPostShaderNames.size()); + for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; - leftColumn->Add(new ItemHeader(StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1))); - postProcChoice_ = leftColumn->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName)); + + // TODO: I want to set UI::FILL_PARENT or an explicit width here, but breaks badly??? + LinearLayout *shaderRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::WRAP_CONTENT, UI::WRAP_CONTENT)); + shaderRow->SetSpacing(4.0f); + leftColumn->Add(shaderRow); + + postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f))); + postProcChoice_->SetAutoExpand(false); postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); @@ -285,11 +292,61 @@ void DisplayLayoutScreen::CreateViews() { return !g_Config.bSkipBufferEffects && !enableStereo(); }); + if (i < g_Config.vPostShaderNames.size()) { + bool hasSettings = false; + std::vector shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + for (auto shaderInfo : shaderChain) { + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + hasSettings = true; + break; + } + } + } + if (hasSettings) { + auto settingsButton = shaderRow->Add(new Choice(ImageID("I_SLIDERS"))); + settingsButton->OnClick.Add([=](EventParams &e) { + settingsVisible_[i] = !settingsVisible_[i]; + RecreateViews(); + return UI::EVENT_DONE; + }); + } + } + + if (i > 0 && i < g_Config.vPostShaderNames.size()) { + auto upButton = shaderRow->Add(new Choice(ImageID("I_ARROW_UP"))); + upButton->OnClick.Add([=](EventParams &e) { + std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]); + RecreateViews(); + return UI::EVENT_DONE; + }); + } + if (i < g_Config.vPostShaderNames.size() - 1) { + auto downButton = shaderRow->Add(new Choice(ImageID("I_ARROW_DOWN"))); + downButton->OnClick.Add([=](EventParams &e) { + std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]); + RecreateViews(); + return UI::EVENT_DONE; + }); + } + if (i < g_Config.vPostShaderNames.size()) { + auto deleteButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"))); + deleteButton->OnClick.Add([=](EventParams &e) { + g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); + RecreateViews(); + return UI::EVENT_DONE; + }); + } + // No need for settings on the last one. if (i == g_Config.vPostShaderNames.size()) continue; - auto shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + if (!settingsVisible_[i]) + continue; + + std::vector shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); for (auto shaderInfo : shaderChain) { // Disable duplicated shader slider bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end(); @@ -300,6 +357,7 @@ void DisplayLayoutScreen::CreateViews() { for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { auto &setting = shaderInfo->settings[i]; if (!setting.name.empty()) { + // This map lookup will create the setting in the mPostShaderSetting map if it doesn't exist, with a default value of 0.0. auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; if (duplicated) { auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); @@ -320,3 +378,40 @@ void DisplayLayoutScreen::CreateViews() { root_->Add(new DisplayLayoutBackground(mode_, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, 0.0f, 0.0f, 0.0f, 0.0f))); } + +void PostProcScreen::CreateViews() { + auto ps = GetI18NCategory("PostShaders"); + ReloadAllPostShaderInfo(screenManager()->getDrawContext()); + shaders_ = GetAllPostShaderInfo(); + std::vector items; + int selected = -1; + const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_]; + + for (int i = 0; i < (int)shaders_.size(); i++) { + if (!shaders_[i].visible) + continue; + if (shaders_[i].isStereo != showStereoShaders_) + continue; + if (shaders_[i].section == selectedName) + selected = (int)indexTranslation_.size(); + items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); + indexTranslation_.push_back(i); + } + adaptor_ = UI::StringVectorListAdaptor(items, selected); + ListPopupScreen::CreateViews(); +} + +void PostProcScreen::OnCompleted(DialogResult result) { + if (result != DR_OK) + return; + const std::string &value = shaders_[indexTranslation_[listView_->GetSelected()]].section; + // I feel this logic belongs more in the caller, but eh... + if (showStereoShaders_) { + g_Config.sStereoToMonoShader = value; + } else { + if (id_ < (int)g_Config.vPostShaderNames.size()) + g_Config.vPostShaderNames[id_] = value; + else + g_Config.vPostShaderNames.push_back(value); + } +} diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 690bbfde55..d55d89d462 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -19,6 +19,8 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "GPU/Common/PostShader.h" + #include "MiscScreens.h" class DisplayLayoutScreen : public UIDialogScreenWithGameBackground { @@ -45,4 +47,23 @@ private: UI::ChoiceStrip *mode_ = nullptr; UI::Choice *postProcChoice_ = nullptr; std::string shaderNames_[256]; + std::vector settingsVisible_; +}; + +class PostProcScreen : public ListPopupScreen { +public: + PostProcScreen(const std::string &title, int id, bool showStereoShaders) + : ListPopupScreen(title), id_(id), showStereoShaders_(showStereoShaders) { } + + void CreateViews() override; + + const char *tag() const override { return "PostProc"; } + +private: + void OnCompleted(DialogResult result) override; + bool ShowButtons() const override { return true; } + std::vector shaders_; + int id_; + bool showStereoShaders_; + std::vector indexTranslation_; }; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 505897dba6..e00ec856a0 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -551,45 +551,6 @@ void PromptScreen::TriggerFinish(DialogResult result) { UIDialogScreenWithBackground::TriggerFinish(result); } -PostProcScreen::PostProcScreen(const std::string &title, int id, bool showStereoShaders) : ListPopupScreen(title), id_(id), showStereoShaders_(showStereoShaders) { } - -void PostProcScreen::CreateViews() { - auto ps = GetI18NCategory("PostShaders"); - ReloadAllPostShaderInfo(screenManager()->getDrawContext()); - shaders_ = GetAllPostShaderInfo(); - std::vector items; - int selected = -1; - const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_]; - - for (int i = 0; i < (int)shaders_.size(); i++) { - if (!shaders_[i].visible) - continue; - if (shaders_[i].isStereo != showStereoShaders_) - continue; - if (shaders_[i].section == selectedName) - selected = (int)indexTranslation_.size(); - items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); - indexTranslation_.push_back(i); - } - adaptor_ = UI::StringVectorListAdaptor(items, selected); - ListPopupScreen::CreateViews(); -} - -void PostProcScreen::OnCompleted(DialogResult result) { - if (result != DR_OK) - return; - const std::string &value = shaders_[indexTranslation_[listView_->GetSelected()]].section; - // I feel this logic belongs more in the caller, but eh... - if (showStereoShaders_) { - g_Config.sStereoToMonoShader = value; - } else { - if (id_ < (int)g_Config.vPostShaderNames.size()) - g_Config.vPostShaderNames[id_] = value; - else - g_Config.vPostShaderNames.push_back(value); - } -} - TextureShaderScreen::TextureShaderScreen(const std::string &title) : ListPopupScreen(title) {} void TextureShaderScreen::CreateViews() { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index f0eca81ff5..07f544f855 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -109,23 +109,6 @@ private: std::vector langs_; }; -class PostProcScreen : public ListPopupScreen { -public: - PostProcScreen(const std::string &title, int id, bool showStereoShaders); - - void CreateViews() override; - - const char *tag() const override { return "PostProc"; } - -private: - void OnCompleted(DialogResult result) override; - bool ShowButtons() const override { return true; } - std::vector shaders_; - int id_; - bool showStereoShaders_; - std::vector indexTranslation_; -}; - class TextureShaderScreen : public ListPopupScreen { public: TextureShaderScreen(const std::string &title); From 39b627c0c1b52f7a0d0082c6d0c6145489473b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 6 Dec 2022 16:32:56 +0100 Subject: [PATCH 611/715] Fix layout issues, misc cleanup and comments --- Common/UI/UIScreen.cpp | 10 +++++++--- Common/UI/UIScreen.h | 2 +- Common/UI/View.cpp | 3 ++- Common/UI/View.h | 5 ----- Common/UI/ViewGroup.cpp | 16 ++++++++++++---- UI/DisplayLayoutScreen.cpp | 12 +++++------- UI/NativeApp.cpp | 6 +++--- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index c56d09856a..ff30080553 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -814,7 +814,7 @@ void AbstractChoiceWithValueDisplay::GetContentDimensionsBySpec(const UIContext const std::string valueText = ValueText(); int paddingX = 12; // Assume we want at least 20% of the size for the label, at a minimum. - float availWidth = (horiz.size - paddingX * 2) * 0.8f; + float availWidth = (horiz.size - paddingX * 2) * (text_.empty() ? 1.0f : 0.8f); if (availWidth < 0) { availWidth = 65535.0f; } @@ -826,11 +826,15 @@ void AbstractChoiceWithValueDisplay::GetContentDimensionsBySpec(const UIContext valueW += paddingX; // Give the choice itself less space to grow in, so it shrinks if needed. - MeasureSpec horizLabel = horiz; - horizLabel.size -= valueW; + // MeasureSpec horizLabel = horiz; + // horizLabel.size -= valueW; Choice::GetContentDimensionsBySpec(dc, horiz, vert, w, h); w += valueW; + // Fill out anyway if there's space. + if (horiz.type == AT_MOST && w < horiz.size) { + w = horiz.size; + } h = std::max(h, valueH); } diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 4b113d3001..d1f483f0fc 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -463,8 +463,8 @@ public: private: std::string ValueText() const override; - int *iValue_ = nullptr; std::string *sValue_ = nullptr; + int *iValue_ = nullptr; const char *category_ = nullptr; std::string (*translateCallback_)(const char *value) = nullptr; }; diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 87ae8a640a..48d6de8abf 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -414,7 +414,8 @@ void ClickableItem::GetContentDimensions(const UIContext &dc, float &w, float &h } ClickableItem::ClickableItem(LayoutParams *layoutParams) : Clickable(layoutParams) { - if (!layoutParams && autoExpand_) { + if (!layoutParams) { + // The default LayoutParams assigned by View::View defaults to WRAP_CONTENT/WRAP_CONTENT. if (layoutParams_->width == WRAP_CONTENT) layoutParams_->width = FILL_PARENT; } diff --git a/Common/UI/View.h b/Common/UI/View.h index fb26db156f..64c9cdacf8 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -692,11 +692,6 @@ public: // Draws the item background. void Draw(UIContext &dc) override; - - void SetAutoExpand(bool autoExpand) { autoExpand_ = autoExpand; } - -private: - bool autoExpand_ = true; }; // Use to trigger something or open a submenu screen. diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 9c7960f2fe..f32bd6fd37 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -514,8 +514,9 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v float sum = 0.0f; float maxOther = 0.0f; float totalWeight = 0.0f; - float weightSum = 0.0f; - float weightZeroSum = 0.0f; + + float weightSum = 0.0f; // Total sum of weights + float weightZeroSum = 0.0f; // Sum of sizes of things with weight 0.0, a bit confusingly named int numVisible = 0; @@ -593,8 +594,11 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v for (View *view : views_) { if (view->GetVisibility() == V_GONE) continue; - const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); + // FILL_PARENT is not appropriate in this direction. It gets ignored though. + // We have a bit too many of these due to the hack in the ClickableItem constructor. + // _dbg_assert_(view->GetLayoutParams()->width != UI::FILL_PARENT); + const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); if (linLayoutParams && linLayoutParams->weight > 0.0f) { Margins margins = defaultMargins_; if (linLayoutParams->HasMargins()) @@ -638,8 +642,11 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v for (View *view : views_) { if (view->GetVisibility() == V_GONE) continue; - const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); + // FILL_PARENT is not appropriate in this direction. It gets ignored though. + // We have a bit too many of these due to the hack in the ClickableItem constructor. + // _dbg_assert_(view->GetLayoutParams()->height != UI::FILL_PARENT); + const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); if (linLayoutParams && linLayoutParams->weight > 0.0f) { Margins margins = defaultMargins_; if (linLayoutParams->HasMargins()) @@ -649,6 +656,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v h = MeasureSpec(AT_MOST, measuredWidth_); float unit = (allowedHeight - weightZeroSum) / weightSum; if (weightSum == 0.0f) { + // We must have gotten an inf. unit = 1.0f; } MeasureSpec v(AT_MOST, unit * linLayoutParams->weight - margins.vert()); diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index fd80fa8daf..cb20889c13 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -271,13 +271,11 @@ void DisplayLayoutScreen::CreateViews() { // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; - // TODO: I want to set UI::FILL_PARENT or an explicit width here, but breaks badly??? - LinearLayout *shaderRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::WRAP_CONTENT, UI::WRAP_CONTENT)); + LinearLayout *shaderRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)); shaderRow->SetSpacing(4.0f); leftColumn->Add(shaderRow); postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f))); - postProcChoice_->SetAutoExpand(false); postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); @@ -305,7 +303,7 @@ void DisplayLayoutScreen::CreateViews() { } } if (hasSettings) { - auto settingsButton = shaderRow->Add(new Choice(ImageID("I_SLIDERS"))); + auto settingsButton = shaderRow->Add(new Choice(ImageID("I_SLIDERS"), new LinearLayoutParams(0.0f))); settingsButton->OnClick.Add([=](EventParams &e) { settingsVisible_[i] = !settingsVisible_[i]; RecreateViews(); @@ -315,7 +313,7 @@ void DisplayLayoutScreen::CreateViews() { } if (i > 0 && i < g_Config.vPostShaderNames.size()) { - auto upButton = shaderRow->Add(new Choice(ImageID("I_ARROW_UP"))); + auto upButton = shaderRow->Add(new Choice(ImageID("I_ARROW_UP"), new LinearLayoutParams(0.0f))); upButton->OnClick.Add([=](EventParams &e) { std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]); RecreateViews(); @@ -323,7 +321,7 @@ void DisplayLayoutScreen::CreateViews() { }); } if (i < g_Config.vPostShaderNames.size() - 1) { - auto downButton = shaderRow->Add(new Choice(ImageID("I_ARROW_DOWN"))); + auto downButton = shaderRow->Add(new Choice(ImageID("I_ARROW_DOWN"), new LinearLayoutParams(0.0f))); downButton->OnClick.Add([=](EventParams &e) { std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]); RecreateViews(); @@ -331,7 +329,7 @@ void DisplayLayoutScreen::CreateViews() { }); } if (i < g_Config.vPostShaderNames.size()) { - auto deleteButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"))); + auto deleteButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(0.0f))); deleteButton->OnClick.Add([=](EventParams &e) { g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); RecreateViews(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 055d1ead17..3c5c6a1b24 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1064,7 +1064,7 @@ void TakeScreenshot() { } void RenderOverlays(UIContext *dc, void *userdata) { - // Thin bar at the top of the screen like Chrome. + // Thin bar at the top of the screen. std::vector progress = g_DownloadManager.GetCurrentProgress(); if (!progress.empty()) { static const uint32_t colors[4] = { @@ -1091,8 +1091,8 @@ void RenderOverlays(UIContext *dc, void *userdata) { } void NativeRender(GraphicsContext *graphicsContext) { - _assert_(graphicsContext != nullptr); - _assert_(screenManager != nullptr); + _dbg_assert_(graphicsContext != nullptr); + _dbg_assert_(screenManager != nullptr); g_GameManager.Update(); From a83a3f9d5d709bd9831efd6e9d109bc22d6d950b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 01:09:44 +0100 Subject: [PATCH 612/715] Declutter using a context menu, which I had to create from scratch. --- Common/UI/UIScreen.cpp | 41 ++++++++++++++++++--- Common/UI/UIScreen.h | 38 +++++++++++++++++-- Common/UI/View.cpp | 1 + UI/DisplayLayoutScreen.cpp | 75 ++++++++++++++++++++++++-------------- 4 files changed, 119 insertions(+), 36 deletions(-) diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index ff30080553..fb2371c3e4 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -312,10 +312,6 @@ void PopupScreen::TriggerFinish(DialogResult result) { } } -void PopupScreen::resized() { - RecreateViews(); -} - void PopupScreen::CreateViews() { using namespace UI; UIContext &dc = *screenManager()->getUIContext(); @@ -336,7 +332,9 @@ void PopupScreen::CreateViews() { box_->SetDropShadowExpand(std::max(dp_xres, dp_yres)); View *title = new PopupHeader(title_); - box_->Add(title); + if (HasTitleBar()) { + box_->Add(title); + } CreatePopupContents(box_); root_->SetDefaultFocusView(box_); @@ -403,6 +401,39 @@ UI::EventReturn ListPopupScreen::OnListChoice(UI::EventParams &e) { namespace UI { +PopupContextMenuScreen::PopupContextMenuScreen(const ContextMenuItem *items, size_t itemCount, I18NCategory *category, UI::View *sourceView) + : PopupScreen("", "", ""), items_(items), itemCount_(itemCount), category_(category), sourceView_(sourceView) +{ + enabled_.resize(itemCount, true); + SetPopupOrigin(sourceView); +} + +void PopupContextMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { + for (size_t i = 0; i < itemCount_; i++) { + if (items_[i].imageID) { + Choice *choice = new Choice(items_[i].text, ImageID(items_[i].imageID)); + parent->Add(choice); + if (enabled_[i]) { + choice->OnClick.Add([=](EventParams &p) { + TriggerFinish(DR_OK); + p.a = (uint32_t)i; + OnChoice.Dispatch(p); + return EVENT_DONE; + }); + } + else { + choice->SetEnabled(false); + } + } + } + + // Hacky: Override the position to look like a popup menu. + AnchorLayoutParams *ap = (AnchorLayoutParams *)parent->GetLayoutParams(); + ap->center = false; + ap->left = sourceView_->GetBounds().x; + ap->top = sourceView_->GetBounds().y2(); +} + std::string ChopTitle(const std::string &title) { size_t pos = title.find('\n'); if (pos != title.npos) { diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index d1f483f0fc..1b25dc4231 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -76,7 +76,6 @@ public: virtual bool isTransparent() const override { return true; } virtual bool touch(const TouchInput &touch) override; virtual bool key(const KeyInput &key) override; - virtual void resized() override; virtual void TriggerFinish(DialogResult result) override; @@ -91,6 +90,7 @@ protected: virtual bool ShowButtons() const { return true; } virtual bool CanComplete(DialogResult result) { return true; } virtual void OnCompleted(DialogResult result) {} + virtual bool HasTitleBar() const { return true; } const std::string &Title() { return title_; } virtual void update() override; @@ -250,7 +250,7 @@ public: Event OnChange; private: - virtual void OnCompleted(DialogResult result) override; + void OnCompleted(DialogResult result) override; TextEdit *edit_; std::string *value_; std::string textEditValue_; @@ -258,13 +258,45 @@ private: int maxLen_; }; +// TODO: Break out a lot of popup stuff from UIScreen.h. + +struct ContextMenuItem { + const char *text; + const char *imageID; +}; + +// Once a selection has been made, +class PopupContextMenuScreen : public PopupScreen { +public: + PopupContextMenuScreen(const ContextMenuItem *items, size_t itemCount, I18NCategory *category, UI::View *sourceView); + void CreatePopupContents(ViewGroup *parent) override; + + const char *tag() const override { return "ContextMenuPopup"; } + + void SetEnabled(size_t index, bool enabled) { + enabled_[index] = enabled; + } + + UI::Event OnChoice; + +protected: + bool HasTitleBar() const { return false; } + +private: + const ContextMenuItem *items_; + size_t itemCount_; + I18NCategory *category_; + UI::View *sourceView_; + std::vector enabled_; +}; + class AbstractChoiceWithValueDisplay : public UI::Choice { public: AbstractChoiceWithValueDisplay(const std::string &text, LayoutParams *layoutParams = nullptr) : Choice(text, layoutParams) { } - virtual void Draw(UIContext &dc) override; + void Draw(UIContext &dc) override; void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; protected: diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 48d6de8abf..c3bdf847d6 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -500,6 +500,7 @@ void Choice::Draw(UIContext &dc) { if (image_.isValid()) { const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(image_); + _dbg_assert_(image); paddingX += image->w + 6; availWidth -= image->w + 6; // TODO: Use scale rotation and flip here as well (DrawImageRotated is always ALIGN_CENTER for now) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index cb20889c13..b3b6794616 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -23,6 +23,7 @@ #include "Common/Render/DrawBuffer.h" #include "Common/UI/Context.h" #include "Common/UI/View.h" +#include "Common/UI/UIScreen.h" #include "Common/Math/math_util.h" #include "Common/System/Display.h" #include "Common/System/NativeApp.h" @@ -267,6 +268,12 @@ void DisplayLayoutScreen::CreateViews() { std::set alreadyAddedShader; settingsVisible_.resize(g_Config.vPostShaderNames.size()); + static ContextMenuItem postShaderContextMenu[] = { + { "Move Up", "I_ARROW_UP" }, + { "Move Down", "I_ARROW_DOWN" }, + { "Remove", "I_TRASHCAN" }, + }; + for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; @@ -310,32 +317,35 @@ void DisplayLayoutScreen::CreateViews() { return UI::EVENT_DONE; }); } + + auto moreButton = shaderRow->Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(0.0f))); + moreButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { + PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), gr.get(), moreButton); + screenManager()->push(contextMenu); + contextMenu->SetEnabled(0, i > 0); + contextMenu->SetEnabled(1, i < g_Config.vPostShaderNames.size() - 1); + contextMenu->OnChoice.Add([=](EventParams &e) -> UI::EventReturn { + switch (e.a) { + case 0: // Move up + std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]); + break; + case 1: // Move down + std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]); + break; + case 2: // Remove + g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); + break; + default: + return UI::EVENT_DONE; + } + NativeMessageReceived("gpu_configChanged", ""); + RecreateViews(); + return UI::EVENT_DONE; + }); + return UI::EVENT_DONE; + }); } - if (i > 0 && i < g_Config.vPostShaderNames.size()) { - auto upButton = shaderRow->Add(new Choice(ImageID("I_ARROW_UP"), new LinearLayoutParams(0.0f))); - upButton->OnClick.Add([=](EventParams &e) { - std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]); - RecreateViews(); - return UI::EVENT_DONE; - }); - } - if (i < g_Config.vPostShaderNames.size() - 1) { - auto downButton = shaderRow->Add(new Choice(ImageID("I_ARROW_DOWN"), new LinearLayoutParams(0.0f))); - downButton->OnClick.Add([=](EventParams &e) { - std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]); - RecreateViews(); - return UI::EVENT_DONE; - }); - } - if (i < g_Config.vPostShaderNames.size()) { - auto deleteButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(0.0f))); - deleteButton->OnClick.Add([=](EventParams &e) { - g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); - RecreateViews(); - return UI::EVENT_DONE; - }); - } // No need for settings on the last one. if (i == g_Config.vPostShaderNames.size()) @@ -405,11 +415,20 @@ void PostProcScreen::OnCompleted(DialogResult result) { const std::string &value = shaders_[indexTranslation_[listView_->GetSelected()]].section; // I feel this logic belongs more in the caller, but eh... if (showStereoShaders_) { - g_Config.sStereoToMonoShader = value; + if (g_Config.sStereoToMonoShader != value) { + g_Config.sStereoToMonoShader = value; + NativeMessageReceived("gpu_configChanged", ""); + } } else { - if (id_ < (int)g_Config.vPostShaderNames.size()) - g_Config.vPostShaderNames[id_] = value; - else + if (id_ < (int)g_Config.vPostShaderNames.size()) { + if (g_Config.vPostShaderNames[id_] != value) { + g_Config.vPostShaderNames[id_] = value; + NativeMessageReceived("gpu_configChanged", ""); + } + } + else { g_Config.vPostShaderNames.push_back(value); + NativeMessageReceived("gpu_configChanged", ""); + } } } From 59c4ff6af4c1f4d0a7687116006d94773a8cc3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 01:13:29 +0100 Subject: [PATCH 613/715] Make translatable --- UI/DisplayLayoutScreen.cpp | 2 +- assets/lang/en_US.ini | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index b3b6794616..389b9c8533 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -320,7 +320,7 @@ void DisplayLayoutScreen::CreateViews() { auto moreButton = shaderRow->Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(0.0f))); moreButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { - PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), gr.get(), moreButton); + PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), di.get(), moreButton); screenManager()->push(contextMenu); contextMenu->SetEnabled(0, i > 0); contextMenu->SetEnabled(1, i < g_Config.vPostShaderNames.size() - 1); diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index de41e305d8..9869ef161a 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -338,6 +338,8 @@ Load completed = Load completed. Loading = Loading\nPlease Wait... LoadingFailed = Unable to load data. Move = Move +Move Up = Move Up +Move Down = Move Down Network Connection = Network Connection NEW DATA = NEW DATA No = No @@ -345,6 +347,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry From 241dd4093b93b21f71c7719421ed94955b9695d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 11:12:10 +0100 Subject: [PATCH 614/715] Change the Settings toggle to a specially styled checkbox --- Common/Data/Color/RGBAUtil.h | 6 +++ Common/UI/View.cpp | 76 ++++++++++++++++++++++++++++-------- Common/UI/View.h | 9 ++++- UI/DisplayLayoutScreen.cpp | 4 +- UI/DisplayLayoutScreen.h | 4 +- 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/Common/Data/Color/RGBAUtil.h b/Common/Data/Color/RGBAUtil.h index 9e8128bae1..3ea03f328a 100644 --- a/Common/Data/Color/RGBAUtil.h +++ b/Common/Data/Color/RGBAUtil.h @@ -16,3 +16,9 @@ typedef unsigned int Color; inline Color darkenColor(Color color) { return (color & 0xFF000000) | ((color >> 1) & 0x7F7F7F); } + +inline Color lightenColor(Color color) { + color = ~color; + color = (color & 0xFF000000) | ((color >> 1) & 0x7F7F7F); + return ~color; +} diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index c3bdf847d6..769089e375 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -700,28 +700,55 @@ void CheckBox::Draw(UIContext &dc) { if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } - if (HasFocus()) { - style = dc.theme->itemFocusedStyle; - } - if (down_) { - style = dc.theme->itemDownStyle; + ImageID image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; + + // In image mode, light up instead of showing a checkbox. + if (imageID_.isValid()) { + image = imageID_; + if (Toggled()) { + if (HasFocus()) { + style = dc.theme->itemDownStyle; + } else { + style = dc.theme->itemFocusedStyle; + } + } else { + if (HasFocus()) { + style = dc.theme->itemDownStyle; + } else { + style = dc.theme->itemStyle; + } + } + + if (down_) { + style.background.color = lightenColor(style.background.color); + } + + } else { + if (HasFocus()) { + style = dc.theme->itemFocusedStyle; + } + if (down_) { + style = dc.theme->itemDownStyle; + } } + dc.SetFontStyle(dc.theme->uiFont); - ClickableItem::Draw(dc); + DrawBG(dc, style); - ImageID image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; float imageW, imageH; dc.Draw()->MeasureImage(image, &imageW, &imageH); const int paddingX = 12; // Padding right of the checkbox image too. const float availWidth = bounds_.w - paddingX * 2 - imageW - paddingX; - float scale = CalculateTextScale(dc, availWidth); - dc.SetFontScale(scale, scale); - Bounds textBounds(bounds_.x + paddingX, bounds_.y, availWidth, bounds_.h); - dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); + if (!text_.empty()) { + float scale = CalculateTextScale(dc, availWidth); + dc.SetFontScale(scale, scale); + Bounds textBounds(bounds_.x + paddingX, bounds_.y, availWidth, bounds_.h); + dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); + } dc.Draw()->DrawImage(image, bounds_.x2() - paddingX, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); dc.SetFontScale(1.0f, 1.0f); } @@ -747,24 +774,41 @@ float CheckBox::CalculateTextScale(const UIContext &dc, float availWidth) const void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) const { ImageID image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; + if (imageID_.isValid()) { + image = imageID_; + } + float imageW, imageH; dc.Draw()->MeasureImage(image, &imageW, &imageH); const int paddingX = 12; + + if (imageID_.isValid()) { + w = imageW + paddingX * 2; + h = std::max(imageH, ITEM_HEIGHT); + return; + } + + // The below code is kinda wacky, we shouldn't involve bounds_ here. + // Padding right of the checkbox image too. float availWidth = bounds_.w - paddingX * 2 - imageW - paddingX; if (availWidth < 0.0f) { // Let it have as much space as it needs. availWidth = MAX_ITEM_SIZE; } - float scale = CalculateTextScale(dc, availWidth); - float actualWidth, actualHeight; - Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); + if (!text_.empty()) { + float scale = CalculateTextScale(dc, availWidth); + float actualWidth, actualHeight; + Bounds availBounds(0, 0, availWidth, bounds_.h); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); + h = std::max(actualHeight, ITEM_HEIGHT); + } else { + h = std::max(imageH, ITEM_HEIGHT); + } w = bounds_.w; - h = std::max(actualHeight, ITEM_HEIGHT); } void BitCheckBox::Toggle() { diff --git a/Common/UI/View.h b/Common/UI/View.h index 64c9cdacf8..0d52216771 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -827,11 +827,17 @@ private: class CheckBox : public ClickableItem { public: - CheckBox(bool *toggle, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = 0) + CheckBox(bool *toggle, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = nullptr) : ClickableItem(layoutParams), toggle_(toggle), text_(text), smallText_(smallText) { OnClick.Handle(this, &CheckBox::OnClicked); } + // Image-only "checkbox", lights up instead of showing a checkmark. + CheckBox(bool *toggle, ImageID imageID, LayoutParams *layoutParams = nullptr) + : ClickableItem(layoutParams), toggle_(toggle), imageID_(imageID) { + OnClick.Handle(this, &CheckBox::OnClicked); + } + void Draw(UIContext &dc) override; std::string DescribeText() const override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -846,6 +852,7 @@ private: bool *toggle_; std::string text_; std::string smallText_; + ImageID imageID_; }; class BitCheckBox : public CheckBox { diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 389b9c8533..d09a9b7d4e 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -310,9 +310,9 @@ void DisplayLayoutScreen::CreateViews() { } } if (hasSettings) { - auto settingsButton = shaderRow->Add(new Choice(ImageID("I_SLIDERS"), new LinearLayoutParams(0.0f))); + CheckBox *checkBox = new CheckBox(&settingsVisible_[i], ImageID("I_SLIDERS"), new LinearLayoutParams(0.0f)); + auto settingsButton = shaderRow->Add(checkBox); settingsButton->OnClick.Add([=](EventParams &e) { - settingsVisible_[i] = !settingsVisible_[i]; RecreateViews(); return UI::EVENT_DONE; }); diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index d55d89d462..a494b9d288 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -17,6 +17,8 @@ #pragma once +#include + #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" #include "GPU/Common/PostShader.h" @@ -47,7 +49,7 @@ private: UI::ChoiceStrip *mode_ = nullptr; UI::Choice *postProcChoice_ = nullptr; std::string shaderNames_[256]; - std::vector settingsVisible_; + std::deque settingsVisible_; // vector is an insane bitpacked specialization! }; class PostProcScreen : public ListPopupScreen { From 509d04844b964518fb4cef9f029e56e13870cb0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 11:21:15 +0100 Subject: [PATCH 615/715] Combine two translation strings, add another --- UI/DisplayLayoutScreen.cpp | 11 +++++++++-- assets/lang/en_US.ini | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index d09a9b7d4e..94d88ddf06 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -150,6 +150,7 @@ void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult resu } UI::EventReturn DisplayLayoutScreen::OnPostProcShaderChange(UI::EventParams &e) { + // Remove the virtual "Off" entry. TODO: Get rid of it generally. g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); NativeMessageReceived("gpu_configChanged", ""); @@ -163,7 +164,13 @@ UI::EventReturn DisplayLayoutScreen::OnPostProcShaderChange(UI::EventParams &e) } static std::string PostShaderTranslateName(const char *value) { + auto gr = GetI18NCategory("Graphics"); auto ps = GetI18NCategory("PostShaders"); + if (!strcmp(value, "Off")) { + // Off is a legacy fake item (gonna migrate off it later). + return gr->T("Add postprocessing shader"); + } + const ShaderInfo *info = GetPostShaderInfo(value); if (info) { return ps->T(value, info ? info->name.c_str() : value); @@ -263,7 +270,7 @@ void DisplayLayoutScreen::CreateViews() { return g_Config.bStereoRendering && multiViewSupported; }; - leftColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); + leftColumn->Add(new ItemHeader(gr->T("Postprocessing shaders"))); std::set alreadyAddedShader; settingsVisible_.resize(g_Config.vPostShaderNames.size()); @@ -285,7 +292,7 @@ void DisplayLayoutScreen::CreateViews() { postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f))); postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); - auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); + auto procScreen = new PostProcScreen(gr->T("Postprocessing shaders"), i, false); procScreen->SetHasDropShadow(false); procScreen->OnChoice.Handle(this, &DisplayLayoutScreen::OnPostProcShaderChange); if (e.v) diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 9869ef161a..a483413ede 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -555,8 +555,8 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Add postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates From 8bd6621c40c9a059553a4dac1c63da82144a2573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 11:35:41 +0100 Subject: [PATCH 616/715] Remove postprocessing option from desktop menu (doesn't support multi-shader) --- Windows/MainWindowMenu.cpp | 87 +----------------------------------- Windows/ppsspp.rc | 4 -- Windows/resource.h | 2 - assets/lang/ar_AE.ini | 1 - assets/lang/az_AZ.ini | 1 - assets/lang/bg_BG.ini | 1 - assets/lang/ca_ES.ini | 1 - assets/lang/cz_CZ.ini | 1 - assets/lang/da_DK.ini | 1 - assets/lang/de_DE.ini | 1 - assets/lang/dr_ID.ini | 1 - assets/lang/en_US.ini | 3 +- assets/lang/es_ES.ini | 1 - assets/lang/es_LA.ini | 1 - assets/lang/fa_IR.ini | 1 - assets/lang/fi_FI.ini | 1 - assets/lang/fr_FR.ini | 1 - assets/lang/gl_ES.ini | 1 - assets/lang/gr_EL.ini | 1 - assets/lang/he_IL.ini | 1 - assets/lang/he_IL_invert.ini | 1 - assets/lang/hr_HR.ini | 1 - assets/lang/hu_HU.ini | 1 - assets/lang/id_ID.ini | 1 - assets/lang/it_IT.ini | 1 - assets/lang/ja_JP.ini | 1 - assets/lang/jv_ID.ini | 1 - assets/lang/ko_KR.ini | 1 - assets/lang/lo_LA.ini | 1 - assets/lang/lt-LT.ini | 1 - assets/lang/ms_MY.ini | 1 - assets/lang/nl_NL.ini | 1 - assets/lang/no_NO.ini | 1 - assets/lang/pl_PL.ini | 1 - assets/lang/pt_BR.ini | 1 - assets/lang/pt_PT.ini | 1 - assets/lang/ro_RO.ini | 1 - assets/lang/ru_RU.ini | 1 - assets/lang/sv_SE.ini | 1 - assets/lang/tg_PH.ini | 1 - assets/lang/th_TH.ini | 1 - assets/lang/tr_TR.ini | 1 - assets/lang/uk_UA.ini | 3 +- assets/lang/vi_VN.ini | 1 - assets/lang/zh_CN.ini | 1 - assets/lang/zh_TW.ini | 1 - 46 files changed, 3 insertions(+), 137 deletions(-) diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 37c01cb3ed..25af2cd08e 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -154,68 +154,6 @@ namespace MainWindow { AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_ABOUT, aboutPPSSPP.c_str()); } - void UpdateDynamicMenuCheckmarks(HMENU menu) { - int item = ID_SHADERS_BASE + 1; - - for (size_t i = 0; i < availableShaders.size(); i++) { - bool checked = false; - if (g_Config.vPostShaderNames.empty() && availableShaders[i] == "Off") - checked = true; - else if (g_Config.vPostShaderNames.size() == 1 && availableShaders[i] == g_Config.vPostShaderNames[0]) - checked = true; - - CheckMenuItem(menu, item++, checked ? MF_CHECKED : MF_UNCHECKED); - } - } - - bool CreateShadersSubmenu(HMENU menu) { - // NOTE: We do not load this until translations are loaded! - if (!I18NCategoryLoaded("PostShaders")) - return false; - - // We only reload this initially and when a menu is actually opened. - if (!menuShaderInfoLoaded) { - // This is on Windows where we don't currently blacklist any vendors, or similar. - // TODO: Figure out how to have the GPU data while reloading the post shader info. - ReloadAllPostShaderInfo(nullptr); - menuShaderInfoLoaded = true; - } - - std::vector info = GetAllPostShaderInfo(); - - if (menuShaderInfo.size() == info.size() && std::equal(info.begin(), info.end(), menuShaderInfo.begin())) { - return false; - } - - auto ps = GetI18NCategory("PostShaders"); - - HMENU shaderMenu = GetSubmenuById(menu, ID_OPTIONS_SHADER_MENU); - EmptySubMenu(shaderMenu); - - int item = ID_SHADERS_BASE + 1; - const char *translatedShaderName = nullptr; - - availableShaders.clear(); - for (auto i = info.begin(); i != info.end(); ++i) { - if (!i->visible) - continue; - int checkedStatus = MF_UNCHECKED; - availableShaders.push_back(i->section); - if (g_Config.vPostShaderNames.empty() && i->section == "Off") { - checkedStatus = MF_CHECKED; - } else if (g_Config.vPostShaderNames.size() == 1 && g_Config.vPostShaderNames[0] == i->section) { - checkedStatus = MF_CHECKED; - } - - translatedShaderName = ps->T(i->section.c_str(), i->name.c_str()); - - AppendMenu(shaderMenu, MF_STRING | MF_BYPOSITION | checkedStatus, item++, ConvertUTF8ToWString(translatedShaderName).c_str()); - } - - menuShaderInfo = info; - return true; - } - static void TranslateMenuItem(const HMENU hMenu, const int menuID, const std::wstring& accelerator = L"", const char *key = nullptr) { auto des = GetI18NCategory("DesktopUI"); @@ -302,7 +240,6 @@ namespace MainWindow { // Skip display multipliers x1-x10 TranslateMenuItem(menu, ID_OPTIONS_FULLSCREEN, g_Config.bSystemControls ? L"\tAlt+Return, F11" : L""); TranslateMenuItem(menu, ID_OPTIONS_VSYNC); - TranslateMenuItem(menu, ID_OPTIONS_SHADER_MENU); TranslateMenuItem(menu, ID_OPTIONS_SCREEN_MENU, g_Config.bSystemControls ? L"\tCtrl+1" : L""); TranslateMenuItem(menu, ID_OPTIONS_SCREENAUTO); // Skip rendering resolution 2x-5x.. @@ -360,10 +297,6 @@ namespace MainWindow { changed = true; } - if (CreateShadersSubmenu(menu)) { - changed = true; - } - if (changed) { DrawMenuBar(hWnd); } @@ -1034,25 +967,8 @@ namespace MainWindow { break; default: - { - // Handle the dynamic shader switching here. - // The Menu ID is contained in wParam, so subtract - // ID_SHADERS_BASE and an additional 1 off it. - u32 index = (wParam - ID_SHADERS_BASE - 1); - if (index < availableShaders.size()) { - g_Config.vPostShaderNames.clear(); - if (availableShaders[index] != "Off") - g_Config.vPostShaderNames.push_back(availableShaders[index]); - g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); - - NativeMessageReceived("gpu_renderResized", ""); - NativeMessageReceived("postshader_updated", ""); - break; - } - MessageBox(hWnd, L"Unimplemented", L"Sorry", 0); - } - break; + break; } } @@ -1329,7 +1245,6 @@ namespace MainWindow { EnableMenuItem(menu, ID_DEBUG_GEDEBUGGER, MF_GRAYED); #endif - UpdateDynamicMenuCheckmarks(menu); UpdateCommands(); } diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 54951ee77a..40a9d9cc6d 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -553,10 +553,6 @@ BEGIN MENUITEM "Fullscreen", ID_OPTIONS_FULLSCREEN MENUITEM "VSync", ID_OPTIONS_VSYNC MENUITEM "Skip Buffer Effects", ID_OPTIONS_SKIP_BUFFER_EFFECTS - POPUP "Postprocessing Shader", ID_OPTIONS_SHADER_MENU - BEGIN - MENUITEM "", 0, MFT_SEPARATOR - END POPUP "Rendering Resolution", ID_OPTIONS_SCREEN_MENU BEGIN MENUITEM "Auto", ID_OPTIONS_SCREENAUTO diff --git a/Windows/resource.h b/Windows/resource.h index 6bc03a9429..83ef889573 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -118,8 +118,6 @@ #define IDC_GEDBG_PRIMCOUNTER 1201 #define IDC_BUTTON_SEARCH 1204 -#define ID_SHADERS_BASE 5000 - #define ID_FILE_EXIT 40000 #define ID_DEBUG_SAVEMAPFILE 40001 #define ID_DISASM_RUNTOHERE 40004 diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index d862a5b530..8170c880d9 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -192,7 +192,6 @@ Pause = ‎&إيقاف مؤقت Pause When Not Focused = ‎&إيقاف مؤقت حينما لا يكون مفعلاً Portrait = ‎لوحة Portrait reversed = ‎لوحة معكوسة -Postprocessing Shader = Postprocessin&g shader PPSSPP Forums = ‎PPSSPP &منتديات Record = ‎&تسجيل Record Audio = ‎تسجيل &الصوت diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index d7747c4d18..71c99544b1 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 2c3cda2d84..e17f01449d 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = Пауза, когато не фокусиран Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &форум Record = &Record Record Audio = Record &audio diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 4c1a0f9ec6..2e639cebea 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -184,7 +184,6 @@ Pause = &Pausa Pause When Not Focused = &Pausa quan es canviï de finestra Portrait = Vertical Portrait reversed = Vertical invertit -Postprocessing Shader = &Shader de postprocessat PPSSPP Forums = &Fòrums de PPSSPP Record = Enregistreu Record Audio = Enregistreu Àudio diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index dbb664fefa..17b67bf6c0 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -184,7 +184,6 @@ Pause = &Pozastavit Pause When Not Focused = &Pozastavit pokud okno není zaměřeno Portrait = Na výšku Portrait reversed = Na výšku obráceně -Postprocessing Shader = &Shader následného zpracování PPSSPP Forums = &Fóra PPSSPP Record = &Record Record Audio = Record &audio diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index f55140f39b..0daae5d768 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = P&ause når ikke i fokus Portrait = Portræt Portrait reversed = Omvendt portræt -Postprocessing Shader = Efterbehandlin&gs shader PPSSPP Forums = PPSSPP &forum Record = Optag Record Audio = Optag Lyd diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 0e183a0dfb..32d4f76ceb 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -184,7 +184,6 @@ Pause = Pause Pause When Not Focused = Pausieren im Hintergrund Portrait = Hochformat Portrait reversed = Hochformat umgedreht -Postprocessing Shader = Nachbearbeitungs-Shader PPSSPP Forums = PPSSPP Forum Record = Aufzeichnung Record Audio = Ton aufzeichnen diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 8f8340c886..b5759e71ca 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -184,7 +184,6 @@ Pause = &Paus Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forumna Record = &Record Record Audio = Record &audio diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index a483413ede..4f18c1f24d 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -208,7 +208,6 @@ Pause = &Pause Pause When Not Focused = &Pause when not focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g shader PPSSPP Forums = PPSSPP &forums Record = &Record Record Audio = Record &audio @@ -479,6 +478,7 @@ Use UI background = Use UI background 9x PSP = 9× PSP 10x PSP = 10× PSP 16x = 16× +Add postprocessing shader = Add postprocessing shader Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) @@ -555,7 +555,6 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Add postprocessing shader Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index d41857869a..a7e9f92edf 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -184,7 +184,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar al cambiar de ventana Portrait = &Vertical Portrait reversed = Vertical &invertido -Postprocessing Shader = &Shader de postprocesado PPSSPP Forums = &Foro de PPSSPP Record = G&rabar Record Audio = Grabar &audio diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index e36fd8c31c..dc3cd361ee 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -184,7 +184,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar al cambiar de ventana Portrait = Retrato Portrait reversed = Retrato inverso -Postprocessing Shader = &Shader de postprocesado PPSSPP Forums = &Foro de PPSSPP Record = G&rabar Record Audio = Grabar &audio diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 54e119c4f2..bf4a4421d1 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -184,7 +184,6 @@ Pause = ‎مکث Pause When Not Focused = ‎هنگامی که پنجره فعال نباشد بازی متوقف شود Portrait = ‎عمودی Portrait reversed = ‎عمودی وارونه -Postprocessing Shader = ‎اضافه کردن افکت PPSSPP Forums = ‎PPSSPP انجمن های Record = ‎ضبط کردن Record Audio = ‎ضبط صدا diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 260e4d30c7..4e5543efac 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 89a4cde7ce..924ab0d7b4 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = Mettre en pa&use si pas au premier plan Portrait = Portrait Portrait reversed = Portrait inversé -Postprocessing Shader = S&haders de post-traitement PPSSPP Forums = Visiter le &forum de PPSSPP Record = E&nregistrer Record Audio = Enregistrer le &son diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 4f301f1147..02aebd2a2b 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -184,7 +184,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar ó cambiar de ventá Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = &Shader de postprocesado PPSSPP Forums = &Foro de PPSSPP Record = &Record Record Audio = Record &audio diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 0fd4b4889b..7eb3b299df 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -184,7 +184,6 @@ Pause = &Πάυση Pause When Not Focused = Παύση σε κατάσταση παρασκηνίου Portrait = Κατακόρυφο προσανατολισμός Portrait reversed = Αντεστραμένος κατακόρυφος προσανατολισμός -Postprocessing Shader = Shader Μετεπεξεργασίας PPSSPP Forums = PPSSPP &Forum Record = Καταγραφή Record Audio = Καταγραφή Ήχου diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 12d2b9dfd9..d797ddef6e 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -184,7 +184,6 @@ Pause = &השהה Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index a455edd43d..68ef0dc9de 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index dd275caed9..3b16686aee 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -184,7 +184,6 @@ Pause = &Pauza Pause When Not Focused = &Pauziraj kad nije fokusirano Portrait = Portret Portrait reversed = Obrnuti portret -Postprocessing Shader = Postupa&k sjenčanja PPSSPP Forums = PPSSPP &forumi Record = &Snimaj Record Audio = Snimaj &zvuk diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 09bf6c6476..47b108496d 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -184,7 +184,6 @@ Pause = &Szünet Pause When Not Focused = &Szüneteltetés, ha nincs fókuszban Portrait = Álló Portrait reversed = Fordított álló -Postprocessing Shader = Utóeffektező shader PPSSPP Forums = PPSSPP &fórum Record = &Felvétel Record Audio = &Hang felvétele diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index ff777e4581..965f8a7734 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -184,7 +184,6 @@ Pause = Jeda Pause When Not Focused = Jeda ketika tidak fokus Portrait = Tegak Portrait reversed = Tegak terbalik -Postprocessing Shader = Pemrosesan shader PPSSPP Forums = &Forum PPSSPP Record = Rekam Record Audio = Rekam suara diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 0af6c2d099..85619e5adc 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -184,7 +184,6 @@ Pause = Pausa Pause When Not Focused = Pausa quando non attivo Portrait = Ritratto Portrait reversed = Ritratto invertito -Postprocessing Shader = Shader di post-elaborazione PPSSPP Forums = Forum PPSSPP Record = Registra Record Audio = Registra Audio diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index c340110427..1299f48104 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -184,7 +184,6 @@ Pause = 一時停止(&P) Pause When Not Focused = 非フォーカス時は一時停止する(&P) Portrait = 縦 Portrait reversed = 縦 (反転) -Postprocessing Shader = 後処理シェーダ(&G) PPSSPP Forums = PPSSPPフォーラム(&F) Record = 記録(&R) Record Audio = オーディオを記録する(&A) diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 36b869e9f2..956b84ed72 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -184,7 +184,6 @@ Pause = &Ngaso Pause When Not Focused = &Ngaso Nalika Ora Fokus Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Ngatifke Shader PPSSPP Forums = &Forum PPSSPP Record = &Record Record Audio = Record &audio diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index f7cf4002ec..2376beeb74 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -184,7 +184,6 @@ Pause = 일시 정지(&P) Pause When Not Focused = 포커싱되지 않았을 때 일시 정지(&P) Portrait = 세로방향 Portrait reversed = 세로방향 반전 -Postprocessing Shader = 후처리 셰이더(&G) PPSSPP Forums = PPSSPP 포럼(&F) Record = 녹음(&R) Record Audio = 사운드 녹음(&A) diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 2773dd95f1..80da2bfb33 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -184,7 +184,6 @@ Pause = &ຢຸດຊົ່ວຄາວ Pause When Not Focused = &ຢຸດຊົ່ວຄາວເມື່ອບໍ່ໄດ້ຫຼິ້ນ Portrait = ແນວຕັ້ງ Portrait reversed = ກັບດ້ານແນວຕັ້ງ -Postprocessing Shader = &ຂະບວນການເຮັດວຽກໄລ່ປັບເສດແສງສີ PPSSPP Forums = &ຟໍຣຳ PPSSPP Record = ການບັນທຶກ Record Audio = ບັນທຶກສຽງ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index d7f0439ec5..f0d88f13e5 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -184,7 +184,6 @@ Pause = &Pauzė Pause When Not Focused = &Stabdyti kai nefokusuota Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forumai Record = &Record Record Audio = Record &audio diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index c0fcc500c2..8a70da4e01 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -184,7 +184,6 @@ Pause = &Jeda Pause When Not Focused = &Jeda ketika tidak difokus Portrait = Portrait Portrait reversed = Portrait songsang -Postprocessing Shader = Shader pasc&apemprosesan PPSSPP Forums = PPSSPP &Forum Record = &Rakam Record Audio = Rakam &audio diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 4691e9eddd..1279d2fe05 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -184,7 +184,6 @@ Pause = &Pauzeren Pause When Not Focused = &Pauzeren wanneer venster inactief is Portrait = Portret Portrait reversed = Omgekeerd portret -Postprocessing Shader = &Nabewerkingsshader PPSSPP Forums = &PPSSPP-forum Record = Opnemen Record Audio = Audio opnemen diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 4835560145..95ac67e534 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 8dd0476756..604d4b7e23 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -184,7 +184,6 @@ Pause = Pauza Pause When Not Focused = Pauzuj, gdy okno nieaktywne Portrait = Pionowo Portrait reversed = Odwrócone pionowo -Postprocessing Shader = Efekty wizualne shaderów PPSSPP Forums = Forum PPSSPP Record = &Nagrywaj Record Audio = Nagrywaj &dźwięk diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 0c2f988711..1341c5cd8b 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -208,7 +208,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar quando não focado Portrait = Retrato Portrait reversed = Retrato invertido -Postprocessing Shader = Shader de pós-processamento PPSSPP Forums = Fórums do &PPSSPP Record = &Gravar Record Audio = Gravar &áudio diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 678779d5b1..0f1c44dc45 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -208,7 +208,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar quando não focado Portrait = Retrato Portrait reversed = Retrato invertido -Postprocessing Shader = Shader de Pós-Processamento PPSSPP Forums = Fórums do &PPSSPP Record = &Gravar Record Audio = Gravar &Áudio diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 95e3d6bb7f..de55371650 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -184,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 4537365dd0..b596255985 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -184,7 +184,6 @@ Pause = &Пауза Pause When Not Focused = &Пауза, когда окно не в фокусе Portrait = Портретная Portrait reversed = Портретная (перевернутая) -Postprocessing Shader = &Постобработка (шейдер) PPSSPP Forums = &Форум PPSSPP Record = &Запись Record Audio = Запись &звука diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 6d085d23d8..2609d96237 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -184,7 +184,6 @@ Pause = Paus Pause When Not Focused = Pausa vid tappat fokus Portrait = Porträtt Portrait reversed = Porträtt omvänt -Postprocessing Shader = Postprocessing Shader PPSSPP Forums = PPSSPP-forum Record = &Record Record Audio = Record &audio diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index d649050859..f11d6cb979 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -184,7 +184,6 @@ Pause = Pause Pause When Not Focused = Ihinto kapag hindi naka pokus Portrait = Patayo Portrait reversed = Pabaliktad na patayo -Postprocessing Shader = Postprocessing Shader PPSSPP Forums = PPSSPP Forums Record = Record Record Audio = Record audio diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index c287d70dd8..e29a10547b 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -184,7 +184,6 @@ Pause = หยุดชั่วคราว Pause When Not Focused = หยุดชั่วคราวเมื่อไม่ได้เล่น Portrait = แนวตั้ง Portrait reversed = แนวตั้งกลับด้าน -Postprocessing Shader = กระบวนการทำงานปรับเฉดแสงสี PPSSPP Forums = เว็บ PPSSPP Forums Record = การอัดบันทึก Record Audio = อัดบันทึกเสียง diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 415cbd1e91..61e3ea259d 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -186,7 +186,6 @@ Pause = PPSSPP Menüsü Pause When Not Focused = &Başka programa geçildiğinde duraklat Portrait = Dikey Portrait reversed = Ters Dikey -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP Forumları Record = Kayıt Record Audio = Ses Kaydet diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 1b6e6ec377..5fb8c200b0 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -184,7 +184,6 @@ Pause = &Пауза Pause When Not Focused = &Пауза коли вікно не в фокусі Portrait = Портретне Portrait reversed = Портретна (перевернуто) -Postprocessing Shader = &Подальша обробка (шейдер) PPSSPP Forums = &Форум PPSSPP Record = &Запис Record Audio = Запис &аудіо @@ -529,7 +528,7 @@ Partial Stretch = Часткове розтягнення Percent of FPS = Відсоток FPS Performance = Продуктивність Postprocessing effect = Postprocessing effects -Postprocessing Shader = Шейдери +Postprocessing Shader = &Подальша обробка (шейдер) Recreate Activity = Відтворити діяльність Render duplicate frames to 60hz = Відображення повторюваних кадрів до 60 Гц RenderDuplicateFrames Tip = Можна зробити більш плавний кадр в іграх, які працюють у нижчих кадрах diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index f459105a2f..ae713388a9 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -184,7 +184,6 @@ Pause = Tạm dừng Pause When Not Focused = Dừng trò chơi khi "ko tập trung" Portrait = Chiều dọc Portrait reversed = Chiều dọc đảo ngược -Postprocessing Shader = Xử lý hậu đổ bóng PPSSPP Forums = Diễn đàn PPSSPP Record = Ghi lại Record Audio = Ghi âm thanh diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 2628aa563f..84ce0f679e 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -184,7 +184,6 @@ Pause = 暂停 (&P) Pause When Not Focused = 后台运行时自动暂停 (&P) Portrait = 纵向 Portrait reversed = 纵向反转 -Postprocessing Shader = 后处理着色器 (&g) PPSSPP Forums = PPSSPP官方论坛 (&F) Record = 录制 (&R) Record Audio = 录制音频 (&A) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 2c5bda9581..2572eeaedb 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -184,7 +184,6 @@ Pause = 暫停 (&P) Pause When Not Focused = 未聚焦時暫停 (&P) Portrait = 直向 Portrait reversed = 直向反轉 -Postprocessing Shader = 後處理著色器 (&G) PPSSPP Forums = PPSSPP 論壇 (&F) Record = 錄製 (&R) Record Audio = 錄製音訊 (&A) From 6ee5382e86571d42906d2f329a4b0fa9baa19c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 11:38:52 +0100 Subject: [PATCH 617/715] Remove obsolete translation key "Postprocessing effects" --- assets/lang/ar_AE.ini | 1 - assets/lang/az_AZ.ini | 1 - assets/lang/bg_BG.ini | 1 - assets/lang/ca_ES.ini | 1 - assets/lang/cz_CZ.ini | 1 - assets/lang/da_DK.ini | 3 +-- assets/lang/de_DE.ini | 1 - assets/lang/dr_ID.ini | 1 - assets/lang/es_ES.ini | 1 - assets/lang/es_LA.ini | 1 - assets/lang/fa_IR.ini | 1 - assets/lang/fi_FI.ini | 1 - assets/lang/fr_FR.ini | 1 - assets/lang/gl_ES.ini | 1 - assets/lang/gr_EL.ini | 1 - assets/lang/he_IL.ini | 1 - assets/lang/he_IL_invert.ini | 1 - assets/lang/hr_HR.ini | 1 - assets/lang/hu_HU.ini | 1 - assets/lang/id_ID.ini | 1 - assets/lang/it_IT.ini | 1 - assets/lang/ja_JP.ini | 1 - assets/lang/jv_ID.ini | 1 - assets/lang/ko_KR.ini | 1 - assets/lang/lo_LA.ini | 1 - assets/lang/lt-LT.ini | 1 - assets/lang/ms_MY.ini | 1 - assets/lang/nl_NL.ini | 1 - assets/lang/no_NO.ini | 1 - assets/lang/pl_PL.ini | 1 - assets/lang/pt_BR.ini | 1 - assets/lang/pt_PT.ini | 1 - assets/lang/ro_RO.ini | 1 - assets/lang/ru_RU.ini | 1 - assets/lang/sv_SE.ini | 1 - assets/lang/tg_PH.ini | 1 - assets/lang/th_TH.ini | 1 - assets/lang/tr_TR.ini | 1 - assets/lang/uk_UA.ini | 1 - assets/lang/vi_VN.ini | 1 - assets/lang/zh_CN.ini | 1 - assets/lang/zh_TW.ini | 1 - 42 files changed, 1 insertion(+), 43 deletions(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 8170c880d9..5f1df8b382 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -535,7 +535,6 @@ Overlay Information = ‎معلومات النسق Partial Stretch = ‎تمطيط جزئي Percent of FPS = Percent of FPS Performance = ‎الأداء -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 71c99544b1..43d6a5ceff 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -527,7 +527,6 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index e17f01449d..99b813314c 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -527,7 +527,6 @@ Overlay Information = Обща информация Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 2e639cebea..3ea943ea74 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -527,7 +527,6 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 17b67bf6c0..d75814f98c 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -527,7 +527,6 @@ Overlay Information = Informace v překryvu Partial Stretch = Částečné roztažení Percent of FPS = Percent of FPS Performance = Výkon -Postprocessing effect = Postprocessing effects Postprocessing Shader = Shader následného zpracování Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 0daae5d768..69d88be3a5 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -527,8 +527,7 @@ Overlay Information = Overlay information Partial Stretch = Delvis strukket Percent of FPS = Percent of FPS Performance = Ydelse -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Efterbehandlings shader +Postprocessing Shader = Efterbehandlings-shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 32d4f76ceb..d8ca26e9cb 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -527,7 +527,6 @@ Overlay Information = Eingeblendete Informationen Partial Stretch = Teilweise strecken Percent of FPS = Prozent an FPS Performance = Leistung -Postprocessing effect = Nachbearbeitungs-Effekte Postprocessing Shader = Nachbearbeitungs-Shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index b5759e71ca..f36af98dc6 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -527,7 +527,6 @@ Overlay Information = Pempakitan Overlay Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index a7e9f92edf..cf952cdafa 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -527,7 +527,6 @@ Overlay Information = Información en pantalla Partial Stretch = Estirado parcial Percent of FPS = % de FPS Performance = Rendimiento -Postprocessing effect = Efecto de postprocesado Postprocessing Shader = Shader de postprocesado Recreate Activity = Recrear actividad Render duplicate frames to 60hz = Renderizar cuadros duplicados a 60Hz diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index dc3cd361ee..dbc54513bb 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -527,7 +527,6 @@ Overlay Information = Información en pantalla Partial Stretch = Estirado parcial Percent of FPS = % de FPS Performance = Rendimiento -Postprocessing effect = Efectos de postprocesado Postprocessing Shader = Shader de postprocesado Recreate Activity = Recrear actividad Render duplicate frames to 60hz = Procesar cuadros duplicados a 60 Hz diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index bf4a4421d1..f828b82e71 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -527,7 +527,6 @@ Overlay Information = ‎Overlay اطلاعات Partial Stretch = ‎کشیدگی جزئی Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = ‎افکت پس-پردازش Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 4e5543efac..bbbfbac99c 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -527,7 +527,6 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 924ab0d7b4..2c22ac4eb1 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -527,7 +527,6 @@ Overlay Information = Informations incrustées à l'écran Partial Stretch = Étirement partiel Percent of FPS = Pourcentage de FPS Performance = Performances -Postprocessing effect = Effets de post-traitement Postprocessing Shader = Shaders de post-traitement Recreate Activity = Recréer l'animation Render duplicate frames to 60hz = Dupliquer les images pour atteindre 60 Hz diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 02aebd2a2b..630b96feb8 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -527,7 +527,6 @@ Overlay Information = Información en pantalla Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Rendemento -Postprocessing effect = Postprocessing effects Postprocessing Shader = Shader de postprocesado Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 7eb3b299df..8fceeb73bc 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -527,7 +527,6 @@ Overlay Information = Πληροφορίες Οθόνης Partial Stretch = Μερική επέκταση Percent of FPS = Percent of FPS Performance = Επίδοσεις -Postprocessing effect = Postprocessing effects Postprocessing Shader = Shader Μετεπεξεργασίας Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index d797ddef6e..cf2351b69e 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -527,7 +527,6 @@ Overlay Information = כיסוי מידע Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 68ef0dc9de..4c914cff23 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -527,7 +527,6 @@ Overlay Information = עדימ יוסיכ Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 3b16686aee..8875a7ad98 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -527,7 +527,6 @@ Overlay Information = Prekrivanje informacija Partial Stretch = Djelomično rastezanje Percent of FPS = Postotak FPS-a Performance = Performansa -Postprocessing effect = Postprocessing effects Postprocessing Shader = Sjenčanje poslije procesa Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 47b108496d..93c47f1709 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -527,7 +527,6 @@ Overlay Information = Overlay információk Partial Stretch = Részleges nyújtás Percent of FPS = FPS százalékában Performance = Teljesítmény -Postprocessing effect = Postprocessing effects Postprocessing Shader = Utóeffektező shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Képkockák duplázása 60 Hz rendereléshez diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 965f8a7734..74c91387ce 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -527,7 +527,6 @@ Overlay Information = Tampilan Informasi Partial Stretch = Peregangan sebagian Percent of FPS = Persen FPS Performance = Kinerja -Postprocessing effect = Efek pemrosesan Postprocessing Shader = Pemrosesan shader Recreate Activity = Buat ulang aktivitas Render duplicate frames to 60hz = Pelukisan bingkai duplikat menjadi 60 Hz diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 85619e5adc..56918bf5a7 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -528,7 +528,6 @@ Overlay Information = Copri Informazioni Partial Stretch = Estensione Parziale Percent of FPS = Percentuale di FPS Performance = Prestazioni -Postprocessing effect = Effetti di post-elaborazione Postprocessing Shader = Shader di post-elaborazione Recreate Activity = Ricrea l'animazione Render duplicate frames to 60hz = Duplica i frame da renderizzare a 60 Hz diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 1299f48104..2994e6ee46 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -527,7 +527,6 @@ Overlay Information = オーバーレイ表示 Partial Stretch = 部分的に拡大 Percent of FPS = FPS中のパーセント Performance = パフォーマンス -Postprocessing effect = 後処理エフェクト Postprocessing Shader = 後処理シェーダ Recreate Activity = Recreate activity Render duplicate frames to 60hz = フレームを複製して60Hzでレンダリングする diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 956b84ed72..69e8030181 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -527,7 +527,6 @@ Overlay Information = Informasi numpuki Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Kinerja -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 2376beeb74..36258311cb 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -527,7 +527,6 @@ Overlay Information = 오버레이 정보 Partial Stretch = 부분 늘이기 Percent of FPS = FPS 비율 Performance = 성능 -Postprocessing effect = 후처리 효과 Postprocessing Shader = 후처리 쉐이더 Recreate Activity = 활동 재생성 Render duplicate frames to 60hz = 중복 프레임을 60Hz로 렌더링 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 80da2bfb33..ed7954e6ba 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -527,7 +527,6 @@ Overlay Information = ການສະແດງຂໍ້ມູນຊ້ອນທ Partial Stretch = ແນວຕັ້ງດຶງເຕັມຈໍ Percent of FPS = Percent of FPS Performance = ປະສິດທິພາບ -Postprocessing effect = Postprocessing effects Postprocessing Shader = ຂະບວນການເຮັດວຽກໄລ່ປັບເສດສີ Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index f0d88f13e5..2f508639ba 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -527,7 +527,6 @@ Overlay Information = Užkadrinė informacija Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Greitis -Postprocessing effect = Postprocessing effects Postprocessing Shader = "Įdėjiniminio" krovimo "šešėliai" (FX) Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 8a70da4e01..7e93e331dd 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -527,7 +527,6 @@ Overlay Information = Maklumat pertindihan Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Prestasi -Postprocessing effect = Postprocessing effects Postprocessing Shader = Pascapemprosesan Shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 1279d2fe05..a39d5cb72b 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -527,7 +527,6 @@ Overlay Information = Informatie op het scherm Partial Stretch = Gedeeltelijk uitrekken Percent of FPS = Percent of FPS Performance = Prestaties -Postprocessing effect = Postprocessing effects Postprocessing Shader = Nabewerkingsshader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 95ac67e534..f4b4a42217 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -527,7 +527,6 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 604d4b7e23..b4c2094fc4 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -527,7 +527,6 @@ Overlay Information = Nakładka informacyjna Partial Stretch = Częściowe rozciągnięcie Percent of FPS = Procent FPS Performance = Wydajność -Postprocessing effect = Postprocessing effects Postprocessing Shader = Efekty wizualne shaderów Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 1341c5cd8b..d3891c6714 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -551,7 +551,6 @@ Overlay Information = Informações da sobreposição Partial Stretch = Esticamento parcial Percent of FPS = Porcentagem dos FPS Performance = Performance -Postprocessing effect = Efeitos de pós-processamento Postprocessing Shader = Shader de pós-processamento Recreate Activity = Recriar atividade Render duplicate frames to 60hz = Renderizar frames duplicados a 60 Hz diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 0f1c44dc45..c708b368d4 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -551,7 +551,6 @@ Overlay Information = Informações da sobreposição Partial Stretch = Esticamento Parcial Percent of FPS = Percentagem dos FPS Performance = Performance -Postprocessing effect = Efeitos de Pós-Processamento Postprocessing Shader = Shader de Pós-Processamento Recreate Activity = Recriar atividade Render duplicate frames to 60hz = Renderizar quadros duplicados a 60 Hz diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index de55371650..86dc65bf2a 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -527,7 +527,6 @@ Overlay Information = Informație suprapusă Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performanță -Postprocessing effect = Postprocessing effects Postprocessing Shader = Shader postprocesare Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index b596255985..76f7d44d5c 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -527,7 +527,6 @@ Overlay Information = Информация в оверлее Partial Stretch = Частичное растягивание Percent of FPS = Процент от FPS Performance = Производительность -Postprocessing effect = Эффекты постобработки Postprocessing Shader = Постобработка (шейдер) Recreate Activity = Создать активность заново Render duplicate frames to 60hz = Рендеринг дублирующихся кадров до 60 Гц diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 2609d96237..57cb40b2eb 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -527,7 +527,6 @@ Overlay Information = Overlay-information Partial Stretch = Partial stretch Percent of FPS = Procent av FPS Performance = Prestanda -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing-Shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index f11d6cb979..31094be5de 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -527,7 +527,6 @@ Overlay Information = Overlay na impormasyon Partial Stretch = Parsiyal na unatin Percent of FPS = Porsiyento ng FPS Performance = Performance -Postprocessing effect = Postprocessing effects Postprocessing Shader = Postprocessing shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index e29a10547b..f198a1059c 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -527,7 +527,6 @@ Overlay Information = การแสดงข้อมูลซ้อนทั Partial Stretch = แนวตั้งดึงเต็มจอ Percent of FPS = อิงจากเปอร์เซ็นต์เฟรมต่อวิ Performance = ประสิทธิภาพ -Postprocessing effect = กระบวนการทำงานปรับเอฟเฟ็คท์ Postprocessing Shader = กระบวนการทำงานปรับเฉดแสงสี Recreate Activity = สร้างกิจกรรมใหม่ Render duplicate frames to 60hz = แสดงผลเฟรมซ้ำให้ถึง 60 เฮิร์ตซ diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 61e3ea259d..60a754b9a9 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -529,7 +529,6 @@ Overlay Information = Ek Bilgi Partial Stretch = Tam ekran (kısmi sünme) Percent of FPS = FPS yüzdesi Performance = Performans -Postprocessing effect = Postprocessing efektleri Postprocessing Shader = Postprocessing gölgelendiricisi Recreate Activity = Recreate activity Render duplicate frames to 60hz = Yinelenen kareleri 60Hz'de işleyin diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 5fb8c200b0..4f3e84db04 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -527,7 +527,6 @@ Overlay Information = Інформація про накладення Partial Stretch = Часткове розтягнення Percent of FPS = Відсоток FPS Performance = Продуктивність -Postprocessing effect = Postprocessing effects Postprocessing Shader = &Подальша обробка (шейдер) Recreate Activity = Відтворити діяльність Render duplicate frames to 60hz = Відображення повторюваних кадрів до 60 Гц diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index ae713388a9..ca5258e328 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -527,7 +527,6 @@ Overlay Information = Hiển thị thông tin trên màn hình Partial Stretch = Từng phần dãn ra Percent of FPS = Percent of FPS Performance = Hiệu năng -Postprocessing effect = Postprocessing effects Postprocessing Shader = Xử lý hậu đổ bóng Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 84ce0f679e..6318a5171e 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -527,7 +527,6 @@ Overlay Information = 叠加信息 Partial Stretch = 部分拉伸 Percent of FPS = 帧率的百分比 Performance = 性能 -Postprocessing effect = 滤镜效果 Postprocessing Shader = 后处理着色器 Recreate Activity = 重建进程 Render duplicate frames to 60hz = 渲染重复帧至60Hz diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 2572eeaedb..64e0cf7902 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -527,7 +527,6 @@ Overlay Information = 覆疊資訊 Partial Stretch = 部分延展 Percent of FPS = FPS 百分比 Performance = 效能 -Postprocessing effect = 後處理效果 Postprocessing Shader = 後處理著色器 Recreate Activity = 重新建立活動 Render duplicate frames to 60hz = 轉譯重複影格至 60 Hz From ed7f3d69a7b546cdcacebeb021b36d7ee2e4efa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 12:09:06 +0100 Subject: [PATCH 618/715] Rename Postprocessing shader to Postprocessing shaders. Make low-effort attempt at updating --- UI/DisplayLayoutScreen.cpp | 6 +++++- assets/lang/ar_AE.ini | 2 +- assets/lang/az_AZ.ini | 2 +- assets/lang/bg_BG.ini | 2 +- assets/lang/ca_ES.ini | 2 +- assets/lang/cz_CZ.ini | 2 +- assets/lang/da_DK.ini | 2 +- assets/lang/de_DE.ini | 2 +- assets/lang/dr_ID.ini | 2 +- assets/lang/en_US.ini | 2 +- assets/lang/es_ES.ini | 2 +- assets/lang/es_LA.ini | 2 +- assets/lang/fa_IR.ini | 2 +- assets/lang/fi_FI.ini | 2 +- assets/lang/fr_FR.ini | 2 +- assets/lang/gl_ES.ini | 2 +- assets/lang/gr_EL.ini | 2 +- assets/lang/he_IL.ini | 2 +- assets/lang/he_IL_invert.ini | 2 +- assets/lang/hr_HR.ini | 2 +- assets/lang/hu_HU.ini | 2 +- assets/lang/id_ID.ini | 2 +- assets/lang/it_IT.ini | 2 +- assets/lang/ja_JP.ini | 2 +- assets/lang/jv_ID.ini | 2 +- assets/lang/ko_KR.ini | 2 +- assets/lang/lo_LA.ini | 2 +- assets/lang/lt-LT.ini | 2 +- assets/lang/ms_MY.ini | 2 +- assets/lang/nl_NL.ini | 2 +- assets/lang/no_NO.ini | 2 +- assets/lang/pl_PL.ini | 2 +- assets/lang/pt_BR.ini | 14 +++++++------- assets/lang/pt_PT.ini | 2 +- assets/lang/ro_RO.ini | 2 +- assets/lang/ru_RU.ini | 2 +- assets/lang/sv_SE.ini | 2 +- assets/lang/tg_PH.ini | 2 +- assets/lang/th_TH.ini | 2 +- assets/lang/tr_TR.ini | 2 +- assets/lang/uk_UA.ini | 2 +- assets/lang/vi_VN.ini | 2 +- assets/lang/zh_CN.ini | 2 +- assets/lang/zh_TW.ini | 2 +- 44 files changed, 54 insertions(+), 50 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 94d88ddf06..074c0c8454 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -289,7 +289,11 @@ void DisplayLayoutScreen::CreateViews() { shaderRow->SetSpacing(4.0f); leftColumn->Add(shaderRow); - postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f))); + if (shaderNames_[i] != "Off") { + postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f))); + } else { + postProcChoice_ = shaderRow->Add(new Choice(ImageID("I_PLUS"))); + } postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Postprocessing shaders"), i, false); diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 5f1df8b382..cfe820017d 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -535,7 +535,7 @@ Overlay Information = ‎معلومات النسق Partial Stretch = ‎تمطيط جزئي Percent of FPS = Percent of FPS Performance = ‎الأداء -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 43d6a5ceff..8e128787d4 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 99b813314c..bfe20b675b 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -527,7 +527,7 @@ Overlay Information = Обща информация Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 3ea943ea74..39012a1d45 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index d75814f98c..d01f3b4a6b 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -527,7 +527,7 @@ Overlay Information = Informace v překryvu Partial Stretch = Částečné roztažení Percent of FPS = Percent of FPS Performance = Výkon -Postprocessing Shader = Shader následného zpracování +Postprocessing shaders = Shader následného zpracování Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 69d88be3a5..175826444f 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay information Partial Stretch = Delvis strukket Percent of FPS = Percent of FPS Performance = Ydelse -Postprocessing Shader = Efterbehandlings-shader +Postprocessing shaders = Efterbehandlings-shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index d8ca26e9cb..d8c818b1a6 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -527,7 +527,7 @@ Overlay Information = Eingeblendete Informationen Partial Stretch = Teilweise strecken Percent of FPS = Prozent an FPS Performance = Leistung -Postprocessing Shader = Nachbearbeitungs-Shader +Postprocessing shaders = Nachbearbeitungs-Shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Kann Framerate smoother in Spielen machen, die eine niedrige Framerate haben. diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index f36af98dc6..2d8fe93cea 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -527,7 +527,7 @@ Overlay Information = Pempakitan Overlay Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 4f18c1f24d..e7d6e56f25 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -478,7 +478,6 @@ Use UI background = Use UI background 9x PSP = 9× PSP 10x PSP = 10× PSP 16x = 16× -Add postprocessing shader = Add postprocessing shader Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) @@ -1061,6 +1060,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Information = Display information diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index cf952cdafa..2fc9427bcd 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -527,7 +527,7 @@ Overlay Information = Información en pantalla Partial Stretch = Estirado parcial Percent of FPS = % de FPS Performance = Rendimiento -Postprocessing Shader = Shader de postprocesado +Postprocessing shaders = Shaders de postprocesado Recreate Activity = Recrear actividad Render duplicate frames to 60hz = Renderizar cuadros duplicados a 60Hz RenderDuplicateFrames Tip = Puede hacer la imagen más fluida in juegos con una tasa de cuadros más baja. diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index dbc54513bb..f79c3ed1d5 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -527,7 +527,7 @@ Overlay Information = Información en pantalla Partial Stretch = Estirado parcial Percent of FPS = % de FPS Performance = Rendimiento -Postprocessing Shader = Shader de postprocesado +Postprocessing shaders = Shaders de postprocesado Recreate Activity = Recrear actividad Render duplicate frames to 60hz = Procesar cuadros duplicados a 60 Hz RenderDuplicateFrames Tip = Puede hacer que la fluidez sea más suave en juegos con tasas de cuadros bajas. diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index f828b82e71..7a20277cf1 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -527,7 +527,7 @@ Overlay Information = ‎Overlay اطلاعات Partial Stretch = ‎کشیدگی جزئی Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = ‎افکت پس-پردازش +Postprocessing shaders = ‎افکت پس-پردازش Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index bbbfbac99c..62f3be2ef9 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 2c22ac4eb1..ddc0a96e5d 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -527,7 +527,7 @@ Overlay Information = Informations incrustées à l'écran Partial Stretch = Étirement partiel Percent of FPS = Pourcentage de FPS Performance = Performances -Postprocessing Shader = Shaders de post-traitement +Postprocessing shaders = Shaders de post-traitement Recreate Activity = Recréer l'animation Render duplicate frames to 60hz = Dupliquer les images pour atteindre 60 Hz RenderDuplicateFrames Tip = Peut améliorer la fluidité dans les jeux qui fonctionnent à des fréquences d'images plus faibles diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 630b96feb8..6347325170 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -527,7 +527,7 @@ Overlay Information = Información en pantalla Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Rendemento -Postprocessing Shader = Shader de postprocesado +Postprocessing shaders = Shaders de postprocesado Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 8fceeb73bc..cb2ff97c56 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -527,7 +527,7 @@ Overlay Information = Πληροφορίες Οθόνης Partial Stretch = Μερική επέκταση Percent of FPS = Percent of FPS Performance = Επίδοσεις -Postprocessing Shader = Shader Μετεπεξεργασίας +Postprocessing shaders = Shaders Μετεπεξεργασίας Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index cf2351b69e..d2d8f486d6 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -527,7 +527,7 @@ Overlay Information = כיסוי מידע Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 4c914cff23..9068566a76 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -527,7 +527,7 @@ Overlay Information = עדימ יוסיכ Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 8875a7ad98..2c347fe787 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -527,7 +527,7 @@ Overlay Information = Prekrivanje informacija Partial Stretch = Djelomično rastezanje Percent of FPS = Postotak FPS-a Performance = Performansa -Postprocessing Shader = Sjenčanje poslije procesa +Postprocessing shaders = Sjenčanje poslije procesa Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Izlgađiva frameove u igrama koje ih jako malo imaju diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 93c47f1709..70150dcb4d 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay információk Partial Stretch = Részleges nyújtás Percent of FPS = FPS százalékában Performance = Teljesítmény -Postprocessing Shader = Utóeffektező shader +Postprocessing shaders = Utóeffektező shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Képkockák duplázása 60 Hz rendereléshez RenderDuplicateFrames Tip = Simábbá teheti az alacsonyabb képkocka számon futó játékok kirajzolását diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 74c91387ce..bb4226dc7f 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -527,7 +527,7 @@ Overlay Information = Tampilan Informasi Partial Stretch = Peregangan sebagian Percent of FPS = Persen FPS Performance = Kinerja -Postprocessing Shader = Pemrosesan shader +Postprocessing shaders = Pemrosesan shaders Recreate Activity = Buat ulang aktivitas Render duplicate frames to 60hz = Pelukisan bingkai duplikat menjadi 60 Hz RenderDuplicateFrames Tip = Dapat membuat laju bingkai lebih lancar dalam permainan yang berjalan pada laju bingkai yang lebih rendah diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 56918bf5a7..8dea8e447c 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -528,7 +528,7 @@ Overlay Information = Copri Informazioni Partial Stretch = Estensione Parziale Percent of FPS = Percentuale di FPS Performance = Prestazioni -Postprocessing Shader = Shader di post-elaborazione +Postprocessing shaders = Shader di post-elaborazione Recreate Activity = Ricrea l'animazione Render duplicate frames to 60hz = Duplica i frame da renderizzare a 60 Hz RenderDuplicateFrames Tip = Può migliorare la fluidità nei giochi che funzionano a frame rate inferiori diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 2994e6ee46..ee55c7e99c 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -527,7 +527,7 @@ Overlay Information = オーバーレイ表示 Partial Stretch = 部分的に拡大 Percent of FPS = FPS中のパーセント Performance = パフォーマンス -Postprocessing Shader = 後処理シェーダ +Postprocessing shaders = 後処理シェーダ Recreate Activity = Recreate activity Render duplicate frames to 60hz = フレームを複製して60Hzでレンダリングする RenderDuplicateFrames Tip = フレームレートが低いゲームでフレームレートをよりスムーズにできます diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 69e8030181..8c7d386bb6 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -527,7 +527,7 @@ Overlay Information = Informasi numpuki Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Kinerja -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 36258311cb..a1919793ae 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -527,7 +527,7 @@ Overlay Information = 오버레이 정보 Partial Stretch = 부분 늘이기 Percent of FPS = FPS 비율 Performance = 성능 -Postprocessing Shader = 후처리 쉐이더 +Postprocessing shaders = 후처리 쉐이더 Recreate Activity = 활동 재생성 Render duplicate frames to 60hz = 중복 프레임을 60Hz로 렌더링 RenderDuplicateFrames Tip = 낮은 프레임 속도에서 실행되는 게임에서 프레임 속도를 더 부드럽게 만들 수 있습니다. diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index ed7954e6ba..6aca838f3c 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -527,7 +527,7 @@ Overlay Information = ການສະແດງຂໍ້ມູນຊ້ອນທ Partial Stretch = ແນວຕັ້ງດຶງເຕັມຈໍ Percent of FPS = Percent of FPS Performance = ປະສິດທິພາບ -Postprocessing Shader = ຂະບວນການເຮັດວຽກໄລ່ປັບເສດສີ +Postprocessing shaders = ຂະບວນການເຮັດວຽກໄລ່ປັບເສດສີ Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 2f508639ba..d6afbeda6e 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -527,7 +527,7 @@ Overlay Information = Užkadrinė informacija Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Greitis -Postprocessing Shader = "Įdėjiniminio" krovimo "šešėliai" (FX) +Postprocessing shaders = "Įdėjiniminio" krovimo "šešėliai" (FX) Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 7e93e331dd..f9ce1af659 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -527,7 +527,7 @@ Overlay Information = Maklumat pertindihan Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Prestasi -Postprocessing Shader = Pascapemprosesan Shader +Postprocessing shaders = Pascapemprosesan Shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index a39d5cb72b..82436dc220 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -527,7 +527,7 @@ Overlay Information = Informatie op het scherm Partial Stretch = Gedeeltelijk uitrekken Percent of FPS = Percent of FPS Performance = Prestaties -Postprocessing Shader = Nabewerkingsshader +Postprocessing shaders = Nabewerkingsshaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index f4b4a42217..4870106ec3 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index b4c2094fc4..b8b0c3fc49 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -527,7 +527,7 @@ Overlay Information = Nakładka informacyjna Partial Stretch = Częściowe rozciągnięcie Percent of FPS = Procent FPS Performance = Wydajność -Postprocessing Shader = Efekty wizualne shaderów +Postprocessing shaders = Efekty wizualne shaderów Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index d3891c6714..f9581a2f37 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -518,7 +518,7 @@ Frame Skipping = Pulo dos frames Frame Skipping Type = Tipo de pulo dos frames FullScreen = Tela cheia Geometry shader culling = Abate do shader da geometria -Hack Settings = Configurações dos hacks (pode causar erros gráficos) +Hack Settings = Configurações dos hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por hardware Hardware Transform = Transformação por hardware hardware transform error - falling back to software = Erro de transformação pelo hardware, retrocedendo pro software. @@ -551,7 +551,7 @@ Overlay Information = Informações da sobreposição Partial Stretch = Esticamento parcial Percent of FPS = Porcentagem dos FPS Performance = Performance -Postprocessing Shader = Shader de pós-processamento +Postprocessing shaders = Shaders de pós-processamento Recreate Activity = Recriar atividade Render duplicate frames to 60hz = Renderizar frames duplicados a 60 Hz RenderDuplicateFrames Tip = Pode tornar a taxa dos frames mais suave em jogos que executam em taxas de frames menores @@ -886,10 +886,10 @@ tools = Ferramentas grátis usadas: # Leave extra lines blank. 4 contributors per line seems to look best. translators1 = Papel, gabrielmop, Efraim Lopes, AkiraJkr translators2 = Felipe -translators3 = -translators4 = -translators5 = -translators6 = +translators3 = +translators4 = +translators5 = +translators6 = Twitter @PPSSPP_emu = Twitter @PPSSPP_emu website = Verifique o site da web: written = Escrito em C++ pela velocidade e portabilidade @@ -990,7 +990,7 @@ View Feedback = Visualizar todos os feedbacks Date = Data Filename = Nome do arquivo No screenshot = Sem screenshot -None yet. Things will appear here after you save. = Nada ainda. As coisas aparecerão aqui após você salvar. +None yet. Things will appear here after you save. = Nada ainda. As coisas aparecerão aqui após você salvar. Nothing matching '%1' was found. = Nada combinando com o '%1' foi achado. Save Data = Dados salvos Save States = States salvos diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index c708b368d4..7454ae808f 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -551,7 +551,7 @@ Overlay Information = Informações da sobreposição Partial Stretch = Esticamento Parcial Percent of FPS = Percentagem dos FPS Performance = Performance -Postprocessing Shader = Shader de Pós-Processamento +Postprocessing shaders = Shaders de Pós-Processamento Recreate Activity = Recriar atividade Render duplicate frames to 60hz = Renderizar quadros duplicados a 60 Hz RenderDuplicateFrames Tip = Pode tornar a taxa dos quadros mais suave em jogos que executam em taxas de quadros menores diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 86dc65bf2a..fcbd230d25 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -527,7 +527,7 @@ Overlay Information = Informație suprapusă Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performanță -Postprocessing Shader = Shader postprocesare +Postprocessing shaders = Shaders postprocesare Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 76f7d44d5c..73a61761ba 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -527,7 +527,7 @@ Overlay Information = Информация в оверлее Partial Stretch = Частичное растягивание Percent of FPS = Процент от FPS Performance = Производительность -Postprocessing Shader = Постобработка (шейдер) +Postprocessing shaders = Постобработка (шейдер) Recreate Activity = Создать активность заново Render duplicate frames to 60hz = Рендеринг дублирующихся кадров до 60 Гц RenderDuplicateFrames Tip = Может сгладить частоту кадров в тех играх, где она низкая diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 57cb40b2eb..8984620e83 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay-information Partial Stretch = Partial stretch Percent of FPS = Procent av FPS Performance = Prestanda -Postprocessing Shader = Postprocessing-Shader +Postprocessing shaders = Postprocessing-Shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 31094be5de..e1e755dc0c 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -527,7 +527,7 @@ Overlay Information = Overlay na impormasyon Partial Stretch = Parsiyal na unatin Percent of FPS = Porsiyento ng FPS Performance = Performance -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index f198a1059c..245b775fb2 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -527,7 +527,7 @@ Overlay Information = การแสดงข้อมูลซ้อนทั Partial Stretch = แนวตั้งดึงเต็มจอ Percent of FPS = อิงจากเปอร์เซ็นต์เฟรมต่อวิ Performance = ประสิทธิภาพ -Postprocessing Shader = กระบวนการทำงานปรับเฉดแสงสี +Postprocessing shaders = กระบวนการทำงานปรับเฉดแสงสี Recreate Activity = สร้างกิจกรรมใหม่ Render duplicate frames to 60hz = แสดงผลเฟรมซ้ำให้ถึง 60 เฮิร์ตซ RenderDuplicateFrames Tip = ช่วยให้ภาพดูลื่นตาขึ้น ในเกมที่ใช้เฟรมเรทต่ำ diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 60a754b9a9..35bc0318bb 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -529,7 +529,7 @@ Overlay Information = Ek Bilgi Partial Stretch = Tam ekran (kısmi sünme) Percent of FPS = FPS yüzdesi Performance = Performans -Postprocessing Shader = Postprocessing gölgelendiricisi +Postprocessing shaders = Postprocessing gölgelendiricisi Recreate Activity = Recreate activity Render duplicate frames to 60hz = Yinelenen kareleri 60Hz'de işleyin RenderDuplicateFrames Tip = Daha düşük kare hızlarında çalışan oyunlarda kare hızını düzeltebilir diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 4f3e84db04..913909df96 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -527,7 +527,7 @@ Overlay Information = Інформація про накладення Partial Stretch = Часткове розтягнення Percent of FPS = Відсоток FPS Performance = Продуктивність -Postprocessing Shader = &Подальша обробка (шейдер) +Postprocessing shaders = &Подальша обробка (шейдер) Recreate Activity = Відтворити діяльність Render duplicate frames to 60hz = Відображення повторюваних кадрів до 60 Гц RenderDuplicateFrames Tip = Можна зробити більш плавний кадр в іграх, які працюють у нижчих кадрах diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index ca5258e328..ae19c2cb29 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -527,7 +527,7 @@ Overlay Information = Hiển thị thông tin trên màn hình Partial Stretch = Từng phần dãn ra Percent of FPS = Percent of FPS Performance = Hiệu năng -Postprocessing Shader = Xử lý hậu đổ bóng +Postprocessing shaders = Xử lý hậu đổ bóng Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 6318a5171e..be9a9d185a 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -527,7 +527,7 @@ Overlay Information = 叠加信息 Partial Stretch = 部分拉伸 Percent of FPS = 帧率的百分比 Performance = 性能 -Postprocessing Shader = 后处理着色器 +Postprocessing shaders = 后处理着色器 Recreate Activity = 重建进程 Render duplicate frames to 60hz = 渲染重复帧至60Hz RenderDuplicateFrames Tip = 在较低帧率的游戏中可以使帧速率更平滑 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 64e0cf7902..912e9af28a 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -527,7 +527,7 @@ Overlay Information = 覆疊資訊 Partial Stretch = 部分延展 Percent of FPS = FPS 百分比 Performance = 效能 -Postprocessing Shader = 後處理著色器 +Postprocessing shaders = 後處理著色器 Recreate Activity = 重新建立活動 Render duplicate frames to 60hz = 轉譯重複影格至 60 Hz RenderDuplicateFrames Tip = 可以使以較低影格速率執行的遊戲更加順暢 From 49e55135c582e92b6988ec041c7aa69f6cb2c71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 12:10:45 +0100 Subject: [PATCH 619/715] Translation: Copy missing lines --- assets/lang/ar_AE.ini | 4 ++++ assets/lang/az_AZ.ini | 4 ++++ assets/lang/bg_BG.ini | 4 ++++ assets/lang/ca_ES.ini | 4 ++++ assets/lang/cz_CZ.ini | 4 ++++ assets/lang/da_DK.ini | 4 ++++ assets/lang/de_DE.ini | 4 ++++ assets/lang/dr_ID.ini | 4 ++++ assets/lang/es_ES.ini | 4 ++++ assets/lang/es_LA.ini | 4 ++++ assets/lang/fa_IR.ini | 4 ++++ assets/lang/fi_FI.ini | 4 ++++ assets/lang/fr_FR.ini | 4 ++++ assets/lang/gl_ES.ini | 4 ++++ assets/lang/gr_EL.ini | 4 ++++ assets/lang/he_IL.ini | 4 ++++ assets/lang/he_IL_invert.ini | 4 ++++ assets/lang/hr_HR.ini | 4 ++++ assets/lang/hu_HU.ini | 4 ++++ assets/lang/id_ID.ini | 4 ++++ assets/lang/it_IT.ini | 4 ++++ assets/lang/ja_JP.ini | 4 ++++ assets/lang/jv_ID.ini | 4 ++++ assets/lang/ko_KR.ini | 4 ++++ assets/lang/lo_LA.ini | 4 ++++ assets/lang/lt-LT.ini | 4 ++++ assets/lang/ms_MY.ini | 4 ++++ assets/lang/nl_NL.ini | 4 ++++ assets/lang/no_NO.ini | 4 ++++ assets/lang/pl_PL.ini | 4 ++++ assets/lang/pt_BR.ini | 5 +++++ assets/lang/pt_PT.ini | 4 ++++ assets/lang/ro_RO.ini | 4 ++++ assets/lang/ru_RU.ini | 3 +++ assets/lang/sv_SE.ini | 4 ++++ assets/lang/tg_PH.ini | 4 ++++ assets/lang/th_TH.ini | 4 ++++ assets/lang/tr_TR.ini | 4 ++++ assets/lang/uk_UA.ini | 4 ++++ assets/lang/vi_VN.ini | 4 ++++ assets/lang/zh_CN.ini | 4 ++++ assets/lang/zh_TW.ini | 4 ++++ 42 files changed, 168 insertions(+) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index cfe820017d..7fca56e265 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -321,6 +321,8 @@ Load completed = ‎التحميل إكتمل. Loading = ‎تحميل\nمن فضلك إنتظر... LoadingFailed = ‎غير قادر علي تحميل البيانات. Move = ‎تحريك +Move Down = Move Down +Move Up = Move Up Network Connection = ‎إتصال الشبكة NEW DATA = ‎بيانات جديدة No = ‎لا @@ -328,6 +330,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = ‎حسناً Old savedata detected = ‎بيانات حفظ قديمة قد إكتشفت Options = ‎إعدادات +Remove = Remove Reset = ‎إستعادة Resize = ‎تغيير الحجم Retry = ‎حاول مجدداً @@ -1048,6 +1051,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 8e128787d4..77b127ddd3 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -313,6 +313,8 @@ Load completed = Yükləmə Tamamlandı Loading = Yüklənir\nZəhmət Olmasa Gözləyin... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = Xeyir @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index bfe20b675b..8448605e28 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -313,6 +313,8 @@ Load completed = Зареждането завършено. Loading = Зареждане\nМоля изчакайте... LoadingFailed = Unable to load data. Move = Преместване +Move Down = Move Down +Move Up = Move Up Network Connection = Мрежова връзка NEW DATA = Нови данни No = Не @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Преоразмеряване Retry = Нов опит @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 39012a1d45..6aaddb4987 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -313,6 +313,8 @@ Load completed = Carrega completada Loading = Carregant\nEspera un moment... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = No @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index d01f3b4a6b..6870e757c8 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -313,6 +313,8 @@ Load completed = Načítání dokončeno. Loading = Načítání\nČekejte prosím... LoadingFailed = Nelze načíst data. Move = Přesunout +Move Down = Move Down +Move Up = Move Up Network Connection = Síťové připojení NEW DATA = NOVÁ DATA No = Ne @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Zjištěna stará uložená data Options = Volby +Remove = Remove Reset = Resetovat Resize = Velikost Retry = Zkusit znovu @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 175826444f..26516055bc 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -313,6 +313,8 @@ Load completed = Hentet. Loading = Henter\nVent venligst... LoadingFailed = Ikke muligt at indlæse data. Move = Flyt +Move Down = Move Down +Move Up = Move Up Network Connection = Netværksforbindelse NEW DATA = NY DATA No = Nej @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Gamle savedata fundet Options = Optioner +Remove = Remove Reset = Nulstil Resize = Størrelse Retry = Prøv igen @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index d8c818b1a6..9f351c67d8 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -313,6 +313,8 @@ Load completed = Laden abgeschlossen Loading = Laden\nBitte warten... LoadingFailed = Daten konnten nicht geladen werden. Move = Bewegen +Move Down = Move Down +Move Up = Move Up Network Connection = Netzwerkverbindung NEW DATA = Neue Daten No = Nein @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Alter Speicherstand entdeckt Options = Optionen +Remove = Remove Reset = Zurücksetzen Resize = Größe ändern Retry = Wiederholen @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger vorhanden +Depth buffer format = Depth buffer format Device Info = Geräteinfo Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 2d8fe93cea..be19011bf0 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -313,6 +313,8 @@ Load completed = Tibukka'mi. Loading = Dibukka'i\nTajammi... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = DATA baru No = Edda mane @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Okemi mane Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 2fc9427bcd..0e08165255 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -313,6 +313,8 @@ Load completed = Carga completada. Loading = Cargando\nEspera un momento... LoadingFailed = Los datos del juego no se pudieron cargar. Move = Posición +Move Down = Move Down +Move Up = Move Up Network Connection = Conexión de red NEW DATA = NUEVOS DATOS DE PARTIDA No = No @@ -320,6 +322,7 @@ ObtainingIP = Obteniendo direcciónnn IP.\nPor favor espera... OK = Aceptar Old savedata detected = Se han detectado datos del juego antiguos. Options = Opciones +Remove = Remove Reset = Reiniciar Resize = Tamaño Retry = Reintentar @@ -1040,6 +1043,7 @@ CPU Name = Nombre D3DCompiler Version = Versión del compilador D3D Debug = Desarrollo Debugger Present = Depurador presente +Depth buffer format = Depth buffer format Device Info = Info. del dispositivo Directories = Directorios Display Color Formats = Display Color Formats diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index f79c3ed1d5..1c60ffd956 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -313,6 +313,8 @@ Load completed = Datos cargados. Loading = Cargando\nPor favor espere... LoadingFailed = Los datos del juego no se pudieron cargar. Move = Mover +Move Down = Move Down +Move Up = Move Up Network Connection = Conexión de red NEW DATA = CREAR DATOS No = No @@ -320,6 +322,7 @@ ObtainingIP = Obteniendo dirección IP.\nEspera un momento... OK = OK Old savedata detected = Se han detectado datos del juego antiguos. Options = Opciones +Remove = Remove Reset = Reiniciar Resize = Tamaño Retry = Reintentar @@ -1040,6 +1043,7 @@ CPU Name = Nombre D3DCompiler Version = Versión del compilador D3D Debug = Desarrollo Debugger Present = Depurador presente +Depth buffer format = Depth buffer format Device Info = Info de dispositivo Directories = Directorios Display Color Formats = Display Color Formats diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 7a20277cf1..ce59fe1520 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -313,6 +313,8 @@ Load completed = ‎.بارگیری نکمیل شد Loading = ‎درحال بارگیری\n...منتظر بمانید LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = ‎دیتای جدید No = ‎خیر @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = ‎تایید Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 62f3be2ef9..030b9adfbe 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -313,6 +313,8 @@ Load completed = Lataus onnistui. Loading = Ladataan\nOdota... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = Ei @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index ddc0a96e5d..20bf66436f 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -313,6 +313,8 @@ Load completed = Chargement terminé. Loading = Chargement\nVeuillez patienter... LoadingFailed = Chargement impossible. Move = Déplacer +Move Down = Move Down +Move Up = Move Up Network Connection = Connexion réseau NEW DATA = NOUVELLES DONNÉES No = Non @@ -320,6 +322,7 @@ ObtainingIP = Obtention de l'adresse IP\nVeuillez patienter... OK = OK Old savedata detected = Ancienne sauvegarde détectée Options = Options +Remove = Remove Reset = Remise à 0 Resize = Zoomer Retry = Réessayer @@ -1031,6 +1034,7 @@ CPU Name = Nom D3DCompiler Version = Version de D3DCompiler Debug = Débogage Debugger Present = Débogueur présent +Depth buffer format = Depth buffer format Device Info = Informations sur l'appareil Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 6347325170..5384d7b934 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -313,6 +313,8 @@ Load completed = Carga completada. Loading = Cargando\nAgarda un momento... LoadingFailed = Os datos nom se puideron cargar. Move = Posición +Move Down = Move Down +Move Up = Move Up Network Connection = Conexión de rede NEW DATA = NOVOS DATOS No = Non @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Aceptar Old savedata detected = Detectados datos de gardado antigos. Options = Options +Remove = Remove Reset = Reiniciar Resize = Tamaño Retry = Reintentar @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index cb2ff97c56..113602a7a2 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -313,6 +313,8 @@ Load completed = ΦΟΡΤΩΣΗ ΟΛΟΚΛΗΡΩΘΗΚΕ Loading = ΦΟΡΤΩΣΗ\nΠΑΡΑΚΑΛΩ ΠΕΡΙΜΕΝΕΤΕ... LoadingFailed = ΑΔΥΝΑΜΙΑ ΦΟΡΤΩΣΗΣ ΔΕΔΟΜΕΝΩΝ. Move = ΜΕΤΑΚΙΝΗΣΗ +Move Down = Move Down +Move Up = Move Up Network Connection = ΣΥΝΔΕΣΗ ΔΙΚΤΥΟΥ NEW DATA = ΝΕΑ ΔΕΔΟΜΕΝΑ No = ΟΧΙ @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Εντοπίστηκαν παλαιά αρχεία αποθήκευσης Options = ΕΠΙΛΟΓΕΣ +Remove = Remove Reset = ΕΠΑΝΑΦΟΡΑ Resize = ΑΛΛΑΓΗ ΜΕΓΕΘΟΥΣ Retry = ΕΠΑΝΑΛΗΨΗ @@ -1040,6 +1043,7 @@ CPU Name = Όνομα D3DCompiler Version = Έκδοση D3DCompiler Debug = Εντοπισμός σφαλμάτων Debugger Present = Παρουσία πρόγραμματος εντοπισμού σφαλμάτων +Depth buffer format = Depth buffer format Device Info = Πληροφορίες συσκευής Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index d2d8f486d6..3e1145ab04 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -313,6 +313,8 @@ Load completed = .המלשוה הניעט Loading = ...ןתמה אנא ...ןעוט LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = םישדח םינותנ No = אל @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = רדסב Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 9068566a76..5087eeb6ac 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -313,6 +313,8 @@ Load completed = .המלשוה הניעט Loading = ...ןתמה אנא ...ןעוט LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = םישדח םינותנ No = אל @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = רדסב Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 2c347fe787..c39645fbd7 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -313,6 +313,8 @@ Load completed = Učitavanje dovršeno. Loading = Učitavanje\nPričekajte... LoadingFailed = Nije moguće učitati datu. Move = Pomakni +Move Down = Move Down +Move Up = Move Up Network Connection = Internetska veza NEW DATA = NOVA DATA No = Ne @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Uočena stara savedata Options = Opcije +Remove = Remove Reset = Reset Resize = Resize Retry = Ponovi @@ -1040,6 +1043,7 @@ CPU Name = Ime D3DCompiler Version = D3DCompiler verzija Debug = Otklanjanje grešaka Debugger Present = Otklanjivač grešaka prisutan +Depth buffer format = Depth buffer format Device Info = Informacije o uređaju Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 70150dcb4d..71859b15d9 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -313,6 +313,8 @@ Load completed = Betöltve. Loading = Betöltés\nKérlek várj... LoadingFailed = Betöltés sikertelen. Move = Mozgat +Move Down = Move Down +Move Up = Move Up Network Connection = Hálózati kapcsolat NEW DATA = ÚJ MENTÉS No = Nem @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Régi mentés észlelve Options = Opciók +Remove = Remove Reset = Visszaállít Resize = Átméretez Retry = Újra @@ -1040,6 +1043,7 @@ CPU Name = Név D3DCompiler Version = D3DCompiler verzió Debug = Hibakeresés Debugger Present = Debugger jelen +Depth buffer format = Depth buffer format Device Info = Eszközinfó Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index bb4226dc7f..e821086ee2 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -313,6 +313,8 @@ Load completed = Selesai memuat. Loading = Memuat\nMohon Tunggu... LoadingFailed = Tidak dapat memuat data. Move = Pindah +Move Down = Move Down +Move Up = Move Up Network Connection = Koneksi Jaringan NEW DATA = DATA BARU No = Tidak @@ -320,6 +322,7 @@ ObtainingIP = Mendapatkan alamat IP.\nHarap tunggu... OK = Oke Old savedata detected = Simpanan data lama terdeteksi Options = Pilihan +Remove = Remove Reset = Atur ulang Resize = Atur ulang ukuran Retry = Coba lagi @@ -1040,6 +1043,7 @@ CPU Name = Nama CPU D3DCompiler Version = Versi D3DCompiler Debug = Awakutu Debugger Present = Pengawakutu tersedia +Depth buffer format = Depth buffer format Device Info = Info perangkat Directories = Direktori Display Color Formats = Format warna tampilan diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 8dea8e447c..2e88064c95 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -313,6 +313,8 @@ Load completed = Caricamento completato. Loading = Caricamento in corso.\nAttendere, prego... LoadingFailed = Impossibile caricare i dati. Move = Sposta +Move Down = Move Down +Move Up = Move Up Network Connection = Connessione di Rete NEW DATA = NUOVI DATI No = No @@ -320,6 +322,7 @@ ObtainingIP = Cerco di ottenere l'indirizzo IP.\nAttendere, prego... OK = OK Old savedata detected = Rilevati vecchi dati salvati Options = Opzioni +Remove = Remove Reset = Reset Resize = Ridimensiona Retry = Riprova @@ -1041,6 +1044,7 @@ CPU Name = Nome D3DCompiler Version = Versione D3DCompiler Debug = Debug Debugger Present = Debugger presente +Depth buffer format = Depth buffer format Device Info = Informazioni dispositivo Directories = Cartelle Display Color Formats = Formati colore di visualizzazione diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index ee55c7e99c..4bb7bb99f2 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -313,6 +313,8 @@ Load completed = ロードが完了しました。 Loading = ロード中です。\nしばらくお待ちください... LoadingFailed = データをロードできませんでした。 Move = 移動 +Move Down = Move Down +Move Up = Move Up Network Connection = ネットワーク接続 NEW DATA = 新しいデータ No = いいえ @@ -320,6 +322,7 @@ ObtainingIP = IPアドレスの取得中。 \nしばらくお待ちください. OK = OK Old savedata detected = 古いセーブデータを検出しました Options = オプション +Remove = Remove Reset = リセット Resize = リサイズ Retry = リトライ @@ -1040,6 +1043,7 @@ CPU Name = CPU名 D3DCompiler Version = D3DCompilerバージョン Debug = デバッグ Debugger Present = デバッガーあり +Depth buffer format = Depth buffer format Device Info = デバイス情報 Directories = ディレクトリ Display Color Formats = Display Color Formats diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 8c7d386bb6..595b012bcb 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -313,6 +313,8 @@ Load completed = Mbukak rampung. Loading = Mbukak\nMohon nteni... LoadingFailed = Ora biso mbukak data. Move = Pindahno +Move Down = Move Down +Move Up = Move Up Network Connection = Koneksi Jaringan NEW DATA = DATA ANYAR No = Ora @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = He.eh Old savedata detected = Simpenan lawas terdeteksi Options = Opsi +Remove = Remove Reset = Ngreset Resize = Ubah Ukuran Retry = Jajal Maning @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index a1919793ae..c7af635ae7 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -313,6 +313,8 @@ Load completed = 불러오기가 완료되었습니다. Loading = 로딩 중\n잠시만 기다려 주세요... LoadingFailed = 데이터를 불러올 수 없습니다. Move = 이동 +Move Down = Move Down +Move Up = Move Up Network Connection = 네트워크 연결 NEW DATA = 새로운 데이터 No = 아니오 @@ -320,6 +322,7 @@ ObtainingIP = IP 주소를 가져오는 중입니다.\n잠시만 기다려 주 OK = 확인 Old savedata detected = 오래된 저장 데이터 감지됨 Options = 옵션 +Remove = Remove Reset = 재설정 Resize = 크기 조정 Retry = 재시도 @@ -1053,6 +1056,7 @@ CPU Name = 이름 D3DCompiler Version = D3D컴파일러 버전 Debug = 디버그 Debugger Present = 디버거 탐지 +Depth buffer format = Depth buffer format Device Info = 장치 정보 Directories = 디렉토리 Display Information = 정보 표시 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 6aca838f3c..b1cf4ebcbc 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -313,6 +313,8 @@ Load completed = ໂຫຼດຂໍ້ມູນສຳເລັດ Loading = ກຳລັງໂຫຼດ\nກະລຸນາລໍຖ້າ... LoadingFailed = ບໍ່ສາມາດໂຫຼດຂໍ້ມູນ. Move = ເຄື່ອນຍ້າຍ +Move Down = Move Down +Move Up = Move Up Network Connection = ການເຊື່ອມຕໍ່ເຄື່ອຂ່າຍ NEW DATA = ຂໍ້ມູນໃໝ່ No = ບໍ່ແມ່ນ @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = ຕົກລົງ Old savedata detected = ກວດພົບຂໍ້ມູນເຊບເກົ່າ Options = ໂຕເລືອກ +Remove = Remove Reset = ຕັ້ງຄ່າໃໝ່ Resize = ປັບຂະໜາດ Retry = ລອງໃໝ່ອີກຄັ້ງ @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index d6afbeda6e..2a64d882e3 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -313,6 +313,8 @@ Load completed = Krovimas baigtas. Loading = Kraunama\nPrašome palaukti... LoadingFailed = Neįmanoma krauti duomenų. Move = Perkelti +Move Down = Move Down +Move Up = Move Up Network Connection = Interneto tinklas NEW DATA = NAUJI DUOMENYS No = Ne @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Gerai Old savedata detected = Aptikti seniau išsaugoti duomenys Options = Options +Remove = Remove Reset = Perkrauti Resize = Perkeisti dydį Retry = Pabandyti dar kartą @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index f9ce1af659..4ecf0105ac 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -313,6 +313,8 @@ Load completed = Memuat selesai. Loading = Memuat\nSila tunggu... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = DATA BAHARU No = Tidak @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Mula semula Resize = Resize Retry = Cuba semula @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 82436dc220..cea29bbbc5 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -313,6 +313,8 @@ Load completed = Het laden is voltooid. Loading = Bezig met laden...\nEen ogenblik geduld. LoadingFailed = Kan de data niet laden. Move = Slepen +Move Down = Move Down +Move Up = Move Up Network Connection = Netwerkverbinding NEW DATA = NIEUWE DATA No = Nee @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Oude savedata gedetecteerd Options = Opties +Remove = Remove Reset = Herstellen Resize = Schalen Retry = Opnieuw @@ -1040,6 +1043,7 @@ CPU Name = Naam D3DCompiler Version = D3DCompiler version Debug = Fouten opsporen Debugger Present = Foutopsporing aanwezig +Depth buffer format = Depth buffer format Device Info = Apparaatinformatie Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 4870106ec3..d0808c29b7 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -313,6 +313,8 @@ Load completed = Ferdig lastet. Loading = Laster\nVent litt... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = Nei @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index b8b0c3fc49..b01d9e8770 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -313,6 +313,8 @@ Load completed = Ładowanie zakończone. Loading = Ładowanie\nProszę czekać... LoadingFailed = Nie można wczytać danych. Move = Przenieś +Move Down = Move Down +Move Up = Move Up Network Connection = Połączenie sieciowe NEW DATA = NOWE DANE No = Nie @@ -320,6 +322,7 @@ ObtainingIP = Uzyskiwanie adresu IP.\nProszę czekać... OK = OK Old savedata detected = Wykryto stary zapis gry Options = Opcje +Remove = Remove Reset = Resetuj Resize = Przeskaluj Retry = Spróbuj ponownie @@ -1040,6 +1043,7 @@ CPU Name = Nazwa D3DCompiler Version = Wersja D3DCompiler Debug = Debug Debugger Present = Debugger obecny +Depth buffer format = Depth buffer format Device Info = Inf. o urządzeniu Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index f9581a2f37..c58d1353b7 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -337,6 +337,8 @@ Load completed = Carregamento completado. Loading = Carregando\nPor favor espere... LoadingFailed = Incapaz de carregar os dados. Move = Mover +Move Down = Move Down +Move Up = Move Up Network Connection = Conexão de rede NEW DATA = NOVOS DADOS No = Não @@ -344,6 +346,7 @@ ObtainingIP = Obtendo endereço de IP.\nPor favor espere... OK = Ok Old savedata detected = Dados antigos do save detectados Options = Opções +Remove = Remove Reset = Resetar Resize = Redimensionar Retry = Tentar de novo @@ -1057,9 +1060,11 @@ CPU Name = Nome D3DCompiler Version = Versão do compilador D3D Debug = Debug Debugger Present = Debugger presente +Depth buffer format = Depth buffer format Device Info = Informação do dispositivo Directories = Diretórios Display Information = Informação da tela +Driver bugs = Driver bugs Driver Version = Versão do driver Driver Version = Versão do driver EGL Extensions = Extensões do EGL diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 7454ae808f..b5d98f0685 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -337,6 +337,8 @@ Load completed = Carregamento completado. Loading = Carregando\nPor favor espere... LoadingFailed = Incapaz de carregar os dados. Move = Mover +Move Down = Move Down +Move Up = Move Up Network Connection = Conexão de rede NEW DATA = NOVOS DADOS No = Não @@ -344,6 +346,7 @@ ObtainingIP = Obtendo o Endereço de IP.\nPor favor espere... OK = Ok Old savedata detected = Dados antigos do save detectados Options = Opções +Remove = Remove Reset = Reiniciar Resize = Redimensionar Retry = Tentar de novo @@ -1057,6 +1060,7 @@ CPU Name = Nome D3DCompiler Version = Versão do compilador D3D Debug = Debug Debugger Present = Depurador presente +Depth buffer format = Depth buffer format Device Info = Informação do dispositivo Directories = Diretórios Display Information = Informação da tela diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index fcbd230d25..135170999a 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -313,6 +313,8 @@ Load completed = Încărcare Completă Loading = Se încarcă\nAșteptați... LoadingFailed = Nu s-au putut încărca datele. Move = Mișcă +Move Down = Move Down +Move Up = Move Up Network Connection = Conexiune la rețea NEW DATA = DATE NOI No = Nu @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Date vechi salvate detectate Options = Options +Remove = Remove Reset = Resetare Resize = Modificare marime Retry = Reîncearcă @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 73a61761ba..318d699e06 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -313,6 +313,8 @@ Load completed = Загрузка завершена Loading = Загрузка\nПожалуйста, подождите... LoadingFailed = Невозможно загрузить даные. Move = Положение +Move Down = Move Down +Move Up = Move Up Network Connection = Сетевое подключение NEW DATA = Новое сохранение No = Нет @@ -320,6 +322,7 @@ ObtainingIP = Получение IP-адреса.\nПожалуйста, под OK = OK Old savedata detected = Старый формат сохранений обнаружен Options = Опции +Remove = Remove Reset = Сбросить Resize = Размер Retry = Снова diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 8984620e83..1863ae4623 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -313,6 +313,8 @@ Load completed = Laddat. Loading = Laddar\nVänta... LoadingFailed = Kunde inte ladda data. Move = Flytta +Move Down = Move Down +Move Up = Move Up Network Connection = Nätverksuppkoppling NEW DATA = NY DATA No = Nej @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Gammal savedata upptäckt Options = Options +Remove = Remove Reset = Återställ Resize = Ändra storlek Retry = Försök igen @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index e1e755dc0c..260c8f3ec6 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -313,6 +313,8 @@ Load completed = Kumpletong na-i load. Loading = Sandali lamang... LoadingFailed = Loading ng datos ay pumalya. Move = Galawin +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = BAGONG DATOS No = Hindi @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Sige Old savedata detected = Nahanap ang lumang savedata Options = Options +Remove = Remove Reset = Ibalik Resize = Resize Retry = Ulitin @@ -1040,6 +1043,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 245b775fb2..ace20b3246 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -313,6 +313,8 @@ Load completed = โหลดข้อมูลสำเร็จ Loading = กำลังโหลด\nโปรดรอ... LoadingFailed = ไม่สามารถโหลดข้อมูลนี้ได้ Move = ย้าย +Move Down = Move Down +Move Up = Move Up Network Connection = การเชื่อมต่อเครือข่าย NEW DATA = ข้อมูลใหม่ No = ไม่ใช่ @@ -320,6 +322,7 @@ ObtainingIP = กำลังรับไอพี\nโปรดรอสัก OK = ตกลง Old savedata detected = ตรวจพบข้อมูลเซฟเก่า Options = ตัวเลือก +Remove = Remove Reset = ตั้งค่าใหม่ Resize = ขนาด Retry = ลองใหม่ @@ -1040,6 +1043,7 @@ CPU Name = ชื่อหน่วยประมวลผลหลัก D3DCompiler Version = เวอร์ชั่นตัวคอมไพล์ของ D3D Debug = แก้ไขบั๊ก Debugger Present = ตัวช่วยแก้ไขบั๊ก +Depth buffer format = Depth buffer format Device Info = ข้อมูลอุปกรณ์ Directories = เส้นทางเก็บข้อมูล Display Color Formats = รูปแบบสีของหน้าจอแสดงผล diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 35bc0318bb..a12dcd7f67 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -315,6 +315,8 @@ Load completed = Yükleme tamamlandı. Loading = Yükleniyor\nLütfen Bekleyin... LoadingFailed = Veri yüklenemedi. Move = Taşı +Move Down = Move Down +Move Up = Move Up Network Connection = Ağ Bağlantısı NEW DATA = YENİ VERİ No = Hayır @@ -322,6 +324,7 @@ ObtainingIP = IP adresi alınıyor.\nLütfen bekleyin... OK = Tamam Old savedata detected = Eski kayıt bulundu. Options = Ayarlar +Remove = Remove Reset = Sıfırla Resize = Yeniden Boyutlandır Retry = Yeniden Dene @@ -1041,6 +1044,7 @@ CPU Name = Ad D3DCompiler Version = D3DCompiler sürümü Debug = Hata Ayıklama Debugger Present = Hata ayıklayıcı var +Depth buffer format = Depth buffer format Device Info = Cihaz bilgisi Directories = Dizinler Display Color Formats = Renk Biçimlerini Görüntüle diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 913909df96..bd967631c1 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -313,6 +313,8 @@ Load completed = Завантаження завершене Loading = Завантаження\nБудь ласка, зачекайте... LoadingFailed = Не вдалося завантажити дані. Move = Положення +Move Down = Move Down +Move Up = Move Up Network Connection = Підключення до мережі NEW DATA = Нове збереження No = Ні @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Виявлено старий формат збережень Options = Опції: +Remove = Remove Reset = Скинути Resize = Розмір Retry = Повторити @@ -1040,6 +1043,7 @@ CPU Name = Назва D3DCompiler Version = Версія D3DCompiler Debug = Налагодження Debugger Present = Присутній налагоджувач +Depth buffer format = Depth buffer format Device Info = Інформація про пристрій Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index ae19c2cb29..b0788c4456 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -313,6 +313,8 @@ Load completed = Đã load xong. Loading = Đang load\nXin đợi... LoadingFailed = Không thể load dữ liệu này. Move = Di chuyển +Move Down = Move Down +Move Up = Move Up Network Connection = Kết nối mạng NEW DATA = DỮ LIỆU MỚI No = Không @@ -320,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Phát hiện dữ liệu cũ Options = Tùy chọn +Remove = Remove Reset = Mặc định Resize = Thay đổi kích thước Retry = Thử lại @@ -1040,6 +1043,7 @@ CPU Name = Tên D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Thông tin thiết bị Directories = Directories Display Color Formats = Display Color Formats diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index be9a9d185a..0fc0b4cf6a 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -313,6 +313,8 @@ Load completed = 已载入。 Loading = 载入中\n请稍候... LoadingFailed = 无法载入存档。 Move = 移动 +Move Down = Move Down +Move Up = Move Up Network Connection = 网络连接 NEW DATA = 新建存档 No = 否 @@ -320,6 +322,7 @@ ObtainingIP = 获取IP地址.\n请稍候... OK = 确定 Old savedata detected = 检测到旧版本的存档数据 Options = 选项 +Remove = Remove Reset = 重置 Resize = 调整大小 Retry = 重试 @@ -1034,6 +1037,7 @@ CPU Name = CPU 名称 D3DCompiler Version = D3DCompiler版本 Debug = 调试 Debugger Present = 调试器已连接 +Depth buffer format = Depth buffer format Device Info = 设备信息 Directories = 路径 Display Color Formats = 显示颜色格式 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 912e9af28a..1133d8adaa 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -313,6 +313,8 @@ Load completed = 載入完成 Loading = 正在載入\n請稍候… LoadingFailed = 無法載入資料 Move = 移動 +Move Down = Move Down +Move Up = Move Up Network Connection = 網路連線 NEW DATA = 新存檔 No = 否 @@ -320,6 +322,7 @@ ObtainingIP = 正在取得 IP 位址\n請稍候… OK = 確定 Old savedata detected = 偵測到舊版存檔資料 Options = 選項 +Remove = Remove Reset = 重設 Resize = 調整大小 Retry = 重試 @@ -1033,6 +1036,7 @@ CPU Name = CPU 名稱 D3DCompiler Version = D3DCompiler 版本 Debug = 偵錯 Debugger Present = 偵錯工具呈現 +Depth buffer format = Depth buffer format Device Info = 裝置資訊 Directories = 目錄 Display Information = 顯示器資訊 From 6042af78ec9a3b85618ba5b8c92ca0686e03d9be Mon Sep 17 00:00:00 2001 From: Stuart Kenny Date: Wed, 7 Dec 2022 09:13:17 +0000 Subject: [PATCH 620/715] Expose MSAA option for libretro. --- libretro/libretro.cpp | 24 ++++++++++++++++++++++++ libretro/libretro_core_options.h | 16 ++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 49f92cc989..e0cb5c0e6e 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -597,6 +597,7 @@ static void check_variables(CoreParameter &coreParam) int iInternalResolution_prev; int iTexScalingType_prev; int iTexScalingLevel_prev; + int iMultiSampleLevel_prev; var.key = "ppsspp_language"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) @@ -745,6 +746,21 @@ static void check_variables(CoreParameter &coreParam) g_Config.iInternalResolution = 10; } + var.key = "ppsspp_mulitsample_level"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iMultiSampleLevel_prev = g_Config.iMultiSampleLevel; + + if (!strcmp(var.value, "Disabled")) + g_Config.iMultiSampleLevel = 0; + else if (!strcmp(var.value, "x2")) + g_Config.iMultiSampleLevel = 1; + else if (!strcmp(var.value, "x4")) + g_Config.iMultiSampleLevel = 2; + else if (!strcmp(var.value, "x8")) + g_Config.iMultiSampleLevel = 3; + } + var.key = "ppsspp_skip_buffer_effects"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { @@ -1134,6 +1150,14 @@ static void check_variables(CoreParameter &coreParam) } } + if (g_Config.iMultiSampleLevel != iMultiSampleLevel_prev && PSP_IsInited()) + { + if (gpu) + { + gpu->NotifyRenderResized(); + } + } + if (updateAvInfo) { retro_system_av_info avInfo; diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index cc5f428268..ede76d29e2 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -283,6 +283,22 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "480x272" }, + { + "ppsspp_mulitsample_level", + "MSAA Antialiasing (Vulkan Only)", + NULL, + NULL, + NULL, + "video", + { + {"Disabled", NULL}, + {"x2", NULL}, + {"x4", NULL}, + {"x8", NULL}, + {NULL, NULL} + }, + "Disabled" + }, { "ppsspp_skip_buffer_effects", "Skip Buffer Effects", From 7aab096791f8d1d7173e75ba0f278381651a05b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 13:23:33 +0100 Subject: [PATCH 621/715] LittleBigPlanet: Compat flag to work around smoke rendering problem See #16030 Hopefully just for the release. There might be a tweak of our heuristics that can fix it too, but much riskier at this point. --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + GPU/Common/FramebufferManagerCommon.cpp | 2 +- GPU/Common/TextureCacheCommon.cpp | 5 +++++ assets/compat.ini | 8 ++++++++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index deba3981bd..c4b287387d 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -123,6 +123,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "EnglishOrJapaneseOnly", &flags_.EnglishOrJapaneseOnly); CheckSetting(iniFile, gameID, "OldAdrenoPixelDepthRoundingGL", &flags_.OldAdrenoPixelDepthRoundingGL); CheckSetting(iniFile, gameID, "ForceCircleButtonConfirm", &flags_.ForceCircleButtonConfirm); + CheckSetting(iniFile, gameID, "DisallowFramebufferAtOffset", &flags_.DisallowFramebufferAtOffset); } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 29ad3a701a..5f0796afc5 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -94,6 +94,7 @@ struct CompatFlags { bool EnglishOrJapaneseOnly; bool OldAdrenoPixelDepthRoundingGL; bool ForceCircleButtonConfirm; + bool DisallowFramebufferAtOffset; }; struct VRCompat { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 88c27b03a3..613ab0a157 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -429,7 +429,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer vfb->height = drawing_height; } break; - } else if (v->fb_stride == params.fb_stride && v->fb_format == params.fb_format && !PSP_CoreParameter().compat.flags().SplitFramebufferMargin) { + } else if (!PSP_CoreParameter().compat.flags().DisallowFramebufferAtOffset && v->fb_stride == params.fb_stride && v->fb_format == params.fb_format && !PSP_CoreParameter().compat.flags().SplitFramebufferMargin) { u32 v_fb_first_line_end_ptr = v->fb_address + v->fb_stride * bpp; u32 v_fb_end_ptr = v->fb_address + v->fb_stride * v->height * bpp; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 9d0b46db2e..e4d634f2b6 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -690,6 +690,10 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en relevancy -= 2; } + if (candidate.match.xOffset != 0 && PSP_CoreParameter().compat.flags().DisallowFramebufferAtOffset) { + continue; + } + // Avoid binding as texture the framebuffer we're rendering to. // In Killzone, we split the framebuffer but the matching algorithm can still pick the wrong one, // which this avoids completely. @@ -714,6 +718,7 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en if (i != candidates.size() - 1) cands += "\n"; } + cands += "\n"; WARN_LOG(G3D, "GetFramebufferCandidates: Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", (int)candidates.size(), diff --git a/assets/compat.ini b/assets/compat.ini index 9315b3db70..1d32831437 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1394,3 +1394,11 @@ NPUG70097 = true # Demo # Shining Ark, issue #15663 NPJH50717 = true ULJM06223 = true + +[DisallowFramebufferAtOffset] +# Little Big Planet, see #16030 +UCUS98744 = true +UCES01264 = true +UCJS10107 = true +NPJG00073 = true +UCAS40262 = true From cd24d3edf9b2c780052cd8b681401e7e59c71083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 16:15:02 +0100 Subject: [PATCH 622/715] Fix context menu translation support --- Common/UI/UIScreen.cpp | 2 +- assets/lang/sv_SE.ini | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index fb2371c3e4..63b743d33a 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -411,7 +411,7 @@ PopupContextMenuScreen::PopupContextMenuScreen(const ContextMenuItem *items, siz void PopupContextMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { for (size_t i = 0; i < itemCount_; i++) { if (items_[i].imageID) { - Choice *choice = new Choice(items_[i].text, ImageID(items_[i].imageID)); + Choice *choice = new Choice(category_->T(items_[i].text), ImageID(items_[i].imageID)); parent->Add(choice); if (enabled_[i]) { choice->OnClick.Add([=](EventParams &p) { diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 1863ae4623..a1b55bc588 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -273,10 +273,10 @@ VFPU = VFPU [Dialog] * PSP res = * PSP res -Active = Active +Active = Aktiv Back = Tillbaka Cancel = Avbryt -Center = Center +Center = Centrera ChangingGPUBackends = PPSSPP måste starta om för att byta GPU-backend. Vill du starta om nu? ChangingInflightFrames = Changing graphics command buffering requires PPSSPP to restart. Restart now? Channel: = Channel: @@ -288,8 +288,8 @@ ConnectingAP = Kopplar upp till acceesspunkten.\nVänta... ConnectingPleaseWait = Kopplar upp.\nVänta... ConnectionName = Uppkopplingsnamn Corrupted Data = Korrupt data -Delete = Ta bort -Delete all = Ta bort allt +Delete = Radera +Delete all = Radera allt Delete completed = Borttaget. DeleteConfirm = All sparad data tas bort.\nÄr du säker på att du vill göra detta? DeleteConfirmAll = Vill du verkligen ta bort all\nsparad data för spelet? @@ -313,16 +313,16 @@ Load completed = Laddat. Loading = Laddar\nVänta... LoadingFailed = Kunde inte ladda data. Move = Flytta -Move Down = Move Down -Move Up = Move Up +Move Down = Flytta ner +Move Up = Flytta upp Network Connection = Nätverksuppkoppling NEW DATA = NY DATA No = Nej ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Gammal savedata upptäckt -Options = Options -Remove = Remove +Options = Inställningar +Remove = Ta bort Reset = Återställ Resize = Ändra storlek Retry = Försök igen @@ -520,7 +520,7 @@ Mode = Mode Must Restart = Starta om PPSSPP för att ändringen ska få effekt. Native device resolution = Native device resolution Nearest = Närmast -No buffer = No buffer +No buffer = Ingen buffer Skip Buffer Effects = Skippa buffereffekter (snabbare, risk för fel) None = Inget Number of Frames = Antal frames @@ -550,7 +550,7 @@ Speed = Hastighet Speed Hacks = Speed-hacks (kan orsaka renderingsproblem) Stereo display shader = Stereo display shader Stereo rendering = Stereo-rendering -Stretch = Stretch +Stretch = Sträck ut Texture Filter = Texturfilter Texture Filtering = Texturfiltrering Texture Scaling = Texturskalning From 8401250a906c1027b85ad51e14e2c01a25e9904d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 16:21:53 +0100 Subject: [PATCH 623/715] Postshaders: Move delete button directly to the items. --- UI/DisplayLayoutScreen.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 074c0c8454..432e3b5eaa 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -329,6 +329,14 @@ void DisplayLayoutScreen::CreateViews() { }); } + auto removeButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(0.0f))); + removeButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { + g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); + NativeMessageReceived("gpu_configChanged", ""); + RecreateViews(); + return UI::EVENT_DONE; + }); + auto moreButton = shaderRow->Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(0.0f))); moreButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), di.get(), moreButton); From 8ff1156c043a6fbe0833c44ae066d7d529cff36a Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 7 Dec 2022 21:19:33 +0100 Subject: [PATCH 624/715] OpenXR - SDK updated --- Common/VR/PPSSPPVR.cpp | 2 +- Common/VR/VRBase.cpp | 59 +- Common/VR/VRBase.h | 2 +- .../libs/pico/arm64-v8a/libopenxr_loader.so | Bin 1571392 -> 12242344 bytes ext/openxr/openxr.h | 2350 ++++++++++++++++- ext/openxr/openxr_platform.h | 192 +- ext/openxr/openxr_platform_defines.h | 2 +- ext/openxr/openxr_reflection.h | 1427 +++++++++- 8 files changed, 3899 insertions(+), 135 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 0a0ac9dd2f..98e2ee7ec0 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -141,7 +141,7 @@ void InitVROnAndroid(void* vm, void* activity, const char* system, int version, //Set platform flags if (strcmp(vendor, "PICO") == 0) { VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO, true); - VR_SetPlatformFLag(VR_PLATFORM_PICO_INIT, true); + VR_SetPlatformFLag(VR_PLATFORM_INSTANCE_EXT, true); } else if ((strcmp(vendor, "META") == 0) || (strcmp(vendor, "OCULUS") == 0)) { VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true); VR_SetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT, true); diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 2855a75e1a..2cb2d0557d 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -9,34 +9,6 @@ #include #endif -enum ConfigsSetEXT { - UNREAL_VERSION = 0, - TRACKING_ORIGIN, - OPENGL_NOERROR, - ENABLE_SIX_DOF, - PRESENTATION_FLAG, - ENABLE_CPT, - PLATFORM, - FOVEATION_LEVEL, - SET_DISPLAY_RATE = 8, - MRC_TEXTURE_ID = 9, -}; - -enum PxrTrackingDof { - PXR_TRACKING_3DOF = 0, - PXR_TRACKING_6DOF = 1 -}; - -typedef XrResult (XRAPI_PTR *PFN_xrSetEngineVersionPico)(XrInstance instance,const char* version); -typedef XrResult (XRAPI_PTR *PFN_xrStartCVControllerThreadPico)(XrInstance instance,int headSensorState, int handSensorState); -typedef XrResult (XRAPI_PTR *PFN_xrStopCVControllerThreadPico)(XrInstance instance,int headSensorState, int handSensorState); -typedef XrResult (XRAPI_PTR *PFN_xrSetConfigPICO) (XrSession instance, enum ConfigsSetEXT configIndex, const char *configData); - -PFN_xrSetConfigPICO pfnXrSetConfigPICO = nullptr; -PFN_xrSetEngineVersionPico pfnXrSetEngineVersionPico = nullptr; -PFN_xrStartCVControllerThreadPico pfnXrStartCVControllerThreadPico = nullptr; -PFN_xrStopCVControllerThreadPico pfnXrStopCVControllerThreadPico = nullptr; - static bool vr_platform[VR_PLATFORM_MAX]; static engine_t vr_engine; int vr_initialized = 0; @@ -76,18 +48,13 @@ void VR_Init( void* system, const char* name, int version ) { } extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME); #ifdef ANDROID + if (VR_GetPlatformFlag(VR_PLATFORM_INSTANCE_EXT)) { + extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); + } if (VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) { extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); } - if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { - extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); - extensions.push_back("XR_PICO_android_controller_function_ext_enable"); - extensions.push_back("XR_PICO_view_state_ext_enable"); - extensions.push_back("XR_PICO_frame_end_info_ext"); - extensions.push_back("XR_PICO_configs_ext"); - extensions.push_back("XR_PICO_reset_sensor"); - } #endif // Create the OpenXR instance. @@ -112,7 +79,7 @@ void VR_Init( void* system, const char* name, int version ) { #ifdef ANDROID XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; - if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { + if (VR_GetPlatformFlag(VR_PLATFORM_INSTANCE_EXT)) { ovrJava* java = (ovrJava*)system; instanceCreateInfoAndroid.applicationVM = java->Vm; instanceCreateInfoAndroid.applicationActivity = java->ActivityObject; @@ -129,15 +96,6 @@ void VR_Init( void* system, const char* name, int version ) { XRLoadInstanceFunctions(vr_engine.appState.Instance); - if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrSetEngineVersionPico", (PFN_xrVoidFunction*)(&pfnXrSetEngineVersionPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStartCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStartCVControllerThreadPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStopCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStopCVControllerThreadPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance,"xrSetConfigPICO", (PFN_xrVoidFunction*)(&pfnXrSetConfigPICO)); - if (pfnXrSetEngineVersionPico != nullptr) pfnXrSetEngineVersionPico(vr_engine.appState.Instance, "2.8.0.1"); - if (pfnXrStartCVControllerThreadPico != nullptr) pfnXrStartCVControllerThreadPico(vr_engine.appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); - } - XrInstanceProperties instanceInfo; instanceInfo.type = XR_TYPE_INSTANCE_PROPERTIES; instanceInfo.next = NULL; @@ -196,12 +154,6 @@ void VR_Init( void* system, const char* name, int version ) { void VR_Destroy( engine_t* engine ) { if (engine == &vr_engine) { - if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { - if (pfnXrStopCVControllerThreadPico != nullptr) { - pfnXrStopCVControllerThreadPico(engine->appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); - } - } - xrDestroyInstance(engine->appState.Instance); ovrApp_Destroy(&engine->appState); } @@ -246,9 +198,6 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu ALOGE("Failed to create XR session: %d.", initResult); exit(1); } - if (VR_GetPlatformFlag(VR_PLATFORM_PICO_INIT)) { - pfnXrSetConfigPICO(engine->appState.Session, TRACKING_ORIGIN, "1"); - } // Create a space to the first path XrReferenceSpaceCreateInfo spaceCreateInfo = {}; diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 10c2648a2f..25efb1b712 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -121,8 +121,8 @@ typedef struct { enum VRPlatformFlag { VR_PLATFORM_CONTROLLER_PICO, VR_PLATFORM_CONTROLLER_QUEST, + VR_PLATFORM_INSTANCE_EXT, VR_PLATFORM_PERFORMANCE_EXT, - VR_PLATFORM_PICO_INIT, VR_PLATFORM_RENDERER_VULKAN, VR_PLATFORM_TRACKING_FLOOR, VR_PLATFORM_MAX diff --git a/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so b/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so index 784337e64e2ddcec00edf528d4c23f7b8e8a9048..c93b4e444d7681f2dac6b53af4048a76b65c601f 100644 GIT binary patch literal 12242344 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

KCYxeUC!uQTB(d84=rYHMljl> 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

Qo~w(TfQ-buSbJ|L(t_Q>)ZMX_xNRzG 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 z z;LPpuV++%vo9In#59#NkM~lz{#e)o8>SZo72(N*J1Wxj z=UI{eqKt-VB>IYSGFS7$Urrft@=We!3@`MNKKCX#SaX#wVEZTuSeOr#F}>;^d@bQG z65E#X{mAe~&_m`Vh5pvxMm*rBjrg>WSYxzo{Po4)MJ^Nb@WDmipvoGL4jvDVULC)1 zhbJm<9CyLh6QHfvhphm=7GN&~r-oGC0sGzH*pP}|4&xb{!wg(pMH0keHpCph(YE1 z`9^fV_!ROyow8D=%-vb<3VFU7d?Z#k5}wMhMI#HoT=@7XW3hew%DeoI4(3DQsp(@` zbQ9mpinR;gwal%Z!bVH%@Jnr{cxSDj*%yt2Tnk+!o+|#A_v9h7hY88Ga6*Rp5A@IJu0co<~PL&zS2I z=vGf$dhhl47(zD_rYJnfKnuDe!Nlc6q@(FIXeO{lCK%%t8Ka0VeP;d3W*qNljmXv( z-EZj|(r2r3hlSGjj0EP9;qTI>5B^^&JOkds{tEqI=m4wV3y$)=g4V)o(Q{tlQ%0_J z1RrpZoN*>{ru*u!8O`S-N7p9s3^@^8cVH)Fj8Hfaan9zA z&`*JLc7ked1ZH_Jy51VQrla@txX|>&CBASNSY3c?mf+B0c7t94ec=kHqyiOgDUWjb)OyZf~7#Vqb$IFWEq^=u; zCL?DwKf$l=bFA?yd|1(cg0IzVRH3!hC(ng`jg&zSUW0C$uaD6W1h*96N`?N+{j@!V zZ9nnphSw!GVFP@tg)0HwAmp%JZG<*C@0M4pnuzlv!fJBk|l2 zO9!vV2vbvbr=-b$Ru=RRR6K>E4>M zm#zpb z@m2-=mBl5cW%qfPmREXn7S8eNO1&%nWu;34Rn^|56suBeD`%F~tPE88s{?b&s;d2E z#etb?s{>_KrR8Ov)hdmNt!&qpFE^oGmseg>R=uF6dR0yJ<*WRa{*?hhp6)HHS+T+! zr_5PYErhezSYCGd{ejAIZ?S)szqqt|owul_+GxjLS?OPQ7B#QSGpm?W<^a32tg2?| z($eD6Kv}i7igpYh>G~}q#4@D^GM)o>@+t#1))*+=RcWX#XwY74N$C>(t};+vQ%S$}uJ*6s(S3nxi+yyk;+!Q*DwTIhO~5PY8hzJZi>7Fx zvXV~R2MW{_7Y71M=>CGQjTGLRD!D7Q)Q5LnXCyB29J5q)7vQj{3b zLh4w8@~A9dM;oG8Oj0jgTWOF`-L91Ue#C?egkiIxWrI*pACI?oos$MrKLoKep>gw{E>Vop61(p7?`vUUdsukt;l@=Fh zW^tb-2(1!9(WO@e%I>Q!G2gPwZCNRjw*t%zP;QyMNX-=XXs&6*ywzyWRpl#6%L3|l z(@Kbh)Kqr4pYF9fEJ!-V>vBtAJ9{p&AE%(2Q)bBMEK9;ym1~iSz7VzIwI23p4@3|| zkrd3%nLlIROf4*>riIb!rlKZLxlTV;-pW8lO=)GID%we`l09K%m5IS>h9R963Bc3P zU^4d~eu|Eg7XMLb=3y{jzk>MgFRtQ1eg)Y8+V@@)w`iogkXF|6zC zx^`u9xp)>@v)D9}MepdlsP;4m2Nsts`r=h4WAMT6=$cXdQFEk+Ibxwt8%{Yo5w1ntyp+%@JSOk-q_xF z%fzs)EJfF&w#06EF~z1}M6qyI4YRS$j#`a}UtERL84*S?GO8{1m+2k`>$E>I8T)LA zx3@&QFv5gb`#U-6K^VSdd9hX{OSEzjoR`QLw7A4yTBeLHWg8$e1+IqhuB4*Mdeq6Pvy1J>6dVbBAqCBcf^)N&GOyV)& z>Yy5;HWt<2b5#a=`6LzqEdu7yqqiEWq5}+VO_bsPS9#6Oss|IDdfbdvFrqW`&=Lk9 zrkvjBRi@`9@)ZlWmzP&wb@eq#<(_pZpRZ)&GEF z-h!MNGZz)in3;R~%?f!8s5Sn|GOZ$I^uy?-vZ%Z&pwu14AKrWEvrEhQxs!52gL~CX zJ<7XR-8^&t%tbl#)Z&FR^VGtbi)N|Y=if4a!JYG!_W`f^k{3pM`DeI?_woRG$pcgD zwQqW_0QS_wA9eggUFS8}_V-VC_ZQpyalD&nd;c%Ivwwe@d;9mla(sW8<9mC%=km9- zZ~so(x8MK4aeo8tOGvB0a2^Uw7e?J`#=B+6`WCaV?3(7#}nzq&-1wQRgO=(xF4~Ox zxR_?*tU@zw5o8>;==S;fb8ekkAi@=&hO+?Q&JGEA8S$Aw+3Hf_Xe+gg@2@PCke;_3 zQLZdq5{M4PL`J=Rui7-{z_>(0u{bpW%W7Gq)-?)=v~3}vCmKBpO5d9@u()qUd69pG z16<1yw<8`kg{B-jB_U44I-Bv486VewS>3!;MqNTT?Wjh3|B})wp<#g?n>iFEpj&Ol zuB3BXQZYWx2jfjwG^P^y$Sk`=;T<5s=2%chR)~@W4G^luF)_)>is)H!WvLMrx+027 z)fEE205y4uvOi`3U_C~(q7k)%g*o}Nqv60Pwe0#xA`Ot`kqGPfVJn=I|p? ze&U73PJ>02X*UdHyd^MGO>{mWK4+}y01ZM_)l#^$PP^9uhQdzv#01Y`r#%F4VxcD7 zalX90Op2H_Vm^#}!PVJHmyexc{K<-7No+9KoTcRX!txa>W}*eE`Fl~Iia1Vw`C=Us z=K+7z6f?IG$Y<)(_MFNV8wx{LZ2V2+y|dbA?2pcB8N6Hq)Cvz4?y*3b} z8E&Hh+))}>gGyRjdS4B*sC+Ik&{&t}@hQ-ym^_G?mtDNZze*3xXX&t5CyLP*Ht4Lf zb_k>8=B&iwlJ9ehb-X?H1<&vFmsWRqxG1n9;I9gFd9Fj^c8)CRyjf%nPiL;BJ|lo` z);>!ng!x;4Y~2twxBfI}ZqdLHwfyph;=Lh_{Mh8o5E7GT0pX%4CiX}6Le3K0FRr-{ zk}ze0XC&55&w7hHlq)`F*?pQ?)z$vu5)+ST-SP%D=NS>%t`!)s&EmKvf!y+P2wB$U z`7FA!08eGM(sv-2<&{@2?eb!w3?l)2U0JbFTmXqmqZaDLc8ua#WvhLZ|35gEB&iVN{i`+S|Y`RtBMx7qh`f&KT$^`W-!y5OmG&M z5m;SnOIvWhwwf@CIV!ha#&5s0szSu&LoCbuf&H|k(KZevY&zz6C zS?-vG?DE{uhVpo>OvF~%ag?V7WJ~P0-M(rGipF|lwh4IRGFM{C1C?T6SKJa?N?op=~}U7rCC8#B`pf9sw|h8OqitYyIH^hHfmO8_^|m=bk&A?w^#|Yq6rFRi&w}dG#oc1hU+;Y1GA8o~&kEX(F*mZ{?CBzCl)s z#E}VQdtG0EQoO8;;4}1?*nm2{0k1Y~x#gUrQ(Pu-iaj8jY~)UH?4;D->qjYLw2$yj z#+Ea_n^j)x%YA%2PxZR@9W8HDZsWQvuU{L@7)EGIV}miYfEv4hW`aVBFVG^l>gB(0 z+&@04ba=J&Y)C3mrTUb*zY?xl)zz(DDV>tfUDKno5>c*@5`Cm}?TP4Y>T*(2F+*j1 zIa)0D>2gzUI!-OdZ5+x`b`e>X#6E_SWvM|n8uw~(jfA@YtTv*|syjIDom9)L=30tU zX0BwZ#=Ge>W5@hH(W9#8v@X6nf`!1r3%*~geNdUMZv25UdDGF#Zk@VfubY&;yiLX^ zQ&rD)lXT>;Nh-C*ecq|5z{uqI^s$->*GE@{S$vZLrKDAned3BQC30Q1E^%R|GD=%) zRg+c5)kjt`tREx3Qyo|5RX<8}wZJK@lc)uGl}}u5H+ibGM^s&q4ae0-k|+IWY)b4t zC=-`^{hjP5XrB(sYOIW}Wx%z2j{}h*xD4qW9y?5Sz zn6;TicX%iH>{Gfl`!t)5aC6}a7g=pOzHidUabWSeQc6OJ)x3|ecUy{78&8WDU*Ae2 zD2e!{ad>!mig#M^)YPm@mHi}kgeUpf85`3+#MIrU(&x&RQ?kQ0#reXTJnJ{mS{k2R zlS=HLmp%tJDA;Y2hijCeEc}8ApJ#|1$+pFYd_ad&<#ta6QekH zqOH~&tc9iRtN2`*65sQ$ey+(Uic5hfinE$&OfcjaPES2iG&4?&A9>po#lZi7 z;pkf%D@QM7J*%Y+qIloPaP)sb9qn4Vdo?fD?#ow5)3Ql@&R=G_7HwP`_Pzg!q9gL; zhJmLr&6AzSZ#w-%0?geqi_u_*UPDQw{XV- z@5hx3tHp%VKCaVJ?mOVL&=iMxA99UyjkP#KB#vludBn7@ZO2ZDqpbn1kX6n3f!$APOnamdHuV@3Dcp8iCt5ZL%X<|pkIWQ$bK<5-{ek4 zs&_DmD^zyxzEg?ijtQBgG{;5F+GK# z#r3J zsI{`}8}f4-nAl6NBqRk1wG@}j>V73FwSB8|B3iwq#!FE}Nm!2J)(j)(*S*|GHziI$ zaDY@4WQrZKv18J$oKxF;EKSS}8RIM^E?Axsm&%Fr0qjMW7pu6+L%oJ&dTexv<7k{4 z=8COj97`d7loF^NfO*l$#+8oenP#eoxH5)m2gNM}Mxw=KJLBASGvf6R8^?z^(YJAi zN{LIOHZA#XuGyHLEmO( zm9FFJ7o&8s z5-0W4RYMK&WtB4lW5-0ScS;g{YAC>Wj(|Ga$(Q2^&Zlt3S6RtM#{JZ4N*#Gf++jI7 z#1{!I;s_b}`8G99Ly=W!v!h%rbzoR&N@>z3j+s)_s>#^Ca6C;pR?c)>R&eY1arXB= zsJ?#pDzWp=E3Llt+j!smz@?%~8;;@#LyRG)4Kq`hiXny=LyAEkxKzxcJgpA7nM=i0 zhUQb3iWY_$hCYVqYt>=?4VQ|&Z@g6WFibEc3AbSE&6kP`v&6sYQgMwTMfe=UnYUjm zCf-UOZ@W}nVK`4X#*lv(`MvWJ*Bp``?_0u`iV}lq?ou)RZp!^0=FQMc*upUJ{!2wW zgNtE+A<7VBX!(On#S0PgX3+88$zWnQ`T^?05M+ojTx4)ENM|V12QL-PAELYrGknfuOE0;`2b=vMZbB-MbaE4*})9IQPDTj^pR7py+)@CDtgu$MTUzdDXB|4RN}j z%XtPl5vhG%C?j|87N_Qw+wn)hxO7O}!uPGLzkO)8(dPqgRz5EBe$v^}KG| zj@^99YIlCA8)>CH64w>@BvG-_MxIj9$m-=HR7u;QyS$UyxmzRO`o)%%Z|6q!c06s| zT_R@PNO^o(xv;K&BDJZs50<)lk`Wukb#qi^u<0zT#@5cWYQ*JcDw37ws!UUNzA64Lv7wQqb`@ZnvnY@#QxJJ3sKGb@@a;}sqxDv5uJJG z27Pl>9P=r48u$3RRYvR7YR}v&_TQA_+O=I(+<3~xWXeh*)%W8eaU89t4-av&!0($; z_Yc>l=bVO;T~()7_G^?zT9>-CO5S&WTcvc>D@5aQq+HCz28-K_ z*)2QaYjEC5D?I7KR|=pu<7JAW+`3z{sgS29`n;#;1oDO(nCd+Vr4@JYo>VVZDNVIw zUENp;$u@-~)slG}t%aK1_Gk2l<|$2erKOrad>Zrfp2SD*4%xXU#u zhwZh!G%>r<4x2hDyH$J$E0+!KlJ48Nt|QR5l*?Cq>W7ii-XfRV)ca=nm{INp5_|XR z=Z#jbLFMG^=GpBXlQ}OjJUUaCueJ{w80VY7sQOe6PIHn@d^f4zwv-FES#AxM@{moe zPu6zrszBw+`~8v{+atdCDpw+xVyqUIxPx6wB}t1X){1!s$H}!~h#|uu&#V>CF?dd` z71M86D;nOoRy@iOWmslN&aM@8Zz7(-{XXIuE;5+jzs5e>TG1I^8>S4Ot@94io8Kk-IwgmO+)Pm3qN{`L8g+~+<1 zqzYWM=~k;-n@7VXQVtW83R+#VTc=0;>iJN)HtUAkv#NNTX0)!1>LCk0)5UQYrB)Iv z>=4(4jgN_)Q|-2Zd-vYqV#_1Wr>WP9Nn9N_vF?i?r<9M>e0}qAoarw2ZT3p0(q3*9 zJ0$KMtDb3jLwGHt)#EE7&9&0h=rJDU!xea3ovVF=ujHldJ(rGxU0an@%|T0lt@KRk zkoS;u1NWkh@<57H(hXMM^*y|#?K`hKCjJad8>|Cu9N!o_bzI!gEe-%FU-ozG-d($X zsXKUPqu4_;bBIF}Lb>=lP&!)0cCyl(J0!M{;w!pE+G&wIFPA(X$ulT;v~*dzEp|(f#cLU~3|VB0&oXSaSgqD}Ylqcl?X-4TyRCL>kJW1(v<_KitIs;z zZfUo+x3_n++uA$ZyV|?k?d?77-uA)vp?105*FM}~>9BURcXV{vIyyVLI=VaT9X%c1 zj=_$h4!OhEF>JHgthRPrhs|c|v~}6KZFXCa&1)O94cTOy&o9lsXcXo8zIy*bN zI=egVojsl2&cV*1PPx<9IoxIGvUat1b#&RfI=i~My1VRMJzd_e!LFe$xy#oz+->Q$ zcDHwTblbW+ySuu(yY1aQ-QMoO?xAkE+t)p8x7e-rc6*22X799j*}Ls_dym~~AG8nI zWxLNl++*pn_O$nO^w@ejd%AkMd+c-wZ_i-QP>>lyZ1yjE|!x5I1mc6z(K-Cn!5 z$LsZS)u>nY`nKL*O zbq;k6br0ExdWO71gF{0@@{n(6ShmPkxn1s%ZE~mFC3nkqxkvWOgYu9p^K6@8pT%eO zwfj1JHeaW&%h&C*`+9s{ACKzc(KkNd@Gy&Tn8h$mQx4M{!&GUQVhxk^Fr%fNyTlr{ zbAqFIJ7*?$va8L_E2Y~*N*BzFyKQ(Rfbtcei~re8sksqb+`Xb40pmc|L*jWt*KVH@ z2a-0+cBgZaUG36Saw_?Xom(SENT;Th9E`)9(&unuRi3qJOU2x6+&(4sQG=s*N|cR@ zamD?lH8+d*^Vy=@DWlw$z&_=b67D3UK6Tc2c*m#|dvR5_Z9K&s%DMWEi6XAcQmvn8 zUn;>@cu@=LRw_JS$HgrwJIfIqsht$xDYsATtXe)*?I?~*ip`S9Ma{fwq*zR1xrx0^ zWj#G>6V-G1nRatEl`%Bt7$$yJ5t_DilXH;P2;cXA06$3&|~ ztC#B=Z>J>2yYG-3BA1(`HnpgtCQ^MNt0E37XFIC0^DFl?Xt|9}2Btamdk6F9Xs@Ks zqBfEpVNsw{>@{puc%^Y~=k6`-{zy^Re)VD%ksIaRFjMWm9(h`M;?WRuP)-q4HMd&u z8>PUw+VIltd+*-c-+TCu{nD=KsY!7LW!Hlzj_=YQRda*V1`kg9lo8(Ja+htFdLgKY zAmPrbadn}zcN{3yM44&zj<8s0?H!^`xz2^d-l9ADAo4jr-fTdm^5 zv7h7hoG~~sw12;d?9smMj8BRf@zOf5TBA*KJh?tcYFC#dF&pIAUuwtFysSM3#!iUN zS=;8$14sIJkXZkb{deAdfNOW|IdI5%_?~ib-A0QQ!^O8`agV|-Wh*ik*fnu{SM8SV zMr~tQx`kn%x~<%3T5Xgvg|a%k*ko{@8naQloU(1G8gZjIq(7c~Ty~B+C{NT89~SE-)E2E&-vPA@H;C6RFjh9>^;4<2 zNnG{m6<2jj6Y8h4l9q=Su}9%jZ%TKLPD&FT)gB#E@9+^}4)c_HxA;_*#Kw>tWt8`o zl|~6}(3Bh0t+En{iEiAW^OE9japfUjP-Lx_-q=7!l!nj#n!+|*qPhuhlsNG#E|C?B z@rYXEsSQf1Ehh@6^bYaNv|TPP(!6oq5~`{-H$f}SRlk@>vafWZ_+|;TvTQcGt{Rss zg;mAYH!qU5Q?$`)wQfTvmi@Z5>NQnS)tkdBOwBzZ(`?BY&ai{wdWKyLoeVcJ+{Cbt;Z+O=7!EV={Bh}C1}_7TnURh$Jj5W*5C0wm z&n=hU!tf4;cQO0{gLr`ThZ+8i;V&5en&A@+f5-3$!{->j!0;u8Z!$D7{J$#iDdtsQ z=Jyb{QMvz;`0BDhOt`-M-yn`%B90;QTxIbUijn6~t08e5br70Si zhpoIQlwQ`zOnUmolB?~M)eFpO>1Vf}o0yg6XIavnOSd)gd|H2fZyM&{hz>53q`H-3%WA%DF^wZkEG8ejY9D z>mNKd#(@Hd_&UvVt!rboOMk=xopL71`c^;nN%h$L1vAROx{>8|4<@Ttt0I zs^TtFj;d6Ss!~)%UuI%1fE+pzD9u=#oM&g#7G~q|LAEM1P(Z0wb;`|iR1jz zO5)+jq919c-n@8PhpK%H-1fc9LE3(+w0%&`i7oIIb5ix5gBRr03a@5bG>rP3xPm3do)BaP^-sxl0Jn!iU=b4pr{L*2rK;!BFPIH}5 zBb*$y7uO4jTt$v#Fe$PUnTR|@7GioarI<=$0%`9ZQr{iQ?lC*b6Jq;PwMdjDrHmB& zzG71(_M_#h_hR2t#EJdo8?^T#ZRx#8E5`RS?AG4jQT1NzYm4z>-+Qz1MlFpf-9~w_ zL#J$k#lD<))67uX-!t<57KYL$TEvT&PDR9+s{5GY?W`8A&tO1{zo=Qt z@9BD#R=}&Yd^hvy&gVBh{Z_5qZ`R8F|5|=qPkH^Oe5&QYPAf;lYVCF1|4^T7JG5){ zZ&>rAk*ykH(*k~L-l3Z>#(N6W#-b0*dI}tCY7wa{Vxu&- zY2!w*em^tIJ**Un-*rSC>bGtIHt5;uxkVlc=|t zuXr!&R%%x`VQxK8FEOo{pNJFh#X2C$E#8YVh}U5TQAUwQ^q2bahqU+; zxLF=fZJfwwvozK1N-||Rh_qsU;#F#cQn{+zN{lbnUo02#DuqjJSlt$4e0BXrxVoMq zTwN~_uC9X!i~K~H#H){?^uBVeuuJ_`+$o+M8>l{b**PSRLL8_&>S$47mE-NziMz$! zm>i5aFf`OtKJrj=@Y>q0CE0vh=hS8sm$P?{ZkEI`XJqvO?$ zD;AZgU`@ZE*3YMQWNmi#(xJJ!i7N56>8+im3ACeRbiLx( z&i9K;-8qNRFYX% zwbhhftbe5$^owid#(9#WudZuVitzN7-zGDwU6$6)a(UEq3{SJ(R(n+qH?E&JU09lF z^`c#0l&4q!4U1A+d$p;R9w^Q<_iWUiHaTHk(`(9ABCF~uRq}s&-BoKEaxZUUNMXfyc@tUl$LD0yvE6EWgx_R*S| z)Yin#twrKDf|QGttM+KD9iC+N`Xdl}VJ7wsl+g_2cWNXCF)5kuGhIH{WNj zOL>{S>$;Sie+3acYc;dK%vTZir%T)Me$Kj0tgC7Lcu`YH{5H!;pZB4D@zkHn7c_DG zcx6QOMpWz$OmVW8E8K>}vkq&R^x`G*5HBSk@kZn&UZwnU&vtJS;pG#(;u;aD`6HQS;n~SUEziU~uWkOt zYjF09u{Zoag_Axv{`lKof$zM3X8#Z~k^kZopS<`SGI)pX6<>PiF&@6nb8f_iM&;|~ zw7B}q=BkrSDL)ocpQ7}O*UDvf;?YCZol=`b8CTQsY)Vu)ubOe~{r&QIzqTEy9@9=& zE|qih>DxQ#)M`=d6K!-y;YN26Zgl71Mt2Ktbcf(ZcLi>AC*VeR|7~=~-$r-&u{Nqt z!RkMu{rVU;EOVF0Zf-&qYpb|;L9A@7VC$0_Mat5Ox_}}l)I?lk#v~euYll_9yZy&6qi87yHZo0e*c#%}AXEPr9j2Dt>*eCR=V$ z*eM-Wp6MehDwY}n?l%@SBf?vLIGebnNo>=IsjtY+n$=jXf%x_MA@w;3&tmi_m)iG> z{;+%ZG(Sj$)jgzoeXUGBK3ToySviiS%($QJCttj1`|8nRm8+h#YQ5GTV^V%b0|#Sf zy#2nBe)ZSq#ACJO-Mjnyx%G>ODD?;YQ~flHvd~%FTA8B2XmJYGz>v z+`_ogL|PnI-SAVj>Ro|c)hud$tU69SmW_vpv9!ydx0Rds)cfqVPiZTFxTH+WN?psP zno-&VRkTsn^U}uDCLf&S+WR5#8*kM~y@TVE0Xj_S35oq9Tyn~(xmk9r+GA7;w+_(JtlQ@swSI$nJ8H4@%z z`px2>ZoccgxY`fPzkgThy4u!|^^2cmqTklM`otQ+4{<4Xf|h<>RQuhsYq;P_{XP3l z6C4uXvxjD8yn~}Btl~)c)X3=Ze&vYZDEF$cLf0fiMhe8h2f`^xQRzXckN*cB|!$JPkw2QKd7thzKZjss)bQzyGfOxq@IW>BPUenGO$rHynNTsYLl}&&W z6klpKh*CaHl&?aZ%b~<$zLWjxb9*FyAG|UFclU4`L3I{2KOcT1&~6cW>gk!P+mj?D!=E+{FMr8>BML5_1CjG zC~wKd{*ZF{G@mWyW)x5C6H{=XzH%piX|sQe4i<-ZZbDLZ_BrvUbFEep|YC%lo-57&h&V}Hn) zxA0l~SDbG@#ry3_%Fjy9ri0SgC0o<;n%qr~a*y0jtr!m~Wq-BuSB;t~zklDBXO%v5 zs|vkKR~1m+9$FVuO7Re5#Pzk}J9+7~MK@lR>n&AdN-3&+&IaT6SH&INdbldL>M0w2 zKfm>DN`4tfa}(_;V8^sAna)L)MQ}^dG4@r8Z^0z#J@@7X>+>feqcw%d| z=@ruYe-d%;lJ04GYtwtV`{xCud2iFZnqEunkGM}VARW}EdUex>m3M#GG$y^3Jz9Bd z=^saH%I_O}S3A8Voz{Jmx!u)tS~taTmhfp^Ui$5(ziN7SlSBG@=>h5GN?bR~=_R_- zzpJ;D-Zk#yO_j8*TXI`((LJ4i+)<@We~t22lGbSPr7hy$H=35V+@if#W2*liRMHHv z?0s8(TkqT={yvp|8D;v9(r+Z`?OU((Z|@d0#a)`!>A$e$JLFN=y8hqEEo$7}rs{EF zEw(!DPsxGLrL7M$RQ~<6X>RN5bn3rY`CTcd;*Yn8_mWhJDZQg(U;XUozTkHlxlP}! zzL#{oHT3g(jnqFV4id1leu8JBO9J&-AI8#ty7FaNNhH3xNOyUAd}GS*w~r1VknVQ7 z)%&NEy$rrs)P=;YSZdVJxN`VPJPg>!!5#6?_35#P#1~yj{T_4!Q)VcW9U7Mo(#2e*Hb8SLyL%*T)ov1Pc<$E~a;`#A4@r+?5OYY!Of1}taj>mIy znY)LT5#^)b;xNsLKxK*>M#pYo4@(@xki64@aq)mRzo>Vc#18=;8)MI@O&o%o3UEk- zFWa&>r@>yN64-g2G&Zj8Ws!>ABJn+mN7rd-#Zi`0Qt?DVB`@_2zn9Jw>Rz09!*8jb zl%_d%Jk8JKjSsW?RDSXk9}XYJhg zG|ZiNUY9gHAq~4EuUGOOk%o>-@{}Z>kmS21-?-#EEct#}H3P?MQ(#FruhON7%;k4)D8J)CjQH|=-~Hv7>&ox6 zapmx?%DYPb50oPxs6^gWd3$r!+j7#X**PlX9gcDWM|E^L_J+#4%2d}?-ri72z_Wu- zR?X#_N}_AZnTRyyKrmQ&TX|QR?1q~w4Rd`t!S$5{*H>b1xVfC*mh!vpm3NhiZmy)f zxvHfcH&xxJL}#q=7S@Fw#@+lauO`~cVdOBEx^6H| z9B?c@MM({+cXg{Liq^*{H;(d%LNTFw6R7e?CiQ+&Exw$g8f(0{Ivef!rOW11JHre+?~vc4#sk>LwOjvWMn@4@QAo!(>Y%LV33@LCFe=WIV0VgDULn0r{7!QN>DsOP zDDU0M$Lf=tgI$!w&Btv6bFo?uDbIOnu<-4++r}qPa{S)Su7J3S{La$OK_m0B9pJN^ z=Q6s~wWNVb?BZwV#V_hMkk;CD8;{NjXqg|NeEb;6Q=3kCBHfi1PK8}I1d{62f5S$FIo z8}g4&ah$o)DLUybrQZi@bef(c%9kr;!=P;x8rleVh>tgAIX3t?*W(u7(;6+7<*vI9 zI1lq9Qw@D2w0Dz`leOY^iP>fG`bFOgj0X6^+}PHwU3>;Vi51go**iGu_8!|C2sG4M zop-6biDKn#aNW1^P~LHVyG{9oZ*ZD+>k;Mh52ljYUh`C?V+~H(;}XXj8cb~Md5X>4 zQTzFGRPYj~HW zqx>zR!8x>Bw2#;Fim6U0y-<3l{)H{PbkBYM3pt?sYli0%`(o)D={m{Aa0~Z+zJ^N# z#<_Cg_0pTAuoRU(Dt%l!FMV11)sy)59Vy3I&#QIPmaD}XkuCS=?z!ilXGmLg&v<5c z_p_hV{oLoh;Dy~UdC@C=haYILM7)}uvz zZG_Wq3)qK-?@7`O+AxkD@`?Qp z(_>!?^CRAmew@QN@$MH<55ggg;dxBq3g)ow#g7(sSuWSbRt%s6=h1^X3}OKzXnP6u z$0TNO30H6pb>HXS{Fjmsx-rB2gFDHO@LBYrX&3on0;6cKJX%cR9?W8kmHMI^TYtcG z=)g33P-6{M^MHnhHwF6n8OrqJ3#+I7iP(44Rt?Zx!g`Z*o#gK zpp0iQgo_x%RZOAjAo*Y~>T;6g!B(6_2S(713mCu^j9`n4@{949!Sk5MEE;}FzIV_r zXh#>iP{vsdiSQxHfhkO34zs8~OuM56TmOZ2L>v0ih3CIHjA3aJre@;814d>B~84TbWMzHN( z%7uNH!4T$g9t|sOr_hWS(S>=G(fAt5gD#BW1g0>7Y34t0AMH;#gt~v1q;qJ(EILv0 zkPliggl>%CX-r`pbGU#7%wg+)P;Rtg^Zk?uO_*nXev}E%Vh~p`iiQVhC)|TsJc9*{ zqv28VM>FQpg)RN`Pjq0bt4W&0FyR=+@jRw5i#c4y0_p~+7wKJSSf!t!8JEz7dGw>v zOMWK~_H zp&29S#Ch~!9)oD~(O&4pBp$^KhA@xk(eMkF14by%%rMJ=@I1Ql0tQez#&|SiLX5`@ zrZJDJXvovPBTSEd=t3Ej(7tW&}moSXd7|RV!m_|G1(1W^5tOwYN zF?67QoN}NI19%i8ID&BuV;aw54pXRGV|y~e`hpAS#0+}S^n26?ofyTLN$P|1n8hUK zF^Bp)nxs8b)a$=k?r6hBbmKAx&=jCN=*EN?j~Ogr9*xsX|4Yh^HavrFT*80|pI~~7 zV_d{z3fC})#*@_NziB75QJx645?)3J>Sw4I8Zm%-FpM#bV;a-AiYur)MSca^4NbU+ z4s^Vhd~gYaD7}s_^UGqCaC4A$LOW(Lj0KEhh;$dx@GI8;*Hca$KsN@^k7qGXx|ui7 zJ{Wx?xad~iNQJms*wm3BDPB%Mb$@fR?F1&pBiZ7f%GV+Ln2j}bITO;QqVcmZ8lKtDFW zopNCdMp4Ej&S4f4SinUzG_n7DntX5(-B`c?w!MRLpc@l7f@zH73ND~-3!iUjLeD$t z?|2$zJc~h0VHD@yMLEzBrX09{1)TkT+IcJE(T3;Hg%{9|mUpwf(2a319@Ch@95%m) za`5nXKbmkB9T-73&Z8eQ7{+aL5o&qYZNy{2=An#`63S<-k4Yz@zBKwLhYMScsAj&U~1Bu=!8u zcQ|*J@=<@!pV9vaN73+1=8HD$jgb#7U;r;-1a%)FA8f-6j^GMTpzc}p6Kut^Xv6d9 z!X=b(+n-ZEv||MOFpe{r!a2<10v2!?4bN`kM;Tadcp6=pLK(9dMEyMZ;RGh|ET+-^ zQObuSsMnJ}ns5P~=>9A6!I{5i{lX=Tq4Q&u2Ty;T_Qs>BWO&J53XPa<-cQjVF>llrC*^L zm(Yc4D5L(9HF?EP`MK@vnd6qvqFoH5Ba1K{U zcL6hm3z)~|zbC)LtY4^q9`i#J=Fy4vPg6ehUf|CNL((KSDm}#vIO| z&OpCG6K2qX%jibS0_}vSF@kYS;6==!>2u77`7dFfa2^dWWchxcdZ7#5IDr8?ixFJJ z1QsxZ#(!XXw4wgDS-xmSKRWRY%D99f%wZJQFwFe-q{xr38`GG=6PiqVwytBl)B; zLAYg!a-swC=t6xf%LUE2iZRlMzQOV!yo`R__D?Kd^kWRen8fp#CjHzu$qy45+JpED zSiluDyo7fA7Wv~Gx-f<^rZ9-cZ?l}ykFBq!|6!7_>z~OF2QZHzG`y5@p$!Y@Li+{E zi31oG;qTCn*!o?{hq~|4U&%L&el%q1hr~Nj|1!4MXvR5o;XKNi#t>e_C?5Sj<-#y# z@jMnVhpk519c^g&0m}~~7{CRL;026h0n<4DL&|~Xim_1aGRp#%HSMmZzsA$%T#n8paMVghad#(2_Q#0+8GO`(C|v; zi#80Q8|N{AS&X2xLOy7~G}>_mU8uX3c0&_}F~oc_=pej|Zk+vh@)KcDjBr0vga@ zCOpp(2t8~Izs->pT4h*0h;~2mNA=Ayb(Efyz7{e7zqV&7uk8aH42nKwSs*#8yn80~gVaD;Pk@NIuwyaSY8fcLA=Ap{0NVr2g4Y|Bt|iV30%Q6nmfrCCs1!EKQ!S| z7waGS1-i+P@L81c0*0{JPJcm956cy2F^5a2yNmYOjXkvEjpT<3bm9f{pw2YZleDYUcxLIZf1Q&JGSm-{XrWVZlRxG7y}r`FlI20YnVp;9?FGBQFkNxqY3BH ziAnU}G6u1AFXh2rbW@%zCJF0rr99}s0`_5$@n_KBARn~h61vc~kN$#gjFHalq}>Sb z!8BocKl34+#3Z)dM*b*c0p~DJx{+5=@0;lN!n;`xz08Mj3f*`C{b)Ks{vsX5a2`{b z#4KhpkM`Rs@6Dt`C;4U3M%Z+a{Lqem3}6_~U>xI^!jOyh6k#mj+#Qtb7W(rcrXxS; zFzXkdMhEe6^k4>qDD_cqY{Mk(!3@fn#~IY`p?+w_Rdk`@)#Q(D7{ap{!wjZSx|4FD z8FhQ<&uGFBIxvYIG#;TG=)x$KIle21~7zCjA0&A z*m4i$5aUs|k9@HeGnk}ZESI1``;^46b1w+wP-$lp}$L{cI1>h6WGyLk9+M1S4WRCeU&}^S_63VTSNo z%wq}-x3QeihUXqY(mDIdkFXy-gj)v4m+*NE5%zn@pYSZkF@h;v!yM`d>0fBW)>knf zbYSZc`QZ!(F^mzsfC+TSln*@^XFeCubBy*n#(Xh7!um(Nag_0dTc&7V!ZWBpN`J-- z@wt=CU!)Jw-XnaDzMp=G^B<%hDE|rl2hB0cjeQ>_A2fZ8_84XRk)XV2`4r0s+dfS` zhkG!GbEvzQa-az>q662^gRM#00edlu=P-#`%;3?_u$*uf z4X>d;pbgtT%kn`N25 z&S4m{7(?6VsUP-Y7Dq6TDKvP<{~yQ~^XSIq6#3xN7f3Ji|03mhkaoZb@!P({e9?v( z^k5!mQGY-CfoR6_=tRpR?T#{ra1LXb#1t-J7Pozw<&S=BeSqbK4m^i$%wPahU!fe> z`;U|Zx1}iuw%`hyQP)qo(S$K{Vg}9BW8kZlhj17}cn)J?Jh~Zg{~F5|Xa0$JbpJEu zWPAv7cm@mTyg)ezNQVwQiylm1n(3V1p}d4AFi&_5BZQsbrQA4z8JxitTtK~-a-a#D zzeoNLv0eNjGPN)Z2V91@l*f*qC6r$4B#@_h>!e| z{y}&RW4PWVH|aXEEhCk4jpJKkRSG90R0%jB}`x*Gq~+n)CbL|A7Z^i6ON!0 zb10+b*R(&nFp4rJFpL>Ihj~n)US@k)Wd4-jAU#$z6K+E%?m-V;#E__8(__UT;W$Px zgK^?LTafS^rZI^t7~J|;QSYOlpc$9Yg=^?XgN}UBjxls$63<~4Gg!c7Gz`;DSCJ2< z(1kga(eVuO!7~`cI3{rov)Fqz`G|OIWji?k%*TojoOl-HdlSq1*^d=7)ME+r=+ZO4 zG+`VaD7}($q61x|bG6Y97{?&-8H|c_JCOL? zb(Ej5{d$%I2C#sAW|qV6(eCKL^XNwZ4U~uJ7H|dUcalHx&AaGtB0VN>5!0B*6--!I zj+68YG`xlN(@MDspGGGpP{u_J;u=O#-%fsL!3;Wa1!d$x2vQhLcn+OdKpERQXh(Em z3<-}#wg;*bNB_G0Puz)FS zone0x9oW2&c0&^e(2ZdXVjRz43e%WF$w|Ja=&xu(H##u5pL{Te0o-;Q^~N@g;|!*8 z4s)17-D~MLXu`9vqWv+8GA4TI54egkbRVD`7{Dwhv49ygypH9AW^~<7`=E?6CNP8- z(M)^nIY@qlW0=D8n8h8`vJ98E4Uj z3+TrThHx39sCUyJ(1;lf;tD2E_eRUhWi-5%boWtTynvoh z(_bE-zYtELjLR58Q$OvCE==KR43XYGK)xc3y0_8qz4SXYVVvlq8}GAgliZ@CSSr4%!_oWe<%F|&DeH=@}Z1= zJcD7(U>vudWcgzY=Fo%%+=GU9(cjUGGw8$!dhk33F^dk$5u2eu;I>ngmv{#z@ib;J zg9U7RE&Vmjc(maRx-p7jrk7qv`xACy1Sc?ovzW#huHYi-f1i4y3G?W{mLTQBHVmK( zBj~|6#xad4%;6g9-p%LF>&XY#(1{aopguTU00S5jVbbZ}PWcEQ#RNt%gA16)B@B}8=xNINewHtqaT#5xe+TV{tr#O+3`2xh zMHp@Gq?~vZb2x%&(pla`{usdm@r&3Rq5fgYiv#Gv1O{;tBdGg*%86~*`dOAIW(Z%v zJQmRK2bAmGloKuJLO1$x0z){9QH)^{6PUpZn8#(*e}MeZgl+Gk-!VUFj(pJcUc$up zqKqC4;ygxBdLQLP1E$f2Ih;e?AJR`TLO%ZYlRx1kI&ld-n8zRa$pn#==m_^5aTh9bC|{$=5Pshe?-6f zW6FUp)IUP`(MeeMCzJ=<&_=v5M!5*jVGJXf#6`?v9t&vt2>m8Xe(1o{=)toXz%)kC z^ykEr@Ad} zG3znfFp6$Ghau+Q7N@@vc3~I;7{{}i#suc@0_y&R<%K3}{%gvEHuPXG1~7zSJcBVz zV+wU2Bi~1856lv7{y61B8@8S$Jv#6lx-o@*betnU?86v_F@I?B9^jpRzvu zE&Z4Igwa8G89i9Q02)6*`=b*R=)nT%O$q9?K>09Dd=ghs_jmM*|3mwr8PB2%6DZ>< zhS2ay;+cL1V}w(f!ez|i8WyniQ#v$%+PTtUM}SWiDgy)cLY%5V5A^&s4aGRhdjB*rk0 zDQtO!@}LrM3j-d@R=*B$yQT|8DgQqc$QB2_i z=5QHxe@S`Lv^Tb)16}CB2@GNgBRG!|G)sJdH9YFocU3#T86q^Ec=RnExir4O=p_bDZrN zI&cv^X#N)EKqp3U1QQs^>qx3!UMF+}E7e)QYh|khbu@7A+ql}9f!iyM1%lD}#u3{EPen34jh=z}o z4s9s?kbE$Se$-#2AK(neaUN5+?ML(jbfWGY`Cu!aMH`xbOucXf18C1tFFb<@T*5RK za0T0bN`3x@<%K5nqZ4P*gE0)^d5mD_U&set%k*mz#udz={%=`sKcijnJcenn-WBpA ztp5+D6X8c`C&GRViTG94W3*!mWz1n1b)R54V3z4x9wYpD%7Z52)9A!Cl(F}5^20dB zZ~>E;!z`|09zDOH-4m=QXvR3YZ~Qcg6Z;S%|v9nI8NS73SK$gjwk_#g%`gHg2nn)2ZU zW-*Hel#29=Pmv$m&>=lubYma-F^FNbH$7gA;}WJ(x8?ET3c65#p7jEQ%-^AVyl5ia zhcUtz(Lp$mZrpYi`C==E(2p_9VG7SZa~DQ!Ye3a z^DgRzCX8YZleo=7z0iRxOn25wy_Tp)JIjT5V+Y}{u)NTQ5p*!#Wuu&gV;I0?j9_ag z<-}ghU;y(NL&HDPPtb-fT}+QI3}6r=7{>%�=`YnI7$ENYf5z!!zi{H4LD|PJ5#h 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

8Xi{?|mkMSNm+B{S7JkIJ@ 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 iGM_Q4O?RpR`J6j|bvE#N;&#QIinV zR2GJQh8~;z7sA5cgGnZRi0Ym}B(XY`eKn}2y4!&cFDO;reL$G%JVfd0$a|b_j8l=o zl2G;Oji8L`)sa+@tzdidW1LBTAKDJG4*TKRRiq{2O#V4^l*u?M1Nm9Rt1LKI1&)Ne zqPUArN1VyOhv-B2I?U*-afs7XTHsVjkij(KQuAT>=--gX1LO}xGH=?9BcgXhnkl3w z79;5V2*YfJcS=-dbNm`<;I)uu1@cdmULc}oUPn1pmUj6Q%JRlPY~gP7RYu^tQ2lM0 zN>TNJ5xAX@(*tH5xH%NwN@~p>h}1Vk8Oo{x`_j7lAijc=v zeu$e!GF(V&U@}_i@jEC6Ii^6{I&goe9=TXofQLijpICsiK(PRGS-V0_`_&cTflzh_ zlxM_zR&@AJ7JypG0z4RsDKI90Xp98V=S?CtKPn))266#cAsRk!9_bO8#LdbS6<*}r z*$&^N55L`VIX@O0gSs6Blu)jhomzhC!t&^rhP^( z1(Mn)sbC)>Iqw2MM=0U13z4?71pTcc@nI6NHC%qN=r|o~DkmG^W3zL~7>5!tbqV5h zuo2#p>N>{oCZ`>+be0kR-NHH#fl8Mm!zXR(hoI1@Lin^zEe{GEdxZaTAiZ1L>5Jq@ zBm7Zh8~}8p5!Tv5MBV|J4kN;WIC6QA=qhD6DURG7Bsz=;m($d4Q%z(V$aEMHt`JB5 z7-aI%;YxAjDi_MWez>wGf8;W`9%S0r4`=9)VoeCLdQ;tbBfL4X5D?m~4_7Y*i+q7R z+9M9vvhq~qTxfyrGluKMk#7W$vd6 z@$~kfk$VYW=F-V(RAfBpw8s>_Mn8)#6ZW#=qDGmPxu?|O?U4_NIkua^`I-*&OaTuY zNkt|-+lG5-dA22!3KACks%~C^ofj)?Q1e_=(LbYDFp)0ujf=m>#*^WyNZpo3no)M1 zSEHZ?xu}Q#8D%P41t@KJg&(yQM$I#T-(5h74WMCe02iV(bC_cTV#Cy+M!KlQWujDM z9RRf96@JbJSc3R3Hh}-w085beE?}(pV)vzK{mLky=9_QB!tZ_+VBd0Zv!krdb@zbHoy|(ITvuu1|$mdyNfziCQ3!} zu-Qc$USYq_8dR1bOI$!X8(;}?#08|;fJ8ysVlRv9Ik!v{Hva*j4Xk~&m`i;fyMGHvdNt$?<+IAF51Ga zJm6(>-P9b_x(l-Jq2_*H3ob24fl4LOe<0%K)(_&p7btp=o6q^J*MjgZ5r5)B!s!SI zHK5w$L#z{z-6i!v9YYcxCSvU2KXv*mT6O8>sN}7wv({*pPth${2#>o06M4CoPF?!- z&9x{}uAL*#6{A2X*V@T^jQ;O{Exo1GXOUS*zDA_M&QE~r@N+~?yA?X6rD3_YPULH3 z2QEka9;ZCKr3)DV2tBuz%X1O^+oe>z1kH``(@xX20Q-AIxy zF2y5K4a!SPM&6Rryh*tg4yoKID2Fw@#$iPVDML0u-hn!? zUj7jO>2jxJ4~1xH?!#}nzjf?Mu-sodZ7o{KO~X4$Ex$!wE%$araBC-Gv;KFwhleN1 z>yP8TzB=fsFa0k=7r|rPkFhIv?h_>u=w4sK6Xjbdo$y5Y2DtDOC7o086D395C(3i3 zzZBl1p=YkGm{C;qyWsCth{y9{i$^Rc`-yL5?@x8r! z%jRwf8djx+?9ELGi69~hC=kE`V((o<#a^&t#V(>EiUq%lSSTV2B6h)!4I4JZ0xF1N zL$M$ND)2tfnX+>e{QdFr`EYaZbIP2VIXg3Z_RMS_fgc8}@3|guxRIV=?z!Gfxbrsx zw)b4r8w{itNmZ14E@qDNo~!b`cd*`n3HMD5Z1J8&#f!w4;5y{dvE^RIo~WF;abmL+ z-#GcyU08%%T7Bch`e32UtAk09=EiAns1c4~Qnhdk;b?|WbK^wa|8?V3w;6ISGedG> zsk${`5!T3VXivGTV%?m(sys_6?6OXmJub)g3k8kZgC^GDuIf3%F+Rtp47a9Sv?Ytc z)t$jz6%`j*=iF6cK)D_}!R&w%Vk(sZg;i=Ypu9%i@!QR_Wb;)-O;HGErBkz+v9 z1By~dTZ5lrlNZf}HD*A09(;O0NmMJoxK)d+8BiMQh|dL04=7FK-UCe!C`mhMogLBW zdO%^5>o&9l3fm$eLHWKOP&%N=WI$o($biB~wzN406oS&YjR%xY*s$00Rcz1e`4l$b z^~yXvFzeNqwcBzkW*#q{`L#>d+rYlt#w$156v{efxPL+5uDJ|%EXen5%QM`sun3Z6 z+qK?dX^*T|R+SFp6wIx`hnIc0o7xIlR^T=lm()gS;+xPuaenK$?TVC*&{&$QQq)7q!x^vj`sLfUg7K-F4Z~C+%dbdoY@gep^;oZuU)-)iiW%(5%PYN>){KJQ0wQtgOD_ zUeI|*UUqDvsv+#7!6AuI@ACk1gJs$As^w{q*ZUiwOdu>fK{Z0}!(i8YwCzO2Mh#x? z&w((#tn4Hg-MgRWJw>6%v-f+y0#tZUbvosLzr1rIy zoulNGfp;48+yo7jQLT1{?f73dLXqe&UhjttdToNLCtJM-U|A>v*E=M6u+{r(khlS- zY;;2MdLPwaqhk_O>soC{w>TuF>y`m($}YQ2k?8GS!v>&y;9Pb`;z*^#c2)as%Es$q zfxPM&NNG97B<}Gko8;2u$%oC&ujaIO$;GI5kL-L5T7KE)rF-Kq_sx{GN`=3(=+c{k z@KI7(YmMk9No}()Y?t-QljY3h{#Z!I*LKYoFK0^GukmUFo8`==0-wCCUbp;~TMThO zRNS8%cva5lqAwKg{GKS#E@#LYw4s({Il~G`2zmIcSR=fpmoq$DTk6WQwWS1EECl4{ zvS#@T zdRapzwX9(g+Q_zG1{lz|xfxRSu6INC>}*_FoQAn-YqSA1G$hD(vwCq&mkB2=m$m=B6X?_<_F+Baa`jrh4&ZpOu*72ZoE^7ieg_ z8n8ZoU=VaE5iff6Fg3^V_<;{U*DPnHE*BP&jHVo+ra2xz@c6@Hwtz zd?R3e{J;lJnbV-q96xZ~7n<&qL}`~W+}4^`9N30NOL;KI$mE-5~K zKyeQT%uqUxA8@$yD*)T$2W-E4`JTfz*e{$)xA$;Ui1$|P8}w&v}3;N`;z4N0ckL~M)G$UoW~CceiSc& zeDfc0VPU$L;|EkjUJghfKahBHK>twJTU`31W>}PJ%pgkR+YQ5#CJbz6t)}pkR96umL4wqhhJMg082c-S0ny)Ca#}7!URks2$#}A17OMA*3fz=)Ffq48t z#joguMW`r_AF$)fFI_;|Cla>kN$J2P~|r zR(1LBCHD9MOY^FJH!zMLu&@#-ocsq$Sqzi5O|wfBT`E-g+K{@X=_|^%>3gxRCHtui z2_8Q%XeGw2CD4H52Soc2`e9-HrZ{<%aE~?WP-^n#(`_<@8bOSY;*qMSW`z$*5t766|6Ey~031MJyGClAO^uj;hTa^A7a zz=h)ngi9Q%Y8ha2{D5+cA)Dvy@dFOy*MK+u9`ZPTAc3p70^n+thjP1V zU!b^QyPTR;&h@#4^4VKYDLFm zt*~j|t_rbfe;?p7onh1d|KK9b=}BYLer@)!PC10=kb-u}{1TIbM&Aeqph^K-$%|rm z7k!1>?afM-DQHW8vkkf3erQcjiI)Y%;=!e&<3f0pNkMz5HfK}Nq!^KqvI_k>0DK*Gk61&e-89xNauEY%fOpehYMlPEIOk&k?j=9$A6=bbs`)4)DOF|lRM(8 z7qJBCWNdE_0n=T$y}h)MQ!>p*b1cN5tb zfWaoR36Xp{k*#mFb^)`!omP7JiGXb)o0aiwI}|6fWuB|b;ZAZ;*kNuvBu8SwlEG_d z+fBG1UuK1VxPgOxhKl38E7jpAnfF6h+@-a1A5#a#(RM-x{s+NDq`#S*q(xvTl%LVMUd4!m@fkN%Q94UN-* z1Tqu{5~fhFkOGqqB+%GU&}bTH;{6CD>}@!PiQVCB%0)BrX#xq<&6crwU2bBTL;$-W z6xsZvo(rB0VAs!Wd1)fijJ7(DL_QLOI)N$%jmxn;LP4WXjX`)Ma)aR*pJUU6UyDIs z7=!Rggo=v{avzD*WIp!thmUsCpk2Wx8UfG7R6OHt`4B@34G-jN0<7 zZUsgc{j6><$_nyLW?}BlF$b4F=8lP~qf0;&>)@a#Kwdb;OOu8pDHmPIA~-w1L8-XNI>$llY9^sUk?cq& z6?$V4x(VB6Peg3RKG0hT3*>w5`?-l7bF4!li>zrh*D9F>tFP| zc0y#VZFU_ZUggcEq_!M92x|Qfd~G|c(`-h{>*(!Np?*A>%B9*d0@mz##3*{PV=Lw7 zi~46k885DWU)w)7rP`z)S>t;Ei)*}wgIA~+~2ii5>N$ugVtO1Ky zKRXrIe5hSxUTSx!)po>p8TkDa<8%tvuF>Kn?E@bciCkyk`AtPOfF`c7K+|Yz@EL6K zq6~t3;u<(S$;tS@L#dzt1-|ShxVk-L@z-t1` z_A6#-V5R`G{ED{(*fD#z08b-3e+zVw-)xa@4N*@-BKoj&;u1gNMJ>Ix*pGNINn3r1 zY?QSKnzm?*I6~XZ&ZCha;O7KRT?^yY9*7cvbE&frUFi2e6&vsW*6CY-i16j;HOCkMm-i<|-fO zJTS0YIv+=bh|y^;96|f_dXqYe=k~M6R+xWvGc&idKB1ryRmkj#^=2*9=((L$3rA2c zx)`5kZl~^|+0&idSJG7E<4~oVJy}Fxj9hU|Gqw0+-JH4o9+pzbgR19twqGb{Gzm1Z z4s-iR!!cf(GJKeF(Nq?p=XNSCvd)>?(Mo@zdVa=PeBMM2RZjsni_hDrP29`65w6e2 z@D2cbH&;2N@%4Em4)+g^;d=n$xhpSae)+eb(QpS(=w#mXy=)62L{* zrz+2d+mIDI$w>8&(QUtMGn6i7OzaM~pj^}p zpXTbK?jrwnt}gg*1u8CgZ?w(1fVLI`j=4=6FfPaXhk{1i83S+uy#DE=) z0azSUaghPV7tl^nP;>$1siCSAu(^QRQ=9a^?PugZpEIV+yR+5hnfBLXG6zSiF<$S^ z_&)N@60g;*;k^`^OkL$C;YA$WGuP_s-Y0{BUDWCh#V~^m4U>TK5ooJ>jyfK-q^MW^ zI6j%=(`sbHLPNjrQqrFn`ZM@sl25B^8#WtNCJ#SbO-$q)b~oVUM5y5kfPC=T>VdgQ zNiUtK9(%SL-SCZ}Klpu8(rcje(6UxHHtc;vnLP4rH7${E7-7JN6QPFZ0diwetC>#m ze*xsf&Q^~(;MSwdY9dG zVB$l{RV~fFICBR4Y}}2YD69-tBF6#2u;Eb2d7=XC=C%M`ltR&l}xtUS?b0 z^X@qbj|SfNb|BX7LqFW(7BtZg6Zz{S^Gj$St6#ysWXL`R2IjD}TW~mjyQI>uKq_eo z(q~#e8??plJ~Dr9#=c8J+jqEz^9ZgMb{wl7BFgqk-&4S>vUVDC(4FPmp65=MG^5^j_k=xI>t-GK<6iwkC==vI(3|9jejrPuOdNpU4yE@gph%nC zuY?==O39McsSdU)KZyjNdQ zpV<+uaUxovqNBG1v5Kv6+UXeBs(x*weg)qU%3cO$nqSfN7yNcfJ4`0rL(7)(bw;dB zMNf@n`LY~Vr=pkYCn=+JIS|&TqPO8IK{=i9zoPFEuu7xlf1tRYMEiK<_u~6d$hGa+ zHghJhZ7SON9S+8qgH8oQjF(9gttcR0sBkmBwL619JJ_E>-BSMyI*=v43LjFjj{Y_P zl%%5Nr-QbTDz-8z^2_jZ^E9B&7Rux2Z>Lpy67er zuUZL~djn`YK$lC&pv&o)0KM|nsO^y`u5G^_nTcR5uQ*%!tQUAHF7V3f$;Z=_VVN`W zhmBitVQz;Bgf77yH;vd?eqE-11^o#rhASN?*pvk-e1wa)PH;SSqe4*;6a>GI1>LG} z?3&=Oaf)eomecSs5NX-FSSyF3O1e*LJdn)Ug@$=DnO#z8Nk)6rqq?kYHz49sk13Cm zs+OJrR6J^y<|`cwgmY}gb6TNvO!hUvT;zQ%64|x&Bk1n7*-J6vetRd zPvP3GrlDo{f|?uyBXX7N(j5?j_sWMtbuC_-H3S9khet4#)tPouqmDSU>=ZHYGw_Z6 zHse+9o*}y*o*{6IDd`yeuiQJcv#-~*b9Tnd`BW1XgPYPS(Za{Dl@E1kSBczd zz#k#)u%@)x!2c!f@TRnqW}0?{OA}iL>;+ogxsV&I>M-DD0MeC5YhXSA>B?giP|Xf% ziLR^u1&w_ezMw15f>ZjHH9?n;(eXU}p|WFuQ?0+kuV7PX-zxY84&X=iXX0QSh*WMF z#5dCmAXnKr;G6aQppLU$yd9w932&`rgvc^lg5NrRKPVE%{{vr|IR2Mxuf*~BGgwM2 z{&O?y_*CJCKMQ=y=GO850^o;^$cLb5$8Ss<&~ppx_^g^g;64D_@dZd6pN4A3e+fod z#}ChfssHKt&x(1an_9;wJ6^RT@ZNy6<6m}80(U95j_<-}0M?HGmef({e%QeKWoV)w z64s9Y6KLA;U6J}0*72K&oCunB{6r*pPwagVH0}6JXg`6b9p9nN7rBm+b^Io@Q$f>? z--I^J(2mGBG_hsC&!B0?mpTmSj84&xuYjQdwBrkqIQ|XiXvg2R^7v-m-o~<`HhTsJ zAiwgYbPX5C?Kypr(5w<~I_{C(1OwC9#gxY0nQY z;%8#r3{?5Qt$TSypZ_1*Ahr?9fFgiY_})`F+mnXFnj~lYi`#ht+gHZ%XYe(#=$^~H zra9X}-}hWrXwD@Y$=SAar6kGOP6*3I`@}0YlCxdRq*d6QZBm__ZDC%OV9eRJn39cO zo}-pGcxBuMa5@Z5&bA0WRh+YJF}EJf*%m?u?|Rh=n6qs$UFyBB=u-Q;rHW8o_Nu1s z=F+6}{20)*|spGTOwy(l#@$=P0PSk6jqCoCcvm4Jm&3+8OU{03r7*mr|h#yMKz&T}<< zjw>0D2ds0pM>u7cL7~an{@j<_DM&e?Xj^Zx?2Ior11z5LMkyd-B^`Yc`sh(QtLY%e+AbY(zg$jX3+ zFf78H?fu@@e0QhlKFVCh7e5c0&e?9PBd-5I)9!65cROf0XFHMe;>?E{p5lmj@i4#) zi{O=UF85Lc&n)8J|08ws3SJpk37^$28oy-V*?6o*SlTha^?Y?mxV$n>8ceQ{{1k&T zXIt<(UI6)uk8!=w7QQl0HRO$ebk26-%>n&GU2k#g1)5=z<_J` z%O_gR+9q7;ntdM(I%m6)Azpm&r<%6Di7+ko@?U|$=4?yF@_T=V`>wrESH3b%+CaP` z|AN7pvu$x@Wq#Yw)lHb>YzvXYCGK8;7v*eA`&U&gRL33im2pyP)dV0WXItdYy@)P3 z2a^pSJu+u|%SGq}{AbR#E#Iq}4#?zei>^Y~FVtz6cx4<-mp)gnTlFAFCTH8xvBQ@d zM$Wc{Rn@AV1dGh5=EB^6}m3gq;6^UfU@oAi&@v_ zaQR7I=`z3SVX*D91a(EuwrJmqepuN1YYq2EQ(Zy|M0?dr&`r*^h!GZ=X1HRhI_{FM zj1vZSlg^ZF^NpqsjSopR24? zDAq;U%aWY!(O|JT+oGJU;pJ;zz^xu;26@q%;2*Kj{7m3BXIt=3iC69LqUJ~N$g*pX zT4HF(*-mK6qpo{N>qE}ARj1{;pchTfc0v=mroA48biDSk7&+VY33-t)a<*Fom+1^S z+k3!8lAP_^AIFTwob7Kb@F1}c4@1L%z7gz%Dg|sMFZu`)^cCi8n~rDB_E?lK0HrZ! zd)hQDUe-uF=qfte!J|yh_P-A&$A(HVQlOMoxN?R*d9tq*9_-1MEo=a)bGFygI6>p_ zkLUwIACfZDiOo`|&e`rWQ*+JOIG40#yck?MXPbuT+-p_NWshpwLa|BbY%5yjV{rA3 zXoJN8Ei01y+|a(!G!~_7uVy<+&US!CG&$SrX63vspG9^9a<XL|-@bk4RahsC=&+tEYL;iEz%pU&AH4kA}} z8I!Y3D=|LWZ>(Jer%O;&}i2)olc_a9D9a zOlZkdeqvrc-LU@UvZ|;2n@v&Y2O(#BQ&F?Ih#U=AXW^WTR`5dwPY0}@^1JX_!1^hF zY;EzPhptYZ@(+4IvotTQNy_Q>1mL2l{Hh!e&7hz1t8%0w`TYUgr~Fc1Qoa0S;PxrM z;A|4FdMK!DEdD;0Uov_NdV>03%d27V_~O240?9FYxaI z{|ZzwV&1s3l71iJGpUN7IaWwt<)D4i)$o zfqOh-9qVa_`w0WD%6*n_=ewdn>sZtqjHi}rR!JO-qqTOdc27EvMTTO>I+%imE>Bp; zqOqZ%(Gj2-$C_d|hKb$bDU^$j#;0*C>MrWn;`EWJPie=ZZH{A|D+b&RE45>>{-L1J zg~k9lRsr(DF~);HweK7FXolEB&yu%1uf-`#5c1A! zzJJQAuirD>p~VlFH%EG2J)YV{kKE{akM7`m^+VF_)>eb#I@~+`a5rjQDL=>PpTTL6 z2z~(}SWRlQ$xUjNQGZ@K+5@-j-c%^rKOLQl@7v|^{Q#}-mW^u&{ClWo6xhFQ4`U8Y zs{$t&cA+bqCK{|gWfV5a#gsBdm|_T9C(Kh_%w>Mi5cXQ<8_f^7SmS!DGN%6@EUx;; z44<@~Q==z~2-2($^<_h)RmuW~%J;{yhk}IaC|JWzd{eV{aY;=|o_^NPOK*qv(2~-Q z@xz9;*riFc#rw6_a!XyBv{D?_rX&Ve|6TfVcm>W-V@t=g0Q2~r`k(Zx>l8e=LrQXF z>VHnN6%2Q}E+xx}`V~d+!+@E2RR4SW^Xtehz8H-`K!>?U^%th&VOypoN>{(qWrxn_X|qiN->b@xA(s((%uDuFv>h{c4vbzIm&Z1l8)-7Qx$hPDxO${+}ZF3&0Gk z)UQvEgKpiTeb@xivE$U@zW$(e{7M(i=Vy|d1T-xW=KSJqG(&`klD0#UwBA+YEi+C5 z1Er03-B#1uG*PM;hHRITSWErX#tdG3Q8!I{$feOZFCNid)23%sFDZkhR`27|c&!?j z^uFnMs~(zfhO0wr#SbsP>-H(R*Qn#T0fG%uUG*1FLi;+|`Bit@hRMc1Udy&!>==p9{Rtc3|&raIro=bib5@v+K7n z!mD|uOg+%|s_6urq^tLti{Jz1*Xk*li4WNmU+%z+$6HKH$+kg-E=6e&Myyk^;RiXA} zU&h#)Iq5E#8Ny>_ir(pMHAUClmX81Tq2_ok&6(Q|Pb5ox+egrXOR#2c`YZsxmb~>1 z*oO(d=8AMYZoX!DD}A1@D9H&Q`_hs%@20!nX(i(a7ijpsv}$+7{n#hIT+=llrZ0EO zdGSrPSg5%&9nbt!v&>JAaLRe)Gn@;E(V*s&^i7WB$afG?s{(v?I-asfvwW7mEs<>Z z6Uj?46H05SpFioJ0jmL8hlhe`OcdBWv=JIsaN#8@R z7IJMeO6GD%2ULNZ56C=Cnfua(nLqg659F)dsQ#)q@qUSs9YC*g^my^ApO8LR2e^Hv z4K5U2OO}Cbj$iQp?RwBUWc~)=(xMp5Tp-kZk&X}jRr4XGGU2Pc1$K&}s0Pej6V!Z} zjwk-^dv|XMr6;=uelBfrKk5_Vbmp4T>G-)nG~Xzf?^?|c2XhP|I= zM&4@sLWHAwH18VH-p}N($Ej+Z`)htN^`-NA@pUORUDfh`Q`4pi zUpy&PvrkQj?CGL|qnR=%+7>!EgViif$1|F#nW$#FCVW-X%2HnM?ZCHNR+%RzR84D+ z4E^)b`iE**uH>p`H_`AB4y=RDKWwULgIt;lR<~@ClA~^Fj@C3bvwllhpGeb=acPWC zdR517mXbhr&4~`pt2%dc4WHq_+KdTXXxfD?O_?#TWy*VCdsKF~rpdri$hF3;0cOFP zOR{#b@v1qj$Rx?>MkYzl2bG*HIqK?3^2OVHoO`%cshslA<$nkZZC9#Kd6PBD12bYvycsrenG%vaxj}atFyG?1l%}p5ic)r83(sFBs7d?%q6LP*om(sW} zMzj1>x`nWamVTSv?5kMe3VptV!0|tTC04jnm&s~*`R{M>Rje>*rfVwZ=RdmDS5cEq z49>>zs`L1i)}|#YR+wpX9ov>iWTRb?c@0V~KJIGY>)4>J9#&mg=r}5+WfT8mB`#!5}}06_TMi zq*Fz~!m&sADqeCd+9Mzx@skj{2TY7U%#O^$Aqi#p=dgmkF8D5Bzqbb4ivIUIJ> zY@gW@i?maqp=O|0{ty1j?AX8Is6&14cusnIkQlb0`i7Fjd~XK9{qD73d2f^>(_=%! zlc1OU1o|PIa>JGsYPJc1Bb0_}GUovxev&%PXKTIWjGT#xyijKRmkm&00m~q`m0jkj>E$9M|^mN8w@%+wSwpx zK{wsc_in)d`v0Y#fHK7!wMU2d-yi73sluW7dl$9clUk5)YzdC*4*)tmRk#O#nao}P zKq`ec6CFVbTd&Xt)(UBcLnFvT~Pe6MTFYr2|8n;ftY+N6DN zzXK1E-w|!zeiz^Czzcv&{`UR-Tz%g=b6)#_e)u429n4_W6||d%o{`r05%&T#w|zSG zJOIT#M@Xmdtx4q$X)#GvUxUQywEdPTB|%xQnuf^bLnCTdMgE$HccbyKl%pg;9h%Fjpi&)`Hz1iOO}97t+(G6ea6v2Ls% z4ZuTM-YL|L@S_v(ouR+FYqUbVwM`T%4M&OaHDKa;x^ARqda8&?iV;p_)2yac8W9MK zvhxGO;)s1{u#;G*QuUFGDFuqKz!1((m_Kzfm-#b8cvjNsq@_N0vBu4%%J|~{U~$!d z-IUL%*0QElr@=mECob14I2Qvy>0x!h`PZOgx+|nX;_Z8B+G>|3^^Zpx+TSissvG|X z+I7c5=X!rKyuuGhvB~0ndixUkt4pQS{saY22F&eob(s`>$Z)R)%qNL;K@q%fgIc}T zg{hD4Cb#%vbmjeOWnXuPA5R7g19)}KT$Xs1k!+sYaxW5 z0A_fhu0;{N5-{`W>NYEa2ln+P^jFt0bt~Lhx9Au)L3Aw&=5zhJtNn?kYdt zU}SnYCI>V#5W)QQ{j^f%Ub4!8YU)1?-q$T`thD!@J8GFdneL;ft@ZM^0OFWbH{Mi$?uOH{fHSsGHz9S7 z)B6K3U^2W{Hz{?Q1CIyH@Lt^%w`672Z-zG2>5f3rc18G(`#9YjFV;?3lM8DguORRn(mm?5^h=Nwo@0WaQmpf4e| zx))rUvfvib7#^#8IrSEvc(;>c;u;GVqDhztV&+-hMZ&3*qgiwCh1*h^=m3O5KmCi+&kkhS=)f zcj5eiJv98G@e;XB%ij;2A-1~t2A3AduLaJG(Yggicr~xBeKDU^--ah;a?^0bGdi+% z5t5?xO+$O!MA*n$9`lt%);d2}99etkF%V2-?L0i2vyruBP%e?R*ITL~43V`<5atRW z!G{;s%}OF`zqivIucbLL`r#8~iTlIzb!6=Y0KS%_)h4p`h+%mv{fe+C$!2IgHlU5H zNty9Q1~!p3#r+vzUQURtz3Y_2M&Vq{$XXx#6_)ww51n#u1*{`$iyX<*(TXOrc4L)| ztSw0-RTztrHL*Yp(l|w!TwA%GO}hdr7Vf8 z31Mx*%*dL>G_#GYk$?lgQA#YT zG8yY!DP1CK+i+Zr`aYLL*67WgH5gfYwS5v<6PeE;9Z-cA?G70eSsRY1nvSe(On+6j zLlRlDdXVS}SVz`2m%-4X-B@QMYX@Pv)h)pCy{HYCO=N9Qy^X9ne4L>J#TGutpMgu$m1VEOJf&%(DyoNtCbD*2 zSKT^on()P+gT_e*ku}bBszH@GQD^8dk+oYffpH~<$Xa8*s%4;=$Xe3jRsG={CbA~5 z3>{U|42;N{g>^`4>uy>Ek+p=TLRyc5cIO4K0FgDJv6*#btxI=JLu4(XsmR*HpfN?1 zku^*6s#^5WFd}Of)@F<~G(^@CnlhsmqG~3xCNvos3bO#~$eJAtJeedV)>AY|N@UHM zB>&Ahk+tg|Y8+WR><-lPD13PFooO`+BC<9FfFCBbB(g@#i>or4b%D#OB5MzTrXy>Q z;EvS~Pht@q8ohX{tc|RFglSsQkY+L?iL5;d79CkT+gjm8U62uFB5VBv8(BMFSXhGB zZvkM*!ZVRIf#X3XHnOJ5lq%%E2P|25jI2pbRb=gKv=^_q3?plTvoXBtEAT0;O-poS z4QpW)S?e$jS6IbVq+8|Uw>Q{isUd)|;-h?gxMw44BLv=E;2#0&$l5m$H{2KbHnNsQ zd44F|`BD@p#xb%+y}^OhQa!+g256j)to2#$BukN@II?ye5U+4Lf=`l(bWV=OhJr>X zgJvRY9~+KgIocgwK)GlrK22ney8n;JT0In)$l9yWz{uLcsH%>vwMPI=Mb=0R52E^p zQvs^T+8PU%?+cQSti2Ap6InZ)LME~%8mh^xBWsr+u+=ECwg;#ZStFZ7)`-~1TJ~^= zv_@p@5tQCEvUWYJXJn1@x{j>zt9XYKS=$_rVACMkF~uFwi9J{NW}WQ-_J1g7v<+yc z1BS2H9K&*Sg|HXpqVD)K9YEbh9grl8Nni*?#y&_JfmHg&LAfi!m{vWlutfn&E3V_xf-)!J~ znmYZkop7iAReKj|s?!}D?(+@YK20+;cYZlwCQa7VnKC(Qc+tw4YV4>%S~hJ}_XgQR zP(4YIokOmQ-9hoI>nxGB?SvlEVrIPV?#lsk)RpRSZ+9miQVDt zl#6b_r|}Hqmj96;JL6Z>mI<=7&B16q* zKrBj@ra&H<`BcSC`y*E%})HAZGc@M>*2C`7YLm?SWjDc$$1eAHM>CA zq`afzE|59k8^G__1#-qpEnXHBiwE0_jvH_vY<7W+T$Stskzzzb$||e_O={Iw3J-F; zSPMh{^2{!f4Kz;B_#dEqv;7{DGSi98Qm9(-#A8<5T_7x{374#W;+i#jr^lyKuHMa| z%6Zbz7HS$rv<(B+!eKhXhQ$FbE0SAjXy0gBB9{ynwb^P^S<v1OCnl8AJbnBh}gqq?bu`h)dnP}Mg#S;x4zP8QwD#yx~&*n~k9Q|DJ8$aXLo7iV_ z_XF_5uVuU(Vc_MtHw6Ap;NJo36-4b53HRVl?FwR`z`~t>7qA_ss5khHTB~GO$)n#D*Zn$$8r@KWuQ$u z1s*ceaEuod!cACG6tYlu0X&3?|I{*tR$I1{Y9EHNyciGBDbx+j|L| zA!9}cG8B&tTT!rZCYbcdKx0EeBjypBkzuOg7$$ayy(t&cgNy;__qPqlcxj4ouo!T-F#!Ee#YG0VBSUTWG$`;pJe;a{ zody(k!%y~mhnez-EF3^hvLNG!)A_x!n^Us3Lb^PM@A736e&NG4ae~_HEQFn9ZP2Qf z9s$B&Q-r01yQr7}YHaR6gw?DKOth72gR`DZ)&@tm*5YN2#DfDx$EV;mYlB_e=&__l zpo)v8)M~S{wWY zF1+FkJRn5!>3Lu^h(+@Nt@QGhsFa-ttW4so?sBy@ zyFSk*NR`Mm!K0}o&Yjz{iBeeG)@D1v8DuSWAN12JBv3)kOmU^E} zUA&fh3tD6?#er1TQv71JuJy|9h0wZRv$W!1gq^*LANgs+0AlU{FqAXOAfbm*A*XIZ_BrX&Dw#jS(dWXSj72EnhuGJwb}0s z-3)gTza;e5J+(Y93>qiTbqu}5J$-$zMSy3mwb?88BIo8w8k1Me{W8*T?<3?Z{l+h* z-)b|%Mdak5o?l8%3&MBUIO^Bw>R0dqp~BH%7>C)hWN5GufG{dj{l%0$L(6(CZrKkO zeY`&`%KUbvvx;TrS@B%;w&WG9yWGxIOmGVYjot^%%vFC~p*e<0u3Pvy<)V-AY33^G z{*S4GVVK#M!44CKnT}k-;xNoj)Tg2<48!nea2r2-uzJy3FL~-Y8p1H8b2bu&5rN03 zB);Qf{jjn!{WJij%!^MMuHk%|I{olD;cmFZmp20<4D-6f-QrRWw@=dy&7J=qunogV znM{ksv0yJJVHnz~!!VOhDOxq|28tI?IKi%B)T;4fG34|UHEdRmmkZqUB)f{a6ykoU zxPz1JD&{_cg**Q-V7rPTXK+2W$R#AJ7#gQnF^3)xU*&xTF=zE~EF}sL46&;RmKzEh zod}v)HC}d{<`|!&3E^3ki%!F*Sv6Aef4BtiD{eTJ2K*VcyPD%?w!{znQbpYJC_A65 zhXy~~g*r>o#9qWaMl+uMWHZXp!4BiJaHTH+jWo?YUwT)k9L z=L(7Wf_P)?AaTG0)t7bdOMOvGE=1g|MJL$r$r`sv}EHqaz ziFHpr&P>^K!HrDWM-7FV;-UW%Xpy0xiK{a7+YD9-e;jeY9v)75)x(_qD?j4{C)nX( zG5|lkf~n1M)kHfyye{xH0S;^;)dLYM#9iG#+5f=1hbW+sjehGSTcc89$v7j?&{nK-DsXp|_v z$=T{Yb`ORr+U5*XCy4mLdloo)=kP0rAJ?J&ir2+tP-&Nc?%CWnfP3~+C9 z+Gd}=n+CYURDY_7IT!0??-XdjLn`Wg3}3y7Da&StpM#B`X^zv;`DLYJA8Lv8br)mp# z*^8li#$!bjS&KL5sqf9Oo~kCY52!l6?Gfv#c?4_yaDl*w&$OPpE5!X!apxbko_eyt z!kzyPu${=r87!ujWFq5!3hk*Q9@ZWrTl$jl$McjZd_B#22+Iuxjh+F`Ok|Hww;nt!ejU;p_|SsbTbxug7=%zxpNWE!b6S}Dq_{Qh0ubcyMKUCZYykLE0tiZyZZ;b-2uaGn7 zNG(a|hFfm5uRJqb`wB5j0|Pe2#@vdP;m%*{RzqO4 zM1~f#nmCn26=fnr-%^>BB&H<3)hoO9aY!OEMAwqY5Wh5z4BhtuyAjK#!W_G7+VX7- zdV8}cxGC6+-h3xnHklo+j0}x>H(54)^txR(6^jQ$MaS>pHIboL-b$8DQjADQS%uTy zw#z00!J%xYLi2a*vZ=d8<9R^!QzL3fCpJr=df9Z_yLQ>MQ7*M?I((j8HnCj2{E^b* zcJJ9`lcLG;N6{98rXxeNtVr%9G`NloDOw_D_pC(^pfcRDP zj-Ddf8(848dp^cjFY1Y}W{TuK7c)if^@^5hUh;1ulS6r4v>Rm16j=fpGev#^8U2Jn zmBZrQDe~x7ohed?hG?aiKNpp2wiw)DAEWNr3|&)Ecs3~>gP$Pkwm zPGo4=n`FQ;^MW_*GV@c^DmZ|pCCy=$nQWhpEHgKo3pK^d%x|DYmYE#oWtqt@Cc@Aw zd;T(rATo63JhWlO3VzzHS7NS2hPbm!M~1k1kyH~#hGs0K^wcCWG{bLrVTq0mJ^C~o z`eoLjoY$#Dh8`?u%tL}e(;LqCT1S3ff19lD3#;9fHLYP&sFxtn+uQ@C=ys z7XOKbk{}SPV}n45ceMQ(0iQ!x;A8x6_!xo-wCBVUobWxdltG@j5@RQWK%AsGKu7#y zf;hF=y$zjXnb7$qq4z{AUgUYWfzbKI(A#EDtpdI18fb=NExh;&=+)Q2yAbfhEdU3f z;j0&w3THKE^cQV`@KO)w|(i z>>hZ`n_1N_lN`(R7HT2KG7b22BgZn8O+m4h_E;wV3{oG!%ohAsL25Jwg1qnLu}mj6 zgV$lz#ABI8;(L>0nKq&!s1-F2fStF}MaMD;yU^7sNIaHFu-z!5FdoZfF{Mlqcr23; z4oH}%x|qw%W0{2ckaehnQov)GEY`T*iiO8A{TGX?p2so?pR}G+BOc3?5TschDvxDq zq~4+OSf)l)M}a+-i7a?5@ON6ml{l8^Pykv|+A;3-kEShlY0_-*rvGZ%QkN#J6mJ0S zx?|C2-=%klSNP!|DQelebn&rF3VvmM+8oQoRxsT6Zb-{`k7Jo!_%bgeDZe8y{) zE!Bvomm$iok7Zh(&PXmaj%9LK;@2};a#eboNJ{b1qmVSmGWE-8$<;1P+&0XpqhHn* z!D|3BBN)drISS*COEczJrl+7=x9G8Kf@sasP64M$8(-H#)7msqsu&hU8OaF8u}qCh_2Mlz*R+RR8ri(~v@JAkdPa4J z7<87@sy7Bz&M7>WX^)ngZ-%QwYQ+yPKfYBaIhIK}FMmPnj9S6+SSHa+SHzLrZ8GLq zrcE5r=-oD>mfC-3+B$HXii|my$*GxG7_T-oFPn5#plF}8%a~)C5=Yatrz0+R|R;smTe3Kl@wBGQQXC1!FrS_k9%9vxB9GWWo zsjW0^^Xv%G@05LO=Zra)DXEVaU$Aw?9Lwaw$8^DtwQbOM?Xn3hgBo@YZIdy_GC4G5 zL2XxkHC1QVEil)il8atLbC_e9?(C*7srF6y;&Zxd9UZbeePXVBt>Z1|VCp@OW%^?W zt)spPUp%j;zBW5HrA_apFVL-;(yr~DDL$4-4MwLmWMrp-J(fw}{DFNm%ww6vLuCU( zzE|H&ax9bJY$z|^3Uev9fXJ~-30}=BMUG{n6L4y-J~e}ce>~Z$o)h@$Sf(d1dEZ&K%41Je14kv2%y0F&3N04!j=^rLMt; z7adiig4{foY2am=VDoFyaEX7kwNj^w1A zZ#R$qG+MKKmVPFYOg4{+Wy$6-{tQ@^faN%w$BGHT98#m1D5%NiG2s+?vUyCfcM^@< zJZ3SaEZICJgbxyCZXUCkX11HhNbusio79Yq&0`AyILfgVXN;z8aA~4HzUgK)(PHzM z)ANNlZb_TXV@p3r3`I(3yenA4;-X>5n3FpZ9Lx0W*U7O=Cr*T1E&LA0GKoyfg_zN( z!iz44jM+T4Y*N~69^07ys_yrv?XgT&j~9=dg1qoLsBfR?jtfQCl4W@DB@d;|u}rrB zaA{F5Fq_R|17>Kx`i#T(BJC7KQ9m%7&12mjOPkGOPJ!#B4PHil%;vFc9@l)MT*Fcv z%JZK-kxq_flHSTUdn%o59+Ud9@xAhJ%-&S5<SnFLOBDV_ zYWxGR9>+3`X{A|yD(xvOEWztHv30t5^O(T#Lv7OLSSD4bR3ZOV+jO#dOlqn&kG))> zt~l8|CO8|ztKJ2l(%Q5{ZysyboNbGz1jjAGRbR0OD7pBulC(LN={~@ISVH-DTu#Hw zb8`eP6ZokR)~REeMnc?he^{#FRk;TR7Vi9tX4*Jz9;4o%CACy{x=$x~(m4H;;JkNn z)|pB0Bt!AD&;IBeuW<3(DU;wyV?#ls-9eKu4vuiY;2q5|OzaL1qg=EPJ|$>_BiyN* zEwj-bD!sDJ-h>_cSSAlH%gtlA;;-I3cJ1pay?KnpushW^40!T3kKOq)ys-FKrfoo#Xd~Gq+DJs=U~(+e9xtZ6Dr_EGjy7q! zdF&0=0-MKp0qV_T_F8l{kHycYymE6a)4$+V$1<&1s&8^}EYsIdpc!khjK3$7TAIp$Q!2~P(|Zi7_R{E z!-ST+3xk*!UujtXa#__7x*oLI15nPoa4S(WS44(S#YMa;V865% zJeV@?!uZhIf^@gFdLTVIjMp2M=B1w`<@6i*P)ZG?E%f7_IA790&^b(14w% zcV)iI{Qwxd!6+Y3H}LXYDOCC4Ljw0h2kU|KI*1$Y`37E!pmBO2?SpW?9Z1PgJdh5iV4)lj19hf6jSU5jjswjMqz@R5VPbc94&`u07s^He zH-mwcy8m+^ZJX(ihefT^3;c?OE6_a2dox2SO5U5vpTQ=ge8C@{+9AIZ>BJc zg81wU)tUY2(^Dsjckf6;jGQI+^esAXUPMQ6o(7ZQu_$8X1&GMUYDoLdo!Kl z9hE4KwKZ=y_v0lGF=%^nHPNz58-&h_hxp#TJznVqWdUw6<<6N zH2vPp#yaBWBQ)*arg9g9rr(>H$a(RP2A<-G;JkxtQs%vxF85pm&n)8ZF*4=N>I&PR zPVE8b)Giv|Z{XRfeFc_w%x`vW${TnPxaS)GmunjL1U2pL^!?4J4cf}w|18kRI+V1H;en~&05YnyPXYxYSn@EDo& zy2cD%-0KESTi=)_hIsi`!LVW<2>Xa(NyYNpj>cTF7a;EKmo^aZ$WJmj-$(z`A0JDnm-$uu-iC2&2{honnWFu0HfLeMSPl0`Q(Zy|M0?fn+f(+vnIcA5 zXqw?4Fz}cfzBf}C*iAY#FcvurLc@DA6PgMQbjJQe^WIFW*sFRN@Z4{qZb(|yGx&|#lAOl>}v4IdoyPaP05Z1yf<^+1im-(BYb+1UC`jY zne}IAmcjm~!tym);z@w@do!0Ol5ypk8b03tE#Xeyn<@H}_h#~EK()?$GX?uwF#Fz2 z5zCK*a=C`j_O+#P`B{2aIoIbZD;0`$Q6JQwkNwko`uQ8cV&9u7%GnxTJ~~?+A1?3B z6np~<&EE~&zBg0w3|+FS_8iTR_hwpl?NRd#4e!lNXv(9`J6G$&do!&%E!PgcXx^Kd z&_u3juSY%TQmhr;n`u{tcyHza;4+=zy_r|RMdaE#fP0KyIuSDjbKkND>Wq&tpl<|c zu;JNCUQ`P2lBf{gn`t_pxo__RH(Lfi9<0U78i@y|h>nBcQ6~4T!?8Md1iK=o7%5Q7 zDoh7W?}{W4T*wwLY&isBfR0$4?-F#iX#6@*o%==&>BMF!RJCAy(s7z=hFI2wOWHCH zk58Fhkt|o|uu19hgNC+H8bt4kRJ4I7q)hG`Eh~~sqitha{f$`d%2l%+85oTEq7fwn z=a+2NE_dd3fm>(kL0#o0ssDIZ^r zKGxYo>{CBHf}PwFUvXd_I864?_JHMX343AA9;9WOm(Wx#vxmqW4?dGUbP83$^_XP- zDP(j8ohpaLyV*kxM>*L;LL{Hg9-0DTQ3f5Y^zu1W%4QE)8PB$Zn?Z+IK{af!v4Y;K zU|3PCpfk@5AV?e>7iHF!& z!R7$`u#L3B-v(Zu>mhI~@BxR~Si$WM_cQ~q$~}{C=hGG8D%O=CihiQx3AR0va0%8hr+uct3)!Pa2M4Vt4pG<)Sa~X<`M`{hzUd+U$X- zxNJC~ZBB}~N6QPh!b%BNjLWh9p`cL~G%)}hPW~_)zs|%4|OFg;6{>S4^}#dKF_k)SV!FbVqdiv)c)=Rq!WPuGssbqyVBHb3KoPqmIU6o4Pj zrWx^v240>UBk+p??{k`UtQ8LTI|g2rE61&|9}0JVcNAzHi+Y1Msim4#6360btsSe| z$&O=@q1dsmqF`a*N!GDwY$#}SEojEEUN9WP#P0Bal#52=(>NA&7xioLPNtVm(T+vi z9LJg<20RHXwPUgVp`g(eV*nhhC**}=yfj5PQw*4941i-%aghP8WA!}zB4lKCLmZ>$ zZwOEH{22j=7QbVuUYn(ZiOVx|=U8?F79n0?*1gs;h6h7Iqnq^tB?HS2g1okjk;3pU z%0;*1)3`hp|EFbG)7(P?9GAa@8me{&Y+U|IYLoD&4THk+`bV1h>YAnh*M{pB%br5D zADM+}XYRpCa5g&0$3Ml6v0@Tye^4r|>UK_!PnkkNqm`f;$G9-9Iflstr*IwRqBZz5 zjzQi3QF{i-CvAX(n!V9;@j$P5Z}j8Tm+Xz^&)^w;RD#uumi_CgG!g8L?yz31?`qs5 z>O^1xmBbJIt>QR1qHZAoKNQ{Z1OI3^pQcVfTrAx8|Eq2jus8Zghx`6@8g8Ga8Jask zWxeVwIigO=Y$>C0ddT?uGx{So9TIac zh-)ZOSow*)AXsiFXfz5mGY9GR;f&No0-?ne)MC)`M42m0k~i`GH*z zs&ZJoyB>V`LuWlGMDpqN;M9*Atp{nPm%nblvmUfEUNs*evMq|%gSA<24ch=WI=g&h zZ*=HP!5rE`SN9?oYHoDcq-JmQ7r@PpPQP#MjZU$6aDeD|09kJ4MrZ9W$&HQ_BN9?p z;olYZMu$M~4l7ky^Q*nlX=~9q`rY2>P(wPgSqjxRI@|tXZ*(@wrEYW%SZQx`SgyWd zk<#Nc|J1aF(jfYVMbSpDvNt-ktVr&SzwC{UqOmAdqvRs3&7QiPU4Ruu-(_}1F&fPk zyurFB9%oh*bis|RD7t+IHN~4&?t~UuQLyuiA0x|(VzcczHX}daYR|`tqM47+xcjy? zKj0<6cu+N&7e(joY<|Gk0zV{hhi*1MU`L1>?tFKfA238<;m)_|;p7KUZ}0@QR4-qm z_ePHfvmPGG+dC5n8Hy*4eJNOIQ*9>>8XF249R!-0I5w}b69?@M2U9LO9G_<5pzfkk zqIg9yp-Wl~Q?$()rfv`e=5^NU$K_c6P|)aRV*uvur?=J|<8y3^@Gddnc4Gim6jWSf zfV-k-n?11;4RD7kJ{|PpM>?d#1rY`;)5UPP(1Wjh>DWE(fk>-A{KAIugcu6|JNsg(~<>lxu5n2vp1Ts_=^v@npSG~{16K)V&6+>1qQijBFINx!#lm50%?H~Jq|v+&D4swlHJ zI!9ZjBr!$&NPMeTb~aeKH=3>`d!zZK@!sgA!`Y2kHa&2h9vs790P^vJv#FSw`Cjxb zk{r#l$)uSxKKwwa52wM2x__Li#mgFr2iJ>^=15UC%ciT&)x#{}!%~bCC}kB68Ky_s zzEXHFob6PoIWKME!~4@XLE}x%Pn-BKHKY@prBJk8A?%*t@DP4qR#!Qi& zxIorZPm#Nw)M$#Nm0tdDz&5gLWsyKx>8tapJYZ(Yj|O7TJMc! zBBG+()MXU^*&QtY6ALAKqgfqyZ}h4M(q7L`r{Uw}NBA)ZAGPn{!=InVoYn1DHXQaw za|+~G6Y-1L+gzI+V(1*pgw8Js{e@Lpo;!?$&M$`EHhaZN(2K5tE>qAf@mT29Pd9#m zfFJe*9Q?^%h`QmcxdxbOXs&_Yzu9Y`ootR1nRQZ62f7kJsg{ow>1@IrWG@36*e=CR3|e{n1>`7Gt(@lWaEm1GqN`r znQ5nk(_wHj(?saV;>?b5=eUyb`G9q1+99Hl zX5#q>6q?Mm^@iob)J0C2OTl6?({4OGV=~hmE%Ap2zRZ=3TOOfyQl_seGUX`1Iy23w zTRaJHmRWDt6)E`%u+B_#tctfe5_?j+f_qGgono5yJit0L&4phCT$GunIwCVDBR7J` zOmn#NdjqzaX|~_J{8-?(Gw*1e?q)Au3P@+BJzj3QGN3Xqx)L73(TkaBHAiW_yHj)@ zWv=3jPXJA4rZv_PPc^iAo67wJn$Ap1Y)=c6?|J2ggNX~+DvfNf@)G?-i?`Hv0G%rwEr((Ce7$Kb*;nQ7vP@yUR6 zW?JIS0sTW=Z}D4(VUgqRib0gd9go!-mNa2te`qzM4cFQxTyoLJsUd2+IWp548G`LT zhPJ*jO$_n!FMz>jrb)%}spB$9W}38tct?IWgEKSD;>ybWZ6NaIRWj3r$l=n97XmNJ zOq2Gnsy{wsGt;Ehs;hwg{hxW4x$nI1d%50}Z1cYFyvkoX-@tkQT6VC6Pd=kk|Tkr$TTvY2Qk@o z6CZ=5Bhx%O%Jfw*BGVjL7A-LtG##1d&_v>G4I?tmfu%^&x(DiHWEwSzr$EV@G^wVa z`iiuz2EHdQVpDMW(WHPP)0TlvN2am%*;Jj$f%hu7wx8-pDkhT2)s;8}`k=$8#X6o^ zWSU}VabLiROk=&&Oe!AeHBCcgnoHv~N&*uuCo+v`GQVMfKRkl`5Sd0TTOcTnPetM< zaNUW3d4FHU#T_bGJXeGN2a-OCd~k7{*p-(4HcR8SvQ)c zq(-LEXZK}f+PkP>?oBE(jVVrK+Ha-6$B}9KI|X!PS~^PQvts!5OlT09RGL0eo zK0tg|8D!8b%V)85vArmNOB&!2nf4Y~oX9j*PPKve_PYl74N8toW4tkC8XpGSiA-a> z1>uQ3njevA4!i16-EL625SixEWRKbf8tX%3nxjt1bwVrZ$TXM6a)nzxHWYU7#0HUR z&a4oTX-@#>+ZiI$%AkwzwZ)NX-?R&0nh(#zJ1qiozHOP*H_X*9LlxDMh%JExPwNqx zrf0I`dFYE?LUl-c`Al!6#G?hoP5-r|V-aP; z&5bZaB>MnWk!hcjag5q~fU3we(%^S(=1i66q2u+6YZY5oh>Ppe-T^N4y?!!8c@Shi z4caQ&ezr+@9wcooXdHd^gGrX9$TdUVs>n1+qpYOue4%n=+CJ4Bf!~6O9iN26f=^{+ zn!coEp#r$TMLY@GJfc%%n!~`6XW$#_PZ3BbzT`MLM zpIW>5V10^OUQw(0q-wxy9A~2`c{; z{1eqkO{#xlA+)f6f?9z66Lg^c6W9j@Lnc24TU8nrTe>Ue;KKg7LqNaXbsVr^T_7{; zIvo{!G86%yVbQyA!k!FRz1=mDVaa_^!{$0!l9dPJUiR&G335!|#>j?9sy_{3L1F1|(h2tF{s>eIP%qv}tyaNsuZhY5?!RLd{6t0moEfUk0wc1938$=Cp}XzxIkCmip9M~gjB!vnpN_C~;;Q@Z_T5{E;~`dqrH-LAHeFpHBTYzRe+UuzzhEgSa}CL+1rgKIo<&; zJOQxs4p5`$s{I_W@(y_6Yo9FO9gq#t3ozY7;2rRA$5#M$yaP_Vi};_w9q$0)_}tZG z$2;&ORt3$!C8Gn(_`5)L|EWO3@Y+mg@$Z@(#Fi z!k(+)r5+Js{{&ch2fW-BpH}di6z&0lm3QDv6jXIldxM5I`MzP8>oI-_u;U%z3gc@e z-hPV0$veRKw^VEKIlvw7fUL+PfRuN@?ae0j4|%=Wt)Ed02qbeluw-DR_HxbeV<84= z52dEaRHf!ZAuhh??FnE|@2wTcN7zR+4FPclY#>WTyydeV?*JDp{xl%xy)~`_?j7-O zG)~?D2bWgHlhZuj0VdMGCG38{Q@jIQ|B1H%>-W|;*F=fuT<-wO--QPgxJTe-qrC&e z!J@qbPW~dX1F(K?jddljneKQ8$aEgWWYVp{d?+%$;3>@ zJ3#8BVj`KWJ+T1vL5Fb#!#luY1T#%B`~?R6-WoGdGpRM%JufI4yaO&xuI2WDrr%q0 z6pKW)S*~}0TK3A`f%)Ll-T~&~4wd*Fu=WnfZqWjB4DB88FwO<6y#p?sNizWU4$wqH zc?V8ER@gg0eMou-4x)y=-T|gK-hmG)fsefdM@Bl{fgUK8&+19F?@nmo9jGm3KhWT)9lD zNA?b^Rm}nK0M_*_QH`nV`mgxru^X+Up2<>c7}kDjo=G^wJES<&>-r-&riKn6!Zw1|FW$#_rPXU9ou4f|gsdfDqAf~MA$x3`U z1%-0f^^S~i`fq`CeLr*oUe|AdoLbl4kM3h$B5iJQ^}3$Qe}#2@kkq8E>xV%Luj}dB z;B`G6xa<0-Fxc_BzIQGvw)6@5wGTbwtm_v5z$RAICGA>|I_vuP7;eMxWWZ`&AIIcd zbN`^>bD^dTGk3feGIZAUq}S|9S~96fysoEiq5{Ddj_@qni6M2-9wot~4@_#&PR3e{ z#)^T)y#kB&&YELzi0rl!Bp15|zuX6~XeZq%%i`4V*6FAZUYCvF0Js~#IrQyYMFIVnytAZ1MoM0Z_Ir{-0J#eTpy=#J2M>HVGz)AzzOyv$kq3hQ!*E|s|J za+gq+wHL>`VTIP^sZ2_Rvo0s9XI;+B6+%}l^e}kVhtwQcmnYUJMp~CUrV9H>;FInI&jY?UA!%4G$x!+&ODQBUnXTI}oADR`h)(tZrET9-$wxp}5Tp0Ib&K9`5)Vz|Ojyo0F&_-eQAiT~4^L=L1qt?eE2x zs#WVVd#nz62v20NE5yf~MBxuAH!w8=a^2 zZdSq`2w1Jlz1;6>c#S6m_~th`>+(*{g(~b`8s6mV#xU1od@W#SUCtH8*GN3{mSvCC<>j9~Cx!apf>L2oYv+d2!y1XC*E43$Uh97+e8K|C>n!h#Ig+g3> z(c8n{cGl$u)Cl_rP5ZBqFj*?%*T19Y^z=O$E?9gvAZK09bs#&_360ab+`*-l@g`e5 z>vAU2z$NVGfTyg>x&9L;0qb=+=bGs9uDdR0`HT2oIqng-+30ooX0YgWxs$(0#NKn) z<*X}tKM?iQo=oRKOm^MGHjwnX+@mA;zJjqXcVJnx#CXv3Q+tOd5_>g_b-4pekz}>4 z&bpkMMAErH$tN|brk`3s+IB3D%Gw;4pI(>$3^x7Lp0(dj)tUTqo3kz_by6{rOxB*b zal5-NXEB1ArWoD?gI~PoR)UsDzmyZLN zUY9c$cc{cczp~ zuyvEc9`7E|BHU;IU zH6^XfzXpr5E@$Ob8+cB*+_NrcoWA5J;x7Yt*5!;_geNjqD1NNV9d^~DW@{Rr+PgH_ zqcT^z>vBh(l3T863zQsXCBLs+xYc6~h)AWvy4;x+VqM-AIN#2&F5iVN;;ze!y+pHY ztjj}lopm|&4Ra7xJk^qj6|d*6%k@l_*5!MEQytP%``YuJb$P0|xrud@MUT?!@~I2l zbvb9l5}a4^9B67?PJlUzni;Q{JL~et9Ms+kRISTNgWt88Gga&IZi}3C`4zdi4eY(( zQtNWcSFNu(ce}@n&bnOEczrEtdqGp{a+*C| zW9quR9aVsR4_Zg9%c(UCt2;GM0*4~j8HajZeg}@Jp=n*dO3S3DQ6@^J8_V+(N!FUUxf`B3)Wb$R`Ho^?4BiBGM|$Ag%%E+;GT863dQy4;ZwPX8^iF24g^ zfY;@-P#J1n?nn1Ahm$t9xO!bq<-fwZ{1>Xq)OC4LXyJ7^T^qbErvrCg-U@>qugm`d zqbNPD0e+&}}+>d z#irqx`vBJEq&sCZIoak}moFtn$#$@k4VWFG@>`6?mV?FyU|qgWbIj$c zuwEy**c$w@0a%xl;uHf?*5!FvJJnl9KfACls`oIKHO215WS~@_)Vzqh(^wvsKD^V| zn&yUB3ynFw{c;nnNtm=*f{ln@4U5_6iP&juAOI!F^=MCCrf5HSXs@>XVQXp0zT}>)D)N{ZtE@yW6TTkA~Q3%nKJ^9o9RI?QcZf zT#VRbcSsLH&TzlIZB1D3H0EKkN3B(o=lsPRJNd*WK$08_IV1dbz4c1+Z!e4eCtzC5 z=UhmE*S{9#)jW0@^C+|*d_BzTxt#y}PeHe;(UDXIv1`zq$=8(A&2Kl@p!ke{Yo zOlFQh^rm8nVFNCwLGeU3iHEP>@-#&S7G11S<#kx zX~c%-L~kqFihyhmHs~oX)t6wfln*4}vzgggLxBXRRugi08c<=5ajd zj4mj3MPdH|d=Z|9=KLKP?&%qCz8BUzjg9xfL*5VToyI&RV+-xPt%@dsZc~|(b_TSk zk6@QYU(oGnine}RSno9UtlO4SZtM<4iv(vdjk>dvyXWIDJ4bSg1ZMzM%_nQC^lk1= zV+)^-NWKg&-yAOeEmI}#G;wBo^qtlyLO*Pzj!G&v14X#JtnkH*F0;Z+K?C;mU@Yd5fl<#@_9&IJW!g&TUvTiN*f#g~&f4i; z?xSno8p#Ur`;R(Ged>|TmxpMRSxDYx}HjGHA}CQnbO zQl4;HjkRxusVL{pJBCYguFbiIERL4iDyOr!kfp3u%*7h}ct* z(L0TO*FUUx8oQGIMC75cv(uQPN7$VPU>hMk!p$ldXom|$m6Gxh_TYhGz0=r50A5ey+_(@OS3 zqvWI}Yon(q`1I*$Ig!bFD+Qi0MsdF#pwjA#eEC?#y(I;H=P`LJ&)VrxVv?Y+&BqmO zS3#O$=sG^EcN&}6#%T){j@^RlJrAE{)|Y|!T@&TKpLZJLdZ5mWw^k;F^-g2n^3HiO ztalo7VO2#NCWljZ8sniQzUwJ9;?PcGoCA;D_8(8H%7_LlUhi1QwH>zbDoyO|S z3A48@tFMP961UA&Fm@U%DDvVwMZ->GE=`*8^Zc;0(-_luU`WK}84N@w z4J&+;q}vVeG)DIW-f4_RU3HV(STgMHG*-R6AyRi5Yk;pDnoaP7X#Na23Sy_Rmh|mI z%cZ$HjS+?~OcYbByS=RP)3>+8Iduo2s_kHWBrf^?KJi;Qnk}qweKyp(-;x0?xa5dJAkW>W7g1l zp#x@g21)HSHu(q3yVKY$B&2s5V-1Ih+9T@2sw{Omgm-|%c6!l%nBTd?H#{wr zMswfmS8zE$nW4Dj*9XG<| zF8-^fFD?1$vn_1MNe%07cy42O+i#Y>v~Ghqe5(x4J*D7tp)m|IcYN^gmd9HPPV;kO zcRzhb#;Hr|;tBL9`i3WAUN0p{Bx@d5*VOC~B3r1dix_3fWyUL^RHd{Mp@&P0 zKy69Kc(~N!j1rF)5I3*EtEc#04c3qP;nH`1sbb-kP|k)kG^*Y*DAKG5EsuG?B_39`r#58q8<{-e5U=Y zX#3eF^-8FuJ#)#@50}WY6uDRbQ?#E?h| zWp{g=ewadC@Cpx8PD8rD!<3%T!UJ?Wh@=kC#p$cye^;cj8N);CZfK*@U(&C=sl0RN zeH?&cZKt8uo|f(0d6zQ$F~j{TICtJacbB_)j&tYDW|+C-Ws#xtFopD*Uz3*1?zlhk zowqZX)$s6OS50PN<KJgN(HpjSU7(-#F%$ac&%Bw>6sNVk7XYZycmM zWt8yVdCLd4mJ7>aifr=?Q!ChjYFSGCY~19ap3&G^Z2%sooYx$4LsS*kTWr7^+5kLE zA;l>MxOXlZrut@*0p4M15~;8sw8MIsdIA~@YYOR{hC@7oLxbyK>IJ}hm?{xhGU;iX zT$vA8W*+$TF!eI2Qp42ykWqoaG9Sv`J52RUgxz6^iNvRdsS-)K@(+|u>yDX&v{J;k z0CpZYIx={{SKY-??p?K2@02&MpW$>8_U`MP-YIWhVP45C!p6V6pQ65b6=nE=nojR5 zh3UOvN$$F}oZgwwFmuO)$k6GX#A%i!E$+>WmI$hMZmywv1$(L7?{@x$x)I4}b*EQQ zz80ggKS0wrub(u>+z^>y3CbyUQCB;91u6c2dPSld4506Jl5@}V-OhbvfcxD}IyGOK z3(S5mS9!YMGzc)PgT!h-T3JphayA*XypXVYjA@&zD4PCmCyAKrNnN~uRasm7-A>Mi z$|qd+Bdx6XyPewos6Mb*tO~T23f|B>?ETc{c5n;3bz`S_<)=1VaXVh!#A#mnsm*o_ z9|5eU{TCo^Sd#m-rcU#g##+v>m^=P>Gf(ppr`esfWICVPq=lbq-b#&B^AhH{=&vJ* zZp5^8}RYyIs_}3u7u(F8NUQ$;zq5jk+!Q8y6jeFKp4Ej@>E(15TeNBDEpg*SeC;>^v7 zRFGuJPGLR$xQ&cs)II`K#kP`JJ~-63nn5_$x0)?lCOxejGEp+saVTQL!KZIEG}7o> z%?+)cTaCIYBug9yHb`2zSv=>%MV2t&b*o>u5=E`JM?902NDm_+2YK79*w{k;>D`Kg!;k0_mLrc9HRSGOe&c7tC&wc92WJ~48qU;A^4g11b%|>l-Bc4 z3&SPx&?{7h_$nqn&7!e1Mh9G9QJUU<^)l!wy}1E-%IzgDIlXxc1Q0C_*!%>CBGv?l zx;J;ivF^>eOPq<*8CT{%mgxpQ-J5SGRchk&8f4VON#;Y@dwX;JrJml*MB-Du`2!GB zBDKg$5pRn^IlbAD5t-CfR0pEoSF2G&_1B@ktG$7r;oI@k`a@ugpNoiku^AEiZpA%O zHx6er9)ofmPMv$M5Qp>9Ysl7(!=Y32Pe_=r($RXN#$JFRtpq6!=Z$fw$5&(=&TbqR zio>~r2J>xJa}MmZxJ-$|VRojwaX5^fA{jRh$HAmBHx7ph=Urxs!*MV#GsWRB;h{?? zf>c0pI1W~@+>(XjaQ+vIS3SkyFdx^Rr$iKo;}W=9JyeRrDWKj%r8t}dRF48D4u@ET zy{2hY$KhN8pd`5-?dHuC?FYYy#?@x;(X_)}8rPCNx_MN`;WX$)7nARG%BoC@Xlfje zgx3M4_ev0lL$#o}TeghqI2o^==d&Or2Tr*A5B$?wyIw%H;!*Lo^*qb$eO~8{uF|OkqIx3lxg_KH$+dD;d z98Q5;h25vKqAl|Z6B|CC*hSG+1Y~otLDz7p{>E#PIu7TY=3C{}!KI=f5&y4i)Q!X8 z#*069LsU){DGrDAQg;(}PPeFz!x5f-v;%PEI7X9y0#Og#vwKv>;dn~M7TRYtO$6Ph zG9~TF8>2c7$L(l}mh2JLaX6OSmQpVFW<`qxi!hD)lalLrYgEVKB!H??$=afO>8H(n zBB!(8KBW0Ff*!u|+?0cRMs*yHhbHq5-KJ>8gOymnC-3>7sW=?BJlL7}_Nb1-@xtE$ zu23D7StjVhJg5nK*d0+FhvT713o?4Ct0^=1``u12CpHng3e}b`0PWV z@fDdJ%I1Yz8 z0o|H2mp`f=F`A1QCam%eMz9dFm0^j~hD0;dB@BD$V-XU!7T`WIIDvS=ML%8ndW^ zS<-IiQ?QQ1k=*tD@|s2*PJK^4@lkFZPKAJC`P$#ulh4(`sE)(A-XnQzj2nk@*;Fk1 z{2g6MHx7p_bK`L6)TE-Al#eG4CzW8{MAX=y$f!^p4s$Zyjl*HAx2uuja2!l3bK`KB zaF5GOaX1d9n4LHrA_)7>GW4cTsSvU4kkN5Cm5N1m9L|;W zC$5V{oj4pvkFYyl71eP#<8d=prKCKBeW`d<$KgBWIVfw31!MmP07waNME@I~12ACgO0s@EO1~;AXuY zpwjA#{D*|%-jV`;l9ac6#NoI~OcE6K$xKDtRgk6_ik6G&IGmynIBmhgvFWHb9f#91 zTi*LQ4u{K2ombdxE6Ceb*2R?aHqVi_tE@{N*yO6S>r|9Ode(mdIi&N@63?xqMjVR6 z;T(AEwli~8WkiGPTnkxMY!)okaX2$8tJ*19h|eBdMc#c7hjWf~P?pl1*nH^FaX9~0 zm3Jb<;S}Uc{8BCI#NoINp4eMG>crtN%tJ?FPYnel4#$C29M0M66b*4WE{(lOiHw?2 zCk}^cRLv?5C%cxSAr8l-y;T|aphSM{s1t|d&_tqs9R(u}$AOg@H`Y}&#NoI!X~w{M zQ6~x0hAM;jH~g22Udn=TEG^4Qmyt zk#RVWd>qknI0j6SG!eTr(2c`s^+`m>;k@ZsA!0UII=zf1r`5uCsZSNliSXOZLOF=W zzXRsYr%#0`;zB96-})?~<8Wl2T!i?OpGVv{94@Jh!|CxwL_X3e5>Yikl_4^B;FoKg zEKzYd3qPQ`#nZs<18~)sp7}7v;XLwwL3AQl8f!cFFS4UY8C0Gnz_<b8AOfdXN*vB=P}y%tZ0t8A#Erw5A3+?>6YqH{kSaE{0w1QDPky$= zsX%H!i_zFn&~yd9`mR%f)Rfj(l8ZfxUtNKuJEa2MrkiMVk%oF`rNB6bUGBKIN1;gGFz*b3gd ziYniU!&!@B3;V<}=hBjoGLvk`?B&j-CAT2VX88IQ&ZYG;#Bn=k_=1Mdh0>6pVKH}n z`AW~FMVw}JVs{^9l5y(Nio*_$!y(M`tSdwk$yZ-d4L&mm>NBcV8~s3Bcw+vNA@OsrJ*- zz^whWz9mW~J#CIF^D@g^0H5~L`n7p@qjmvgl%H1SL)m-%wDp!o+@}sqBtGS*-3MZd zpO&l?@rPfIxPDqkMr6{ZNp<0U>HuH%#!XZQco3GeS{Y-R)S1i{WGHoY5u;4G%!tFG zD%Ei~IqE{7IGh7oJX%29T);Zc40Rub)myKMg$H4r4QI%CCI1ACOVx-oH#<_JCSQFm zq926yCF2;iA9+2ZAB2$xziTsRsvd-OeM51rV#^9~$p>MTHbnG;Ffv3v(31IF*0lX> zlX?&)Y2UmV(GSANvJ|-;8x`#*Q_}cB7|XdAY5CyHb<_li!e!^6`a?yUU^J{MZ;a>sWAb|M`}uUVV4WFEv#i|@Sq zz^sOc(>pyk4q`~XaqQxbG50Iy#zDqfjK=nYrf(cAp+?<#$!_ZqSLy-$>Kg~?P8lUq z<8bcXOU;9DL9)#=Ocf!^ljZj~!xWX@Vl;LYXnL61p*iMqRaj+7E_N+`^)N+>Qw(tL zTr^BA-%SR1AC8`+GT4iEIm1*s95RM=nhI4ChayIIWIas%16U7JSzkNDR8v=`1It_n zpB|l+1^+_YPCp-*|>8CK8_-rdEKMGE9+`B3=oFavmo+G9q&tZtheU zDEHZ)Q*K`U$sJ^GIqdXKdGne;)oI`PQ-Pb;Qw#@>IK6W*#0^VwFVpb3&~}EIJKhl) zI=z!P%^9S{y?N0RLG{i(hg7d%FO?gIGms>b!+vyn1?6io8tV_5?iJaP=WaQdO|V9i zTx=MAb*~`B|4*-Y=LZ--aX94M^Tgq_Bt>o<4xO593A5WBlx{ZcpG$yYbz=B?z_fd< z6Nf{vc{9^q{a(>@91hd&B3k@97{JjNTkzd^&W6e-T=yfbtT+xwyC0qCiyUNWl&csl z{R7#aJbggsQm#snC!!6=0PKRx@1w7u6|rWDmjIVN|bq zLo?{e9+!c;j@|mW(x4-In1N_gL;PDXaNnZH9=3?8;!1r>d$gUtH2_BQCb~_in8|85 zrQV&r#z)IpYYt_?Ik73+nYe@14<0-UNo=A^{fjrzrGtW-=w7@;&4~HZq%+QZX)>TCS&Cd;)U65}k~E$#v0SG1#l*s>n8)C2mw`hspc+%}jVGw1 z*y(4Tdn2_5HcqE@uZ2Sq`yGe+-uNGm^}TU~mPt>$&6T;2W&EgCeQ%_pk*_)28;?Rp z-5X^-l)d-f*!54(y^)E;r|ykgK}@+fl9eJ}8HIB0jgE}#s`5_Z%Lgq~1_ut&t&;tFvlIrIQ^UG6^E-=4r0WCbgq@kYYmvrC; z4*gdIrXg_XEAWZZH^Wyc9G3#$={azSJQgZ&$Z<|k;Lw_Ml1>dA+8T+fz@dlfdV7>g zkU`g}3LK(m-zsqEiD*;>4n0AvlbMz5Q-MPQ>gQy^5AaDh2uZr*4HU&XK)l#+@YD}p z&BfT`5Z%BbDwsELs5c%C)XRY9zupHW@Kd8aeu}`gTkk>mX3GZ;HAIOhaER`RH0s3Y zKnD($5890soklgL(}7F>wTYtB<2$C)fu@%V&Lw)vOmPR5+P(vN)hD9rK)|rRq8e$A zLlOHFhx%&Rk7Io`Y|%35Y4^J_!&v4A@ae1JIH^*BM|R_=z8Yjcl)d+A7zG9=jE;%K zr>=${K}@+C$Vw4!h(bA6gCip{si}G7uJ>>&)Nn(DRTOK{4nObWd3v!=@Zh}Ol3w^3 z+8aObjg7(ww09CbyEQ~bkUtU(}#f?sgicKw{{*qOX)qKF(djJl!0&IkPdf>%?kK_Ul zrog`g=65Qs@RyD)B35al^5x!P*)1k2mh|v9uENH10JAT*nDXVy?2iKGcPg(@`B33R zyf$iQb?q`DP&TaUf{eqPJ-~UEQ(og#B_cDtLiuvZ66wng+Ncb6I3*|0CBKY*?S79( zwJ-NJ0EYDn$=mN~_+)4d!z&psF&@@QU+(uF?guq|E+mkjVKH}n2ViFkMtaQ+Y#f=+ zD@rm>O~F2YjEqxzP7y=uit-|@ByZ|QlPA5jVEo~{!Tj!-(64} zsPrSgew=&MUk>SV*e~kj;pp`@d?NQ(!^kL-?h_3Gi&8zSYm7DO^wwv88e@HR`s=fE#@Ile zq5AAEV{E9-Sbg@lF*c*lgyYx9oX;C$6LltO+67~5lRD4pvww`S$YPE@y=bg8>MW>S zS_=Maw5{{9CS5Yd`>L(O*(NH#FjNIRaH^!pyG-zia&#sK}JTlbx55IHm=Q%;bhVzP=-LJtUeiPl*`V=$#;Gj zILye&uBlIk8`ZNL;A9(_KEkLQ`v?d30LZOrw4+kA#&IAwK92ckv?{2DcG#;;Fg z4@L452|i*p$sU6fTKwfcYP89oqEAK|o!igBNt~=5YhDY-nc3IEzR|W(JT97 zeKNtgH+wHmej~Pt#(?ZYnli~4o_$)MJZX%z|HDc1Z!D2p+Mv2ItTT`icG<%UE~DUo z0h`1j>;|B{fdAaGg=sfwnq814h2ulPFoT5SSTTE)&I6X6T}I?44Qdu`$GaNNR4|JW z2X+Ji?fKU-L~d4!i1F zR7+RL6Hj6~!1{7%oXM@LvUr@#Oxoa`jm&cE8Q-H#WF0ce&IjpkQk8G;V@s2M@hk?= zOoAI3)UQ?5#uoshZJ2W#>x_vi;%@^#NbF5gaQi5*z;WQsq;}O)EI?y-qXRWhfwKY6 zzXdhjA_Z;%_)b#NG6lXH(9;vkirm&ICQjCHn-o*xtAQUUEo~Jp;*k^h9yk7T+c{7_ zoX#YuV~TVcuGE|G1zc);5nl$D1A|Zxw<^e_Yh2hL0zY^X;yn!le6qapqZ+;=g*_ew zYdvDWTjSHvj))lt_8{SXHO`F{9|~+<7B1;~G)~Pa;xmEM%{=$sRD1*QZ%NPn8fP@Q3tY&>0C#2TryhIZ65@&dcl&>P*3v(-DuVA(=H~?pKW*OS7(UIiw1W`ajjBRoZzcKKOhw^$|wRtWwC-^0sf6hiwlv?15O+TX&Dbu zQXsA55p?F!r9|cBoOy#fIDZiTmDjR$%w@(YgKgC6zG~AjP07L7l2Lh6MLH2iGdiuj z#b-4nHV&f*eeyG)_i0S>g`dTkL?qE^Cs2zhJ3#ReM8nHKZ8C0MGjQftz+q=PT~Ec} zVw>coLgY`QyMXAcvnbMCDIKUQc(G`Zno?RKl$nF9pul#N9>V!tRFCCkX1EF1rlnDeRem z-Xr+-bXn@U1S95P$>g#kRHdP>lK)z)Q_uiaI{NSdjR(+9y-_1oTKRH_rAkwu)t*Gk z@L4;bpHIy$to=b%^;O#YZUx|_iQ+V5H2f7=SDkou1nHQo6ZjQZSH-U($!{`w^wpi2 z+=t0SiG1}${Q9n*k6%9)r5~B;_!#?cqx774Q0i_O)AUVP=5857r)Dd{Vz0a?pTYXQ zTgEUwJRK@xo90VDqyMlW<^AxYI&`VT-7>}{bY|@|dQhBY%2uwaOiIPZ_py2@uXKC1 zjA7b^eU^e`x)np$Y^C8t_w%NSNfn716XWegMUb91FF zV;oH7TKy-LYYT6#EM(uMX>GhT&ON>YG-t~gR!TK(j(DD`d+GulmP1uw%b1@vBW)Su zm@4e+j>xxFuw~2%^hd)QPKMe808^}_{~_O}&?QCim4K!2>YOSf{6`J@g`{^8u?ZV;awJ^Soo3yJgHu%`)8An^|O@ zeZZo(jLA9?)mz4RwAeRlc(hm2o(x!R8RIF0{T^VoWsDd86R_IK)swxQdorrGjPb&~ z0IMxys8Mv)J`Y%J8RLaN15DrP_0Qnv0h-(RRr;Q=m8*w4UJtOdWsKAABK{C?XDe62 zg}oAx+A?PDOkJ%eDZ>Se9zu(EKemiHp!w$csQX9*B%huBn|$NKKi^kShuuii78I5n z0Giq|#+AeSh8kY#5fS#cfYp{UUhe2A1+PirZUR_s<+|LtQ1J~h4R7+TVVJu}{1w2? zmN8sme2v6^(l~A9%J}P4YjOK`Tv**uGkX*+?CyZnmND)%VN(B)*PFdmGkoXi?vjC( z+UGRGkA)bhJ(QYOr&T@|3UTp8Z?6D@+RC+nA;SJk)BYUa#ODs~);B|xhp{%(2-Za;L;ugSq z%NWizu>?r3N5Gi$OXXGR<{jIFn+>^r{YQ+%8L;RrW1Rd&qRQE*vz06BO7;Vywu~Xu zc@UFbH}Nt^ddnD(j$bs4En^&57A;ZjPrPgKJuIu{p@~Fa4P(og0wT%9psB4~sYyHq zO8%%xHT~2A(za4_sI0Hy@*{V(|7RnSIEQiTM`T({Y2QTEncUz{mvC)A)sIw6B$KNv zkqo3eTe-4P1T#%B^aX?7GKLwbnN+Ouc1^=pt}czAqa`wf>CTohj$%{-;17?$%-()k zl0lfe6xcULB;E&?-ZF;TU$q6E>^NJ-$ZpXLh~6^B!#Dx3-ZI98Gie4u-os3qXwa51 z@!vz~qM?;8{5yR{R@uQJQLfdGs5V&|K1>|H3M|FJGRH4DUZh!+G zLg-nQhh9E#a7zd?p)vmK4{$*B=b!2q*`MHqYTN&;Ka{-_Cugtm3;#5KMg`*ckM&#U z0hnChd_m4kkMV_uHWhQ0}+$2YC5X>|#_Z`X1U!c$}A;`#rFMx8|r3QbElEzO4`jd z+{egqx!wJCSiig94xO5$*0bLZW7jd}?6<>W@yDT@Tr7UtZ-*iKT|jET9h##0EVeFY zEmYH0?6-3nEY5yAtek2?#M}KS-#YL=qO_THDAV{H;Ld(K%%4wq;up=2{dO28c6B*+ zKcsYFza5t*FUPH*>3wh=bxN)(T2b$V>(W@R@Ff#_kTRruKK9#jrqtMPXDM)=3t+#U zj*Ha5)YXX1!L`Ocrn7-3g>}Cp4?V&R`tMec)GU+wiTN@v9FuBH#124$pWGoVQ!fc9 z%wWM{H_Twi9wi zs>3obk#UULi-4*y1JdAkZRSi>m_gdNifa{HR)~x1)qW6MYVRE~M1>2;e0FKtezr-4 z8Aw{~{ZSp3NtUI^y{TzGnUY3XN!xkEquA+K1}c#sasC!e3@?^0s>aeqpuXuev@FyV zs)qPh&?^)Db3|Y3!IO*W;Yxl1jvW{z0}IUghYaB|a$S=qlYibNor$VfV|c+J6e!{5 z=^0mD#U>A~@rmF!i2rqu4PF6y)25(Q;wcPb_g;IYTzEwD@bh{67x4Eb{=&IPfdaWO z7>lBlQP&RqLHi4@Mwd)|NIi*4Y_CO6R}ZPFXB*aYR3*RQP{gQW^h4@-IOZo|`1;{~ zEt8%`4W?wu;84Uq!Q%)0kecdHeL-@u?fB(R zi6_RSJLQ3`CkDB~Roh`|?+{x`T_umRaEx4u`sBySR5s7!@a@WI=n|gic_rfK29zb90?aiC{iz&JshD9&mxmZ^Pucj zBLPJ6gJmXD+7houj-uAEm%!~oVG)rBgIl@r#t|H=4W9-X6=@o@e*sGXV@70X@MjN8 zGqBJ=5NQ&$(|?YNB_Xhk4n7Tet-OYYCkDxnB4PPV$?gtX4Ll}@OimFQq2cL;MdpLn z3zOl<3`HYb%|S2I5YrLX&}9~B9JIHBZ!4*O!J}I8*+)UUnJisYNQWIk<>8y#BC@!! zTs6?hrx01(za3Q&SKvOO3)|1jX z1vJ&dROPA;ofhUo6G3EBLr`m$p(`=cDJa{Q*H_HdwJa7$J@7+);0$=U4``_v-DJ2` z&<6Mzg->OBmfV7pdLixr81vanlCR#Cahzi+K>XkBWq|8;wTWM+QA|@-(Zvhi& zi5hK3_2804{$rq!(>U7YKV&NPW>D>t%Q#vk|6NV*YOesD3ztz5hxE09Xw?k8>WEg( z{|~J6tTcLqt17?#KML&T$~PDWkd|}N9x}uHHvo{^HF`6ZT2=O0faG0`-onqsWD8t( zQ7-$Uw|Y1S1FY2m71PrLz723Afwy@;|G(0?8NK5-Dh_oOk#Q}mj=F5LLWW*kMYHmo zYSv!YuGBVVlm#o@$f7ypur{S_Kn^x z&1f(Vz!!~Ra9_zr8bpInfRYn5dXE>)_)qcPC(#Pj`VD#jW!`>XbRN*9O`!K7Mn!|~ z0g#_GIzR#O%hKN#9Vq3bf%j{4kc*nqsJB6y(F`ibOA>V$(Et~eL?^nad||)ABbxN2 zhx8V`uixMokZ6@2ecC072DJ@^PIXbGYq2Ix^N^&jBEEE)>K4i)IT21zHA5v!Ek@lrAZDn$ zG{;~z+S*2P%%Nwfr2Bu&0Y!x;$z;q>iAl~-DGOy}?ZC~au|H|``hlN*NAwgH2-WjN z{s|n%fmd(DE!=>vhGxWAy$N0?qHC5oMO}uPDyS`S1*?IJhQ{j6I^o<)s(TYDXf7cU zd;n*Mdx5bf>B5#MBrbfF)*?P2@7ADbQe&jQJ3^x9;uaj$Rt`}UH7X!R?tZ`n!CoWB z$jEpR(yN;xx@2tjAdOc&|qpHxPK+;n|X#i$#ai<25p(j#(% z?68J$kyZjdPn0QS0k(+*s=_6VPC<^%sxd>7MzTN?ppWCf#_S0=R{~_P$pK=)DWDxC z`ux0gj>1MbG|x`K&!-gblrgz30v@`6>G6yiIJ}7t#|Q63vWX5Cdqn9_N(Hxr=I;vn zD>UVjS&Luo$-ik^V!4-f{5a}D2B!XvvRO<%xfQu@DT7ZurhO5RA zPhOum^;`E=YOG&;viaoMad~Eb!wob93aFFTIPopcy`=DZkZ35VaZ5|9KHZ3|3<)nDVXcb`4PdUAU?je ztf+Cxqb)cF=tUCy&x^hdc`u)|KJLutdFMw_r!Dv#SEg{1qeHo_9D7w`_7adOBw3H0O^kt-Z z$>TuUO61a-9CFE??%eHTFomfLmNB?{`Z6q+QFJQ~QWqkZ)#R|3+ykUpL{4aO#3h@g zP;^@i`cK58qDXxiQ4f#X+q<0rQzZO(u`n9U-lnpkf+eWgJlo{9O@htGdCC_Sk@ORQxYe^I35IV0NEs1*fy|c zgeQFj;Kc;GR_yM8rtY&uFv~}}6dWI^;c{9FQQ>d^PD{67w(kRG_vEkxG+O=zEBMG> zsY>O395hOr@RAy;em2=Xu9-Hga|W4@(}PE8X<+K5%Y&c{{q-MZ3_&pZBX$5%j1a zNY-)TUY?mi*d0wOZ+s0c!uNHzsGNQ6ga4Xe`kHO>iP+Vf3^Dxc zG*RyrAI)8G+GPB0KBeHro2!o$;uhbud#go-sJX}Y9*wqz zZG-2gA+(1g4FVPYZ&8QKzIl6^Fp+hnMF6i5p%dN-Aks8YW&owF@SV5_sAdL!M64EM z&g=xMcM{l0ia}QAP{!`t~BWZ>g=Im>qEfo(&>@{Z_sd853F1| zXF;otVnl8T$mqY7l=&4(TRu4Hy)^hXs`)Z=VRGkxM`A?Y zG<;OTz&j|$qMEaAZN0@1X)!b7+A?OQVfasfk|t+{&Hlns&83D_7a5y$%fXcUQ$Vk9 zbCV7xiMq_V!Y3IUl9|D)z({pea}Bk)mlW;*5?yIE*DIJfl#&e!YRyU}Yb9@blt|JC zAO$~zG24iwZ0y2P8GxDep@(!QlkU`{&pf1unY2QazVwi&;zjVVCVk~0^&d#ZEcv<0 zYo~|w7%S|oNxM8Go*o1zYSPyp61_Jff?G7{8xM&iM1$uvX}5<&!JQ&l`3q&n9uJAe zU=h4allFQ@li0#_nzYYD;t%)*f6=6GJ*25D75`G@wckUU$)w(z^qq%9Asiw&SCbBS zNZhA_ziHAB9umJu7%cx)ni#pZl&JZWhjjjJD0J=*HRlI!2iMZ;L!#yp57&HHq!tD9 zK;P3E^q*b22<`_P6@pys0BwIJR@3@2SNlXyk2zb5_WAC7kU0m?9a&Puk zq%(|~<1sj14K2CreUq}E!pTq!75G-|voXDt$-UFpcsdBAGk2hhEi6SD+aCh{2miT4 zQsBS`Y4X*Sp+5O)3UkLB0_Im!hG7a*4hl^9YRVws{A$YZ6x?13oL@~Dk)r)DV16~_ zkrcSZjx_md%A+Z82f+Ml%E%OW9AJJmWps*(?`n8ViYaCP1)lr3#<)*+xJcM|tO~H+ zrSX-Ege`VIOcM?8pF7D%^@_I!xT+d!c(Q`I0*FJ{PlLwqq)hSgtY3+2)9_RUvj}Hy z7yl?tzJD^!SCMmJT2)rp8MF!b&wbw4>OJcAY(Y#f^>c6c*-vSfnTmzQi5oAkf<|kU z+}S?4EN5BL^k}-*6++Ax2 z|7d^-PSua!f@-^;w3KTxs>5Fwdp-*=C zM905zvYFVv_KnqlV=`!Pr$@(CKkax)GkoK_tp7wEe?67&x5&4MKG~0aOW=gF`p$>< zarDU#$f}Y)LA+YWdivxLPFm@c!#+``J5IPrM{v?xpZtuI0s7=9WX9p-Ju>_lC{r}$ z7o5!3C#P`oiaz-rhOXBqr$KpJpZtZBt@`9VRKJ7Q0X`tr7knaZ7bq7{2UT~!|Gpu7 zX~Fs-ahcBd$n&~5e-Qsw_sa7jI9^HT2juzdI6h712j%&{IDQ@(R6Q=wYoaClB9E#k z9~fIPCGd1e3+9i#%5C1wKOL; zT*pbb_MCL@%gK$SIJxNsPHtJv$*pTS>A97X{8{@rncV|ZmY(@@=yjZ)`E&2jqGbLK ztVet1FF4063zuOM(ldWiWlk1H-lnscuHj@!l9Q#CIeDcHC$Bc+WLXDJmfyt5%DXsO z^&ls!M{u%cJSXd>a#t#G!65Yp80PbqqBy0aV0nGbB53E zF7pn7_q5{Vz5$%{8^_80&vVlMWlkR2$jN|jIC=OaCj)(3NPMu($@!^xQUIT^c;lgEDKWZW4}9vAPD>L-eDG9kgqr0Y0&vOg!2pXB7J zg`7-T$H~-foILwIC(oVZ_oyj02p$Z2ZaTt43ry>0fS?<#eS{jnmaeQ%=_!-8fxu^yTz* zV>qW9jLDpCH0E*oma&G@&Bj(vw-~!Qea|??=~m-1r`wGZA5eZfjB1>IWVGk>6XSMH zKQjh!`h_u()31yLobEE#a{7(2jnm!6Zcg_Y$2i?32pe zP7fG2aeC0`$LaURNKSt+p6B#OV+E&&jIEp=HooEXC*vrmM~q9H{%jQgkn%ZdWOI7V zsLSauMq5r#7(F>XX*|g3uf|wTe>0xr^pvrL)6>QVPR|%$aC+AGk<&koGn}3?0v}O6 ze;L8b39_93+@f@fB8cR66WNhH{KjR}#FB{)+Dty0jYWOa5 z>hl%*nDqL6S)2xZwK)y?uIJSB-O6d2ZxE*;-&34gzLz)+``+U;;@ib()OUo_bl*iz zi}+%nkp7~+a!7kNuUChY`aI}0Z*Y-D!shuM7;N$#CryuW((FG@nqU1Xv9zqrNvk%T zwC=-6o1vVvorI)hddHBs-NcXR+3NmfL}>NECQkZuX00CjlFtSl<>cY>oD2+qMx29k zIT_r7lOeZpGIR_l!{%`^{0&Y<9OdK@|K}w4Xo8cGEjbx=Hz%WqaWduwPR6e0I8lWyi@@(@m@OygwgdQP6*&dIc$oILkEC(}=J^1Sa$((*!4 zPG(i$WOfTq=G@51-2R-*dxVokPjj+l7AH$ra0MEB~dW?LAk0MajM8 zIk~S6C;hJH??xdt~ zDNdS{=cH+MPMS62qGMIZ$haucYI}BwzI}GCv)?xUQ%raszCy#9A zsq;9Qwvm(R-*EE$Nls>@?ItZVZBAaO&&jMVoXozLlR4u# znY)OSd2ewt{~JygoZ@6*Xb)*wRDqKh8*#F@Gbb;`p+zdFa-PuZitXa;wInJQ0^{^PM^HjFYfS7r9<-2WFlr< z2AFQUONi$n;<|p}))&S@_r4hw2l1b_J=E(dA31bGt)L30cjGjZerSd*db~YGT9D5c zTvH}pjKhDVF@MoQTY%H|VF6A>HE2<%nGgDWVtfuBbd(BwoskYNW#uq`>uUN}^u#-? zzIC+%-*Nim5IhTi;YZjr(&fuA*sH2e6QvqP(W3JmzG>j+{h7U7bK8j+<&tX-81)6)Th7teFFmuNb0OnHA z)&`{4{FSt@sT}`IrQrDIJru@I@y|2B;I8eY5MdNuavtw|IngClsMP3^XNfI&2bgsH zGYq#Fjgbn9&gW>EO-5Yli&+(dC1rF8sg%(rl!d8{EQ5;U z_-87cC;s_e$|c!7tgJ))Gw2qhvF)I-b%=l7s5ub-OdMa6TB&#C=ZLqBH@*>9zTE8ZAmSfYXeo zbehhmuHof_>nEYI=}oukLqhW7k(T-0Zn#R@{f6#!7DpoXzTv*<_B4)<&~=G7-Qa6> zKBzlns1lDB5I5s{NXMqV?wf8i#)JgF;e$8bI2+E8^Gc2$i{~R1p}!GlZgz(mBH8P) zkbcwc7#YW?-D_M(zv)IA{I1QMse03`@8gPV6o^eH%#z$+xf%t&0krN znoCji_%F|6jYRaFc(cr5U`?^R6cmib1LT=Pdho6+=raopQ4{q9m-=0-scVd{}znb_p`sXyWL?`@rxxt_jr_XUbueyQ1 z(1jaB#yg0{#wlHXG)?>p3e_nJ+Hx)m+Ql#uzswGa>T^P(i{Idneen!UPSX-yfj>{Q zn1?3f>j0f0IBED@84)i6oel8crLDp}!=$X9yI^d3bFL5SCZ6i~^F>t8dDY#h_q%cM(e~UKk@DGN8e{dvXOScR879d`D9e`s!4BYd9aE5^*^PFKIRou+p zPdeWF&K(AxS>z4_oDEBGUdi?^I>P_~W)GMllK#ccFmTF2?R`Kykjcx~WWQ@OXR3yQ z*Isgl0m`QkmmCJ3L2!f`1}I;3IdkrI-=)qlAZdINN?N0rone41OOeZa#Tf=9&6Uff zdgNiC>9UY$yhaWKcg|MB0M|;!d=x$2d38uMBsvWP4g+g)xzLbP7pjZ#BeaBi+3;ml zy4jU#FxFsZfnk7vD+~i8<`=p!*Fy_mn4wwf!lVOzVU`b8U!`&`vfRlzaR51Yyhu6M zE|@a`Y8coDi2{R8Wk_;v-Cj_+(Sgpb!1Y|QwIzPSKdyVy>gngz=c1pJBo71SgT*$G zk?7~qwN5|(gp6!{3H|&qjzsKbydlGHyP}^zjAPx;?|t3v=e@Of)JzpOiyR~!uYT|L z^B>o_{hYI53C=6oaJ|#d2{1dr43V4;G=ZB#pt-rnLG85HoPJIk{I1QMsp{vCX|7dl zSs^aj&o6>Y^>fNs^;gc_9{9S`&m~RvGP2A*4jO+W{s*=!MQ+p^PCqBB)eGUQGn49( z`+0vfz|oDepHs{TwTmpsgjvWSejjK@h)(_7VPFfm?wAYxd;uzzZ+Dx~5~`m+gGx8s zke#tk1$!F-SLo+HQj>bSn*%M}^LnpPJ&z7_&nq7^VIAlE5sIR64*h_fTl_~kw=I}6 z0ji(pyjdu>;*jLrRxek%(SgpbKtF%_{}?+D@F86_l>1p(7APAOsMkh|*N5h#eI*fQ2GTQF<>Duz`qTrzwb_fT;h^J9~Fo{Oa%d z^E`R^yfg2-^UiFWo!!~HDb4tTKlXF+>es(rUK*YZa>xYt zmaDnGxGt`e!Hclmazzp|Et3Z7TdqiQrX{Lxxm-0h)1tw><=Q*db>{|u3Rl&ta?^La zDT{k0_(T+7HLLH*6HP+=)`#96eEWG6Ea>mIw$S&09ANp%QWL2 z{%-$CKD^n9(S;st{3K%yG((Ryw8oL~CHHhHbdJw`SghZ`>!SCkbC_Std)^Iul=hny z&oHL)7iv*X?u;3>lJUY>o3eOM)OA(%7REw7m8X%#F_iHJ4N_a+ce`Z{_eOq zef%_CY+&sDaG5$G`WxMv$o-dH-Su+Q9cjjW{N3?g+8JJwYQl@FmU*cdxQAsy>XN1E zoDM5F?bk}Zn!zoTx-s=S#yX`M+?aYFV?CdkzA^Pe#s+Q#YNg)d*hslrsTVCaiI#fP zVzc;6y=t+Am-BB-y=zg5mm5ZOaXL`%JOu~(u_y>{`n-S?8^s)?~G@gBx%H?v8c1pOk$nnXe~67-uGTN4R`NYJlhe3(cm zAwj>3@p&TQBNFt>7`qb*f0Ll!#^5QWgwQ0PjjUhC*yARo-p43AdyLV?(;$w~+5FwH zJFy#0$k97vN_BU}q&lfjF7Fg$-12*-u#*?NDx&ql3&-+Ic4c+P2H*K3fq9H^@7Sy- zq|zpy&D53bs#!sZpkCwAsFYYCvGag)CKvJEM^Vb<_v}bK?{4U=Ot|BE~ z;T^FmqJ4%Zo=qgYyG`DL=Rf)T-$@=>?(J!^sCt>9+vL1Ay-oJj$S@l4_rFa}cu6+- z3@_T9d)1qGhP&>#S}X1f^tX6vvU?FN2%gb{uA15oWj)xY*IRCMasg6>CvlZqlTNuI zl(>iv)IFF|`{*7_suOYoa;|k%9i#3+DLSqk`*WM`65jV}?~U>Nop`@0ROb(U^~uxT zuS!%lAy<1(sjhcdl^LyKX2b5dCUm%k-{{u+Jil?v+ivX4#u|4t40UIF4mDKBHK*KzZFt z=9(rfNezJ`2N(j^&!<22_qOy6RC2CK8kraZucE|12HX`WsfWPQ4TG6zvIYKQ2>ctp zcy@CgWU?m{K{l5l|F5 zy`;|X2{n0sPt=h-zt=uUXvvrOs)&|2zyBa>R^ylCMT)(?=x%bDkQ zw}G7q>tPA);`9%$@H8-~rp7^%TSd0-nY(~{m6(8swc@2}!b|EZ;W|xtN#>@m64{4n zVA5$7(Gm@8yeZMZN`SY43kV}9PPK3g>jsLKGaKk$970{vj0gGq-!o-mQayR5JY!N_ z&#wR5BbkEUX~uK>ag3N#-Qi~97!kEf8sf|ja*xO%t1aV8{x~ALdIz^#!D@3g#!Ywv)p|{u@6#2_7CQsWu#Y9a#IxHK8 zxV058w~W8}V+8)q4W84+n(&Y)#YFsD+lp86Ws+68ZD$nQ>K5C7d$MhuU-dt?wwz^Y z#zXwklk)uAbG8w+%1?Lvvsia-lT~4xchiim{I%#9kY!jDYc8v)%G9R4Szy?rQy_7e zH|*z8{gW0A8+e93ci2$TI|t;a4BGl9y)o=zSC_{&clsxk8sBhjYSBF)OH?C#HZh%Vr-FHv%Bvi`S!h`F4}Qa{)?aEOJkw5->BKs7mZgz zkw-r@d--yD$VcbLVOw*RPu04J9J%h*T<_!ecg~exN~qa~=YPjY3rcx?51n}WUmN3L z{O(T8eu>ouC$$w72A2|)k$UOAW^Z5R+mptFeEybx9^+|a!Jrly5Wnh)l`7#U0Y-SO z4v5Q?sZse^tm=x@xc|#)HC6>Cy*9-s;UsF*kyZXKnfJ8UgPn}VsGR0cGZstX7yq|# z^<>_w|53OZ2C@#I<{WQfca1>rWZpcz05B1i?2GR2J4g&h<*8W7QiGcBC6*fK-jdi8 zOAQt#4LGPyB7G$Rkb$7SSCSTj^cKgW}WmR^{<{#bO@*1o=ipMY9 zZr4k*Q`TkO-?CTIa8J@Li?maQ|F#)Yk9m20Br1D(&Bs)&iqk3@d)X#6_j7Bjf5+h0 z3;4Z~eX7>IH-+7t1B#!AYLL_p%Fjb}q}{sIA^CZzrAh54`FW@-_*E30_p?&DwFdOh za<#)sHLP{>&xzWOD1K_I*07}0Ur>Fuu1Km!QO#O@V$_a~p^|-JGW(=b1+|(bwNpy% zRh6VcHBa-CG~d%0&n%OB`dYV``KKjVoapnvr?36Lo^kqmhVgu~#e`tu^mR^~-`Ryz z=cpDn1M1v@2guWqb-I%yjJKTP#%$6N1}ZII8$A2?UY7S!8< z^8m>USkBnuQrCl=D|GgMZjP2)l0|AKi&2zk+lCVqBm2^svIJ^ zlN%gT(znd~SRnhmYVnE`j-yWhU-qdOn0>mFqN>I1=6MeVxuN8*MN8A?)~CYroSAwtWEprM9Ro}6EPl>Y1tI9y`{w8=>AYOVWy+mbZ0@d|0 zDXhJ?>b<^6=aDmwDShqmN(vfnqD#F4`M>$W#Wt7f@qf{{GY0aaRuOS#Yuusr=dIHC za*Q5Y%UeR8p|z-0WLWxd#ZGicGkSHT@79F#IT5D%ZcX?})G8wWt=MDtrWw8h-Q{N# z+v*nkui6$;5%0Q5Z6f}ywhcUGx&AI)TUF%=a%))BDk9D-HcF4NuWz4b z{K?<{KC%dEFR4csqIw=#=nfNcrc=GW3p?LUKi`vPR6S31cW0vXYb2<;!~Uz~AJNB6 zJL#4WKC|Ugc@+`5wrYV8lSgIGWb}lQn}gb@fp6#Fmt#8kxOs*>TqNVhe)_lS{)p?V_1Dn zuB(%qE1hlxW@04Y6%4nOT$NTIYa_6pRQcv%xUD!&rXD0!K3^Da?@84skPJK+^-9zE z=8QZtOM8{J*1bG%{->c-gjbUO9})U_M=~h+?x-OZp`;su$rIc!A0{IV>(o=Ex)Dl2 zmFA{)nrI~=^rY%rQa8d{s|-5soqGHVU83Wj1a8KOx8okv zsl7>c!;*q3%}t$5s@rj%RQ&+J4Xa8OpHVMsfQS=*qh3KPe&280NW_nCBJxVoje2bw z@jcK?e(uQE?=N01Z_iW2X#UiTHvP#(LR~9r{&baAxQJ-=@6@?TPbZROdl}&$Q^lXQBGTPiO~+{kr&Os?IKZ_(UeceJ@d9Q@>_(jm8|?$Dy?OibDh*Wk))m1)k$p= zN$oH-0@En?H16`-bwc-Mh3AS-eg%e2-5+i3Lxsb5la{@r>9<6~5AZg+8)43zwE ztq%S<{I5SGS9cy%tFub0DOTa7qIJ=pr7do1t97J`=UQD;o^`IHJ@*WBY?o=|_PVlZ zSpVv((W`NS!o6-uP_$Po=mVOQ)9c;@RpR4__eK#m$4*S>tgZn9RaSa=Qsq2iT`XC5 zUSt@t_M*z?Yb?13vaXj5Q42*al$lKLXUn59+_|PI_n()X^&(%z2!*YIr1UOag|EUl z8NwHi5f7rqBQ9184p`B^ltag&)<1Ax+Ds^@jRg(xy)WY+wAY+7N2w6gw zCaI}VSMs9dN{g+R>LT6}Rj5#eUiQ9(k4OhEIBQ*yoito1_J!JBM4`lOeJh3ZM$~>k zWz!b^%>bkDv}A~CZMhOvt}umBPW&+;tD=x(SPxu9t~e+ZSJq{cA!(K+xz~y+RH(&M zcnNfRp6Lg$JDOI-EUuD-nn^*6DTZxCCrT!#oS*%#BaThg*b6)M!K zlqk%TG))gQK)pg#Axkm}{}z**B~7TWw(Hx7w0k8@sILf1<{>SaRkQ|@;S*tY`8Z@W zFIT~TFaPV4fO*OLK|_8JvmBp4E+(~<7bnVHnrprc?_!THcUhjf1pY$OYv-Gvz|tk< z>eLM!glB#dGRjqC8yZTVK!dU(Jt&`N4$ABLMxb6SY^>+6T;+cnRVJUkNsRVj@bMEt zqg<}XNX|IHNs?bz;x2aqpO%&)`lmr9&fpxnHYiaBB|Ibicm?W->vNbiSDPDw8Kmx# zoIEjgofv@=q+F3h>P1pEncAL|*VCx1hWjg_QlSwTM(PoyR>OJjn{B*>4YL(;{W6-19k5OxK`d90vNLw)@N0{n(7pK`~~G&Q3m>Qikkjx8q)J>kS|Xa-Hj%j zKn?cgtD?Tiya#=CRneGa-Vk3yW!TSB(b5;_mJKRPzGx(DsxO@LALPp6I7sE(hV(f- zk$z_k(sX7Z1I`j;(D?`%a`qy_&S_+tQ*j8NTyyFmBTiGK<=l(Ra0Viy&SYe!vlMAN z-ythFYA6>6rxNmPr#|u=rzNtI(+_#B^8_;2nTa-K(4ciutPa5f`rI$t3#b^^l;;}WMbGT&*6bewL;%bX{XwVgG{I?fNsE1bx1 zb~)!_WIg8&WPPU(@=9ks@+xNm@@i)*@*3w)WCN%A2*WtC>fjfC=T>ON4xs_i#BYRN zgyxPo1bqxmA1ibc+BaP&ccfvI&Jel*T2vy`2U@IY2DC)ehtN_@hoGJ7#V+=+VeHb> z0Qy{0H)yw}DbN?1-i7vP`U+aPP0E%VWf-e8)rMAUDu7BpliX3zEKRRNvo)1MCw`FJ zU!jwlvLE3Aq^7H(y+2EC0ra(|kxCnr1_#&r8}aXy+OsHJX-dss*jsB5CcQSsx3Hgy#Ms^d>ZF{Lj!fXy0TZ#Us4^ zny!KlXc`C|)HDZL^s?A}1})Zf8d{<$cPv{$QzPhoO`V__v!%q7&`X+@K`(3i8hS<3 z323IKv&R|6nE6toH8fV!qtG}_??dA?9fuy%RDHZ*Jg%t+v~#7Doeb^Lv;z8E(|%~T zCi^kAzNX8e6MLn^z0maGhoNy$=~F^Wq3xP}gO0o_X%{|DpRN;X0nI%wG#r}#r_cgu z_#;Q4Jy6MJA>R}1?H>tMhbC!i4o%TC1Um7#S(0`X+PO%`p3Iif)CgL!LelPsR%)6Ct}8V8MiO>*Ccj=U+f6Z%Ed zAJ9=vRj1MSnr?-TX&L|>*YrFz>Mbd|1bRf%KIlFF?CA zt%N?;v=`c~$v2(-UQ zTGNxzH=5pu=I;NM-2KozO&30c-KWP$YYcs(sU!5QriswB&m?y~G*#0sXuYP4XANV6 zrn=DFAH=Q&G*8q0&@(?u+SAapn$|$Wf0MK$(7r!~;?J>tA2}{%p+%1i4TVl@7Mcy6 z)U*Sdeo)eWf}Yl7K2IH*&Vgo3_?_Hqp`EV@-3^^uEA%+DcdO6>Xwit1&>m=IiIDjM zd$y*FA@@ph2jpH!20-qWWCkRk%VN+pQ|{1A`+PJoZ>a`qr!zbxNi!L`wI8f^u#BrS z3!L{*rE9D_((KxZ z`P>$$PHbg?T%T(1864l87#vHdse2e4CxcS=`l3bWq=($?THuSSq6^XV=(vL~M-^Sk zEssR6I{GSc7dni}^(~S$Lt>E|2kTHv0_q19z9VTu)-oZ$R3YnfA$>C^CWTrwX^zPp zsj{WyifRpSgDS6*6n2+1A*-*DWLVYOk}F;c#h*1^G9=AfB#n7SRG~sGZn=%LpKnE7 zAQ@WyKuD)$kXyJ#RH43-TPV4Ol55FkEIc5&4+6bNhZ>b?-HqA{y8(eE4@Zm*f%19g zzP;&sFD+k#o8S_DRfm`S%hwE>yWkqa7e~#)cP!&I;Y)JN{Yx!ly>P8uvvgCs@vU%v zo*CSnZnUffJNae|{zCZDx@Ha7cP@NcL-SKOPq=ndbI+D^<5S@}&CTaNOgD~HhA(ex z9)M?_2VYTO{slM5h3j@Vk8MjgItbV6V?J4$ZtNDWKhRtaJ5}H-hnsb`ryGw8Up2-Y z2iLg(zIvkh9K1*Pn(5}-@JZnYGtB6YbmNk$aKjSwD|nW0qq%0_qjaNVHTc>^=DYA@ z;l?Y>E$}mO____|U+}xaO-jvrAEz4?E`+b&X%2!13g58Td<#A#+;pFL3T~PQ-+08# z_$1w!Cw$Y1;>z#`!Z&mC`Z&r)QEmyV;>BbUK?x?GZd!lr|7^Ou+Rs7V>bYqk#Et{(1*(k-A zptNePiW}}qH>QZvx~(dH3FY=$C~XQ<@h+6@qO|Rma$Ta>$otKyR=eJ(|5KSmXI+s&RP%H0!H@e3&9E1)izB|;DEH1##obY+ zh*D6ZibtZ{SO=xUTva@3PrA`VlrD=@@hp^$qV!mSgD=yK%*#>wZ&1ZIq6`;hP^l{J zjqc6OX9k;Omz0KwXqqPN?E}O*v3R zdEM|8ue~i|G`kIDcGy>(*(_qTY=QD-)K`2N$~IBv=J<-|Hjfy)MR_OJS6p&?gp(1< zdwIU%Pv77pGNLTW_Z43{+cNT7qb#lKD}Eb=MZre-_Z#|(d%S5G=Zf+{Q(y7bb1b8& zD9f7riWi~u6J>c@U-9*L8z#z%0$=f)Eh5HvQC4^N6^B|zj7!>~tm)$`u8uNGl(hqW z#W$j?6=lP4UvW2-Bcf~^<0~G6a$1y46Me{x+W+lcY5D4%Tb6+eJ7my1;SPfLBp zs$Im`BFbkweZ`-l{CE$_=X-s{AKn=;Cf|#)d!MiP!n-0y^A0Fq9`P05fU;JUuTJ=i zkD{CsWv}5c?$$nHZ0(5hb=Y6r@$QH*r4!1bsK0n7N?K=>!#V!q_ffitawOMZyzd_R zO_X2r{KakWjTpf$D97^s#RE`AigLWJzj!Um3!?ni&|kb8rD9i<-<$f2f9Mb~E*IrQ zbAR#Y9V15L?kFeQV%9lgyei760)O$?E)gTY2g)Da{ly1STJ=OZ-N#?twQIyUDazji z{Y6Vq-sy#6sNw#iZ_#QNqWRSre^Izw#AqX$sV4f1;%Ea!3#jS-qGGhCMGLDL{-WXC zBSuzlw1_J47d?-*RWwV@^%wc>V>5}Cp%(dzVm%^8|NGIRYK6b(GPDz-WvUJSq9MH_ zeC-A;OO^VImZNR#i&jDH^cQ`P*0CR2j@s)lx}i_Rctfq9-s4rU8foK=1JhSKtw1%SPseH3&K3Z4NE>d;PqEFBs6Ro;xXciqun=V=n z)zmC1-#=n36RoCdZWc8_`%1KnRa>)Y3EDx?@>PLZ^fB7-L1>QZZWbLzdrq`VRUfk` zTof@%M7vB4G>fJTVEc(yo0qGK=A%737_E*PV;1c|dr!2>)kL%C2-<4Vu29p>qFakO zfrwUD%`l7BpiO)bt)40|i@rs>bqHF0HP&7!VoKZ@2^?KF!fpoNE_U9a|?_E*POLhZ)>SDh{aB#Pv^5!qbr;g^hFHpg zPWA9r3kXbCT|9RToV@gOy1rxR#vQ|$2|@Rcu{+c0(@^w1!hODphCLrw_e<3sP3t|_ zGnKDr@$HXD93=*wOlxP#KyGOa`!M<@$?I%d$Ii$Lnw2ElG^Cx4SSVJbh*n^_8s>?X zov19@5k&h8Ci+%&B+<@7(Kovf`*IAsK)f>QR9#G~3+zTK!32vW%NmTdA4U8u6^`SM zN?`6;>QPUPY~-@X4P&VB2W%EoNR8!r^ZoMSVSNKP<18b(9p&O&?uf69zQ!$O4Z&*m zK2oC+M_1GO3HHPx_nqzwymmRp!_~y9n`xDYJy!DABVkpWoKmssZd&!uw7Ly7xDLS& zLLy^r5q4+9Lb0DH-3jEV$2^UD+}pS(Xj~&qrcp*spmFxgP>GcOP~9wd`@*K$q?}tM z(dmQqITMlYyoI$Hdp#GhR`R>q-=KfSSYO>|T0g>`Hi>EQG{Ue{WdhAWtP#^!*$e{t zNJ*h!Cd}q(FE3G#1mi!%;mJyVS|_o1Oa^6x|C!4UHEtrYsy z-5kQEDpk%e;?y}C)#o%uj#((v{0~4!7Rwa(yHH{i^~Q%i7%@z0-{U$GHq}n$9K}#M z^Uje&S!TkPimP0om5)jEN<^p+GdqP=Lol;0Y~K!@5UXCM z)f#pK6nn!iME=Zeq$)J6zGvily7@6NwI(6$=MlTa{s*^CAG#EuLF!0o3*&gVmfM< zDC^{ap8_?K0;?z>5LF-e;=5V;wnJ=|QDDr}O0Ke;1EMM~y6Bu01XB9V*{-tEXBlVJ z;jK~Aw7;iZGx0bdj{=r@%j5BFugAGwkMlUhtV;Av^g_gFanakV31$w3?W>^=B=LUJ zx)%2Is&q!M4Qc#7Ez<6em?x$m5rRNimHOgS7ew7?w-dr_Qgu6aaGcstQ{Ymj3K-y7 zFTft(3s4hVY!Mjy0AX)LR22K&R3Ok$ed5_-pHe~Uf%Ru})S+czBb#XmwUaIOD^*t) zWf!NeFopHz``njnL~}_#Ac5a+RRc4>g7xWDNoDuhjYu3N_<(6$54&+np9QrjAT2lo zVMOIK`8SDakLUofibYyu{q{<(U=8b0Qtioz{$lkF4H2lT_IMidWuhT^sPGjHxgC@3 zlu>(WNOgw7I`*%VN9?`gs=CkKkI6LQzNYmvToxx^5v|HeRPy?nRyyqF>5H_!M94YQ z9sOKHE;Dv=W~mRRGiRgvn^uE=DWuPy?X>+pNV^B(kW{jtb_wLD?>z1L-rKGpXxC;; z#E1Hkc72VaPw4yPkXneVT~c+CX)S^O8Sg(%++SkC`#(tgFk+>YJVp=#dFr4ih(q2W zej`|L!f9WgK4!J@ zr>~|yX0`H{FF)QXY4*3TcDyjD82-BP;-sSdSGgCG^GH#b`t(Jmk#Jp~^$3+mCn9D_ zLLci%FmoDgzXq+7#DS(Y2X^~S>sco~z2YOrbL!DW>PuSV4e2Je4?u^SL}3q%F6x2QlMs?t0a zq$euS8zCYUjG{n4De$0ajfFiGJdJ8tFCb&DAndmhcZ#WvZ-E?D&g1(mukWZo9Dn(S zO2*feQJMazdje`ErF+^ZNGuT?Vp@N~o;ow~q)r<#=9*))eK zP@5@gHIn;3*yG!*F22){v2qBzBBGj@Ho&()o~rBdUC-;gKFwQ9^}2ai(!8}OGRjp~ z(Y()5^hx4sf2H^&KKalO*XkPDY7La?h9azyLZcD(6hv4mzMP5$a+Tw$_)>4hmr?Qe zxZgn;Rhx=sou6EHRULm~$a;iq)x>8Xz+|zweb}@P!=9#>ufa}HBtpV;uXJlr4J!v3 zI~QSJglH_qZy+jxJk`h()wSNJ8WUCO@^u|irTV4`-H{6Mdg+0|;`~uWe{p^*&INMR zjUMMWC7kPB>1Ld_#AFd=)Gcxt$iTdll)lAhZ4`H(Am&TLUAPlys9Jm6weh-Zi@VgQ zp&hXf$3BaP7V1uaO~cNG=7_77xDtq}X8!mnKo8ZLDPdya$SIa4&y>VP8seeNxn6_ohtPRQr@OS(@a$jr2L2 zkbY+$(sXhI}^B5zL&peGhlr5^Ja(-WIfbmIqdfPRA#<3XDm z?=QQN=tB+1NYzdskhAUG6nIub8gE)1Vb3Y2FREb` zBV$7l_87!aF&%+#fm}7j6a7$c^bZkzM@)3U!-&2w%6c5|z#@mY*u|;rP4*t>BXRne zX?+8G>eq+S@1z;lX`~(IS>j?b9ZmfLIqG3g{d`)zY|8HuZ|^-SXQ1mTeJ76^)#Ijh zGwi9T05!M}VOU*|u^tF}0OB{P?FniV$W>!KwT<((c09GEZq^>7wW*u6$ECGA$2078 zh$d41Q}`3eS<3re0Z>|H=j+!qtB<$dE`@sxPunU#pA0Z)q6 zY;Qbs2qD!!Z}@Y|`sYo5o?+iifmfuGSE)oGtX}q)&0FxPz_NLZnSO5Zhfv^GDKOEr zM!^4Uz%sh4zI^t_FeFxtHIXp-!+raa@4VX^@Qd@3;?4I9Kx&zO<)g;q80DCGr zg=$!TBV*=eR1`%t6Vnw`B#^6?dMbK9QBgm+gZhAqEKKxqxQw2vg3=5JYPsy0EumOD zaoPoOwK!djQ-P>@*B`$Oki%5Hhtt$fy+}?R({3KODY=fS1aj0WPyDOB@vkBN)RDDTI;vc4CQ*3euck2n4SVXn6xCC&zV2FAkQloP zVK+sbkb1XLuRt!(FUvO2MsK~FsP_X*^oepa{k8#RG!E33ZN zKkNx;F>0_JFCgBt{Ku(u(u68nz{Lm*de^Mq0A4P(2v`8x)GS?jIyLAM!Y(?XY%W>{Auqt_!&NR4aj z2ju_UtQBT*u}IcR!<4Bv8NFt$3Y(kAm#0NptE1-ENnVp^Ywy9txf+@@;lOkClN;UFmgJUvFog3VCHz(`U{Gt@%G8PlGDU0 z2WGwkM=L{N-c!l?)w%%uXGnEPGpwtT(WZ!f6v_Izen9@u&Dvkq0|z`kaM05Ohde#- z6Zb1m;G{Ee!l<;MH3jzUIAwEM^T`PALva6x+(UTkctAfJ5;oP5fKy8nodTrKnT+&1 zi;#)&*H4tPPa>L2ReuMn1qAZdZ-KG{_Vo`bS+i8xqpz&lDyrwv?#Dsa9F-Ga zM2j92m169C)a4jx`guM7bkPN zhUzl^PbE|E61&r;)&|>vUfF%||My4bta~MEafAk*2d28E_6EgO2@8IxDp5 zAj3{OWSTPqneM!bj5r@6E$3HchI8(>>8u27ggndXfs8uSkeSYEr0x8UEblnq(VI>o zGTV6_8FTg^D>ymda~*VUN1p9GhOFqUMV{lFLRNCB|B%jFu6D@E&S>O$&YQ?w=WFEo z&RIXE8&#ZZkQX>zkX4=W$ZF0)WZd}*d7+cOj}e|z4|$Q(6ItDP3R%NhfvoB5LtgBh zwVziVoqS|1=N@FfGY&cTsH{C%0d4qF-jqK8ZPZl$0Jr$hN$xGs^keeI{}AYDO>aVb z_sL_$&!KNMMGvMM-)XuL`d(9i=m$+Rp`SGEhJMzRd5DK*dR@(R&@Y+>K&4|Omf6sD zO?#jnnkxL1ZhWMv0rat^{*b$h=OyT*Ue8ksoznCh^oOP@Kc^d~HMNEQ)HDkEOVbkQ zZ%scz!@ricRX@yQRK233E99>2D1pZ5w9laNn$A0donC{~0&-U^je*=%OUog5jm2qb z-*9PL)nC$${hA7(1Dald4r*Eh?bWLz{(#)I6E%+Vqij0uPRLz5F$wxkr+or_uPNtO zVtGTh+wIWKWwI{m322w5mC)y!PC&agRXfJZx|&)+?&_v-&`Q0|X&JOi(;>)RYg6TT zx-mkpy15P7_o(a}gP;vRNo^(2-tUFJfxgyc|AyyxWM##z&`M21A$QHya%kVPvLf&x zv|m%X-_wmB^4#}({v?8DWbbSY zt=K3u7+R@m4pg#T()L2LG-dxqEW0G_c4)&9p@Goc6GAf~cfH#YXwi$Z-KzY}+bx>z zhDtt^v?x?iEE_3FCwe7u6ESJxFl`yP{h{0(ToreB}~n)3V+qjaj|_Jn54 z6q*DbSs=6m`bEKZm&0VQm^2f z2A$Hh9Qs4kuh8Caq{MkaV%BTrdPDA7xwoN3Ps{4HqtIeabwZKEs<{!+SiOF3D|BS8 z*p&+ty{5KM$p%S#5OUYbt$@DPtL9EY-)OotEnL5HG|w2Ck8|A3bZ+py8>-DG)J#R3uf@Dsiu06yDF_4bmC(<4?P79KP|Kg z8lmYlG*VO5auMTUP4_^fG);r{JuGY1K7{sbik!vXq^TKnP}AekAx+z$pER9>O2&&!({yOOrgx#oG<^v@u1Qsl7*A-r2AZI0 z7&KAS8fcOx;~ch!ruxuSO+BF_Go`k7pk+kzJAU;iPpnbo>w9pP{yQcK2 z^oFMT&_|jcfIimr3iOGlZ=gk^PEfX5HCptTP$y{2RH2ukv6}WmN1m0moH#97Ak-9^ zxK!vdXp*KK&}2>77t)R$lG_&A_lwYr(0)xnLkBcnmPZ77C1+n~%p_UKIS<;fP3QV#dpc#*z61(c`38Z^v3u<$h{USnJqLD+OScm6xyii7_>>#MfqG^ zG_{4cXnG9Vs_8>$#_-dW&2{kix=>eWmZrBLcl>++az~6cE~S-vM0O|Sj=d*C?$~=X ztR8pX47qneV<7hq=sn2213Cz~cR=yWBZ)hp0?54sdJ1yyfVM*JxV_vJ9IJX{ z-UM>T?ZY8=+&&L-$L-%k?zp{j-AH2G-Wqbp?PDN!JiZQc$K$6UceH+SJ&sU4TDlK% z@AzJW+u`?mbg>1A0T>^)`mw``5s zJ9i-+XCN~1vggN4YRp584GieleP;4bvvc_1m$wOq=Xa=CotlB)NV&b|=#&vV2=lsN5B*X;=l!`oy{*><19T zuA}b9saqgF_Gl>HqY--*^P{oR)ZHItlN1<3-N&zG5yvekW2rm0al{xT$~fx25@nhw zybWZAJXrni-B_q(r{X79*hh)Gmwc5&dgs@U@WI|((U!v=?}*UK`sj}Ooj?bry~V%FPjhp-vz?sIO(vEdBV za)y@ckjnW9nTS`aD3G$lLzc|BS!Xdh7_EqSxhbj7Wyv?<1kG4c_5uuz>}5!my&37t z{uJrY{uXIwA4LYTjV2LeSav1kL)rC_L$liFvv)yLzmv41 z(E5*svTleNqo)a72F-Xv=r*YI>G9AgX!=N@7oly>jf0jzdrv+BeF^P*MJPi1-B@Zs zZY<5A{@GoTf$YIZJ9`2$(W`ge<};Sx#*FGFWfj1lY1qN2!TK!_?lkN$^w=nbJrOZM z3N2w8R-j?lJkK=jeD5^u0`D~JJBevne>3J+7kZ~*-(?#12f~tB{;c?byPSjUKM4T<5O|axH%5S zg&Q){&57&}!i^mdSgXbD288`FVhDDzha_AeFIMaccc3@iL5XlL7N3I&w;A^Oy!9aA z79^D+gxeFPo|p{{=ekv2PD<>LfOU3x?}ri85c@uV`9GoX1>!oicFtayc_GL6&WMM>qUP^I|g zNo6|c#%q$w)1j*I=1JulPSQP+%Cn)G@uH;i924E6lFIX;+VLlo$_t^o@t2ayi=nIH zbCSx8P{a6pN#&)`b@5e6<>gS*cxh63C3H*to1`)`)I5GNsk|C$8PB>o(YV(_ZQ~au zmDfY<;|-EZNvI&+CaKH{b&d~6Dzih~;}ep~oKUa$yGiAZP@i~dQh77fKYlc+ycHT4 zkKU4~^zG1)cV6F-_%R)sdi)7d}uZn-+NC4NCtSraOa z*H0>ILm$WQNGj_>JKdE;i`X|~jjRUj($Sj`?_v?V-f9MB&VlU$DAJ4*%4TJCfxRa| zRQIW*H4Kc6Lf8`#2Pl}en)9DPZq_o-`ER-R{I|k;{#(iUZ#VXG{mNRUc$g^9E-#j< zwL_~#A~r@FKns@g3b{CJOA^4vWJx^M2 zXHpo}%b@)hVwe2;5 z4a?t(Z4gG-S%?x=_N(PQa1_W>i#-nyK=%wUkj`(yu2`wu|x={Tih39#QrNbK`YUWT>dV4l?wW zEBLi^yP6f$+*Np9(B6-Ed8zy(w!g5v{}mMXL2(-l6RaL~^8FVuW+Uv%2p``RRojVJ zps8B#iFkuI;*CW7XmWdRBI1cjWit^sYh20Q6SffX^W^Bq=Uan$apPIjc!7G!7&!9no2OR!foYHk6jfpMV#LlvMz!%hoac^A=Q%9_93eQ>^Xt8L`^JEYX`>eLD)SIUy7G@ zgeXu~anqT6Nk+*{XDURw>0FD6RIlWwa|?=I*TqdI>z_!jDplVdvX;PZ)naVe+mVeW z@4b-qX(~^5zJBLZ3)%Nw(+*;~C}fB4^cf?C7l*72*wdP_Vsaui?90fWDW*$8R^9(H zmG?Ug`yR44is{mj)#<-X^)fkW9PhtiGrtw~;jlI3O#2elM4!G1#^xjJWr)Yb{wRGa z&`=%n^yyFDKK+?K-A^p(chRSZ>C;EBuP@3GhLWj$;Fl2Vv|=Rp5WfdQ`a&pdsvkqn zQE7~GHmc8Qgmlk@dI7rrI2-TK-9g#rtuadrTWw%ZPxe9$eu&^>(#Y5Vggp}Roz!)T zHV8CS$2@H~?rp1+OQLQyq(82bTXA4Oz}eOIa$$Wa|URd-BO-A~@|>_pWK=?n)SsxwuOM(H3* zmoV!PuZD(7U)2fg-9*?_PS|N8iB4;z&*_d#Trdl<|68)!x%R@QY87^-0){gm={`2v z3nd0G&rrsG4bebizBp{nfir8O*zZFHJB&U_>he3m$0h}a^|`{7(5Pu=fX z2-^qespI(poUg@1zh2!p%)$LDrMI`E^!H)w1YFi_!Hj$98h0(Y4aO=U>m@K(1Qi36MsA+Ay{HEyGH>ZQigu%%yWtk{95w&Th=53*|@#)`kq z_!G!c8^UF4_xbtP_()RqLjFx*hEwe+aQ{2{{G{brjX^%$u#q_GQ zY5{>9RX45dd{{5db3Uw}7LI>SMT;q;u1uq)a=&pvBCDNdZzr{pcxs(ku zxR0Y6mV7(K4t8X1wiLQM&5FSPER;(c%f6AegV-XbHxsEqu4>|m^m=ckHxTK)nCMN{ zG%Xr`AgSD#mK7g?G8Av>rZo1qk>dObLGp-lYcGN16t6F$!ZRxGGmA6T)y-jLE zlgd-LIo?!TX;Lf5?tr*ZoZpUffqZqV$N6nu=gn|l854cNXf9j!MM}57o6;p|)=b!K zMcFIZWp4%RPn2xHgztYM?Oli_Qu3)ZeQgpp)uc4%VF|{01?h9PA^pzpNYkl;LE^NN z-I*gt%C1SXD#C89vfMgY9hLR3$XIQJ-4HQCOjpr7fv8&UY2FHN^H!$ua_$2ZcvlLn zO|u5T9^a3m8kTnZ6!^_OSk;bL&!w!&+AVvO`!4uWU1$Z;-h$X5g|1B3O%^s)?R2M9 z>T`}Eea^Wg@4R5r9hpCRRQ+wI5km&-4MK$ii};3u&+g= zi~WG~Y5{?$>X%-2==SF|(bTxUD4hXNFDW$;agCI!nQje*GxJdFC!ju(dU?c}0=sof z0mGh+TrPQ6M69>Z$P2DP4gM`w)<$IPLxlY~VuIK|NL&I@HP92+Aa7iQB`&iorJ{%h zQmR(El?`XUieks1Pb9T&#HsUl+q_a4MD)qVJ+4N}KR}eAQ;Xpl?o)gbPDHY}U^xSwkJO#UHXmg=m>`DT6cdCHr3VXPOc<6Es;KF0@ClSMJBgDp5BolrxBz;L-lxi*$v|p z1ev;QP9Vr^OmvVF3G#fDM1`u{8;yEcgo}vQzYP6^57>cG=2#-y#6rYHR9$Sq|XSr}Q zN`Ksu()A-&OSo(Y4t7R0tox955#oKZ>g{eAVN-QacTVBVaL$n|ry=T6jHR1}fUrKufa@2dCeQpu$NgbYx*_^*p zRe5}6Ym?%R@k6Q{9rDtvbmQzBp24--PsK7b5-H(~xHNN~AuqWS@ZC z$gR%!vil&Gi^GM4Bao}!_JlJx5sseEnnyS-G0}V1eD0E18 ziu0|A*(9qsaW0UrO47?(Gz;hQ8`M@0O3h9;@KrfzuccsASh?Nd|j@pW- zjDL}_st7wD(L_ui!M8xJ8t(Bu!W-U5!t-OI`}5%luTG%cj{`L-LVxxbr-Q`lBZ#;- zeF&!lQT1RXeonIJ5S(`0%P0D!=uiT--jr2Prv zPO;xW(*$zWYERSFcz1xcH0@eUWR_2@VKZB+{hTH*MU)Haeb>MDy~eF8dHN?&N{5uC88 zF0h;u%#>4#^f@PxiBsx(QsrtyH!1X8#M%I7-hpE8f}WDphL-gu>;^6cnEyhamb^xm zb?S_~VEX;ip0kklIf(DY>I#}7kgxJRO>w+Uxs;})rZ6tEqVa{;>$7QXD<{4JMIQup ztlW4hifngvxy5;QIF&?uP{|<6dIa|LZ`r1OkqpC{iL~b;l-NJu_K>itx>-)e`{dGj zIZ`>zkv``>B)^x0G@a*>0cRmH=xjoUoF9;hORCw22ZiEuuw|veo*2$XHDbEv>fnIh zSS_%uS}7};Z3;FJE9*L>-5k+DtX`+n1p25aJ)Jf!(P{eJ^Aw%dn0j^BOsCUYCzYqI ztavw+x)0FWXXwEJD7w?0r3Xi#TrD}zS$So*@XuTMWw-DzSheGS6w(WQF?-Rf8;=l* zR%TcY<7cDj6^k!fP2(4!gv9J+t9iUJN`FyavD%hRG|aRL$|f3KwL0sGhBadL8b4uZ z$?ckTEdklLAr4WkYT?fB2%GAPu=4~V^D-4uIUgW>&R!%dV0y~d$wda7tB^tGUS!A_ zjto1mBGa5T$aH5fGUAxMI0-p%WQKDKvYgWkd6qL48Fl6$Go8&y+c}IZ?_>}_mXn9f zc5Xq&oZiR^&QxTM^A7TCXFD=+JjuY)vS^r{gSec|P*d2B0%7%pr5E$Jk#_S_t$H!P zRwi0L{SiW~OtMV<5kjp@wt_~qBL$jWA2y;_M+?DQ1>@V-eAXaR>_-r-rLxv$ zwSYiW-ENkBIp7Y{^W}gRrss=?EltlC4_ldxfu&me6U1WiS2x4@9QN$chf#yK_mlng z7#KT=umkAh#Qv;|Y5{?UDlMbzq?MlGIcY^QJWr3T49^sNMuz9Kvd;s#1}b+JN7z1gHzZdY#Q~! zrhbO?0qpTqcHa1m48!^YY41Z+7kibV&#c0xI$=4-@NYP0-%plvHIjF{k)|^i8F1b~ z2A$o=kQ1ax;*4>5f3BV4?aB=6O4w6-bJRo!w*q5#BJ8e+o?>5t77664Oiu^f-VQEL z2g@K_!d6*yaHrZC?mS|4MpoGe&0-l`otEKuhxolJ!&(h{;*jFOounDo9;Ce=u~O&dU zLfEZa3NZhHRDH?&B*WUC%F}WEfEuhnK;k+G#*QHD(}-uq*GI%9kfXMF;wtsVwVf`J z)x($IL+!}mS}hOShe+v#8CC;Q?VAx_OTv2G3CvKdGU5vXJw9EHJNb2Gee=2|;clF` zTg!p-z*|xG8$;_da$Vo+#nqb`_RE+wlvaJ3VZ9D}di#CU#B}{iFt!e1??6-)`>li_ zkfSzwTD8gBs?CIv3UG_GDq8F_Ztq8FUpXrq_S9A#HJCO~`mh!ltBtT5iV%CFT(y8e zUG=-CwiAik`pMIzlZi$zpo}`jZq=9QmW%QSJ#Yd=UkOiVRML~;$0g^_jNG`1Tb=V) zMxLHK|66kY&d7H=s=YM!XokI+)E|X^aSw4}Qyt21h5?52tYkU!k$j#BnKlX|RjkX;ecP+GPx!}@=my$PI+)gM3poVkmcam?JAG_EZ(6B;50iLq8hWea7A zsFbB1qoK&Y7BP*B(|`JB&LpXWaJxz#{t)CH4SAJmg;AD0{Ih{Ixn!YYh7rdDO%?&uS z2;>H$0%>|=JnDWy@lK}H^Bz&bw9J(d|3bPrR!c@c_H#NU8!CJ|O$(_%YBw=`>q z=$>Y#N-x-`>(jicax1M{rs*MccMpn{6x2`CV?bv-1SWG9sCOw{o~BDdo7~dC=zgSb zMVjD}?gsr>TIP0Wi*c=@R;KAUqBhcy&%g#Jj%Gu?0-1FXMdncyR}g;_8bTsZ^|Tt& z%Wg<-G^8@>VFc>Nw2&+S(yBgb;hGmg(;VJa-?VJJ{{>V{`fZUW`wMBDeA4pk0p{f2 z#BlScqdY0!X?g{e`Q5fNpuC|t4L&kUQH-La{4_lubjHnKGS`6GKwX$PA9b$K-@gLRLuRsj*g8#@SgJ zkF2BsA~(GzAS)MuX$uExVj4Dw>p1th?UJlwcTKe`mu)zjn*@|r-v$mtid>h4Z z;_pH$NOVzytyT=NTX6?kaT2d$WD3=tXvHAlIgOQzzKz~_8JdA;R86wEM62&@J+aOK12c7W{n9N?FzMyn{n!X9N37!VH|A(^jDCizf)1%{b!3PM? zB`CAzqR3o^;tbu4Mw>{qSHrC~jj-EvH`)}9{2sI^de3Mi+7!JlGYV~rHsjtjypT39 zF3IW1c*5yA6||LTSzzR|mFiG9x)#dJOHs5Y{wRVX5mtw-ppJM!$ywrO1T}P1$Xs9l z!qs3ntUsi6#dJLiv{jotYEuju-hYBJ^HCIA2|b01NDNcISrr|#EBYN3MPI>x9IYP> zynHzJM_PILz|cP)-TP-+&zcWI!-lC7Y5iqVhp0K3HprY-r?SRx(qxBUN&5S=%se34 z-wV1@x~>b_3i=AL!3R({x*f`_4k$8vqWGP*$>}u$B*My{9$PR2>1M%{6a~}G2bvOJ znRML7Dxr%-C>pTJB)A}vtxj8wKVvukZ!}&5BCYxdjn9rSPI`H{dBjgUl}g8<@fiH} zr{5dX^$E~cQ_OQw1k4~{VtQuwgd}G*=}GCj251Y+Q%#WXaK-!YpxH&#FsCXiXrp~!p{MGfM|BTXclsC%tU zkM=S>oF|Ym$aE?oav&R<9;$gB82Pku95cfkQT^y@b$VvSiAm0O(mT`j1)!~lUjo+A z4N+#cLa~IXr_*&C&>5q^WL^*I2&HeO>)xP^Ee-JbAIe!{pxc$M?}^g|?;}9ZM42@k zMdo4@g9&{leMEpnSg9ARrfsvE_9B{A8JI6%q+Uu7-F+hsdVzU4J%pc`_!06ZbhZV~ zNMJNPmoDc{`JIaA(-BEJkYVgts9ATp}<82BWwxs0^FWdZ>Q@kqj*`N zdxG^IQ|t>e>lPH5Ls1-||2Gi?3AAX3)uLDJ7QKcReFhBkrd~&9MVt2qJL?7b>d3m^ zN!PD{wqkt`Ebf1!%#twKA43U!H$C%LNS`1*IHdoGnn}oICnIEYZ5#rbbv}yB92B#O zuN|rpAc40pg<=yqFJzs3YK3q!xho7RjDx|DknRE68aTWj4&DhFo_|A`ISvJG=;Bqg z@J%9Hb+>$9@A;NR;)YOi%^j#-W_XWKsOH`X(=$}QX5Up+oww+%R|t2O-=*`A}Tri#d=)PSLucpB@Fd&hv+F3V| z+S@mguJ+^glYhY=eF6-UGqf}9>|oA^%+ZxlX4XXEBlN#W0g13W6p~=Bg+~2|6fl?> zWPS?a=+*<&*9_)+7?9BF8+<<_@*5uC!XWw^9tT6#9j)&;66eACIIR!BnuJ#SL$M#r z_yX3^AIta>*1rHE$HuQ{{UNMdGuV_2y$^I^l8-><=-*Ig{*9t8p~p}WiEMSm>e`>} zuKfjF8{J}$qHCjD?5~)B{CtM5M2#&o^cc`qa5KR=dN#_ec_=cMqsS(-Ir2jSPljd0*59UfehQEu z-lX{uHmX^Mcjb8oRjY;>ng50KQF`j0p^t*LDwW9>n9iD0QD$bLm`P|?R7xUSb+9V! zXjj?^mEH=7w7WApJjNkO-?=tq=y-A>4)#wg4h?;C6(tE5Z!Sz$Mv1xVn_JKAxd}1Z`?f`1nj- zq?(yNBgvUY=!Ohk9<-IC>R@sHN11gAip&BO0|{M*07-<^Vk^KUc7TsEN0Hl@OW84_ zV7;E!Ph{wEpsk9E!8%&%cobym6reU{=*Qwwa;dOIpf91!d<(^0gsww4B=Xb>E1bvd za8@Fm_fUE60~jZ(kS{eEzg9|Sbw;>m9~et#uF0rU^L8+j*0mYg=62J5Mm;YhvjF%e ztZ;6IY*VEDsyHLR9Gp4%Em5lcB9uw_Yf<|0KSAlw4+7?0@Av74-%1{sk%S+*hOaDA zdIl*f^yL017LXN6fptl_l<7@WP^K5(gkn2cQm(L-@jJ^!ELhR z(%a~zwu9n@Tc9`%g&Ud)Eh$}z6czflTT#>^E7TQWT~aP(`U)y2(^Uz+jw~rxSk_U* z!j(d58$pP$Gj4`r3R$6wNu7qPLjG)^e6Ik%N=<>gma2;efFi3&Y05NhLi|pA+v<)} z;Q?1Ptj1-#$9A~O2O41fslsrZE%<+2a;bJ`7jB#43%!*=z2l6ZaC)f0js>UO#+A!C z1MwHmy$#TD*YDL1V-8=K;@g)SriJ57RQ{VX%He6Q@U{M&GUads5KbpK{>GrolAe-0 z@>OZ$c1fojfM zw>wVGCddCo6yEEku{R4e@ACEK8Fyxd!rL>c&_)C-n)4 ze!mmq@s_6`zl0b}=grR43-PtEKMDbu-~r@>Ke#7#L!oPf-)hU5Xz85Pr4TQoc#9$eioHfQPk zLH8H+v(BwAx5w|S#$Qh9x%JONcisEY&p)^RR_IbcfPPV;Ucxm&RtMl6f|mUY=tltR z;yZddYXoFkpYUb4CLB{ak9(=vi?QGYnt$kb9#OE{Afv_DiK?uipA?BRN%e!RvBaB; z*OeqWCpT7gDt4Z%0(lj$_P2$L7a^>8Emn%1AY`S$n^8XmeI1mc)*(K#)|q6UetZxX zgF{ed3B^L+J{YQ`**J`BsNz(-5{~OvY$1-%hp=KR+c7>|y$f*nVra62lA_-b_!+^1 zluOF(Lk+t` z>Z@q{6e*Fh(7zR;c%3p*t`ub5eUzmPgEo(fAIP>M_*YUQV-X6LCOLH~I8Ju|PzK1_ zB>RP`fUE?vT1WYnwp5Z8+&YkE9T|!s`E#6l$v`-6O_@+EG}jKdJ7q$#&`TzuSUwSj z3q=wO{})vpr+!Xr-zWHgJ-W%6qAtNt;&C|T3`$O#qE5VC)oF{Vlrva^n^)C*w>W1= z2;Ae~cxjw-M;P35;O-&v&TMeMgX0v;ar2Uzu$G)FRLU&QNqRG{S0P&Fsgqpo0wAtc z`1L`>xCH408bDe!prVu0kw(Ve33Q>9_|9?{$-|C;q~x1&PR@078^NxDbjY`mc4IJ} zbgFt6;u`C#Iyu*)$|SqWBhaLCLFr+p6hn5VsxU;CQQQj#KFeULY60<>QPuE83#j~Y zs=idwsxMRlOLhH3NM+sX$7+(2Lcy3e7+b#if zH^}y%8STj%=J_+nn6DYE#e-F*vpxMHgzx>XT$|Ww-+y{F z{hr!-!$BP-RZQv>Dbcbh5-M#zWREd=YF(iS)-)>;vn-r~bYtLj_lH3xFTis69#$}Y z4P_hGgSzE$6hhrZe?rxS!fgxIEuxH+9!rV}z2gaJ@5GFBXH!N>FC;~U-n9|MI#l_>7A^~YC$+*Jr)&&aQiW{CG_@72cJ!d9 zp<>EhCQmOTh%$ZGGbo-UOUjibzf6{tOG+Q5t!RnU`>CZ&??&tNf60<^g*`=f&a+Tt zqHsyMlT!sh~`M zN2f((Nx4!CS`OL0TTw`_&!$#bjs&+du2O)X{m@t09dB}>W`_PLipEuic; zslT_Qc`NBoIa0?UV^iu)c&A!cw8Xq?R&WkC7fBOUf1Y!?|$9!eyb$E`nCr zMe`u5M3z(`+Yy_HJvZP#LA0gZ6KTtgMCS+vw6O;+tnyDqFGpMCP@1~Zl9`Oc>&&ZN;h5eE2s<)tc zc_(CK^%=^9WuaS8L7C243_#Djzg3>J9 z*ID$Kjn3^{3hG;GNoiieyT6egN$NDIDWrn9oX>h1lz#YK6r5AK5@o`2#<{h~(m|1U zVWBB=ub^V$3@BK**O9&90Z>zCLMGI0l#y-hABrox*16C6k9WljFW$pJ>TAdUR2#qZ z;3^!j4(2tXKKFT*@-#1*4Y$>B!RILooE&PdA#-2Y0X|Mu9+&-B^uNH#ebJnu-=slm zKBT;3ko$@UjvmjvI|l0j;2ne9S3Q8-F?ee!jWclR&pQUWZ&*4fwHrjdW01Sk5(kaR z8pwIaAa}Q=b5f5%bjMu~zpGLhSWs%&Eg?2v=y!(VFZV;wBpRX<7z6ot)P4NzTDDhg z-_;7iy|UBqT!eS?{ZfX-j~HBLUwV5}Q`4|eZwC_X)gq8lIu{*NC? zcADhQ@gM4jU--Np9X;Ri9|O&|-{d|V_6NG-(^BmCxeMwyuL!y`{&MHO3|q-#kUFOc zz2q+PrMw$2zh*DwBE%&uEA39}*)HF&BlYWj$1wss!OHyxMHVT2m=qQI>pxKZMOLW( zU|mu!WxD(_C@9m-2)>XkDOXrlSH!}Vg00n85hCoG-=VmkEGgZOl%$3bSBm^!0lEKA z6yvBRtMgBQy&A6EQp!l_MWTg5Z>5%AT>8_Ssh~{Hg%|xASyHYPO@4vwv!B84r$X58 zNr~(v701bvDx%h<)}>Z@(miiEv;)znZdFomkh+Kz``KktBvdoXK0gXGYF(iS)-)>; zvrZ?$Zukynt=Kk~7Nqn@QdH=V2)U1}P~E_~q+H7MQYt9Z=>%^iOUf1YiEj}L3zvm{ zn_6MV9E9w1vZVBhZ@~UUmQ<0jQv6L>!&8v4a8F}M>w_rV3M-%xHiwkRq##>F%1nY* z)XH?Y6?4M9cqv-hjWSZYFDWYYcc)R@NtTo=vuF%iQZ6YyfC|wPryrq~GX0;wP^=|O z$`$qlhWjFA8I)D}8^x#ppx8qh*&=~drR_n=ge6#CLt9~~&`FO$OPPN2D-;=INx8xf z`4X;JxGZ!%YK3h;NK3M$3fYdx8DR<@3U-+km+8^B5=5DvrBD=+CFODj(UZuMa!Kj3 zREU;1y_8zY^!NV&ypb#^SJ;=x4)H^~(FZfK`hCiTEnsR%>AKWXp?{&4te%~O;%~B~ zTw%+t1iK>$#b*J?$m$%*gk_<7Q9+q5pn|M^kr7-?mXs^Ss!tH^lgUsVWGe?!D=Y_) zdtDjeTBo9zNCjElmKG&sNx5IKc$BPA?e>9vf~-)J$i7Hcs5eRdL>V0vi38(>if38T zkEFJP(k$EqEPnnJo%{V~Fe`)YH;a_!rtD^sP1^%1n^YxIwMktKNp>6VlU z%h~02BufWH;)R8#%)On83Liqj!o8d95mJ@+LMGG<%E&hMkH>}+&b>p<1>EU!XE~|& zU3WqM47JKp1DlV!`0 zv%-o<@It_|NV#(NhxdV8DRx(2|5ZZq5+P*u6P3ZT1@8NlkS`fLfB!XM7D{F31mqXQR`CcQmfexcL}xCs)AZWY8WZ&>|nB_ zTvG0&%b@5|fMPNgWc4YsU8tQ;87aMt6cu`MGib#hJ?pJhP^SA*yOS&_SBmMELRK4v z`!yB9{+E=k37% zrdg4gRcH>Dhj;A~Ov>d;HuYGr1^(Q}$~hBrpNMt9M#tX-CwIEfeKPEC1Df#Mr|SE= zg68=?che|*pbqm8Phw?xZZFm3-G64mF$?!IRz~VRbeH*u8+iDfqo6p+xnCWctsQD} zhNt)@=7bF(DfMxDI5YqA6lYJZi+r>3|9Tqx*HGe1a%y!<_OJM;jPog^wK|3TTOhB3 z=GE#P_Agpe)_Hsomq)a-vhLl{=6m}}m67(Uw-n>>lV<(>^ z^FDiUEeavBnu2}x9C#kP%+uvdfZPN!KX zSbWNw+8Wj43axH_6q2TdAc?&&21vdM8;@ zuCVhFfxDlwy`;Xxr^4=%ZYYjYMz%;GUo%qwM#zLESf|lKSSoZbwUp`lj5MDtDOcE! zu7N8SE(_h6T45Jo3)xL%Nfojkk@Io8?ocr)F4Lo@5JZ{oay^QN$dYm;jmycBa!Kj; zXe(Oc^efa-rq`o&`dzZ5Tw!nT0ogZ{k#Y}{%IyhC6yMzdidr3b5(=`qJ&W>WNx8zd z?FCsLWu#nTU#Az!^yO5L)fchoLY9;(MS2^^w%v$=_3EM2l68e;KyKgOU_10hF^gKV z`pGL%EFw$Fy&7KJ^<;(GM0P7#q5eyDCt0CBAl1DsWOPs@4y5=m6+2kbaZ+!C(k$G= zEP7srj_lG7)Ok-qOGk8Y8EGd_iJBTd( z6^T<8nlg716_Z*)!NQ$QwnuAF(=LZhsFjqF)f++SFNT3Cy$gj^%m;q_|9v{+=Mp^uAFjj*}(jN*eu7gC*sX(mkjUEpa-RTFP_-I>;wW z$`!UX+4WX=vR+r1OCriqe;^Bdi{XPK&1JWm{CF=^yNZt9U$elI` zMTKXeC95x^SxvH}-1k{rN>-?*gTS^SE7WkZ-N*{nm(+gB=%7d(NO2Dpr&!TMQh~{+ zgN0jz#eu=-@O?u-JxVPp&C`VY1X-s)sOL#(QaeaB1I6b=umIE5UdqV2!X6|`$|dC< zBTIip;*^D^%+=V&vQln^f`wa|>{q19-3FOZ^(Z5&d1i50=qoAXla_8rQlh9j6=u08 z1gCRw26OvB>kcD?lpalr3SIkt6f?*QwT@s?E@gTJ6_n|z(@<<8OUf0NbreZOyQm=L z9%b<OpHOFsf<;!rgMe&cQ5}VQ z{&Uch(xi0iY*6(|p}2$!p;&0LqIJdW0pe000`3OlgkqtoaEDMPkP)J#i~+d}$Ynr! z&2oU5Vf`>6WL>iEd*uK*^C;N+9z*dgwPba-m0*j(x^GcNN`FX-3VniFEHiEGbut6N@2Rh{7%ZJaJ?%ASJS`RMaI)s)$;bT9;bQ=Ud%tsr`x6^`zR*0o9L` zXjv2qHJq|VjGkJ3??ByIx@12g zOUf0NIQPGl3H2x0Q)EeLD%@$5rEP(XRFU9LJPuhdWu%H&=;42(XiS+5;7Jp zSy$LyXTaV>txzm9S$!|58=pc^o5dtTgkpgQ5tAF#_W#*A;H-zD!NrdMOoXoMcM3WB zI0fVN6oAjTvhW~mDyzM85T@hbVPH>X&&?3nBnG-ANP;q)#A zmpSOVZm;ST+%7uSXDTgL*TG%EjCgUxT`%eu#p~edW{MZnZBW7xcT!99!BAC15Y2Ak zYGWRQ6nmqd3H3azz0Ep`p%hfZ=>|HTD^6qKHQx;BKKwQ79y5?^H9r7p5*}S`c4JKA zxk`n&;Ne798IYbFR?%rTIA$QOid7>Tj7$*ERK=v76*o@}%xtBpZhIL;5kvb|F4h z^byHMVs?P!z|a{0j)QEunJZ4qP5z(2FqJKzcKp9Y=x3Ocm+*adBDVnG-Xk};_MBJ6Yt(jFP^PCH2MW&{yQfRcOYJt9e^ zWF);rBq2)fjQR<_hY%diaZ#))Q1=&~)DpDO6{`y{?KF)AYEijP5~oL(6JT%QI|m*{cZqJDA2HTdX>OYt=|*sf=V6 zPFZ(TRi{-q^D{lgYTZ-dE{uG-Rh^b~iq*3l@V{AqwsK9ItqPv1 z;f9P;C1srug-<&~qsMJlfXCn)?XFUx>KX_Q>FoH0w6t)1Seyw~W77 zEhFwr!ASQh=RDJBj51&2)_z2brp=SO3bRYMs&@cspoRYIImtw~lc zR@d_X&N7c!Ad>4S>1IoMP}0Me^rhs+s3ho_)>)Y1TyZcehO-U?_Om4$DH&-?CQ>rR zmJFcebz3rol0z{`sk)02t)ikx3?nHoiHX1E5d=eu;)i2mW*XvY6fcU3A$fq3r7=lP zDFj9MYkej*YJ!CEH_?Qnizk@Y$LDfbx%G$YS*gCHrj2 z7nIy@OTMLKW=vA5exf8V(SNBrN_nFMx#`wYb)3pN2}-9_{Y82GM0v4Nogv>Dtu`_` zk|~}e(~LS~Kb?~OQ6MB0C^;cZj9^MtHA?&{CMs5W6g_5})uUvcElHu|Nm~-8#4L55 z>ugFKB`cRFYQQE{R?&SAt-O?|DyEg*qFq4I;h6JM)s~X%#8i~3E|gcdv5 zEV)z#qqY_z`k=IcaKOYl&Q*a{12clxMb~+`= zu>fFOLQxk6ZkE1cHII_+wqy|{J#EQyO8P`45!1C4e-{TXKw&VYcKH zB_nK!!U_M19WhC%Dnm)dvon`L`Q8|^SY=W2sV%8O$#h$iOUbO5q*T?Sq*kK;QdN)g zOB3X#+e%d9WZL2+A=gmy!sI|`aF zk!#aZ#21N}WU)F(^yP9;Z7Jd_QDzyF@2N8v{=G%lk2+&_n7V6NK~QwX>KG;MY{?l) zy2nn!La{ADsVcM?*7dGVcG@<}sDuAPuY>;&PQh(2lk4Xv9|$|yw-u{*DY`=@&(}cU z<7Je^YA?k@W8$*+;nrH)=|N)TjtMaPi7~fbqGCB=N3H`Jwg=#@s1v#B!=0yMHI@o< z1uK>e8;V)#AY5*TvRxOkk~>S$h6zGLdzy%=VhGQ?SWTth2Sg#6h$d(Gl+k*OJKP+D@)i8GYY+=C+Jp$` zEdc%^$XujE@1PldvGTLy3Zu0nGpUd?!e6_|GMvOBrY}|nv?vmZEpAQmaFIx)(#ORr zK=DW$*o>0NXW9R^8@hdFf_Rp?3h2A=*RG#5t@gVZ6+%fNm1OaPca|Cn)Jh_UiK_d# zki6n8R*wVK_Cz$M;4nb(?1Bu(XQ=xsrjyl{EbO*YcQU41D|Szy%reG12sj`n5?R^* zP;j4&WvA@BWQG_9hj4OtMxAk#Q{u)XWxu6hq6}sXl%L3jRdg6fs(&c1E?$aNnQOqTmhNYP1#9@Fm7KPtXjQDnVK}wDKk5OK zrBtQSqOLViWys@ZA+eKeY%zYJ2C^w4V*!tsv+}7?6eLxNDUM1aqqPRaS9i8e>r!%^ zExDAEZnmTaCD+@Mwv_a+B^@d0WlOH7y*^DCGSv@Z%aO=#H>4BU0+es(8e61#N6NVFuziAsf{^BNn=~$ z!$x`SWwxXoB`u?pU=7o_bc$P$F=H49N=lltuAo<8HA)I>NggGaM)CGAWYT$6Gz5;cpA z@VV4=IEQ5fu$F)}0+3r$QLm3uakVJU^16mPGjF0s5r6q~-53OrA5Q*1h1VxlKF*+g+;yUJH6G2LRj{ea@OvEK6Ben#;m zIWkFY`5$osXRNqzqHcyJY_C2$&m=W zS}vt{K>W~wrxp~OGg1^C@zj>O^)h^=DglsnnsOniUlF}Rh!=p=_Az4iD@K+ z=F1^{jhclqjj`Dc>CePU91-3*xKn5nGoJw8c37JB}9tRPL~pM+`HxzPK?edv&MhG*>N{@O~tL8(u5i& zC<7QvKtU{m1Qbrb1oRew91tXY@ldR0QP(VH%qJftT|o~ppMdc(gK8O3 zm$5b2!bqFFTRO%&S1jZFdm-8}vKnt9^a{z1jHzPv0wrCesK|;pi^f}{Vi<@0c)Qnt z#jbhKrap$Za_izpIBxzV)d|<)aG%GO%c;9lgWuNQ!9z7A^?NkLE4*sSxoW`vLStK9 zY^UHAW%AmuhO{MCEE~=l#K&<;^2D;CSk70D_cpXfs6e^T!}I{(aMpsK4LqzGd0IZ% zquj&Lq*sBqmGuY_z7h@9?GGl&qdvZDeDZQX-yX$!`TCV8m&cc`w@Q89!>8K*SkNrY~&=b!G)zf&?I^V~DtEYu9refCB#rg$UKMU(G zwW4)NGOZs(Yb~T{-$5Y%0CGmTMC8I~L?gs!=rjEIa`I(0Q=B)m5@K=|sZn0S2MD$? zu;2H$P=7vvkBpN_LN)OMO8Nz}!aFmZKyvb>ymZ-hYR0YG!rxflJOH{8@=R?2`!9Bt3 zyNKXycvPjm2-BU0u86_d^exiP*q&bZpDxFU!!z)0Zs%5C$=bkR4!#+m0t0qgU>ey6 zR#!%^`$`rB7LuL09~VaRR415}$IJD?v)Z>6^z6XLldCylT>J@odO!weG24Zw!%9y0 zN26uohgd)PE&ku|wS@4qtc(1zWPVK{{M_r{dpY+S;qU%ct?|;yIeb-PuRWuT@TmX0 zY3DiNxg5ze)X^d{Mdl)&rSNmef7gGsGaWrc?tp(ZxFzTTa{K&KJZ^@nKit^0h8^qQ zU=oa{P*ExYO&XCqGn1;ccGbU1{&h<9#Kw z{2}tYdC9=YCi*Lq-^<}Z{)Dd<`H$~Q6TbAosIKIXY(PSL&5lIw=W~DIx7ncxJ$sZ1 z9S<;yk9}n%S)Z)$jg)NnY>xU0=;*V^NIB%Yiu~uSc$wOWiPZXDV2s4T5kou`I0-`j_3DED=)rG5%SRot+ym5-vrsEk_X#EwW>q`^)c1k5?Tj~vtLKaKwn9yh!)1Sk)iW^jEZib> z!ox|tg;xQ09HX2oxva%+n%F`UO|51Dyc4K+q~#-YDRHL+2J4*}Jzm*s2sx!Sn} zsBx7nUl(H1V+D3(@A%ZW(1B~s$)djkG>g;%)!(aWqU6dsfS06WcN+p-bPw8t+VBYL zFj=!Ya(2P)fM;iVq6zF8RW0ZI2eT~N8+#e0do5I1OE894DE}nWcFuR@4uN83un#&l zS`#g}+g*qG?t4G!Dj+VbIs%U{kYZkDc^<+T3Cdj$X^DxnB#%92A}z_5Dc_gx2A!c! zdnOnGnDR*_;p;z4ai{`QI_xGee2$XLpn)DULp7OfB4uCl5!{fhtpk?hIE8-;)Jjip z#!lm}abFRwFT!J(@vUE^_Ib$quv3M7fPB8a)svsa_oR%9!pT6*I18n_y^p8;0$5e? z6>;R0lwL=Q3VrVfc-VhF7L>@t{wD~h)P0vAQhFaLD)gK^D1IPI$`zK&R}l+W3OduN z-vA=)$5d1#OKO2io?>#;pDl9>pqPss42HL84!)B9ED7cE3@|B`5$Cd)_gAvhfO}H? zZFr+)!-nYDL7unf;%zFtO++nGPX~=BXB0M2|Nd0jnir{+p3y`x+6tqs-o(s~PT)mq z*;Es#L45_(Kj%PYPcx`N;w$hizD0PWnM`5&`WXTA#(=4frj&gvi5nQAp6(f$IbQ&y zBCNC=&obwSCtrkswH((@B1Vt z6~RRZwj8+!?DIg~rOBt!(}S|{y@;E6P{XB9r~y)4`(_LjCzr*Ps=&p1-prYyaE(`J zB)E=!J7cH#UTq&9O5-lABAmIjdPoirD^Q#HC(Ew87nOANIUkt?MW$1k!7^kcxHce^ ztA4<5#!dgVL5g#Yhm|4AUUOEeIx|e>%o0@_*lmS8i9SL7p4#^mvO9-IP}kAaNWF%y3V3xp7t6MNazV6_5HD#qC@1mDuGKH({`? z<+`A};&E@adK7Jt%Z&3CuQPfbHRrOYCdlShNy$Od8vAAmIfeihT$JK`ieOQ@83mfz zS)fMEG%fBg*{OO6zxjk;8y$O-h0FkwO_qteJcTc9w^nuxZkWoy=_r-k4?gY;KAB=# zDoJBq(FwXM=?5h%*gmgnvo_6z*|xq`wOJ-WXO;=jtW7TiwGsi|Vj~%#)o3%}4*|L2 z;uL3U!15`LUZv`IJ`W;v<(~f|`X@*I0k<5A%ursWe|lw);mNmTwvv-?u6Obs5PHx= zW#&a%ZaHT>{%Q}2%!}K9#Jm_X0i!CnHhjvwSfvJdR%Un=n|hbSFjB9KMVWak)iMvf zU$Xif!Fehh5yu6Hj>(>jnGYT346c7Xvk@?p!_XeAiu^{i9ELsx^Bby{!_YS#GebEg zra9~iUUv86B}FY&nTh4{#ghL_YA^qZ2kAG1CKQ=#lGsGtVBr1;=rW18#08=Rxautg zWj56stT%>YRI2b1^_!5FFT3O_V(xUTJ~^~Ga1N*?^|9w z5*gd;+DNW01M*a$cheMSz^4|rE3vU&H=A@nU~2`#Sn*N2*%OK5{C^Y!^};cMZ{UL) zTV-r)7uE?ry%HDm!#K|{mLDUeUeG{F!t2Sl3TA!AzKe|r)7Jl>rqg&QQnZyl;#+A( z#IHa-P>|wmG7*_x?n7kEpFvhQf)TdQ@+a+!p-inUfXe>bLh%hyc+vP?oFWc?f}%G7 zS!82doY|wAK#Met%EEmpe?jnC;G*klL9o#(^xTPW@cL{_7|T{hzq=coGdA30o)0d3 z;}}wALCkQv_+!g`M!frs;O7X4I~5)HGlIv!S_v>s3;&E4p*v;^m5Cz>jU}Kw2SZ^? zqLewi2M^>_DrSuN?sPUZ@(;e|OnLL#O)$LzU?IoV)fjWHBif5R_ zQxY10-Ns)vB_ROQTZduvfpKjX*Sq5bFsRIEi0o0^&n8Y)o6I!j@R);u~XwC%qF&QGqBfq9`m?8(<8=B zw(k}nKdc8Cj*+1lne4k&09MzSDHZ%R$@%Y3R!bzt*l0IhQwOM7$ZvF!NkECO!mdEw zZBQo538)Uz-cdk(W4Clhd`ry$eH5r7gEEU%0?NeoI#4_QwBmX&-k0gupMbjegvqV+ z>zsI$sWJ3hlJlNjqx3**`D!H5-;MV*MwhRQ;Lv5(@|6*+A=>Er(gLiNaZ}GI)RS{o zJ+TdBuGF&(sMRWP)I==@NXEm7w;9`kZ=~WI969k`A-h&sYgsXi?Spu0WHj1>_-G4) ze9vSq-&>im*c#i7u$3k0o!|?IoQt%q+3!T$m}Tjm1UIpvV+Pp3WB6@J)Dayz3#1t( zj;tR&%cMeQ%`uasWiWd6@)Rfgcgv9BTG=$q)0;q^FetM;5oIk;eD$ZbJdw40m{FAa zJAOFixK-1V`0-&-^?{o3FDSD--2l`{ygW2Ik5`!HMwX|90Lrto3unUUZ{ylboHg+Q z7}O>P;JKDzyn(3LDb0lW1yH$j%3YD-JdL(Svz}0I8yRH2<4Mj)(>Er0Uf-CjoC?x6 z(e1KAnd`B_oHfKQ!bKT}7?clq8FX zoQMZUJme&rm_`=aCfA6`S-pAyjoW9h4V%uD)ZiaL*=xgd=R(y1D)}4JtCIS@JbT23 zy6O9_KwXk#&IB@Jx4{>aAw#`FnH@MUB&IXw!*ud|_*iF7A7&_QkB?`Vbli(TO~H#d zqoa&RIZW1J{$N>tsX030%alzA%!<_H?=$EV8ljYBttZ&{~^vN8qB1L_sjL1nW0n z!Je=wo3--EcjT6%cLnqwQf9d~)1kp+f}YbC%mt1eoF1nyA+WWrp8rCeyunzujWvFcmV6dG89S6D+N;P1gG%D{|b3y8`l}k6Z!8 zCnxa==u`OR6;S&WCv~9}KCP_rU}Ex}#)qm`r#OEvvXE*Bnvgi^>j8Nxum#wQ9<#7P zViQMw4`6ErKVM_gBAWnl)~H_vAJ%pM=L`54L;R>Wkm#uY6c%T9(krOx>rGZXWf@Q6 zsQ(eDGS{RyBi35T5RtL&H2F_IgWtqmVWFgbF_g*Lr9geV-a_%mTkys)bg=vRmngad zkVQ6e)L#UxHR`Vf&KmXiAq}~_;h!+-O|8#vvqt@*nvcW{A2aGJePOxJ2*$b32=4L* zpf~Ej0c$0|R1*3d*L6=@O_PMi5@1GsW1^lBlo|EsGnwwyU)e1-4u6vtM@M}dSXx;L zqfb>~J76&Ct3|K-OL^UIqA!h%`uOC;A~L6ro$!0!W)qPNxJokMq8rX?MEk!t9MdZO z4<3gzZ8xo|7C%JHsiOfU`DTL<|Xj~7*s{a=e+Z{)x`~oijC(+>^b+! zr{Yc>e`6j*$20CMJ!vI9BUlz-D;hICCZV34rU@n;Y{FTnH9#%=7gQUG<{hB!M4izC zVG~J5bP)Wr(Tc}A$;Sqgi6=w(oI&OcVB%>JACJk-WkkUnYm%ez74azJt1nOm|3_a_ zfVyje<*Vsp%#m1JW`M5)D)SAiZSCUQw(9kNYnzGs2z(U3X4TXoK58?-&r9+-ht2uG zTo3VlaP9#<3NR~D)9P-pZ#!RVF&Vrrz7{jU?*(f3zo5(jUkcQ?m#tRcAgzuL@OjW# z0hnff1f$=KYtuP5#s^?fr-17Il9i19L?sUJD|W;U@Fff52KaB=t)yoJQvtT3G3mI) z=W{xnCYW@v31^|E1C{eHs5bDd@Fstsa|h~-4)EI~9nk^)_bXOB|6_pv1|PrJH4TZ6 z$7Cn$_c;UMEjqvp<58wJju6J7A0w)NG)3t5-XuIMZ=c zBZ|E@zTRwN3!ej)zg$RE9`69sBZlbz`yIgKfX{hmqz1`CB@hvseWEoHe24&((K$*DS1Zu`qE3PT=zD%DU2I}%@ zCTp^2O^-*J8Z(1F=V7}>>4C&~(PDhuytsT`+`Kq4&Kidq!2rP4h&T0&Mm;~8J~S

xvy8dRC!Te& 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≷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%0A;#Yrfa%MNj*63?y!5+Jn1Gi?*s5m_e#r( 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

-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%0D6fD!irUgBjAa<%`UD6gi3Uj)CK65rlW9ceHBpyV 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%0DP4+fVj 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

?e)eZi2JN} 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

C_1&_|O|ij>F5_zT8V7*5@hSjoWX@!nuG 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

xGys=4>8=5VVm1JapqLsYkBN_g~K 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

8JA#g!?zD(z#VU}V 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 Qt_fM3nS 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

T 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 ZdlYA%7iq0rm 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%0AAGCl`#FwClobn8Esz+|WB1T*I$ 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 &4)J5Ws{#;$;>A(}TW< zTLyV;o zRNe>I$l;Eg5N6}U2wv+77F~1qQN$|rWM2cgiJ^vc2P&W$TwrBhiZ6f?KgJ8A7h@}# zYQa1tKU~eYg}u+Vz$fE@)aUF9|Jfe;B_gmJ%L^$NQhb^n%Ky#t3ZSjGXm>_# zwcp095{53yYto-H`% zplaX6?~1ctsL86n&CZLnR;sSKaTi|H_nrPW%O@D$S$!AR1do{%P)1<~%5LcyY&_}e z#C<~X#Sk15&vp;ZoPpn=*?y7P&UJT2O$MT0a{tB1=eq8QR~NAN%G}Fm$?kw`whpHe zYd}hE_Y!oXqq~ER&4$X&E0-8QX5AI5vvP94rxJE+UoAK>?H1O&6AB| z6B1*XSh07Olwu2DFLx^ z-S@xdzF&gIxT;AXV@8iNfSVwXJ&T$QDE6dc01>QXa#ZGCgC;Wdx2f-vJaHF5XexTS z*%M`!FeIm0UL{zI0<_cvCoeI``F^|@%vN+aAMJG1Y?6mynxGL-81?`oPw8FQ=+XtC zi)mINEuC}){)wKUK4drP&==80_bf93ss9V;z+!b6R&a)tjB%^WeXIA8#p!Wqlz%_^ zab6iYi^a4+i4cv)bzCe|UrcfR(pllSID!GY@BA=ey>*UbJ0yae4+B-#IImfioEK9LHCm@FhSVCP?7G+_ZE9D;$5p;Q+(oNa64kmFKHZ z_)__wq~dUdvJOm)gP})&p~wxYg&y3_p6(!3&sU%DCBTCOs6@_)B?R`+>p2gfSLPle zaC!CZYx*?Xs$S%wtBFitAfjw+E$O4hjEIwL&N6<41r@o6{ep7Eo-&^d1M*1BCOk@d z^Vk@qgFld4ae#?$K*t5=rjT2Oi{ew!uW~(DBQ^#Ji}4hlSTZ^|i{+l}*%1YogaNxBg%{RZgKF+9)fN!XbI!IE)gnp_T)8(gLLv~~K-lU% zAra_JelIH|_ez_fFO#{!0IR*cm2CUGR24)E#p=5+M{|fy1=Vilyzzpi2oungs|Tox zx8P+cdXlSXal(4@=)lx_tf$w)+NiB>)G|Nz?^#eQ#3m-j%0Aw*FGi!ufyh;?1H?#b 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

CHv;1A zq2q0WqYL+)ZTI^I=RQtwKJ&J^8x(`UE=xCSE@#*hUpQPMRs_062r}bv*6P#`z9dS8 z8uW=DY(SPrbmkztPH^-!L`y4pjXFotc2p3@bO@=)c`077_hgePI!^@E!w0`3-&&v0|hFvR^> zf%@?{{2n}qiPYsJ=FpBe$Ihw0AB%A;rl9w8dRXlT{BLd$lRqKk2gHzx;|Itpg8S|? z`OOkDWd&l&qv9$Q+2(C~Pq*}70go1(Vd;^Qk!T@$l6zztjI5nRq`I z?GU!WJ>4%pdczfNz9=RsQRO+(-rflSdrW-C1I_JBRok9OUPlPz*w<}euR}FE3~t%q zV_)U2Hzapu=CN-lemygdTU&**A7|ik5|O|nj=_Cf11KUm{29<&m+hw$iyYknq1FKg za+4(wsvCPrHGPe@B|^H-J1zN)cLsS_N$?fRe?w{32^M763C4)){ay>;-yza*K`9Z$ zGP@>;$4XMJCgrBds^FX}I)uY~&?lMKmVr~blp@2294!!zek0YtgA^%=6955abg?mO zlzIy+A$%S1SaQw>>A?oIxfCpKd|}a8Xmv<;P&Yo4;)qNETrZtA>?FtDbZWdXj=HPa z?A$~702>|D+GG?8zGWzu+DEW!M^ zrhRuufURJ|eERi&^-I3R+Rz|B1xlN5!{Lw|0-zf@b9BAC1KKAEo0g!S8nky(V1Pof z^NH=cI|Ew%^-w)$5y9AV7C0))Cr2IKPgs|_TX=grL{LBSiZafSQ(W40a!-pV6KX0R zClD*1dZ{;YZrMfHD;zevOgAey>5O-QdRFlI**$pmdEj&N*$r?lzac}z>v7uJL4fxF z!OAh>0|YCVcl@@5r}Et-8onA$CwI<8b(gt_Ym7S9zy^yXj2Cmd&^|f$Zl)4iw|6dN zpp;_v17=sUtRKxN>ur=MM0cL##!!E)!I+9$gQ*E(uUvhg6RZD zpN!(cU$YXetO1c06?UmB7k!1MJbFR8Jc4b5h&#UZx29 z>bEf^Z}X71Db?+Cn>Vl_Sg z_66d7K(V@Dkb9rY9=yCbOq{%qPXUPH8gwu4l2{35t$n=V zvN)QD@=fB)7+rL?-!6g=i?-1r#0ufUyFq^LU4hpHgHd&WReyopzl6pOW$H`D3Jk@3>p z(4`_Igdk*yMml{XIaPI85^7GHS934h6eZKC08V)h9{&~n2%>*y#K@PQfQ4qNWUMpk+IAOUDx0S3?-w`dBFz%X|ek$D!jEaQxtl z_O6--z~(bEjQyaFV*ARv1|65BJkdTYPja)JP2gm$0a~|^wPtPHmt>q-yWdLLV%F~6 z$z)ra>18`B*KArFow#!c?`y4?x@B9iq&xsu>vzn$AOEacA-T#^f#_rv!HK%%Y$@AX z&=mn)J^jfx0o4Z(cbc1b<_SrY&{+XWnY`kusB;_nH}GaJ*|Ya~3h63n8AIllv(1CL z)c(Ao!B{+OV2Zvk>0a|ZuW%)9C(m?&y|Yfmf@iwanJ0SKFFN(id9I7?pZ9ZL?i>r? zGhJkBw$FWOX${$(l+StCc#{a$@}c*zf53-QewX8lyibomx}}ACrgWWIYE1gMlQ$9{ zKu-VY+|{4wq0C7h#8jXCL7b{$?0~Fix^)krS7t7aciy68fhXWbi#V7i(JV~x4o#Om ztBu`EzK(1pBG;W%=g0Zkw_q_r&dxi$QI5{ByP%FZqQ~-DpUCR-2F9G4d^<1Sv5AxA zX5N=0TZm>zk23{&Gwrdlhp4IX^q%qvLla$!s=xis#na#Z2LChf@_NtBboopCY#dj6 zG7^YU=*exJi5zcZ&$l{`dhI%6vh@-0R!63nw(0dkJyG6b^!m4dh7TzJWRoZH>>qGM z_F>e!?Pc-JD7l>`<0hwXf`5%hbqhO^UQ^7;>(sj-=4LXf=ZZGG}P48#Ai}U3e!c4!k`KlIUPb{72#vlmd1_KvYJVAwR*JlVn8Vx7EY>JieRAms4Mi*JHu-akHzx%?*@$2?zRG$jOE|KF^c4ekdIA z0qYY(Vfv8 z+sQ=9pdTeAPU1cXzAeE+;}?#u+_g*Qu}{gpoT(Hm>et1yP{IfCFq$ml#SfdN%CXLY z0RG0+@@I;4L+KUU&O9Z9N7hfG^_I<557qrA%g}wJSn1T^0RX?=&cyT&t zC;c5{6yx;}{4x^uQ37au@h&K3u|A@_ea)r_v25C#?Vj~xTbNM5-!%b3TXpP0H*k1QeOQfy(NfvK?Y z0bLhkR3iBCXKyM_wGHTaRY)-Dl5iUqQ5Xa=K% zO-`$?(4#+Qb<`D^$_~!FE8kDr70!_^$YXQ-UVEoll|PE`Y1z8+ZWbDqowCotCGTAsAn9bs3D*21^BzAH;lh)cE2n93m~;|@7^V;_#lK5XV*@}odl}x$qukH zGFOGTw5OH7isQ$g7Pey%+NSrxuCNPfX3$YdrP|b|4k+2J1Hc<#^t6=bThYo#`);i6 z&ak{4TwY~9a--UwmgtNKsGV87dN#CncVNrJ!0wdktu#dUX{jwILDtg(WhAn)T*eB$ zZr$|L&h4z+f7EGE&1ckU^Z>4T!8n@FBWO^PU@@g!ev5E2h>%)+5q+=y-!4*L#p9@j zpqB)Z?-5;A>c{Tadi?^S@$xI@LSG=e_hk529b$4gj|ahgk;Id`*5Io5I;htNUqg(R zgz;kD8jyG0Yty|BU*PR-^q4c~;q`i4{2j=h%)r)SHch`$} zG{019Z#8WeIwA8&B|YQ}PKZ;OXntQrlX*Oy03|ax55&>D*-i7_AKyomXQ6da|B`sB zIwXT@G!u;gn#X$(1Wc~PcaMY_4e&5{2$vlGx zawphYx9MeT(_UA2YknmpSp9AfTxDCLr?6dg;#~4rHyhaWdbe%Xio{;Q-NBTirSo z!hV}fCkya1dI`vN*xUqSN(p)s4*oK`-VzNk$Xf;WjnUhzZ-S^dbWfkr&uZYS=P6BhQ8;ndC9iibKQix{ZK$}yW{Ch z;@Q#JY_fjuX6QBD72BcVIwGH0^_w7XWe_e%!f?|RZ348v|83IQHOljb1OTy?fe zEaa!?AA_9`y=iW;c?LE@7rs~@D@1^t|6@B0a4 zEmqEHy_~D&E7r_;I`EHm@cMk3K&Rync5wV9@n{E|U;2RB*TmnwP!6zMlU>|{gI=_d z>l+RA0(-T8tS(+xg?xoqI9o_tz?wn-n11jN4*SUu(mz9G-NXM!k<#|kn=TuxwxLgf z68v?VIlEPVF9)~`C-E(a=R6)oT|O{CX`NYqhRiMH=gW)jYLLgA{46O^vC^?`<5lvNLE7 zM&j_bYi35Vb#J*iq7&9#bkCqtISnShqH=nJ{{7grTvy9*z^ZBa)@Ye#Iy-A0>?>=g z*X=gl_mE98`tDVFwKT{Et!=g6?SX5`Lhi&fRGv{vmr;c4BxJG0jG-}~0$9&^-IIws-xEJYL>OVtlJeOw{RuUb^EH<(V0A;vUxIgtJlH(&91QA8D^TzodR}YcxyY@HLA7zQD^gh_vtujC1p2IGfq;+ExxLrkgh>+q$TQbo zjB!#Sx@9z?$YMw1Ri)|t8>}r|*IT+mOVhTH?&cL6YGzuYU1}*cOrg zx{s21q@%*~Y=$g`tOQxX7_6~+m1CW>1)d6+J4#5A;ppxku$}VHTVq7dBEEXNw*$Ri z*5OiNl5YmbZPU3oHw88>n3gnZkW#TVfZ_%kS{ zHUCXoxC}LIv+2W);~Yc}H;_6>?(rtq{~#>}VL~XjYC$6W`Lv&34F;~+csgGMckwK& z!R$cJWy2s+dbfEk2xoCHB7~xqbOXfKq4Y)zI6*5bQjYA=>KV1#`MWPkH=0AA;V9Cy z`&+Yf4&_L${*C;+xCRnyh)Qa)Qzc#REPzL$($XkDva8;OqjT}m3F^3)Z^Xru0*Tri zDFAz2{z_n6;i0%z51Q5v{fCuJrWrE#rr)VM_*!2VQr?k!aTA&ld%afDgE&LxX+i7} zY>^-rGrn7%i!9}ywOnRPL!v(^0vjGCfD- zj!Ly0m3vx2$MK|nmgzSt16N7AQMtEjx{b=+sqJZNHtd~Ntk-zz=8bTn?-~8 zHXazZs(X%4h>~nk?f=?+dnKc{hV|rQI2pp9p92Y$peDX~n;zP(`h2l-d2s!WEdZ0T z+47D7pdl>c#8Wr113)}httovg*%-{`u z1S!cg$HN}yq$y9bgT0W5Agr?&&~$=#R@f7$^$*sXLAJacXhrx2dEf0F2AzID3-j96iPqO2tPWh~j7I`i{&QXqG-)S!SL_vN z#-P_cG?_@MGm@CF?+pZH9V#2 z_4VGPZ&7ic9MEbEeQiSUU(h%u@IS>hs3s6DY4u0WK)GxeP<43^8XG z=8>?ab2De82RSrdwEX&tm&AuKN5nFYOE17CVsg&Pe;!cC?1$0xCLD52(8kWKQ3No(vhhEEqtI}NF&ok1TnuJqanX7$nwnTSd(3*xhlGjey zRn;)+UZ}58>3C3`^N{{H-t3qKUD4nN2WpN=qb^Jbxhi=FnR-CGId^@ix_10y^SW@V znYe+RKb}oT@gx%C_%4iJ`cB84Plrcd|5gR-?G&D_o#H#Am_xPk8DdE^X$v{69FPlL zaNWTRyQ0zG$mL8&mxuXDbQe!j5H7--Xw=2G>4Z>F2Q}$aUo5>-7q#S4uhumK_1c|> z9IH7QI>Y3Els9xi2fP-NJ!U}0ra%e;XY7p;k=HAO;#n9203m-}h2w~!u-wN5A5Vcz z>yo_YUzohEb3j?%jANq-xub{3v6|UY<1zM>-)H<3Y? z(>CzX&JEMj{jcCDmH|o0;W@W*pD3OqzcOl$NR&2?`?pdCho&cIgk}@UAIcL@N5UVD zL`foK6o`;XrbQ2=i5q53_M-(+&vC|=dSmSEO)Z19jiRlAsPPz6vki2f&O~#8)yZ3c z1S}JtHDUFnF$5bCauc9rE~H^dS5jO^nY{J2jMXXWl@uD9cdCwfPo4ZJcn?VRjJ~vX z0Tw-~Nv@54#fp1JJ))so-Mn-qn4*6N0z9!cZ4g6^I>{T)xxuK-N8MV?%I7=bah+fV zDO@MaTLIG}v0&EcYp!bd?-*ie{ES})D;BZ3^!hrMm%6(+n?Fm}T&O$X(Ls(2r zQXSS{Q*t;2CldQgU)fr?0n*1Rw2QZNn0773BGN?JXYF>Cez~_z3y$rM$*RW3+>Gts zJNqcxbglEZe&(D@32b#HAcm%XVHt5r&uj#tyZ6i2=YktCk!dP8q4l8X)kKiaftnDJ3$6z2*0K!+m(+MCLiXL463Gpu%v6i{nv?jqIm z(ShkGjGV(>tEN0v`S5*bo{a1ppz#1Tor<|@++$;MXU zQ2ge2a}3XoOdE*e{uNf{Hprcy@pL-e<#mDrL%7SyR8Y%rLa-kks`ADR82|?%IZTlD zsQan@mUP$FN8OqG9g3R6*8DPtd2n)f1v5VFtaw72{1!sK4&F7JH{C`*2tEyJIrV-+ zEn6*;iUV6!+#c@g6Cgom=)nt1f?}mv~pE zm#~|z3x+`f`6?>F;+$NTaQ|3DU~h!n<8ix)5tw@kJ#-ytqMKA43Agb-gK;WTc%ura#a{tQG#!& z?|e$f(d%)eDHOP~lwIPR;2QxK3-~eywUG=J6OIA3C`qOXuPhVV2djX#N$;Wa8ij>f@s_CrB~Ap*F}0qAfx!-LuXnkM3}c!Iwqc;d7A zVU}=?^%_M}lh4ywn7(Q;eBn4TKF@3VZGs><*;*CV1~QA(?X>oPZ^EHSXH1(2ahUJ* zhof&_5q)}Jn+vb1+K5cABzx5+F!%8va?l>dbR$=4ZD82aYQfd4wur`<89E5yI0=l! zBm4`%LbY4_umAdA`hO0D|23Ea<5pS=I9Yv5@TNGu?%U#*eb-kCG>7EIuHFfj{PV59>TpZ@_0?!PdDtN`!HC}Q#WoSOpaK2*ENvk2xv>+bOMm9|u=Z;;lH7Tmn+5hSzyJO3xWtAC0~A^eHJidV z)?!thtF<&lM;(N|*)ES2drDUgDiqgnUyY&<-_DUo5J~@`Y{0x1A$-~s)@P(~Jmi(V z_5gK6BWgnAU4z9X6=i-9>3T?AX&9CKTN8RkjMHq!;rD>EnibDtBaBrTgQl?d7>7vN zUTxtYXp-9iAjN>@L|(0rF10qih}21=igLBz#A~z%z>4{fbJ}8WWnTugpmUQ#YeLNh z)7FABTh$u*6``)ym46bJaU%!wt7Ia=L~L+y@__PJcnq*Y4;s5(6J$;YR_dSha9_KN zwSZ8$NW2gCnFm?^bA4tlcT>2ww;WW!(~6f`=;RDsICkVp%~L#7YYkQgmA&^ty!AR* z6@Z-A)T#~cJW00d*hFnClo=2AuyAH67ps9nuV|1ZBM`3Ra!GNY%SYSXQQ}KA0a*4>Pe<#}e~0y*I6s$`P@1SiX~JU70g;7=lio66-kP zBpAUWXN_$8E0lN1@dxI#zHsH&u&W3iu_V{9eoepj(&As8vUE$OXJ3CWZ& zK9#xBHNz=s>?9CX4{Y1IRxGFA3TK`%B~~-)Bdh7lj+0f(dFwbjv}~QM!pmF7)lOwA zWmQR@I$6C>wo+C}HlheF-wxX_J%5zHB647WUrYSEdg$V}0dDsrJv-1ed^=^ImO9t9s#!v?YzfP8{`f z#RgS3v`&p*8F{)z)gk z*=22lZ`w3~xr#?o8aPDs0^(t^kXlBS+AtIqb1I?WsfL@Pi-F&gjsLpCW)mIAmr84Z z(!M85FooG$ZnM`7!0zF$qeihJ>4)^iBml*18@p*F7^jqxWEcy=MuQc#nkvT*=tKf4 zM8F~!Nn9vJH;v7hibIqy%;Lzz#LEyS`zh>cXgPYE1WW(!@g9X?`kX>)_P_=?l7F(V z+jcVjEk-F2(rDwh4KSFMbhs28tGdT!=P&GYVV}5eHp_BX7$EWWSJLaUafsyjmI9)r z-^B@qHbyltBxj~1HgjWi14=;)shPxY(kCd)xfWq8B?pii&{Fj6OxI1d0a9EReLu&2 zQ+0^)KyXKkswm7bjTVJoeZ4&7sr4h}tX3hYEYe9|ETTUuGj-v3^7zJT*kE@S@I#JNY5VETPQ)iI*B8EgaQWXXxOOr1= zfLnmBc3HZ|s6RA9)trh`(1=n6DALZ`ywv7d!E6NFfHwm7U|g<2!)STEGX z_G(i525r8ER%$VY4O7uRGEO+dne}f}yTf1Y^lcghVvd4XL|Gq}*}z6ex6a?D(KAk+ zE~#x8WFJP1U^bhtVRM3(H(N&!kMqYB|H!e@C?o#_tFZW6YG^u3$CDON zV+3)-C}v2Z8`ehbI~gIGQT{m0wBk+?pckI^3u8S(0eb}LzbMCAk^rsHJ%aB=nS?S=1O zqUOY*th#rWB+&mH%usN8d5CVYAtlT6zolOFPTxlpr0t<9K~iRTrFApYHpkOyl#&q& zx1?i)axk3OBY<2-j)9qQ3*%)UrA>hq{I?W5N53qnj1=A!KhVpG%&(zC!v@FudV8oj zFhSxgYfI=z_7;_!d{OHo?nz z8#>~a1+++C+_GcF-EjparAM?5ValTkVpj?fIL_q%{I4Mw7Cn^t!y?&*suYN}ai7*28C7r))aBNiHxQY+^(mp*H~D~d}&MRqh9u-0}7CV-1aw45K@pUr0|Dz%oabwp*}AsJ3(pUA)d&7oho zZr)#)T$&q3kMVf~NAY^}@s>LB>=amS&YQ`a_jX;@vVBx}$8EWmIa;bDXBUgzwH1G% zuCS@dKlilDY8DRcAsi!cLkX1M{y>DO0>J$@`+Z285}W_$A4b3Ce34MM48{q|hUw}U zrYRudOjLf+-w=kYtZ!+t8CWHw*U;(>K=!oEcRX*fdixYaD6%;ryO;7?_De_C+`|ly ziyut<*DaGNcLg_ATCDOGS2@Wp%BERD9s82pACMxlj-p)BBF(NWPhrSeY8+I3vzJU)bW!6n*rI-sZi z06lSGaL(F%g-}|rE~imlcM~^h=aFPnn7rc`ykpVM;dcIG_~m8|U&;dvZd&tAm96W2 zjZr0I&(#unPqn3UPh=3DH4pAHsU6G450@sNr$eYilXWJC?_ni`&*X8k2El_v4u|ib zK=SFGBoE%@&AEO(c&ZW(NEO0O&1NnkW`$mz~wr?8l3UVxEIf7yyfVTS-dHMR$7V20EaQV zY$lByjF}mqxy9|#7_eAR4xui^)#A)fY?)q07d%?i&_ktxLV{Pes}8vM9ZtPr4y)53 zl)AJYBDv-fQfj4* zNFE&cVfLZe9*9-bclexoC9$&RWVnY8hU);rWu_v?hRbkFZJt8y_B_6iP`4@KM%D(v zOiU#rH9S|S1KIX|nb3c+I`Ga@`U^?77tgC-8LF(QE{#ea|8){f@5aGSu--|U8{h|{ zqA2w@_|Eh8zS}?fo6d)6gLz3=IHrS^vA>0O7McawnP>-hu~qnybO+U3j@G~jXbp^& zCB_X*${TMSd~J^$`$BZIPjXP*{UMB8e!va^bbmDI<6muVqD~@C(q^&{M=L(qK%DRf z=^LueGL4ioaDF?DMw9XSe&Hi99nnzYm)-a`MzEozNtxuxgyR2dJWfDhfD(VG6N~6T zmaH5E3)%%Q#?^0g&fKLzj$r0YNF?$wNP>DwAA=@V)cAws-@UkdI)g=2ByK=f4h50m zj-dwA&`q8qq+)&rJtg(RM5}4)s}&Q}kkn6UKEnde==?!^u~wlk;`?6W<#{8#csaXA zc^Hqg)Q%yJnG}?iZ?w%Y&s4EOT_AkjeBg|}0I~_sNgXWea|um_B@}nR%S<6bABT=h zoMDLA8w(g^MtaivzF;Xo>vA$U0MUtR&vPnl4poYgz+jspsOc5W=3`nV#5fX=JlHIV zSde{-tj%yX60OV)xr{|GK_YIWwR4-w2C`uPuCbHu9ZZ+t43H_gAg85U=MkACq{@on9afEa;^Bvn)A%9nGBAjpkCCPH zyOf)XhJ`{Tl|6Q8!gAX_;EpItUfHl@5?Qj>A57ChuH|CiWx3c_87o^Z)a@2bKsWbO zLGsD`!M}f;v6g@m-_x-7fI@hv^&xs{p~ct8r)up!0(PfyAFcFj^}}Eh#SO)hxB2T> z5=>mGXsh)Vb+ox=Ikjs^2fd#oDW0Q?(PJ!jz~VxUJ+L!;hPUt#RXgm>BK$HAzkpO1 z)A|I~fWD-k<%21}qlmwV3nr`~~7LT+AP? zQNUt34wrPTT6WI(avqb9N>=G`meN)XU)IQmjm(JTvL1)$E^Zdk)^avg1++yO3&=cd zZ7M)nfB4)=gf)lXRKu|T@cGpbYmUFE*k;|~H&tA$IsT>+pLK`dROPYe_#5j()*N5x z-bOZ)A)B$WO4me69bYH26B2~xgY1^&)m_ylo>zPPO+{2|?mU=kF4wCI|0cHA!1(!m zukHk!7+>x2H*vnY6KrCAwa4GY`|3`xk@?k~K;eFgG?=OI8;+!^$4^F#BtEE;xn1pp z0aK%+XNtzE6PufE*>9MGBS5}XF|DdwB7|}Su`mR~m{=mstmWAg0(BbMT9{l*C{r{C zmr7r;c%@+2*a2?JT z=609e)B`s<&=uTZJkN2=D!us($08dPA_aFL3#*o27w4x6pqmSEwn6Vu$JM&3)V5*x z988~#dM-e=ZDUJ=`7GNit#?A>?^bL>E+RsSo`Pi*%+_Wbm#z*U$8ze;g%J^)O-#?S zOT;D00xH>=vZwH$d<;;ATZYq!oH&H*@Tar+I2=re2*ecqQjtMkfaWi}eCHj?Bx)T2bDusunK9PdztM$3+nPpKm8!l2BUUY*~mR9hMpGlZeS06GO{ zI%hc`PvSZ~^GT>I2p*BBroq2~;Y{a{s3&TWYr=^#DgE1>-EVgsO@j!+H7tu6LUNi(`jV&&vDTo1QWuwoE5`6El|etT#SqH_McFBB!F|`p^q-1Jf_A zywVQ&=hZ23v)l62&TdIg(@6_6xXf^K&>oC#$GCtyc(a{)M_@B z)op5?;^lTn0RCU8m7S4~0Kx z33yf1yK2kKR`M#0CwIbB^}GT~HIW`nXe`ll5fFde?)VR^*sJv(FO1T{i$K{=o-p=mDQz7rMNRPPYp|fhD4JNwSft@ z`U9rbL1H}rsZ`(5m2Bi-kwO!z+S=3>J-o0rsV0JLJOq_YXq}${GaV!0?AwUa=5&1E_h2x1DO`LNx}Ur%RHvwQ4)WA3rnb77_=*@bVft^M9Jsq{IVhtImWay+$;d*+qW zem&P}TYIlo{8IQZrpsZuZ~ei|d&-n9ohz+*HDAJ-N_tJVbxF0n&o5$8uVka7t>OcT z5{3QeuaRZ8FJX|z_105Digye}KUv#ncGDMV;n7n8&wk-bUjH}Wz$vy^!0-uJ01 zgs~_D!>=C~lhB`p!TsQ3x{EduM(oVR9a4lu)H`KpD$ncqDLRw{$xQbw`hLo!Q)eTk zh!t9geECOo3|8KFgIocYi@SA(AjvG{|g z%?5HMW<}^zs%9nYsXV9^p_SsO+L&_R2vms-vA#FENF5r?#$VDefC|&{ub~95WMCXa zy#t-z_GD9A3>A%{^>sLY9EIbz%V_NX|eP}xk*TXF-$!2$7mN6`%FW2meCFBEL2s_TQj(_fe8 z;oalIFY9Qsy1M%<9IY>@M+)k)qsn<-FL6_00JREIH4xIWLK*Mxs!O;C?!rki$ldQ1 z0NDMagwv0R;5oo>8Z458Ga@>L0U`6!dPFh<{vs!tvg4}|j7TURsOG=$Q(xSRUQvFa zgl3oEv`PoJH%|YHh;)3ZYeAl}Mtd>=SYzds&isN7l^qrN;^0Sa=#LZ>;_qIWttJb;dO%Q#T*6e% zEC%t(dim9_{`%45toqAR>8XY<-7=+!>%|s+I{!RdDJw5MKw{x5{pO*dmZzRVQ@TcN z)0SSqBkfafc0DZ9YXsM~k_jbBxO;mclybBNgGC9H{*(Ch>3l>kth{fSaym-}|HY zM~nobFI{x>ly6F(#iH*z&SIfg-Dk1TtJ!C<(Cb-evCzwzXR*-R*=MoP>v?Cf&;ZV} zSm@2#L96UM6d$J@t;X*gSl<1?hR(aAXv)&WH9qJao( zzt!iB^&>9%qX~BL7pZa&GuBPGTA|jEe@g|Hw5OGmseS$g>(SgOL8Ls3A;+KMQF)QZ zutpm->v4G2jW^ONR!T~s0c@;%a}OnS6$BWjuNgB_kE=MUJ+XM-1gmm|CsAT&cBK_ z*H70dJ1~R!WP}cHswD#w-&=1zsSjNz-ViS?^kWT7~q-1G%1{E4IkM+16_t+u^5W2p2 zM9EPSi~ZGP{@Gsy>yHE0ET2fNbbkL@)_z8&Kib#ZWiVR>-0WLKT$mkpHr;h}$*6^! zykl!$=@F}ovh1PPKjn*wU>V#T`9IiUaojsw-Sb22Irr&%Quf=e3RsjydS%Qv-EU}m)kgl4IoO-o<7Bc} zqvySW??e!6bB`gK{>343IMk!gz)3Kr#;di?D)x4jgUOuxbFdr_hRidVW!(BVXZ|(* z&)THC;E2c5ldW#jH@c`S!)p47fcYFO`qwv}!N(AB#lGfsa5o9rV%SkxDI8uB0Mc*+ za-tF_;c@_t1lYU8iKHLwB)-!!Vc5x zB?~|!6zkg^hD|qRIRU4xryB1m5!odkg)pS+h5s((qF%l}*%_HM2f1YO(`Gu+gcLlk z*IJGV1E1#vQWHu4D)J=zQ;3LCI8i7zf%i?flv1N`yGEuiEAER_sYKOzI)+I&Z7LhV z;xP#kapJG;qgfE@*Mef<{xj`a7zd?A%vR7gTC1#+Mjy0s&sl{h6d4n9ife+Jf$^3OaFB270wMxB(&g%7i`e(0~MI~&j8Q`%&-ZQA@MJ65A_0VgK zv$ozij66DJDhGChUrDQ6EI5Q{$JCm`J%2{qyP+v$Z+)(qcVsTm(Fm+9Mx{D%mC`wE zWFQ;H-Q(y}xaOoMTtbPZ4ThU{&|;3k z^me%nz7FTaraIQpsM2in;ReXrcph-DjmE|?G8lzy~xCi zyO>EO@0a_Ye~bVBf|SWy{9hh0$_~uVxOAlE2#c#Yp0pDy!xSXcdp66e52a_C(p%l{ z$osm6&YpSJgxZ@by{dUuHz1X)MxSTJoBl-SCArDzfXX22oE$XK&<{0;i&^4~C2POt zTFS~UG{gQhC6gm9O?7tB@7it0i^8WlRwS~lvSAeCZL}g8%WRKip3zdGtuei-nlLuR zG^Y9(1+hYhKdh$1XF&T+OKNb&bTM*DYLXd)5$v5SV;QhuVF@rQ^D5$7vQHw8n67Tb zyHDrV-D{b;sM@q4)dT}*?N^-%<%z_CDiw(}hDz~&s!LZHP6;_FrhQ^YxzdX&_rU3n z^+O6_nFC@B{f-f8i!rGGT1$-4FrD%U4$;#Q-(tuJx~5AR2PSaYT z(o*GlOvN;wip8%S50+`R$WToSps1vZ8pD^Nr0Vp=i+GJPBq>I!bWahCscNKtW7vN6 z<0zF>?}QWhF6Iv+$B2ri0e8yIAZir)xObukzQ(y4L;j8)*PRSFtkKH9pD!uoHIet6 z-h~tY=ER?}QYT|&#o&M*iG>-TYv^`SM`!2mb9Ah{c`=-O_ z!Z*-M1`<9noaus$h=)+(4>piJU&a^j`w+5E{A*50$a=$xIx0QrL}(dSk^#NKumI~% z*Z2?C1fIpog)&I7fr)gErOvg9X=#w8h;yLIi70ZjDDW%C!-*0VAs!)w&yecK{qKX5 zG}ZAYgaZy$4a3##Jh8<53>ps}!t}douk0Iu`S37%z}tB`pkua*FJjVzLu=q$@?hDk zf)n1kxqgko@VyCo_QzY6ORROJ}~{mjHSP zDYB{PgZw-(e$B$ci16c$P%ublF^`0?H{rVje9-UTap<+Thho0b$Vb{(G<(2p0w#D% z2W$8NaP{U3Tz)9s@PGdChDJ0Dn93ylwV8dI%qYG!L*I+l&cPb3B#VRT{3#q<*Q11f zpK7OiN6U~#^Oxa0>UGaXAzi7$O@D=3p+{fpYGcDDUV{x5EW>mzj>pAbd@KMzFC)75 zgV|U}Ga#llVlQUnPu}Jev+Ky_lSgJ(lU?Y{n5We{zUKKMTU>`DPGIg&`}_al@8Zh3 zyxH~T>17H7>Oo{ZQ4zxhd7B6~h&UxuEvTa5O~%pq>m-=ojf0(Fz4Q0K|7Y@dG7nHF z9>t*^!1Vq;S}eZv4)?#?^Zusaja4^KKEQv4 z`(j&2f8Vo6fAxO8OijvtvsO2bh4<&NU_)-1V{vr!-N6YT3zPel--1ipgP4b=Tv9SA zm;8ydr%0$m_!QK5U{H9ml3}iU4c9jZ%vBd}l6xKM;^!q204Y?5l|;m|sn>a%%+AP} z^ok)w?uK`u7rc_6?|II`SHR;FNsk#{%eNg;V%}G{wrJ4w{#4kOkO)1fezFjjDTv^A zNlKT{*9P7(>xpWKD|*Gso@Z&4J@d(}G=L03;+hZ>DeRS{xdSqbO0m&Dk##=gC&+2T z1d1Se&Mzi{b5xL|;Zi_>`hl$I)^t+3Es zcjJ5Hz4|e}3g^D^OA1=m7n8<{Honw@TOz1~h{2gXr6U%>(RebYEc{*+n<4@PZ>u~^ zXcw2Du)$4CAaQ?RJeVI|Lcy^YlBNcfPW%MpgnneOBBLZ7f$!Cd2G$XxD}owspi~vb zjXYo)ZsbX$>`-aJ7D>jJpu9LT_-wEE(n-+Cq|>2iF3dp=;3R}UmBzFsBLuPNk_(dq zCa{hUxX2(98RT41MP-wYJ-?@g<2p*^K1xg%Y3AF!Zs+Nzwci(C`>=leyGa3R^BSJ4;w64+?4~5VKHOu)zwpJ;H z{8^6EG(Z^>9BAF>}1|Exeq)1#up2U+Oylo{8AoUl;fm9SwKOj~VE@4bJ zMLD3rmf;;D49RYa;N0Q1x3lCd@h$IEyqfh3qDMx6we`=l#0qj76hF>@B~t(?D7x}y zFD!3gU%Wo1Fng1UW!-Z6amH_Yx)*)m(7$YDrAb+wIF+h&>U)|^v>okV8_Ff?(|M<` zg`KIe4mxe}P9;-`G(5S%&pT`MovsGQVevL;Ip}X&^#5#Hthv6ueEUXA#zV!F%4(}c zkhwehS_~UGn_6p$&$FkB?S_2V?tKk^uj_5$2(mbk!g9EfyB6Xb0xJ6b#Pjlxf9Q6A zhTY6L4LOq78tI=m{NRSJY&}lyI>WIeEz$16`1&O)9A?txl6V-BA@Xa#7aGgk_x(7e zfI3tUYJf$T>U!=k1JsWe1syU*L!bqwKy3Zxc9h0G>Z=u@$(A zud~gemRh<$nut*RzEG2_sams=L;(X?|hGt$X8N(}bF2*cr z(@<0!H}KLJut6`%c-cl`SUckIr-BR-K7nq*r+wO3#Ux;GdaBH z^oZramH}g`wM3Kwx2JUNW*hTX*z9^>G(`(lq2PMTiFI$ofv!4<*lF9;;1vuR*h}N1 z{96J-39zUT7l!3xkWBppH#F3?ChK3@^sE{Kn(+NMk0I&5-eBQY3SZ&+qRXor-+p@w zrWO4_{>d`y+2F9Zpv~6U8z60p5l>@KXdR7t;JaN28Bp|vbn8yHR$F^>DxE6SA9hQH zP5Q{&T5GQ38&N?bdcJkX_e(6ROwH%IbH%nr0IGxoN-n93bm?2Hi2=A!wW5)@Lbk+d zT61AmU3G^$%%%D^?g?#U9a(o{rp67?QBjcVyLTI3RJL_?o8X3{L_aN-kes&z^&D9> zQLgU4wg!dOwe4N3xdih_XVc79V%nk=g|bOMgngZyW!yW4435rir*s9w(5bAs}LcPB~Kx0*aP^?ShgH|l{S|vJ7B}EkR_kJU#9ih zK{_O_=LBgVd{&D|v_@I~d!+L-`>M`eD7IgbLJ~*D zbV`K*R6f$h#P-p`m1emn>oKy76~l#sIKvGzX}nt%5RzQPpPYjWU<`8BV*8WqN&QZ0 zn$>bQ0p&KyJTVQUM#vX&c>9U#AaHZiy3sA{QcG>lC<{&DS57=taH(Z;ac~eDM{>IxgJBxaE4?G3vPb!4-WX z4ghu3<{BkvMuK_7YFfqR_dR8qZ@5K=vz%$er_HRy-}LZC8J4)j4BLXL-ymR_L>P8{ zm{MZ~t=Wk#THUj6jMaHZvXES`63tWwsBvj1s^G!^UN-9GBIx*tu0Hc+1Usq5c&1*H zIl89Im;pkcHG?kKCW26I|JYoK$d>&C*xE&s(FHgI7zJA{WafgC9B8?8ogPH@U^kkL zx=IOd6ma-L&ACr)@lZp9n4Js!Dc7CGFNw@MG0~_JnPREK{B->$CL*PyAf&(~WxwCI z#i#-$!)bL61A=j2=&9P~5E)gTVTEQtwkCU)YL(sfLeK~ZzUrHSe|^UZd8Cb5YE90@ zsk=?EcS2&OC6%IFs5|VPhWD3A{%Hin5QXIlrHB|Ehl_AF4rgnBjiP^~HSK}g(;L>P z2~Ydk@Bd07-`=k8Kg{Q2e~G37R6~tN=xc~dtF>+0M!Vd5n=fosw6ZU3H|x=vc!pY{ zysAGRe*w%shKyI^o;4!4)65d;ETV>P|@i zGv$vg)wPrJtumD=R|w7!u>(OGU`jIcLh4G&%OQQ#A8h?e5K_=@&sJ znxSjpBKx?+Sqp+Vm^^AsLotebA?$fhWl&d`GPaQ3{i-xs}D>?n+{@K zy+Hx@r;90UgB!pmlVqyeGu-${1)QLQY9#ug#=VROKmEE|aD8A}<`B!I--QiKqq~G1 zITYa>Jro7-jHB;Xd9}IrA5ce>*6cK4&_ca^v5IgKP9fzENOaZLPf2?H#H0q3493iC zEvu{lHMh=+F)$+NDdI|`s6tf1&uMC-_+4>OkSt>lr&_N{#HH71G?*$G&6R{p;Zau1 zo-)!f3rDGI=%hDG#!+kNr}tY4UrrZWJXn&g#7qHHGqSPh;uw@%L2`pTM!9yYH&ilA z_?Z`5@!DeX%2eSBh;ztRnRDSd7T=!?gN`j+CK#74Pxkbf(PzyUDN5(HnTSJQs~QTb zPLp-|@-VI(|MDo!4$Y}Etc9;U_zOkf*|cfyKV*Ev`70`TfhLuu;5Xf7mJCdlpIo_N zCBU`-M^U(<^NW{m_94rUCZ|bp(;*VZH@Gkn zn?XM$5XDmHbTQ$W4qGl|nHN&8d+=B!rg{xO(f_z`1EeWfdRc;H>5nK7d9Y$CGK8*D zDL#FaW0UYITnZ%Pv+PU0F{%NeI!6+qCt+~U;;98%Qljp_b?X>WcpbSP;=sQ1%)q{w zY+ojI8WfqhPD*!XWw(ZtWpR{{baqhZ3(-^sH9$1-P^EG=lg6iXjbwPVR3^^}bzoGL zTwCHo0AJ3yOj*R%U{A1CgkQ(^jc@}Uwc-Yfry$jbdc2qM((tS05uGX=!#HfaiW7y3 zFn8!gk!YeDjVLZRDB*33J`T-Sp!5c<>L#eZiPs=*i2QuTTVBaTGI3b(V_fD)1{zfif!@+y zCVWk)x2GdknD)jBu$FVDfc6vvDsWoH*lPRqyu<2i##-TVliMW;Q}qH3?`M)do+1c78jJMw9XSe&HWb&9c7uWjFpUJ~0|z z$W%`&g8reGmixbN906=i6QM!4O%JbgX=;a5mkMN`Lkowf2a{CgqxOaral4~kO6@LA zM8#C*W`f9Bj|CZU16zs&R&|U9sFY7a4I)Kx;%6b!&Uce)N!BD)#&upXNhBHS$V4&8 z4i?%)aJOOHhc-nKR&^5??9;)+wtG!?$|1>K^*B>5O_F?S+?gcs5EoGgZ5LfS$2UZP znyZ1x2@=qF;_*E^*+`XWL9V~bx)+0_<5>}f^e-B}mCB2iBATz*axXtn z6WGy&WtQUIXuV7UUfa$W)(w>ia-b7r(%02ei&!*(*pe6knPxjO1B;?oh;Y=<9sZuB z!)+n360>C$)xIf5$yL`LsO$hB7se~D!-NRffj+QRW(i~obAq|f+JPssGjG~9vsLdn z(1RIIjg)@v`s+O2<$OkWRuyY7brmRV4R&Rk#}gZrVjs-dV28&QcP$eXg|o0Zl!k)q zVTDfKxGmSggVjID1%Mq|gY6+b1vUiBx|%hB0#gRecp;dUdD9~6+3N8-Rt`WW(sar!PX$Vh z$AD?Ufp#S)1sCt#fzqQRV1))N*|Y8hp5gcajY4u`VO zvu3->q-mWJ+9n@eyUX0A)={asWZt=4GQ}yf!d603xq`t~lciG*)Xr5%jj5lqs^9aAdBGd~F9u3EJmSBaY zh$LJ*mxI``_6~`Fq)C01rS98Ld;F;=Xqsk_Gc({vg}! ztlrO;X);6K$XMyaN`h!in1#;iFPVj2l)v%l=(~fHzv=8gAxhIyR24fpN7*Lk;=aff z_WFQc(mpb~M`=9O8PlcVu_}H+eSP}-!iA)0mYg!bKiMZ{jxBeA&%R`c%pXR zxgjppwrS;|TXnRwZE2z?HSuTjCjIEzB*kx_$#0FQivRP!#y)O~{$W~bp2s=}=^p{r z>UE$TT1RRP%kAdI2yduM$kop>$Gi}!Y$g-{y)kb!MU40=~f@8s9z&G-{E3(=EtFuR{)DCIJjrDVZ% zjHHy5#+1ih0~Vt$_||Rqk)CE7PD^)m(vAxt_X?>l=|P4`Fws8rS6zeiYO`aPF@s?` z*BD~{f_0Uspdr8wq^d(>XLB`Z_Xs%(l&w?S+ef_iaUD%o@C+ed5|u8)Rc|tXP=6KQ zbM_Q}C4L%*caL~%y^LlLJ@L!^BzRas$sNs?<8axVqTYBodkB}LC(B}jy~Q#dN26dJ z_GST|@B_G`Cc#}eS@ps%DDxXE7CZ~R9Xx~*kgwW@1VS%(e4y0-aO{tRbvvZ-eeJXJ{<~j(&^{SlzQ58w_^-Fu`q=&J>#J++k@s(J-(F~++zc-I zm$yA|hb4-b`M7L{%V-Xc_f?bPGugRO@Of`TKi0IT6a)fP9uc|TACfNFZO-G&BG*Y# zz2VZP)^V444Fxw8H*}~gd$DkDRO;FVcB+yvPA z;OX`@G4`qNqX4Ks3Kp$^ZVulp@Yv6*R<`r-E_{e)tzbkQx>;=OVMZ6D2Nx&w=my-oXPfu6FM07&Z zZrqQ>57s0pwQ?Su^Rz`%5Xr_cXe}RM1;d(zq%&-VxF|`-Jr|k4k0V&+9+s#c&qzko zoIzYYM^m+%VL25bK~#?6!f%3NNvBkCLNwJ9_A_Sc9QUQ+Xb1CBixv7`YGY}Jz##cV zv!`GgQS&Ep*Eh_KK*Hp7@kMK`Sl^_&N7)fPH5-@inv z$-xykQ5a0EIvL(BOm9C6<9>fS9e&tHU)SU*`htB1XVAKd{hyO*-+zS20##OgL`=k( z%}Z@q7+uEaRhp{c*n6~$bXILaN53xhZ>$v|Ey%HoeGCcDNP>(y>-ZxJ|Ghs_*c4o8 zoLP2q-C!`$-EhL1hlIE@d9&UwgV`z=arZQ*f#!%!E5Ulc^w-NETCa@sj1BXH@=lX$ zoO)DJf$S%$@IAcssem6sF4YJPul{@#k!(+ye@+d6()aT%Y`U3D@$PQIii#6Y;6%X( zrk}zGhhsMOsdV|9+2drgSYro_Xn|yJHh{_D8s?~6xU{;-nWC<-e!fo|-$QC}lk6eO zn4g2?SaeS&k`B4MA!U@K;op3IK_rwV)PN7iRb~3r8Zh?$r^8cMQy`yPZHfn1%YEv% z2*2r51QdT23^##C6s)1noJO@8q9P<5;O{l(9i($4OW3ecy+1PeOV57-0sIH5)kGs7 z2~)(kf&7P&-}}S(P%VeKuYETd5th8s#~?Y(BOFJzT=Z| zzGrMBN+78x^Syo?i!DJ6MKl$oYQ7qbIDeArSm?Z|5KfW-Pont>`;PKL6dP7?B-*e; z0h!ozwAhW|t2W}bQK+%#ny%qlZ`j2=CV=8rQnXNeywOim3gOx>Z--2CD-0#r)VIlnm^ zRUtk3YUOFULq~J0MIa%ET~z_}7+W%lP*Q?$6#rZS&FU~!z&JuTv4k&{3#k(BG{S{2Q|i%3$u(^HO4$#jv>+sa#k+A8YAulN#^mWI~*stdVA_t zuoTL1z%h+t+GK|c?X*G2sWM9>t&p)gupvc>FtgNP{D*h5lJ4OLnwz3x|HjrPCy zj(-k5g*WT*)uV0b89q&WIbYNHHw<5yW;TjPzfA3vv86++>%5>5PYCG^Z@02_F~;W;zAm*6`Gb8%8cJ zfwy@ZHGrq0`Z@<}ei~~fjRm8E=OTNCQk0PuVp+eF>=`2pcau38M!cLP6FW;^i|J4A zU6nao(WF)uQS;%^Kn^z7kzvyad1kmhKvF}x|8$yab4H80SgsrlH|{b?xSHjAwcH~^ zHTwf~^EA~fm&R=GL_Q1G9BRH}UAU4yggA5A>#BCX-i^0&L{t+j(dhST={u+MF4IPQE zU4!OIlXhOV%bKE#2brRxYj&-8D^?K8gJVu+p32}On06L$Y5B+zzFPEFALoygu}|5_ zdam@>_*YIc7Fp6VMoFY3i_b**F{KrcR$4mcG?+#Ah}cA|^d#gYN?FiAkDNdl&3Hcb zgV6{8CPfdZh%XvBu+erhpV80U@Pt00>@4LsA~Vg?&fp+SD3D0Yr(M!L;9CPzJ1QS zm!Bp{_&#x|)tk7Ur6%bU2jw9?g^4n;1viSh4anFAaOG02oUP4p&M&_*H4A5QcbWr*gpVDg4UKQ}>?9=8iLk=>GI zU3oC@E1g+!-6RI6OofFlUonQ|0!3*vumK%o1JTVVQD;gP8EIrDQ-^fKd>e}?Oa}YC%oI}d7>v%@qlTPQ{_c5m#zD()gZS1K$%Oqr<4PC_LrbA2jD=T4X2Rw(~ z6N7*f%bq8P)uetz!jQ!@rGC;#gflIv2wYwy>l7%HB|DWri-ro?3QJvT*Sbdde7>!z(75ceRP29d+Lb~ng<&tLAIZTJYNIiqLDrb910=|!@)n{k=vTyZptvA>b7Vwl8x*>l z2=_NxFigq9AV*@rEo7%4wH z;+g<8#cFat#)6m5>635ukIVCIaBg>FoEE%ed7Wljm`<~%Zmo#@+<>LAhO9TGziyG{ z1bHfjOQu(7_$rbvX@OZmI!-#zo=`UME@H&WF!^p60 z%lVu`@%e{s!k7Tfryx$U{}7z?3;oEA-()OT>^L;EDkc6%k7V0;J(`cl))ewl$|*H* z_BlykL`|QuS8OZJA^^HVlhEED0{>fssI&)+h)a|CJUYQsl~9&jWJ^)iKO4JLTU4KIrq*7;r%CJ)bv%O=Ewi1*LF=Mief9(0^(f$1`HAXeKi@Bz9 zhba5Pt2=I-ibRpwl)q?%u{`H}XR>iNeI;3pb=R#0B`5+!-Em#`+=|;eZ8Mf0j_2Io zZG$JvWAdChQd_uf1rbR%_!dc_#NeYDT2rk3$656IBh1tvU`;%r$iBe`azv9yu*Ydz zu0t=yzq$wCHFlHfKaxRzyOV?)ZUsr$_y_h;iAf08I@2DIj7+9p`86SkKV-q#y>qJc z_?(B)UMQ71GU;r4p{>3xTfI(H%!`lz^l`F|`c7cAN47>$r4nQs?5}f+sMUuEQdzA~ zT|19WXEFzf)AkVCvyt#~F?iZ;<}5~Wk3TC*bHZJn3U7Yg9_ticLCcT}=keCWAr7Ln znd|;x)z^A{YiR5cr4CR9ruyc*o|W7Twuj76UrzFH!JyW0@w`|7k~WR}6yj@~96mh8 zSkIA&Z5ml{E-3Q^g-_xmv^9i;>Ns>>>zoOpGLWyql>ZZ>lleti%S~(%$Ts054J%Q| zMAITN;{=+9Z3mV#vZZaywFH&!9(7qz?jX4LC-cw!YradR<+I?KBIOUntBtfhYXsj& zA^R9Td~9fuG}QL25*KZ<${Odi-2UIZ=kQMiIOzniHE2nLX>px9mEo-cmE!w3@=))K z`hgsOTf;B1VI=$(3{`w?K|BM?*(L>e zEN@!rRi>g6AuK~9V&@LK8r1rGYKaD=ET4!PaMM&n;~TovJ`Qb0RR$Db02fipFW@&P zj%2Y01n!GKuy?xr)%+Y+H<%)tp$uFwiT;HIlnJ^L>qoFW-W3hAd5CY;-jNCLfVw{S z{=g1s;%dW_E3pd1pruby=N4q{SHI#lcaAxc#zS5Vg&uw&ag#(*f+eT%})15{9@O2V)gsYg_2 zcP})gOWa23W!^6D(>?x91m-_dPDHc>5IGVr3^OWhR?)$m58QzR$8;TevWoauuY zezUcKNe8d+khOfw%HcNui18W8e`I@4VY}z>0G_U~nWfh7G3jECqmev{n#S7nN=EHt z>v)uKl{S}hIO<^M55wtV{k3iKa@6Q8QllW>PT(l15!V||Zj-hqDO9&3A9}Xr81*_} zPXG^0>YSIY*HKd0$g0*+a+v&D9VG`ddOS9^f0{Xo%6bo}a)hRUH#S#lX@b8`6cBHo zAWKx_XbS|R5(my+^OZRA&rr+(N&;fJdK%k#0;E8#3vwp3NE!v9AT+cHMHA&KT1He8 zAf{MMEVXd5P-!z=!AQQIAiluT){%EarlO( z*bC70DQ57k?MNq+c>9z$n2>18(x6((xlQ@msLY^RRvV@S*!U^khuG;Ux|ku)M?dAS z(uC(q`)LWU@F`HpKAC8A8v*$yvNC(f5usPklO8Ka82tOhM-gvg2h?&!#L~e$ono)6 zMP+-|TEwUl@!lCZwn-uBda62FiXEvA)*vt9w&aNvRo!u-n~PTYgEN=6VGb_SbK8v# zIG~8$_GPh-ra2tVA7`m(*%n269^%*$L~)1NV&o|w(2;FTsC7);BG>l3#|7H5stZ*< zXnCQ^ObLOux1-_jk7xvp#^4V~Iw#fS-$oYIg8g2lyxp=l&+`fsk1m6os?Ljcq zTjzLH>jhC^g<1U{lo&+=F*%{G#*>LvLC0GK!`Ic_Zzw_iPwFwg>hV86&L`t=iC$Uj zmETMK!{kMoP7$GtPXlT*u1}3xdeO*7(Q5Q4e>3_REDeb1BWc5?%?}< zJyk8UM-XYAhYXU4s#8H3j7Vekl-UO(ZU&@8U*ZFF1e)&Cf1_RW27>t!@p`b{m^Pbd z0s;E@bV0pS!!h@`b@cz~YDcJmR7Sg4?_eC>2Pn>fM8`?E4rwzQ+7@c1Mtx6v`V2Y+ zc7}q2WJ!eAB1%B3l^cq74OamI-j1Cu(XFaMuH&K3-9M>YaN>q-rge*=W2EnOv4K_z0yAJ z%^s(B`1al$k1r=D2*fZmKmb)bUm>z}zoK+B+cPZ*`z}+$zM9F&wuIg!nnr6ArQZJR zaWc7qeFWMu+Il@UyMKSKoXHE$Z z({LFP7fXINp8{A3G0Pv#XR!FUWW?ri_$TuTj3R8~{D}C`e8vNY&*rlygsDZ?>f1Tp zDW}XQsX0I&Flt|$@2h>F6b_)Jk0_rflBe>S8gHO{jGB3z9`YMaseFzgQO8Hzp9j{eoJ_<`nb0jt$>MWJeZ9`npOSPfa)lKFPZ%14yG=@yR!Mcj1Wu#P*$3J z>39*#0|zsABmGnv1|L$P@iof-%*LNQ&yoo|mrUTzC%pVE#>*4_cc z6#?cY6pt17y8b~=e7Q3BZx_l!tc(yjxz&bV`p|~=rx^q2jM`IYZGit|PpaW)7do3< zYsM?-6Xp(hyFloMx6>!Aw-46yoAuX8I8JVF{R8ubq#DcUamj^iV=+n9e~$SwmSrE_ z!Df<(*EiuLZs8;4Y0rMz7P=h|O{4VY64-P+w2x9%Ai3lka6EE|fID23`41h;K)f5C z@ph-o{fN%-X!=X;^x9h_;^#hnh#-ORUI4-ukZVB&o;i(XNXcb`0c1M)GfkZ}>ghO4 z-$;JW1=d6O-*oY~4$o2CD430;vSfUkI|f9?K1G7XdmaCl2dJv4T68FaEg&93J&{#O zw1?7>_qES0mD|(5N5L7E(**kT??fdOiCXJBraaesvWQJg-TI4(+1~kPY|9qko$yMu zMe}lq)!2uR#g@z$^>sQ%))(u3Kv}Wl0b|*YCycc_o=7|jybxh|NK14mA13Tfl77y! z-T|(gtNVNW7jhnwWF~a~C?6!mBL-2PzaZO``aFM-Qoeivj9M8F=Uo3F=LIo?@n!O9=Ch~*!M1v7mZG95>IcU2#~A77a2>>4CjQNM$RqV`K6whS z!+UUH;%CIJ%?}H`MN;+%{dq=DYc2_o=vHX6fiOngBzh03k9}UoHO~ga58hG#%Q~E` zqWSCsEEPsgQHM;{H%mgjh`;Ta&+dqf^fVNjikod1UY?^eAj$Jv@*QTMW!|wXTy0*D z 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�Cg+$YsaXYKyMhPt`E9t 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%0A!G^9&~AlV}9gWBA{szD&`Q+BRD-5OG>D+56@ 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%0Ab_Q@79zsz0OXGc?D;GZW={1 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 AX8-^I literal 1571392 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 z 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 &qYr?z#u(OoLd& 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 (L0Q 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≺`TUXc4~#8OJvFkT;<-^3K3`~+AA4@}=0TCi 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%0AP{*}Da@MCcK>>igKdL4aEbj!Gu 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 N@9YhPTk=Wp{|}gD> 48)& 0xffffULL) #define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) #define XR_VERSION_PATCH(version) (uint32_t)((uint64_t)(version) & 0xffffffffULL) +#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16 + + #if !defined(XR_NULL_HANDLE) #if (XR_PTR_SIZE == 8) && XR_CPP_NULLPTR_SUPPORTED #define XR_NULL_HANDLE nullptr @@ -120,7 +123,6 @@ XR_DEFINE_HANDLE(XrActionSet) #define XR_MAX_PATH_LENGTH 256 #define XR_MAX_STRUCTURE_NAME_SIZE 64 #define XR_MAX_RESULT_STRING_SIZE 64 -#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16 #define XR_MAX_ACTION_SET_NAME_SIZE 64 #define XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE 128 #define XR_MAX_ACTION_NAME_SIZE 64 @@ -181,13 +183,37 @@ typedef enum XrResult { XR_ERROR_LOCALIZED_NAME_DUPLICATED = -48, XR_ERROR_LOCALIZED_NAME_INVALID = -49, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING = -50, + XR_ERROR_RUNTIME_UNAVAILABLE = -51, XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR = -1000003000, XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR = -1000003001, XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT = -1000039001, XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT = -1000053000, XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT = -1000055000, + XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT = -1000066000, + XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT = -1000097000, + XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT = -1000097001, + XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT = -1000097002, + XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT = -1000097003, + XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT = -1000097004, + XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT = -1000097005, XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB = -1000101000, XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB = -1000108000, + XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB = -1000113000, + XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB = -1000113001, + XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB = -1000113002, + XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB = -1000113003, + XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB = -1000118000, + XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB = -1000118001, + XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB = -1000118002, + XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB = -1000118003, + XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB = -1000118004, + XR_ERROR_UNKNOWN_PASSTHROUGH_FB = -1000118050, + XR_ERROR_RENDER_MODEL_KEY_INVALID_FB = -1000119000, + XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020, + XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000, + XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001, + XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001, + XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002, XR_RESULT_MAX_ENUM = 0x7FFFFFFF } XrResult; @@ -242,17 +268,6 @@ typedef enum XrStructureType { XR_TYPE_ACTIONS_SYNC_INFO = 61, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO = 62, XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO = 63, - //pico add new type - XR_TYPE_EVENT_CONTROLLER_STATE_CHANGED = 1200006064, - XR_TYPE_EVENT_SEETHROUGH_STATE_CHANGED = 1200006065, - XR_TYPE_EVENT_HARDIPD_STATE_CHANGED = 1200006066, - XR_TYPE_EVENT_KEY_EVENT = 1200006067, - XR_TYPE_EVENT_FOVEATION_LEVEL_CHANGED = 1200006068, - XR_TYPE_EVENT_FRUSTUM_STATE_CHANGED = 1200006069, - XR_TYPE_EVENT_RENDER_TEXTURE_CHANGED = 1200006070, - XR_TYPE_EVENT_TARGET_FRAME_RATE_STATE_CHANGED = 1200006071, - XR_TYPE_EVENT_MRC_STATUS_CHANGED = 1200006072, - XR_TYPE_EVENT_REFRESH_RATE_CHANGE = 1200006073, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR = 1000006000, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR = 1000008000, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR = 1000010000, @@ -291,9 +306,14 @@ typedef enum XrStructureType { XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR = 1000034000, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT = 1000039000, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT = 1000039001, + XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB = 1000040000, + XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB = 1000041001, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT = 1000046000, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX = 1000048004, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT = 1000049000, + XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT = 1000049001, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT = 1000049002, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT = 1000049003, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT = 1000051000, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT = 1000051001, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT = 1000051002, @@ -317,16 +337,118 @@ typedef enum XrStructureType { XR_TYPE_CONTROLLER_MODEL_STATE_MSFT = 1000055004, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC = 1000059000, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT = 1000063000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT = 1000066000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT = 1000066001, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000, + XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB = 1000072000, + XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT = 1000078000, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000, + XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT = 1000080000, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR = 1000089000, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR = 1000090000, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR = 1000090001, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR = 1000090003, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR = 1000091000, + XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT = 1000097000, + XR_TYPE_SCENE_CREATE_INFO_MSFT = 1000097001, + XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT = 1000097002, + XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT = 1000097003, + XR_TYPE_SCENE_COMPONENTS_MSFT = 1000097004, + XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT = 1000097005, + XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT = 1000097006, + XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT = 1000097007, + XR_TYPE_SCENE_OBJECTS_MSFT = 1000097008, + XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT = 1000097009, + XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT = 1000097010, + XR_TYPE_SCENE_PLANES_MSFT = 1000097011, + XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT = 1000097012, + XR_TYPE_SCENE_MESHES_MSFT = 1000097013, + XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT = 1000097014, + XR_TYPE_SCENE_MESH_BUFFERS_MSFT = 1000097015, + XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT = 1000097016, + XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT = 1000097017, + XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT = 1000097018, + XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT = 1000098000, + XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT = 1000098001, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB = 1000101000, + XR_TYPE_VIVE_TRACKER_PATHS_HTCX = 1000103000, + XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX = 1000103001, + XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC = 1000104000, + XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC = 1000104001, + XR_TYPE_FACIAL_EXPRESSIONS_HTC = 1000104002, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB = 1000108000, + XR_TYPE_HAND_TRACKING_MESH_FB = 1000110001, + XR_TYPE_HAND_TRACKING_SCALE_FB = 1000110003, + XR_TYPE_HAND_TRACKING_AIM_STATE_FB = 1000111001, + XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB = 1000112000, + XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB = 1000113004, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB = 1000113003, + XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB = 1000113007, + XR_TYPE_SPACE_COMPONENT_STATUS_FB = 1000113001, + XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB = 1000113005, + XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB = 1000113006, + XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB = 1000114000, + XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB = 1000114001, + XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB = 1000114002, + XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB = 1000115000, + XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB = 1000116009, + XR_TYPE_KEYBOARD_TRACKING_QUERY_FB = 1000116004, + XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB = 1000116002, + XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB = 1000117001, + XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB = 1000118000, + XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001, + XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002, + XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003, + XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB = 1000118004, + XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB = 1000118005, + XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB = 1000118021, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB = 1000118022, + XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB = 1000118023, + XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB = 1000118030, + XR_TYPE_RENDER_MODEL_PATH_INFO_FB = 1000119000, + XR_TYPE_RENDER_MODEL_PROPERTIES_FB = 1000119001, + XR_TYPE_RENDER_MODEL_BUFFER_FB = 1000119002, + XR_TYPE_RENDER_MODEL_LOAD_INFO_FB = 1000119003, + XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB = 1000119004, + XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB = 1000119005, XR_TYPE_BINDING_MODIFICATIONS_KHR = 1000120000, + XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO = 1000121000, + XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO = 1000121001, + XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO = 1000121002, + XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO = 1000122000, + XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO = 1000124000, + XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO = 1000124001, + XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO = 1000124002, + XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT = 1000142000, + XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT = 1000142001, + XR_TYPE_SPACE_QUERY_INFO_FB = 1000156001, + XR_TYPE_SPACE_QUERY_RESULTS_FB = 1000156002, + XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB = 1000156003, + XR_TYPE_SPACE_UUID_FILTER_INFO_FB = 1000156054, + XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB = 1000156052, + XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB = 1000156103, + XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB = 1000156104, + XR_TYPE_SPACE_SAVE_INFO_FB = 1000158000, + XR_TYPE_SPACE_ERASE_INFO_FB = 1000158001, + XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB = 1000158106, + XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB = 1000158107, + XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB = 1000160000, + XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB = 1000161000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB = 1000162000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB = 1000163000, + XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB = 1000171000, + XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB = 1000171001, + XR_TYPE_SEMANTIC_LABELS_FB = 1000175000, + XR_TYPE_ROOM_LAYOUT_FB = 1000175001, + XR_TYPE_BOUNDARY_2D_FB = 1000175002, + XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE = 1000196000, + XR_TYPE_SPACE_CONTAINER_FB = 1000199000, + XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB = 1000203002, + XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB = 1000204000, + XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META = 1000227000, + XR_TYPE_PERFORMANCE_METRICS_STATE_META = 1000232001, + XR_TYPE_PERFORMANCE_METRICS_COUNTER_META = 1000232002, XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, @@ -359,6 +481,7 @@ typedef enum XrReferenceSpaceType { XR_REFERENCE_SPACE_TYPE_LOCAL = 2, XR_REFERENCE_SPACE_TYPE_STAGE = 3, XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000, + XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000, XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF } XrReferenceSpaceType; @@ -401,7 +524,17 @@ typedef enum XrObjectType { XR_OBJECT_TYPE_ACTION = 6, XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000019000, XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT = 1000039000, + XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT = 1000049000, XR_OBJECT_TYPE_HAND_TRACKER_EXT = 1000051000, + XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT = 1000097000, + XR_OBJECT_TYPE_SCENE_MSFT = 1000097001, + XR_OBJECT_TYPE_FACIAL_TRACKER_HTC = 1000104000, + XR_OBJECT_TYPE_FOVEATION_PROFILE_FB = 1000114000, + XR_OBJECT_TYPE_TRIANGLE_MESH_FB = 1000117000, + XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000, + XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002, + XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000, XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } XrObjectType; typedef XrFlags64 XrInstanceCreateFlags; @@ -443,6 +576,7 @@ static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT = 0x00000 static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT = 0x00000020; static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT = 0x00000040; static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND = 0x00000080; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR = 0x00000080; // alias of XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND typedef XrFlags64 XrCompositionLayerFlags; @@ -555,6 +689,7 @@ typedef struct XrVector3f { float z; } XrVector3f; +// XrSpaceVelocity extends XrSpaceLocation typedef struct XrSpaceVelocity { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1307,7 +1442,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback( XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback( XrSession session, const XrHapticActionInfo* hapticActionInfo); -#endif +#endif /* !XR_NO_PROTOTYPES */ #define XR_KHR_composition_layer_cube 1 @@ -1327,8 +1462,9 @@ typedef struct XrCompositionLayerCubeKHR { #define XR_KHR_composition_layer_depth 1 -#define XR_KHR_composition_layer_depth_SPEC_VERSION 5 +#define XR_KHR_composition_layer_depth_SPEC_VERSION 6 #define XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME "XR_KHR_composition_layer_depth" +// XrCompositionLayerDepthInfoKHR extends XrCompositionLayerProjectionView typedef struct XrCompositionLayerDepthInfoKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1409,18 +1545,21 @@ typedef struct XrEventDataVisibilityMaskChangedKHR { typedef XrResult (XRAPI_PTR *PFN_xrGetVisibilityMaskKHR)(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetVisibilityMaskKHR( XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_KHR_composition_layer_color_scale_bias 1 #define XR_KHR_composition_layer_color_scale_bias_SPEC_VERSION 5 #define XR_KHR_COMPOSITION_LAYER_COLOR_SCALE_BIAS_EXTENSION_NAME "XR_KHR_composition_layer_color_scale_bias" +// XrCompositionLayerColorScaleBiasKHR extends XrCompositionLayerBaseHeader typedef struct XrCompositionLayerColorScaleBiasKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1441,9 +1580,11 @@ typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR { typedef XrResult (XRAPI_PTR *PFN_xrInitializeLoaderKHR)(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR( const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_KHR_composition_layer_equirect2 1 @@ -1468,11 +1609,12 @@ typedef struct XrCompositionLayerEquirect2KHR { #define XR_KHR_binding_modification 1 #define XR_KHR_binding_modification_SPEC_VERSION 1 #define XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME "XR_KHR_binding_modification" -typedef struct XrBindingModificationBaseHeaderKHR { +typedef struct XR_MAY_ALIAS XrBindingModificationBaseHeaderKHR { XrStructureType type; const void* XR_MAY_ALIAS next; } XrBindingModificationBaseHeaderKHR; +// XrBindingModificationsKHR extends XrInteractionProfileSuggestedBinding typedef struct XrBindingModificationsKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1482,8 +1624,13 @@ typedef struct XrBindingModificationsKHR { +#define XR_KHR_swapchain_usage_input_attachment_bit 1 +#define XR_KHR_swapchain_usage_input_attachment_bit_SPEC_VERSION 3 +#define XR_KHR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_KHR_swapchain_usage_input_attachment_bit" + + #define XR_EXT_performance_settings 1 -#define XR_EXT_performance_settings_SPEC_VERSION 1 +#define XR_EXT_performance_settings_SPEC_VERSION 3 #define XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME "XR_EXT_performance_settings" typedef enum XrPerfSettingsDomainEXT { @@ -1525,31 +1672,35 @@ typedef struct XrEventDataPerfSettingsEXT { typedef XrResult (XRAPI_PTR *PFN_xrPerfSettingsSetPerformanceLevelEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrPerfSettingsSetPerformanceLevelEXT( XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_thermal_query 1 -#define XR_EXT_thermal_query_SPEC_VERSION 1 +#define XR_EXT_thermal_query_SPEC_VERSION 2 #define XR_EXT_THERMAL_QUERY_EXTENSION_NAME "XR_EXT_thermal_query" typedef XrResult (XRAPI_PTR *PFN_xrThermalGetTemperatureTrendEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrThermalGetTemperatureTrendEXT( XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_debug_utils 1 XR_DEFINE_HANDLE(XrDebugUtilsMessengerEXT) -#define XR_EXT_debug_utils_SPEC_VERSION 3 +#define XR_EXT_debug_utils_SPEC_VERSION 4 #define XR_EXT_DEBUG_UTILS_EXTENSION_NAME "XR_EXT_debug_utils" typedef XrFlags64 XrDebugUtilsMessageSeverityFlagsEXT; @@ -1600,6 +1751,7 @@ typedef XrBool32 (XRAPI_PTR *PFN_xrDebugUtilsMessengerCallbackEXT)( void* userData); +// XrDebugUtilsMessengerCreateInfoEXT extends XrInstanceCreateInfo typedef struct XrDebugUtilsMessengerCreateInfoEXT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1618,6 +1770,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrSessionEndDebugUtilsLabelRegionEXT)(XrSession typedef XrResult (XRAPI_PTR *PFN_xrSessionInsertDebugUtilsLabelEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrSetDebugUtilsObjectNameEXT( XrInstance instance, const XrDebugUtilsObjectNameInfoEXT* nameInfo); @@ -1646,18 +1799,21 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT( XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT( XrSession session, const XrDebugUtilsLabelEXT* labelInfo); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_eye_gaze_interaction 1 -#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 1 +#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 2 #define XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME "XR_EXT_eye_gaze_interaction" +// XrSystemEyeGazeInteractionPropertiesEXT extends XrSystemProperties typedef struct XrSystemEyeGazeInteractionPropertiesEXT { XrStructureType type; void* XR_MAY_ALIAS next; XrBool32 supportsEyeGazeInteraction; } XrSystemEyeGazeInteractionPropertiesEXT; +// XrEyeGazeSampleTimeEXT extends XrSpaceLocation typedef struct XrEyeGazeSampleTimeEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1667,18 +1823,18 @@ typedef struct XrEyeGazeSampleTimeEXT { #define XR_EXTX_overlay 1 -#define XR_EXTX_overlay_SPEC_VERSION 4 +#define XR_EXTX_overlay_SPEC_VERSION 5 #define XR_EXTX_OVERLAY_EXTENSION_NAME "XR_EXTX_overlay" typedef XrFlags64 XrOverlaySessionCreateFlagsEXTX; // Flag bits for XrOverlaySessionCreateFlagsEXTX -static const XrOverlaySessionCreateFlagsEXTX XR_OVERLAY_SESSION_CREATE_RELAXED_DISPLAY_TIME_BIT_EXTX = 0x00000001; typedef XrFlags64 XrOverlayMainSessionFlagsEXTX; // Flag bits for XrOverlayMainSessionFlagsEXTX static const XrOverlayMainSessionFlagsEXTX XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX = 0x00000001; +// XrSessionCreateInfoOverlayEXTX extends XrSessionCreateInfo typedef struct XrSessionCreateInfoOverlayEXTX { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1707,7 +1863,7 @@ typedef struct XrEventDataMainSessionVisibilityChangedEXTX { #define XR_MSFT_spatial_anchor 1 XR_DEFINE_HANDLE(XrSpatialAnchorMSFT) -#define XR_MSFT_spatial_anchor_SPEC_VERSION 1 +#define XR_MSFT_spatial_anchor_SPEC_VERSION 2 #define XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME "XR_MSFT_spatial_anchor" typedef struct XrSpatialAnchorCreateInfoMSFT { XrStructureType type; @@ -1729,6 +1885,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorSpaceMSFT)(XrSession sessi typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorMSFT)(XrSpatialAnchorMSFT anchor); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorMSFT( XrSession session, const XrSpatialAnchorCreateInfoMSFT* createInfo, @@ -1741,7 +1898,50 @@ XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorSpaceMSFT( XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT( XrSpatialAnchorMSFT anchor); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_image_layout 1 +#define XR_FB_composition_layer_image_layout_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_IMAGE_LAYOUT_EXTENSION_NAME "XR_FB_composition_layer_image_layout" +typedef XrFlags64 XrCompositionLayerImageLayoutFlagsFB; + +// Flag bits for XrCompositionLayerImageLayoutFlagsFB +static const XrCompositionLayerImageLayoutFlagsFB XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB = 0x00000001; + +// XrCompositionLayerImageLayoutFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerImageLayoutFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrCompositionLayerImageLayoutFlagsFB flags; +} XrCompositionLayerImageLayoutFB; + + + +#define XR_FB_composition_layer_alpha_blend 1 +#define XR_FB_composition_layer_alpha_blend_SPEC_VERSION 2 +#define XR_FB_COMPOSITION_LAYER_ALPHA_BLEND_EXTENSION_NAME "XR_FB_composition_layer_alpha_blend" + +typedef enum XrBlendFactorFB { + XR_BLEND_FACTOR_ZERO_FB = 0, + XR_BLEND_FACTOR_ONE_FB = 1, + XR_BLEND_FACTOR_SRC_ALPHA_FB = 2, + XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB = 3, + XR_BLEND_FACTOR_DST_ALPHA_FB = 4, + XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB = 5, + XR_BLEND_FACTOR_MAX_ENUM_FB = 0x7FFFFFFF +} XrBlendFactorFB; +// XrCompositionLayerAlphaBlendFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerAlphaBlendFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBlendFactorFB srcFactorColor; + XrBlendFactorFB dstFactorColor; + XrBlendFactorFB srcFactorAlpha; + XrBlendFactorFB dstFactorAlpha; +} XrCompositionLayerAlphaBlendFB; + #define XR_MND_headless 1 @@ -1757,6 +1957,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT( #define XR_EXT_view_configuration_depth_range 1 #define XR_EXT_view_configuration_depth_range_SPEC_VERSION 1 #define XR_EXT_VIEW_CONFIGURATION_DEPTH_RANGE_EXTENSION_NAME "XR_EXT_view_configuration_depth_range" +// XrViewConfigurationDepthRangeEXT extends XrViewConfigurationView typedef struct XrViewConfigurationDepthRangeEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1769,7 +1970,7 @@ typedef struct XrViewConfigurationDepthRangeEXT { #define XR_EXT_conformance_automation 1 -#define XR_EXT_conformance_automation_SPEC_VERSION 1 +#define XR_EXT_conformance_automation_SPEC_VERSION 3 #define XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME "XR_EXT_conformance_automation" typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceActiveEXT)(XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrBool32 isActive); typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateBoolEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrBool32 state); @@ -1778,6 +1979,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateVector2fEXT)(XrSession ses typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceLocationEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrSpace space, XrPosef pose); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceActiveEXT( XrSession session, XrPath interactionProfile, @@ -1808,12 +2010,15 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceLocationEXT( XrPath inputSourcePath, XrSpace space, XrPosef pose); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_spatial_graph_bridge 1 -#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 1 +XR_DEFINE_HANDLE(XrSpatialGraphNodeBindingMSFT) +#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 2 #define XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME "XR_MSFT_spatial_graph_bridge" +#define XR_GUID_SIZE_MSFT 16 typedef enum XrSpatialGraphNodeTypeMSFT { XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT = 1, @@ -1824,18 +2029,56 @@ typedef struct XrSpatialGraphNodeSpaceCreateInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; XrSpatialGraphNodeTypeMSFT nodeType; - uint8_t nodeId[16]; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; XrPosef pose; } XrSpatialGraphNodeSpaceCreateInfoMSFT; +typedef struct XrSpatialGraphStaticNodeBindingCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialGraphStaticNodeBindingCreateInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpatialGraphNodeBindingPropertiesGetInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; + XrPosef poseInNodeSpace; +} XrSpatialGraphNodeBindingPropertiesMSFT; + typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialGraphNodeSpaceMSFT)(XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrTryCreateSpatialGraphStaticNodeBindingMSFT)(XrSession session, const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, XrSpatialGraphNodeBindingMSFT* nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialGraphNodeBindingMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpatialGraphNodeBindingPropertiesMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding, const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, XrSpatialGraphNodeBindingPropertiesMSFT* properties); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT( XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space); -#endif + +XRAPI_ATTR XrResult XRAPI_CALL xrTryCreateSpatialGraphStaticNodeBindingMSFT( + XrSession session, + const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, + XrSpatialGraphNodeBindingMSFT* nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialGraphNodeBindingMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpatialGraphNodeBindingPropertiesMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding, + const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, + XrSpatialGraphNodeBindingPropertiesMSFT* properties); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_hand_interaction 1 @@ -1848,7 +2091,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT( #define XR_HAND_JOINT_COUNT_EXT 26 XR_DEFINE_HANDLE(XrHandTrackerEXT) -#define XR_EXT_hand_tracking_SPEC_VERSION 2 +#define XR_EXT_hand_tracking_SPEC_VERSION 4 #define XR_EXT_HAND_TRACKING_EXTENSION_NAME "XR_EXT_hand_tracking" typedef enum XrHandEXT { @@ -1889,8 +2132,10 @@ typedef enum XrHandJointEXT { typedef enum XrHandJointSetEXT { XR_HAND_JOINT_SET_DEFAULT_EXT = 0, + XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP = 1000149000, XR_HAND_JOINT_SET_MAX_ENUM_EXT = 0x7FFFFFFF } XrHandJointSetEXT; +// XrSystemHandTrackingPropertiesEXT extends XrSystemProperties typedef struct XrSystemHandTrackingPropertiesEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1931,6 +2176,7 @@ typedef struct XrHandJointLocationsEXT { XrHandJointLocationEXT* jointLocations; } XrHandJointLocationsEXT; +// XrHandJointVelocitiesEXT extends XrHandJointLocationsEXT typedef struct XrHandJointVelocitiesEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1943,6 +2189,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrDestroyHandTrackerEXT)(XrHandTrackerEXT handT typedef XrResult (XRAPI_PTR *PFN_xrLocateHandJointsEXT)(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandTrackerEXT( XrSession session, const XrHandTrackerCreateInfoEXT* createInfo, @@ -1955,11 +2202,12 @@ XRAPI_ATTR XrResult XRAPI_CALL xrLocateHandJointsEXT( XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_hand_tracking_mesh 1 -#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 2 +#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 4 #define XR_MSFT_HAND_TRACKING_MESH_EXTENSION_NAME "XR_MSFT_hand_tracking_mesh" typedef enum XrHandPoseTypeMSFT { @@ -1967,6 +2215,7 @@ typedef enum XrHandPoseTypeMSFT { XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT = 1, XR_HAND_POSE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF } XrHandPoseTypeMSFT; +// XrSystemHandTrackingMeshPropertiesMSFT extends XrSystemProperties typedef struct XrSystemHandTrackingMeshPropertiesMSFT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -2018,6 +2267,7 @@ typedef struct XrHandMeshMSFT { XrHandMeshVertexBufferMSFT vertexBuffer; } XrHandMeshMSFT; +// XrHandPoseTypeInfoMSFT extends XrHandTrackerCreateInfoEXT typedef struct XrHandPoseTypeInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2028,6 +2278,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateHandMeshSpaceMSFT)(XrHandTrackerEXT han typedef XrResult (XRAPI_PTR *PFN_xrUpdateHandMeshMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandMeshSpaceMSFT( XrHandTrackerEXT handTracker, const XrHandMeshSpaceCreateInfoMSFT* createInfo, @@ -2037,12 +2288,14 @@ XRAPI_ATTR XrResult XRAPI_CALL xrUpdateHandMeshMSFT( XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_secondary_view_configuration 1 #define XR_MSFT_secondary_view_configuration_SPEC_VERSION 1 #define XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME "XR_MSFT_secondary_view_configuration" +// XrSecondaryViewConfigurationSessionBeginInfoMSFT extends XrSessionBeginInfo typedef struct XrSecondaryViewConfigurationSessionBeginInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2057,6 +2310,7 @@ typedef struct XrSecondaryViewConfigurationStateMSFT { XrBool32 active; } XrSecondaryViewConfigurationStateMSFT; +// XrSecondaryViewConfigurationFrameStateMSFT extends XrFrameState typedef struct XrSecondaryViewConfigurationFrameStateMSFT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -2073,6 +2327,7 @@ typedef struct XrSecondaryViewConfigurationLayerInfoMSFT { const XrCompositionLayerBaseHeader* const* layers; } XrSecondaryViewConfigurationLayerInfoMSFT; +// XrSecondaryViewConfigurationFrameEndInfoMSFT extends XrFrameEndInfo typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2080,6 +2335,7 @@ typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT { const XrSecondaryViewConfigurationLayerInfoMSFT* viewConfigurationLayersInfo; } XrSecondaryViewConfigurationFrameEndInfoMSFT; +// XrSecondaryViewConfigurationSwapchainCreateInfoMSFT extends XrSwapchainCreateInfo typedef struct XrSecondaryViewConfigurationSwapchainCreateInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2142,6 +2398,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelPropertiesMSFT)(XrSession s typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelStateMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelKeyMSFT( XrSession session, XrPath topLevelUserPath, @@ -2163,7 +2420,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT( XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_win32_appcontainer_compatible 1 @@ -2174,6 +2432,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT( #define XR_EPIC_view_configuration_fov 1 #define XR_EPIC_view_configuration_fov_SPEC_VERSION 2 #define XR_EPIC_VIEW_CONFIGURATION_FOV_EXTENSION_NAME "XR_EPIC_view_configuration_fov" +// XrViewConfigurationViewFovEPIC extends XrViewConfigurationView typedef struct XrViewConfigurationViewFovEPIC { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2183,13 +2442,116 @@ typedef struct XrViewConfigurationViewFovEPIC { +#define XR_MSFT_composition_layer_reprojection 1 +#define XR_MSFT_composition_layer_reprojection_SPEC_VERSION 1 +#define XR_MSFT_COMPOSITION_LAYER_REPROJECTION_EXTENSION_NAME "XR_MSFT_composition_layer_reprojection" + +typedef enum XrReprojectionModeMSFT { + XR_REPROJECTION_MODE_DEPTH_MSFT = 1, + XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT = 2, + XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT = 3, + XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT = 4, + XR_REPROJECTION_MODE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrReprojectionModeMSFT; +// XrCompositionLayerReprojectionInfoMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReprojectionModeMSFT reprojectionMode; +} XrCompositionLayerReprojectionInfoMSFT; + +// XrCompositionLayerReprojectionPlaneOverrideMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionPlaneOverrideMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVector3f position; + XrVector3f normal; + XrVector3f velocity; +} XrCompositionLayerReprojectionPlaneOverrideMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReprojectionModesMSFT)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t modeCapacityInput, uint32_t* modeCountOutput, XrReprojectionModeMSFT* modes); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReprojectionModesMSFT( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t modeCapacityInput, + uint32_t* modeCountOutput, + XrReprojectionModeMSFT* modes); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_HUAWEI_controller_interaction 1 #define XR_HUAWEI_controller_interaction_SPEC_VERSION 1 #define XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HUAWEI_controller_interaction" +#define XR_FB_swapchain_update_state 1 +#define XR_FB_swapchain_update_state_SPEC_VERSION 3 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME "XR_FB_swapchain_update_state" +typedef struct XR_MAY_ALIAS XrSwapchainStateBaseHeaderFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainStateBaseHeaderFB; + +typedef XrResult (XRAPI_PTR *PFN_xrUpdateSwapchainFB)(XrSwapchain swapchain, const XrSwapchainStateBaseHeaderFB* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSwapchainStateFB)(XrSwapchain swapchain, XrSwapchainStateBaseHeaderFB* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateSwapchainFB( + XrSwapchain swapchain, + const XrSwapchainStateBaseHeaderFB* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSwapchainStateFB( + XrSwapchain swapchain, + XrSwapchainStateBaseHeaderFB* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_secure_content 1 +#define XR_FB_composition_layer_secure_content_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SECURE_CONTENT_EXTENSION_NAME "XR_FB_composition_layer_secure_content" +typedef XrFlags64 XrCompositionLayerSecureContentFlagsFB; + +// Flag bits for XrCompositionLayerSecureContentFlagsFB +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB = 0x00000001; +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB = 0x00000002; + +// XrCompositionLayerSecureContentFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSecureContentFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSecureContentFlagsFB flags; +} XrCompositionLayerSecureContentFB; + + + +#define XR_EXT_dpad_binding 1 +#define XR_EXT_dpad_binding_SPEC_VERSION 1 +#define XR_EXT_DPAD_BINDING_EXTENSION_NAME "XR_EXT_dpad_binding" +typedef struct XrInteractionProfileDpadBindingEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath binding; + XrActionSet actionSet; + float forceThreshold; + float forceThresholdReleased; + float centerRegion; + float wedgeAngle; + XrBool32 isSticky; + const XrHapticBaseHeader* onHaptic; + const XrHapticBaseHeader* offHaptic; +} XrInteractionProfileDpadBindingEXT; + + + #define XR_VALVE_analog_threshold 1 -#define XR_VALVE_analog_threshold_SPEC_VERSION 1 +#define XR_VALVE_analog_threshold_SPEC_VERSION 2 #define XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME "XR_VALVE_analog_threshold" typedef struct XrInteractionProfileAnalogThresholdVALVE { XrStructureType type; @@ -2204,6 +2566,24 @@ typedef struct XrInteractionProfileAnalogThresholdVALVE { +#define XR_EXT_hand_joints_motion_range 1 +#define XR_EXT_hand_joints_motion_range_SPEC_VERSION 1 +#define XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME "XR_EXT_hand_joints_motion_range" + +typedef enum XrHandJointsMotionRangeEXT { + XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT = 1, + XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT = 2, + XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointsMotionRangeEXT; +// XrHandJointsMotionRangeInfoEXT extends XrHandJointsLocateInfoEXT +typedef struct XrHandJointsMotionRangeInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandJointsMotionRangeEXT handJointsMotionRange; +} XrHandJointsMotionRangeInfoEXT; + + + #define XR_EXT_samsung_odyssey_controller 1 #define XR_EXT_samsung_odyssey_controller_SPEC_VERSION 1 #define XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME "XR_EXT_samsung_odyssey_controller" @@ -2219,6 +2599,374 @@ typedef struct XrInteractionProfileAnalogThresholdVALVE { #define XR_MND_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_MND_swapchain_usage_input_attachment_bit" +#define XR_MSFT_scene_understanding 1 + + XR_DEFINE_HANDLE(XrSceneObserverMSFT) + + + XR_DEFINE_HANDLE(XrSceneMSFT) + +#define XR_MSFT_scene_understanding_SPEC_VERSION 1 +#define XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME "XR_MSFT_scene_understanding" + +typedef enum XrSceneComputeFeatureMSFT { + XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT = 1, + XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT = 2, + XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT = 1000098000, + XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeFeatureMSFT; + +typedef enum XrSceneComputeConsistencyMSFT { + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT = 1, + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT = 2, + XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT = 3, + XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeConsistencyMSFT; + +typedef enum XrMeshComputeLodMSFT { + XR_MESH_COMPUTE_LOD_COARSE_MSFT = 1, + XR_MESH_COMPUTE_LOD_MEDIUM_MSFT = 2, + XR_MESH_COMPUTE_LOD_FINE_MSFT = 3, + XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT = 4, + XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrMeshComputeLodMSFT; + +typedef enum XrSceneComponentTypeMSFT { + XR_SCENE_COMPONENT_TYPE_INVALID_MSFT = -1, + XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT = 1, + XR_SCENE_COMPONENT_TYPE_PLANE_MSFT = 2, + XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT = 1000098000, + XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComponentTypeMSFT; + +typedef enum XrSceneObjectTypeMSFT { + XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT = -1, + XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT = 1, + XR_SCENE_OBJECT_TYPE_WALL_MSFT = 2, + XR_SCENE_OBJECT_TYPE_FLOOR_MSFT = 3, + XR_SCENE_OBJECT_TYPE_CEILING_MSFT = 4, + XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT = 5, + XR_SCENE_OBJECT_TYPE_INFERRED_MSFT = 6, + XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneObjectTypeMSFT; + +typedef enum XrScenePlaneAlignmentTypeMSFT { + XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT = 0, + XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT = 1, + XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT = 2, + XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrScenePlaneAlignmentTypeMSFT; + +typedef enum XrSceneComputeStateMSFT { + XR_SCENE_COMPUTE_STATE_NONE_MSFT = 0, + XR_SCENE_COMPUTE_STATE_UPDATING_MSFT = 1, + XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT = 2, + XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT = 3, + XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeStateMSFT; +typedef struct XrUuidMSFT { + uint8_t bytes[16]; +} XrUuidMSFT; + +typedef struct XrSceneObserverCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneObserverCreateInfoMSFT; + +typedef struct XrSceneCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneCreateInfoMSFT; + +typedef struct XrSceneSphereBoundMSFT { + XrVector3f center; + float radius; +} XrSceneSphereBoundMSFT; + +typedef struct XrSceneOrientedBoxBoundMSFT { + XrPosef pose; + XrVector3f extents; +} XrSceneOrientedBoxBoundMSFT; + +typedef struct XrSceneFrustumBoundMSFT { + XrPosef pose; + XrFovf fov; + float farDistance; +} XrSceneFrustumBoundMSFT; + +typedef struct XrSceneBoundsMSFT { + XrSpace space; + XrTime time; + uint32_t sphereCount; + const XrSceneSphereBoundMSFT* spheres; + uint32_t boxCount; + const XrSceneOrientedBoxBoundMSFT* boxes; + uint32_t frustumCount; + const XrSceneFrustumBoundMSFT* frustums; +} XrSceneBoundsMSFT; + +typedef struct XrNewSceneComputeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t requestedFeatureCount; + const XrSceneComputeFeatureMSFT* requestedFeatures; + XrSceneComputeConsistencyMSFT consistency; + XrSceneBoundsMSFT bounds; +} XrNewSceneComputeInfoMSFT; + +// XrVisualMeshComputeLodInfoMSFT extends XrNewSceneComputeInfoMSFT +typedef struct XrVisualMeshComputeLodInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMeshComputeLodMSFT lod; +} XrVisualMeshComputeLodInfoMSFT; + +typedef struct XrSceneComponentMSFT { + XrSceneComponentTypeMSFT componentType; + XrUuidMSFT id; + XrUuidMSFT parentId; + XrTime updateTime; +} XrSceneComponentMSFT; + +typedef struct XrSceneComponentsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t componentCapacityInput; + uint32_t componentCountOutput; + XrSceneComponentMSFT* components; +} XrSceneComponentsMSFT; + +typedef struct XrSceneComponentsGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSceneComponentTypeMSFT componentType; +} XrSceneComponentsGetInfoMSFT; + +typedef struct XrSceneComponentLocationMSFT { + XrSpaceLocationFlags flags; + XrPosef pose; +} XrSceneComponentLocationMSFT; + +typedef struct XrSceneComponentLocationsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t locationCount; + XrSceneComponentLocationMSFT* locations; +} XrSceneComponentLocationsMSFT; + +typedef struct XrSceneComponentsLocateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + uint32_t componentIdCount; + const XrUuidMSFT* componentIds; +} XrSceneComponentsLocateInfoMSFT; + +typedef struct XrSceneObjectMSFT { + XrSceneObjectTypeMSFT objectType; +} XrSceneObjectMSFT; + +// XrSceneObjectsMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneObjectsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneObjectCount; + XrSceneObjectMSFT* sceneObjects; +} XrSceneObjectsMSFT; + +// XrSceneComponentParentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneComponentParentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT parentId; +} XrSceneComponentParentFilterInfoMSFT; + +// XrSceneObjectTypesFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneObjectTypesFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t objectTypeCount; + const XrSceneObjectTypeMSFT* objectTypes; +} XrSceneObjectTypesFilterInfoMSFT; + +typedef struct XrScenePlaneMSFT { + XrScenePlaneAlignmentTypeMSFT alignment; + XrExtent2Df size; + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrScenePlaneMSFT; + +// XrScenePlanesMSFT extends XrSceneComponentsMSFT +typedef struct XrScenePlanesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t scenePlaneCount; + XrScenePlaneMSFT* scenePlanes; +} XrScenePlanesMSFT; + +// XrScenePlaneAlignmentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrScenePlaneAlignmentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t alignmentCount; + const XrScenePlaneAlignmentTypeMSFT* alignments; +} XrScenePlaneAlignmentFilterInfoMSFT; + +typedef struct XrSceneMeshMSFT { + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrSceneMeshMSFT; + +// XrSceneMeshesMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneMeshesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneMeshCount; + XrSceneMeshMSFT* sceneMeshes; +} XrSceneMeshesMSFT; + +typedef struct XrSceneMeshBuffersGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t meshBufferId; +} XrSceneMeshBuffersGetInfoMSFT; + +typedef struct XrSceneMeshBuffersMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSceneMeshBuffersMSFT; + +typedef struct XrSceneMeshVertexBufferMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertices; +} XrSceneMeshVertexBufferMSFT; + +typedef struct XrSceneMeshIndicesUint32MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrSceneMeshIndicesUint32MSFT; + +typedef struct XrSceneMeshIndicesUint16MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint16_t* indices; +} XrSceneMeshIndicesUint16MSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSceneComputeFeaturesMSFT)(XrInstance instance, XrSystemId systemId, uint32_t featureCapacityInput, uint32_t* featureCountOutput, XrSceneComputeFeatureMSFT* features); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneObserverMSFT)(XrSession session, const XrSceneObserverCreateInfoMSFT* createInfo, XrSceneObserverMSFT* sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneObserverMSFT)(XrSceneObserverMSFT sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneCreateInfoMSFT* createInfo, XrSceneMSFT* scene); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneMSFT)(XrSceneMSFT scene); +typedef XrResult (XRAPI_PTR *PFN_xrComputeNewSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrNewSceneComputeInfoMSFT* computeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComputeStateMSFT)(XrSceneObserverMSFT sceneObserver, XrSceneComputeStateMSFT* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsGetInfoMSFT* getInfo, XrSceneComponentsMSFT* components); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsLocateInfoMSFT* locateInfo, XrSceneComponentLocationsMSFT* locations); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneMeshBuffersMSFT)(XrSceneMSFT scene, const XrSceneMeshBuffersGetInfoMSFT* getInfo, XrSceneMeshBuffersMSFT* buffers); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSceneComputeFeaturesMSFT( + XrInstance instance, + XrSystemId systemId, + uint32_t featureCapacityInput, + uint32_t* featureCountOutput, + XrSceneComputeFeatureMSFT* features); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneObserverMSFT( + XrSession session, + const XrSceneObserverCreateInfoMSFT* createInfo, + XrSceneObserverMSFT* sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneObserverMSFT( + XrSceneObserverMSFT sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneCreateInfoMSFT* createInfo, + XrSceneMSFT* scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneMSFT( + XrSceneMSFT scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrComputeNewSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrNewSceneComputeInfoMSFT* computeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComputeStateMSFT( + XrSceneObserverMSFT sceneObserver, + XrSceneComputeStateMSFT* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsGetInfoMSFT* getInfo, + XrSceneComponentsMSFT* components); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsLocateInfoMSFT* locateInfo, + XrSceneComponentLocationsMSFT* locations); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneMeshBuffersMSFT( + XrSceneMSFT scene, + const XrSceneMeshBuffersGetInfoMSFT* getInfo, + XrSceneMeshBuffersMSFT* buffers); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_scene_understanding_serialization 1 +#define XR_MSFT_scene_understanding_serialization_SPEC_VERSION 1 +#define XR_MSFT_SCENE_UNDERSTANDING_SERIALIZATION_EXTENSION_NAME "XR_MSFT_scene_understanding_serialization" +typedef struct XrSerializedSceneFragmentDataGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT sceneFragmentId; +} XrSerializedSceneFragmentDataGetInfoMSFT; + +typedef struct XrDeserializeSceneFragmentMSFT { + uint32_t bufferSize; + const uint8_t* buffer; +} XrDeserializeSceneFragmentMSFT; + +typedef struct XrSceneDeserializeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t fragmentCount; + const XrDeserializeSceneFragmentMSFT* fragments; +} XrSceneDeserializeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrDeserializeSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneDeserializeInfoMSFT* deserializeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSerializedSceneFragmentDataMSFT)(XrSceneMSFT scene, const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, uint32_t countInput, uint32_t* readOutput, uint8_t* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrDeserializeSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneDeserializeInfoMSFT* deserializeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSerializedSceneFragmentDataMSFT( + XrSceneMSFT scene, + const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, + uint32_t countInput, + uint32_t* readOutput, + uint8_t* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_FB_display_refresh_rate 1 #define XR_FB_display_refresh_rate_SPEC_VERSION 1 #define XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME "XR_FB_display_refresh_rate" @@ -2234,6 +2982,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrGetDisplayRefreshRateFB)(XrSession session, f typedef XrResult (XRAPI_PTR *PFN_xrRequestDisplayRefreshRateFB)(XrSession session, float displayRefreshRate); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateDisplayRefreshRatesFB( XrSession session, uint32_t displayRefreshRateCapacityInput, @@ -2247,7 +2996,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetDisplayRefreshRateFB( XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB( XrSession session, float displayRefreshRate); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_HTC_vive_cosmos_controller_interaction 1 @@ -2255,8 +3005,171 @@ XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB( #define XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_cosmos_controller_interaction" +#define XR_HTCX_vive_tracker_interaction 1 +#define XR_HTCX_vive_tracker_interaction_SPEC_VERSION 1 +#define XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTCX_vive_tracker_interaction" +typedef struct XrViveTrackerPathsHTCX { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath persistentPath; + XrPath rolePath; +} XrViveTrackerPathsHTCX; + +typedef struct XrEventDataViveTrackerConnectedHTCX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViveTrackerPathsHTCX* paths; +} XrEventDataViveTrackerConnectedHTCX; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViveTrackerPathsHTCX)(XrInstance instance, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrViveTrackerPathsHTCX* paths); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViveTrackerPathsHTCX( + XrInstance instance, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrViveTrackerPathsHTCX* paths); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_facial_tracking 1 + +#define XR_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 + + +#define XR_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 + +XR_DEFINE_HANDLE(XrFacialTrackerHTC) +#define XR_HTC_facial_tracking_SPEC_VERSION 1 +#define XR_HTC_FACIAL_TRACKING_EXTENSION_NAME "XR_HTC_facial_tracking" + +typedef enum XrEyeExpressionHTC { + XR_EYE_EXPRESSION_LEFT_BLINK_HTC = 0, + XR_EYE_EXPRESSION_LEFT_WIDE_HTC = 1, + XR_EYE_EXPRESSION_RIGHT_BLINK_HTC = 2, + XR_EYE_EXPRESSION_RIGHT_WIDE_HTC = 3, + XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC = 4, + XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC = 5, + XR_EYE_EXPRESSION_LEFT_DOWN_HTC = 6, + XR_EYE_EXPRESSION_RIGHT_DOWN_HTC = 7, + XR_EYE_EXPRESSION_LEFT_OUT_HTC = 8, + XR_EYE_EXPRESSION_RIGHT_IN_HTC = 9, + XR_EYE_EXPRESSION_LEFT_IN_HTC = 10, + XR_EYE_EXPRESSION_RIGHT_OUT_HTC = 11, + XR_EYE_EXPRESSION_LEFT_UP_HTC = 12, + XR_EYE_EXPRESSION_RIGHT_UP_HTC = 13, + XR_EYE_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrEyeExpressionHTC; + +typedef enum XrLipExpressionHTC { + XR_LIP_EXPRESSION_JAW_RIGHT_HTC = 0, + XR_LIP_EXPRESSION_JAW_LEFT_HTC = 1, + XR_LIP_EXPRESSION_JAW_FORWARD_HTC = 2, + XR_LIP_EXPRESSION_JAW_OPEN_HTC = 3, + XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC = 4, + XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC = 5, + XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC = 6, + XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC = 7, + XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC = 8, + XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC = 9, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC = 10, + XR_LIP_EXPRESSION_MOUTH_POUT_HTC = 11, + XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC = 12, + XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC = 13, + XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC = 14, + XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC = 15, + XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC = 16, + XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC = 17, + XR_LIP_EXPRESSION_CHEEK_SUCK_HTC = 18, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC = 19, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC = 20, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC = 21, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC = 22, + XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC = 23, + XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC = 24, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC = 25, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC = 26, + XR_LIP_EXPRESSION_TONGUE_LEFT_HTC = 27, + XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC = 28, + XR_LIP_EXPRESSION_TONGUE_UP_HTC = 29, + XR_LIP_EXPRESSION_TONGUE_DOWN_HTC = 30, + XR_LIP_EXPRESSION_TONGUE_ROLL_HTC = 31, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC = 32, + XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC = 33, + XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC = 34, + XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC = 35, + XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC = 36, + XR_LIP_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrLipExpressionHTC; + +typedef enum XrFacialTrackingTypeHTC { + XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC = 1, + XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC = 2, + XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC = 0x7FFFFFFF +} XrFacialTrackingTypeHTC; +// XrSystemFacialTrackingPropertiesHTC extends XrSystemProperties +typedef struct XrSystemFacialTrackingPropertiesHTC { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportEyeFacialTracking; + XrBool32 supportLipFacialTracking; +} XrSystemFacialTrackingPropertiesHTC; + +typedef struct XrFacialExpressionsHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrTime sampleTime; + uint32_t expressionCount; + float* expressionWeightings; +} XrFacialExpressionsHTC; + +typedef struct XrFacialTrackerCreateInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFacialTrackingTypeHTC facialTrackingType; +} XrFacialTrackerCreateInfoHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFacialTrackerHTC)(XrSession session, const XrFacialTrackerCreateInfoHTC* createInfo, XrFacialTrackerHTC* facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFacialTrackerHTC)(XrFacialTrackerHTC facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetFacialExpressionsHTC)(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC* facialExpressions); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFacialTrackerHTC( + XrSession session, + const XrFacialTrackerCreateInfoHTC* createInfo, + XrFacialTrackerHTC* facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFacialTrackerHTC( + XrFacialTrackerHTC facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetFacialExpressionsHTC( + XrFacialTrackerHTC facialTracker, + XrFacialExpressionsHTC* facialExpressions); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_focus3_controller_interaction 1 +#define XR_HTC_vive_focus3_controller_interaction_SPEC_VERSION 2 +#define XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_focus3_controller_interaction" + + +#define XR_HTC_hand_interaction 1 +#define XR_HTC_hand_interaction_SPEC_VERSION 1 +#define XR_HTC_HAND_INTERACTION_EXTENSION_NAME "XR_HTC_hand_interaction" + + +#define XR_HTC_vive_wrist_tracker_interaction 1 +#define XR_HTC_vive_wrist_tracker_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_WRIST_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_wrist_tracker_interaction" + + #define XR_FB_color_space 1 -#define XR_FB_color_space_SPEC_VERSION 1 +#define XR_FB_color_space_SPEC_VERSION 2 #define XR_FB_COLOR_SPACE_EXTENSION_NAME "XR_FB_color_space" typedef enum XrColorSpaceFB { @@ -2270,6 +3183,7 @@ typedef enum XrColorSpaceFB { XR_COLOR_SPACE_ADOBE_RGB_FB = 7, XR_COLOR_SPACE_MAX_ENUM_FB = 0x7FFFFFFF } XrColorSpaceFB; +// XrSystemColorSpacePropertiesFB extends XrSystemProperties typedef struct XrSystemColorSpacePropertiesFB { XrStructureType type; void* XR_MAY_ALIAS next; @@ -2280,6 +3194,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrEnumerateColorSpacesFB)(XrSession session, ui typedef XrResult (XRAPI_PTR *PFN_xrSetColorSpaceFB)(XrSession session, const XrColorSpaceFB colorspace); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB( XrSession session, uint32_t colorSpaceCapacityInput, @@ -2289,7 +3204,1354 @@ XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB( XRAPI_ATTR XrResult XRAPI_CALL xrSetColorSpaceFB( XrSession session, const XrColorSpaceFB colorspace); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_mesh 1 +#define XR_FB_hand_tracking_mesh_SPEC_VERSION 2 +#define XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME "XR_FB_hand_tracking_mesh" +typedef struct XrVector4sFB { + int16_t x; + int16_t y; + int16_t z; + int16_t w; +} XrVector4sFB; + +typedef struct XrHandTrackingMeshFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCapacityInput; + uint32_t jointCountOutput; + XrPosef* jointBindPoses; + float* jointRadii; + XrHandJointEXT* jointParents; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertexPositions; + XrVector3f* vertexNormals; + XrVector2f* vertexUVs; + XrVector4sFB* vertexBlendIndices; + XrVector4f* vertexBlendWeights; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + int16_t* indices; +} XrHandTrackingMeshFB; + +// XrHandTrackingScaleFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingScaleFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + float sensorOutput; + float currentOutput; + XrBool32 overrideHandScale; + float overrideValueInput; +} XrHandTrackingScaleFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetHandMeshFB)(XrHandTrackerEXT handTracker, XrHandTrackingMeshFB* mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetHandMeshFB( + XrHandTrackerEXT handTracker, + XrHandTrackingMeshFB* mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_aim 1 +#define XR_FB_hand_tracking_aim_SPEC_VERSION 2 +#define XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME "XR_FB_hand_tracking_aim" +typedef XrFlags64 XrHandTrackingAimFlagsFB; + +// Flag bits for XrHandTrackingAimFlagsFB +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB = 0x00000001; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_VALID_BIT_FB = 0x00000002; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB = 0x00000004; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB = 0x00000008; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB = 0x00000010; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB = 0x00000020; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB = 0x00000040; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB = 0x00000080; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB = 0x00000100; + +// XrHandTrackingAimStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingAimStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandTrackingAimFlagsFB status; + XrPosef aimPose; + float pinchStrengthIndex; + float pinchStrengthMiddle; + float pinchStrengthRing; + float pinchStrengthLittle; +} XrHandTrackingAimStateFB; + + + +#define XR_FB_hand_tracking_capsules 1 +#define XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB 2 +#define XR_HAND_TRACKING_CAPSULE_COUNT_FB 19 +#define XR_FB_hand_tracking_capsules_SPEC_VERSION 3 +#define XR_FB_HAND_TRACKING_CAPSULES_EXTENSION_NAME "XR_FB_hand_tracking_capsules" +#define XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB +#define XR_FB_HAND_TRACKING_CAPSULE_COUNT XR_HAND_TRACKING_CAPSULE_COUNT_FB +typedef struct XrHandCapsuleFB { + XrVector3f points[XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB]; + float radius; + XrHandJointEXT joint; +} XrHandCapsuleFB; + +// XrHandTrackingCapsulesStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingCapsulesStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandCapsuleFB capsules[XR_HAND_TRACKING_CAPSULE_COUNT_FB]; +} XrHandTrackingCapsulesStateFB; + + + +#define XR_FB_spatial_entity 1 +XR_DEFINE_ATOM(XrAsyncRequestIdFB) +#define XR_UUID_SIZE_EXT 16 +#define XR_FB_spatial_entity_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_EXTENSION_NAME "XR_FB_spatial_entity" + +typedef enum XrSpaceComponentTypeFB { + XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB = 0, + XR_SPACE_COMPONENT_TYPE_STORABLE_FB = 1, + XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB = 3, + XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB = 4, + XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB = 5, + XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB = 6, + XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB = 7, + XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceComponentTypeFB; +// XrSystemSpatialEntityPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpatialEntityPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsSpatialEntity; +} XrSystemSpatialEntityPropertiesFB; + +typedef struct XrSpatialAnchorCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialAnchorCreateInfoFB; + +typedef struct XrSpaceComponentStatusSetInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; + XrDuration timeout; +} XrSpaceComponentStatusSetInfoFB; + +typedef struct XrSpaceComponentStatusFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 enabled; + XrBool32 changePending; +} XrSpaceComponentStatusFB; + +typedef struct XrUuidEXT { + uint8_t data[XR_UUID_SIZE_EXT]; +} XrUuidEXT; + +typedef struct XrEventDataSpatialAnchorCreateCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; +} XrEventDataSpatialAnchorCreateCompleteFB; + +typedef struct XrEventDataSpaceSetStatusCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; +} XrEventDataSpaceSetStatusCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFB)(XrSession session, const XrSpatialAnchorCreateInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceUuidFB)(XrSpace space, XrUuidEXT* uuid); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSpaceSupportedComponentsFB)(XrSpace space, uint32_t componentTypeCapacityInput, uint32_t* componentTypeCountOutput, XrSpaceComponentTypeFB* componentTypes); +typedef XrResult (XRAPI_PTR *PFN_xrSetSpaceComponentStatusFB)(XrSpace space, const XrSpaceComponentStatusSetInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceComponentStatusFB)(XrSpace space, XrSpaceComponentTypeFB componentType, XrSpaceComponentStatusFB* status); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFB( + XrSession session, + const XrSpatialAnchorCreateInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceUuidFB( + XrSpace space, + XrUuidEXT* uuid); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSpaceSupportedComponentsFB( + XrSpace space, + uint32_t componentTypeCapacityInput, + uint32_t* componentTypeCountOutput, + XrSpaceComponentTypeFB* componentTypes); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetSpaceComponentStatusFB( + XrSpace space, + const XrSpaceComponentStatusSetInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceComponentStatusFB( + XrSpace space, + XrSpaceComponentTypeFB componentType, + XrSpaceComponentStatusFB* status); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation 1 +XR_DEFINE_HANDLE(XrFoveationProfileFB) +#define XR_FB_foveation_SPEC_VERSION 1 +#define XR_FB_FOVEATION_EXTENSION_NAME "XR_FB_foveation" +typedef XrFlags64 XrSwapchainCreateFoveationFlagsFB; + +// Flag bits for XrSwapchainCreateFoveationFlagsFB +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB = 0x00000001; +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB = 0x00000002; + +typedef XrFlags64 XrSwapchainStateFoveationFlagsFB; + +// Flag bits for XrSwapchainStateFoveationFlagsFB + +typedef struct XrFoveationProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrFoveationProfileCreateInfoFB; + +// XrSwapchainCreateInfoFoveationFB extends XrSwapchainCreateInfo +typedef struct XrSwapchainCreateInfoFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainCreateFoveationFlagsFB flags; +} XrSwapchainCreateInfoFoveationFB; + +typedef struct XrSwapchainStateFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainStateFoveationFlagsFB flags; + XrFoveationProfileFB profile; +} XrSwapchainStateFoveationFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFoveationProfileFB)(XrSession session, const XrFoveationProfileCreateInfoFB* createInfo, XrFoveationProfileFB* profile); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFoveationProfileFB)(XrFoveationProfileFB profile); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFoveationProfileFB( + XrSession session, + const XrFoveationProfileCreateInfoFB* createInfo, + XrFoveationProfileFB* profile); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFoveationProfileFB( + XrFoveationProfileFB profile); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation_configuration 1 +#define XR_FB_foveation_configuration_SPEC_VERSION 1 +#define XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME "XR_FB_foveation_configuration" + +typedef enum XrFoveationLevelFB { + XR_FOVEATION_LEVEL_NONE_FB = 0, + XR_FOVEATION_LEVEL_LOW_FB = 1, + XR_FOVEATION_LEVEL_MEDIUM_FB = 2, + XR_FOVEATION_LEVEL_HIGH_FB = 3, + XR_FOVEATION_LEVEL_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationLevelFB; + +typedef enum XrFoveationDynamicFB { + XR_FOVEATION_DYNAMIC_DISABLED_FB = 0, + XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB = 1, + XR_FOVEATION_DYNAMIC_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationDynamicFB; +// XrFoveationLevelProfileCreateInfoFB extends XrFoveationProfileCreateInfoFB +typedef struct XrFoveationLevelProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrFoveationLevelFB level; + float verticalOffset; + XrFoveationDynamicFB dynamic; +} XrFoveationLevelProfileCreateInfoFB; + + + +#define XR_FB_keyboard_tracking 1 +#define XR_FB_keyboard_tracking_SPEC_VERSION 1 +#define XR_FB_KEYBOARD_TRACKING_EXTENSION_NAME "XR_FB_keyboard_tracking" +#define XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB 128 +typedef XrFlags64 XrKeyboardTrackingFlagsFB; + +// Flag bits for XrKeyboardTrackingFlagsFB +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_EXISTS_BIT_FB = 0x00000001; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_REMOTE_BIT_FB = 0x00000004; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB = 0x00000008; + +typedef XrFlags64 XrKeyboardTrackingQueryFlagsFB; + +// Flag bits for XrKeyboardTrackingQueryFlagsFB +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB = 0x00000004; + +// XrSystemKeyboardTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemKeyboardTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsKeyboardTracking; +} XrSystemKeyboardTrackingPropertiesFB; + +typedef struct XrKeyboardTrackingDescriptionFB { + uint64_t trackedKeyboardId; + XrVector3f size; + XrKeyboardTrackingFlagsFB flags; + char name[XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB]; +} XrKeyboardTrackingDescriptionFB; + +typedef struct XrKeyboardSpaceCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint64_t trackedKeyboardId; +} XrKeyboardSpaceCreateInfoFB; + +typedef struct XrKeyboardTrackingQueryFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrKeyboardTrackingQueryFlagsFB flags; +} XrKeyboardTrackingQueryFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySystemTrackedKeyboardFB)(XrSession session, const XrKeyboardTrackingQueryFB* queryInfo, XrKeyboardTrackingDescriptionFB* keyboard); +typedef XrResult (XRAPI_PTR *PFN_xrCreateKeyboardSpaceFB)(XrSession session, const XrKeyboardSpaceCreateInfoFB* createInfo, XrSpace* keyboardSpace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySystemTrackedKeyboardFB( + XrSession session, + const XrKeyboardTrackingQueryFB* queryInfo, + XrKeyboardTrackingDescriptionFB* keyboard); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateKeyboardSpaceFB( + XrSession session, + const XrKeyboardSpaceCreateInfoFB* createInfo, + XrSpace* keyboardSpace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_triangle_mesh 1 +XR_DEFINE_HANDLE(XrTriangleMeshFB) +#define XR_FB_triangle_mesh_SPEC_VERSION 2 +#define XR_FB_TRIANGLE_MESH_EXTENSION_NAME "XR_FB_triangle_mesh" + +typedef enum XrWindingOrderFB { + XR_WINDING_ORDER_UNKNOWN_FB = 0, + XR_WINDING_ORDER_CW_FB = 1, + XR_WINDING_ORDER_CCW_FB = 2, + XR_WINDING_ORDER_MAX_ENUM_FB = 0x7FFFFFFF +} XrWindingOrderFB; +typedef XrFlags64 XrTriangleMeshFlagsFB; + +// Flag bits for XrTriangleMeshFlagsFB +static const XrTriangleMeshFlagsFB XR_TRIANGLE_MESH_MUTABLE_BIT_FB = 0x00000001; + +typedef struct XrTriangleMeshCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTriangleMeshFlagsFB flags; + XrWindingOrderFB windingOrder; + uint32_t vertexCount; + const XrVector3f* vertexBuffer; + uint32_t triangleCount; + const uint32_t* indexBuffer; +} XrTriangleMeshCreateInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateTriangleMeshFB)(XrSession session, const XrTriangleMeshCreateInfoFB* createInfo, XrTriangleMeshFB* outTriangleMesh); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyTriangleMeshFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetVertexBufferFB)(XrTriangleMeshFB mesh, XrVector3f** outVertexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetIndexBufferFB)(XrTriangleMeshFB mesh, uint32_t** outIndexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginUpdateFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndUpdateFB)(XrTriangleMeshFB mesh, uint32_t vertexCount, uint32_t triangleCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginVertexBufferUpdateFB)(XrTriangleMeshFB mesh, uint32_t* outVertexCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndVertexBufferUpdateFB)(XrTriangleMeshFB mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateTriangleMeshFB( + XrSession session, + const XrTriangleMeshCreateInfoFB* createInfo, + XrTriangleMeshFB* outTriangleMesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyTriangleMeshFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetVertexBufferFB( + XrTriangleMeshFB mesh, + XrVector3f** outVertexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetIndexBufferFB( + XrTriangleMeshFB mesh, + uint32_t** outIndexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginUpdateFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndUpdateFB( + XrTriangleMeshFB mesh, + uint32_t vertexCount, + uint32_t triangleCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginVertexBufferUpdateFB( + XrTriangleMeshFB mesh, + uint32_t* outVertexCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndVertexBufferUpdateFB( + XrTriangleMeshFB mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough 1 +XR_DEFINE_HANDLE(XrPassthroughFB) +XR_DEFINE_HANDLE(XrPassthroughLayerFB) +XR_DEFINE_HANDLE(XrGeometryInstanceFB) +#define XR_FB_passthrough_SPEC_VERSION 2 +#define XR_FB_PASSTHROUGH_EXTENSION_NAME "XR_FB_passthrough" +#define XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB 256 + +typedef enum XrPassthroughLayerPurposeFB { + XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB = 0, + XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB = 1, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB = 1000203001, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB = 1000203002, + XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB = 0x7FFFFFFF +} XrPassthroughLayerPurposeFB; +typedef XrFlags64 XrPassthroughFlagsFB; + +// Flag bits for XrPassthroughFlagsFB +static const XrPassthroughFlagsFB XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001; + +typedef XrFlags64 XrPassthroughStateChangedFlagsFB; + +// Flag bits for XrPassthroughStateChangedFlagsFB +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB = 0x00000001; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB = 0x00000002; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB = 0x00000004; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB = 0x00000008; + +// XrSystemPassthroughPropertiesFB extends XrSystemProperties +typedef struct XrSystemPassthroughPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsPassthrough; +} XrSystemPassthroughPropertiesFB; + +typedef struct XrPassthroughCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFlagsFB flags; +} XrPassthroughCreateInfoFB; + +typedef struct XrPassthroughLayerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFB passthrough; + XrPassthroughFlagsFB flags; + XrPassthroughLayerPurposeFB purpose; +} XrPassthroughLayerCreateInfoFB; + +// XrCompositionLayerPassthroughFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerPassthroughFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags flags; + XrSpace space; + XrPassthroughLayerFB layerHandle; +} XrCompositionLayerPassthroughFB; + +typedef struct XrGeometryInstanceCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughLayerFB layer; + XrTriangleMeshFB mesh; + XrSpace baseSpace; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceCreateInfoFB; + +typedef struct XrGeometryInstanceTransformFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceTransformFB; + +typedef struct XrPassthroughStyleFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float textureOpacityFactor; + XrColor4f edgeColor; +} XrPassthroughStyleFB; + +// XrPassthroughColorMapMonoToRgbaFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToRgbaFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToRgbaFB; + +// XrPassthroughColorMapMonoToMonoFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToMonoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToMonoFB; + +// XrPassthroughBrightnessContrastSaturationFB extends XrPassthroughStyleFB +typedef struct XrPassthroughBrightnessContrastSaturationFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float brightness; + float contrast; + float saturation; +} XrPassthroughBrightnessContrastSaturationFB; + +typedef struct XrEventDataPassthroughStateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughStateChangedFlagsFB flags; +} XrEventDataPassthroughStateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughFB)(XrSession session, const XrPassthroughCreateInfoFB* createInfo, XrPassthroughFB* outPassthrough); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughStartFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughPauseFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughLayerFB)(XrSession session, const XrPassthroughLayerCreateInfoFB* createInfo, XrPassthroughLayerFB* outLayer); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughLayerFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerPauseFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerResumeFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetStyleFB)(XrPassthroughLayerFB layer, const XrPassthroughStyleFB* style); +typedef XrResult (XRAPI_PTR *PFN_xrCreateGeometryInstanceFB)(XrSession session, const XrGeometryInstanceCreateInfoFB* createInfo, XrGeometryInstanceFB* outGeometryInstance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyGeometryInstanceFB)(XrGeometryInstanceFB instance); +typedef XrResult (XRAPI_PTR *PFN_xrGeometryInstanceSetTransformFB)(XrGeometryInstanceFB instance, const XrGeometryInstanceTransformFB* transformation); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughFB( + XrSession session, + const XrPassthroughCreateInfoFB* createInfo, + XrPassthroughFB* outPassthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughStartFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughPauseFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughLayerFB( + XrSession session, + const XrPassthroughLayerCreateInfoFB* createInfo, + XrPassthroughLayerFB* outLayer); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughLayerFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerPauseFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerResumeFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetStyleFB( + XrPassthroughLayerFB layer, + const XrPassthroughStyleFB* style); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateGeometryInstanceFB( + XrSession session, + const XrGeometryInstanceCreateInfoFB* createInfo, + XrGeometryInstanceFB* outGeometryInstance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyGeometryInstanceFB( + XrGeometryInstanceFB instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGeometryInstanceSetTransformFB( + XrGeometryInstanceFB instance, + const XrGeometryInstanceTransformFB* transformation); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_render_model 1 + +#define XR_NULL_RENDER_MODEL_KEY_FB 0 + +XR_DEFINE_ATOM(XrRenderModelKeyFB) +#define XR_FB_render_model_SPEC_VERSION 2 +#define XR_FB_RENDER_MODEL_EXTENSION_NAME "XR_FB_render_model" +#define XR_MAX_RENDER_MODEL_NAME_SIZE_FB 64 +typedef XrFlags64 XrRenderModelFlagsFB; + +// Flag bits for XrRenderModelFlagsFB +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB = 0x00000001; +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB = 0x00000002; + +typedef struct XrRenderModelPathInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath path; +} XrRenderModelPathInfoFB; + +typedef struct XrRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vendorId; + char modelName[XR_MAX_RENDER_MODEL_NAME_SIZE_FB]; + XrRenderModelKeyFB modelKey; + uint32_t modelVersion; + XrRenderModelFlagsFB flags; +} XrRenderModelPropertiesFB; + +typedef struct XrRenderModelBufferFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + uint8_t* buffer; +} XrRenderModelBufferFB; + +typedef struct XrRenderModelLoadInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelKeyFB modelKey; +} XrRenderModelLoadInfoFB; + +// XrSystemRenderModelPropertiesFB extends XrSystemProperties +typedef struct XrSystemRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsRenderModelLoading; +} XrSystemRenderModelPropertiesFB; + +// XrRenderModelCapabilitiesRequestFB extends XrSystemProperties +typedef struct XrRenderModelCapabilitiesRequestFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelFlagsFB flags; +} XrRenderModelCapabilitiesRequestFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateRenderModelPathsFB)(XrSession session, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrRenderModelPathInfoFB* paths); +typedef XrResult (XRAPI_PTR *PFN_xrGetRenderModelPropertiesFB)(XrSession session, XrPath path, XrRenderModelPropertiesFB* properties); +typedef XrResult (XRAPI_PTR *PFN_xrLoadRenderModelFB)(XrSession session, const XrRenderModelLoadInfoFB* info, XrRenderModelBufferFB* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateRenderModelPathsFB( + XrSession session, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrRenderModelPathInfoFB* paths); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetRenderModelPropertiesFB( + XrSession session, + XrPath path, + XrRenderModelPropertiesFB* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadRenderModelFB( + XrSession session, + const XrRenderModelLoadInfoFB* info, + XrRenderModelBufferFB* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_foveated_rendering 1 +#define XR_VARJO_foveated_rendering_SPEC_VERSION 2 +#define XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME "XR_VARJO_foveated_rendering" +// XrViewLocateFoveatedRenderingVARJO extends XrViewLocateInfo +typedef struct XrViewLocateFoveatedRenderingVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrViewLocateFoveatedRenderingVARJO; + +// XrFoveatedViewConfigurationViewVARJO extends XrViewConfigurationView +typedef struct XrFoveatedViewConfigurationViewVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrFoveatedViewConfigurationViewVARJO; + +// XrSystemFoveatedRenderingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemFoveatedRenderingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsFoveatedRendering; +} XrSystemFoveatedRenderingPropertiesVARJO; + + + +#define XR_VARJO_composition_layer_depth_test 1 +#define XR_VARJO_composition_layer_depth_test_SPEC_VERSION 2 +#define XR_VARJO_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_VARJO_composition_layer_depth_test" +// XrCompositionLayerDepthTestVARJO extends XrCompositionLayerProjection +typedef struct XrCompositionLayerDepthTestVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float depthTestRangeNearZ; + float depthTestRangeFarZ; +} XrCompositionLayerDepthTestVARJO; + + + +#define XR_VARJO_environment_depth_estimation 1 +#define XR_VARJO_environment_depth_estimation_SPEC_VERSION 1 +#define XR_VARJO_ENVIRONMENT_DEPTH_ESTIMATION_EXTENSION_NAME "XR_VARJO_environment_depth_estimation" +typedef XrResult (XRAPI_PTR *PFN_xrSetEnvironmentDepthEstimationVARJO)(XrSession session, XrBool32 enabled); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetEnvironmentDepthEstimationVARJO( + XrSession session, + XrBool32 enabled); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_marker_tracking 1 +#define XR_VARJO_marker_tracking_SPEC_VERSION 1 +#define XR_VARJO_MARKER_TRACKING_EXTENSION_NAME "XR_VARJO_marker_tracking" +// XrSystemMarkerTrackingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemMarkerTrackingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsMarkerTracking; +} XrSystemMarkerTrackingPropertiesVARJO; + +typedef struct XrEventDataMarkerTrackingUpdateVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrBool32 isActive; + XrBool32 isPredicted; + XrTime time; +} XrEventDataMarkerTrackingUpdateVARJO; + +typedef struct XrMarkerSpaceCreateInfoVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrPosef poseInMarkerSpace; +} XrMarkerSpaceCreateInfoVARJO; + +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingVARJO)(XrSession session, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingTimeoutVARJO)(XrSession session, uint64_t markerId, XrDuration timeout); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingPredictionVARJO)(XrSession session, uint64_t markerId, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerSizeVARJO)(XrSession session, uint64_t markerId, XrExtent2Df* size); +typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceVARJO)(XrSession session, const XrMarkerSpaceCreateInfoVARJO* createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingVARJO( + XrSession session, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingTimeoutVARJO( + XrSession session, + uint64_t markerId, + XrDuration timeout); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingPredictionVARJO( + XrSession session, + uint64_t markerId, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerSizeVARJO( + XrSession session, + uint64_t markerId, + XrExtent2Df* size); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceVARJO( + XrSession session, + const XrMarkerSpaceCreateInfoVARJO* createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_view_offset 1 +#define XR_VARJO_view_offset_SPEC_VERSION 1 +#define XR_VARJO_VIEW_OFFSET_EXTENSION_NAME "XR_VARJO_view_offset" +typedef XrResult (XRAPI_PTR *PFN_xrSetViewOffsetVARJO)(XrSession session, float offset); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetViewOffsetVARJO( + XrSession session, + float offset); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_spatial_anchor_persistence 1 +XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT) +#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256 +#define XR_MSFT_spatial_anchor_persistence_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_PERSISTENCE_EXTENSION_NAME "XR_MSFT_spatial_anchor_persistence" +typedef struct XrSpatialAnchorPersistenceNameMSFT { + char name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT]; +} XrSpatialAnchorPersistenceNameMSFT; + +typedef struct XrSpatialAnchorPersistenceInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; + XrSpatialAnchorMSFT spatialAnchor; +} XrSpatialAnchorPersistenceInfoMSFT; + +typedef struct XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; +} XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorStoreConnectionMSFT)(XrSession session, XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorStoreConnectionMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrPersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, uint32_t spatialAnchorNamesCapacityInput, uint32_t* spatialAnchorNamesCountOutput, XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPersistedNameMSFT)(XrSession session, const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, XrSpatialAnchorMSFT* spatialAnchor); +typedef XrResult (XRAPI_PTR *PFN_xrUnpersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); +typedef XrResult (XRAPI_PTR *PFN_xrClearSpatialAnchorStoreMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorStoreConnectionMSFT( + XrSession session, + XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorStoreConnectionMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrPersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePersistedSpatialAnchorNamesMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + uint32_t spatialAnchorNamesCapacityInput, + uint32_t* spatialAnchorNamesCountOutput, + XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPersistedNameMSFT( + XrSession session, + const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, + XrSpatialAnchorMSFT* spatialAnchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrUnpersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); + +XRAPI_ATTR XrResult XRAPI_CALL xrClearSpatialAnchorStoreMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_ULTRALEAP_hand_tracking_forearm 1 + +#define XR_HAND_FOREARM_JOINT_COUNT_ULTRALEAP 27 + +#define XR_ULTRALEAP_hand_tracking_forearm_SPEC_VERSION 1 +#define XR_ULTRALEAP_HAND_TRACKING_FOREARM_EXTENSION_NAME "XR_ULTRALEAP_hand_tracking_forearm" + +typedef enum XrHandForearmJointULTRALEAP { + XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP = 0, + XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP = 1, + XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP = 2, + XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP = 3, + XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP = 4, + XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP = 5, + XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP = 6, + XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP = 7, + XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP = 8, + XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP = 9, + XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP = 10, + XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP = 11, + XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP = 12, + XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP = 13, + XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP = 14, + XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP = 15, + XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP = 16, + XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP = 17, + XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP = 18, + XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP = 19, + XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP = 20, + XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP = 21, + XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP = 22, + XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP = 23, + XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP = 24, + XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP = 25, + XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP = 26, + XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP = 0x7FFFFFFF +} XrHandForearmJointULTRALEAP; + + +#define XR_FB_spatial_entity_query 1 +#define XR_FB_spatial_entity_query_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_QUERY_EXTENSION_NAME "XR_FB_spatial_entity_query" + +typedef enum XrSpaceQueryActionFB { + XR_SPACE_QUERY_ACTION_LOAD_FB = 0, + XR_SPACE_QUERY_ACTION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceQueryActionFB; + +typedef enum XrSpaceStorageLocationFB { + XR_SPACE_STORAGE_LOCATION_INVALID_FB = 0, + XR_SPACE_STORAGE_LOCATION_LOCAL_FB = 1, + XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceStorageLocationFB; +typedef struct XR_MAY_ALIAS XrSpaceQueryInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceQueryInfoBaseHeaderFB; + +typedef struct XR_MAY_ALIAS XrSpaceFilterInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceFilterInfoBaseHeaderFB; + +typedef struct XrSpaceQueryInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceQueryActionFB queryAction; + uint32_t maxResultCount; + XrDuration timeout; + const XrSpaceFilterInfoBaseHeaderFB* filter; + const XrSpaceFilterInfoBaseHeaderFB* excludeFilter; +} XrSpaceQueryInfoFB; + +// XrSpaceStorageLocationFilterInfoFB extends XrSpaceFilterInfoBaseHeaderFB +typedef struct XrSpaceStorageLocationFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceStorageLocationFB location; +} XrSpaceStorageLocationFilterInfoFB; + +typedef struct XrSpaceUuidFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCount; + XrUuidEXT* uuids; +} XrSpaceUuidFilterInfoFB; + +typedef struct XrSpaceComponentFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; +} XrSpaceComponentFilterInfoFB; + +typedef struct XrSpaceQueryResultFB { + XrSpace space; + XrUuidEXT uuid; +} XrSpaceQueryResultFB; + +typedef struct XrSpaceQueryResultsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t resultCapacityInput; + uint32_t resultCountOutput; + XrSpaceQueryResultFB* results; +} XrSpaceQueryResultsFB; + +typedef struct XrEventDataSpaceQueryResultsAvailableFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; +} XrEventDataSpaceQueryResultsAvailableFB; + +typedef struct XrEventDataSpaceQueryCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; +} XrEventDataSpaceQueryCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySpacesFB)(XrSession session, const XrSpaceQueryInfoBaseHeaderFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrRetrieveSpaceQueryResultsFB)(XrSession session, XrAsyncRequestIdFB requestId, XrSpaceQueryResultsFB* results); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySpacesFB( + XrSession session, + const XrSpaceQueryInfoBaseHeaderFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrRetrieveSpaceQueryResultsFB( + XrSession session, + XrAsyncRequestIdFB requestId, + XrSpaceQueryResultsFB* results); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_storage 1 +#define XR_FB_spatial_entity_storage_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_STORAGE_EXTENSION_NAME "XR_FB_spatial_entity_storage" + +typedef enum XrSpacePersistenceModeFB { + XR_SPACE_PERSISTENCE_MODE_INVALID_FB = 0, + XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB = 1, + XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpacePersistenceModeFB; +typedef struct XrSpaceSaveInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; + XrSpacePersistenceModeFB persistenceMode; +} XrSpaceSaveInfoFB; + +typedef struct XrSpaceEraseInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; +} XrSpaceEraseInfoFB; + +typedef struct XrEventDataSpaceSaveCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceSaveCompleteFB; + +typedef struct XrEventDataSpaceEraseCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceEraseCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrSaveSpaceFB)(XrSession session, const XrSpaceSaveInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrEraseSpaceFB)(XrSession session, const XrSpaceEraseInfoFB* info, XrAsyncRequestIdFB* requestId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSaveSpaceFB( + XrSession session, + const XrSpaceSaveInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrEraseSpaceFB( + XrSession session, + const XrSpaceEraseInfoFB* info, + XrAsyncRequestIdFB* requestId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_space_warp 1 +#define XR_FB_space_warp_SPEC_VERSION 2 +#define XR_FB_SPACE_WARP_EXTENSION_NAME "XR_FB_space_warp" +typedef XrFlags64 XrCompositionLayerSpaceWarpInfoFlagsFB; + +// Flag bits for XrCompositionLayerSpaceWarpInfoFlagsFB +static const XrCompositionLayerSpaceWarpInfoFlagsFB XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB = 0x00000001; + +// XrCompositionLayerSpaceWarpInfoFB extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerSpaceWarpInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSpaceWarpInfoFlagsFB layerFlags; + XrSwapchainSubImage motionVectorSubImage; + XrPosef appSpaceDeltaPose; + XrSwapchainSubImage depthSubImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerSpaceWarpInfoFB; + +// XrSystemSpaceWarpPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpaceWarpPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedMotionVectorImageRectWidth; + uint32_t recommendedMotionVectorImageRectHeight; +} XrSystemSpaceWarpPropertiesFB; + + + +#define XR_FB_scene 1 +#define XR_FB_scene_SPEC_VERSION 1 +#define XR_FB_SCENE_EXTENSION_NAME "XR_FB_scene" +typedef struct XrExtent3DfFB { + float width; + float height; + float depth; +} XrExtent3DfFB; + +typedef struct XrOffset3DfFB { + float x; + float y; + float z; +} XrOffset3DfFB; + +typedef struct XrRect3DfFB { + XrOffset3DfFB offset; + XrExtent3DfFB extent; +} XrRect3DfFB; + +typedef struct XrSemanticLabelsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + char* buffer; +} XrSemanticLabelsFB; + +typedef struct XrRoomLayoutFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidEXT floorUuid; + XrUuidEXT ceilingUuid; + uint32_t wallUuidCapacityInput; + uint32_t wallUuidCountOutput; + XrUuidEXT* wallUuids; +} XrRoomLayoutFB; + +typedef struct XrBoundary2DFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; +} XrBoundary2DFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox2DFB)(XrSession session, XrSpace space, XrRect2Df* boundingBox2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox3DFB)(XrSession session, XrSpace space, XrRect3DfFB* boundingBox3DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceSemanticLabelsFB)(XrSession session, XrSpace space, XrSemanticLabelsFB* semanticLabelsOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundary2DFB)(XrSession session, XrSpace space, XrBoundary2DFB* boundary2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceRoomLayoutFB)(XrSession session, XrSpace space, XrRoomLayoutFB* roomLayoutOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox2DFB( + XrSession session, + XrSpace space, + XrRect2Df* boundingBox2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox3DFB( + XrSession session, + XrSpace space, + XrRect3DfFB* boundingBox3DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceSemanticLabelsFB( + XrSession session, + XrSpace space, + XrSemanticLabelsFB* semanticLabelsOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundary2DFB( + XrSession session, + XrSpace space, + XrBoundary2DFB* boundary2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceRoomLayoutFB( + XrSession session, + XrSpace space, + XrRoomLayoutFB* roomLayoutOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_palm_pose 1 +#define XR_EXT_palm_pose_SPEC_VERSION 2 +#define XR_EXT_PALM_POSE_EXTENSION_NAME "XR_EXT_palm_pose" + + +#define XR_ALMALENCE_digital_lens_control 1 +#define XR_ALMALENCE_digital_lens_control_SPEC_VERSION 1 +#define XR_ALMALENCE_DIGITAL_LENS_CONTROL_EXTENSION_NAME "XR_ALMALENCE_digital_lens_control" +typedef XrFlags64 XrDigitalLensControlFlagsALMALENCE; + +// Flag bits for XrDigitalLensControlFlagsALMALENCE +static const XrDigitalLensControlFlagsALMALENCE XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE = 0x00000001; + +typedef struct XrDigitalLensControlALMALENCE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDigitalLensControlFlagsALMALENCE flags; +} XrDigitalLensControlALMALENCE; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDigitalLensControlALMALENCE)(XrSession session, const XrDigitalLensControlALMALENCE* digitalLensControl); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDigitalLensControlALMALENCE( + XrSession session, + const XrDigitalLensControlALMALENCE* digitalLensControl); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_container 1 +#define XR_FB_spatial_entity_container_SPEC_VERSION 2 +#define XR_FB_SPATIAL_ENTITY_CONTAINER_EXTENSION_NAME "XR_FB_spatial_entity_container" +typedef struct XrSpaceContainerFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCapacityInput; + uint32_t uuidCountOutput; + XrUuidEXT* uuids; +} XrSpaceContainerFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceContainerFB)(XrSession session, XrSpace space, XrSpaceContainerFB* spaceContainerOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceContainerFB( + XrSession session, + XrSpace space, + XrSpaceContainerFB* spaceContainerOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough_keyboard_hands 1 +#define XR_FB_passthrough_keyboard_hands_SPEC_VERSION 2 +#define XR_FB_PASSTHROUGH_KEYBOARD_HANDS_EXTENSION_NAME "XR_FB_passthrough_keyboard_hands" +typedef struct XrPassthroughKeyboardHandsIntensityFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float leftHandIntensity; + float rightHandIntensity; +} XrPassthroughKeyboardHandsIntensityFB; + +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB)(XrPassthroughLayerFB layer, const XrPassthroughKeyboardHandsIntensityFB* intensity); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetKeyboardHandsIntensityFB( + XrPassthroughLayerFB layer, + const XrPassthroughKeyboardHandsIntensityFB* intensity); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_settings 1 +#define XR_FB_composition_layer_settings_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SETTINGS_EXTENSION_NAME "XR_FB_composition_layer_settings" +typedef XrFlags64 XrCompositionLayerSettingsFlagsFB; + +// Flag bits for XrCompositionLayerSettingsFlagsFB +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB = 0x00000001; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB = 0x00000002; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB = 0x00000004; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB = 0x00000008; + +// XrCompositionLayerSettingsFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSettingsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSettingsFlagsFB layerFlags; +} XrCompositionLayerSettingsFB; + + + +#define XR_META_performance_metrics 1 +#define XR_META_performance_metrics_SPEC_VERSION 1 +#define XR_META_PERFORMANCE_METRICS_EXTENSION_NAME "XR_META_performance_metrics" + +typedef enum XrPerformanceMetricsCounterUnitMETA { + XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META = 0, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META = 1, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META = 2, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META = 3, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META = 4, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META = 0x7FFFFFFF +} XrPerformanceMetricsCounterUnitMETA; +typedef XrFlags64 XrPerformanceMetricsCounterFlagsMETA; + +// Flag bits for XrPerformanceMetricsCounterFlagsMETA +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META = 0x00000001; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META = 0x00000002; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META = 0x00000004; + +typedef struct XrPerformanceMetricsStateMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 enabled; +} XrPerformanceMetricsStateMETA; + +typedef struct XrPerformanceMetricsCounterMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPerformanceMetricsCounterFlagsMETA counterFlags; + XrPerformanceMetricsCounterUnitMETA counterUnit; + uint32_t uintValue; + float floatValue; +} XrPerformanceMetricsCounterMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePerformanceMetricsCounterPathsMETA)(XrInstance instance, uint32_t counterPathCapacityInput, uint32_t* counterPathCountOutput, XrPath* counterPaths); +typedef XrResult (XRAPI_PTR *PFN_xrSetPerformanceMetricsStateMETA)(XrSession session, const XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetPerformanceMetricsStateMETA)(XrSession session, XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrQueryPerformanceMetricsCounterMETA)(XrSession session, XrPath counterPath, XrPerformanceMetricsCounterMETA* counter); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePerformanceMetricsCounterPathsMETA( + XrInstance instance, + uint32_t counterPathCapacityInput, + uint32_t* counterPathCountOutput, + XrPath* counterPaths); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetPerformanceMetricsStateMETA( + XrSession session, + const XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetPerformanceMetricsStateMETA( + XrSession session, + XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrQueryPerformanceMetricsCounterMETA( + XrSession session, + XrPath counterPath, + XrPerformanceMetricsCounterMETA* counter); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_uuid 1 +#define XR_EXT_uuid_SPEC_VERSION 1 +#define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid" #ifdef __cplusplus } diff --git a/ext/openxr/openxr_platform.h b/ext/openxr/openxr_platform.h index f7e6338064..f0fbf6955a 100644 --- a/ext/openxr/openxr_platform.h +++ b/ext/openxr/openxr_platform.h @@ -2,7 +2,7 @@ #define OPENXR_PLATFORM_H_ 1 /* -** Copyright (c) 2017-2021, The Khronos Group Inc. +** Copyright (c) 2017-2022, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -35,11 +35,13 @@ typedef enum XrAndroidThreadTypeKHR { typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR( XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_ANDROID */ #ifdef XR_USE_PLATFORM_ANDROID @@ -50,12 +52,14 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR( typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR( XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_ANDROID */ #ifdef XR_USE_PLATFORM_ANDROID @@ -63,6 +67,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR( #define XR_KHR_android_create_instance 1 #define XR_KHR_android_create_instance_SPEC_VERSION 3 #define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance" +// XrInstanceCreateInfoAndroidKHR extends XrInstanceCreateInfo typedef struct XrInstanceCreateInfoAndroidKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -75,7 +80,7 @@ typedef struct XrInstanceCreateInfoAndroidKHR { #ifdef XR_USE_GRAPHICS_API_VULKAN #define XR_KHR_vulkan_swapchain_format_list 1 -#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 3 +#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 4 #define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list" typedef struct XrVulkanSwapchainFormatListCreateInfoKHR { XrStructureType type; @@ -89,9 +94,10 @@ typedef struct XrVulkanSwapchainFormatListCreateInfoKHR { #ifdef XR_USE_GRAPHICS_API_OPENGL #define XR_KHR_opengl_enable 1 -#define XR_KHR_opengl_enable_SPEC_VERSION 9 +#define XR_KHR_opengl_enable_SPEC_VERSION 10 #define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable" #ifdef XR_USE_PLATFORM_WIN32 +// XrGraphicsBindingOpenGLWin32KHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLWin32KHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -101,6 +107,7 @@ typedef struct XrGraphicsBindingOpenGLWin32KHR { #endif // XR_USE_PLATFORM_WIN32 #ifdef XR_USE_PLATFORM_XLIB +// XrGraphicsBindingOpenGLXlibKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLXlibKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -113,6 +120,7 @@ typedef struct XrGraphicsBindingOpenGLXlibKHR { #endif // XR_USE_PLATFORM_XLIB #ifdef XR_USE_PLATFORM_XCB +// XrGraphicsBindingOpenGLXcbKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLXcbKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -126,6 +134,7 @@ typedef struct XrGraphicsBindingOpenGLXcbKHR { #endif // XR_USE_PLATFORM_XCB #ifdef XR_USE_PLATFORM_WAYLAND +// XrGraphicsBindingOpenGLWaylandKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLWaylandKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -149,19 +158,22 @@ typedef struct XrGraphicsRequirementsOpenGLKHR { typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_OPENGL */ #ifdef XR_USE_GRAPHICS_API_OPENGL_ES #define XR_KHR_opengl_es_enable 1 -#define XR_KHR_opengl_es_enable_SPEC_VERSION 7 +#define XR_KHR_opengl_es_enable_SPEC_VERSION 8 #define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable" #ifdef XR_USE_PLATFORM_ANDROID +// XrGraphicsBindingOpenGLESAndroidKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLESAndroidKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -187,18 +199,21 @@ typedef struct XrGraphicsRequirementsOpenGLESKHR { typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ #ifdef XR_USE_GRAPHICS_API_VULKAN #define XR_KHR_vulkan_enable 1 -#define XR_KHR_vulkan_enable_SPEC_VERSION 7 +#define XR_KHR_vulkan_enable_SPEC_VERSION 8 #define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable" +// XrGraphicsBindingVulkanKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingVulkanKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -228,6 +243,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instan typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR( XrInstance instance, XrSystemId systemId, @@ -252,14 +268,16 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_VULKAN */ #ifdef XR_USE_GRAPHICS_API_D3D11 #define XR_KHR_D3D11_enable 1 -#define XR_KHR_D3D11_enable_SPEC_VERSION 5 +#define XR_KHR_D3D11_enable_SPEC_VERSION 9 #define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable" +// XrGraphicsBindingD3D11KHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingD3D11KHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -282,18 +300,21 @@ typedef struct XrGraphicsRequirementsD3D11KHR { typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_D3D11 */ #ifdef XR_USE_GRAPHICS_API_D3D12 #define XR_KHR_D3D12_enable 1 -#define XR_KHR_D3D12_enable_SPEC_VERSION 7 +#define XR_KHR_D3D12_enable_SPEC_VERSION 9 #define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable" +// XrGraphicsBindingD3D12KHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingD3D12KHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -317,11 +338,13 @@ typedef struct XrGraphicsRequirementsD3D12KHR { typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_D3D12 */ #ifdef XR_USE_PLATFORM_WIN32 @@ -333,6 +356,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrIn typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR( XrInstance instance, const LARGE_INTEGER* performanceCounter, @@ -342,7 +366,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR( XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_WIN32 */ #ifdef XR_USE_TIMESPEC @@ -354,6 +379,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance inst typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR( XrInstance instance, const struct timespec* timespecTime, @@ -363,7 +389,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR( XrInstance instance, XrTime time, struct timespec* timespecTime); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_TIMESPEC */ #ifdef XR_USE_PLATFORM_ANDROID @@ -383,7 +410,7 @@ typedef struct XrLoaderInitInfoAndroidKHR { #ifdef XR_USE_GRAPHICS_API_VULKAN #define XR_KHR_vulkan_enable2 1 -#define XR_KHR_vulkan_enable2_SPEC_VERSION 1 +#define XR_KHR_vulkan_enable2_SPEC_VERSION 2 #define XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME "XR_KHR_vulkan_enable2" typedef XrFlags64 XrVulkanInstanceCreateFlagsKHR; @@ -427,12 +454,13 @@ typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR; typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR; -typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR*createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult); typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult); typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice); typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanInstanceKHR( XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, @@ -454,7 +482,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_VULKAN */ #ifdef XR_USE_PLATFORM_EGL @@ -462,6 +491,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( #define XR_MNDX_egl_enable 1 #define XR_MNDX_egl_enable_SPEC_VERSION 1 #define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable" +// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo typedef struct XrGraphicsBindingEGLMNDX { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -482,6 +512,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)( typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT( XrSession session, IUnknown* perceptionAnchor, @@ -491,7 +522,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT( XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_WIN32 */ #ifdef XR_USE_PLATFORM_WIN32 @@ -500,6 +532,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT( #define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1 #define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment" #ifdef XR_USE_PLATFORM_WIN32 +// XrHolographicWindowAttachmentMSFT extends XrSessionCreateInfo typedef struct XrHolographicWindowAttachmentMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -522,6 +555,7 @@ static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCH static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002; #ifdef XR_USE_PLATFORM_ANDROID +// XrAndroidSurfaceSwapchainCreateInfoFB extends XrSwapchainCreateInfo typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -531,6 +565,124 @@ typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { #endif /* XR_USE_PLATFORM_ANDROID */ +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_OCULUS_audio_device_guid 1 +#define XR_OCULUS_audio_device_guid_SPEC_VERSION 1 +#define XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME "XR_OCULUS_audio_device_guid" +#define XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS 128 +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioOutputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioInputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioOutputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioInputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_foveation_vulkan 1 +#define XR_FB_foveation_vulkan_SPEC_VERSION 1 +#define XR_FB_FOVEATION_VULKAN_EXTENSION_NAME "XR_FB_foveation_vulkan" +// XrSwapchainImageFoveationVulkanFB extends XrSwapchainImageVulkanKHR +typedef struct XrSwapchainImageFoveationVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; + uint32_t width; + uint32_t height; +} XrSwapchainImageFoveationVulkanFB; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_swapchain_update_state_android_surface 1 +#define XR_FB_swapchain_update_state_android_surface_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_ANDROID_SURFACE_EXTENSION_NAME "XR_FB_swapchain_update_state_android_surface" +#ifdef XR_USE_PLATFORM_ANDROID +typedef struct XrSwapchainStateAndroidSurfaceDimensionsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t width; + uint32_t height; +} XrSwapchainStateAndroidSurfaceDimensionsFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_FB_swapchain_update_state_opengl_es 1 +#define XR_FB_swapchain_update_state_opengl_es_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME "XR_FB_swapchain_update_state_opengl_es" +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +typedef struct XrSwapchainStateSamplerOpenGLESFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + EGLenum minFilter; + EGLenum magFilter; + EGLenum wrapModeS; + EGLenum wrapModeT; + EGLenum swizzleRed; + EGLenum swizzleGreen; + EGLenum swizzleBlue; + EGLenum swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerOpenGLESFB; +#endif // XR_USE_GRAPHICS_API_OPENGL_ES + +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_swapchain_update_state_vulkan 1 +#define XR_FB_swapchain_update_state_vulkan_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME "XR_FB_swapchain_update_state_vulkan" +#ifdef XR_USE_GRAPHICS_API_VULKAN +typedef struct XrSwapchainStateSamplerVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkFilter minFilter; + VkFilter magFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode wrapModeS; + VkSamplerAddressMode wrapModeT; + VkComponentSwizzle swizzleRed; + VkComponentSwizzle swizzleGreen; + VkComponentSwizzle swizzleBlue; + VkComponentSwizzle swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerVulkanFB; +#endif // XR_USE_GRAPHICS_API_VULKAN + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_META_vulkan_swapchain_create_info 1 +#define XR_META_vulkan_swapchain_create_info_SPEC_VERSION 1 +#define XR_META_VULKAN_SWAPCHAIN_CREATE_INFO_EXTENSION_NAME "XR_META_vulkan_swapchain_create_info" +// XrVulkanSwapchainCreateInfoMETA extends XrSwapchainCreateInfo +typedef struct XrVulkanSwapchainCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + VkImageCreateFlags additionalCreateFlags; + VkImageUsageFlags additionalUsageFlags; +} XrVulkanSwapchainCreateInfoMETA; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + #ifdef __cplusplus } #endif diff --git a/ext/openxr/openxr_platform_defines.h b/ext/openxr/openxr_platform_defines.h index a7ffcb459e..31fa05a0c8 100644 --- a/ext/openxr/openxr_platform_defines.h +++ b/ext/openxr/openxr_platform_defines.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2017-2021, The Khronos Group Inc. +** Copyright (c) 2017-2022, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ diff --git a/ext/openxr/openxr_reflection.h b/ext/openxr/openxr_reflection.h index 5597c94a6e..31e2e40945 100644 --- a/ext/openxr/openxr_reflection.h +++ b/ext/openxr/openxr_reflection.h @@ -2,7 +2,7 @@ #define OPENXR_REFLECTION_H_ 1 /* -** Copyright (c) 2017-2021, The Khronos Group Inc. +** Copyright (c) 2017-2022, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -85,13 +85,37 @@ XR_ENUM_STR(XrResult); _(XR_ERROR_LOCALIZED_NAME_DUPLICATED, -48) \ _(XR_ERROR_LOCALIZED_NAME_INVALID, -49) \ _(XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, -50) \ + _(XR_ERROR_RUNTIME_UNAVAILABLE, -51) \ _(XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR, -1000003000) \ _(XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR, -1000003001) \ _(XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT, -1000039001) \ _(XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT, -1000053000) \ _(XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT, -1000055000) \ + _(XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT, -1000066000) \ + _(XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT, -1000097000) \ + _(XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT, -1000097001) \ + _(XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT, -1000097002) \ + _(XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT, -1000097003) \ + _(XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT, -1000097004) \ + _(XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT, -1000097005) \ _(XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB, -1000101000) \ _(XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB, -1000108000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB, -1000113000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB, -1000113001) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB, -1000113002) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB, -1000113003) \ + _(XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB, -1000118000) \ + _(XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB, -1000118001) \ + _(XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB, -1000118002) \ + _(XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB, -1000118003) \ + _(XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB, -1000118004) \ + _(XR_ERROR_UNKNOWN_PASSTHROUGH_FB, -1000118050) \ + _(XR_ERROR_RENDER_MODEL_KEY_INVALID_FB, -1000119000) \ + _(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \ + _(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \ + _(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \ _(XR_RESULT_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrStructureType(_) \ @@ -183,9 +207,14 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR, 1000034000) \ _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT, 1000039000) \ _(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT, 1000039001) \ + _(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB, 1000040000) \ + _(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB, 1000041001) \ _(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT, 1000046000) \ _(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, 1000048004) \ _(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT, 1000049000) \ + _(XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT, 1000049001) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT, 1000049002) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT, 1000049003) \ _(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, 1000051000) \ _(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, 1000051001) \ _(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, 1000051002) \ @@ -209,16 +238,118 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT, 1000055004) \ _(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC, 1000059000) \ _(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT, 1000063000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT, 1000066000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT, 1000066001) \ _(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \ + _(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB, 1000072000) \ + _(XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT, 1000078000) \ _(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \ + _(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, 1000080000) \ _(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, 1000089000) \ _(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, 1000090000) \ _(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, 1000090001) \ _(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, 1000090003) \ _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, 1000091000) \ + _(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT, 1000097000) \ + _(XR_TYPE_SCENE_CREATE_INFO_MSFT, 1000097001) \ + _(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT, 1000097002) \ + _(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT, 1000097003) \ + _(XR_TYPE_SCENE_COMPONENTS_MSFT, 1000097004) \ + _(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT, 1000097005) \ + _(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT, 1000097006) \ + _(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT, 1000097007) \ + _(XR_TYPE_SCENE_OBJECTS_MSFT, 1000097008) \ + _(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT, 1000097009) \ + _(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT, 1000097010) \ + _(XR_TYPE_SCENE_PLANES_MSFT, 1000097011) \ + _(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT, 1000097012) \ + _(XR_TYPE_SCENE_MESHES_MSFT, 1000097013) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT, 1000097014) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_MSFT, 1000097015) \ + _(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT, 1000097016) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT, 1000097017) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT, 1000097018) \ + _(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT, 1000098000) \ + _(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT, 1000098001) \ _(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB, 1000101000) \ + _(XR_TYPE_VIVE_TRACKER_PATHS_HTCX, 1000103000) \ + _(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX, 1000103001) \ + _(XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC, 1000104000) \ + _(XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC, 1000104001) \ + _(XR_TYPE_FACIAL_EXPRESSIONS_HTC, 1000104002) \ _(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB, 1000108000) \ + _(XR_TYPE_HAND_TRACKING_MESH_FB, 1000110001) \ + _(XR_TYPE_HAND_TRACKING_SCALE_FB, 1000110003) \ + _(XR_TYPE_HAND_TRACKING_AIM_STATE_FB, 1000111001) \ + _(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB, 1000112000) \ + _(XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB, 1000113004) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB, 1000113003) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB, 1000113007) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_FB, 1000113001) \ + _(XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB, 1000113005) \ + _(XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB, 1000113006) \ + _(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB, 1000114000) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB, 1000114001) \ + _(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB, 1000114002) \ + _(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB, 1000115000) \ + _(XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB, 1000116009) \ + _(XR_TYPE_KEYBOARD_TRACKING_QUERY_FB, 1000116004) \ + _(XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB, 1000116002) \ + _(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB, 1000117001) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB, 1000118000) \ + _(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, 1000118001) \ + _(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, 1000118002) \ + _(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, 1000118003) \ + _(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB, 1000118004) \ + _(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB, 1000118005) \ + _(XR_TYPE_PASSTHROUGH_STYLE_FB, 1000118020) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB, 1000118021) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB, 1000118022) \ + _(XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB, 1000118023) \ + _(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB, 1000118030) \ + _(XR_TYPE_RENDER_MODEL_PATH_INFO_FB, 1000119000) \ + _(XR_TYPE_RENDER_MODEL_PROPERTIES_FB, 1000119001) \ + _(XR_TYPE_RENDER_MODEL_BUFFER_FB, 1000119002) \ + _(XR_TYPE_RENDER_MODEL_LOAD_INFO_FB, 1000119003) \ + _(XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB, 1000119004) \ + _(XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB, 1000119005) \ _(XR_TYPE_BINDING_MODIFICATIONS_KHR, 1000120000) \ + _(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO, 1000121000) \ + _(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO, 1000121001) \ + _(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO, 1000121002) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO, 1000122000) \ + _(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO, 1000124000) \ + _(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO, 1000124001) \ + _(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO, 1000124002) \ + _(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT, 1000142000) \ + _(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT, 1000142001) \ + _(XR_TYPE_SPACE_QUERY_INFO_FB, 1000156001) \ + _(XR_TYPE_SPACE_QUERY_RESULTS_FB, 1000156002) \ + _(XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB, 1000156003) \ + _(XR_TYPE_SPACE_UUID_FILTER_INFO_FB, 1000156054) \ + _(XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB, 1000156052) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB, 1000156103) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB, 1000156104) \ + _(XR_TYPE_SPACE_SAVE_INFO_FB, 1000158000) \ + _(XR_TYPE_SPACE_ERASE_INFO_FB, 1000158001) \ + _(XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB, 1000158106) \ + _(XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB, 1000158107) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB, 1000160000) \ + _(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB, 1000161000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB, 1000162000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB, 1000163000) \ + _(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB, 1000171000) \ + _(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB, 1000171001) \ + _(XR_TYPE_SEMANTIC_LABELS_FB, 1000175000) \ + _(XR_TYPE_ROOM_LAYOUT_FB, 1000175001) \ + _(XR_TYPE_BOUNDARY_2D_FB, 1000175002) \ + _(XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE, 1000196000) \ + _(XR_TYPE_SPACE_CONTAINER_FB, 1000199000) \ + _(XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB, 1000203002) \ + _(XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB, 1000204000) \ + _(XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META, 1000227000) \ + _(XR_TYPE_PERFORMANCE_METRICS_STATE_META, 1000232001) \ + _(XR_TYPE_PERFORMANCE_METRICS_COUNTER_META, 1000232002) \ _(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrFormFactor(_) \ @@ -244,6 +375,7 @@ XR_ENUM_STR(XrResult); _(XR_REFERENCE_SPACE_TYPE_LOCAL, 2) \ _(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \ _(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \ + _(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \ _(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrActionType(_) \ @@ -282,7 +414,17 @@ XR_ENUM_STR(XrResult); _(XR_OBJECT_TYPE_ACTION, 6) \ _(XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, 1000019000) \ _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT, 1000039000) \ + _(XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT, 1000049000) \ _(XR_OBJECT_TYPE_HAND_TRACKER_EXT, 1000051000) \ + _(XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT, 1000097000) \ + _(XR_OBJECT_TYPE_SCENE_MSFT, 1000097001) \ + _(XR_OBJECT_TYPE_FACIAL_TRACKER_HTC, 1000104000) \ + _(XR_OBJECT_TYPE_FOVEATION_PROFILE_FB, 1000114000) \ + _(XR_OBJECT_TYPE_TRIANGLE_MESH_FB, 1000117000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \ + _(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \ _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \ @@ -322,6 +464,15 @@ XR_ENUM_STR(XrResult); _(XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT, 75) \ _(XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrBlendFactorFB(_) \ + _(XR_BLEND_FACTOR_ZERO_FB, 0) \ + _(XR_BLEND_FACTOR_ONE_FB, 1) \ + _(XR_BLEND_FACTOR_SRC_ALPHA_FB, 2) \ + _(XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB, 3) \ + _(XR_BLEND_FACTOR_DST_ALPHA_FB, 4) \ + _(XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB, 5) \ + _(XR_BLEND_FACTOR_MAX_ENUM_FB, 0x7FFFFFFF) + #define XR_LIST_ENUM_XrSpatialGraphNodeTypeMSFT(_) \ _(XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT, 1) \ _(XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT, 2) \ @@ -363,6 +514,7 @@ XR_ENUM_STR(XrResult); #define XR_LIST_ENUM_XrHandJointSetEXT(_) \ _(XR_HAND_JOINT_SET_DEFAULT_EXT, 0) \ + _(XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP, 1000149000) \ _(XR_HAND_JOINT_SET_MAX_ENUM_EXT, 0x7FFFFFFF) #define XR_LIST_ENUM_XrHandPoseTypeMSFT(_) \ @@ -370,6 +522,133 @@ XR_ENUM_STR(XrResult); _(XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT, 1) \ _(XR_HAND_POSE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrReprojectionModeMSFT(_) \ + _(XR_REPROJECTION_MODE_DEPTH_MSFT, 1) \ + _(XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT, 2) \ + _(XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT, 3) \ + _(XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT, 4) \ + _(XR_REPROJECTION_MODE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointsMotionRangeEXT(_) \ + _(XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT, 1) \ + _(XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT, 2) \ + _(XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeFeatureMSFT(_) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT, 2) \ + _(XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT, 1000098000) \ + _(XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeConsistencyMSFT(_) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT, 2) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT, 3) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMeshComputeLodMSFT(_) \ + _(XR_MESH_COMPUTE_LOD_COARSE_MSFT, 1) \ + _(XR_MESH_COMPUTE_LOD_MEDIUM_MSFT, 2) \ + _(XR_MESH_COMPUTE_LOD_FINE_MSFT, 3) \ + _(XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT, 4) \ + _(XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComponentTypeMSFT(_) \ + _(XR_SCENE_COMPONENT_TYPE_INVALID_MSFT, -1) \ + _(XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT, 1) \ + _(XR_SCENE_COMPONENT_TYPE_PLANE_MSFT, 2) \ + _(XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT, 1000098000) \ + _(XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneObjectTypeMSFT(_) \ + _(XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT, -1) \ + _(XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT, 1) \ + _(XR_SCENE_OBJECT_TYPE_WALL_MSFT, 2) \ + _(XR_SCENE_OBJECT_TYPE_FLOOR_MSFT, 3) \ + _(XR_SCENE_OBJECT_TYPE_CEILING_MSFT, 4) \ + _(XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT, 5) \ + _(XR_SCENE_OBJECT_TYPE_INFERRED_MSFT, 6) \ + _(XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrScenePlaneAlignmentTypeMSFT(_) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT, 0) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT, 1) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT, 2) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeStateMSFT(_) \ + _(XR_SCENE_COMPUTE_STATE_NONE_MSFT, 0) \ + _(XR_SCENE_COMPUTE_STATE_UPDATING_MSFT, 1) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT, 2) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT, 3) \ + _(XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeExpressionHTC(_) \ + _(XR_EYE_EXPRESSION_LEFT_BLINK_HTC, 0) \ + _(XR_EYE_EXPRESSION_LEFT_WIDE_HTC, 1) \ + _(XR_EYE_EXPRESSION_RIGHT_BLINK_HTC, 2) \ + _(XR_EYE_EXPRESSION_RIGHT_WIDE_HTC, 3) \ + _(XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC, 4) \ + _(XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC, 5) \ + _(XR_EYE_EXPRESSION_LEFT_DOWN_HTC, 6) \ + _(XR_EYE_EXPRESSION_RIGHT_DOWN_HTC, 7) \ + _(XR_EYE_EXPRESSION_LEFT_OUT_HTC, 8) \ + _(XR_EYE_EXPRESSION_RIGHT_IN_HTC, 9) \ + _(XR_EYE_EXPRESSION_LEFT_IN_HTC, 10) \ + _(XR_EYE_EXPRESSION_RIGHT_OUT_HTC, 11) \ + _(XR_EYE_EXPRESSION_LEFT_UP_HTC, 12) \ + _(XR_EYE_EXPRESSION_RIGHT_UP_HTC, 13) \ + _(XR_EYE_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLipExpressionHTC(_) \ + _(XR_LIP_EXPRESSION_JAW_RIGHT_HTC, 0) \ + _(XR_LIP_EXPRESSION_JAW_LEFT_HTC, 1) \ + _(XR_LIP_EXPRESSION_JAW_FORWARD_HTC, 2) \ + _(XR_LIP_EXPRESSION_JAW_OPEN_HTC, 3) \ + _(XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC, 4) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC, 5) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC, 6) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC, 7) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC, 8) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC, 9) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC, 10) \ + _(XR_LIP_EXPRESSION_MOUTH_POUT_HTC, 11) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC, 12) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC, 13) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC, 14) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC, 15) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC, 16) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC, 17) \ + _(XR_LIP_EXPRESSION_CHEEK_SUCK_HTC, 18) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC, 19) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC, 20) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC, 21) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC, 22) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC, 23) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC, 24) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC, 25) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC, 26) \ + _(XR_LIP_EXPRESSION_TONGUE_LEFT_HTC, 27) \ + _(XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC, 28) \ + _(XR_LIP_EXPRESSION_TONGUE_UP_HTC, 29) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWN_HTC, 30) \ + _(XR_LIP_EXPRESSION_TONGUE_ROLL_HTC, 31) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC, 32) \ + _(XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC, 33) \ + _(XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC, 34) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC, 35) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC, 36) \ + _(XR_LIP_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFacialTrackingTypeHTC(_) \ + _(XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC, 1) \ + _(XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC, 2) \ + _(XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC, 0x7FFFFFFF) + #define XR_LIST_ENUM_XrColorSpaceFB(_) \ _(XR_COLOR_SPACE_UNMANAGED_FB, 0) \ _(XR_COLOR_SPACE_REC2020_FB, 1) \ @@ -381,6 +660,93 @@ XR_ENUM_STR(XrResult); _(XR_COLOR_SPACE_ADOBE_RGB_FB, 7) \ _(XR_COLOR_SPACE_MAX_ENUM_FB, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrSpaceComponentTypeFB(_) \ + _(XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB, 0) \ + _(XR_SPACE_COMPONENT_TYPE_STORABLE_FB, 1) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB, 3) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB, 4) \ + _(XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB, 5) \ + _(XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB, 6) \ + _(XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB, 7) \ + _(XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationLevelFB(_) \ + _(XR_FOVEATION_LEVEL_NONE_FB, 0) \ + _(XR_FOVEATION_LEVEL_LOW_FB, 1) \ + _(XR_FOVEATION_LEVEL_MEDIUM_FB, 2) \ + _(XR_FOVEATION_LEVEL_HIGH_FB, 3) \ + _(XR_FOVEATION_LEVEL_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationDynamicFB(_) \ + _(XR_FOVEATION_DYNAMIC_DISABLED_FB, 0) \ + _(XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB, 1) \ + _(XR_FOVEATION_DYNAMIC_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrWindingOrderFB(_) \ + _(XR_WINDING_ORDER_UNKNOWN_FB, 0) \ + _(XR_WINDING_ORDER_CW_FB, 1) \ + _(XR_WINDING_ORDER_CCW_FB, 2) \ + _(XR_WINDING_ORDER_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPassthroughLayerPurposeFB(_) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, 0) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB, 1) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB, 1000203001) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB, 1000203002) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandForearmJointULTRALEAP(_) \ + _(XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP, 0) \ + _(XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP, 1) \ + _(XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP, 2) \ + _(XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP, 3) \ + _(XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP, 4) \ + _(XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP, 5) \ + _(XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP, 6) \ + _(XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP, 7) \ + _(XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP, 8) \ + _(XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP, 9) \ + _(XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP, 10) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP, 11) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP, 12) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP, 13) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP, 14) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP, 15) \ + _(XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP, 16) \ + _(XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP, 17) \ + _(XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP, 18) \ + _(XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP, 19) \ + _(XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP, 20) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP, 21) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP, 22) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP, 23) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP, 24) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP, 25) \ + _(XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP, 26) \ + _(XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceQueryActionFB(_) \ + _(XR_SPACE_QUERY_ACTION_LOAD_FB, 0) \ + _(XR_SPACE_QUERY_ACTION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceStorageLocationFB(_) \ + _(XR_SPACE_STORAGE_LOCATION_INVALID_FB, 0) \ + _(XR_SPACE_STORAGE_LOCATION_LOCAL_FB, 1) \ + _(XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpacePersistenceModeFB(_) \ + _(XR_SPACE_PERSISTENCE_MODE_INVALID_FB, 0) \ + _(XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB, 1) \ + _(XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerformanceMetricsCounterUnitMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META, 0) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META, 1) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META, 2) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META, 3) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META, 4) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META, 0x7FFFFFFF) + #define XR_LIST_BITS_XrInstanceCreateFlags(_) #define XR_LIST_BITS_XrSessionCreateFlags(_) @@ -408,6 +774,7 @@ XR_ENUM_STR(XrResult); _(XR_SWAPCHAIN_USAGE_SAMPLED_BIT, 0x00000020) \ _(XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, 0x00000040) \ _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND, 0x00000080) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR, XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND) \ #define XR_LIST_BITS_XrCompositionLayerFlags(_) \ _(XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, 0x00000001) \ @@ -441,16 +808,82 @@ XR_ENUM_STR(XrResult); _(XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 0x00000004) \ _(XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT, 0x00000008) \ -#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_) \ - _(XR_OVERLAY_SESSION_CREATE_RELAXED_DISPLAY_TIME_BIT_EXTX, 0x00000001) \ +#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_) #define XR_LIST_BITS_XrOverlayMainSessionFlagsEXTX(_) \ _(XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX, 0x00000001) \ +#define XR_LIST_BITS_XrCompositionLayerImageLayoutFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB, 0x00000001) \ + #define XR_LIST_BITS_XrAndroidSurfaceSwapchainFlagsFB(_) \ _(XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB, 0x00000001) \ _(XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB, 0x00000002) \ +#define XR_LIST_BITS_XrCompositionLayerSecureContentFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrHandTrackingAimFlagsFB(_) \ + _(XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB, 0x00000001) \ + _(XR_HAND_TRACKING_AIM_VALID_BIT_FB, 0x00000002) \ + _(XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB, 0x00000004) \ + _(XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB, 0x00000008) \ + _(XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB, 0x00000010) \ + _(XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB, 0x00000020) \ + _(XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB, 0x00000040) \ + _(XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB, 0x00000080) \ + _(XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB, 0x00000100) \ + +#define XR_LIST_BITS_XrSwapchainCreateFoveationFlagsFB(_) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainStateFoveationFlagsFB(_) + +#define XR_LIST_BITS_XrKeyboardTrackingFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_EXISTS_BIT_FB, 0x00000001) \ + _(XR_KEYBOARD_TRACKING_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_REMOTE_BIT_FB, 0x00000004) \ + _(XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrKeyboardTrackingQueryFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB, 0x00000004) \ + +#define XR_LIST_BITS_XrTriangleMeshFlagsFB(_) \ + _(XR_TRIANGLE_MESH_MUTABLE_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughFlagsFB(_) \ + _(XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughStateChangedFlagsFB(_) \ + _(XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB, 0x00000002) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB, 0x00000004) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrRenderModelFlagsFB(_) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB, 0x00000001) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \ + _(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerSettingsFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB, 0x00000002) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB, 0x00000004) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrPerformanceMetricsCounterFlagsMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META, 0x00000001) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META, 0x00000002) \ + _(XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META, 0x00000004) \ + #define XR_LIST_STRUCT_XrApiLayerProperties(_) \ _(type) \ _(next) \ @@ -1213,6 +1646,19 @@ XR_ENUM_STR(XrResult); _(anchor) \ _(poseInAnchorSpace) \ +#define XR_LIST_STRUCT_XrCompositionLayerImageLayoutFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrCompositionLayerAlphaBlendFB(_) \ + _(type) \ + _(next) \ + _(srcFactorColor) \ + _(dstFactorColor) \ + _(srcFactorAlpha) \ + _(dstFactorAlpha) \ + #define XR_LIST_STRUCT_XrViewConfigurationDepthRangeEXT(_) \ _(type) \ _(next) \ @@ -1236,6 +1682,23 @@ XR_ENUM_STR(XrResult); _(nodeId) \ _(pose) \ +#define XR_LIST_STRUCT_XrSpatialGraphStaticNodeBindingCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesGetInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(nodeId) \ + _(poseInNodeSpace) \ + #define XR_LIST_STRUCT_XrSystemHandTrackingPropertiesEXT(_) \ _(type) \ _(next) \ @@ -1404,11 +1867,45 @@ XR_ENUM_STR(XrResult); _(holographicSpace) \ _(coreWindow) \ +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionInfoMSFT(_) \ + _(type) \ + _(next) \ + _(reprojectionMode) \ + +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionPlaneOverrideMSFT(_) \ + _(type) \ + _(next) \ + _(position) \ + _(normal) \ + _(velocity) \ + #define XR_LIST_STRUCT_XrAndroidSurfaceSwapchainCreateInfoFB(_) \ _(type) \ _(next) \ _(createFlags) \ +#define XR_LIST_STRUCT_XrSwapchainStateBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSecureContentFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrInteractionProfileDpadBindingEXT(_) \ + _(type) \ + _(next) \ + _(binding) \ + _(actionSet) \ + _(forceThreshold) \ + _(forceThresholdReleased) \ + _(centerRegion) \ + _(wedgeAngle) \ + _(isSticky) \ + _(onHaptic) \ + _(offHaptic) \ + #define XR_LIST_STRUCT_XrInteractionProfileAnalogThresholdVALVE(_) \ _(type) \ _(next) \ @@ -1419,17 +1916,765 @@ XR_ENUM_STR(XrResult); _(onHaptic) \ _(offHaptic) \ +#define XR_LIST_STRUCT_XrHandJointsMotionRangeInfoEXT(_) \ + _(type) \ + _(next) \ + _(handJointsMotionRange) \ + +#define XR_LIST_STRUCT_XrUuidMSFT(_) \ + _(bytes) \ + +#define XR_LIST_STRUCT_XrSceneObserverCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneSphereBoundMSFT(_) \ + _(center) \ + _(radius) \ + +#define XR_LIST_STRUCT_XrSceneOrientedBoxBoundMSFT(_) \ + _(pose) \ + _(extents) \ + +#define XR_LIST_STRUCT_XrSceneFrustumBoundMSFT(_) \ + _(pose) \ + _(fov) \ + _(farDistance) \ + +#define XR_LIST_STRUCT_XrSceneBoundsMSFT(_) \ + _(space) \ + _(time) \ + _(sphereCount) \ + _(spheres) \ + _(boxCount) \ + _(boxes) \ + _(frustumCount) \ + _(frustums) \ + +#define XR_LIST_STRUCT_XrNewSceneComputeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(requestedFeatureCount) \ + _(requestedFeatures) \ + _(consistency) \ + _(bounds) \ + +#define XR_LIST_STRUCT_XrVisualMeshComputeLodInfoMSFT(_) \ + _(type) \ + _(next) \ + _(lod) \ + +#define XR_LIST_STRUCT_XrSceneComponentMSFT(_) \ + _(componentType) \ + _(id) \ + _(parentId) \ + _(updateTime) \ + +#define XR_LIST_STRUCT_XrSceneComponentsMSFT(_) \ + _(type) \ + _(next) \ + _(componentCapacityInput) \ + _(componentCountOutput) \ + _(components) \ + +#define XR_LIST_STRUCT_XrSceneComponentsGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationMSFT(_) \ + _(flags) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationsMSFT(_) \ + _(type) \ + _(next) \ + _(locationCount) \ + _(locations) \ + +#define XR_LIST_STRUCT_XrSceneComponentsLocateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(componentIdCount) \ + _(componentIds) \ + +#define XR_LIST_STRUCT_XrSceneObjectMSFT(_) \ + _(objectType) \ + +#define XR_LIST_STRUCT_XrSceneObjectsMSFT(_) \ + _(type) \ + _(next) \ + _(sceneObjectCount) \ + _(sceneObjects) \ + +#define XR_LIST_STRUCT_XrSceneComponentParentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(parentId) \ + +#define XR_LIST_STRUCT_XrSceneObjectTypesFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(objectTypeCount) \ + _(objectTypes) \ + +#define XR_LIST_STRUCT_XrScenePlaneMSFT(_) \ + _(alignment) \ + _(size) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrScenePlanesMSFT(_) \ + _(type) \ + _(next) \ + _(scenePlaneCount) \ + _(scenePlanes) \ + +#define XR_LIST_STRUCT_XrScenePlaneAlignmentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(alignmentCount) \ + _(alignments) \ + +#define XR_LIST_STRUCT_XrSceneMeshMSFT(_) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrSceneMeshesMSFT(_) \ + _(type) \ + _(next) \ + _(sceneMeshCount) \ + _(sceneMeshes) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(meshBufferId) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneMeshVertexBufferMSFT(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint32MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint16MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSerializedSceneFragmentDataGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(sceneFragmentId) \ + +#define XR_LIST_STRUCT_XrDeserializeSceneFragmentMSFT(_) \ + _(bufferSize) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrSceneDeserializeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(fragmentCount) \ + _(fragments) \ + #define XR_LIST_STRUCT_XrEventDataDisplayRefreshRateChangedFB(_) \ _(type) \ _(next) \ _(fromDisplayRefreshRate) \ _(toDisplayRefreshRate) \ +#define XR_LIST_STRUCT_XrViveTrackerPathsHTCX(_) \ + _(type) \ + _(next) \ + _(persistentPath) \ + _(rolePath) \ + +#define XR_LIST_STRUCT_XrEventDataViveTrackerConnectedHTCX(_) \ + _(type) \ + _(next) \ + _(paths) \ + +#define XR_LIST_STRUCT_XrSystemFacialTrackingPropertiesHTC(_) \ + _(type) \ + _(next) \ + _(supportEyeFacialTracking) \ + _(supportLipFacialTracking) \ + +#define XR_LIST_STRUCT_XrFacialExpressionsHTC(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(sampleTime) \ + _(expressionCount) \ + _(expressionWeightings) \ + +#define XR_LIST_STRUCT_XrFacialTrackerCreateInfoHTC(_) \ + _(type) \ + _(next) \ + _(facialTrackingType) \ + #define XR_LIST_STRUCT_XrSystemColorSpacePropertiesFB(_) \ _(type) \ _(next) \ _(colorSpace) \ +#define XR_LIST_STRUCT_XrVector4sFB(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrHandTrackingMeshFB(_) \ + _(type) \ + _(next) \ + _(jointCapacityInput) \ + _(jointCountOutput) \ + _(jointBindPoses) \ + _(jointRadii) \ + _(jointParents) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertexPositions) \ + _(vertexNormals) \ + _(vertexUVs) \ + _(vertexBlendIndices) \ + _(vertexBlendWeights) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrHandTrackingScaleFB(_) \ + _(type) \ + _(next) \ + _(sensorOutput) \ + _(currentOutput) \ + _(overrideHandScale) \ + _(overrideValueInput) \ + +#define XR_LIST_STRUCT_XrHandTrackingAimStateFB(_) \ + _(type) \ + _(next) \ + _(status) \ + _(aimPose) \ + _(pinchStrengthIndex) \ + _(pinchStrengthMiddle) \ + _(pinchStrengthRing) \ + _(pinchStrengthLittle) \ + +#define XR_LIST_STRUCT_XrHandCapsuleFB(_) \ + _(points) \ + _(radius) \ + _(joint) \ + +#define XR_LIST_STRUCT_XrHandTrackingCapsulesStateFB(_) \ + _(type) \ + _(next) \ + _(capsules) \ + +#define XR_LIST_STRUCT_XrSystemSpatialEntityPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsSpatialEntity) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpaceComponentStatusSetInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + _(enabled) \ + _(timeout) \ + +#define XR_LIST_STRUCT_XrSpaceComponentStatusFB(_) \ + _(type) \ + _(next) \ + _(enabled) \ + _(changePending) \ + +#define XR_LIST_STRUCT_XrUuidEXT(_) \ + _(data) \ + +#define XR_LIST_STRUCT_XrEventDataSpatialAnchorCreateCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceSetStatusCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(componentType) \ + _(enabled) \ + +#define XR_LIST_STRUCT_XrFoveationProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainCreateInfoFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSwapchainStateFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(profile) \ + +#define XR_LIST_STRUCT_XrFoveationLevelProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(level) \ + _(verticalOffset) \ + _(dynamic) \ + +#define XR_LIST_STRUCT_XrSystemKeyboardTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsKeyboardTracking) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingDescriptionFB(_) \ + _(trackedKeyboardId) \ + _(size) \ + _(flags) \ + _(name) \ + +#define XR_LIST_STRUCT_XrKeyboardSpaceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(trackedKeyboardId) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingQueryFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrTriangleMeshCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(windingOrder) \ + _(vertexCount) \ + _(vertexBuffer) \ + _(triangleCount) \ + _(indexBuffer) \ + +#define XR_LIST_STRUCT_XrSystemPassthroughPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsPassthrough) \ + +#define XR_LIST_STRUCT_XrPassthroughCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrPassthroughLayerCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(passthrough) \ + _(flags) \ + _(purpose) \ + +#define XR_LIST_STRUCT_XrCompositionLayerPassthroughFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(space) \ + _(layerHandle) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(layer) \ + _(mesh) \ + _(baseSpace) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceTransformFB(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrPassthroughStyleFB(_) \ + _(type) \ + _(next) \ + _(textureOpacityFactor) \ + _(edgeColor) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToRgbaFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToMonoFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrPassthroughBrightnessContrastSaturationFB(_) \ + _(type) \ + _(next) \ + _(brightness) \ + _(contrast) \ + _(saturation) \ + +#define XR_LIST_STRUCT_XrEventDataPassthroughStateChangedFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelPathInfoFB(_) \ + _(type) \ + _(next) \ + _(path) \ + +#define XR_LIST_STRUCT_XrRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(vendorId) \ + _(modelName) \ + _(modelKey) \ + _(modelVersion) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelBufferFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrRenderModelLoadInfoFB(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +#define XR_LIST_STRUCT_XrSystemRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsRenderModelLoading) \ + +#define XR_LIST_STRUCT_XrRenderModelCapabilitiesRequestFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrViewLocateFoveatedRenderingVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrFoveatedViewConfigurationViewVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrSystemFoveatedRenderingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsFoveatedRendering) \ + +#define XR_LIST_STRUCT_XrCompositionLayerDepthTestVARJO(_) \ + _(type) \ + _(next) \ + _(depthTestRangeNearZ) \ + _(depthTestRangeFarZ) \ + +#define XR_LIST_STRUCT_XrSystemMarkerTrackingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsMarkerTracking) \ + +#define XR_LIST_STRUCT_XrEventDataMarkerTrackingUpdateVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(isActive) \ + _(isPredicted) \ + _(time) \ + +#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(poseInMarkerSpace) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \ + _(name) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorPersistenceName) \ + _(spatialAnchor) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorStore) \ + _(spatialAnchorPersistenceName) \ + +#define XR_LIST_STRUCT_XrSpaceQueryInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpaceFilterInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpaceQueryInfoFB(_) \ + _(type) \ + _(next) \ + _(queryAction) \ + _(maxResultCount) \ + _(timeout) \ + _(filter) \ + _(excludeFilter) \ + +#define XR_LIST_STRUCT_XrSpaceStorageLocationFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(location) \ + +#define XR_LIST_STRUCT_XrSpaceUuidFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(uuidCount) \ + _(uuids) \ + +#define XR_LIST_STRUCT_XrSpaceComponentFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +#define XR_LIST_STRUCT_XrSpaceQueryResultFB(_) \ + _(space) \ + _(uuid) \ + +#define XR_LIST_STRUCT_XrSpaceQueryResultsFB(_) \ + _(type) \ + _(next) \ + _(resultCapacityInput) \ + _(resultCountOutput) \ + _(results) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceQueryResultsAvailableFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceQueryCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + +#define XR_LIST_STRUCT_XrSpaceSaveInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + _(persistenceMode) \ + +#define XR_LIST_STRUCT_XrSpaceEraseInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceSaveCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceEraseCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +#define XR_LIST_STRUCT_XrSwapchainImageFoveationVulkanFB(_) \ + _(type) \ + _(next) \ + _(image) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateAndroidSurfaceDimensionsFB(_) \ + _(type) \ + _(next) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerOpenGLESFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerVulkanFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(mipmapMode) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSpaceWarpInfoFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(motionVectorSubImage) \ + _(appSpaceDeltaPose) \ + _(depthSubImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +#define XR_LIST_STRUCT_XrSystemSpaceWarpPropertiesFB(_) \ + _(type) \ + _(next) \ + _(recommendedMotionVectorImageRectWidth) \ + _(recommendedMotionVectorImageRectHeight) \ + +#define XR_LIST_STRUCT_XrExtent3DfFB(_) \ + _(width) \ + _(height) \ + _(depth) \ + +#define XR_LIST_STRUCT_XrOffset3DfFB(_) \ + _(x) \ + _(y) \ + _(z) \ + +#define XR_LIST_STRUCT_XrRect3DfFB(_) \ + _(offset) \ + _(extent) \ + +#define XR_LIST_STRUCT_XrSemanticLabelsFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrRoomLayoutFB(_) \ + _(type) \ + _(next) \ + _(floorUuid) \ + _(ceilingUuid) \ + _(wallUuidCapacityInput) \ + _(wallUuidCountOutput) \ + _(wallUuids) \ + +#define XR_LIST_STRUCT_XrBoundary2DFB(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrDigitalLensControlALMALENCE(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSpaceContainerFB(_) \ + _(type) \ + _(next) \ + _(uuidCapacityInput) \ + _(uuidCountOutput) \ + _(uuids) \ + +#define XR_LIST_STRUCT_XrPassthroughKeyboardHandsIntensityFB(_) \ + _(type) \ + _(next) \ + _(leftHandIntensity) \ + _(rightHandIntensity) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSettingsFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + +#define XR_LIST_STRUCT_XrVulkanSwapchainCreateInfoMETA(_) \ + _(type) \ + _(next) \ + _(additionalCreateFlags) \ + _(additionalUsageFlags) \ + +#define XR_LIST_STRUCT_XrPerformanceMetricsStateMETA(_) \ + _(type) \ + _(next) \ + _(enabled) \ + +#define XR_LIST_STRUCT_XrPerformanceMetricsCounterMETA(_) \ + _(type) \ + _(next) \ + _(counterFlags) \ + _(counterUnit) \ + _(uintValue) \ + _(floatValue) \ + #define XR_LIST_STRUCTURE_TYPES_CORE(_) \ @@ -1502,8 +2747,13 @@ XR_ENUM_STR(XrResult); _(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \ _(XrSpatialAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) \ _(XrSpatialAnchorSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) \ + _(XrCompositionLayerImageLayoutFB, XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) \ + _(XrCompositionLayerAlphaBlendFB, XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) \ _(XrViewConfigurationDepthRangeEXT, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) \ _(XrSpatialGraphNodeSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) \ + _(XrSpatialGraphStaticNodeBindingCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesGetInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT) \ _(XrSystemHandTrackingPropertiesEXT, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) \ _(XrHandTrackerCreateInfoEXT, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) \ _(XrHandJointsLocateInfoEXT, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) \ @@ -1526,9 +2776,106 @@ XR_ENUM_STR(XrResult); _(XrControllerModelNodeStateMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) \ _(XrControllerModelStateMSFT, XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) \ _(XrViewConfigurationViewFovEPIC, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) \ + _(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \ + _(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \ + _(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \ + _(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \ _(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \ + _(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \ + _(XrSceneObserverCreateInfoMSFT, XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) \ + _(XrSceneCreateInfoMSFT, XR_TYPE_SCENE_CREATE_INFO_MSFT) \ + _(XrNewSceneComputeInfoMSFT, XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) \ + _(XrVisualMeshComputeLodInfoMSFT, XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) \ + _(XrSceneComponentsMSFT, XR_TYPE_SCENE_COMPONENTS_MSFT) \ + _(XrSceneComponentsGetInfoMSFT, XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) \ + _(XrSceneComponentLocationsMSFT, XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) \ + _(XrSceneComponentsLocateInfoMSFT, XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) \ + _(XrSceneObjectsMSFT, XR_TYPE_SCENE_OBJECTS_MSFT) \ + _(XrSceneComponentParentFilterInfoMSFT, XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) \ + _(XrSceneObjectTypesFilterInfoMSFT, XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) \ + _(XrScenePlanesMSFT, XR_TYPE_SCENE_PLANES_MSFT) \ + _(XrScenePlaneAlignmentFilterInfoMSFT, XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) \ + _(XrSceneMeshesMSFT, XR_TYPE_SCENE_MESHES_MSFT) \ + _(XrSceneMeshBuffersGetInfoMSFT, XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) \ + _(XrSceneMeshBuffersMSFT, XR_TYPE_SCENE_MESH_BUFFERS_MSFT) \ + _(XrSceneMeshVertexBufferMSFT, XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) \ + _(XrSceneMeshIndicesUint32MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) \ + _(XrSceneMeshIndicesUint16MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) \ + _(XrSerializedSceneFragmentDataGetInfoMSFT, XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) \ + _(XrSceneDeserializeInfoMSFT, XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) \ _(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \ + _(XrViveTrackerPathsHTCX, XR_TYPE_VIVE_TRACKER_PATHS_HTCX) \ + _(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \ + _(XrSystemFacialTrackingPropertiesHTC, XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC) \ + _(XrFacialExpressionsHTC, XR_TYPE_FACIAL_EXPRESSIONS_HTC) \ + _(XrFacialTrackerCreateInfoHTC, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC) \ _(XrSystemColorSpacePropertiesFB, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) \ + _(XrHandTrackingMeshFB, XR_TYPE_HAND_TRACKING_MESH_FB) \ + _(XrHandTrackingScaleFB, XR_TYPE_HAND_TRACKING_SCALE_FB) \ + _(XrHandTrackingAimStateFB, XR_TYPE_HAND_TRACKING_AIM_STATE_FB) \ + _(XrHandTrackingCapsulesStateFB, XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) \ + _(XrSystemSpatialEntityPropertiesFB, XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB) \ + _(XrSpatialAnchorCreateInfoFB, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB) \ + _(XrSpaceComponentStatusSetInfoFB, XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB) \ + _(XrSpaceComponentStatusFB, XR_TYPE_SPACE_COMPONENT_STATUS_FB) \ + _(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \ + _(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \ + _(XrFoveationProfileCreateInfoFB, XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) \ + _(XrSwapchainCreateInfoFoveationFB, XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) \ + _(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \ + _(XrFoveationLevelProfileCreateInfoFB, XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) \ + _(XrSystemKeyboardTrackingPropertiesFB, XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB) \ + _(XrKeyboardSpaceCreateInfoFB, XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB) \ + _(XrKeyboardTrackingQueryFB, XR_TYPE_KEYBOARD_TRACKING_QUERY_FB) \ + _(XrTriangleMeshCreateInfoFB, XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) \ + _(XrSystemPassthroughPropertiesFB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) \ + _(XrPassthroughCreateInfoFB, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) \ + _(XrPassthroughLayerCreateInfoFB, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) \ + _(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \ + _(XrGeometryInstanceCreateInfoFB, XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) \ + _(XrGeometryInstanceTransformFB, XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) \ + _(XrPassthroughStyleFB, XR_TYPE_PASSTHROUGH_STYLE_FB) \ + _(XrPassthroughColorMapMonoToRgbaFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) \ + _(XrPassthroughColorMapMonoToMonoFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) \ + _(XrPassthroughBrightnessContrastSaturationFB, XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB) \ + _(XrEventDataPassthroughStateChangedFB, XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) \ + _(XrRenderModelPathInfoFB, XR_TYPE_RENDER_MODEL_PATH_INFO_FB) \ + _(XrRenderModelPropertiesFB, XR_TYPE_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelBufferFB, XR_TYPE_RENDER_MODEL_BUFFER_FB) \ + _(XrRenderModelLoadInfoFB, XR_TYPE_RENDER_MODEL_LOAD_INFO_FB) \ + _(XrSystemRenderModelPropertiesFB, XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelCapabilitiesRequestFB, XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB) \ + _(XrViewLocateFoveatedRenderingVARJO, XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) \ + _(XrFoveatedViewConfigurationViewVARJO, XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) \ + _(XrSystemFoveatedRenderingPropertiesVARJO, XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) \ + _(XrCompositionLayerDepthTestVARJO, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) \ + _(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \ + _(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ + _(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ + _(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ + _(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \ + _(XrSpaceStorageLocationFilterInfoFB, XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB) \ + _(XrSpaceUuidFilterInfoFB, XR_TYPE_SPACE_UUID_FILTER_INFO_FB) \ + _(XrSpaceComponentFilterInfoFB, XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB) \ + _(XrSpaceQueryResultsFB, XR_TYPE_SPACE_QUERY_RESULTS_FB) \ + _(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \ + _(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \ + _(XrSpaceSaveInfoFB, XR_TYPE_SPACE_SAVE_INFO_FB) \ + _(XrSpaceEraseInfoFB, XR_TYPE_SPACE_ERASE_INFO_FB) \ + _(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \ + _(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \ + _(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \ + _(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \ + _(XrSemanticLabelsFB, XR_TYPE_SEMANTIC_LABELS_FB) \ + _(XrRoomLayoutFB, XR_TYPE_ROOM_LAYOUT_FB) \ + _(XrBoundary2DFB, XR_TYPE_BOUNDARY_2D_FB) \ + _(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \ + _(XrSpaceContainerFB, XR_TYPE_SPACE_CONTAINER_FB) \ + _(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \ + _(XrCompositionLayerSettingsFB, XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB) \ + _(XrPerformanceMetricsStateMETA, XR_TYPE_PERFORMANCE_METRICS_STATE_META) \ + _(XrPerformanceMetricsCounterMETA, XR_TYPE_PERFORMANCE_METRICS_COUNTER_META) \ @@ -1605,12 +2952,22 @@ XR_ENUM_STR(XrResult); #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ _(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ _(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \ + _(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ #else #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) #endif +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) +#endif + #if defined(XR_USE_GRAPHICS_API_VULKAN) #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ _(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ @@ -1620,6 +2977,9 @@ XR_ENUM_STR(XrResult); _(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \ _(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \ _(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \ + _(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \ + _(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + _(XrVulkanSwapchainCreateInfoMETA, XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META) \ #else @@ -1631,21 +2991,13 @@ XR_ENUM_STR(XrResult); _(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ _(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ _(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ + _(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ #else #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) #endif -#if defined(XR_USE_PLATFORM_ANDROID) && defined(XR_USE_GRAPHICS_API_OPENGL_ES) -#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ - _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ - - -#else -#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) -#endif - #if defined(XR_USE_PLATFORM_EGL) #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ _(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ @@ -1674,9 +3026,9 @@ XR_ENUM_STR(XrResult); XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ - XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ @@ -1707,6 +3059,8 @@ XR_ENUM_STR(XrResult); _(XR_VARJO_quad_views, 38) \ _(XR_MSFT_unbounded_reference_space, 39) \ _(XR_MSFT_spatial_anchor, 40) \ + _(XR_FB_composition_layer_image_layout, 41) \ + _(XR_FB_composition_layer_alpha_blend, 42) \ _(XR_MND_headless, 43) \ _(XR_OCULUS_android_session_state_enable, 45) \ _(XR_EXT_view_configuration_depth_range, 47) \ @@ -1723,9 +3077,14 @@ XR_ENUM_STR(XrResult); _(XR_EXT_win32_appcontainer_compatible, 58) \ _(XR_EPIC_view_configuration_fov, 60) \ _(XR_MSFT_holographic_window_attachment, 64) \ + _(XR_MSFT_composition_layer_reprojection, 67) \ _(XR_HUAWEI_controller_interaction, 70) \ _(XR_FB_android_surface_swapchain_create, 71) \ + _(XR_FB_swapchain_update_state, 72) \ + _(XR_FB_composition_layer_secure_content, 73) \ + _(XR_EXT_dpad_binding, 79) \ _(XR_VALVE_analog_threshold, 80) \ + _(XR_EXT_hand_joints_motion_range, 81) \ _(XR_KHR_loader_init, 89) \ _(XR_KHR_loader_init_android, 90) \ _(XR_KHR_vulkan_enable2, 91) \ @@ -1733,10 +3092,52 @@ XR_ENUM_STR(XrResult); _(XR_EXT_samsung_odyssey_controller, 95) \ _(XR_EXT_hp_mixed_reality_controller, 96) \ _(XR_MND_swapchain_usage_input_attachment_bit, 97) \ + _(XR_MSFT_scene_understanding, 98) \ + _(XR_MSFT_scene_understanding_serialization, 99) \ _(XR_FB_display_refresh_rate, 102) \ _(XR_HTC_vive_cosmos_controller_interaction, 103) \ + _(XR_HTCX_vive_tracker_interaction, 104) \ + _(XR_HTC_facial_tracking, 105) \ + _(XR_HTC_vive_focus3_controller_interaction, 106) \ + _(XR_HTC_hand_interaction, 107) \ + _(XR_HTC_vive_wrist_tracker_interaction, 108) \ _(XR_FB_color_space, 109) \ + _(XR_FB_hand_tracking_mesh, 111) \ + _(XR_FB_hand_tracking_aim, 112) \ + _(XR_FB_hand_tracking_capsules, 113) \ + _(XR_FB_spatial_entity, 114) \ + _(XR_FB_foveation, 115) \ + _(XR_FB_foveation_configuration, 116) \ + _(XR_FB_keyboard_tracking, 117) \ + _(XR_FB_triangle_mesh, 118) \ + _(XR_FB_passthrough, 119) \ + _(XR_FB_render_model, 120) \ _(XR_KHR_binding_modification, 121) \ + _(XR_VARJO_foveated_rendering, 122) \ + _(XR_VARJO_composition_layer_depth_test, 123) \ + _(XR_VARJO_environment_depth_estimation, 124) \ + _(XR_VARJO_marker_tracking, 125) \ + _(XR_VARJO_view_offset, 126) \ + _(XR_MSFT_spatial_anchor_persistence, 143) \ + _(XR_ULTRALEAP_hand_tracking_forearm, 150) \ + _(XR_FB_spatial_entity_query, 157) \ + _(XR_FB_spatial_entity_storage, 159) \ + _(XR_OCULUS_audio_device_guid, 160) \ + _(XR_FB_foveation_vulkan, 161) \ + _(XR_FB_swapchain_update_state_android_surface, 162) \ + _(XR_FB_swapchain_update_state_opengl_es, 163) \ + _(XR_FB_swapchain_update_state_vulkan, 164) \ + _(XR_KHR_swapchain_usage_input_attachment_bit, 166) \ + _(XR_FB_space_warp, 172) \ + _(XR_FB_scene, 176) \ + _(XR_EXT_palm_pose, 177) \ + _(XR_ALMALENCE_digital_lens_control, 197) \ + _(XR_FB_spatial_entity_container, 200) \ + _(XR_FB_passthrough_keyboard_hands, 204) \ + _(XR_FB_composition_layer_settings, 205) \ + _(XR_META_vulkan_swapchain_create_info, 228) \ + _(XR_META_performance_metrics, 233) \ + _(XR_EXT_uuid, 300) \ #endif From 0aeb2074288c1a635f025b9fd685a92f91d907bf Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 7 Dec 2022 21:40:13 +0100 Subject: [PATCH 625/715] OpenXR - Separate config for VR build --- Core/Config.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 8d7606e554..e4f893d54a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1324,9 +1324,11 @@ void Config::Reload() { // really think of any other legit uses). void Config::UpdateIniLocation(const char *iniFileName, const char *controllerIniFilename) { const bool useIniFilename = iniFileName != nullptr && strlen(iniFileName) > 0; - iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : "ppsspp.ini"); + const char *ppssppIniFilename = IsVREnabled() ? "ppssppvr.ini" : "ppsspp.ini"; + iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : ppssppIniFilename); const bool useControllerIniFilename = controllerIniFilename != nullptr && strlen(controllerIniFilename) > 0; - controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : "controls.ini"); + const char *controlsIniFilename = IsVREnabled() ? "controlsvr.ini" : "controls.ini"; + controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : controlsIniFilename); } void Config::Load(const char *iniFileName, const char *controllerIniFilename) { @@ -1819,7 +1821,8 @@ bool Config::deleteGameConfig(const std::string& pGameId) { } Path Config::getGameConfigFile(const std::string &pGameId) { - std::string iniFileName = pGameId + "_ppsspp.ini"; + const char *ppssppIniFilename = IsVREnabled() ? "_ppssppvr.ini" : "_ppsspp.ini"; + std::string iniFileName = pGameId + ppssppIniFilename; Path iniFileNameFull = FindConfigFile(iniFileName); return iniFileNameFull; From 70ce76a8d552af8e840338f4437edde2a4dfa66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 22:28:55 +0100 Subject: [PATCH 626/715] Delete the builtin Grayscale shader. Also make unknown shaders go away from list. --- GPU/Common/PostShader.cpp | 10 ++++++++++ GPU/Common/PostShader.h | 1 + GPU/Common/PresentationCommon.cpp | 1 + assets/shaders/defaultshaders.ini | 5 ----- assets/shaders/grayscale.fsh | 16 ---------------- 5 files changed, 12 insertions(+), 21 deletions(-) delete mode 100644 assets/shaders/grayscale.fsh diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 636c1b39e8..0cf1971e53 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -250,6 +250,16 @@ void ReloadAllPostShaderInfo(Draw::DrawContext *draw) { LoadPostShaderInfo(draw, directories); } +void RemoveUnknownPostShaders(std::vector *names) { + for (auto iter = names->begin(); iter != names->end(); ) { + if (GetPostShaderInfo(*iter) == nullptr) { + iter = names->erase(iter); + } else { + ++iter; + } + } +} + const ShaderInfo *GetPostShaderInfo(const std::string &name) { for (size_t i = 0; i < shaderInfo.size(); i++) { if (shaderInfo[i].section == name) diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index 06fc69a159..4b4061988c 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -114,3 +114,4 @@ const std::vector &GetAllPostShaderInfo(); const TextureShaderInfo *GetTextureShaderInfo(const std::string &name); const std::vector &GetAllTextureShaderInfo(); +void RemoveUnknownPostShaders(std::vector *names); diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index e07eec1499..f8837e2808 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -879,6 +879,7 @@ void PresentationCommon::CalculateRenderResolution(int *width, int *height, int std::vector shaderInfo; if (!g_Config.vPostShaderNames.empty()) { ReloadAllPostShaderInfo(draw_); + RemoveUnknownPostShaders(&g_Config.vPostShaderNames); shaderInfo = GetFullPostShadersChain(g_Config.vPostShaderNames); } diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index 2a33454069..b6412bb357 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -28,11 +28,6 @@ Name=Vignette Author=Henrik Fragment=vignette.fsh Vertex=fxaa.vsh -[Grayscale] -Name=Grayscale -Author=Henrik -Fragment=grayscale.fsh -Vertex=fxaa.vsh [Bloom] Name=Bloom Fragment=bloom.fsh diff --git a/assets/shaders/grayscale.fsh b/assets/shaders/grayscale.fsh deleted file mode 100644 index f309204e12..0000000000 --- a/assets/shaders/grayscale.fsh +++ /dev/null @@ -1,16 +0,0 @@ -// Simple grayscale shader - -#ifdef GL_ES -precision mediump float; -precision mediump int; -#endif - -uniform sampler2D sampler0; -varying vec2 v_texcoord0; - -void main() { - vec3 rgb = texture2D(sampler0, v_texcoord0.xy).xyz; - float luma = dot(rgb, vec3(0.299, 0.587, 0.114)); - gl_FragColor.rgb = vec3(luma, luma, luma); - gl_FragColor.a = 1.0; -} From 79d303f35ccdbf6942c2ce22ef4e3546c62be3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 22:47:28 +0100 Subject: [PATCH 627/715] Delete the InverseColors shader too --- assets/lang/ar_AE.ini | 4 +--- assets/lang/az_AZ.ini | 4 +--- assets/lang/bg_BG.ini | 8 +++----- assets/lang/ca_ES.ini | 4 +--- assets/lang/cz_CZ.ini | 4 +--- assets/lang/da_DK.ini | 4 +--- assets/lang/de_DE.ini | 4 +--- assets/lang/dr_ID.ini | 4 +--- assets/lang/en_US.ini | 4 +--- assets/lang/es_ES.ini | 4 +--- assets/lang/es_LA.ini | 4 +--- assets/lang/fa_IR.ini | 4 +--- assets/lang/fi_FI.ini | 4 +--- assets/lang/fr_FR.ini | 4 +--- assets/lang/gl_ES.ini | 4 +--- assets/lang/gr_EL.ini | 4 +--- assets/lang/he_IL.ini | 4 +--- assets/lang/he_IL_invert.ini | 4 +--- assets/lang/hr_HR.ini | 4 +--- assets/lang/hu_HU.ini | 4 +--- assets/lang/id_ID.ini | 4 +--- assets/lang/it_IT.ini | 4 +--- assets/lang/ja_JP.ini | 4 +--- assets/lang/jv_ID.ini | 4 +--- assets/lang/ko_KR.ini | 4 +--- assets/lang/lo_LA.ini | 4 +--- assets/lang/lt-LT.ini | 4 +--- assets/lang/ms_MY.ini | 4 +--- assets/lang/nl_NL.ini | 4 +--- assets/lang/no_NO.ini | 4 +--- assets/lang/pl_PL.ini | 4 +--- assets/lang/pt_BR.ini | 2 -- assets/lang/pt_PT.ini | 4 +--- assets/lang/ro_RO.ini | 4 +--- assets/lang/ru_RU.ini | 4 +--- assets/lang/sv_SE.ini | 4 +--- assets/lang/tg_PH.ini | 4 +--- assets/lang/th_TH.ini | 2 -- assets/lang/tr_TR.ini | 4 +--- assets/lang/uk_UA.ini | 4 +--- assets/lang/vi_VN.ini | 4 +--- assets/lang/zh_CN.ini | 4 +--- assets/lang/zh_TW.ini | 2 -- assets/shaders/defaultshaders.ini | 7 +------ assets/shaders/inversecolors.fsh | 19 ------------------- 45 files changed, 43 insertions(+), 153 deletions(-) delete mode 100644 assets/shaders/inversecolors.fsh diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 7fca56e265..17d598692d 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -848,10 +848,8 @@ Contrast = Contrast CRT = ‎CRT خطوط الفحص FXAA = ‎FXAA منعم الحواف Gamma = Gamma -Grayscale = ‎التدرج الرمادي -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = ‎عكس الألوان MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = ‎الألوان الحقيقية NaturalA = Natural Colors (no blur) diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 77b127ddd3..52bb14dbb5 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 8448605e28..e46549e77b 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -824,8 +824,8 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Сива скала -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Противоположни цветове MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 6aaddb4987..b9bb045f00 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 6870e757c8..21e028bb2e 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = Skenovací řádky CRT FXAA = Vyhlazování hran FXAA Gamma = Gamma -Grayscale = Stupně šedi -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverzní barvy MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Přirozené barvy NaturalA = Natural Colors (no blur) diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 26516055bc..2164937724 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlinier FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Gråskala -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverterede farver MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturlige farver NaturalA = Natural Colors (no blur) diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 9f351c67d8..47e72234e7 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT Scanlines FXAA = FXAA Gamma = Gamma -Grayscale = Graustufen -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Farben invertieren MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natürliche Farben NaturalA = Natürliche Farben (kein Blur) diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index be19011bf0..f46caf79c2 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index e7d6e56f25..923204d4aa 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -833,10 +833,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 0e08165255..4944809a9d 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -840,10 +840,8 @@ Contrast = Contraste CRT = Pantalla de tubo (CRT) FXAA = Antialiasing por FXAA Gamma = Gamma -Grayscale = Escala de grises -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensidad -InverseColors = Invertir colores MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Colores naturales NaturalA = Colores naturales (sin difuminar) diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 1c60ffd956..293d0ffbf5 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -840,10 +840,8 @@ Contrast = Contraste CRT = Pantalla de tubo (CRT) FXAA = Antialiasing por FXAA Gamma = Gamma -Grayscale = Escala de grises -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensidad -InverseColors = Invertir colores MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Colores naturales NaturalA = Colores naturales (sin desenfoques) diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index ce59fe1520..7339bbc014 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 030b9adfbe..8781c52535 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 20bf66436f..41875c547b 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -840,10 +840,8 @@ Contrast = Contraste CRT = Lignes de balayage CRT FXAA = Anticrénelage FXAA Gamma = Gamma -Grayscale = Niveaux de gris -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensité -InverseColors = Couleurs inversées MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Couleurs naturelles NaturalA = Couleurs naturelles (sans flou) diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 5384d7b934..99713f5d1b 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = Monitor con «scanlines» (CRT) FXAA = Antialiasing FXAA Gamma = Gamma -Grayscale = Escala de grises -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Invertir cores MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Cores naturais NaturalA = Natural Colors (no blur) diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 113602a7a2..2b131e20f2 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = Γραμμές σάρωσης CRT FXAA = Εξομάλυνση κορυφών FXAA Gamma = Gamma -Grayscale = Ασπρόμαυρο -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Αντιστροφή Χρωμάτων MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Φυσικά Χρώματα NaturalA = Natural Colors (no blur) diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 3e1145ab04..8ad1145c3f 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 5087eeb6ac..a20c5bb6b1 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index c39645fbd7..b0005f3baa 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Izmijeni boje MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Prirodne boje NaturalA = Prirodne boje (bez zamućivanja) diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 71859b15d9..d69a3c583e 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -840,10 +840,8 @@ Contrast = Kontraszt CRT = CRT FXAA = FXAA élsimítás Gamma = Gamma -Grayscale = Szürkeárnyalatos -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Erősség -InverseColors = Színek megfordítása MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Természetes színek NaturalA = Természetes színek (elmosódás nélkül) diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index e821086ee2..b682b11fbe 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -840,10 +840,8 @@ Contrast = Kontras CRT = CRT FXAA = Mengurangi Artifak Distorsi (FXAA) Gamma = Gamma -Grayscale = Abu-abu -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensitas -InverseColors = Warna Terbalik MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna Natural NaturalA = Warna Natural (tidak kabur) diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 2e88064c95..dbca30189d 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -812,10 +812,8 @@ Contrast = Contrasto CRT = Linee di scansione CRT FXAA = Antialiasing FXAA Gamma = Gamma -Grayscale = Scala di grigi -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensità -InverseColors = Colori invertiti MitchellNetravali = Upscaler Bicubico (Mitchell-Netravali) Natural = Colori naturali NaturalA = Colori naturali (nessuna sfocatura) diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 4bb7bb99f2..4da25737f6 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -811,10 +811,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 595b012bcb..30c7ccb74a 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Keabu-abuan -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Warna kebalik MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna Natural NaturalA = Natural Colors (no blur) diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index c7af635ae7..eca14580f3 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -809,10 +809,8 @@ Contrast = 명암 CRT = CRT 스캔라인 FXAA = FXAA 안티 에일리어싱 Gamma = 감마 -Grayscale = 그레이스케일 -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = 강도 -InverseColors = 색 반전 Natural = 자연스러운 색상 NaturalA = 자연스러운 색상 (흐림 없음) Off = 끔 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index b1cf4ebcbc..16b23df0cd 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT FXAA = FXAA Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = InverseColors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural NaturalA = Natural Colors (no blur) diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 2a64d882e3..469752e628 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT skenavimo linjos FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Perkeisti spalvas MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturalios spalvos NaturalA = Natural Colors (no blur) diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 4ecf0105ac..c39b74ea38 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Anti aliasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Terbalikkan warna MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna asli NaturalA = Natural Colors (no blur) diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index cea29bbbc5..232fe365b4 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT-scanlijnen FXAA = FXAA-antialiasing Gamma = Gamma -Grayscale = Grijswaarden -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Omgekeerde kleuren MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natuurlijke kleuren NaturalA = Natural Colors (no blur) diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index d0808c29b7..13054d392c 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Gråtoneskala -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index b01d9e8770..758bdbf911 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = Imitacja monitora CRT FXAA = Wygładzanie FXAA Gamma = Gamma -Grayscale = Skala szarości -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Odwrócenie kolorów MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturalne kolory NaturalA = Naturalne kolory (bez rozmycia) diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index c58d1353b7..bbf2274b8b 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -833,10 +833,8 @@ Contrast = Contraste CRT = Scanlines do CRT FXAA = Anti-aliasing do FXAA Gamma = Gama -Grayscale = Tons de cinza GreenLevel = Nível verde Intensity = Intensidade -InverseColors = Cores invertidas Natural = Cores naturais NaturalA = Cores naturais (sem borrão) Off = Desligado diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index b5d98f0685..6b64e709c7 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -833,10 +833,8 @@ Contrast = Contraste CRT = Scanlines do CRT FXAA = Anti-aliasing do FXAA Gamma = Gama -Grayscale = Tons de cinza -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensidade -InverseColors = Cores invertidas Natural = Cores naturais NaturalA = Cores naturais (sem borrão) Off = Desligado diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 135170999a..cb6ff40c33 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Culori Inversate MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Culori Naturale NaturalA = Natural Colors (no blur) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 318d699e06..9424063d6b 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -811,10 +811,8 @@ Contrast = Контрастность CRT = ЭЛТ-развертка FXAA = Сглаживание FXAA Gamma = Gamma -Grayscale = Оттенки серого -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Интенсивность -InverseColors = Инвертированные цвета MitchellNetravali = Бикубический (Mitchell-Netravali) апскейлер Natural = Естественные цвета NaturalA = Естественные цвета (без размытия) diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index a1b55bc588..d940e17d1f 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -811,10 +811,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Gamma = Gamma -Grayscale = Gråskala -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = InverseColors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural NaturalA = Natural Colors (no blur) diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 260c8f3ec6..06f45c2f55 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index ace20b3246..179a6e4bdf 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -840,10 +840,8 @@ Contrast = ความคมชัด CRT = ภาพออกโทนเหลืองขึ้นเส้น FXAA = ภาพเน้นลบขอบรอยหยัก Gamma = แกมม่า -Grayscale = ภาพโทนสีเทา GreenLevel = ระดับสีเขียว Intensity = ความเข้มของแสง -InverseColors = ภาพสีกลับ MitchellNetravali = ภาพอัพสเกลแบบไบคิวบิค (มิทเชลล์-เนทราวาลิ) Natural = ภาพเน้นสีธรรมชาติ NaturalA = ภาพเน้นสีธรรมชาติ (ไม่เบลอ) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index a12dcd7f67..04196fdc64 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -841,10 +841,8 @@ Contrast = Karşıtlık CRT = CRT tarama çizgileri FXAA = FXAA Kenar Yumuşatma Gamma = Gamma -Grayscale = Gri tonlama -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Yoğunluk -InverseColors = Ters Renkler MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Doğal Renkler NaturalA = Doğal Renkler (bulanıklık yok) diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index bd967631c1..7403166639 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -840,10 +840,8 @@ Contrast = Контраст CRT = Кінескоп 1 FXAA = FXAA згладжування Gamma = Гамма -Grayscale = Відтінки сірого -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Інтенсивність -InverseColors = Зворотні кольори MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Натуральні кольори NaturalA = Натуральні кольори (без розмиття) diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index b0788c4456..c2efe73fcb 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -840,10 +840,8 @@ Contrast = Contrast CRT = CRT đường quét FXAA = Chống răng cưa FXAA Gamma = Gamma -Grayscale = Đen trắng -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = Intensity -InverseColors = Màu âm bản MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Màu tự nhiên (mờ) NaturalA = Màu tự nhiên (không mờ) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 0fc0b4cf6a..eb68ae14e7 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -840,10 +840,8 @@ Contrast = 对比度 CRT = CRT 扫描线 FXAA = FXAA (快速近似抗锯齿) Gamma = 伽马值 -Grayscale = 灰度图 -GreenLevel = GreenLevel +GreenLevel = Green level Intensity = 强度 -InverseColors = 反色 Natural = 自然色 NaturalA = 自然色(无模糊) Off = 关闭 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 1133d8adaa..6280ffc9b9 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -809,10 +809,8 @@ Contrast = 對比度 CRT = CRT 掃描線 FXAA = FXAA 消除鋸齒 Gamma = 色差補正 -Grayscale = 灰階 GreenLevel = 綠色色階 Intensity = 濃度 -InverseColors = 反轉色彩 Natural = 自然色彩 NaturalA = 自然色彩 (無模糊) Off = 關閉 diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index b6412bb357..e9a6c75167 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -29,7 +29,7 @@ Author=Henrik Fragment=vignette.fsh Vertex=fxaa.vsh [Bloom] -Name=Bloom +Name=Bloom Shader Fragment=bloom.fsh Vertex=fxaa.vsh SettingName1=Amount @@ -49,11 +49,6 @@ SettingDefaultValue1=1.5 SettingMaxValue1=3.0 SettingMinValue1=1.0 SettingStep1=0.1 -[InverseColors] -Name=Inverse Colors -Author=Henrik -Fragment=inversecolors.fsh -Vertex=fxaa.vsh [Scanlines] Name=Scanlines (CRT) Fragment=scanlines.fsh diff --git a/assets/shaders/inversecolors.fsh b/assets/shaders/inversecolors.fsh deleted file mode 100644 index c6367ca2fd..0000000000 --- a/assets/shaders/inversecolors.fsh +++ /dev/null @@ -1,19 +0,0 @@ -// Simple false color shader - -#ifdef GL_ES -precision mediump float; -precision mediump int; -#endif - -uniform sampler2D sampler0; -varying vec2 v_texcoord0; - -void main() { - vec3 rgb = texture2D(sampler0, v_texcoord0.xy).xyz; - float luma = dot(rgb, vec3(0.299, 0.587, 0.114)); - vec3 gray = vec3(luma, luma, luma) - 0.5; - rgb -= vec3(0.5, 0.5, 0.5); - - gl_FragColor.rgb = mix(rgb, gray, 2.0) + 0.5; - gl_FragColor.a = 1.0; -} From 42b74c6a9ae05e953dc89a48d268ce5665bb5c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 23:12:09 +0100 Subject: [PATCH 628/715] Add background to the scroll views. Not really pretty but more readable --- Common/UI/ViewGroup.cpp | 2 ++ UI/DisplayLayoutScreen.cpp | 5 +++++ UI/MiscScreens.cpp | 6 +++++- UI/MiscScreens.h | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f32bd6fd37..ce030a3249 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -928,6 +928,8 @@ void ScrollView::Draw(UIContext &dc) { } dc.PushScissor(bounds_); + dc.FillRect(bg_, bounds_); + // For debugging layout issues, this can be useful. // dc.FillRect(Drawable(0x60FF00FF), bounds_); views_[0]->Draw(dc); diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 432e3b5eaa..9efb29688a 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -218,6 +218,11 @@ void DisplayLayoutScreen::CreateViews() { LinearLayout *bottomControls = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, NONE, NONE, 10.0f, false)); root_->Add(bottomControls); + // Set backgrounds for readability + Drawable backgroundWithAlpha(GetBackgroundColorWithAlpha(*screenManager()->getUIContext())); + leftScrollView->SetBG(backgroundWithAlpha); + rightScrollView->SetBG(backgroundWithAlpha); + if (!IsVREnabled()) { auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); rightColumn->Add(stretch); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index e00ec856a0..f880935e08 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -356,6 +356,10 @@ void DrawBackground(UIContext &dc, float alpha, float x, float y, float z) { } } +uint32_t GetBackgroundColorWithAlpha(UIContext &dc) { + return colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.65f); // 0.65 = 166 = A6 +} + void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z, bool darkenBackground) { using namespace Draw; using namespace UI; @@ -379,7 +383,7 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f dc.Begin(); if (darkenBackground) { - uint32_t color = colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.65f); + uint32_t color = GetBackgroundColorWithAlpha(dc); dc.FillRect(UI::Drawable(color), dc.GetBounds()); dc.Flush(); } diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 07f544f855..d218739a78 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -192,3 +192,5 @@ private: float cutOffY_; bool showing_ = false; }; + +uint32_t GetBackgroundColorWithAlpha(UIContext &dc); From 3e7f7ad8d77c023d5cea706d4f57db84dda75eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Dec 2022 00:01:46 +0100 Subject: [PATCH 629/715] Add CSS-style padding support to LinearLayout. Use to improve the look --- Common/UI/View.h | 7 +++++++ Common/UI/ViewGroup.cpp | 42 +++++++++++++++++++------------------- Common/UI/ViewGroup.h | 2 ++ UI/DisplayLayoutScreen.cpp | 14 +++++++------ 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/Common/UI/View.h b/Common/UI/View.h index 0d52216771..1ab1ea5f68 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -287,6 +287,13 @@ struct Margins { int vert() const { return top + bottom; } + void SetAll(float f) { + int8_t i = (int)f; + top = i; + bottom = i; + left = i; + right = i; + } int8_t top; int8_t bottom; diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index ce030a3249..50398dac45 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -539,19 +539,19 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec v = vert; if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f) v = MeasureSpec(AT_MOST, measuredHeight_); - view->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert()); - if (horiz.type == AT_MOST && view->GetMeasuredWidth() + margins.horiz() > horiz.size - weightZeroSum) { + view->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert() - (float)padding.vert()); + if (horiz.type == AT_MOST && view->GetMeasuredWidth() + margins.horiz() + padding.horiz() > horiz.size - weightZeroSum) { // Try again, this time with AT_MOST. - view->Measure(dc, horiz, v - (float)margins.vert()); + view->Measure(dc, horiz, v - (float)margins.vert() - (float)padding.vert()); } } else if (orientation_ == ORIENT_VERTICAL) { MeasureSpec h = horiz; if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f) h = MeasureSpec(AT_MOST, measuredWidth_); - view->Measure(dc, h - (float)margins.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_)); - if (vert.type == AT_MOST && view->GetMeasuredHeight() + margins.vert() > vert.size - weightZeroSum) { + view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_)); + if (vert.type == AT_MOST && view->GetMeasuredHeight() + margins.vert() + padding.horiz() > vert.size - weightZeroSum) { // Try again, this time with AT_MOST. - view->Measure(dc, h - (float)margins.horiz(), vert); + view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), vert); } } @@ -575,12 +575,12 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } } - weightZeroSum += spacing_ * (numVisible - 1); + weightZeroSum += spacing_ * (numVisible - 1); // +(orientation_ == ORIENT_HORIZONTAL) ? padding.horiz() : padding.vert(); // Alright, got the sum. Let's take the remaining space after the fixed-size views, // and distribute among the weighted ones. if (orientation_ == ORIENT_HORIZONTAL) { - MeasureBySpec(layoutParams_->width, weightZeroSum, horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, weightZeroSum + padding.horiz(), horiz, &measuredWidth_); // If we've got stretch, allow growing to fill the parent. float allowedWidth = measuredWidth_; @@ -588,7 +588,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v allowedWidth = horiz.size; } - float usedWidth = 0.0f; + float usedWidth = 0.0f + padding.horiz(); // Redistribute the stretchy ones! and remeasure the children! for (View *view : views_) { @@ -615,7 +615,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (horiz.type == EXACTLY) { h.type = EXACTLY; } - view->Measure(dc, h, v - (float)margins.vert()); + view->Measure(dc, h, v - (float)margins.vert() - (float)padding.vert()); usedWidth += view->GetMeasuredWidth(); maxOther = std::max(maxOther, view->GetMeasuredHeight() + margins.vert()); } @@ -626,9 +626,9 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } // Measure here in case maxOther moved (can happen due to word wrap.) - MeasureBySpec(layoutParams_->height, maxOther, vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, maxOther + padding.vert(), vert, &measuredHeight_); } else { - MeasureBySpec(layoutParams_->height, weightZeroSum, vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, weightZeroSum + padding.vert(), vert, &measuredHeight_); // If we've got stretch, allow growing to fill the parent. float allowedHeight = measuredHeight_; @@ -636,7 +636,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v allowedHeight = vert.size; } - float usedHeight = 0.0f; + float usedHeight = 0.0f + padding.vert(); // Redistribute the stretchy ones! and remeasure the children! for (View *view : views_) { @@ -663,7 +663,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (vert.type == EXACTLY) { v.type = EXACTLY; } - view->Measure(dc, h - (float)margins.horiz(), v); + view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), v); usedHeight += view->GetMeasuredHeight(); maxOther = std::max(maxOther, view->GetMeasuredWidth() + margins.horiz()); } @@ -674,7 +674,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } // Measure here in case maxOther moved (can happen due to word wrap.) - MeasureBySpec(layoutParams_->width, maxOther, horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, maxOther + padding.horiz(), horiz, &measuredWidth_); } } @@ -686,13 +686,13 @@ void LinearLayout::Layout() { float pos; if (orientation_ == ORIENT_HORIZONTAL) { - pos = bounds.x; - itemBounds.y = bounds.y; - itemBounds.h = measuredHeight_; + pos = bounds.x + padding.left; + itemBounds.y = bounds.y + padding.top; + itemBounds.h = measuredHeight_ - padding.vert(); } else { - pos = bounds.y; - itemBounds.x = bounds.x; - itemBounds.w = measuredWidth_; + pos = bounds.y + padding.top; + itemBounds.x = bounds.x + padding.left; + itemBounds.w = measuredWidth_ - padding.horiz(); } for (size_t i = 0; i < views_.size(); i++) { diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 78c42e84b1..d408548b69 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -106,6 +106,7 @@ protected: // It simply centers the child view. class FrameLayout : public ViewGroup { public: + FrameLayout(LayoutParams *layoutParams = nullptr) : ViewGroup(layoutParams) {} void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; }; @@ -193,6 +194,7 @@ public: spacing_ = spacing; } std::string DescribeLog() const override { return (orientation_ == ORIENT_HORIZONTAL ? "LinearLayoutHoriz: " : "LinearLayoutVert: ") + View::DescribeLog(); } + Margins padding; protected: Orientation orientation_; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 9efb29688a..678977916d 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -203,14 +203,16 @@ void DisplayLayoutScreen::CreateViews() { // impossible. root_->SetExclusiveTouch(true); - ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(400.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); - ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL); + ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(420.0f, FILL_PARENT, 0.f, 0.f, NONE, 0.f, false)); + LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL); + leftColumn->padding.SetAll(8.0f); leftScrollView->Add(leftColumn); leftScrollView->SetClickableBackground(true); root_->Add(leftScrollView); - ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.f, 10.f, false)); - ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL); + ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 0.f, 0.f, 0.f, false)); + LinearLayout *rightColumn = new LinearLayout(ORIENT_VERTICAL); + rightColumn->padding.SetAll(8.0f); rightScrollView->Add(rightColumn); rightScrollView->SetClickableBackground(true); root_->Add(rightScrollView); @@ -220,8 +222,8 @@ void DisplayLayoutScreen::CreateViews() { // Set backgrounds for readability Drawable backgroundWithAlpha(GetBackgroundColorWithAlpha(*screenManager()->getUIContext())); - leftScrollView->SetBG(backgroundWithAlpha); - rightScrollView->SetBG(backgroundWithAlpha); + leftColumn->SetBG(backgroundWithAlpha); + rightColumn->SetBG(backgroundWithAlpha); if (!IsVREnabled()) { auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); From 3201bf9016ef662708a2e13f365abfe46868d174 Mon Sep 17 00:00:00 2001 From: iota97 Date: Thu, 8 Dec 2022 00:51:19 +0100 Subject: [PATCH 630/715] add new image to controls --- UI/GamepadEmu.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index 0eb2a7c60c..9ec5d96556 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -247,6 +247,13 @@ namespace CustomKey { { ImageID("I_ARROW"), 0.0f}, { ImageID("I_ARROW"), 180.0f}, { ImageID("I_GEAR"), 0.0f}, + { ImageID("I_ROTATE_LEFT"), 0.0f}, + { ImageID("I_ROTATE_RIGHT"), 0.0f}, + { ImageID("I_ARROW_LEFT"), 0.0f}, + { ImageID("I_ARROW_RIGHT"), 0.0f}, + { ImageID("I_ARROW_UP"), 0.0f}, + { ImageID("I_ARROW_DOWN"), 0.0f}, + { ImageID("I_THREE_DOTS"), 0.0f}, }; // Shape list From 182355b25866431ee4ad61e494fd409494b657fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Dec 2022 12:23:28 +0100 Subject: [PATCH 631/715] UWP buildfix --- UWP/UWP.vcxproj | 30 +----------------------------- UWP/UWP.vcxproj.filters | 8 +------- 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 3b7f8013d4..5fcdbecf25 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -1597,34 +1597,6 @@ true true - - true - true - true - true - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - true - true - true - true - true true @@ -1774,4 +1746,4 @@ - \ No newline at end of file + diff --git a/UWP/UWP.vcxproj.filters b/UWP/UWP.vcxproj.filters index 03611fcc46..15c471b062 100644 --- a/UWP/UWP.vcxproj.filters +++ b/UWP/UWP.vcxproj.filters @@ -273,12 +273,6 @@ Content\shaders - - Content\shaders - - - Content\shaders - Content\flash0\font @@ -377,4 +371,4 @@ Content - \ No newline at end of file + From 600cb907bdba566aacc112aea33e1e89afae2c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Dec 2022 13:02:44 +0100 Subject: [PATCH 632/715] Auto-open settings if there's only one post-shader --- UI/DisplayLayoutScreen.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 678977916d..4764b069f0 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -280,7 +280,13 @@ void DisplayLayoutScreen::CreateViews() { leftColumn->Add(new ItemHeader(gr->T("Postprocessing shaders"))); std::set alreadyAddedShader; - settingsVisible_.resize(g_Config.vPostShaderNames.size()); + // If there's a single post shader and we're just entering the dialog, + // auto-open the settings. + if (settingsVisible_.empty() && g_Config.vPostShaderNames.size() == 1) { + settingsVisible_.push_back(true); + } else if (settingsVisible_.size() < g_Config.vPostShaderNames.size()) { + settingsVisible_.resize(g_Config.vPostShaderNames.size()); + } static ContextMenuItem postShaderContextMenu[] = { { "Move Up", "I_ARROW_UP" }, From a5cb357058bfd43eacc6cfb95d5e05593a094f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Dec 2022 13:16:33 +0100 Subject: [PATCH 633/715] More strings --- assets/lang/ar_AE.ini | 6 +++--- assets/lang/az_AZ.ini | 6 +++--- assets/lang/bg_BG.ini | 2 +- assets/lang/ca_ES.ini | 6 +++--- assets/lang/cz_CZ.ini | 6 +++--- assets/lang/da_DK.ini | 6 +++--- assets/lang/de_DE.ini | 4 ++-- assets/lang/dr_ID.ini | 6 +++--- assets/lang/en_US.ini | 6 +++--- assets/lang/es_ES.ini | 4 ++-- assets/lang/es_LA.ini | 2 +- assets/lang/fa_IR.ini | 6 +++--- assets/lang/fi_FI.ini | 6 +++--- assets/lang/gl_ES.ini | 6 +++--- assets/lang/gr_EL.ini | 6 +++--- assets/lang/he_IL.ini | 6 +++--- assets/lang/he_IL_invert.ini | 6 +++--- assets/lang/hr_HR.ini | 6 +++--- assets/lang/hu_HU.ini | 6 +++--- assets/lang/id_ID.ini | 6 +++--- assets/lang/it_IT.ini | 4 ++-- assets/lang/ja_JP.ini | 6 +++--- assets/lang/jv_ID.ini | 6 +++--- assets/lang/ko_KR.ini | 6 +++--- assets/lang/lo_LA.ini | 6 +++--- assets/lang/lt-LT.ini | 6 +++--- assets/lang/ms_MY.ini | 6 +++--- assets/lang/nl_NL.ini | 6 +++--- assets/lang/no_NO.ini | 6 +++--- assets/lang/pl_PL.ini | 4 ++-- assets/lang/pt_BR.ini | 6 +++--- assets/lang/pt_PT.ini | 6 +++--- assets/lang/ro_RO.ini | 6 +++--- assets/lang/ru_RU.ini | 6 +++--- assets/lang/sv_SE.ini | 4 ++-- assets/lang/tg_PH.ini | 4 ++-- assets/lang/tr_TR.ini | 6 +++--- assets/lang/uk_UA.ini | 6 +++--- assets/lang/vi_VN.ini | 6 +++--- assets/lang/zh_CN.ini | 6 +++--- assets/lang/zh_TW.ini | 6 +++--- 41 files changed, 113 insertions(+), 113 deletions(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 17d598692d..0d636970f9 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -831,9 +831,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = ‎AA-لون Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 52bb14dbb5..f113e191af 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index e46549e77b..45755b3357 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -823,7 +823,7 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL +4xHqGLSL = 4xHQ pixel art upscaler 5xBR = 5xBR pixel art upscaler 5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index b9bb045f00..4a96b71296 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 21e028bb2e..cc316cb2ba 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Barva Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 2164937724..d7a79a5173 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 47e72234e7..4ff46ac564 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -824,8 +824,8 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = 4×HqGLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AAColor Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index f46caf79c2..cf02bd536c 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 923204d4aa..5d4213d734 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -818,9 +818,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Black border = Black border diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 4944809a9d..2ba2f033d1 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -824,8 +824,8 @@ Undo last save = Deshacer guard. de estado [PostShaders] (duplicated setting, previous slider will be used) = (configuración duplicada, se usará la anterior) 4xHqGLSL = 4xHQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA + color Amount = Cantidad Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 293d0ffbf5..cfa059c136 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -823,7 +823,7 @@ Undo last save = Deshacer guard. de estado [PostShaders] (duplicated setting, previous slider will be used) = (configuraciones duplicadas, se usará la anterior) -4xHqGLSL = 4×HQ GLSL +4xHqGLSL = 4xHQ pixel art upscaler 5xBR = 5×BR 5xBR-lv2 = 5×BR-lv2 AAColor = AA + Color diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 7339bbc014..19dd0501ce 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 8781c52535..26e994dd7e 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 99713f5d1b..d202f17fcb 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA + cor Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 2b131e20f2..240c2b50ed 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 8ad1145c3f..9239455c89 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index a20c5bb6b1..1d42057032 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index b0005f3baa..066ba47e75 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index d69a3c583e..0579abd7c7 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Mennyiség Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index b682b11fbe..2355e6feed 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -823,9 +823,9 @@ Undo last save = Urungkan penyimpanan terakhir [PostShaders] (duplicated setting, previous slider will be used) = (pengaturan duplikat, penggeser sebelumnya akan digunakan) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Warna AA Amount = Nominal Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index dbca30189d..14cafefb42 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -796,8 +796,8 @@ Undo last save = Annulla ultimo salvataggio [PostShaders] (duplicated setting, previous slider will be used) = (parametri duplicati, verrà usata la precedente regolazione) 4xHqGLSL = 4xHQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Colore AA Amount = Quantità Animation speed (0 -> disable) = Velocità animazione (0 -> disabilita) diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 4da25737f6..f420a0646e 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -794,9 +794,9 @@ Undo last save = セーブ内容を戻す [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 30c7ccb74a..320fd6ba87 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index eca14580f3..c99e778885 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -794,9 +794,9 @@ Undo last save = 마지막 저장 실행 취소 [PostShaders] (duplicated setting, previous slider will be used) = (설정이 중복되면 이전 슬라이더가 사용됩니다.) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-색상 Amount = 양 Black border = 검정 테두리 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 16b23df0cd..c1458dbc36 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 469752e628..646f2900a5 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Spalva Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index c39b74ea38..d991357c5c 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Warna AA Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 232fe365b4..249efacdb9 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-kleur Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 13054d392c..bc11cc40a7 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 758bdbf911..b194aebb45 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -824,8 +824,8 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = Skalowanie 4×HQ -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Kolor AA Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index bbf2274b8b..85916ba0d8 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -818,9 +818,9 @@ Undo last save = Desfazer o último salvamento [PostShaders] (duplicated setting, previous slider will be used) = (Configuração duplicada, o slider anterior será usado) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Cores-do-AA Amount = Quantidade Black border = Borda preta diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 6b64e709c7..ed04174528 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -818,9 +818,9 @@ Undo last save = Desfazer o último salvamento [PostShaders] (duplicated setting, previous slider will be used) = (Definição duplicada, o slider anterior será usado) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Cores-do-AA Amount = Quantidade Black border = Borda preta diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index cb6ff40c33..2ac9cbe570 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 9424063d6b..04396dd888 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -794,9 +794,9 @@ Undo last save = Отменить последнее сохранение [PostShaders] (duplicated setting, previous slider will be used) = (дублированная настройка, используется предыдущий ползунок) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-цвета Amount = Размер Animation speed (0 -> disable) = Скорость анимации (0 -> disable) diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index d940e17d1f..a5cea55f8e 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -795,8 +795,8 @@ Undo last save = Ångra senaste spar [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = 4×HqGLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AAColor Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 06f45c2f55..93272cd417 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -824,8 +824,8 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = 4テ幽Q GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 04196fdc64..379752394b 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -824,9 +824,9 @@ Undo last load = Son yüklemeyi geri al Undo last save = Son kaydetmeyi geri al [PostShaders] (duplicated setting, previous slider will be used) = (yinelenen ayar, önceki kaydırıcı kullanılacaktır) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Miktar Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 7403166639..0981be9a88 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Кольори Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index c2efe73fcb..1e73d69f8a 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -823,9 +823,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-màu Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index eb68ae14e7..5e17fd9341 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -824,9 +824,9 @@ Undo last save = 撤销保存 [PostShaders] (duplicated setting, previous slider will be used) = (设置重复, 将使用上面滑块的值) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = 数量 Animation speed (0 -> disable) = 动画速度(0->禁用) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 6280ffc9b9..7458167121 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -794,9 +794,9 @@ Undo last save = 復原上次儲存 [PostShaders] (duplicated setting, previous slider will be used) = (重複的設定,將使用上一個滑桿) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = 數量 Black border = 黑色框線 From 2a9d4b53cba36c90a30d61625aa93205dd37f7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Dec 2022 13:16:44 +0100 Subject: [PATCH 634/715] Add parameters to the Vignette shader --- assets/shaders/defaultshaders.ini | 12 +++++++++++- assets/shaders/vignette.fsh | 8 +++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index e9a6c75167..d987574591 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -28,6 +28,16 @@ Name=Vignette Author=Henrik Fragment=vignette.fsh Vertex=fxaa.vsh +SettingName1=Power +SettingDefaultValue1=0.6 +SettingMaxValue1=2.0 +SettingMinValue1=0.1 +SettingStep1=0.1 +SettingName2=Aspect +SettingDefaultValue2=1.0 +SettingMaxValue2=2.0 +SettingMinValue2=0.5 +SettingStep2=0.1 [Bloom] Name=Bloom Shader Fragment=bloom.fsh @@ -47,7 +57,7 @@ Vertex=fxaa.vsh SettingName1=Amount SettingDefaultValue1=1.5 SettingMaxValue1=3.0 -SettingMinValue1=1.0 +SettingMinValue1=0.1 SettingStep1=0.1 [Scanlines] Name=Scanlines (CRT) diff --git a/assets/shaders/vignette.fsh b/assets/shaders/vignette.fsh index 7e2c92e69a..b4dc2b41c9 100644 --- a/assets/shaders/vignette.fsh +++ b/assets/shaders/vignette.fsh @@ -8,9 +8,15 @@ precision mediump int; uniform sampler2D sampler0; varying vec2 v_texcoord0; +uniform vec4 u_setting; + void main() { - float vignette = 1.1 - 0.6 * (dot(v_texcoord0 - 0.5, v_texcoord0 - 0.5) * 2.0); + vec2 diff = v_texcoord0 - 0.5; + diff.x *= u_setting.y; + diff.y /= u_setting.y; + float vignette = 1.0 - min(1.0, u_setting.x * (dot(diff, diff) * 2.0)); vec3 rgb = texture2D(sampler0, v_texcoord0.xy).xyz; + rgb *= vignette; gl_FragColor.rgb = vignette * rgb; gl_FragColor.a = 1.0; } From 7ff00307722f7680274b6af335ed60365c609ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Dec 2022 16:04:20 +0100 Subject: [PATCH 635/715] Added vertical layout for display layout screen --- Common/UI/UIScreen.cpp | 11 +++++++++++ Common/UI/UIScreen.h | 4 +++- UI/DisplayLayoutScreen.cpp | 32 ++++++++++++++++++++++++-------- UI/GameSettingsScreen.cpp | 15 --------------- UI/GameSettingsScreen.h | 3 --- UI/MainScreen.cpp | 10 ---------- UI/MainScreen.h | 1 - UI/RemoteISOScreen.cpp | 4 ++-- 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 63b743d33a..d1623101d0 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -20,12 +20,17 @@ static const bool ClickDebug = false; UIScreen::UIScreen() : Screen() { + lastVertical_ = UseVerticalLayout(); } UIScreen::~UIScreen() { delete root_; } +bool UIScreen::UseVerticalLayout() const { + return dp_yres > dp_xres * 1.1f; +} + void UIScreen::DoRecreateViews() { if (recreateViews_) { std::lock_guard guard(screenManager()->inputLock_); @@ -60,6 +65,12 @@ void UIScreen::DoRecreateViews() { } void UIScreen::update() { + bool vertical = UseVerticalLayout(); + if (vertical != lastVertical_) { + RecreateViews(); + lastVertical_ = vertical; + } + DoRecreateViews(); if (root_) { diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 1b25dc4231..c9f0eb723e 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -42,7 +42,8 @@ protected: virtual void CreateViews() = 0; virtual void DrawBackground(UIContext &dc) {} - virtual void RecreateViews() override { recreateViews_ = true; } + void RecreateViews() override { recreateViews_ = true; } + bool UseVerticalLayout() const; UI::ViewGroup *root_ = nullptr; Vec3 translation_ = Vec3(0.0f); @@ -54,6 +55,7 @@ private: void DoRecreateViews(); bool recreateViews_ = true; + bool lastVertical_; }; class UIDialogScreen : public UIScreen { diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 4764b069f0..46188760e3 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -199,16 +199,21 @@ void DisplayLayoutScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + bool vertical = bounds.h > bounds.w; + // Make it so that a touch can only affect one view. Makes manipulating the background through the buttons // impossible. root_->SetExclusiveTouch(true); - ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(420.0f, FILL_PARENT, 0.f, 0.f, NONE, 0.f, false)); - LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL); - leftColumn->padding.SetAll(8.0f); - leftScrollView->Add(leftColumn); - leftScrollView->SetClickableBackground(true); - root_->Add(leftScrollView); + LinearLayout *leftColumn; + if (!vertical) { + ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(420.0f, FILL_PARENT, 0.f, 0.f, NONE, 0.f, false)); + leftColumn = new LinearLayout(ORIENT_VERTICAL); + leftColumn->padding.SetAll(8.0f); + leftScrollView->Add(leftColumn); + leftScrollView->SetClickableBackground(true); + root_->Add(leftScrollView); + } ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 0.f, 0.f, 0.f, false)); LinearLayout *rightColumn = new LinearLayout(ORIENT_VERTICAL); @@ -217,8 +222,15 @@ void DisplayLayoutScreen::CreateViews() { rightScrollView->SetClickableBackground(true); root_->Add(rightScrollView); - LinearLayout *bottomControls = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, NONE, NONE, 10.0f, false)); - root_->Add(bottomControls); + LinearLayout *bottomControls; + if (vertical) { + bottomControls = new LinearLayout(ORIENT_HORIZONTAL); + rightColumn->Add(bottomControls); + leftColumn = rightColumn; + } else { + bottomControls = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, NONE, NONE, 10.0f, false)); + root_->Add(bottomControls); + } // Set backgrounds for readability Drawable backgroundWithAlpha(GetBackgroundColorWithAlpha(*screenManager()->getUIContext())); @@ -266,6 +278,10 @@ void DisplayLayoutScreen::CreateViews() { back->OnClick.Handle(this, &UIScreen::OnBack); rightColumn->Add(back); + if (vertical) { + leftColumn->Add(new Spacer(24.0f)); + } + static const char *bufFilters[] = { "Linear", "Nearest", }; leftColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 15d1987f02..3e2a3229a2 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -92,15 +92,10 @@ extern AndroidAudioState *g_audioState; GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, bool editThenRestore) : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), editThenRestore_(editThenRestore) { - lastVertical_ = UseVerticalLayout(); prevInflightFrames_ = g_Config.iInflightFrames; analogSpeedMapped_ = KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr); } -bool GameSettingsScreen::UseVerticalLayout() const { - return dp_yres > dp_xres * 1.1f; -} - // This needs before run CheckGPUFeatures() // TODO: Remove this if fix the issue bool CheckSupportShaderTessellationGLES() { @@ -1297,16 +1292,6 @@ UI::EventReturn GameSettingsScreen::OnHwScaleChange(UI::EventParams &e) { return UI::EVENT_DONE; } -void GameSettingsScreen::update() { - UIScreen::update(); - - bool vertical = UseVerticalLayout(); - if (vertical != lastVertical_) { - RecreateViews(); - lastVertical_ = vertical; - } -} - void GameSettingsScreen::onFinish(DialogResult result) { if (g_Config.bEnableSound) { if (PSP_IsInited() && !IsAudioInitialised()) diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 5b51ee101d..86d5881f56 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -30,7 +30,6 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { public: GameSettingsScreen(const Path &gamePath, std::string gameID = "", bool editThenRestore = false); - void update() override; void onFinish(DialogResult result) override; const char *tag() const override { return "GameSettings"; } @@ -42,7 +41,6 @@ protected: void CallbackRenderingDevice(bool yes); void CallbackInflightFrames(bool yes); void CallbackMemstickFolder(bool yes); - bool UseVerticalLayout() const; void dialogFinished(const Screen *dialog, DialogResult result) override; void RecreateViews() override; @@ -52,7 +50,6 @@ private: void TriggerRestart(const char *why); std::string gameID_; - bool lastVertical_; UI::CheckBox *enableReportsCheckbox_; UI::Choice *layoutEditorChoice_; UI::Choice *displayEditor_; diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 53d77213c2..0855e7eea6 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -966,7 +966,6 @@ UI::EventReturn GameBrowser::OnHomebrewStore(UI::EventParams &e) { MainScreen::MainScreen() { System_SendMessage("event", "mainscreen"); g_BackgroundAudio.SetGame(Path()); - lastVertical_ = UseVerticalLayout(); } MainScreen::~MainScreen() { @@ -1255,15 +1254,6 @@ void MainScreen::sendMessage(const char *message, const char *value) { void MainScreen::update() { UIScreen::update(); UpdateUIState(UISTATE_MENU); - bool vertical = UseVerticalLayout(); - if (vertical != lastVertical_) { - RecreateViews(); - lastVertical_ = vertical; - } -} - -bool MainScreen::UseVerticalLayout() const { - return dp_yres > dp_xres * 1.1f; } UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) { diff --git a/UI/MainScreen.h b/UI/MainScreen.h index b81e193b93..995a912a92 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -114,7 +114,6 @@ protected: void sendMessage(const char *message, const char *value) override; void dialogFinished(const Screen *dialog, DialogResult result) override; - bool UseVerticalLayout() const; bool DrawBackgroundFor(UIContext &dc, const Path &gamePath, float progress); UI::EventReturn OnGameSelected(UI::EventParams &e); diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 7d60e507a4..93e2ae7681 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -517,11 +517,11 @@ RemoteISOBrowseScreen::RemoteISOBrowseScreen(const std::string &url, const std:: } void RemoteISOBrowseScreen::CreateViews() { - bool vertical = UseVerticalLayout(); - auto di = GetI18NCategory("Dialog"); auto ri = GetI18NCategory("RemoteISO"); + bool vertical = UseVerticalLayout(); + Margins actionMenuMargins(0, 10, 10, 0); TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); From d65a74e050e674c52331cb2bdf930e66773c0a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Dec 2022 16:17:44 +0100 Subject: [PATCH 636/715] Improve the pause screen in vertical layout --- UI/PauseScreen.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 85d60a480f..d76824d9b1 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -132,7 +132,7 @@ UI::EventReturn ScreenshotViewScreen::OnUndoState(UI::EventParams &e) { class SaveSlotView : public UI::LinearLayout { public: - SaveSlotView(const Path &gamePath, int slot, UI::LayoutParams *layoutParams = nullptr); + SaveSlotView(const Path &gamePath, int slot, bool vertical, UI::LayoutParams *layoutParams = nullptr); void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { w = 500; h = 90; @@ -169,7 +169,7 @@ private: Path screenshotFilename_; }; -SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams), slot_(slot), gamePath_(gameFilename) { +SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, bool vertical, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams), slot_(slot), gamePath_(gameFilename) { using namespace UI; screenshotFilename_ = SaveState::GenerateSaveSlotFilename(gamePath_, slot, SaveState::SCREENSHOT_EXTENSION); @@ -185,7 +185,7 @@ SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams Add(lines); - LinearLayout *buttons = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + LinearLayout *buttons = new LinearLayout(vertical ? ORIENT_VERTICAL : ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); buttons->SetSpacing(10.0f); lines->Add(buttons); @@ -201,7 +201,11 @@ SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams std::string dateStr = SaveState::GetSlotDateAsString(gamePath_, slot_); if (!dateStr.empty()) { - lines->Add(new TextView(dateStr, new LinearLayoutParams(0.0, G_VCENTER)))->SetShadow(true); + TextView *dateView = new TextView(dateStr, new LinearLayoutParams(0.0, G_VCENTER)); + if (vertical) { + dateView->SetSmall(true); + } + lines->Add(dateView)->SetShadow(true); } } else { fv->SetFilename(Path()); @@ -262,6 +266,8 @@ void GamePauseScreen::CreateViews() { using namespace UI; + bool vertical = UseVerticalLayout(); + Margins scrollMargins(0, 20, 0, 0); Margins actionMenuMargins(0, 20, 15, 0); auto gr = GetI18NCategory("Graphics"); @@ -278,7 +284,7 @@ void GamePauseScreen::CreateViews() { leftColumnItems->Add(new Spacer(0.0)); leftColumnItems->SetSpacing(10.0); for (int i = 0; i < NUM_SAVESLOTS; i++) { - SaveSlotView *slot = leftColumnItems->Add(new SaveSlotView(gamePath_, i, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); + SaveSlotView *slot = leftColumnItems->Add(new SaveSlotView(gamePath_, i, vertical, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); slot->OnStateLoaded.Handle(this, &GamePauseScreen::OnState); slot->OnStateSaved.Handle(this, &GamePauseScreen::OnState); slot->OnScreenshotClicked.Handle(this, &GamePauseScreen::OnScreenshotClicked); @@ -302,7 +308,7 @@ void GamePauseScreen::CreateViews() { rewindButton->OnClick.Handle(this, &GamePauseScreen::OnRewind); } - ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); + ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(vertical ? 200 : 300, FILL_PARENT, actionMenuMargins)); root_->Add(rightColumn); LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL); From a02df90335870e0a44ef0c741e3858533fc24a4c Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 6 Dec 2022 11:41:38 -0500 Subject: [PATCH 637/715] feat(Libretro): Cheat Support --- libretro/libretro.cpp | 84 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index e0cb5c0e6e..d784424035 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -23,6 +23,7 @@ #include "Common/File/VFS/VFS.h" #include "Common/File/VFS/AssetReader.h" #include "Common/Data/Text/I18n.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -36,6 +37,8 @@ #include "Core/System.h" #include "Core/CoreTiming.h" #include "Core/HW/Display.h" +#include "Core/CwCheat.h" +#include "Core/ELF/ParamSFO.h" #include "GPU/GPUState.h" #include "GPU/GPUInterface.h" @@ -1663,9 +1666,86 @@ size_t retro_get_memory_size(unsigned id) return 0; } -void retro_cheat_reset(void) {} +void retro_cheat_reset(void) { + // Init Cheat Engine + CWCheatEngine *cheatEngine = new CWCheatEngine(g_paramSFO.GetDiscID()); + Path file=cheatEngine->CheatFilename(); -void retro_cheat_set(unsigned index, bool enabled, const char *code) { } + // Output cheats to cheat file + std::ofstream outFile; + outFile.open(file.c_str()); + outFile << "_S " << g_paramSFO.GetDiscID() << std::endl; + outFile.close(); + + g_Config.bReloadCheats = true; + + // Parse and Run the Cheats + cheatEngine->ParseCheats(); + if (cheatEngine->HasCheats()) { + cheatEngine->Run(); + } + +} + +void retro_cheat_set(unsigned index, bool enabled, const char *code) { + // Initialize Cheat Engine + CWCheatEngine *cheatEngine = new CWCheatEngine(g_paramSFO.GetDiscID()); + cheatEngine->CreateCheatFile(); + Path file=cheatEngine->CheatFilename(); + + // Read cheats file + std::vector cheats; + std::ifstream cheat_content(file.c_str()); + std::stringstream buffer; + buffer << cheat_content.rdbuf(); + std::string existing_cheats=ReplaceAll(buffer.str(), std::string("\n_C"), std::string("|")); + SplitString(existing_cheats, '|', cheats); + + // Generate Cheat String + std::stringstream cheat(""); + cheat << (enabled ? "1 " : "0 ") << index << std::endl; + std::string code_str(code); + std::vector codes; + code_str=ReplaceAll(code_str, std::string(" "), std::string("+")); + SplitString(code_str, '+', codes); + int part=0; + for (int i=0; i < codes.size(); i++) { + if (codes[i].size() <= 2) { + // _L _M ..etc + // Assume _L + } else if (part == 0) { + cheat << "_L " << codes[i] << " "; + part++; + } else { + cheat << codes[i] << std::endl; + part=0; + } + } + + // Add or Replace the Cheat + if (index + 1 < cheats.size()) { + cheats[index + 1]=cheat.str(); + } else { + cheats.push_back(cheat.str()); + } + + // Output cheats to cheat file + std::ofstream outFile; + outFile.open(file.c_str()); + outFile << "_S " << g_paramSFO.GetDiscID() << std::endl; + for (int i=1; i < cheats.size(); i++) { + outFile << "_C" << cheats[i] << std::endl; + } + outFile.close(); + + g_Config.bReloadCheats = true; + + // Parse and Run the Cheats + cheatEngine->ParseCheats(); + if (cheatEngine->HasCheats()) { + cheatEngine->Run(); + } +} int System_GetPropertyInt(SystemProperty prop) { From d5d0e2c92002e550e87d81950b7b446a5c4d2614 Mon Sep 17 00:00:00 2001 From: iota97 Date: Fri, 9 Dec 2022 09:28:28 +0100 Subject: [PATCH 638/715] Fix SDL fullscreen --- SDL/SDLMain.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index b09a64d5dd..8a0b6c6441 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -569,9 +569,10 @@ int main(int argc, char *argv[]) { Uint32 mode = 0; for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i],"--fullscreen")) + if (!strcmp(argv[i],"--fullscreen")) { mode |= SDL_WINDOW_FULLSCREEN_DESKTOP; - else if (set_xres == -2) + g_Config.iForceFullScreen = 1; + } else if (set_xres == -2) set_xres = parseInt(argv[i]); else if (set_yres == -2) set_yres = parseInt(argv[i]); @@ -657,7 +658,8 @@ int main(int argc, char *argv[]) { if (mode & SDL_WINDOW_FULLSCREEN_DESKTOP) { pixel_xres = g_DesktopWidth; pixel_yres = g_DesktopHeight; - g_Config.iForceFullScreen = 1; + if (g_Config.iForceFullScreen == -1) + g_Config.bFullScreen = true; } else { // set a sensible default resolution (2x) pixel_xres = 480 * 2 * set_scale; @@ -665,7 +667,8 @@ int main(int argc, char *argv[]) { if (portrait) { std::swap(pixel_xres, pixel_yres); } - g_Config.iForceFullScreen = 0; + if (g_Config.iForceFullScreen == -1) + g_Config.bFullScreen = false; } set_dpi = 1.0f / set_dpi; From 0d1f167495639aa2f86f207d004f8560992393dc Mon Sep 17 00:00:00 2001 From: iota97 Date: Wed, 7 Dec 2022 23:02:49 +0100 Subject: [PATCH 639/715] Motion blur --- assets/shaders/defaultshaders.ini | 10 ++++++++++ assets/shaders/motionblur.fsh | 14 ++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 assets/shaders/motionblur.fsh diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index d987574591..cb36c53e38 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -208,3 +208,13 @@ Name=SideBySide Stereo Author=Henrik Rydgård Fragment=stereo_sbs.fsh Vertex=fxaa.vsh +[MotionBlur] +Name=Motion blur +Fragment=motionblur.fsh +Vertex=fxaa.vsh +UsePreviousFrame=true +SettingName1=Strength +SettingDefaultValue1=0.4 +SettingMaxValue1=0.8 +SettingMinValue1=0.3 +SettingStep1=0.05 \ No newline at end of file diff --git a/assets/shaders/motionblur.fsh b/assets/shaders/motionblur.fsh new file mode 100644 index 0000000000..9be51d8225 --- /dev/null +++ b/assets/shaders/motionblur.fsh @@ -0,0 +1,14 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +uniform sampler2D sampler0; +uniform sampler2D sampler2; +uniform vec4 u_setting; +varying vec2 v_texcoord0; + +void main() { + gl_FragColor.rgb = mix(texture2D(sampler0, v_texcoord0.xy).rgb, texture2D(sampler2, v_texcoord0.xy).rgb, u_setting.x); + gl_FragColor.a = 1.0; +} From 241277e08d634eee17f133316d6c6094a2667a93 Mon Sep 17 00:00:00 2001 From: iota97 Date: Wed, 7 Dec 2022 23:17:58 +0100 Subject: [PATCH 640/715] rename --- assets/shaders/defaultshaders.ini | 6 +++--- assets/shaders/{motionblur.fsh => persistence.fsh} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename assets/shaders/{motionblur.fsh => persistence.fsh} (100%) diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index cb36c53e38..b0e48dabb8 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -208,9 +208,9 @@ Name=SideBySide Stereo Author=Henrik Rydgård Fragment=stereo_sbs.fsh Vertex=fxaa.vsh -[MotionBlur] -Name=Motion blur -Fragment=motionblur.fsh +[LCDPersistence] +Name=LCD Persistence +Fragment=persistence.fsh Vertex=fxaa.vsh UsePreviousFrame=true SettingName1=Strength diff --git a/assets/shaders/motionblur.fsh b/assets/shaders/persistence.fsh similarity index 100% rename from assets/shaders/motionblur.fsh rename to assets/shaders/persistence.fsh From 4280a9f51cfedfed3676d4474bad12a0565ecd94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Dec 2022 17:19:08 +0100 Subject: [PATCH 641/715] Force postshaders with the usePreviousFrame flag to the end of the order --- GPU/Common/PostShader.cpp | 22 ++++++++++++++++++++++ GPU/Common/PostShader.h | 5 +++++ GPU/Common/PresentationCommon.cpp | 1 + UI/DisplayLayoutScreen.cpp | 6 +++++- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 0cf1971e53..a29525b2f4 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -324,3 +324,25 @@ const TextureShaderInfo *GetTextureShaderInfo(const std::string &name) { const std::vector &GetAllTextureShaderInfo() { return textureShaderInfo; } + +void FixPostShaderOrder(std::vector *names) { + // There's one rule only that we enforce - only one shader can use UsePreviousFrame, + // and it has to be the last one. So we simply remove any we find from the list, + // and then append it to the end if there is one. + std::string prevFrameShader; + for (auto iter = names->begin(); iter != names->end(); ) { + const ShaderInfo *info = GetPostShaderInfo(*iter); + if (info) { + if (info->usePreviousFrame) { + prevFrameShader = *iter; + iter = names->erase(iter++); + continue; + } + } + ++iter; + } + + if (!prevFrameShader.empty()) { + names->push_back(prevFrameShader); + } +} diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index 4b4061988c..882290d49f 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -115,3 +115,8 @@ const std::vector &GetAllPostShaderInfo(); const TextureShaderInfo *GetTextureShaderInfo(const std::string &name); const std::vector &GetAllTextureShaderInfo(); void RemoveUnknownPostShaders(std::vector *names); + +// Call this any time you alter the postshader list. It makes sure +// that "usePrevFrame" shaders are at the end, and that there's only one. +// It'll also enforce any similar future rules. +void FixPostShaderOrder(std::vector *names); diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index f8837e2808..30fcfe7675 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -880,6 +880,7 @@ void PresentationCommon::CalculateRenderResolution(int *width, int *height, int if (!g_Config.vPostShaderNames.empty()) { ReloadAllPostShaderInfo(draw_); RemoveUnknownPostShaders(&g_Config.vPostShaderNames); + FixPostShaderOrder(&g_Config.vPostShaderNames); shaderInfo = GetFullPostShadersChain(g_Config.vPostShaderNames); } diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 46188760e3..b1612c3c2f 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -152,6 +152,7 @@ void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult resu UI::EventReturn DisplayLayoutScreen::OnPostProcShaderChange(UI::EventParams &e) { // Remove the virtual "Off" entry. TODO: Get rid of it generally. g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); + FixPostShaderOrder(&g_Config.vPostShaderNames); NativeMessageReceived("gpu_configChanged", ""); NativeMessageReceived("gpu_renderResized", ""); // To deal with shaders that can change render resolution like upscaling. @@ -370,7 +371,9 @@ void DisplayLayoutScreen::CreateViews() { moreButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), di.get(), moreButton); screenManager()->push(contextMenu); - contextMenu->SetEnabled(0, i > 0); + const ShaderInfo *info = GetPostShaderInfo(g_Config.vPostShaderNames[i]); + bool usesLastFrame = info ? info->usePreviousFrame : false; + contextMenu->SetEnabled(0, i > 0 && !usesLastFrame); contextMenu->SetEnabled(1, i < g_Config.vPostShaderNames.size() - 1); contextMenu->OnChoice.Add([=](EventParams &e) -> UI::EventReturn { switch (e.a) { @@ -386,6 +389,7 @@ void DisplayLayoutScreen::CreateViews() { default: return UI::EVENT_DONE; } + FixPostShaderOrder(&g_Config.vPostShaderNames); NativeMessageReceived("gpu_configChanged", ""); RecreateViews(); return UI::EVENT_DONE; From 0ad6218dc4f26d8b7cc2081b197a76585934cd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Dec 2022 17:28:58 +0100 Subject: [PATCH 642/715] Fix "usePrevFrame" shaders for OpenGL --- Common/GPU/OpenGL/thin3d_gl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index b107f2f194..1b31be2a1e 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1238,14 +1238,17 @@ bool OpenGLPipeline::LinkShaders() { semantics.push_back({ SEM_TEXCOORD0, "a_texcoord0" }); std::vector queries; + int samplersToCheck; if (!samplers_.is_empty()) { for (int i = 0; i < (int)std::min((const uint32_t)samplers_.size(), MAX_TEXTURE_SLOTS); i++) { queries.push_back({ &samplerLocs_[i], samplers_[i].name, true }); } + samplersToCheck = (int)samplers_.size(); } else { queries.push_back({ &samplerLocs_[0], "sampler0" }); queries.push_back({ &samplerLocs_[1], "sampler1" }); queries.push_back({ &samplerLocs_[2], "sampler2" }); + samplersToCheck = 3; } _assert_(queries.size() <= MAX_TEXTURE_SLOTS); @@ -1254,7 +1257,7 @@ bool OpenGLPipeline::LinkShaders() { } std::vector initialize; for (int i = 0; i < MAX_TEXTURE_SLOTS; ++i) { - if (i < (int)samplers_.size()) { + if (i < samplersToCheck) { initialize.push_back({ &samplerLocs_[i], 0, i }); } else { samplerLocs_[i] = -1; From acf55916fde4de8b2568c0a3da9c4af49c6b0c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Dec 2022 18:04:31 +0100 Subject: [PATCH 643/715] Silence address-sanitizer warnings in Math3D.h on ARM64 (not very serious but good to fix) --- GPU/Math3D.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/GPU/Math3D.h b/GPU/Math3D.h index d6514aa1b0..b3a94ba56c 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -898,7 +898,8 @@ inline void Vec3ByMatrix43(float vecOut[3], const float v[3], const float m[12]) vecOut[1] = vectorGetByIndex<1>(sum); vecOut[2] = vectorGetByIndex<2>(sum); #elif PPSSPP_ARCH(ARM64_NEON) - float32x4_t sum = Vec3ByMatrix43Internal(vld1q_f32(v), m); + float vecIn[4] = {v[0], v[1], v[2], 1.0f}; + float32x4_t sum = Vec3ByMatrix43Internal(vld1q_f32(vecIn), m); vecOut[0] = vgetq_lane_f32(sum, 0); vecOut[1] = vgetq_lane_f32(sum, 1); vecOut[2] = vgetq_lane_f32(sum, 2); @@ -957,7 +958,8 @@ inline void Vec3ByMatrix44(float vecOut[4], const float v[3], const float m[16]) __m128 sum = Vec3ByMatrix44Internal(x, y, z, m); _mm_storeu_ps(vecOut, sum); #elif PPSSPP_ARCH(ARM64_NEON) - float32x4_t sum = Vec3ByMatrix44Internal(vld1q_f32(v), m); + float vecIn[4] = {v[0], v[1], v[2], 1.0f}; + float32x4_t sum = Vec3ByMatrix44Internal(vld1q_f32(vecIn), m); vst1q_f32(vecOut, sum); #else vecOut[0] = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + m[12]; From b7a3cf56cc06396b302aeb365ef7e15a30f1ff3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Dec 2022 20:52:19 +0100 Subject: [PATCH 644/715] OpenGL: Fix lifetime issue with uniform/sampler "locs" for thin3d pipelines --- Common/GPU/OpenGL/GLRenderManager.h | 17 +++++++++++- Common/GPU/OpenGL/thin3d_gl.cpp | 41 ++++++++++++++++++----------- GPU/GLES/ShaderManagerGLES.cpp | 2 +- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 905fd70826..ff48306c3e 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -99,12 +99,23 @@ struct GLRProgramFlags { bool useClipDistance2 : 1; }; +// Unless you manage lifetimes in some smart way, +// your loc data for uniforms and samplers need to be in a struct +// derived from this, and passed into CreateProgram. +class GLRProgramLocData { +public: + virtual ~GLRProgramLocData() {} +}; + class GLRProgram { public: ~GLRProgram() { if (program) { glDeleteProgram(program); } + if (locData_) { + delete locData_; + } } struct Semantic { int location; @@ -127,6 +138,8 @@ public: std::vector semantics_; std::vector queries_; std::vector initialize_; + + GLRProgramLocData *locData_; bool use_clip_distance[8]{}; struct UniformInfo { @@ -148,6 +161,7 @@ public: } return loc; } + std::unordered_map uniformCache_; }; @@ -438,13 +452,14 @@ public: // not be an active render pass. GLRProgram *CreateProgram( std::vector shaders, std::vector semantics, std::vector queries, - std::vector initializers, const GLRProgramFlags &flags) { + std::vector initializers, GLRProgramLocData *locData, const GLRProgramFlags &flags) { GLRInitStep step{ GLRInitStepType::CREATE_PROGRAM }; _assert_(shaders.size() <= ARRAY_SIZE(step.create_program.shaders)); step.create_program.program = new GLRProgram(); step.create_program.program->semantics_ = semantics; step.create_program.program->queries_ = queries; step.create_program.program->initialize_ = initializers; + step.create_program.program->locData_ = locData; step.create_program.program->use_clip_distance[0] = flags.useClipDistance0; step.create_program.program->use_clip_distance[1] = flags.useClipDistance1; step.create_program.program->use_clip_distance[2] = flags.useClipDistance2; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 1b31be2a1e..2536d2beea 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -261,6 +261,11 @@ bool OpenGLShaderModule::Compile(GLRenderManager *render, ShaderLanguage languag return true; } +struct PipelineLocData : GLRProgramLocData { + GLint samplerLocs_[MAX_TEXTURE_SLOTS]{}; + std::vector dynamicUniformLocs_; +}; + class OpenGLInputLayout : public InputLayout { public: OpenGLInputLayout(GLRenderManager *render) : render_(render) {} @@ -285,9 +290,10 @@ public: if (program_) { render_->DeleteProgram(program_); } + // DO NOT delete locs_ here, it's deleted by the render manager. } - bool LinkShaders(); + bool LinkShaders(const PipelineDesc &desc); GLuint prim = 0; std::vector shaders; @@ -296,12 +302,14 @@ public: AutoRef blend; AutoRef raster; + // Not owned! + PipelineLocData *locs_ = nullptr; + // TODO: Optimize by getting the locations first and putting in a custom struct UniformBufferDesc dynamicUniforms; - GLint samplerLocs_[MAX_TEXTURE_SLOTS]{}; - std::vector dynamicUniformLocs_; GLRProgram *program_ = nullptr; + // Allow using other sampler names than sampler0, sampler1 etc in shaders. // If not set, will default to those, though. Slice samplers_; @@ -1133,10 +1141,10 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const } if (desc.uniformDesc) { pipeline->dynamicUniforms = *desc.uniformDesc; - pipeline->dynamicUniformLocs_.resize(desc.uniformDesc->uniforms.size()); } + pipeline->samplers_ = desc.samplers; - if (pipeline->LinkShaders()) { + if (pipeline->LinkShaders(desc)) { // Build the rest of the virtual pipeline object. pipeline->prim = primToGL[(int)desc.prim]; pipeline->depthStencil = (OpenGLDepthStencilState *)desc.depthStencil; @@ -1206,7 +1214,7 @@ ShaderModule *OpenGLContext::CreateShaderModule(ShaderStage stage, ShaderLanguag } } -bool OpenGLPipeline::LinkShaders() { +bool OpenGLPipeline::LinkShaders(const PipelineDesc &desc) { std::vector linkShaders; for (auto shaderModule : shaders) { if (shaderModule) { @@ -1237,35 +1245,38 @@ bool OpenGLPipeline::LinkShaders() { semantics.push_back({ SEM_POSITION, "a_position" }); semantics.push_back({ SEM_TEXCOORD0, "a_texcoord0" }); + locs_ = new PipelineLocData(); + locs_->dynamicUniformLocs_.resize(desc.uniformDesc->uniforms.size()); + std::vector queries; int samplersToCheck; if (!samplers_.is_empty()) { for (int i = 0; i < (int)std::min((const uint32_t)samplers_.size(), MAX_TEXTURE_SLOTS); i++) { - queries.push_back({ &samplerLocs_[i], samplers_[i].name, true }); + queries.push_back({ &locs_->samplerLocs_[i], samplers_[i].name, true }); } samplersToCheck = (int)samplers_.size(); } else { - queries.push_back({ &samplerLocs_[0], "sampler0" }); - queries.push_back({ &samplerLocs_[1], "sampler1" }); - queries.push_back({ &samplerLocs_[2], "sampler2" }); + queries.push_back({ &locs_->samplerLocs_[0], "sampler0" }); + queries.push_back({ &locs_->samplerLocs_[1], "sampler1" }); + queries.push_back({ &locs_->samplerLocs_[2], "sampler2" }); samplersToCheck = 3; } _assert_(queries.size() <= MAX_TEXTURE_SLOTS); for (size_t i = 0; i < dynamicUniforms.uniforms.size(); ++i) { - queries.push_back({ &dynamicUniformLocs_[i], dynamicUniforms.uniforms[i].name }); + queries.push_back({ &locs_->dynamicUniformLocs_[i], dynamicUniforms.uniforms[i].name }); } std::vector initialize; for (int i = 0; i < MAX_TEXTURE_SLOTS; ++i) { if (i < samplersToCheck) { - initialize.push_back({ &samplerLocs_[i], 0, i }); + initialize.push_back({ &locs_->samplerLocs_[i], 0, i }); } else { - samplerLocs_[i] = -1; + locs_->samplerLocs_[i] = -1; } } GLRProgramFlags flags{}; - program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, flags); + program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, locs_, flags); return true; } @@ -1287,7 +1298,7 @@ void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { for (size_t i = 0; i < curPipeline_->dynamicUniforms.uniforms.size(); ++i) { const auto &uniform = curPipeline_->dynamicUniforms.uniforms[i]; - const GLint &loc = curPipeline_->dynamicUniformLocs_[i]; + const GLint &loc = curPipeline_->locs_->dynamicUniformLocs_[i]; const float *data = (const float *)((uint8_t *)ub + uniform.offset); switch (uniform.type) { case UniformType::FLOAT1: diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index cc5211a19f..fa5cc0d2d4 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -204,7 +204,7 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, flags.useClipDistance0 = true; } - program = render->CreateProgram(shaders, semantics, queries, initialize, flags); + program = render->CreateProgram(shaders, semantics, queries, initialize, nullptr, flags); // The rest, use the "dirty" mechanism. dirtyUniforms = DIRTY_ALL_UNIFORMS; From e59b734b2719f4a6ed251bd5585ee97be6b4856c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Dec 2022 23:00:52 +0100 Subject: [PATCH 645/715] Fix case where we could write off the end of a buffer if texture width == 1 and 4-bit color. --- Common/UI/UIScreen.h | 2 +- GPU/Common/TextureCacheCommon.cpp | 4 +++- GPU/Common/TextureDecoder.h | 37 +++++++++++++++++++++++-------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index c9f0eb723e..d0f3dd322b 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -282,7 +282,7 @@ public: UI::Event OnChoice; protected: - bool HasTitleBar() const { return false; } + bool HasTitleBar() const override { return false; } private: const ContextMenuItem *items_; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index e4d634f2b6..c8d4bc01d4 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1673,7 +1673,9 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G case GE_CMODE_16BIT_ABGR5551: case GE_CMODE_16BIT_ABGR4444: { - if (clutAlphaLinear_ && mipmapShareClut && !expandTo32bit) { + // The w > 1 check is to not need a case that handles a single pixel + // in DeIndexTexture4Optimal. + if (clutAlphaLinear_ && mipmapShareClut && !expandTo32bit && w >= 4) { // We don't bother with fullalpha here (clutAlphaLinear_) // Here, reverseColors means the CLUT is already reversed. if (reverseColors) { diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index 7a15a32adc..3df27b4a3b 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -163,22 +163,36 @@ inline void DeIndexTexture4(/*WRITEONLY*/ ClutT *dest, const u8 *indexed, int le ClutT alphaSum = (ClutT)(-1); if (nakedIndex) { - for (int i = 0; i < length; i += 2) { + while (length >= 2) { u8 index = *indexed++; ClutT color0 = clut[index & 0xf]; ClutT color1 = clut[index >> 4]; - dest[i + 0] = color0; - dest[i + 1] = color1; + *dest++ = color0; + *dest++ = color1; alphaSum &= color0 & color1; + length -= 2; + } + if (length) { // Last pixel. Can really only happen in 1xY textures, but making this work generically. + u8 index = *indexed++; + ClutT color0 = clut[index & 0xf]; + *dest = color0; + alphaSum &= color0; } } else { - for (int i = 0; i < length; i += 2) { + while (length >= 2) { u8 index = *indexed++; ClutT color0 = clut[gstate.transformClutIndex((index >> 0) & 0xf)]; ClutT color1 = clut[gstate.transformClutIndex((index >> 4) & 0xf)]; - dest[i + 0] = color0; - dest[i + 1] = color1; + *dest++ = color0; + *dest++ = color1; alphaSum &= color0 & color1; + length -= 2; + } + if (length) { + u8 index = *indexed++; + ClutT color0 = clut[gstate.transformClutIndex((index >> 0) & 0xf)]; + *dest = color0; + alphaSum &= color0; } } @@ -187,10 +201,15 @@ inline void DeIndexTexture4(/*WRITEONLY*/ ClutT *dest, const u8 *indexed, int le template inline void DeIndexTexture4Optimal(ClutT *dest, const u8 *indexed, int length, ClutT color) { - for (int i = 0; i < length; i += 2) { + while (length >= 2) { u8 index = *indexed++; - dest[i + 0] = color | ((index >> 0) & 0xf); - dest[i + 1] = color | ((index >> 4) & 0xf); + *dest++ = color | ((index >> 0) & 0xf); + *dest++ = color | ((index >> 4) & 0xf); + length -= 2; + } + if (length) { + u8 index = *indexed++; + *dest++ = color | ((index >> 0) & 0xf); } } From 3b5770da9b6341adbda01d1f4d0c1cd81ec55eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Dec 2022 23:13:39 +0100 Subject: [PATCH 646/715] DXT5 fix --- GPU/Common/TextureCacheCommon.cpp | 7 ++++--- GPU/Common/TextureDecoder.cpp | 30 +++++++++++++++--------------- GPU/Common/TextureDecoder.h | 6 +++--- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index c8d4bc01d4..e0c2d4667b 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1556,15 +1556,16 @@ static CheckAlphaResult DecodeDXTBlocks(uint8_t *out, int outPitch, uint32_t tex u32 blockIndex = (y / 4) * (bufw / 4); int blockHeight = std::min(h - y, 4); for (int x = 0; x < minw; x += 4) { + int blockWidth = std::min(minw - x, 4); switch (n) { case 1: - DecodeDXT1Block(dst + outPitch32 * y + x, (const DXT1Block *)src + blockIndex, outPitch32, blockHeight, &alphaSum); + DecodeDXT1Block(dst + outPitch32 * y + x, (const DXT1Block *)src + blockIndex, outPitch32, blockWidth, blockHeight, &alphaSum); break; case 3: - DecodeDXT3Block(dst + outPitch32 * y + x, (const DXT3Block *)src + blockIndex, outPitch32, blockHeight); + DecodeDXT3Block(dst + outPitch32 * y + x, (const DXT3Block *)src + blockIndex, outPitch32, blockWidth, blockHeight); break; case 5: - DecodeDXT5Block(dst + outPitch32 * y + x, (const DXT5Block *)src + blockIndex, outPitch32, blockHeight); + DecodeDXT5Block(dst + outPitch32 * y + x, (const DXT5Block *)src + blockIndex, outPitch32, blockWidth, blockHeight); break; } blockIndex++; diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index 22e45b151b..a12be66cb9 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -421,9 +421,9 @@ class DXTDecoder { public: inline void DecodeColors(const DXT1Block *src, bool ignore1bitAlpha); inline void DecodeAlphaDXT5(const DXT5Block *src); - inline void WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int height); - inline void WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int height); - inline void WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int height); + inline void WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int width, int height); + inline void WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int width, int height); + inline void WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int width, int height); bool AnyNonFullAlpha() const { return anyNonFullAlpha_; } @@ -507,11 +507,11 @@ void DXTDecoder::DecodeAlphaDXT5(const DXT5Block *src) { } } -void DXTDecoder::WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int height) { +void DXTDecoder::WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int width, int height) { bool anyColor3 = false; for (int y = 0; y < height; y++) { int colordata = src->lines[y]; - for (int x = 0; x < 4; x++) { + for (int x = 0; x < width; x++) { int col = colordata & 3; if (col == 3) { anyColor3 = true; @@ -527,11 +527,11 @@ void DXTDecoder::WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int } } -void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int height) { +void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int width, int height) { for (int y = 0; y < height; y++) { int colordata = src->color.lines[y]; u32 alphadata = src->alphaLines[y]; - for (int x = 0; x < 4; x++) { + for (int x = 0; x < width; x++) { dst[x] = colors_[colordata & 3] | (alphadata << 28); colordata >>= 2; alphadata >>= 4; @@ -540,13 +540,13 @@ void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int } } -void DXTDecoder::WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int height) { +void DXTDecoder::WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int width, int height) { // 48 bits, 3 bit index per pixel, 12 bits per line. u64 alphadata = ((u64)(u16)src->alphadata1 << 32) | (u32)src->alphadata2; for (int y = 0; y < height; y++) { int colordata = src->color.lines[y]; - for (int x = 0; x < 4; x++) { + for (int x = 0; x < width; x++) { dst[x] = colors_[colordata & 3] | (alpha_[alphadata & 7] << 24); colordata >>= 2; alphadata >>= 3; @@ -619,24 +619,24 @@ uint32_t GetDXT5Texel(const DXT5Block *src, int x, int y) { } // This could probably be done faster by decoding two or four blocks at a time with SSE/NEON. -void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int height, u32 *alpha) { +void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int width, int height, u32 *alpha) { DXTDecoder dxt; dxt.DecodeColors(src, false); - dxt.WriteColorsDXT1(dst, src, pitch, height); + dxt.WriteColorsDXT1(dst, src, pitch, width, height); *alpha &= dxt.AnyNonFullAlpha() ? 0 : 1; } -void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int height) { +void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int width, int height) { DXTDecoder dxt; dxt.DecodeColors(&src->color, true); - dxt.WriteColorsDXT3(dst, src, pitch, height); + dxt.WriteColorsDXT3(dst, src, pitch, width, height); } -void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int height) { +void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int width, int height) { DXTDecoder dxt; dxt.DecodeColors(&src->color, true); dxt.DecodeAlphaDXT5(src); - dxt.WriteColorsDXT5(dst, src, pitch, height); + dxt.WriteColorsDXT5(dst, src, pitch, width, height); } #ifdef _M_SSE diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index 3df27b4a3b..ad54815ff7 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -65,9 +65,9 @@ struct DXT5Block { u8 alpha1; u8 alpha2; }; -void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int height, u32 *alpha); -void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int height); -void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int height); +void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int width, int height, u32 *alpha); +void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int width, int height); +void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int width, int height); uint32_t GetDXT1Texel(const DXT1Block *src, int x, int y); uint32_t GetDXT3Texel(const DXT3Block *src, int x, int y); From 37b0c90a2dd7c1642d29afd895bc97cf13a334b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Dec 2022 18:04:31 +0100 Subject: [PATCH 647/715] Silence address-sanitizer warnings in Math3D.h on ARM64 (not very serious but good to fix) --- GPU/Math3D.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/GPU/Math3D.h b/GPU/Math3D.h index d6514aa1b0..b3a94ba56c 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -898,7 +898,8 @@ inline void Vec3ByMatrix43(float vecOut[3], const float v[3], const float m[12]) vecOut[1] = vectorGetByIndex<1>(sum); vecOut[2] = vectorGetByIndex<2>(sum); #elif PPSSPP_ARCH(ARM64_NEON) - float32x4_t sum = Vec3ByMatrix43Internal(vld1q_f32(v), m); + float vecIn[4] = {v[0], v[1], v[2], 1.0f}; + float32x4_t sum = Vec3ByMatrix43Internal(vld1q_f32(vecIn), m); vecOut[0] = vgetq_lane_f32(sum, 0); vecOut[1] = vgetq_lane_f32(sum, 1); vecOut[2] = vgetq_lane_f32(sum, 2); @@ -957,7 +958,8 @@ inline void Vec3ByMatrix44(float vecOut[4], const float v[3], const float m[16]) __m128 sum = Vec3ByMatrix44Internal(x, y, z, m); _mm_storeu_ps(vecOut, sum); #elif PPSSPP_ARCH(ARM64_NEON) - float32x4_t sum = Vec3ByMatrix44Internal(vld1q_f32(v), m); + float vecIn[4] = {v[0], v[1], v[2], 1.0f}; + float32x4_t sum = Vec3ByMatrix44Internal(vld1q_f32(vecIn), m); vst1q_f32(vecOut, sum); #else vecOut[0] = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + m[12]; From 4ec1e2a17519af4694897ff81702177c76fc5b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 10 Dec 2022 11:28:19 +0100 Subject: [PATCH 648/715] Some minor initialization fixes, and one potential crash found by static analysis --- Common/UI/Root.cpp | 4 +--- Common/UI/UIScreen.h | 4 ++-- GPU/Common/FramebufferManagerCommon.cpp | 5 ++++- GPU/Common/TextureCacheCommon.cpp | 2 +- GPU/Common/VertexDecoderCommon.h | 2 +- GPU/GPU.cpp | 4 +++- Windows/GPU/WindowsGLContext.cpp | 8 ++++---- 7 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Common/UI/Root.cpp b/Common/UI/Root.cpp index b02ae9ee55..ccd1f67352 100644 --- a/Common/UI/Root.cpp +++ b/Common/UI/Root.cpp @@ -33,9 +33,7 @@ std::atomic hasDispatchQueue; std::deque g_dispatchQueue; void EventTriggered(Event *e, EventParams params) { - DispatchQueueItem item; - item.e = e; - item.params = params; + DispatchQueueItem item{ e, params }; std::unique_lock guard(eventMutex_); // Set before adding so we lock and check the added value. diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index d0f3dd322b..03a8f8a18a 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -420,7 +420,7 @@ private: std::string negativeLabel_; std::string units_; ScreenManager *screenManager_; - bool restoreFocus_; + bool restoreFocus_ = false; }; class PopupSliderChoiceFloat : public AbstractChoiceWithValueDisplay { @@ -457,7 +457,7 @@ private: std::string zeroLabel_; std::string units_; ScreenManager *screenManager_; - bool restoreFocus_; + bool restoreFocus_ = false; bool liveUpdate_ = false; bool hasDropShadow_ = true; }; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 613ab0a157..ea199d8d51 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1147,7 +1147,10 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int draw_->BindTextures(0, 1, &pixelsTex, Draw::TextureBindFlags::VULKAN_BIND_ARRAY); // TODO: Replace with draw2D_.Blit() directly. - DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); + DrawActiveTexture(dstX, dstY, width, height, + vfb ? vfb->bufferWidth : pixel_xres, + vfb ? vfb->bufferHeight : pixel_yres, + u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); gpuStats.numUploads++; pixelsTex->Release(); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index e0c2d4667b..afdbe7b500 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1036,7 +1036,7 @@ bool TextureCacheCommon::MatchFramebuffer( } return true; } else if (IsClutFormat((GETextureFormat)(entry.format)) || IsDXTFormat((GETextureFormat)(entry.format))) { - WARN_LOG_ONCE(fourEightBit, G3D, "%s fb_format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); + WARN_LOG_ONCE(fourEightBit, G3D, "%s texture format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); return false; } diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 6ebad221d3..33986f382b 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -583,7 +583,7 @@ private: void Jit_AnyS16Morph(int srcoff, int dstoff); void Jit_AnyFloatMorph(int srcoff, int dstoff); - const VertexDecoder *dec_; + const VertexDecoder *dec_ = nullptr; #if PPSSPP_ARCH(ARM64) Arm64Gen::ARM64FloatEmitter fp; #endif diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index ed6a553c7e..9ff5b8fd35 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -114,6 +114,9 @@ bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { #endif void GPU_Shutdown() { + // Reduce the risk for weird races with the Windows GE debugger. + gpuDebug = nullptr; + // Wait for IsReady, since it might be running on a thread. if (gpu) { gpu->CancelReady(); @@ -123,5 +126,4 @@ void GPU_Shutdown() { } delete gpu; gpu = nullptr; - gpuDebug = nullptr; } diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index e919a10420..05afc4d1f5 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -90,7 +90,7 @@ void WindowsGLContext::Resume() { void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenum type, GLuint id, GLenum severity, const char *msg) { - char sourceStr[32]; + char sourceStr[32]{}; const char *sourceFmt; switch(source) { case GL_DEBUG_SOURCE_API_ARB: sourceFmt = "API"; break; @@ -103,7 +103,7 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu } snprintf(sourceStr, sizeof(sourceStr), sourceFmt, source); - char typeStr[32]; + char typeStr[32]{}; const char *typeFmt; switch(type) { case GL_DEBUG_TYPE_ERROR_ARB: typeFmt = "ERROR"; break; @@ -116,7 +116,7 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu } snprintf(typeStr, sizeof(typeStr), typeFmt, type); - char severityStr[32]; + char severityStr[32]{}; const char *severityFmt; switch (severity) { case GL_DEBUG_SEVERITY_HIGH_ARB: severityFmt = "HIGH"; break; @@ -130,7 +130,7 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu } void DebugCallbackARB(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar *message, GLvoid *userParam) { + GLsizei length, const GLchar *message, GLvoid *userParam) { // Ignore buffer mapping messages from NVIDIA if (source == GL_DEBUG_SOURCE_API_ARB && type == GL_DEBUG_TYPE_OTHER_ARB && id == 131185) { return; From 59ab1374f236ced7cfba9d44e1931384a229e269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 10 Dec 2022 11:41:12 +0100 Subject: [PATCH 649/715] Fix regression in Tactics Ogre - the mipmap level hack broke It broke when we introduced the 3D texture support, in #15727 Fixes #16354 --- GPU/Common/TextureCacheCommon.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index e0c2d4667b..6cede753cc 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -2646,15 +2646,22 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt plan.scaleFactor = plan.scaleFactor > 4 ? 4 : (plan.scaleFactor > 2 ? 2 : 1); } + bool isFakeMipmapChange = IsFakeMipmapChange(); + if (plan.badMipSizes) { // Check for pure 3D texture. int tw = gstate.getTextureWidth(0); int th = gstate.getTextureHeight(0); bool pure3D = true; - for (int i = 0; i < plan.levelsToLoad; i++) { - if (gstate.getTextureWidth(i) != gstate.getTextureWidth(0) || gstate.getTextureHeight(i) != gstate.getTextureHeight(0)) { - pure3D = false; + if (!isFakeMipmapChange) { + for (int i = 0; i < plan.levelsToLoad; i++) { + if (gstate.getTextureWidth(i) != gstate.getTextureWidth(0) || gstate.getTextureHeight(i) != gstate.getTextureHeight(0)) { + pure3D = false; + break; + } } + } else { + pure3D = false; } if (pure3D && draw_->GetDeviceCaps().texture3DSupported) { @@ -2777,11 +2784,13 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt // Always load base level texture here plan.baseLevelSrc = 0; - if (IsFakeMipmapChange()) { + if (isFakeMipmapChange) { // NOTE: Since the level is not part of the cache key, we assume it never changes. plan.baseLevelSrc = std::max(0, gstate.getTexLevelOffset16() / 16); plan.levelsToCreate = 1; plan.levelsToLoad = 1; + // Make sure we already decided not to do a 3D texture above. + _dbg_assert_(plan.depth == 1); } if (plan.isVideo || plan.depth != 1 || plan.decodeToClut8) { From cdb830f3904954ba579ee14dc10662b3e8dd16f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 10 Dec 2022 12:05:40 +0100 Subject: [PATCH 650/715] Minor optimization/cleanup --- Common/Data/Encoding/Utf8.cpp | 21 ++++++++------------- Common/GPU/Vulkan/VulkanImage.h | 2 -- Common/GPU/Vulkan/thin3d_vulkan.cpp | 4 ---- Common/Render/DrawBuffer.cpp | 4 +++- GPU/Vulkan/TextureCacheVulkan.cpp | 2 -- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Common/Data/Encoding/Utf8.cpp b/Common/Data/Encoding/Utf8.cpp index d3ddbdbc21..d30a9432a8 100644 --- a/Common/Data/Encoding/Utf8.cpp +++ b/Common/Data/Encoding/Utf8.cpp @@ -219,19 +219,14 @@ int u8_strlen(const char *s) } /* reads the next utf-8 sequence out of a string, updating an index */ -uint32_t u8_nextchar(const char *s, int *i) -{ - uint32_t ch = 0; - int sz = 0; - - do { - ch <<= 6; - ch += (unsigned char)s[(*i)++]; - sz++; - } while (s[*i] && !isutf(s[*i])); - ch -= offsetsFromUTF8[sz-1]; - - return ch; +uint32_t u8_nextchar(const char *s, int *i) { + uint32_t ch = 0; + int sz = 0; + do { + ch = (ch << 6) + (unsigned char)s[(*i)++]; + sz++; + } while (s[*i] && ((s[*i]) & 0xC0) == 0x80); + return ch - offsetsFromUTF8[sz - 1]; } uint32_t u8_nextchar_unsafe(const char *s, int *i) { diff --git a/Common/GPU/Vulkan/VulkanImage.h b/Common/GPU/Vulkan/VulkanImage.h index e4835059ed..c088fdca5b 100644 --- a/Common/GPU/Vulkan/VulkanImage.h +++ b/Common/GPU/Vulkan/VulkanImage.h @@ -38,8 +38,6 @@ public: return tag_; } - void Touch() {} - // Used in image copies, etc. VkImage GetImage() const { return image_; } diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 08aed9a332..9cfcbea7c9 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -348,7 +348,6 @@ public: VkImageView GetImageView() { if (vkTex_) { - vkTex_->Touch(); return vkTex_->GetImageView(); } return VK_NULL_HANDLE; // This would be bad. @@ -356,7 +355,6 @@ public: VkImageView GetImageArrayView() { if (vkTex_) { - vkTex_->Touch(); return vkTex_->GetImageArrayView(); } return VK_NULL_HANDLE; // This would be bad. @@ -673,8 +671,6 @@ VulkanTexture *VKContext::GetNullTexture() { } nullTexture_->UploadMip(cmdInit, 0, w, h, 0, bindBuf, bindOffset, w); nullTexture_->EndCreate(cmdInit, false, VK_PIPELINE_STAGE_TRANSFER_BIT); - } else { - nullTexture_->Touch(); } return nullTexture_; } diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 9b09e7675b..e3efb6b5d0 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -285,7 +285,9 @@ void DrawBuffer::DrawImageRotated(ImageID atlas_image, float x, float y, float s {u1, image->v2}, }; for (int i = 0; i < 6; i++) { - rot(v[i], angle, x, y); + if (angle != 0.0f) { + rot(v[i], angle, x, y); + } V(v[i][0], v[i][1], 0, color, uv[i][0], uv[i][1]); } } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index f060b47c54..a39d7e71b0 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -404,8 +404,6 @@ void TextureCacheVulkan::BindTexture(TexCacheEntry *entry) { return; } - entry->vkTex->Touch(); - int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel; SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry); curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey); From 3e9f62a3a455843e9a11992944c0a3df7e3b436b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 10 Dec 2022 12:28:16 +0100 Subject: [PATCH 651/715] Minor fixes --- GPU/Common/FramebufferManagerCommon.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index ea199d8d51..685b70c851 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2862,6 +2862,8 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); shaderManager_->DirtyLastShader(); + // Needed for D3D11 to run validation clean. I don't think it's actually an issue. + // textureCache_->ForgetLastTexture(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); } else { From 6885e76d783742736f3953cbbe2bc403e76547c3 Mon Sep 17 00:00:00 2001 From: leoxxx <5364709+leoxxx@users.noreply.github.com> Date: Sat, 10 Dec 2022 23:31:22 +0800 Subject: [PATCH 652/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 5e17fd9341..45e1e41b67 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -178,7 +178,7 @@ Open Chat = 打开聊天 Open Directory... = 打开路径(&D)... Open from MS:/PSP/GAME... = 从MS:/PSP/GAME处打开 (&p)... Open Memory Stick = 打开记忆棒 (&M) -Open New Instance = 打开新的模拟器进程 +Open New Instance = 打开新的实例 OpenGL = &OpenGL Pause = 暂停 (&P) Pause When Not Focused = 后台运行时自动暂停 (&P) @@ -750,7 +750,7 @@ Bottom Right = 右下方 Center Left = 左中间 Center Right = 右中间 Change Mac Address = 更改MAC地址 -Change proAdhocServer Address = 更改PRO Ad Hoc服务器IP地址(localhost=模拟器双开) +Change proAdhocServer Address = 更改PRO Ad Hoc服务器IP地址(localhost=多个实例) ChangeMacSaveConfirm = 生成新的MAC地址? ChangeMacSaveWarning = 一些游戏会在载入存档数据时验证MAC地址,这可能会破坏旧的存档。 Chat = 聊天 From a800938604bf241b9ebcc72ee2bef9c2e08a1867 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 10:39:56 -0800 Subject: [PATCH 653/715] Common: Fix worker thread names. --- Common/Thread/ThreadManager.cpp | 9 +++++++-- Common/Thread/ThreadManager.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Common/Thread/ThreadManager.cpp b/Common/Thread/ThreadManager.cpp index 4f60b5b764..0414ee5e79 100644 --- a/Common/Thread/ThreadManager.cpp +++ b/Common/Thread/ThreadManager.cpp @@ -125,7 +125,12 @@ bool ThreadManager::TeardownTask(Task *task, bool enqueue) { static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread) { char threadName[16]; - snprintf(threadName, sizeof(threadName), "PoolWorker %d", thread->index); + if (thread->type == TaskType::CPU_COMPUTE) { + snprintf(threadName, sizeof(threadName), "PoolWorker %d", thread->index); + } else { + _assert_(thread->type == TaskType::IO_BLOCKING); + snprintf(threadName, sizeof(threadName), "PoolWorkerIO %d", thread->index); + } SetCurrentThreadName(threadName); const bool isCompute = thread->type == TaskType::CPU_COMPUTE; @@ -199,8 +204,8 @@ void ThreadManager::Init(int numRealCores, int numLogicalCoresPerCpu) { thread->cancelled.store(false); thread->private_single.store(nullptr); thread->type = i < numComputeThreads_ ? TaskType::CPU_COMPUTE : TaskType::IO_BLOCKING; - thread->thread = std::thread(&WorkerThreadFunc, global_, thread); thread->index = i; + thread->thread = std::thread(&WorkerThreadFunc, global_, thread); global_->threads_.push_back(thread); } } diff --git a/Common/Thread/ThreadManager.h b/Common/Thread/ThreadManager.h index 5147ad21cc..bd71d8c775 100644 --- a/Common/Thread/ThreadManager.h +++ b/Common/Thread/ThreadManager.h @@ -4,7 +4,7 @@ // The new threadpool. -// To help future smart scheduling. +// To help smart scheduling. enum class TaskType { CPU_COMPUTE, IO_BLOCKING, From dcfd82da05cf79060419106a211ab076f05811e1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 10:40:52 -0800 Subject: [PATCH 654/715] GE Debugger: Fix src/dst stride formatting. --- GPU/GeDisasm.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index a645b5bc2b..af8131958b 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -525,9 +525,10 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { case GE_CMD_TRANSFERSRCW: { u32 xferSrc = (gstate.transfersrc & 0x00FFFFFF) | ((data & 0xFF0000) << 8); - u32 xferSrcW = data & 0x3FF; - if (data & ~0xFF03FF) - snprintf(buffer, bufsize, "Block transfer src: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferSrcW, xferSrc, data & ~0xFF03FF); + u32 xferSrcW = (data & 0x400) != 0 ? 0x400 : (data & 0x3FF); + u32 validMask = (data & 0x400) != 0 ? 0xFF0400 : 0xFF03FF; + if (data & ~validMask) + snprintf(buffer, bufsize, "Block transfer src: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferSrcW, xferSrc, data & ~validMask); else snprintf(buffer, bufsize, "Block transfer src: high=%02x, w=%d (addr %08x)", data >> 16, xferSrcW, xferSrc); break; @@ -546,9 +547,10 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { case GE_CMD_TRANSFERDSTW: { u32 xferDst = (gstate.transferdst & 0x00FFFFFF) | ((data & 0xFF0000) << 8); - u32 xferDstW = data & 0x3FF; - if (data & ~0xFF03FF) - snprintf(buffer, bufsize, "Block transfer dst: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferDstW, xferDst, data & ~0xFF03FF); + u32 xferDstW = (data & 0x400) != 0 ? 0x400 : (data & 0x3FF); + u32 validMask = (data & 0x400) != 0 ? 0xFF0400 : 0xFF03FF; + if (data & ~validMask) + snprintf(buffer, bufsize, "Block transfer dst: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferDstW, xferDst, data & ~validMask); else snprintf(buffer, bufsize, "Block transfer dst: high=%02x, w=%d (addr %08x)", data >> 16, xferDstW, xferDst); break; From 3cc979859c57d95986c8f6b84ff223eea0d72c02 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 10 Dec 2022 21:31:39 +0100 Subject: [PATCH 655/715] OpenXR - Release keys on activation of camera adjust --- Common/VR/PPSSPPVR.cpp | 30 ++++++++++++++++++++++++++++-- Common/VR/PPSSPPVR.h | 4 ++-- android/jni/app-android.cpp | 3 ++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 98e2ee7ec0..a6a7d0c0e3 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -46,6 +46,10 @@ static bool vrFlatGame = false; static float vrMatrix[VR_MATRIX_COUNT][16]; static bool vrMirroring[VR_MIRRORING_COUNT]; +static bool(*NativeAxis)(const AxisInput &axis); +static bool(*NativeKey)(const KeyInput &key); +static bool(*NativeTouch)(const TouchInput &touch); + /* ================================================================================ @@ -185,6 +189,12 @@ void GetVRResolutionPerEye(int* width, int* height) { } } +void SetVRCallbacks(bool(*axis)(const AxisInput &axis), bool(*key)(const KeyInput &key), bool(*touch)(const TouchInput &touch)) { + NativeAxis = axis; + NativeKey = key; + NativeTouch = touch; +} + /* ================================================================================ @@ -197,8 +207,7 @@ void SetVRAppMode(VRAppMode mode) { appMode = mode; } -void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(const KeyInput &key), - bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) { +void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) { //axis if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { AxisInput axis = {}; @@ -405,6 +414,7 @@ bool UpdateVRAxis(const AxisInput &axis) { bool UpdateVRKeys(const KeyInput &key) { //store key value std::vector nativeKeys; + bool wasCameraAdjustOn = pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { pspKeys[nativeKey] = key.flags & KEY_DOWN; @@ -425,6 +435,22 @@ bool UpdateVRKeys(const KeyInput &key) { } } + // Release keys on enabling camera adjust + if (!wasCameraAdjustOn && pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { + KeyInput keyUp; + keyUp.deviceId = key.deviceId; + keyUp.flags = KEY_UP; + + pspKeys[VIRTKEY_VR_CAMERA_ADJUST] = false; + for (auto& pspKey : pspKeys) { + if (pspKey.second) { + keyUp.keyCode = pspKey.first; + NativeKey(keyUp); + } + } + pspKeys[VIRTKEY_VR_CAMERA_ADJUST] = true; + } + // Reset camera adjust if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST] && pspKeys[VIRTKEY_VR_CAMERA_RESET]) { g_Config.fCameraHeight = 0; diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index dec2daaffa..009726a948 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -29,11 +29,11 @@ bool IsVREnabled(); void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name); void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); +void SetVRCallbacks(bool(*axis)(const AxisInput &axis), bool(*key)(const KeyInput &key), bool(*touch)(const TouchInput &touch)); // VR input integration void SetVRAppMode(VRAppMode mode); -void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(const KeyInput &key), - bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); +void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale); bool UpdateVRAxis(const AxisInput &axis); bool UpdateVRKeys(const KeyInput &key); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index b144bc8dcd..ee0cf4c198 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -770,6 +770,7 @@ retry: if (IsVREnabled()) { Version gitVer(PPSSPP_GIT_VERSION); InitVROnAndroid(gJvm, nativeActivity, systemName.c_str(), gitVer.ToInteger(), "PPSSPP"); + SetVRCallbacks(NativeAxis, NativeKey, NativeTouch); } } @@ -1079,7 +1080,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, } if (IsVREnabled()) { - UpdateVRInput(NativeAxis, NativeKey, NativeTouch, g_Config.bHapticFeedback, dp_xscale, dp_yscale); + UpdateVRInput(g_Config.bHapticFeedback, dp_xscale, dp_yscale); FinishVRRender(); } } From 28c115c4bafaa33d4686c92af6668f64768650d4 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 10 Dec 2022 21:36:39 +0100 Subject: [PATCH 656/715] OpenXR - Allow to put HUD out of the screen --- Common/VR/PPSSPPVR.cpp | 2 +- UI/GameSettingsScreen.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index a6a7d0c0e3..46dca63f4b 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -327,7 +327,7 @@ void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) { case JOYSTICK_AXIS_Z: if (axis.second < -0.75f) g_Config.fHeadUpDisplayScale -= 0.01f; if (axis.second > 0.75f) g_Config.fHeadUpDisplayScale += 0.01f; - g_Config.fHeadUpDisplayScale = clampFloat(g_Config.fHeadUpDisplayScale, 0.2f, 1.0f); + g_Config.fHeadUpDisplayScale = clampFloat(g_Config.fHeadUpDisplayScale, 0.2f, 1.5f); break; case JOYSTICK_AXIS_RZ: if (axis.second > 0.75f) g_Config.fCameraDistance -= 0.1f; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 3e2a3229a2..9ca9ce1282 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1091,7 +1091,7 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadUpDisplayScale, 0.2f, 1.0f, vr->T("Heads-up display scale"), 0.1f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadUpDisplayScale, 0.2f, 1.5f, vr->T("Heads-up display scale"), 0.1f, screenManager(), "")); vrSettings->Add(new ItemHeader(vr->T("VR controllers"))); vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); From c2d6e05dd1524270257a398a8417d3501f3aa013 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 10 Dec 2022 21:57:02 +0100 Subject: [PATCH 657/715] OpenXR - Default UI saturation adjusted --- Core/Config.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 31ed1956d8..864568f2ef 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -516,6 +516,19 @@ static bool DefaultEnableStateUndo() { return true; } +static float DefaultUISaturation() { + std::string device = System_GetProperty(SYSPROP_NAME); + if (IsVREnabled() && startsWith(device, "Pico")) { + return 1.5f; + } else if (IsVREnabled() && startsWith(device, "Oculus")) { + return 1.25f; + } else if (IsVREnabled() && startsWith(device, "Meta")) { + return 1.25f; + } else { + return 1.0f; + } +} + struct ConfigSectionSettings { const char *section; ConfigSetting *settings; @@ -597,7 +610,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("BackgroundAnimation", &g_Config.iBackgroundAnimation, 1, true, false), ConfigSetting("UITint", &g_Config.fUITint, 0.0, true, false), - ConfigSetting("UISaturation", &g_Config.fUISaturation, 1.0, true, false), + ConfigSetting("UISaturation", &g_Config.fUISaturation, &DefaultUISaturation, true, false), #if defined(USING_WIN_UI) ConfigSetting("TopMost", &g_Config.bTopMost, false), From d2615fb7c64d0ab64b97d50dfe4ce9ba9bf34862 Mon Sep 17 00:00:00 2001 From: leoxxx <5364709+leoxxx@users.noreply.github.com> Date: Sun, 11 Dec 2022 09:52:11 +0800 Subject: [PATCH 658/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 45e1e41b67..63f8e5d692 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -246,7 +246,7 @@ JIT debug tools = JIT调试工具 Log Dropped Frame Statistics = 记录丢弃帧统计信息 Log Level = 日志等级 Log View = 日志视图 -Logging Channels = 日志源 +Logging Channels = 日志通道 Next = 下一个 No block = 没有内存块 Prev = 之前 @@ -279,7 +279,7 @@ Cancel = 取消 Center = 中心 ChangingGPUBackends = 更改引擎模式后需要重启PPSSPP。立刻重启? ChangingInflightFrames = 更改缓冲图形命令后需要重启PPSSPP。立刻重启? -Channel: = 频道: +Channel: = 信道: Choose PPSSPP save folder = 选择PPSSPP存档的文件夹 Confirm Overwrite = 您要覆盖这个存档吗? Confirm Save = 您要保存到这个存档吗? @@ -804,7 +804,7 @@ UPnP (port-forwarding) = UPnP(端口转发) UPnP need to be reinitialized = UPnP 需要重新初始化 UPnP use original port = UPnP 使用原始端口(启用=兼容PSP) Validating address... = 正在验证地址... -WLAN Channel = WLAN 频道 +WLAN Channel = WLAN信道 You're in Offline Mode, go to lobby or online hall = 您现在是离线模式, 请进入房间或在线大厅 [Pause] From f44852bb18ddaa759b3b86ba357360bca6375a8b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 20:32:12 -0800 Subject: [PATCH 659/715] Global: Cleanup virtual/override specifiers. Also missing virtual destructors, hidden non-overrides, etc. --- Common/CodeBlock.h | 5 +- Common/ConsoleListener.h | 2 +- Common/Data/Text/WrapText.h | 1 + Common/File/VFS/AssetReader.h | 8 ++-- Common/GPU/D3D9/thin3d_d3d9.cpp | 6 +-- Common/GPU/OpenGL/thin3d_gl.cpp | 4 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 4 +- Common/GPU/thin3d.h | 5 +- Common/LogManager.h | 13 +++-- Common/Math/expression_parser.h | 1 + Common/Net/URL.h | 11 ++--- Common/UI/UI.h | 5 +- Common/UI/UIScreen.h | 34 ++++++------- Common/UI/ViewGroup.h | 48 +++++++++---------- Core/Debugger/DebugInterface.h | 2 + Core/Debugger/DisassemblyManager.h | 8 +--- Core/Debugger/WebSocket/DisasmSubscriber.cpp | 2 +- .../WebSocket/GPURecordSubscriber.cpp | 2 +- .../Debugger/WebSocket/GPUStatsSubscriber.cpp | 2 +- .../WebSocket/MemoryInfoSubscriber.cpp | 2 +- .../Debugger/WebSocket/SteppingSubscriber.cpp | 2 +- Core/Dialog/PSPGamedataInstallDialog.h | 10 ++-- Core/Dialog/PSPMsgDialog.h | 14 +++--- Core/Dialog/PSPNetconfDialog.h | 12 ++--- Core/Dialog/PSPNpSigninDialog.h | 12 ++--- Core/Dialog/PSPOskDialog.h | 14 +++--- Core/Dialog/PSPPlaceholderDialog.h | 6 +-- Core/Dialog/PSPSaveDialog.h | 14 +++--- Core/Dialog/PSPScreenshotDialog.h | 12 ++--- Core/FileLoaders/CachingFileLoader.h | 2 +- Core/FileLoaders/DiskCachingFileLoader.h | 2 +- Core/FileLoaders/HTTPFileLoader.h | 16 +++---- Core/FileLoaders/LocalFileLoader.h | 12 ++--- Core/FileLoaders/RamCachingFileLoader.h | 2 +- Core/FileSystems/FileSystem.h | 22 ++++----- Core/Loaders.h | 2 +- Core/MIPS/IR/IRJit.h | 2 +- Core/MIPS/x86/IRToX86.h | 2 +- Core/MIPS/x86/Jit.h | 2 +- Core/Screenshot.cpp | 2 +- Core/ThreadEventQueue.h | 2 + GPU/Common/GPUDebugInterface.h | 1 + GPU/Common/SplineCommon.h | 6 +-- GPU/D3D11/DrawEngineD3D11.h | 2 +- GPU/D3D11/GPU_D3D11.h | 3 -- GPU/Directx9/DrawEngineDX9.h | 2 +- GPU/Directx9/GPU_DX9.h | 3 -- GPU/GLES/DrawEngineGLES.cpp | 4 -- GPU/GLES/DrawEngineGLES.h | 4 +- GPU/GLES/GPU_GLES.h | 3 -- GPU/GPUCommon.h | 2 +- GPU/Vulkan/DrawEngineVulkan.h | 2 +- GPU/Vulkan/GPU_Vulkan.h | 3 -- GPU/Vulkan/TextureCacheVulkan.cpp | 4 +- GPU/Vulkan/TextureCacheVulkan.h | 2 +- Qt/QtHost.h | 26 +++++----- UI/DisplayLayoutScreen.cpp | 2 +- UI/GameInfoCache.cpp | 2 +- UI/InstallZipScreen.h | 6 +-- UI/MainScreen.cpp | 9 +--- UI/MainScreen.h | 1 - UI/MiscScreens.cpp | 9 +--- UI/MiscScreens.h | 4 +- UI/PauseScreen.h | 2 +- UI/RemoteISOScreen.h | 2 +- UI/ReportScreen.cpp | 16 +++---- UI/TouchControlLayoutScreen.h | 16 +++---- Windows/CaptureDevice.h | 14 +++--- Windows/DSoundStream.h | 2 +- Windows/Debugger/Debugger_Lists.h | 41 ++++++++-------- Windows/Debugger/Debugger_MemoryDlg.h | 6 +-- Windows/Debugger/Debugger_VFPUDlg.h | 4 +- Windows/DinputDevice.h | 2 +- Windows/GEDebugger/GEDebugger.h | 4 +- Windows/GEDebugger/TabDisplayLists.h | 28 ++++++----- Windows/GEDebugger/TabState.h | 2 +- Windows/GEDebugger/TabVertices.h | 14 +++--- Windows/WASAPIStream.cpp | 2 +- Windows/WASAPIStream.h | 2 +- Windows/XinputDevice.h | 2 +- headless/Compare.cpp | 4 +- headless/Headless.cpp | 2 +- unittest/TestThreadManager.cpp | 4 +- 83 files changed, 283 insertions(+), 315 deletions(-) diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index e76bbf40ce..0307cf9df6 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -57,7 +57,10 @@ private: public: CodeBlock() {} - virtual ~CodeBlock() { if (region) FreeCodeSpace(); } + ~CodeBlock() { + if (region) + FreeCodeSpace(); + } // Call this before you generate any code. void AllocCodeSpace(int size) { diff --git a/Common/ConsoleListener.h b/Common/ConsoleListener.h index 976e7531cd..32a32b7981 100644 --- a/Common/ConsoleListener.h +++ b/Common/ConsoleListener.h @@ -41,7 +41,7 @@ public: #if defined(USING_WIN_UI) COORD GetCoordinates(int BytesRead, int BufferWidth); #endif - void Log(const LogMessage &message); + void Log(const LogMessage &message) override; void ClearScreen(bool Cursor = true); void Show(bool bShow); diff --git a/Common/Data/Text/WrapText.h b/Common/Data/Text/WrapText.h index bcdd19a6fd..d51f860362 100644 --- a/Common/Data/Text/WrapText.h +++ b/Common/Data/Text/WrapText.h @@ -7,6 +7,7 @@ public: WordWrapper(const char *str, float maxW, int flags) : str_(str), maxW_(maxW), flags_(flags) { } + virtual ~WordWrapper() {} std::string Wrapped(); diff --git a/Common/File/VFS/AssetReader.h b/Common/File/VFS/AssetReader.h index df0c4f2821..36ccd60161 100644 --- a/Common/File/VFS/AssetReader.h +++ b/Common/File/VFS/AssetReader.h @@ -47,10 +47,10 @@ class DirectoryAssetReader : public AssetReader { public: explicit DirectoryAssetReader(const Path &path); // use delete[] - virtual uint8_t *ReadAsset(const char *path, size_t *size); - virtual bool GetFileListing(const char *path, std::vector *listing, const char *filter); - virtual bool GetFileInfo(const char *path, File::FileInfo *info); - virtual std::string toString() const { + uint8_t *ReadAsset(const char *path, size_t *size) override; + bool GetFileListing(const char *path, std::vector *listing, const char *filter) override; + bool GetFileInfo(const char *path, File::FileInfo *info) override; + std::string toString() const override { return path_.ToString(); } diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index e50eb3b1c8..94bce31760 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -291,7 +291,7 @@ public: D3D9Texture(LPDIRECT3DDEVICE9 device, LPDIRECT3DDEVICE9EX deviceEx, const TextureDesc &desc); ~D3D9Texture(); void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler); - LPDIRECT3DBASETEXTURE9 Texture() const { + LPDIRECT3DBASETEXTURE9 TexturePtr() const { // TODO: Cleanup if (tex_) { return tex_; @@ -590,7 +590,7 @@ public: case NativeObject::DEVICE_EX: return (uint64_t)(uintptr_t)deviceEx_; case NativeObject::TEXTURE_VIEW: - return (uint64_t)(((D3D9Texture *)srcObject)->Texture()); + return (uint64_t)(((D3D9Texture *)srcObject)->TexturePtr()); default: return 0; } @@ -1007,7 +1007,7 @@ public: device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL); } } - virtual ~D3D9Buffer() override { + ~D3D9Buffer() { if (ibuffer_) { ibuffer_->Release(); } diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 2536d2beea..6ea0ddc1dd 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -324,7 +324,7 @@ class OpenGLTexture; class OpenGLContext : public DrawContext { public: OpenGLContext(); - virtual ~OpenGLContext(); + ~OpenGLContext(); void SetTargetSize(int w, int h) override { DrawContext::SetTargetSize(w, h); @@ -1084,7 +1084,7 @@ public: buffer_ = render->CreateBuffer(target_, size, usage_); totalSize_ = size; } - ~OpenGLBuffer() override { + ~OpenGLBuffer() { render_->DeleteBuffer(buffer_); } diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 9cfcbea7c9..bb57abdea4 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -382,7 +382,7 @@ class VKFramebuffer; class VKContext : public DrawContext { public: VKContext(VulkanContext *vulkan); - virtual ~VKContext(); + ~VKContext(); void DebugAnnotate(const char *annotation) override; @@ -1362,7 +1362,7 @@ public: VKBuffer(size_t size, uint32_t flags) : dataSize_(size) { data_ = new uint8_t[size]; } - ~VKBuffer() override { + ~VKBuffer() { delete[] data_; } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 78ae3375b8..76afa314be 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -483,10 +483,7 @@ public: virtual ShaderStage GetStage() const = 0; }; -class Pipeline : public RefCountedObject { -public: - virtual ~Pipeline() {} -}; +class Pipeline : public RefCountedObject { }; class RasterState : public RefCountedObject {}; diff --git a/Common/LogManager.h b/Common/LogManager.h index 65423b6121..5d8afddae5 100644 --- a/Common/LogManager.h +++ b/Common/LogManager.h @@ -55,7 +55,7 @@ public: FileLogListener(const char *filename); ~FileLogListener(); - void Log(const LogMessage &msg); + void Log(const LogMessage &msg) override; bool IsValid() { if (!fp_) return false; else return true; } bool IsEnabled() const { return m_enable; } @@ -71,13 +71,12 @@ private: class OutputDebugStringLogListener : public LogListener { public: - void Log(const LogMessage &msg); + void Log(const LogMessage &msg) override; }; class RingbufferLogListener : public LogListener { public: - RingbufferLogListener() : curMessage_(0), count_(0), enabled_(false) {} - void Log(const LogMessage &msg); + void Log(const LogMessage &msg) override; bool IsEnabled() const { return enabled_; } void SetEnabled(bool enable) { enabled_ = enable; } @@ -89,9 +88,9 @@ public: private: enum { MAX_LOGS = 128 }; LogMessage messages_[MAX_LOGS]; - int curMessage_; - int count_; - bool enabled_; + int curMessage_ = 0; + int count_ = 0; + bool enabled_ = false; }; // TODO: A simple buffered log that can be used to display the log in-window diff --git a/Common/Math/expression_parser.h b/Common/Math/expression_parser.h index 3d39340a42..55de0a234a 100644 --- a/Common/Math/expression_parser.h +++ b/Common/Math/expression_parser.h @@ -15,6 +15,7 @@ enum ExpressionType class IExpressionFunctions { public: + virtual ~IExpressionFunctions() {} virtual bool parseReference(char* str, uint32_t& referenceIndex) = 0; virtual bool parseSymbol(char* str, uint32_t& symbolValue) = 0; virtual uint32_t getReferenceValue(uint32_t referenceIndex) = 0; diff --git a/Common/Net/URL.h b/Common/Net/URL.h index 7fcaa0c455..e7f33e6d8a 100644 --- a/Common/Net/URL.h +++ b/Common/Net/URL.h @@ -15,6 +15,8 @@ struct UrlEncoder { + virtual ~UrlEncoder() {} + UrlEncoder() : paramCount(0) { data.reserve(256); @@ -129,8 +131,7 @@ struct MultipartFormDataEncoder : UrlEncoder boundary = temp; } - virtual void Add(const std::string &key, const std::string &value) - { + void Add(const std::string &key, const std::string &value) override { Add(key, value, "", ""); } @@ -158,13 +159,11 @@ struct MultipartFormDataEncoder : UrlEncoder Add(key, std::string((const char *)&value[0], value.size()), filename, mimeType); } - virtual void Finish() - { + void Finish() override { data += "--" + boundary + "--"; } - virtual std::string GetMimeType() const - { + std::string GetMimeType() const override { return "multipart/form-data; boundary=\"" + boundary + "\""; } diff --git a/Common/UI/UI.h b/Common/UI/UI.h index ccd6b50dbe..4357693d16 100644 --- a/Common/UI/UI.h +++ b/Common/UI/UI.h @@ -43,6 +43,7 @@ extern DrawBuffer ui_draw2d_front; // for things that need to be on top of the r // Implement this interface to style your lists class UIListAdapter { public: + virtual ~UIListAdapter() {} virtual size_t getCount() const = 0; virtual void drawItem(int item, int x, int y, int w, int h, bool active) const = 0; virtual float itemHeight(int itemIndex) const { return 64; } @@ -52,8 +53,8 @@ public: class StringVectorListAdapter : public UIListAdapter { public: StringVectorListAdapter(const std::vector *items) : items_(items) {} - virtual size_t getCount() const { return items_->size(); } - virtual void drawItem(int item, int x, int y, int w, int h, bool active) const; + size_t getCount() const override { return items_->size(); } + void drawItem(int item, int x, int y, int w, int h, bool active) const override; private: const std::vector *items_; diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 03a8f8a18a..50a5f1f2d9 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -74,12 +74,12 @@ public: PopupScreen(std::string title, std::string button1 = "", std::string button2 = ""); virtual void CreatePopupContents(UI::ViewGroup *parent) = 0; - virtual void CreateViews() override; - virtual bool isTransparent() const override { return true; } - virtual bool touch(const TouchInput &touch) override; - virtual bool key(const KeyInput &key) override; + void CreateViews() override; + bool isTransparent() const override { return true; } + bool touch(const TouchInput &touch) override; + bool key(const KeyInput &key) override; - virtual void TriggerFinish(DialogResult result) override; + void TriggerFinish(DialogResult result) override; void SetPopupOrigin(const UI::View *view); void SetPopupOffset(float y); @@ -95,7 +95,7 @@ protected: virtual bool HasTitleBar() const { return true; } const std::string &Title() { return title_; } - virtual void update() override; + void update() override; private: UI::ViewGroup *box_; @@ -143,9 +143,9 @@ public: UI::Event OnChoice; protected: - virtual bool FillVertical() const override { return false; } - virtual bool ShowButtons() const override { return showButtons_; } - virtual void CreatePopupContents(UI::ViewGroup *parent) override; + bool FillVertical() const override { return false; } + bool ShowButtons() const override { return showButtons_; } + void CreatePopupContents(UI::ViewGroup *parent) override; UI::StringVectorListAdaptor adaptor_; UI::ListView *listView_ = nullptr; @@ -164,9 +164,9 @@ public: UI::Event OnChoice; protected: - virtual bool FillVertical() const override { return false; } - virtual bool ShowButtons() const override { return true; } - virtual void CreatePopupContents(UI::ViewGroup *parent) override; + bool FillVertical() const override { return false; } + bool ShowButtons() const override { return true; } + void CreatePopupContents(UI::ViewGroup *parent) override; private: void OnCompleted(DialogResult result) override; @@ -182,7 +182,7 @@ class SliderPopupScreen : public PopupScreen { public: SliderPopupScreen(int *value, int minValue, int maxValue, const std::string &title, int step = 1, const std::string &units = "") : PopupScreen(title, "OK", "Cancel"), units_(units), value_(value), minValue_(minValue), maxValue_(maxValue), step_(step) {} - virtual void CreatePopupContents(ViewGroup *parent) override; + void CreatePopupContents(ViewGroup *parent) override; void SetNegativeDisable(const std::string &str) { negativeLabel_ = str; @@ -198,7 +198,7 @@ private: EventReturn OnIncrease(EventParams ¶ms); EventReturn OnTextChange(EventParams ¶ms); EventReturn OnSliderChange(EventParams ¶ms); - virtual void OnCompleted(DialogResult result) override; + void OnCompleted(DialogResult result) override; Slider *slider_ = nullptr; UI::TextEdit *edit_ = nullptr; std::string units_; @@ -227,7 +227,7 @@ private: EventReturn OnDecrease(EventParams ¶ms); EventReturn OnTextChange(EventParams ¶ms); EventReturn OnSliderChange(EventParams ¶ms); - virtual void OnCompleted(DialogResult result) override; + void OnCompleted(DialogResult result) override; UI::SliderFloat *slider_; UI::TextEdit *edit_; std::string units_; @@ -245,7 +245,7 @@ class TextEditPopupScreen : public PopupScreen { public: TextEditPopupScreen(std::string *value, const std::string &placeholder, const std::string &title, int maxLen) : PopupScreen(title, "OK", "Cancel"), value_(value), placeholder_(placeholder), maxLen_(maxLen) {} - virtual void CreatePopupContents(ViewGroup *parent) override; + void CreatePopupContents(ViewGroup *parent) override; const char *tag() const override { return "TextEditPopup"; } @@ -378,7 +378,7 @@ public: } protected: - void PostChoiceCallback(int num) { + void PostChoiceCallback(int num) override { *valueStr_ = choices_[num]; } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index d408548b69..32ddb8eb56 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -24,27 +24,23 @@ struct NeighborResult { class ViewGroup : public View { public: ViewGroup(LayoutParams *layoutParams = 0) : View(layoutParams) {} - virtual ~ViewGroup(); + ~ViewGroup(); // Pass through external events to children. - virtual bool Key(const KeyInput &input) override; - virtual bool Touch(const TouchInput &input) override; - virtual void Axis(const AxisInput &input) override; + bool Key(const KeyInput &input) override; + bool Touch(const TouchInput &input) override; + void Axis(const AxisInput &input) override; // By default, a container will layout to its own bounds. - virtual void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override = 0; - virtual void Layout() override = 0; - virtual void Update() override; - virtual void Query(float x, float y, std::vector &list) override; + void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override = 0; + void Layout() override = 0; + void Update() override; + void Query(float x, float y, std::vector &list) override; - virtual void DeviceLost() override; - virtual void DeviceRestored(Draw::DrawContext *draw) override; + void DeviceLost() override; + void DeviceRestored(Draw::DrawContext *draw) override; - virtual void Draw(UIContext &dc) override; - - // These should be unused. - virtual float GetContentWidth() const { return 0.0f; } - virtual float GetContentHeight() const { return 0.0f; } + void Draw(UIContext &dc) override; // Takes ownership! DO NOT add a view to multiple parents! template @@ -54,8 +50,8 @@ public: return view; } - virtual bool SetFocus() override; - virtual bool SubviewFocused(View *view) override; + bool SetFocus() override; + bool SubviewFocused(View *view) override; virtual void RemoveSubview(View *view); void SetDefaultFocusView(View *view) { defaultFocusView_ = view; } @@ -406,9 +402,9 @@ public: class ChoiceListAdaptor : public ListAdaptor { public: ChoiceListAdaptor(const char *items[], int numItems) : items_(items), numItems_(numItems) {} - virtual View *CreateItemView(int index); - virtual int GetNumItems() { return numItems_; } - virtual bool AddEventCallback(View *view, std::function callback); + View *CreateItemView(int index) override; + int GetNumItems() override { return numItems_; } + bool AddEventCallback(View *view, std::function callback) override; private: const char **items_; @@ -421,12 +417,12 @@ class StringVectorListAdaptor : public ListAdaptor { public: StringVectorListAdaptor() : selected_(-1) {} StringVectorListAdaptor(const std::vector &items, int selected = -1) : items_(items), selected_(selected) {} - virtual View *CreateItemView(int index) override; - virtual int GetNumItems() override { return (int)items_.size(); } - virtual bool AddEventCallback(View *view, std::function callback) override; + View *CreateItemView(int index) override; + int GetNumItems() override { return (int)items_.size(); } + bool AddEventCallback(View *view, std::function callback) override; void SetSelected(int sel) override { selected_ = sel; } - virtual std::string GetTitle(int index) const override { return items_[index]; } - virtual int GetSelected() override { return selected_; } + std::string GetTitle(int index) const override { return items_[index]; } + int GetSelected() override { return selected_; } private: std::vector items_; @@ -440,7 +436,7 @@ public: ListView(ListAdaptor *a, std::set hidden = std::set(), LayoutParams *layoutParams = 0); int GetSelected() { return adaptor_->GetSelected(); } - virtual void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; + void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; virtual void SetMaxHeight(float mh) { maxHeight_ = mh; } Event OnChoice; std::string DescribeLog() const override { return "ListView: " + View::DescribeLog(); } diff --git a/Core/Debugger/DebugInterface.h b/Core/Debugger/DebugInterface.h index 6f48c7db0f..a92c8bab26 100644 --- a/Core/Debugger/DebugInterface.h +++ b/Core/Debugger/DebugInterface.h @@ -31,6 +31,8 @@ enum { class DebugInterface { public: + virtual ~DebugInterface() {} + virtual const char *disasm(unsigned int address, unsigned int align) {return "NODEBUGGER";} virtual int getInstructionSize(int instruction) {return 1;} diff --git a/Core/Debugger/DisassemblyManager.h b/Core/Debugger/DisassemblyManager.h index 00ff46c6fc..81520818b1 100644 --- a/Core/Debugger/DisassemblyManager.h +++ b/Core/Debugger/DisassemblyManager.h @@ -99,8 +99,7 @@ private: class DisassemblyOpcode: public DisassemblyEntry { public: - DisassemblyOpcode(u32 _address, int _num): address(_address), num(_num) { }; - virtual ~DisassemblyOpcode() { }; + DisassemblyOpcode(u32 _address, int _num): address(_address), num(_num) { } void recheck() override { }; int getNumLines() override { return num; }; int getLineNum(u32 address, bool findStart) override { return (address - this->address) / 4; }; @@ -118,8 +117,7 @@ private: class DisassemblyMacro: public DisassemblyEntry { public: - DisassemblyMacro(u32 _address): address(_address) { }; - virtual ~DisassemblyMacro() { }; + DisassemblyMacro(u32 _address): address(_address) { } void setMacroLi(u32 _immediate, u8 _rt); void setMacroMemory(std::string _name, u32 _immediate, u8 _rt, int _dataSize); @@ -147,7 +145,6 @@ class DisassemblyData: public DisassemblyEntry { public: DisassemblyData(u32 _address, u32 _size, DataType _type); - virtual ~DisassemblyData() { }; void recheck() override; int getNumLines() override { return (int)lines.size(); }; @@ -179,7 +176,6 @@ class DisassemblyComment: public DisassemblyEntry { public: DisassemblyComment(u32 _address, u32 _size, std::string name, std::string param); - virtual ~DisassemblyComment() { }; void recheck() override { }; int getNumLines() override { return 1; }; diff --git a/Core/Debugger/WebSocket/DisasmSubscriber.cpp b/Core/Debugger/WebSocket/DisasmSubscriber.cpp index 5d766785a2..d467a25cd8 100644 --- a/Core/Debugger/WebSocket/DisasmSubscriber.cpp +++ b/Core/Debugger/WebSocket/DisasmSubscriber.cpp @@ -36,7 +36,7 @@ public: WebSocketDisasmState() { disasm_.setCpu(currentDebugMIPS); } - ~WebSocketDisasmState() override { + ~WebSocketDisasmState() { disasm_.clear(); } diff --git a/Core/Debugger/WebSocket/GPURecordSubscriber.cpp b/Core/Debugger/WebSocket/GPURecordSubscriber.cpp index f31aa26d54..f1aad51e12 100644 --- a/Core/Debugger/WebSocket/GPURecordSubscriber.cpp +++ b/Core/Debugger/WebSocket/GPURecordSubscriber.cpp @@ -23,7 +23,7 @@ #include "GPU/Debugger/Record.h" struct WebSocketGPURecordState : public DebuggerSubscriber { - ~WebSocketGPURecordState() override; + ~WebSocketGPURecordState(); void Dump(DebuggerRequest &req); void Broadcast(net::WebSocketServer *ws) override; diff --git a/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp b/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp index 0d579b6747..1135ad98a2 100644 --- a/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp +++ b/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp @@ -68,7 +68,7 @@ struct DebuggerGPUStatsEvent { struct WebSocketGPUStatsState : public DebuggerSubscriber { WebSocketGPUStatsState(); - ~WebSocketGPUStatsState() override; + ~WebSocketGPUStatsState(); void Get(DebuggerRequest &req); void Feed(DebuggerRequest &req); diff --git a/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp b/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp index 30eb8cdd02..139b9124ec 100644 --- a/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp +++ b/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp @@ -27,7 +27,7 @@ class WebSocketMemoryInfoState : public DebuggerSubscriber { public: WebSocketMemoryInfoState() { } - ~WebSocketMemoryInfoState() override { + ~WebSocketMemoryInfoState() { UpdateOverride(false); } diff --git a/Core/Debugger/WebSocket/SteppingSubscriber.cpp b/Core/Debugger/WebSocket/SteppingSubscriber.cpp index fcb9296985..b07349a26b 100644 --- a/Core/Debugger/WebSocket/SteppingSubscriber.cpp +++ b/Core/Debugger/WebSocket/SteppingSubscriber.cpp @@ -32,7 +32,7 @@ struct WebSocketSteppingState : public DebuggerSubscriber { WebSocketSteppingState() { disasm_.setCpu(currentDebugMIPS); } - ~WebSocketSteppingState() override { + ~WebSocketSteppingState() { disasm_.clear(); } diff --git a/Core/Dialog/PSPGamedataInstallDialog.h b/Core/Dialog/PSPGamedataInstallDialog.h index a74fdb5254..47febcff9f 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.h +++ b/Core/Dialog/PSPGamedataInstallDialog.h @@ -36,12 +36,12 @@ struct SceUtilityGamedataInstallParam { class PSPGamedataInstallDialog: public PSPDialog { public: PSPGamedataInstallDialog(UtilityDialogType type); - virtual ~PSPGamedataInstallDialog(); + ~PSPGamedataInstallDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; int Abort(); std::string GetGameDataInstallFileName(SceUtilityGamedataInstallParam *param, std::string filename); diff --git a/Core/Dialog/PSPMsgDialog.h b/Core/Dialog/PSPMsgDialog.h index 78ee4e54f4..32a4831640 100644 --- a/Core/Dialog/PSPMsgDialog.h +++ b/Core/Dialog/PSPMsgDialog.h @@ -59,18 +59,18 @@ struct pspMessageDialog class PSPMsgDialog: public PSPDialog { public: PSPMsgDialog(UtilityDialogType type); - virtual ~PSPMsgDialog(); + ~PSPMsgDialog(); - virtual int Init(unsigned int paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(unsigned int paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; int Abort(); protected: - virtual bool UseAutoStatus() override { + bool UseAutoStatus() override { return false; } diff --git a/Core/Dialog/PSPNetconfDialog.h b/Core/Dialog/PSPNetconfDialog.h index 13d267f5d9..52a3ce203a 100644 --- a/Core/Dialog/PSPNetconfDialog.h +++ b/Core/Dialog/PSPNetconfDialog.h @@ -38,13 +38,13 @@ struct SceUtilityNetconfParam { class PSPNetconfDialog: public PSPDialog { public: PSPNetconfDialog(UtilityDialogType type); - virtual ~PSPNetconfDialog(); + ~PSPNetconfDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon* GetCommonParam() override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon* GetCommonParam() override; protected: bool UseAutoStatus() override { diff --git a/Core/Dialog/PSPNpSigninDialog.h b/Core/Dialog/PSPNpSigninDialog.h index 15aac7b0c9..2b31922735 100644 --- a/Core/Dialog/PSPNpSigninDialog.h +++ b/Core/Dialog/PSPNpSigninDialog.h @@ -34,13 +34,13 @@ struct SceUtilityNpSigninParam { class PSPNpSigninDialog: public PSPDialog { public: PSPNpSigninDialog(UtilityDialogType type); - virtual ~PSPNpSigninDialog(); + ~PSPNpSigninDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon* GetCommonParam() override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon* GetCommonParam() override; protected: bool UseAutoStatus() override { diff --git a/Core/Dialog/PSPOskDialog.h b/Core/Dialog/PSPOskDialog.h index c760afb1e4..b4aeefc745 100644 --- a/Core/Dialog/PSPOskDialog.h +++ b/Core/Dialog/PSPOskDialog.h @@ -213,16 +213,16 @@ enum class PSPOskNativeStatus { class PSPOskDialog: public PSPDialog { public: PSPOskDialog(UtilityDialogType type); - virtual ~PSPOskDialog(); + ~PSPOskDialog(); - virtual int Init(u32 oskPtr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(u32 oskPtr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; protected: - virtual bool UseAutoStatus() override { + bool UseAutoStatus() override { return false; } diff --git a/Core/Dialog/PSPPlaceholderDialog.h b/Core/Dialog/PSPPlaceholderDialog.h index 4c81efe636..b494d92944 100644 --- a/Core/Dialog/PSPPlaceholderDialog.h +++ b/Core/Dialog/PSPPlaceholderDialog.h @@ -22,9 +22,9 @@ class PSPPlaceholderDialog: public PSPDialog { public: PSPPlaceholderDialog(UtilityDialogType type); - virtual ~PSPPlaceholderDialog(); + ~PSPPlaceholderDialog(); - virtual int Init(); - virtual int Update(int animSpeed) override; + int Init(); + int Update(int animSpeed) override; }; diff --git a/Core/Dialog/PSPSaveDialog.h b/Core/Dialog/PSPSaveDialog.h index 90f8d6312a..be6024ac52 100644 --- a/Core/Dialog/PSPSaveDialog.h +++ b/Core/Dialog/PSPSaveDialog.h @@ -72,18 +72,18 @@ class PSPSaveDialog: public PSPDialog { public: PSPSaveDialog(UtilityDialogType type); - virtual ~PSPSaveDialog(); + ~PSPSaveDialog(); - virtual int Init(int paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(int paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; void ExecuteIOAction(); protected: - virtual bool UseAutoStatus() override { + bool UseAutoStatus() override { return false; } diff --git a/Core/Dialog/PSPScreenshotDialog.h b/Core/Dialog/PSPScreenshotDialog.h index ae83e9e8ca..760cd8fcc7 100644 --- a/Core/Dialog/PSPScreenshotDialog.h +++ b/Core/Dialog/PSPScreenshotDialog.h @@ -25,13 +25,13 @@ struct SceUtilityScreenshotParams; class PSPScreenshotDialog : public PSPDialog { public: PSPScreenshotDialog(UtilityDialogType type); - virtual ~PSPScreenshotDialog(); + ~PSPScreenshotDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int ContStart(); - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int ContStart(); + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; protected: // TODO: Manage status correctly. diff --git a/Core/FileLoaders/CachingFileLoader.h b/Core/FileLoaders/CachingFileLoader.h index e778265cce..a4299b567d 100644 --- a/Core/FileLoaders/CachingFileLoader.h +++ b/Core/FileLoaders/CachingFileLoader.h @@ -27,7 +27,7 @@ class CachingFileLoader : public ProxiedFileLoader { public: CachingFileLoader(FileLoader *backend); - ~CachingFileLoader() override; + ~CachingFileLoader(); bool Exists() override; bool ExistsFast() override; diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index bfbf780c2b..a9b75f4406 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -31,7 +31,7 @@ class DiskCachingFileLoaderCache; class DiskCachingFileLoader : public ProxiedFileLoader { public: DiskCachingFileLoader(FileLoader *backend); - ~DiskCachingFileLoader() override; + ~DiskCachingFileLoader(); bool Exists() override; bool ExistsFast() override; diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index 84a4361097..ec92b8b9d5 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -30,21 +30,21 @@ class HTTPFileLoader : public FileLoader { public: HTTPFileLoader(const ::Path &filename); - virtual ~HTTPFileLoader() override; + ~HTTPFileLoader(); bool IsRemote() override { return true; } - virtual bool Exists() override; - virtual bool ExistsFast() override; - virtual bool IsDirectory() override; - virtual s64 FileSize() override; - virtual Path GetPath() const override; + bool Exists() override; + bool ExistsFast() override; + bool IsDirectory() override; + s64 FileSize() override; + Path GetPath() const override; - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; + size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; void Cancel() override { cancel_ = true; diff --git a/Core/FileLoaders/LocalFileLoader.h b/Core/FileLoaders/LocalFileLoader.h index 9e1f37c10f..8db0b24b02 100644 --- a/Core/FileLoaders/LocalFileLoader.h +++ b/Core/FileLoaders/LocalFileLoader.h @@ -30,15 +30,15 @@ typedef void *HANDLE; class LocalFileLoader : public FileLoader { public: LocalFileLoader(const Path &filename); - virtual ~LocalFileLoader(); + ~LocalFileLoader(); - virtual bool Exists() override; - virtual bool IsDirectory() override; - virtual s64 FileSize() override; - virtual Path GetPath() const override { + bool Exists() override; + bool IsDirectory() override; + s64 FileSize() override; + Path GetPath() const override { return filename_; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; private: #ifndef _WIN32 diff --git a/Core/FileLoaders/RamCachingFileLoader.h b/Core/FileLoaders/RamCachingFileLoader.h index 44c375d442..dde5e74ecb 100644 --- a/Core/FileLoaders/RamCachingFileLoader.h +++ b/Core/FileLoaders/RamCachingFileLoader.h @@ -27,7 +27,7 @@ class RamCachingFileLoader : public ProxiedFileLoader { public: RamCachingFileLoader(FileLoader *backend); - ~RamCachingFileLoader() override; + ~RamCachingFileLoader(); bool Exists() override; bool ExistsFast() override; diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 350b97cd8f..d2eeca6651 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -77,7 +77,7 @@ public: class SequentialHandleAllocator : public IHandleAllocator { public: SequentialHandleAllocator() : handle_(1) {} - virtual u32 GetNewHandle() override { + u32 GetNewHandle() override { u32 res = handle_++; if (handle_ < 0) { // Some code assumes it'll never become 0. @@ -85,7 +85,7 @@ public: } return res; } - virtual void FreeHandle(u32 handle) override {} + void FreeHandle(u32 handle) override {} private: int handle_; }; @@ -142,7 +142,7 @@ public: class EmptyFileSystem : public IFileSystem { public: - virtual void DoState(PointerWrap &p) override {} + void DoState(PointerWrap &p) override {} std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override { if (exists) *exists = false; @@ -158,14 +158,14 @@ public: size_t SeekFile(u32 handle, s32 position, FileMove type) override {return 0;} PSPFileInfo GetFileInfo(std::string filename) override {PSPFileInfo f; return f;} bool OwnsHandle(u32 handle) override {return false;} - virtual bool MkDir(const std::string &dirname) override {return false;} - virtual bool RmDir(const std::string &dirname) override {return false;} - virtual int RenameFile(const std::string &from, const std::string &to) override {return -1;} - virtual bool RemoveFile(const std::string &filename) override {return false;} - virtual int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override {return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } - virtual PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; } - virtual FileSystemFlags Flags() override { return FileSystemFlags::NONE; } - virtual u64 FreeSpace(const std::string &path) override { return 0; } + bool MkDir(const std::string &dirname) override {return false;} + bool RmDir(const std::string &dirname) override {return false;} + int RenameFile(const std::string &from, const std::string &to) override {return -1;} + bool RemoveFile(const std::string &filename) override {return false;} + int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override { return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } + PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; } + FileSystemFlags Flags() override { return FileSystemFlags::NONE; } + u64 FreeSpace(const std::string &path) override { return 0; } bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } }; diff --git a/Core/Loaders.h b/Core/Loaders.h index fa6c637d9e..2bef2858f5 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -94,7 +94,7 @@ public: class ProxiedFileLoader : public FileLoader { public: ProxiedFileLoader(FileLoader *backend) : backend_(backend) {} - ~ProxiedFileLoader() override { + ~ProxiedFileLoader() { // Takes ownership. delete backend_; } diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index e5aadba24b..973ddf524e 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -136,7 +136,7 @@ private: class IRJit : public JitInterface { public: IRJit(MIPSState *mipsState); - virtual ~IRJit(); + ~IRJit(); void DoState(PointerWrap &p) override; diff --git a/Core/MIPS/x86/IRToX86.h b/Core/MIPS/x86/IRToX86.h index d1555f6405..31a2cc3297 100644 --- a/Core/MIPS/x86/IRToX86.h +++ b/Core/MIPS/x86/IRToX86.h @@ -14,7 +14,7 @@ public: class IRToX86 : public IRToNativeInterface { public: void SetCodeBlock(Gen::XCodeBlock *code) { code_ = code; } - virtual void ConvertIRToNative(const IRInst *instructions, int count, const u32 *constants) override; + void ConvertIRToNative(const IRInst *instructions, int count, const u32 *constants) override; private: Gen::XCodeBlock *code_; diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 0c96188ee4..8427f837ec 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -44,7 +44,7 @@ struct RegCacheState { class Jit : public Gen::XCodeBlock, public JitInterface, public MIPSFrontendInterface { public: Jit(MIPSState *mipsState); - virtual ~Jit(); + ~Jit(); const JitOptions &GetJitOptions() { return jo; } diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp index 00f7d0a305..6ad9de9316 100644 --- a/Core/Screenshot.cpp +++ b/Core/Screenshot.cpp @@ -41,7 +41,7 @@ public: JPEGFileStream(const Path &filename) { fp_ = File::OpenCFile(filename, "wb"); } - ~JPEGFileStream() override { + ~JPEGFileStream() { if (fp_ ) { fclose(fp_); } diff --git a/Core/ThreadEventQueue.h b/Core/ThreadEventQueue.h index d365454776..161e06753c 100644 --- a/Core/ThreadEventQueue.h +++ b/Core/ThreadEventQueue.h @@ -28,6 +28,8 @@ template ActiveDisplayLists() = 0; virtual void ResetListPC(int listID, u32 pc) = 0; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 3b63732c87..f1a834b265 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -63,7 +63,7 @@ struct SurfaceInfo { GEPatchPrimType primType; bool patchFacing; - void Init() { + void BaseInit() { // If specified as 0, uses 1. if (tess_u < 1) tess_u = 1; if (tess_v < 1) tess_v = 1; @@ -88,7 +88,7 @@ struct BezierSurface : public SurfaceInfo { int num_verts_per_patch; void Init(int maxVertices) { - SurfaceInfo::Init(); + SurfaceInfo::BaseInit(); // Downsample until it fits, in case crazy tessellation factors are sent. while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { tess_u--; @@ -126,7 +126,7 @@ struct SplineSurface : public SurfaceInfo { int num_vertices_u; void Init(int maxVertices) { - SurfaceInfo::Init(); + SurfaceInfo::BaseInit(); // Downsample until it fits, in case crazy tessellation factors are sent. while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) { tess_u--; diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 468c8cd3bb..2703828516 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -117,7 +117,7 @@ public: class DrawEngineD3D11 : public DrawEngineCommon { public: DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context); - virtual ~DrawEngineD3D11(); + ~DrawEngineD3D11(); void SetShaderManager(ShaderManagerD3D11 *shaderManager) { shaderManager_ = shaderManager; diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index a4bcbd670f..0fece6f431 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -54,9 +54,6 @@ protected: void FinishDeferred() override; private: - void Flush() { - drawEngine_.Flush(); - } // void ApplyDrawState(int prim); void CheckFlushOp(int cmd, u32 diff); void BuildReportingInfo() override; diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 3bc7222a67..e8bb1fbf42 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -105,7 +105,7 @@ public: class DrawEngineDX9 : public DrawEngineCommon { public: DrawEngineDX9(Draw::DrawContext *draw); - virtual ~DrawEngineDX9(); + ~DrawEngineDX9(); void SetShaderManager(ShaderManagerDX9 *shaderManager) { shaderManager_ = shaderManager; diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 058e1b75d2..621ad79857 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -54,9 +54,6 @@ protected: void FinishDeferred() override; private: - void Flush() { - drawEngine_.Flush(); - } void CheckFlushOp(int cmd, u32 diff); void BuildReportingInfo() override; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 2907929f12..ebdf4051b4 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -487,10 +487,6 @@ void DrawEngineGLES::DoFlush() { GPUDebug::NotifyDraw(); } -bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { - return decJitCache_->IsInSpace(ptr); -} - // TODO: Refactor this to a single USE flag. bool DrawEngineGLES::SupportsHWTessellation() const { bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index a1a8adce97..9352291c29 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -61,7 +61,7 @@ public: class DrawEngineGLES : public DrawEngineCommon { public: DrawEngineGLES(Draw::DrawContext *draw); - virtual ~DrawEngineGLES(); + ~DrawEngineGLES(); void SetShaderManager(ShaderManagerGLES *shaderManager) { shaderManager_ = shaderManager; @@ -97,8 +97,6 @@ public: DoFlush(); } - bool IsCodePtrVertexDecoder(const u8 *ptr) const; - void DispatchFlush() override { Flush(); } GLPushBuffer *GetPushVertexBuffer() { diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index afb1de0f42..ce2b363149 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -65,9 +65,6 @@ protected: void FinishDeferred() override; private: - void Flush() { - drawEngine_.Flush(); - } void CheckFlushOp(int cmd, u32 diff); void BuildReportingInfo() override; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index c15afe508f..26442c09bd 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -71,7 +71,7 @@ struct TransformedVertex { class GPUCommon : public GPUInterface, public GPUDebugInterface { public: GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw); - virtual ~GPUCommon(); + ~GPUCommon(); Draw::DrawContext *GetDrawContext() override { return draw_; diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 239be55390..afc61a25f4 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -140,7 +140,7 @@ enum { class DrawEngineVulkan : public DrawEngineCommon { public: DrawEngineVulkan(Draw::DrawContext *draw); - virtual ~DrawEngineVulkan(); + ~DrawEngineVulkan(); // We reference feature flags, so this is called after construction. void InitDeviceObjects(); diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 8c970948bd..eefaa23b3c 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -71,9 +71,6 @@ protected: void CheckRenderResized() override; private: - void Flush() { - drawEngine_.Flush(); - } void CheckFlushOp(int cmd, u32 diff); void BuildReportingInfo() override; void InitClear() override; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index a39d7e71b0..3205453c21 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -588,7 +588,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } else { data = drawEngine_->GetPushBufferForTextureData()->PushAligned(sz, &bufferOffset, &texBuf, pushAlignment); } - LoadTextureLevel(*entry, (uint8_t *)data, lstride, srcLevel, lfactor, actualFmt); + LoadVulkanTextureLevel(*entry, (uint8_t *)data, lstride, srcLevel, lfactor, actualFmt); if (plan.saveTexture) bufferOffset = drawEngine_->GetPushBufferForTextureData()->PushAligned(&saveData[0], sz, pushAlignment, &texBuf); }; @@ -706,7 +706,7 @@ VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteForm } } -void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt) { +void TextureCacheVulkan::LoadVulkanTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt) { int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index f83595dc46..2c16d02a03 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -100,7 +100,7 @@ protected: void *GetNativeTextureView(const TexCacheEntry *entry) override; private: - void LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt); + void LoadVulkanTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt); VkFormat GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; diff --git a/Qt/QtHost.h b/Qt/QtHost.h index 79a65caa68..d8fa12f1f7 100644 --- a/Qt/QtHost.h +++ b/Qt/QtHost.h @@ -30,45 +30,45 @@ public: mainWindow = mainWindow_; } - virtual void UpdateUI() override { + void UpdateUI() override { mainWindow->updateMenus(); } - virtual void UpdateMemView() override { + void UpdateMemView() override { } - virtual void UpdateDisassembly() override { + void UpdateDisassembly() override { mainWindow->updateMenus(); } - virtual void SetDebugMode(bool mode) override { + void SetDebugMode(bool mode) override { } - virtual bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override { return true; } - virtual void ShutdownGraphics() override {} + bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override { return true; } + void ShutdownGraphics() override {} - virtual void InitSound() override; - virtual void UpdateSound() override {} - virtual void ShutdownSound() override; + void InitSound() override; + void UpdateSound() override {} + void ShutdownSound() override; // this is sent from EMU thread! Make sure that Host handles it properly! - virtual void BootDone() override { + void BootDone() override { g_symbolMap->SortSymbols(); mainWindow->Notify(MainWindowMsg::BOOT_DONE); } - virtual bool IsDebuggingEnabled() override { + bool IsDebuggingEnabled() override { #ifdef _DEBUG return true; #else return false; #endif } - virtual bool AttemptLoadSymbolMap() override { + bool AttemptLoadSymbolMap() override { auto fn = SymbolMapFilename(PSP_CoreParameter().fileToStart); return g_symbolMap->LoadSymbolMap(fn); } - virtual void NotifySymbolMapUpdated() override { g_symbolMap->SortSymbols(); } + void NotifySymbolMapUpdated() override { g_symbolMap->SortSymbols(); } void PrepareShutdown() { auto fn = SymbolMapFilename(PSP_CoreParameter().fileToStart); diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index b1612c3c2f..380208d42c 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -61,7 +61,7 @@ class DisplayLayoutBackground : public UI::View { public: DisplayLayoutBackground(UI::ChoiceStrip *mode, UI::LayoutParams *layoutParams) : UI::View(layoutParams), mode_(mode) {} - bool Touch(const TouchInput &touch) { + bool Touch(const TouchInput &touch) override { int mode = mode_ ? mode_->GetSelection() : 0; if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index b6f0a7cfb7..16efa42e90 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -334,7 +334,7 @@ public: : gamePath_(gamePath), info_(info) { } - ~GameInfoWorkItem() override { + ~GameInfoWorkItem() { info_->pending.store(false); info_->working.store(false); info_->DisposeFileLoader(); diff --git a/UI/InstallZipScreen.h b/UI/InstallZipScreen.h index 140b82fec2..b877595d57 100644 --- a/UI/InstallZipScreen.h +++ b/UI/InstallZipScreen.h @@ -27,13 +27,13 @@ class InstallZipScreen : public UIDialogScreenWithBackground { public: InstallZipScreen(const Path &zipPath); - virtual void update() override; - virtual bool key(const KeyInput &key) override; + void update() override; + bool key(const KeyInput &key) override; const char *tag() const override { return "InstallZip"; } protected: - virtual void CreateViews() override; + void CreateViews() override; private: UI::EventReturn OnInstall(UI::EventParams ¶ms); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 0855e7eea6..5a03804908 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -434,7 +434,7 @@ public: DirButton(const Path &path, const std::string &text, bool gridStyle, UI::LayoutParams *layoutParams = 0) : UI::Button(text, layoutParams), path_(path), gridStyle_(gridStyle), absolute_(true) {} - virtual void Draw(UIContext &dc); + void Draw(UIContext &dc) override; const Path &GetPath() const { return path_; @@ -1490,7 +1490,7 @@ void UmdReplaceScreen::CreateViews() { tabAllGames->OnHoldChoice.Handle(this, &UmdReplaceScreen::OnGameSelected); - rightColumnItems->Add(new Choice(di->T("Cancel")))->OnClick.Handle(this, &UmdReplaceScreen::OnCancel); + rightColumnItems->Add(new Choice(di->T("Cancel")))->OnClick.Handle(this, &UIScreen::OnCancel); rightColumnItems->Add(new Choice(mm->T("Game Settings")))->OnClick.Handle(this, &UmdReplaceScreen::OnGameSettings); if (g_Config.HasRecentIsos()) { @@ -1515,11 +1515,6 @@ UI::EventReturn UmdReplaceScreen::OnGameSelected(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn UmdReplaceScreen::OnCancel(UI::EventParams &e) { - TriggerFinish(DR_CANCEL); - return UI::EVENT_DONE; -} - UI::EventReturn UmdReplaceScreen::OnGameSettings(UI::EventParams &e) { screenManager()->push(new GameSettingsScreen(Path())); return UI::EVENT_DONE; diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 995a912a92..ee79725fd1 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -165,7 +165,6 @@ private: UI::EventReturn OnGameSelected(UI::EventParams &e); UI::EventReturn OnGameSelectedInstant(UI::EventParams &e); - UI::EventReturn OnCancel(UI::EventParams &e); UI::EventReturn OnGameSettings(UI::EventParams &e); }; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index f880935e08..4bcfb1cb83 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -157,7 +157,6 @@ public: class FloatingSymbolsAnimation : public Animation { public: - ~FloatingSymbolsAnimation() override {} void Draw(UIContext &dc, double t, float alpha, float x, float y, float z) override { float xres = dc.GetBounds().w; float yres = dc.GetBounds().h; @@ -196,7 +195,6 @@ private: class RecentGamesAnimation : public Animation { public: - ~RecentGamesAnimation() override {} void Draw(UIContext &dc, double t, float alpha, float x, float y, float z) override { if (lastIndex_ == nextIndex_) { CheckNext(dc, t); @@ -812,7 +810,7 @@ void CreditsScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); Button *back = root_->Add(new Button(di->T("Back"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, 10, false))); - back->OnClick.Handle(this, &CreditsScreen::OnOK); + back->OnClick.Handle(this, &UIScreen::OnOK); root_->SetDefaultFocusView(back); // Really need to redo this whole layout with some linear layouts... @@ -881,11 +879,6 @@ UI::EventReturn CreditsScreen::OnShare(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn CreditsScreen::OnOK(UI::EventParams &e) { - TriggerFinish(DR_OK); - return UI::EVENT_DONE; -} - CreditsScreen::CreditsScreen() { startTime_ = time_now_d(); } diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index d218739a78..32fe101973 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -161,8 +161,6 @@ public: const char *tag() const override { return "Credits"; } private: - UI::EventReturn OnOK(UI::EventParams &e); - UI::EventReturn OnSupport(UI::EventParams &e); UI::EventReturn OnPPSSPPOrg(UI::EventParams &e); UI::EventReturn OnPrivacy(UI::EventParams &e); @@ -183,7 +181,7 @@ public: } void Show(const std::string &text, UI::View *refView = nullptr); - void Draw(UIContext &dc); + void Draw(UIContext &dc) override; std::string GetText() const; private: diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 1d54db7916..f9f0a949ab 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -33,7 +33,7 @@ enum class PauseScreenMode { class GamePauseScreen : public UIDialogScreenWithGameBackground { public: GamePauseScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename), gamePath_(filename) {} - virtual ~GamePauseScreen(); + ~GamePauseScreen(); void dialogFinished(const Screen *dialog, DialogResult dr) override; diff --git a/UI/RemoteISOScreen.h b/UI/RemoteISOScreen.h index b8676e4832..53bc2706ed 100644 --- a/UI/RemoteISOScreen.h +++ b/UI/RemoteISOScreen.h @@ -57,7 +57,7 @@ enum class ScanStatus { class RemoteISOConnectScreen : public UIScreenWithBackground { public: RemoteISOConnectScreen(); - ~RemoteISOConnectScreen() override; + ~RemoteISOConnectScreen(); const char *tag() const override { return "RemoteISOConnect"; } diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index ca09054c28..c192a021a5 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -43,7 +43,7 @@ class RatingChoice : public LinearLayout { public: RatingChoice(const char *captionKey, int *value, LayoutParams *layoutParams = 0); - RatingChoice *SetEnabledPtr(bool *enabled); + RatingChoice *SetEnabledPtrs(bool *enabled); Event OnChoice; @@ -94,7 +94,7 @@ void RatingChoice::Update() { } } -RatingChoice *RatingChoice::SetEnabledPtr(bool *ptr) { +RatingChoice *RatingChoice::SetEnabledPtrs(bool *ptr) { for (int i = 0; i < TotalChoices(); i++) { GetChoice(i)->SetEnabledPtr(ptr); } @@ -139,8 +139,8 @@ public: CompatRatingChoice(const char *captionKey, int *value, LayoutParams *layoutParams = 0); protected: - virtual void SetupChoices() override; - virtual int TotalChoices() override { + void SetupChoices() override; + int TotalChoices() override { return 5; } }; @@ -295,16 +295,16 @@ void ReportScreen::CreateViews() { screenshot_ = nullptr; } - leftColumnItems->Add(new CompatRatingChoice("Overall", (int *)&overall_))->SetEnabledPtr(&enableReporting_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + leftColumnItems->Add(new CompatRatingChoice("Overall", (int *)&overall_))->SetEnabledPtrs(&enableReporting_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); overallDescription_ = leftColumnItems->Add(new TextView("", FLAG_WRAP_TEXT, false, new LinearLayoutParams(Margins(10, 0)))); overallDescription_->SetShadow(true); UI::Orientation ratingsOrient = leftColumnWidth >= 750.0f ? ORIENT_HORIZONTAL : ORIENT_VERTICAL; UI::LinearLayout *ratingsHolder = new LinearLayoutList(ratingsOrient, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); leftColumnItems->Add(ratingsHolder); - ratingsHolder->Add(new RatingChoice("Graphics", &graphics_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); - ratingsHolder->Add(new RatingChoice("Speed", &speed_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); - ratingsHolder->Add(new RatingChoice("Gameplay", &gameplay_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + ratingsHolder->Add(new RatingChoice("Graphics", &graphics_))->SetEnabledPtrs(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + ratingsHolder->Add(new RatingChoice("Speed", &speed_))->SetEnabledPtrs(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + ratingsHolder->Add(new RatingChoice("Gameplay", &gameplay_))->SetEnabledPtrs(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); rightColumnItems->SetSpacing(0.0f); rightColumnItems->Add(new Choice(rp->T("Open Browser")))->OnClick.Handle(this, &ReportScreen::HandleBrowser); diff --git a/UI/TouchControlLayoutScreen.h b/UI/TouchControlLayoutScreen.h index 0c3f328f96..43c5762f4f 100644 --- a/UI/TouchControlLayoutScreen.h +++ b/UI/TouchControlLayoutScreen.h @@ -27,18 +27,18 @@ class TouchControlLayoutScreen : public UIDialogScreenWithGameBackground { public: TouchControlLayoutScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} - virtual void CreateViews() override; - virtual void dialogFinished(const Screen *dialog, DialogResult result) override; - virtual void onFinish(DialogResult reason) override; - virtual void update() override; - virtual void resized() override; + void CreateViews() override; + void dialogFinished(const Screen *dialog, DialogResult result) override; + void onFinish(DialogResult reason) override; + void update() override; + void resized() override; const char *tag() const override { return "TouchControlLayout"; } protected: - virtual UI::EventReturn OnReset(UI::EventParams &e); - virtual UI::EventReturn OnVisibility(UI::EventParams &e); - virtual UI::EventReturn OnMode(UI::EventParams &e); + UI::EventReturn OnReset(UI::EventParams &e); + UI::EventReturn OnVisibility(UI::EventParams &e); + UI::EventReturn OnMode(UI::EventParams &e); private: UI::ChoiceStrip *mode_ = nullptr; diff --git a/Windows/CaptureDevice.h b/Windows/CaptureDevice.h index d457702afe..d0ed3b4b5f 100644 --- a/Windows/CaptureDevice.h +++ b/Windows/CaptureDevice.h @@ -116,12 +116,12 @@ class WindowsCaptureDevice; class ReaderCallback final : public IMFSourceReaderCallback { public: ReaderCallback(WindowsCaptureDevice *device); - ~ReaderCallback(); + virtual ~ReaderCallback(); // IUnknown methods. - STDMETHODIMP QueryInterface(REFIID iid, void** ppv); - STDMETHODIMP_(ULONG) AddRef() { return 0; } // Unused, just define. - STDMETHODIMP_(ULONG) Release() { return 0; } // Unused, just define. + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override; + STDMETHODIMP_(ULONG) AddRef() override { return 0; } // Unused, just define. + STDMETHODIMP_(ULONG) Release() override { return 0; } // Unused, just define. // IMFSourceReaderCallback methods. STDMETHODIMP OnReadSample( @@ -130,10 +130,10 @@ public: DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample // Can be null,even if hrStatus is success. - ); + ) override; - STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) { return S_OK; } - STDMETHODIMP OnFlush(DWORD) { return S_OK; } + STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) override { return S_OK; } + STDMETHODIMP OnFlush(DWORD) override { return S_OK; } AVPixelFormat getAVVideoFormatbyMFVideoFormat(const GUID &MFVideoFormat); AVSampleFormat getAVAudioFormatbyMFAudioFormat(const GUID &MFAudioFormat, const u32 &bitsPerSample); diff --git a/Windows/DSoundStream.h b/Windows/DSoundStream.h index 7b4798449a..b3ebe194ab 100644 --- a/Windows/DSoundStream.h +++ b/Windows/DSoundStream.h @@ -11,7 +11,7 @@ struct IDirectSoundBuffer; class DSoundAudioBackend : public WindowsAudioBackend { public: DSoundAudioBackend(); - ~DSoundAudioBackend() override; + ~DSoundAudioBackend(); bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object void Update() override; diff --git a/Windows/Debugger/Debugger_Lists.h b/Windows/Debugger/Debugger_Lists.h index 43dd834a44..b553de5f7b 100644 --- a/Windows/Debugger/Debugger_Lists.h +++ b/Windows/Debugger/Debugger_Lists.h @@ -15,11 +15,11 @@ public: void showMenu(int itemIndex, const POINT &pt); const char* getCurrentThreadName(); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int) threads.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); - virtual void OnRightClick(int itemIndex, int column, const POINT& point); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int) threads.size(); } + void OnDoubleClick(int itemIndex, int column) override; + void OnRightClick(int itemIndex, int column, const POINT &point) override; private: std::vector threads; }; @@ -31,14 +31,13 @@ class CtrlBreakpointList: public GenericListControl public: CtrlBreakpointList(HWND hwnd, DebugInterface* cpu, CtrlDisAsmView* disasm); void reloadBreakpoints(); - void showMenu(int itemIndex, const POINT &pt); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return getTotalBreakpointCount(); }; - virtual void OnDoubleClick(int itemIndex, int column); - virtual void OnRightClick(int itemIndex, int column, const POINT& point); - virtual void OnToggle(int item, bool newValue); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return getTotalBreakpointCount(); } + void OnDoubleClick(int itemIndex, int column) override; + void OnRightClick(int itemIndex, int column, const POINT &point) override; + void OnToggle(int item, bool newValue) override; private: std::vector displayedBreakPoints_; std::vector displayedMemChecks_; @@ -61,10 +60,10 @@ public: CtrlStackTraceView(HWND hwnd, DebugInterface* cpu, CtrlDisAsmView* disasm); void loadStackTrace(); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int)frames.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int)frames.size(); } + void OnDoubleClick(int itemIndex, int column) override; private: std::vector frames; DebugInterface* cpu; @@ -77,11 +76,11 @@ public: CtrlModuleList(HWND hwnd, DebugInterface* cpu); void loadModules(); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int)modules.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int)modules.size(); } + void OnDoubleClick(int itemIndex, int column) override; private: std::vector modules; DebugInterface* cpu; -}; \ No newline at end of file +}; diff --git a/Windows/Debugger/Debugger_MemoryDlg.h b/Windows/Debugger/Debugger_MemoryDlg.h index b02d72d0d9..4e47d37be1 100644 --- a/Windows/Debugger/Debugger_MemoryDlg.h +++ b/Windows/Debugger/Debugger_MemoryDlg.h @@ -19,7 +19,7 @@ private: HWND memViewHdl, symListHdl, editWnd, searchBoxHdl, srcListHdl; HWND layerDropdown_; HWND status_; - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; public: int index; //helper @@ -33,11 +33,9 @@ public: ~CMemoryDlg(void); void Goto(u32 addr); - void Update(void); + void Update(void) override; void NotifyMapLoaded(); - void NotifySearchCompleted(); - void Size(void); private: diff --git a/Windows/Debugger/Debugger_VFPUDlg.h b/Windows/Debugger/Debugger_VFPUDlg.h index 0e5763dcfc..080957a7a9 100644 --- a/Windows/Debugger/Debugger_VFPUDlg.h +++ b/Windows/Debugger/Debugger_VFPUDlg.h @@ -10,7 +10,7 @@ public: ~CVFPUDlg(); void Goto(u32 addr); - void Update(); + void Update() override; void Size(); private: @@ -18,5 +18,5 @@ private: DebugInterface *cpu; HFONT font; int mode; - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; }; diff --git a/Windows/DinputDevice.h b/Windows/DinputDevice.h index d8ecc8762f..5dc2474e2a 100644 --- a/Windows/DinputDevice.h +++ b/Windows/DinputDevice.h @@ -32,7 +32,7 @@ public: //getDevices(), enumerates all devices if not done yet DinputDevice(int devnum); ~DinputDevice(); - virtual int UpdateState() override; + int UpdateState() override; static size_t getNumPads(); static void CheckDevices() { needsCheck_ = true; diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index 24e7ffd280..56f1d24746 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -81,7 +81,7 @@ public: StepCountDlg(HINSTANCE _hInstance, HWND _hParent); ~StepCountDlg(); protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void Jump(int count, bool relative); }; @@ -94,7 +94,7 @@ public: static void Init(); protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void SetupPreviews(); diff --git a/Windows/GEDebugger/TabDisplayLists.h b/Windows/GEDebugger/TabDisplayLists.h index ff4388225a..5e31a49341 100644 --- a/Windows/GEDebugger/TabDisplayLists.h +++ b/Windows/GEDebugger/TabDisplayLists.h @@ -12,12 +12,15 @@ class CtrlDisplayListStack: public GenericListControl { public: CtrlDisplayListStack(HWND hwnd); - void setDisplayList(DisplayList& _list) { list = _list; Update(); } + void setDisplayList(const DisplayList &_list) { + list = _list; + Update(); + } protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) { return false; }; - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return list.stackptr; }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override { return false; } + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return list.stackptr; } + void OnDoubleClick(int itemIndex, int column) override; private: DisplayList list; }; @@ -26,12 +29,15 @@ class CtrlAllDisplayLists: public GenericListControl { public: CtrlAllDisplayLists(HWND hwnd); - void setDisplayLists(std::vector& _lists) { lists = _lists; Update(); }; + void setDisplayLists(const std::vector &_lists) { + lists = _lists; + Update(); + } protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int) lists.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int) lists.size(); } + void OnDoubleClick(int itemIndex, int column) override; private: std::vector lists; }; @@ -43,7 +49,7 @@ public: ~TabDisplayLists(); void Update(bool reload = true); protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void UpdateSize(WORD width, WORD height); diff --git a/Windows/GEDebugger/TabState.h b/Windows/GEDebugger/TabState.h index 6992af14be..f525b02723 100644 --- a/Windows/GEDebugger/TabState.h +++ b/Windows/GEDebugger/TabState.h @@ -63,7 +63,7 @@ public: } protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; CtrlStateValues *values; diff --git a/Windows/GEDebugger/TabVertices.h b/Windows/GEDebugger/TabVertices.h index 0a1f48be0c..4d7a04d660 100644 --- a/Windows/GEDebugger/TabVertices.h +++ b/Windows/GEDebugger/TabVertices.h @@ -35,9 +35,9 @@ public: } protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) { return false; }; - virtual void GetColumnText(wchar_t *dest, int row, int col); - virtual int GetRowCount(); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override { return false; } + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override; private: void FormatVertCol(wchar_t *dest, const GPUDebugVertex &vert, int col); @@ -57,12 +57,12 @@ public: TabVertices(HINSTANCE _hInstance, HWND _hParent); ~TabVertices(); - virtual void Update() { + void Update() override { values->Update(); } protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void UpdateSize(WORD width, WORD height); @@ -98,12 +98,12 @@ public: TabMatrices(HINSTANCE _hInstance, HWND _hParent); ~TabMatrices(); - virtual void Update() { + void Update() override { values->Update(); } protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void UpdateSize(WORD width, WORD height); diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp index 3481e42d69..6079c030de 100644 --- a/Windows/WASAPIStream.cpp +++ b/Windows/WASAPIStream.cpp @@ -38,7 +38,7 @@ public: CMMNotificationClient() { } - ~CMMNotificationClient() { + virtual ~CMMNotificationClient() { CoTaskMemFree(currentDevice_); currentDevice_ = nullptr; SAFE_RELEASE(_pEnumerator) diff --git a/Windows/WASAPIStream.h b/Windows/WASAPIStream.h index b9e2169a78..9f0b88b40d 100644 --- a/Windows/WASAPIStream.h +++ b/Windows/WASAPIStream.h @@ -8,7 +8,7 @@ class WASAPIAudioBackend : public WindowsAudioBackend { public: WASAPIAudioBackend(); - ~WASAPIAudioBackend() override; + ~WASAPIAudioBackend(); bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object void Update() override {} diff --git a/Windows/XinputDevice.h b/Windows/XinputDevice.h index bcff3e5db8..93347a6722 100644 --- a/Windows/XinputDevice.h +++ b/Windows/XinputDevice.h @@ -8,7 +8,7 @@ class XinputDevice final : public InputDevice { public: XinputDevice(); ~XinputDevice(); - virtual int UpdateState() override; + int UpdateState() override; private: void UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATION &vibration); diff --git a/headless/Compare.cpp b/headless/Compare.cpp index 9c42887342..e99b496b30 100644 --- a/headless/Compare.cpp +++ b/headless/Compare.cpp @@ -138,11 +138,11 @@ protected: BufferedLineReader() { } - virtual bool HasMoreLines() { + bool HasMoreLines() { return pos_ != data_.npos; } - virtual std::string ReadLine() { + std::string ReadLine() { size_t next = data_.find('\n', pos_); if (next == data_.npos) { std::string result = data_.substr(pos_); diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 98aefd31e7..fa63a489e1 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -65,7 +65,7 @@ bool audioRecording_State() { return false; } class PrintfLogger : public LogListener { public: - void Log(const LogMessage &message) { + void Log(const LogMessage &message) override { switch (message.level) { case LogTypes::LVERBOSE: fprintf(stderr, "V %s", message.msg.c_str()); diff --git a/unittest/TestThreadManager.cpp b/unittest/TestThreadManager.cpp index 1457c587ed..ece88ca494 100644 --- a/unittest/TestThreadManager.cpp +++ b/unittest/TestThreadManager.cpp @@ -74,8 +74,8 @@ class IncrementTask : public Task { public: IncrementTask(TaskType type, LimitedWaitable *waitable) : type_(type), waitable_(waitable) {} ~IncrementTask() {} - virtual TaskType Type() const { return type_; } - virtual void Run() { + TaskType Type() const override { return type_; } + void Run() override { g_atomicCounter++; waitable_->Notify(); } From e3fdb183f6c04eda1b88711552fdff5cee010de3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 20:50:11 -0800 Subject: [PATCH 660/715] Common: Remove some unused color conv funcs. We already have versions of these doing other conversions. --- Common/Data/Convert/ColorConv.cpp | 82 ------------------------------- Common/Data/Convert/ColorConv.h | 9 ---- 2 files changed, 91 deletions(-) diff --git a/Common/Data/Convert/ColorConv.cpp b/Common/Data/Convert/ColorConv.cpp index 55686f5c00..01c434e6e5 100644 --- a/Common/Data/Convert/ColorConv.cpp +++ b/Common/Data/Convert/ColorConv.cpp @@ -34,88 +34,6 @@ #endif #endif -// convert 4444 image to 8888, parallelizable -void convert4444_gl(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = ((val >> 12) & 0xF) * 17; - u32 g = ((val >> 8) & 0xF) * 17; - u32 b = ((val >> 4) & 0xF) * 17; - u32 a = ((val >> 0) & 0xF) * 17; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 565 image to 8888, parallelizable -void convert565_gl(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val >> 11) & 0x1F); - u32 g = Convert6To8((val >> 5) & 0x3F); - u32 b = Convert5To8((val)& 0x1F); - out[y*width + x] = (0xFF << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 5551 image to 8888, parallelizable -void convert5551_gl(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val >> 11) & 0x1F); - u32 g = Convert5To8((val >> 6) & 0x1F); - u32 b = Convert5To8((val >> 1) & 0x1F); - u32 a = (val & 0x1) * 255; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 4444 image to 8888, parallelizable -void convert4444_dx9(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = ((val >> 0) & 0xF) * 17; - u32 g = ((val >> 4) & 0xF) * 17; - u32 b = ((val >> 8) & 0xF) * 17; - u32 a = ((val >> 12) & 0xF) * 17; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 565 image to 8888, parallelizable -void convert565_dx9(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val)& 0x1F); - u32 g = Convert6To8((val >> 5) & 0x3F); - u32 b = Convert5To8((val >> 11) & 0x1F); - out[y*width + x] = (0xFF << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 5551 image to 8888, parallelizable -void convert5551_dx9(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val >> 0) & 0x1F); - u32 g = Convert5To8((val >> 5) & 0x1F); - u32 b = Convert5To8((val >> 10) & 0x1F); - u32 a = ((val >> 15) & 0x1) * 255; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - void ConvertBGRA8888ToRGBA8888(u32 *dst, const u32 *src, u32 numPixels) { #ifdef _M_SSE const __m128i maskGA = _mm_set1_epi32(0xFF00FF00); diff --git a/Common/Data/Convert/ColorConv.h b/Common/Data/Convert/ColorConv.h index a7355dbb9d..53a286d127 100644 --- a/Common/Data/Convert/ColorConv.h +++ b/Common/Data/Convert/ColorConv.h @@ -126,15 +126,6 @@ inline u16 RGBA8888ToRGBA444X(u32 value) { return r | g | b; } -// convert image to 8888, parallelizable -// TODO: Implement these in terms of the conversion functions below. -void convert4444_gl(u16* data, u32* out, int width, int l, int u); -void convert565_gl(u16* data, u32* out, int width, int l, int u); -void convert5551_gl(u16* data, u32* out, int width, int l, int u); -void convert4444_dx9(u16* data, u32* out, int width, int l, int u); -void convert565_dx9(u16* data, u32* out, int width, int l, int u); -void convert5551_dx9(u16* data, u32* out, int width, int l, int u); - // "Complete" set of color conversion functions between the usual formats. // TODO: Need to revisit the naming convention of these. Seems totally backwards From a7b7bf78262fbe7432382b5445a71ad741893385 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 21:02:44 -0800 Subject: [PATCH 661/715] Global: Set many read-only params as const. This makes what they do and which args to use clearer, if nothing else. --- Common/Data/Encoding/Utf8.cpp | 2 +- Common/GPU/D3D11/thin3d_d3d11.cpp | 4 ++-- Common/GPU/OpenGL/GLRenderManager.h | 2 +- Common/GPU/OpenGL/thin3d_gl.cpp | 2 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 2 +- Common/LogManager.cpp | 2 +- Common/LogManager.h | 2 +- Common/Render/DrawBuffer.cpp | 2 +- Common/Render/DrawBuffer.h | 2 +- Common/UI/View.cpp | 2 +- Common/UI/View.h | 2 +- Common/UI/ViewGroup.cpp | 4 ++-- Core/Config.cpp | 2 +- Core/Dialog/PSPGamedataInstallDialog.cpp | 2 +- Core/Dialog/PSPGamedataInstallDialog.h | 2 +- Core/Dialog/PSPSaveDialog.cpp | 2 +- Core/Dialog/SavedataParam.cpp | 11 +++++------ Core/Dialog/SavedataParam.h | 6 +++--- Core/FileLoaders/DiskCachingFileLoader.cpp | 2 +- Core/FileLoaders/DiskCachingFileLoader.h | 2 +- Core/FileSystems/DirectoryFileSystem.cpp | 2 +- Core/FileSystems/VirtualDiscFileSystem.cpp | 2 +- Core/HLE/proAdhoc.cpp | 2 +- Core/HLE/proAdhoc.h | 2 +- Core/HLE/sceIo.cpp | 2 +- Core/HLE/sceKernelThread.cpp | 2 +- Core/HLE/sceKernelThread.h | 2 +- Core/HLE/sceKernelVTimer.cpp | 2 +- Core/HLE/sceMpeg.cpp | 6 +++--- Core/HW/AsyncIOManager.cpp | 2 +- Core/HW/AsyncIOManager.h | 2 +- Core/HW/MpegDemux.cpp | 2 +- Core/HW/SimpleAudioDec.cpp | 2 +- Core/HW/SimpleAudioDec.h | 2 +- Core/MIPS/IR/IRCompVFPU.cpp | 8 ++++---- Core/MIPS/JitCommon/JitBlockCache.cpp | 2 +- Core/MIPS/MIPSVFPUUtils.cpp | 2 +- Core/MIPS/MIPSVFPUUtils.h | 2 +- Core/MIPS/x86/CompVFPU.cpp | 4 ++-- GPU/Common/Draw2D.cpp | 2 +- GPU/Common/Draw2D.h | 2 +- GPU/Common/DrawEngineCommon.cpp | 4 ++-- GPU/Common/FramebufferManagerCommon.cpp | 2 +- GPU/Common/SoftwareTransformCommon.cpp | 8 ++++---- GPU/Common/SoftwareTransformCommon.h | 8 ++++---- GPU/Common/TextureCacheCommon.h | 2 +- GPU/Common/TextureScalerCommon.cpp | 22 +++++++++++----------- GPU/Common/TextureShaderCommon.cpp | 2 +- GPU/Common/TextureShaderCommon.h | 2 +- GPU/Common/VertexDecoderCommon.cpp | 2 +- GPU/Common/VertexDecoderCommon.h | 2 +- GPU/Directx9/ShaderManagerDX9.cpp | 2 +- GPU/Directx9/ShaderManagerDX9.h | 2 +- GPU/GPUState.cpp | 2 +- GPU/GPUState.h | 2 +- GPU/Math3D.cpp | 12 ++++-------- GPU/Math3D.h | 8 ++++---- GPU/Software/BinManager.cpp | 2 +- GPU/Software/BinManager.h | 2 +- GPU/Software/Lighting.cpp | 2 +- GPU/Software/TransformUnit.cpp | 2 +- GPU/Software/TransformUnit.h | 2 +- UI/ComboKeyMappingScreen.cpp | 2 +- UI/MiscScreens.cpp | 6 +++--- UI/MiscScreens.h | 4 ++-- Windows/Debugger/CtrlDisAsmView.cpp | 3 +-- Windows/Debugger/CtrlDisAsmView.h | 2 +- Windows/RawInput.cpp | 4 ++-- unittest/TestArm64Emitter.cpp | 2 +- unittest/TestArmEmitter.cpp | 2 +- unittest/TestX64Emitter.cpp | 4 ++-- 71 files changed, 113 insertions(+), 119 deletions(-) diff --git a/Common/Data/Encoding/Utf8.cpp b/Common/Data/Encoding/Utf8.cpp index d30a9432a8..760fe6b07d 100644 --- a/Common/Data/Encoding/Utf8.cpp +++ b/Common/Data/Encoding/Utf8.cpp @@ -112,7 +112,7 @@ int u8_toucs(uint32_t *dest, int sz, const char *src, int srcsz) the NUL as well. the destination string will never be bigger than the source string. */ -int u8_toutf8(char *dest, int sz, uint32_t *src, int srcsz) +int u8_toutf8(char *dest, int sz, const uint32_t *src, int srcsz) { uint32_t ch; int i = 0; diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 9b59852c88..43e6c2b653 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -170,7 +170,7 @@ public: private: void ApplyCurrentState(); - ID3D11DepthStencilState *GetCachedDepthStencilState(D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask); + ID3D11DepthStencilState *GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask); HWND hWnd_; ID3D11Device *device_; @@ -550,7 +550,7 @@ public: float blendFactor[4]; }; -ID3D11DepthStencilState *D3D11DrawContext::GetCachedDepthStencilState(D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask) { +ID3D11DepthStencilState *D3D11DrawContext::GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask) { D3D11DepthStencilKey key; key.desc = state->desc; key.writeMask = stencilWriteMask; diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index ff48306c3e..52ac971cec 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -481,7 +481,7 @@ public: return step.create_program.program; } - GLRInputLayout *CreateInputLayout(std::vector &entries) { + GLRInputLayout *CreateInputLayout(const std::vector &entries) { GLRInitStep step{ GLRInitStepType::CREATE_INPUT_LAYOUT }; step.create_input_layout.inputLayout = new GLRInputLayout(); step.create_input_layout.inputLayout->entries = entries; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 6ea0ddc1dd..c9edb68502 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -517,7 +517,7 @@ static constexpr int MakeIntelSimpleVer(int v1, int v2, int v3) { return (v1 << 16) | (v2 << 8) | v3; } -static bool HasIntelDualSrcBug(int versions[4]) { +static bool HasIntelDualSrcBug(const int versions[4]) { // Intel uses a confusing set of at least 3 version numbering schemes. This is the one given to OpenGL. switch (MakeIntelSimpleVer(versions[0], versions[1], versions[2])) { case MakeIntelSimpleVer(9, 17, 10): diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index d28871e8c7..ec38cabecd 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -11,7 +11,7 @@ using namespace PPSSPP_VK; // Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP NativeGLView NativeRenderer NativeSurfaceView PowerSaveModeReceiver InputDeviceState -static void MergeRenderAreaRectInto(VkRect2D *dest, VkRect2D &src) { +static void MergeRenderAreaRectInto(VkRect2D *dest, const VkRect2D &src) { if (dest->offset.x > src.offset.x) { dest->extent.width += (dest->offset.x - src.offset.x); dest->offset.x = src.offset.x; diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index 26b1ed49ec..13084098a4 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -200,7 +200,7 @@ void LogManager::SaveConfig(Section *section) { } } -void LogManager::LoadConfig(Section *section, bool debugDefaults) { +void LogManager::LoadConfig(const Section *section, bool debugDefaults) { for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) { bool enabled = false; int level = 0; diff --git a/Common/LogManager.h b/Common/LogManager.h index 5d8afddae5..3ee1347f42 100644 --- a/Common/LogManager.h +++ b/Common/LogManager.h @@ -183,5 +183,5 @@ public: void ChangeFileLog(const char *filename); void SaveConfig(Section *section); - void LoadConfig(Section *section, bool debugDefaults); + void LoadConfig(const Section *section, bool debugDefaults); }; diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index e3efb6b5d0..7a50f2844a 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -130,7 +130,7 @@ void DrawBuffer::RectOutline(float x, float y, float w, float h, uint32_t color, vLine(x + w, y, y + h + pixel_in_dps_y, color); } -void DrawBuffer::MultiVGradient(float x, float y, float w, float h, GradientStop *stops, int numStops) { +void DrawBuffer::MultiVGradient(float x, float y, float w, float h, const GradientStop *stops, int numStops) { for (int i = 0; i < numStops - 1; i++) { float t0 = stops[i].t, t1 = stops[i+1].t; uint32_t c0 = stops[i].color, c1 = stops[i+1].color; diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index 4a29893c15..8c6262c7c7 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -88,7 +88,7 @@ public: RectVGradient(x, y, w, h, colorTop, darkenColor(colorTop)); } - void MultiVGradient(float x, float y, float w, float h, GradientStop *stops, int numStops); + void MultiVGradient(float x, float y, float w, float h, const GradientStop *stops, int numStops); void RectCenter(float x, float y, float w, float h, uint32_t color) { Rect(x - w/2, y - h/2, w, h, color); diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 769089e375..8be9b3076d 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -169,7 +169,7 @@ void View::PersistData(PersistStatus status, std::string anonId, PersistMap &sto } } -Point View::GetFocusPosition(FocusDirection dir) { +Point View::GetFocusPosition(FocusDirection dir) const { // The +2/-2 is some extra fudge factor to cover for views sitting right next to each other. // Distance zero yields strange results otherwise. switch (dir) { diff --git a/Common/UI/View.h b/Common/UI/View.h index 1ab1ea5f68..f3c54a0a3d 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -468,7 +468,7 @@ public: virtual bool IsViewGroup() const { return false; } virtual bool ContainsSubview(const View *view) const { return false; } - Point GetFocusPosition(FocusDirection dir); + Point GetFocusPosition(FocusDirection dir) const; template T *AddTween(T *t) { diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 50398dac45..de556ad5d9 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -294,7 +294,7 @@ static float VerticalOverlap(const Bounds &a, const Bounds &b) { return std::min(1.0f, overlap / minH); } -float GetTargetScore(const Point &originPos, int originIndex, View *origin, View *destination, FocusDirection direction) { +float GetTargetScore(const Point &originPos, int originIndex, const View *origin, const View *destination, FocusDirection direction) { // Skip labels and things like that. if (!destination->CanBeFocused()) return 0.0f; @@ -394,7 +394,7 @@ float GetTargetScore(const Point &originPos, int originIndex, View *origin, View } } -float GetDirectionScore(int originIndex, View *origin, View *destination, FocusDirection direction) { +static float GetDirectionScore(int originIndex, const View *origin, View *destination, FocusDirection direction) { Point originPos = origin->GetFocusPosition(direction); return GetTargetScore(originPos, originIndex, origin, destination, direction); } diff --git a/Core/Config.cpp b/Core/Config.cpp index ebc731cbd2..02e10366c0 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -257,7 +257,7 @@ struct ConfigSetting { return type_ != TYPE_TERMINATOR; } - bool Get(Section *section) { + bool Get(const Section *section) { switch (type_) { case TYPE_BOOL: if (cb_.b) { diff --git a/Core/Dialog/PSPGamedataInstallDialog.cpp b/Core/Dialog/PSPGamedataInstallDialog.cpp index 30da2953c6..22ef058313 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.cpp +++ b/Core/Dialog/PSPGamedataInstallDialog.cpp @@ -250,7 +250,7 @@ int PSPGamedataInstallDialog::Shutdown(bool force) { return PSPDialog::Shutdown(force); } -std::string PSPGamedataInstallDialog::GetGameDataInstallFileName(SceUtilityGamedataInstallParam *param, std::string filename){ +std::string PSPGamedataInstallDialog::GetGameDataInstallFileName(const SceUtilityGamedataInstallParam *param, std::string filename) { if (!param) return ""; std::string GameDataInstallPath = saveBasePath + param->gameName + param->dataName + "/"; diff --git a/Core/Dialog/PSPGamedataInstallDialog.h b/Core/Dialog/PSPGamedataInstallDialog.h index 47febcff9f..c73db2a01f 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.h +++ b/Core/Dialog/PSPGamedataInstallDialog.h @@ -44,7 +44,7 @@ public: void DoState(PointerWrap &p) override; int Abort(); - std::string GetGameDataInstallFileName(SceUtilityGamedataInstallParam *param, std::string filename); + std::string GetGameDataInstallFileName(const SceUtilityGamedataInstallParam *param, std::string filename); protected: // TODO: Manage status correctly. diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index a857f53a44..8e0bfcb1ba 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -157,7 +157,7 @@ int PSPSaveDialog::Init(int paramAddr) break; } - if(!param.wouldHasMultiSaveName(param.GetPspParam())) + if (!param.WouldHaveMultiSaveName(param.GetPspParam())) currentSelectedSave = 0; switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index f2c7b1758c..b78f728788 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -86,7 +86,7 @@ namespace return result != 0; } - bool WritePSPFile(std::string filename, u8 *data, SceSize dataSize) + bool WritePSPFile(std::string filename, const u8 *data, SceSize dataSize) { int handle = pspFileSystem.OpenFile(filename, (FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE | FILEACCESS_TRUNCATE)); if (handle < 0) @@ -1516,7 +1516,7 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) saveDataListCount++; } - if (saveDataListCount > 0 && wouldHasMultiSaveName(param)) { + if (saveDataListCount > 0 && WouldHaveMultiSaveName(param)) { hasMultipleFileName = true; saveDataList = new SaveFileInfo[saveDataListCount]; @@ -1842,8 +1842,7 @@ int SavedataParam::GetLastEmptySave() return idx; } -int SavedataParam::GetSaveNameIndex(SceUtilitySavedataParam* param) -{ +int SavedataParam::GetSaveNameIndex(const SceUtilitySavedataParam *param) { std::string saveName = GetSaveName(param); for (int i = 0; i < saveNameListDataCount; i++) { @@ -1857,7 +1856,7 @@ int SavedataParam::GetSaveNameIndex(SceUtilitySavedataParam* param) return 0; } -bool SavedataParam::wouldHasMultiSaveName(SceUtilitySavedataParam* param) { +bool SavedataParam::WouldHaveMultiSaveName(const SceUtilitySavedataParam *param) { switch ((SceUtilitySavedataType)(u32)param->mode) { case SCE_UTILITY_SAVEDATA_TYPE_LOAD: case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: @@ -1937,7 +1936,7 @@ std::shared_ptr SavedataParam::LoadCachedSFO(const std::string &pa return sfoCache_.at(path); } -int SavedataParam::GetSaveCryptMode(SceUtilitySavedataParam *param, const std::string &saveDirName) { +int SavedataParam::GetSaveCryptMode(const SceUtilitySavedataParam *param, const std::string &saveDirName) { std::string dirPath = GetSaveFilePath(param, GetSaveDir(param, saveDirName)); std::string sfopath = dirPath + "/" + SFO_FILENAME; std::shared_ptr sfoFile = LoadCachedSFO(sfopath); diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 65a1ac5cd1..257fc02746 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -317,7 +317,7 @@ public: bool GetList(SceUtilitySavedataParam* param); int GetFilesList(SceUtilitySavedataParam* param, u32 requestAddr); bool GetSize(SceUtilitySavedataParam* param); - int GetSaveCryptMode(SceUtilitySavedataParam* param, const std::string &saveDirName); + int GetSaveCryptMode(const SceUtilitySavedataParam *param, const std::string &saveDirName); bool IsInSaveDataList(std::string saveName, int count); std::string GetGameName(const SceUtilitySavedataParam *param) const; @@ -351,9 +351,9 @@ public: int GetLastDataSave(); int GetFirstEmptySave(); int GetLastEmptySave(); - int GetSaveNameIndex(SceUtilitySavedataParam* param); + int GetSaveNameIndex(const SceUtilitySavedataParam *param); - bool wouldHasMultiSaveName(SceUtilitySavedataParam* param); + bool WouldHaveMultiSaveName(const SceUtilitySavedataParam *param); void ClearCaches(); diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index dd8d59bf05..20c3ae0ad5 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -480,7 +480,7 @@ bool DiskCachingFileLoaderCache::ReadBlockData(u8 *dest, BlockInfo &info, size_t return !failed; } -void DiskCachingFileLoaderCache::WriteBlockData(BlockInfo &info, u8 *src) { +void DiskCachingFileLoaderCache::WriteBlockData(BlockInfo &info, const u8 *src) { if (!f_) { return; } diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index a9b75f4406..242c28ab5d 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -95,7 +95,7 @@ private: struct BlockInfo; bool ReadBlockData(u8 *dest, BlockInfo &info, size_t offset, size_t size); - void WriteBlockData(BlockInfo &info, u8 *src); + void WriteBlockData(BlockInfo &info, const u8 *src); void WriteIndexData(u32 indexPos, BlockInfo &info); s64 GetBlockOffset(u32 block); diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index b2ae2fabb7..27abc90564 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -712,7 +712,7 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { #ifdef _WIN32 #define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL -static void tmFromFiletime(tm &dest, FILETIME &src) { +static void tmFromFiletime(tm &dest, const FILETIME &src) { u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL; u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US; diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index dbe130f30c..5c5a6714e2 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -651,7 +651,7 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { #ifdef _WIN32 #define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL -static void tmFromFiletime(tm &dest, FILETIME &src) +static void tmFromFiletime(tm &dest, const FILETIME &src) { u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL; u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US; diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index dfcc535df0..2a18f05534 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -180,7 +180,7 @@ std::string ip2str(in_addr in, bool maskPublicIP) { return std::string(str); } -std::string mac2str(SceNetEtherAddr* mac) { +std::string mac2str(const SceNetEtherAddr *mac) { char str[18] = ":::::"; if (mac != NULL) { diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index b3594e5a7b..c448d0189b 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -1017,7 +1017,7 @@ bool isPTPPortInUse(uint16_t port, bool forListen, SceNetEtherAddr* dstmac = nul std::string ip2str(in_addr in, bool maskPublicIP = true); // Convert MAC address to string -std::string mac2str(SceNetEtherAddr* mac); +std::string mac2str(const SceNetEtherAddr *mac); /* * Matching Members diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 7425ec2603..e6fbd166e7 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -796,7 +796,7 @@ void __IoShutdown() { memStickFatCallbacks.clear(); } -static std::string IODetermineFilename(FileNode *f) { +static std::string IODetermineFilename(const FileNode *f) { uint64_t offset = pspFileSystem.GetSeekPos(f->handle); if ((pspFileSystem.DevType(f->handle) & PSPDevType::BLOCK) != 0) { return StringFromFormat("%s offset 0x%08llx", f->fullpath.c_str(), offset * 2048); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index e3fcf2e442..995ead9667 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1466,7 +1466,7 @@ void __KernelSaveContext(PSPThreadContext *ctx, bool vfpuEnabled) { } // Loads a CPU context -void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled) { +void __KernelLoadContext(const PSPThreadContext *ctx, bool vfpuEnabled) { // r and f are immediately next to each other and must be. memcpy((void *)currentMIPS->r, (void *)ctx->r, sizeof(ctx->r) + sizeof(ctx->f)); diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index b7e77c95b9..70c380245d 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -177,7 +177,7 @@ bool KernelIsThreadDormant(SceUID threadID); bool KernelIsThreadWaiting(SceUID threadID); void __KernelSaveContext(PSPThreadContext *ctx, bool vfpuEnabled); -void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled); +void __KernelLoadContext(const PSPThreadContext *ctx, bool vfpuEnabled); u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval); // can return an error value u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval); diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 63efc53eda..ce26b208ac 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -71,7 +71,7 @@ KernelObject *__KernelVTimerObject() { return new VTimer; } -static u64 __getVTimerRunningTime(VTimer *vt) { +static u64 __getVTimerRunningTime(const VTimer *vt) { if (vt->nvt.active == 0) return 0; diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index b39b5bd8db..e96ae6ebe8 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -314,7 +314,7 @@ static u32 getMpegVersion(u32 mpegRawVersion) { } } -static void AnalyzeMpeg(u8 *buffer, u32 validSize, MpegContext *ctx) { +static void AnalyzeMpeg(const u8 *buffer, u32 validSize, MpegContext *ctx) { ctx->mpegMagic = *(u32_le*)buffer; ctx->mpegRawVersion = *(u32_le*)(buffer + PSMF_STREAM_VERSION_OFFSET); ctx->mpegVersion = getMpegVersion(ctx->mpegRawVersion); @@ -883,11 +883,11 @@ public: } }; - void add(H264Frames *p){ + void add(const H264Frames *p) { add(p->stream, p->size); }; - void add(u8* str, int sz){ + void add(const u8 *str, int sz) { int newsize = size + sz; u8* newstream = new u8[newsize]; // join two streams diff --git a/Core/HW/AsyncIOManager.cpp b/Core/HW/AsyncIOManager.cpp index 1d4ce89b0a..85a9886053 100644 --- a/Core/HW/AsyncIOManager.cpp +++ b/Core/HW/AsyncIOManager.cpp @@ -134,7 +134,7 @@ void AsyncIOManager::Read(u32 handle, u8 *buf, size_t bytes, u32 invalidateAddr) EventResult(handle, AsyncIOResult(result, usec, invalidateAddr)); } -void AsyncIOManager::Write(u32 handle, u8 *buf, size_t bytes) { +void AsyncIOManager::Write(u32 handle, const u8 *buf, size_t bytes) { int usec = 0; s64 result = pspFileSystem.WriteFile(handle, buf, bytes, usec); EventResult(handle, AsyncIOResult(result, usec)); diff --git a/Core/HW/AsyncIOManager.h b/Core/HW/AsyncIOManager.h index 4b1e0b5276..59d50050cf 100644 --- a/Core/HW/AsyncIOManager.h +++ b/Core/HW/AsyncIOManager.h @@ -98,7 +98,7 @@ private: bool PopResult(u32 handle, AsyncIOResult &result); bool ReadResult(u32 handle, AsyncIOResult &result); void Read(u32 handle, u8 *buf, size_t bytes, u32 invalidateAddr); - void Write(u32 handle, u8 *buf, size_t bytes); + void Write(u32 handle, const u8 *buf, size_t bytes); void EventResult(u32 handle, AsyncIOResult result); diff --git a/Core/HW/MpegDemux.cpp b/Core/HW/MpegDemux.cpp index 4dce9cff05..6dbfa5ec44 100644 --- a/Core/HW/MpegDemux.cpp +++ b/Core/HW/MpegDemux.cpp @@ -288,7 +288,7 @@ bool MpegDemux::demux(int audioChannel) return looksValid; } -static bool isHeader(u8* audioStream, int offset) +static bool isHeader(const u8 *audioStream, int offset) { const u8 header1 = (u8)0x0F; const u8 header2 = (u8)0xD0; diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 8db47c77b5..0a19d92f85 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -120,7 +120,7 @@ bool SimpleAudio::OpenCodec(int block_align) { #endif // USE_FFMPEG } -void SimpleAudio::SetExtraData(u8 *data, int size, int wav_bytes_per_packet) { +void SimpleAudio::SetExtraData(const u8 *data, int size, int wav_bytes_per_packet) { #ifdef USE_FFMPEG if (codecCtx_) { codecCtx_->extradata = (uint8_t *)av_mallocz(size); diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index 533172aaa6..ec792c9031 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -53,7 +53,7 @@ public: int GetAudioCodecID(int audioType); // Get audioCodecId from audioType // Not save stated, only used by UI. Used for ATRAC3 (non+) files. - void SetExtraData(u8 *data, int size, int wav_bytes_per_packet); + void SetExtraData(const u8 *data, int size, int wav_bytes_per_packet); void SetChannels(int channels); diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index f325f006b3..11050c44cc 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -92,7 +92,7 @@ namespace MIPSComp { // Vector regs can overlap in all sorts of swizzled ways. // This does allow a single overlap in sregs[i]. - static bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) { + static bool IsOverlapSafeAllowS(int dreg, int di, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = NULL) { for (int i = 0; i < sn; ++i) { if (sregs[i] == dreg && i != di) return false; @@ -106,7 +106,7 @@ namespace MIPSComp { return true; } - static bool IsOverlapSafeAllowS(int dn, u8 dregs[], int sn, u8 sregs[], int tn = 0, u8 tregs[] = nullptr) { + static bool IsOverlapSafeAllowS(int dn, const u8 dregs[], int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = nullptr) { for (int i = 0; i < dn; ++i) { if (!IsOverlapSafeAllowS(dregs[i], i, sn, sregs, tn, tregs)) { return false; @@ -115,11 +115,11 @@ namespace MIPSComp { return true; } - static bool IsOverlapSafe(int dreg, int sn, u8 sregs[], int tn = 0, u8 tregs[] = nullptr) { + static bool IsOverlapSafe(int dreg, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = nullptr) { return IsOverlapSafeAllowS(dreg, -1, sn, sregs, tn, tregs); } - static bool IsOverlapSafe(int dn, u8 dregs[], int sn, u8 sregs[], int tn = 0, u8 tregs[] = nullptr) { + static bool IsOverlapSafe(int dn, const u8 dregs[], int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = nullptr) { for (int i = 0; i < dn; ++i) { if (!IsOverlapSafe(dregs[i], sn, sregs, tn, tregs)) { return false; diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index f5b11ca4a5..e822c5c47d 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -304,7 +304,7 @@ bool JitBlockCache::RangeMayHaveEmuHacks(u32 start, u32 end) const { return false; } -static int binary_search(JitBlock blocks_[], const u8 *baseoff, int imin, int imax) { +static int binary_search(const JitBlock blocks_[], const u8 *baseoff, int imin, int imax) { while (imin < imax) { int imid = (imin + imax) / 2; if (blocks_[imid].normalEntry < baseoff) diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index e7f7bf7a7f..1019cbf494 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -678,7 +678,7 @@ static int32_t get_sign(uint32_t x) { return x & 0x80000000; } -float vfpu_dot(float a[4], float b[4]) { +float vfpu_dot(const float a[4], const float b[4]) { static const int EXTRA_BITS = 2; float2int result; float2int src[2]; diff --git a/Core/MIPS/MIPSVFPUUtils.h b/Core/MIPS/MIPSVFPUUtils.h index df1a1b85b0..6506a0664d 100644 --- a/Core/MIPS/MIPSVFPUUtils.h +++ b/Core/MIPS/MIPSVFPUUtils.h @@ -63,7 +63,7 @@ inline float vfpu_clamp(float v, float min, float max) { return v >= max ? max : (v <= min ? min : v); } -float vfpu_dot(float a[4], float b[4]); +float vfpu_dot(const float a[4], const float b[4]); float vfpu_sqrt(float a); float vfpu_rsqrt(float a); diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index f2380c8499..5af118061e 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -220,7 +220,7 @@ void Jit::ApplyPrefixD(const u8 *vregs, VectorSize sz) { // Vector regs can overlap in all sorts of swizzled ways. // This does allow a single overlap in sregs[i]. -bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) { +bool IsOverlapSafeAllowS(int dreg, int di, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = NULL) { for (int i = 0; i < sn; ++i) { if (sregs[i] == dreg && i != di) return false; @@ -234,7 +234,7 @@ bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tr return true; } -bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) { +bool IsOverlapSafe(int dreg, int di, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = NULL) { return IsOverlapSafeAllowS(dreg, di, sn, sregs, tn, tregs) && sregs[di] != dreg; } diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index b8b3722610..ddc752ae21 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -303,7 +303,7 @@ void Draw2D::Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX DrawStrip2D(nullptr, vtx, 4, linear, pipeline, srcWidth, srcHeight, scaleFactor); } -void Draw2D::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW, float texH, int scaleFactor) { +void Draw2D::DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW, float texH, int scaleFactor) { using namespace Draw; _dbg_assert_(pipeline); diff --git a/GPU/Common/Draw2D.h b/GPU/Common/Draw2D.h index bf156e6d39..4d7d728404 100644 --- a/GPU/Common/Draw2D.h +++ b/GPU/Common/Draw2D.h @@ -61,7 +61,7 @@ public: Draw2DPipeline *Create2DPipeline(std::function generate); - void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW = 0.0f, float texH = 0.0f, int scaleFactor = 0); + void DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW = 0.0f, float texH = 0.0f, int scaleFactor = 0); void Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2, float srcWidth, float srcHeight, float dstWidth, float dstHeight, bool linear, int scaleFactor); void Ensure2DResources(); diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index f5579de741..762acf0668 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -132,10 +132,10 @@ std::string DrawEngineCommon::DebugGetVertexLoaderString(std::string id, DebugSh struct Plane { float x, y, z, w; void Set(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } - float Test(float f[3]) const { return x * f[0] + y * f[1] + z * f[2] + w; } + float Test(const float f[3]) const { return x * f[0] + y * f[1] + z * f[2] + w; } }; -static void PlanesFromMatrix(float mtx[16], Plane planes[6]) { +static void PlanesFromMatrix(const float mtx[16], Plane planes[6]) { planes[0].Set(mtx[3]-mtx[0], mtx[7]-mtx[4], mtx[11]-mtx[8], mtx[15]-mtx[12]); // Right planes[1].Set(mtx[3]+mtx[0], mtx[7]+mtx[4], mtx[11]+mtx[8], mtx[15]+mtx[12]); // Left planes[2].Set(mtx[3]+mtx[1], mtx[7]+mtx[5], mtx[11]+mtx[9], mtx[15]+mtx[13]); // Bottom diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 685b70c851..d3bfa8677f 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -50,7 +50,7 @@ #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" -static size_t FormatFramebufferName(VirtualFramebuffer *vfb, char *tag, size_t len) { +static size_t FormatFramebufferName(const VirtualFramebuffer *vfb, char *tag, size_t len) { return snprintf(tag, len, "FB_%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, vfb->bufferWidth, vfb->bufferHeight, GeBufferFormatToString(vfb->fb_format)); } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index b85dc342d7..28cdef056e 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -149,7 +149,7 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) { return 0; } -void SoftwareTransform::SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale) { +void SoftwareTransform::SetProjMatrix(const float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale) { memcpy(&projMatrix_.m, mtx, 16 * sizeof(float)); if (invertedY) { @@ -673,7 +673,7 @@ void SoftwareTransform::CalcCullParams(float &minZValue, float &maxZValue) { std::swap(minZValue, maxZValue); } -void SoftwareTransform::ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { +void SoftwareTransform::ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { // Rectangles always need 2 vertices, disregard the last one if there's an odd number. vertexCount = vertexCount & ~1; numTrans = 0; @@ -734,7 +734,7 @@ void SoftwareTransform::ExpandRectangles(int vertexCount, int &maxIndex, u16 *&i inds = newInds; } -void SoftwareTransform::ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { +void SoftwareTransform::ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { // Lines always need 2 vertices, disregard the last one if there's an odd number. vertexCount = vertexCount & ~1; numTrans = 0; @@ -857,7 +857,7 @@ void SoftwareTransform::ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, inds = newInds; } -void SoftwareTransform::ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { +void SoftwareTransform::ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { numTrans = 0; TransformedVertex *trans = &transformedExpanded[0]; diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index 37dbca399b..480bd18e51 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -65,16 +65,16 @@ public: SoftwareTransform(SoftwareTransformParams ¶ms) : params_(params) { } - void SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale); + void SetProjMatrix(const float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale); void Decode(int prim, u32 vertexType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result); void DetectOffsetTexture(int maxIndex); void BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result); protected: void CalcCullParams(float &minZValue, float &maxZValue); - void ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); - void ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); - void ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); + void ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); + void ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); + void ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); const SoftwareTransformParams ¶ms_; Lin::Matrix4x4 projMatrix_; diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index bbaf0eecde..7e20739eee 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -410,7 +410,7 @@ protected: static CheckAlphaResult CheckCLUTAlpha(const uint8_t *pixelData, GEPaletteFormat clutFmt, int w); - inline u32 QuickTexHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, GETextureFormat format, TexCacheEntry *entry) const { + inline u32 QuickTexHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, GETextureFormat format, const TexCacheEntry *entry) const { if (replacer.Enabled()) { return replacer.ComputeHash(addr, bufw, w, h, format, entry->maxSeenV); } diff --git a/GPU/Common/TextureScalerCommon.cpp b/GPU/Common/TextureScalerCommon.cpp index 257836d4f3..a2662a4c04 100644 --- a/GPU/Common/TextureScalerCommon.cpp +++ b/GPU/Common/TextureScalerCommon.cpp @@ -71,7 +71,7 @@ namespace { // 3x3 convolution with Neumann boundary conditions, parallelizable // quite slow, could be sped up a lot // especially handling of separable kernels -void convolve3x3(u32* data, u32* out, const int kernel[3][3], int width, int height, int l, int u) { +void convolve3x3(const u32 *data, u32 *out, const int kernel[3][3], int width, int height, int l, int u) { for (int yb = 0; yb < (u - l) / BLOCK_SIZE + 1; ++yb) { for (int xb = 0; xb < width / BLOCK_SIZE + 1; ++xb) { for (int y = l + yb*BLOCK_SIZE; y < l + (yb + 1)*BLOCK_SIZE && y < u; ++y) { @@ -92,7 +92,7 @@ void convolve3x3(u32* data, u32* out, const int kernel[3][3], int width, int hei } // deposterization: smoothes posterized gradients from low-color-depth (e.g. 444, 565, compressed) sources -void deposterizeH(u32* data, u32* out, int w, int l, int u) { +void deposterizeH(const u32 *data, u32 *out, int w, int l, int u) { static const int T = 8; for (int y = l; y < u; ++y) { for (int x = 0; x < w; ++x) { @@ -120,7 +120,7 @@ void deposterizeH(u32* data, u32* out, int w, int l, int u) { } } } -void deposterizeV(u32* data, u32* out, int w, int h, int l, int u) { +void deposterizeV(const u32 *data, u32 *out, int w, int h, int l, int u) { static const int T = 8; for (int xb = 0; xb < w / BLOCK_SIZE + 1; ++xb) { for (int y = l; y < u; ++y) { @@ -152,7 +152,7 @@ void deposterizeV(u32* data, u32* out, int w, int h, int l, int u) { // generates a distance mask value for each pixel in data // higher values -> larger distance to the surrounding pixels -void generateDistanceMask(u32* data, u32* out, int width, int height, int l, int u) { +void generateDistanceMask(const u32 *data, u32 *out, int width, int height, int l, int u) { for (int yb = 0; yb < (u - l) / BLOCK_SIZE + 1; ++yb) { for (int xb = 0; xb < width / BLOCK_SIZE + 1; ++xb) { for (int y = l + yb*BLOCK_SIZE; y < l + (yb + 1)*BLOCK_SIZE && y < u; ++y) { @@ -183,7 +183,7 @@ void generateDistanceMask(u32* data, u32* out, int width, int height, int l, int } // mix two images based on a mask -void mix(u32* data, u32* source, u32* mask, u32 maskmax, int width, int l, int u) { +void mix(u32 *data, const u32 *source, const u32 *mask, u32 maskmax, int width, int l, int u) { for (int y = l; y < u; ++y) { for (int x = 0; x < width; ++x) { int pos = y*width + x; @@ -448,7 +448,7 @@ static void upscale_cubic( // End of pasted cubic upscaler. -void scaleBicubicBSpline(int factor, u32* data, u32* out, int w, int h, int l, int u) { +void scaleBicubicBSpline(int factor, const u32 *data, u32 *out, int w, int h, int l, int u) { const float B = 1.0f, C = 0.0f; const int wrap_mode = 1; // Clamp upscale_cubic( @@ -458,7 +458,7 @@ void scaleBicubicBSpline(int factor, u32* data, u32* out, int w, int h, int l, i 0, factor*l, factor*w, factor*u); } -void scaleBicubicMitchell(int factor, u32* data, u32* out, int w, int h, int l, int u) { +void scaleBicubicMitchell(int factor, const u32 *data, u32 *out, int w, int h, int l, int u) { const float B = 0.0f, C = 0.5f; // Actually, Catmull-Rom const int wrap_mode = 1; // Clamp upscale_cubic( @@ -478,7 +478,7 @@ const static u8 BILINEAR_FACTORS[4][3][2] = { }; // integral bilinear upscaling by factor f, horizontal part template -void bilinearHt(u32* data, u32* out, int w, int l, int u) { +void bilinearHt(const u32 *data, u32 *out, int w, int l, int u) { static_assert(f > 1 && f <= 5, "Bilinear scaling only implemented for factors 2 to 5"); int outw = w*f; for (int y = l; y < u; ++y) { @@ -497,7 +497,7 @@ void bilinearHt(u32* data, u32* out, int w, int l, int u) { } } } -void bilinearH(int factor, u32* data, u32* out, int w, int l, int u) { +void bilinearH(int factor, const u32 *data, u32 *out, int w, int l, int u) { switch (factor) { case 2: bilinearHt<2>(data, out, w, l, u); break; case 3: bilinearHt<3>(data, out, w, l, u); break; @@ -509,7 +509,7 @@ void bilinearH(int factor, u32* data, u32* out, int w, int l, int u) { // integral bilinear upscaling by factor f, vertical part // gl/gu == global lower and upper bound template -void bilinearVt(u32* data, u32* out, int w, int gl, int gu, int l, int u) { +void bilinearVt(const u32 *data, u32 *out, int w, int gl, int gu, int l, int u) { static_assert(f>1 && f <= 5, "Bilinear scaling only implemented for 2x, 3x, 4x, and 5x"); int outw = w*f; for (int xb = 0; xb < outw / BLOCK_SIZE + 1; ++xb) { @@ -531,7 +531,7 @@ void bilinearVt(u32* data, u32* out, int w, int gl, int gu, int l, int u) { } } } -void bilinearV(int factor, u32* data, u32* out, int w, int gl, int gu, int l, int u) { +void bilinearV(int factor, const u32 *data, u32 *out, int w, int gl, int gu, int l, int u) { switch (factor) { case 2: bilinearVt<2>(data, out, w, gl, gu, l, u); break; case 3: bilinearVt<3>(data, out, w, gl, gu, l, u); break; diff --git a/GPU/Common/TextureShaderCommon.cpp b/GPU/Common/TextureShaderCommon.cpp index a1ba51de53..b706edae66 100644 --- a/GPU/Common/TextureShaderCommon.cpp +++ b/GPU/Common/TextureShaderCommon.cpp @@ -53,7 +53,7 @@ void TextureShaderCache::DeviceLost() { draw_ = nullptr; } -ClutTexture TextureShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut) { +ClutTexture TextureShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, const u32 *rawClut) { // Simplistic, but works well enough. u32 clutId = clutHash ^ (uint32_t)clutFormat; diff --git a/GPU/Common/TextureShaderCommon.h b/GPU/Common/TextureShaderCommon.h index a11ee81210..d6a6096f09 100644 --- a/GPU/Common/TextureShaderCommon.h +++ b/GPU/Common/TextureShaderCommon.h @@ -44,7 +44,7 @@ public: ~TextureShaderCache(); Draw2DPipeline *GetDepalettizeShader(uint32_t clutMode, GETextureFormat texFormat, GEBufferFormat pixelFormat, bool smoothedDepal, u32 depthUpperBits); - ClutTexture GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut); + ClutTexture GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, const u32 *rawClut); Draw::SamplerState *GetSampler(bool linearFilter); diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 3a77375cba..ca38580d65 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -149,7 +149,7 @@ void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBo *indexUpperBound = (u16)upperBound; } -void PrintDecodedVertex(VertexReader &vtx) { +void PrintDecodedVertex(const VertexReader &vtx) { if (vtx.hasNormal()) { float nrm[3]; vtx.ReadNrm(nrm); diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 33986f382b..a326c0e75e 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -301,7 +301,7 @@ private: int vtype_; }; // Debugging utilities -void PrintDecodedVertex(VertexReader &vtx); +void PrintDecodedVertex(const VertexReader &vtx); class VertexDecoder; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index d7f31b8852..27a42d809b 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -197,7 +197,7 @@ void ShaderManagerDX9::VSSetColorUniform3(int creg, u32 color) { device_->SetVertexShaderConstantF(creg, f, 1); } -void ShaderManagerDX9::VSSetFloatUniform4(int creg, float data[4]) { +void ShaderManagerDX9::VSSetFloatUniform4(int creg, const float data[4]) { device_->SetVertexShaderConstantF(creg, data, 1); } diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index 6ee812b2e6..5dcdddfbce 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -104,7 +104,7 @@ private: void VSSetFloat(int creg, float value); void VSSetFloatArray(int creg, const float *value, int count); void VSSetFloat24Uniform3(int creg, const u32 data[3]); - void VSSetFloatUniform4(int creg, float data[4]); + void VSSetFloatUniform4(int creg, const float data[4]); void Clear(); diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index ba0e650bb6..28c13b871a 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -213,7 +213,7 @@ void GPUgstate::FastLoadBoneMatrix(u32 addr) { gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x00FFFFFF); } -void GPUgstate::Restore(u32_le *ptr) { +void GPUgstate::Restore(const u32_le *ptr) { // Not sure what the first 10 values are, exactly, but these seem right. gstate_c.vertexAddr = ptr[5]; gstate_c.indexAddr = ptr[6]; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index e5acb39a18..bc889e542f 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -445,7 +445,7 @@ struct GPUgstate { void Reset(); void Save(u32_le *ptr); - void Restore(u32_le *ptr); + void Restore(const u32_le *ptr); }; bool vertTypeIsSkinningEnabled(u32 vertType); diff --git a/GPU/Math3D.cpp b/GPU/Math3D.cpp index ecb959ec2c..fec4c887bd 100644 --- a/GPU/Math3D.cpp +++ b/GPU/Math3D.cpp @@ -50,8 +50,7 @@ Vec2 Vec2::WithLength(const float l) const } template<> -float Vec2::Distance2To(Vec2 &other) -{ +float Vec2::Distance2To(const Vec2 &other) const { return Vec2(other-(*this)).Length2(); } @@ -99,8 +98,7 @@ Vec3 Vec3::WithLength(const float l) const } template<> -float Vec3::Distance2To(Vec3 &other) -{ +float Vec3::Distance2To(const Vec3 &other) const { return Vec3(other-(*this)).Length2(); } @@ -231,8 +229,7 @@ Vec3Packed Vec3Packed::WithLength(const float l) const } template<> -float Vec3Packed::Distance2To(Vec3Packed &other) -{ +float Vec3Packed::Distance2To(const Vec3Packed &other) const { return Vec3Packed(other-(*this)).Length2(); } @@ -279,8 +276,7 @@ Vec4 Vec4::WithLength(const float l) const } template<> -float Vec4::Distance2To(Vec4 &other) -{ +float Vec4::Distance2To(const Vec4 &other) const { return Vec4(other-(*this)).Length2(); } diff --git a/GPU/Math3D.h b/GPU/Math3D.h index b3a94ba56c..88a62c72da 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -145,7 +145,7 @@ public: float Length() const; void SetLength(const float l); Vec2 WithLength(const float l) const; - float Distance2To(Vec2 &other); + float Distance2To(const Vec2 &other) const; Vec2 Normalized() const; float Normalize(); // returns the previous length, which is often useful @@ -310,7 +310,7 @@ public: float Length() const; void SetLength(const float l); Vec3 WithLength(const float l) const; - float Distance2To(Vec3 &other); + float Distance2To(const Vec3 &other) const; Vec3 Normalized(bool useSSE4 = false) const; Vec3 NormalizedOr001(bool useSSE4 = false) const; float Normalize(); // returns the previous length, which is often useful @@ -478,7 +478,7 @@ public: float Length() const; void SetLength(const float l); Vec3Packed WithLength(const float l) const; - float Distance2To(Vec3Packed &other); + float Distance2To(const Vec3Packed &other) const; Vec3Packed Normalized() const; float Normalize(); // returns the previous length, which is often useful @@ -674,7 +674,7 @@ public: float Length() const; void SetLength(const float l); Vec4 WithLength(const float l) const; - float Distance2To(Vec4 &other); + float Distance2To(const Vec4 &other) const; Vec4 Normalized() const; float Normalize(); // returns the previous length, which is often useful diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 7906cbe79f..1978d32edc 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -333,7 +333,7 @@ void BinManager::MarkPendingWrites(const Rasterizer::RasterizerState &state) { pendingWrites_[1].Expand(gstate.getDepthBufAddress() & mirrorMask, 2, gstate.DepthBufStride(), scissorTL, scissorBR); } -inline void BinDirtyRange::Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, DrawingCoords &tl, DrawingCoords &br) { +inline void BinDirtyRange::Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, const DrawingCoords &tl, const DrawingCoords &br) { const uint32_t w = br.x - tl.x + 1; const uint32_t h = br.y - tl.y + 1; diff --git a/GPU/Software/BinManager.h b/GPU/Software/BinManager.h index 9252d835cc..116fb19e27 100644 --- a/GPU/Software/BinManager.h +++ b/GPU/Software/BinManager.h @@ -177,7 +177,7 @@ struct BinDirtyRange { uint32_t widthBytes; uint32_t height; - void Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, DrawingCoords &tl, DrawingCoords &br); + void Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, const DrawingCoords &tl, const DrawingCoords &br); }; class BinManager { diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index 32596989fe..82315b1b20 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -24,7 +24,7 @@ namespace Lighting { -static inline Vec3f GetLightVec(u32 lparams[12], int light) { +static inline Vec3f GetLightVec(const u32 lparams[12], int light) { #if defined(_M_SSE) && !PPSSPP_ARCH(X86) __m128i values = _mm_loadu_si128((__m128i *)&lparams[3 * light]); __m128i from24 = _mm_slli_epi32(values, 8); diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index b7c9401219..e109f6d87a 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -335,7 +335,7 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { state->roundToScreen = &ClipToScreenInternal; } -ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformState &state) { +ClipVertexData TransformUnit::ReadVertex(const VertexReader &vreader, const TransformState &state) { PROFILE_THIS_SCOPE("read_vert"); // If we ever thread this, we'll have to change this. ClipVertexData vertex; diff --git a/GPU/Software/TransformUnit.h b/GPU/Software/TransformUnit.h index 5ed9994f92..ed7476a13b 100644 --- a/GPU/Software/TransformUnit.h +++ b/GPU/Software/TransformUnit.h @@ -149,7 +149,7 @@ public: SoftDirty GetDirty(); private: - ClipVertexData ReadVertex(VertexReader &vreader, const TransformState &state); + ClipVertexData ReadVertex(const VertexReader &vreader, const TransformState &state); void SendTriangle(CullType cullType, const ClipVertexData *verts, int provoking = 2); u8 *decoded_ = nullptr; diff --git a/UI/ComboKeyMappingScreen.cpp b/UI/ComboKeyMappingScreen.cpp index d4c8a814b6..4af85552c1 100644 --- a/UI/ComboKeyMappingScreen.cpp +++ b/UI/ComboKeyMappingScreen.cpp @@ -271,7 +271,7 @@ void ComboKeyScreen::CreateViews() { } } -static uint64_t arrayToInt(bool ary[ARRAY_SIZE(CustomKey::comboKeyList)]) { +static uint64_t arrayToInt(const bool ary[ARRAY_SIZE(CustomKey::comboKeyList)]) { uint64_t value = 0; for (int i = ARRAY_SIZE(CustomKey::comboKeyList)-1; i >= 0; i--) { value |= ary[i] ? 1 : 0; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 4bcfb1cb83..d1dbb2dd1b 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -354,7 +354,7 @@ void DrawBackground(UIContext &dc, float alpha, float x, float y, float z) { } } -uint32_t GetBackgroundColorWithAlpha(UIContext &dc) { +uint32_t GetBackgroundColorWithAlpha(const UIContext &dc) { return colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.65f); // 0.65 = 166 = A6 } @@ -407,7 +407,7 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f } } -void HandleCommonMessages(const char *message, const char *value, ScreenManager *manager, Screen *activeScreen) { +void HandleCommonMessages(const char *message, const char *value, ScreenManager *manager, const Screen *activeScreen) { bool isActiveScreen = manager->topScreen() == activeScreen; if (!strcmp(message, "clear jit") && PSP_IsInited()) { @@ -1070,7 +1070,7 @@ SettingInfoMessage::SettingInfoMessage(int align, UI::AnchorLayoutParams *lp) Add(new UI::Spacer(10.0f)); } -void SettingInfoMessage::Show(const std::string &text, UI::View *refView) { +void SettingInfoMessage::Show(const std::string &text, const UI::View *refView) { if (refView) { Bounds b = refView->GetBounds(); const UI::AnchorLayoutParams *lp = GetLayoutParams()->As(); diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 32fe101973..f91cfa6bfe 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -179,7 +179,7 @@ public: void SetBottomCutoff(float y) { cutOffY_ = y; } - void Show(const std::string &text, UI::View *refView = nullptr); + void Show(const std::string &text, const UI::View *refView = nullptr); void Draw(UIContext &dc) override; std::string GetText() const; @@ -191,4 +191,4 @@ private: bool showing_ = false; }; -uint32_t GetBackgroundColorWithAlpha(UIContext &dc); +uint32_t GetBackgroundColorWithAlpha(const UIContext &dc); diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 7faf3b6f2b..a179749ecf 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -332,8 +332,7 @@ void CtrlDisAsmView::assembleOpcode(u32 address, std::string defaultText) } -void CtrlDisAsmView::drawBranchLine(HDC hdc, std::map& addressPositions, BranchLine& line) -{ +void CtrlDisAsmView::drawBranchLine(HDC hdc, std::map &addressPositions, const BranchLine &line) { HPEN pen; u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows); diff --git a/Windows/Debugger/CtrlDisAsmView.h b/Windows/Debugger/CtrlDisAsmView.h index 9d58de1935..2930e41544 100644 --- a/Windows/Debugger/CtrlDisAsmView.h +++ b/Windows/Debugger/CtrlDisAsmView.h @@ -72,7 +72,7 @@ class CtrlDisAsmView void calculatePixelPositions(); bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData); void updateStatusBarText(); - void drawBranchLine(HDC hdc, std::map& addressPositions, BranchLine& line); + void drawBranchLine(HDC hdc, std::map &addressPositions, const BranchLine &line); void copyInstructions(u32 startAddr, u32 endAddr, bool withDisasm); std::set getSelectedLineArguments(); void drawArguments(HDC hdc, const DisassemblyLineInfo &line, int x, int y, int textColor, const std::set ¤tArguments); diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index c23efbcf88..b9853c1a79 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -251,7 +251,7 @@ namespace WindowsRawInput { return windowsTransTable[vKey]; } - void ProcessKeyboard(RAWINPUT *raw, bool foreground) { + void ProcessKeyboard(const RAWINPUT *raw, bool foreground) { if (menuActive && UpdateMenuActive()) { // Ignore keyboard input while a menu is active, it's probably interacting with the menu. return; @@ -302,7 +302,7 @@ namespace WindowsRawInput { return true; } - void ProcessMouse(HWND hWnd, RAWINPUT *raw, bool foreground) { + void ProcessMouse(HWND hWnd, const RAWINPUT *raw, bool foreground) { if (menuActive && UpdateMenuActive()) { // Ignore mouse input while a menu is active, it's probably interacting with the menu. return; diff --git a/unittest/TestArm64Emitter.cpp b/unittest/TestArm64Emitter.cpp index af0f37ca45..a795cfbb2f 100644 --- a/unittest/TestArm64Emitter.cpp +++ b/unittest/TestArm64Emitter.cpp @@ -8,7 +8,7 @@ #include "UnitTest.h" -static bool CheckLast(Arm64Gen::ARM64XEmitter &emit, const char *comp) { +static bool CheckLast(const Arm64Gen::ARM64XEmitter &emit, const char *comp) { u32 instr; memcpy(&instr, emit.GetCodePointer() - 4, 4); char disasm[512]; diff --git a/unittest/TestArmEmitter.cpp b/unittest/TestArmEmitter.cpp index 8932ba7c9c..848655058a 100644 --- a/unittest/TestArmEmitter.cpp +++ b/unittest/TestArmEmitter.cpp @@ -10,7 +10,7 @@ #include "UnitTest.h" -static bool CheckLast(ArmGen::ARMXEmitter &emit, const char *comp) { +static bool CheckLast(const ArmGen::ARMXEmitter &emit, const char *comp) { u32 instr; memcpy(&instr, emit.GetCodePointer() - 4, 4); char disasm[512]; diff --git a/unittest/TestX64Emitter.cpp b/unittest/TestX64Emitter.cpp index c92b415d12..14f1a003c2 100644 --- a/unittest/TestX64Emitter.cpp +++ b/unittest/TestX64Emitter.cpp @@ -14,13 +14,13 @@ static const u8 *prevStart = NULL; -bool CheckLast(Gen::XEmitter &emit, const char *comp) { +static bool CheckLast(const Gen::XEmitter &emit, const char *comp) { auto vec = DisassembleX86(prevStart, (int)(emit.GetCodePointer() - prevStart)); EXPECT_EQ_STR(vec[0], std::string(comp)); return true; } -void PrintLast(Gen::XEmitter &emit) { +static void PrintLast(const Gen::XEmitter &emit) { for (const u8 *p = prevStart; p < emit.GetCodePointer(); p++) { printf("%02x ", *p); } From 9cfcbc46e6bcd585916732c027fe844ffae060bd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 21:09:50 -0800 Subject: [PATCH 662/715] Global: Cleanup initialization/pointer checks. Cleaning up a lot of cases of uninitialized data, unchecked return values for failures, and similar. --- Common/Arm64Emitter.h | 2 +- Common/ArmEmitter.h | 29 ++++++------- Common/CPUDetect.cpp | 5 ++- Common/ConsoleListener.h | 4 +- Common/Data/Format/JSONReader.h | 8 ++-- Common/File/FileUtil.cpp | 5 ++- Common/GPU/D3D11/thin3d_d3d11.cpp | 6 ++- Common/GPU/D3D9/thin3d_d3d9.cpp | 9 ++-- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 9 ++-- Common/GPU/Vulkan/thin3d_vulkan.cpp | 12 ++---- Common/Math/expression_parser.cpp | 4 +- Common/Net/HTTPClient.cpp | 2 +- Common/Render/Text/draw_text_win.cpp | 1 + Common/RiscVEmitter.h | 2 +- Common/UI/ViewGroup.cpp | 2 +- Core/Debugger/DisassemblyManager.cpp | 2 +- Core/Debugger/SymbolMap.cpp | 8 ++-- Core/ELF/ElfReader.cpp | 6 +-- Core/FileSystems/MetaFileSystem.h | 2 +- Core/HLE/sceIo.cpp | 5 ++- Core/HW/Camera.cpp | 6 ++- Core/MIPS/IR/IRCompVFPU.cpp | 4 +- Core/Util/BlockAllocator.cpp | 1 + Core/Util/PortManager.cpp | 6 +++ GPU/Common/TextureShaderCommon.cpp | 2 +- GPU/D3D11/DrawEngineD3D11.cpp | 55 +++++++++++++++++-------- GPU/D3D11/TextureCacheD3D11.cpp | 6 ++- GPU/Debugger/Record.cpp | 2 + Windows/DSoundStream.cpp | 2 + Windows/Debugger/Debugger_Disasm.cpp | 4 +- Windows/Debugger/DumpMemoryWindow.cpp | 4 +- Windows/GPU/WindowsGLContext.h | 3 -- Windows/MainWindow.cpp | 2 +- Windows/RawInput.cpp | 10 ++++- Windows/TouchInputHandler.cpp | 15 +++---- Windows/W32Util/Misc.cpp | 12 +++--- Windows/W32Util/ShellUtil.cpp | 8 +++- Windows/WASAPIStream.cpp | 21 ++++++---- Windows/WindowsHost.cpp | 14 ++++--- Windows/XinputDevice.cpp | 6 +-- Windows/main.cpp | 22 ++++------ 41 files changed, 190 insertions(+), 138 deletions(-) diff --git a/Common/Arm64Emitter.h b/Common/Arm64Emitter.h index 66add4e269..aaeb24fb1d 100644 --- a/Common/Arm64Emitter.h +++ b/Common/Arm64Emitter.h @@ -253,7 +253,7 @@ public: private: ARM64Reg m_destReg; WidthSpecifier m_width; - ExtendSpecifier m_extend; + ExtendSpecifier m_extend = EXTEND_UXTB; TypeSpecifier m_type; ShiftType m_shifttype; u32 m_shift; diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index d71c1efdf2..46a36c8805 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -112,32 +112,29 @@ private: OpType Type; // IMM types - u8 Rotation; // Only for u8 values + u8 Rotation = 0; // Only for u8 values // Register types - u8 IndexOrShift; - ShiftType Shift; + u8 IndexOrShift = 0; + ShiftType Shift = ST_LSL; public: - OpType GetType() const - { + OpType GetType() const { return Type; } - Operand2() {} - Operand2(u32 imm, OpType type = TYPE_IMM) - { - Type = type; - Value = imm; - Rotation = 0; + Operand2() { + Type = TYPE_IMM; + Value = 0; + } + Operand2(u32 imm, OpType type = TYPE_IMM) { + Type = type; + Value = imm; } - Operand2(ARMReg Reg) - { + Operand2(ARMReg Reg) { Type = TYPE_REG; Value = Reg; - Rotation = 0; } - Operand2(u8 imm, u8 rotation) - { + Operand2(u8 imm, u8 rotation) { Type = TYPE_IMM; Value = imm; Rotation = rotation; diff --git a/Common/CPUDetect.cpp b/Common/CPUDetect.cpp index 262bbf4def..ebf78012b6 100644 --- a/Common/CPUDetect.cpp +++ b/Common/CPUDetect.cpp @@ -321,7 +321,10 @@ void CPUInfo::Detect() { #if PPSSPP_PLATFORM(WINDOWS) #if !PPSSPP_PLATFORM(UWP) typedef BOOL (WINAPI *getLogicalProcessorInformationEx_f)(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, PDWORD ReturnedLength); - auto getLogicalProcessorInformationEx = (getLogicalProcessorInformationEx_f)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetLogicalProcessorInformationEx"); + getLogicalProcessorInformationEx_f getLogicalProcessorInformationEx = nullptr; + HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); + if (kernel32) + getLogicalProcessorInformationEx = (getLogicalProcessorInformationEx_f)GetProcAddress(kernel32, "GetLogicalProcessorInformationEx"); #else void *getLogicalProcessorInformationEx = nullptr; #endif diff --git a/Common/ConsoleListener.h b/Common/ConsoleListener.h index 32a32b7981..99c6730750 100644 --- a/Common/ConsoleListener.h +++ b/Common/ConsoleListener.h @@ -66,8 +66,8 @@ private: static std::atomic logPendingReadPos; static std::atomic logPendingWritePos; - int openWidth_; - int openHeight_; + int openWidth_ = 0; + int openHeight_ = 0; std::wstring title_; #endif bool bHidden; diff --git a/Common/Data/Format/JSONReader.h b/Common/Data/Format/JSONReader.h index 4156650301..792d6a669a 100644 --- a/Common/Data/Format/JSONReader.h +++ b/Common/Data/Format/JSONReader.h @@ -47,9 +47,11 @@ public: JsonReader(const std::string &filename); JsonReader(const void *data, size_t size) { buffer_ = (char *)malloc(size + 1); - memcpy(buffer_, data, size); - buffer_[size] = 0; - parse(); + if (buffer_) { + memcpy(buffer_, data, size); + buffer_[size] = 0; + parse(); + } } JsonReader(const JsonNode *node) { ok_ = true; diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index 8bab82ae6e..e8088e90bc 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -141,7 +141,7 @@ FILE *OpenCFile(const Path &path, const char *mode) { return nullptr; } FILE *f = fdopen(descriptor, "wb"); - if (!strcmp(mode, "at") || !strcmp(mode, "a")) { + if (f && (!strcmp(mode, "at") || !strcmp(mode, "a"))) { // Append mode. fseek(f, 0, SEEK_END); } @@ -250,7 +250,8 @@ static bool ResolvePathVista(const std::wstring &path, wchar_t *buf, DWORD bufSi #else if (!getFinalPathNameByHandleW) { HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); - getFinalPathNameByHandleW = (getFinalPathNameByHandleW_f)GetProcAddress(kernel32, "GetFinalPathNameByHandleW"); + if (kernel32) + getFinalPathNameByHandleW = (getFinalPathNameByHandleW_f)GetProcAddress(kernel32, "GetFinalPathNameByHandleW"); } #endif diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 43e6c2b653..faafc4998e 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -1476,6 +1476,7 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x dstTex = dst->depthStencilTex; break; } + _assert_(srcTex && dstTex); // TODO: Check for level too! if (width == src->Width() && width == dst->Width() && height == src->Height() && height == dst->Height() && x == 0 && y == 0 && z == 0 && dstX == 0 && dstY == 0 && dstZ == 0) { @@ -1534,7 +1535,7 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel bool useGlobalPacktex = (bx + bw <= 512 && by + bh <= 512) && channelBits == FB_COLOR_BIT; - ID3D11Texture2D *packTex; + ID3D11Texture2D *packTex = nullptr; if (!useGlobalPacktex) { D3D11_TEXTURE2D_DESC packDesc{}; packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; @@ -1573,6 +1574,9 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel packTex = packTexture_; } + if (!packTex) + return false; + D3D11_BOX srcBox{ (UINT)bx, (UINT)by, 0, (UINT)(bx + bw), (UINT)(by + bh), 1 }; DataFormat srcFormat = DataFormat::UNDEFINED; switch (channelBits) { diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 94bce31760..bc0135e834 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -1072,16 +1072,16 @@ void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offse return; } if (buf->vbuffer_) { - void *ptr; + void *ptr = nullptr; HRESULT res = buf->vbuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0); - if (!FAILED(res)) { + if (!FAILED(res) && ptr) { memcpy(ptr, data, size); buf->vbuffer_->Unlock(); } } else if (buf->ibuffer_) { - void *ptr; + void *ptr = nullptr; HRESULT res = buf->ibuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0); - if (!FAILED(res)) { + if (!FAILED(res) && ptr) { memcpy(ptr, data, size); buf->ibuffer_->Unlock(); } @@ -1438,6 +1438,7 @@ bool D3D9Context::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, LPDIRECT3DSURFACE9 offscreen = nullptr; HRESULT hr = E_UNEXPECTED; + _assert_(fb != nullptr); if (channelBits == FB_COLOR_BIT) { fb->tex->GetLevelDesc(0, &desc); diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index ec38cabecd..53f5615931 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1324,7 +1324,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c { VKRGraphicsPipeline *graphicsPipeline = c.graphics_pipeline.pipeline; if (graphicsPipeline != lastGraphicsPipeline) { - VkSampleCountFlagBits fbSampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; + VkSampleCountFlagBits fbSampleCount = fb ? fb->sampleCount : VK_SAMPLE_COUNT_1_BIT; if (RenderPassTypeHasMultisample(rpType) && fbSampleCount != graphicsPipeline->SampleCount()) { // should have been invalidated. @@ -1421,12 +1421,13 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c case VKRRenderCommand::SELF_DEPENDENCY_BARRIER: { _assert_(step.render.pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT); + _assert_(fb); VulkanBarrier barrier; - if (step.render.framebuffer->sampleCount != VK_SAMPLE_COUNT_1_BIT) { + if (fb->sampleCount != VK_SAMPLE_COUNT_1_BIT) { // Rendering is happening to the multisample buffer, not the color buffer. - SelfDependencyBarrier(step.render.framebuffer->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + SelfDependencyBarrier(fb->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); } else { - SelfDependencyBarrier(step.render.framebuffer->color, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + SelfDependencyBarrier(fb->color, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); } barrier.Flush(cmd); break; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index bb57abdea4..4cc760f429 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1184,16 +1184,12 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char } } - if (input) { - for (int i = 0; i < (int)input->bindings.size(); i++) { - pipeline->stride[i] = input->bindings[i].stride; - } - } else { - pipeline->stride[0] = 0; - } - _dbg_assert_(input->bindings.size() == 1); + _dbg_assert_(input && input->bindings.size() == 1); _dbg_assert_((int)input->attributes.size() == (int)input->visc.vertexAttributeDescriptionCount); + for (int i = 0; i < (int)input->bindings.size(); i++) { + pipeline->stride[i] = input->bindings[i].stride; + } gDesc.ibd = input->bindings[0]; for (size_t i = 0; i < input->attributes.size(); i++) { gDesc.attrs[i] = input->attributes[i]; diff --git a/Common/Math/expression_parser.cpp b/Common/Math/expression_parser.cpp index 75e0720c60..b591845bce 100644 --- a/Common/Math/expression_parser.cpp +++ b/Common/Math/expression_parser.cpp @@ -406,8 +406,8 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, size_t num = 0; uint32_t opcode; std::vector valueStack; - unsigned int arg[5]; - float fArg[5]; + unsigned int arg[5]{}; + float fArg[5]{}; bool useFloat = false; while (num < exp.size()) diff --git a/Common/Net/HTTPClient.cpp b/Common/Net/HTTPClient.cpp index fec31dabb8..bac18da12d 100644 --- a/Common/Net/HTTPClient.cpp +++ b/Common/Net/HTTPClient.cpp @@ -224,7 +224,7 @@ void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength, float *prog inbuffer->TakeLineCRLF(&line); if (!line.size()) return; - unsigned int chunkSize; + unsigned int chunkSize = 0; sscanf(line.c_str(), "%x", &chunkSize); if (chunkSize) { std::string data; diff --git a/Common/Render/Text/draw_text_win.cpp b/Common/Render/Text/draw_text_win.cpp index d5af5af762..6cd9885fee 100644 --- a/Common/Render/Text/draw_text_win.cpp +++ b/Common/Render/Text/draw_text_win.cpp @@ -69,6 +69,7 @@ TextDrawerWin32::TextDrawerWin32(Draw::DrawContext *draw) : TextDrawer(draw), ct bmi.bmiHeader.biBitCount = 32; ctx_->hbmBitmap = CreateDIBSection(ctx_->hDC, &bmi, DIB_RGB_COLORS, (VOID**)&ctx_->pBitmapBits, NULL, 0); + _assert_(ctx_->hbmBitmap != nullptr); SetMapMode(ctx_->hDC, MM_TEXT); SelectObject(ctx_->hDC, ctx_->hbmBitmap); diff --git a/Common/RiscVEmitter.h b/Common/RiscVEmitter.h index f2e512a32c..e1b8266a56 100644 --- a/Common/RiscVEmitter.h +++ b/Common/RiscVEmitter.h @@ -113,7 +113,7 @@ struct FixupBranch { ~FixupBranch(); const u8 *ptr = nullptr; - FixupBranchType type; + FixupBranchType type = FixupBranchType::B; }; class RiscVEmitter { diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index de556ad5d9..f7b6f49d11 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -963,7 +963,7 @@ bool ScrollView::SubviewFocused(View *view) { float visibleSize = orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w; float visibleEnd = scrollPos_ + visibleSize; - float viewStart, viewEnd; + float viewStart = 0.0f, viewEnd = 0.0f; switch (orientation_) { case ORIENT_HORIZONTAL: viewStart = layoutScrollPos_ + vBounds.x - bounds_.x; diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp index b57e52610d..667ba134ab 100644 --- a/Core/Debugger/DisassemblyManager.cpp +++ b/Core/Debugger/DisassemblyManager.cpp @@ -122,7 +122,7 @@ void parseDisasm(const char* disasm, char* opcode, char* arguments, bool insertS // parse symbol if (disasm == jumpAddress) { - u32 branchTarget; + u32 branchTarget = 0; sscanf(disasm+3,"%08x",&branchTarget); const std::string addressSymbol = g_symbolMap->GetLabelString(branchTarget); diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp index 63e087d7a8..93a3d238e2 100644 --- a/Core/Debugger/SymbolMap.cpp +++ b/Core/Debugger/SymbolMap.cpp @@ -127,9 +127,9 @@ bool SymbolMap::LoadSymbolMap(const Path &filename) { if (!started) continue; - u32 address = -1, size, vaddress = -1; + u32 address = -1, size = 0, vaddress = -1; int moduleIndex = 0; - int typeInt; + int typeInt = ST_NONE; SymbolType type; char name[128] = {0}; @@ -145,7 +145,9 @@ bool SymbolMap::LoadSymbolMap(const Path &filename) { continue; } - sscanf(line, "%08x %08x %x %i %127c", &address, &size, &vaddress, &typeInt, name); + int matched = sscanf(line, "%08x %08x %x %i %127c", &address, &size, &vaddress, &typeInt, name); + if (matched < 1) + continue; type = (SymbolType) typeInt; if (!hasModules) { if (!Memory::IsValidAddress(vaddress)) { diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index a4a6bfb856..2baf2690d6 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -128,7 +128,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { if (log) { DEBUG_LOG(LOADER, "rel at: %08x info: %08x type: %i", addr, info, type); } - u32 relocateTo = segmentVAddr[relative]; + u32 relocateTo = relative >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[relative]; switch (type) { case R_MIPS_32: @@ -289,9 +289,9 @@ void ElfReader::LoadRelocations2(int rel_seg) } }else{ addr_seg = seg; - relocate_to = segmentVAddr[addr_seg]; + relocate_to = addr_seg >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[addr_seg]; if (!Memory::IsValidAddress(relocate_to)) { - ERROR_LOG(LOADER, "ELF: Bad address to relocate to: %08x", relocate_to); + ERROR_LOG(LOADER, "ELF: Bad address to relocate to: %08x (segment %d)", relocate_to, addr_seg); continue; } diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index 545f21bddc..e574423dd6 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -91,7 +91,7 @@ public: int MapFilePath(const std::string &inpath, std::string &outpath, MountPoint **system); inline int MapFilePath(const std::string &_inpath, std::string &outpath, IFileSystem **system) { - MountPoint *mountPoint; + MountPoint *mountPoint = nullptr; int error = MapFilePath(_inpath, outpath, &mountPoint); if (error == 0) { *system = mountPoint->system.get(); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index e6fbd166e7..d2cf9ec311 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -271,8 +271,9 @@ public: if (p.mode == p.MODE_READ) { pgdInfo = (PGD_DESC*) malloc(sizeof(PGD_DESC)); } - p.DoVoid(pgdInfo, sizeof(PGD_DESC)); - if (p.mode == p.MODE_READ) { + if (pgdInfo) + p.DoVoid(pgdInfo, sizeof(PGD_DESC)); + if (p.mode == p.MODE_READ && pgdInfo) { pgdInfo->block_buf = (u8 *)malloc(pgdInfo->block_size * 2); } } diff --git a/Core/HW/Camera.cpp b/Core/HW/Camera.cpp index 3b99eab646..9cf8138e21 100644 --- a/Core/HW/Camera.cpp +++ b/Core/HW/Camera.cpp @@ -60,7 +60,11 @@ void convert_frame(int inw, int inh, unsigned char *inData, AVPixelFormat inForm void __cameraDummyImage(int width, int height, unsigned char** outData, int* outLen) { #ifdef USE_FFMPEG - unsigned char* rgbData = (unsigned char*)malloc(3 * width * height); + unsigned char *rgbData = (unsigned char *)malloc(3 * width * height); + if (!rgbData) { + *outData = nullptr; + return; + } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { rgbData[3 * (y * width + x) + 0] = x*255/width; diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 11050c44cc..bfdcf69bed 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -184,7 +184,7 @@ namespace MIPSComp { return; int n = GetNumVectorElements(sz); - u8 origV[4]; + u8 origV[4]{}; static const float constantArray[8] = { 0.f, 1.f, 2.f, 0.5f, 3.f, 1.f / 3.f, 0.25f, 1.f / 6.f }; for (int i = 0; i < n; i++) @@ -1697,7 +1697,7 @@ namespace MIPSComp { GetVectorRegs(tregs, sz, _VT); GetVectorRegs(dregs, sz, _VD); - u8 tempregs[4]; + u8 tempregs[4]{}; for (int i = 0; i < n; ++i) { if (!IsOverlapSafe(dregs[i], n, sregs, n, tregs)) { tempregs[i] = IRVTEMP_PFX_T + i; // using IRTEMP0 for other things diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index 696a43513d..270cca6508 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -462,6 +462,7 @@ void BlockAllocator::DoState(PointerWrap &p) } else { + _assert_(bottom_ != nullptr); for (const Block *bp = bottom_; bp != NULL; bp = bp->next) ++count; Do(p, count); diff --git a/Core/Util/PortManager.cpp b/Core/Util/PortManager.cpp index 79120053c8..b0c2bfe487 100644 --- a/Core/Util/PortManager.cpp +++ b/Core/Util/PortManager.cpp @@ -127,7 +127,13 @@ bool PortManager::Initialize(const unsigned int timeout) { m_leaseDuration = "43200"; // 12 hours m_InitState = UPNP_INITSTATE_BUSY; urls = (UPNPUrls*)malloc(sizeof(struct UPNPUrls)); + if (!urls) + return false; datas = (IGDdatas*)malloc(sizeof(struct IGDdatas)); + if (!datas) { + free(urls); + return false; + } memset(urls, 0, sizeof(struct UPNPUrls)); memset(datas, 0, sizeof(struct IGDdatas)); diff --git a/GPU/Common/TextureShaderCommon.cpp b/GPU/Common/TextureShaderCommon.cpp index b706edae66..93428a2238 100644 --- a/GPU/Common/TextureShaderCommon.cpp +++ b/GPU/Common/TextureShaderCommon.cpp @@ -233,7 +233,7 @@ std::vector TextureShaderCache::DebugGetShaderIDs(DebugShaderType t } std::string TextureShaderCache::DebugGetShaderString(std::string idstr, DebugShaderType type, DebugShaderStringType stringType) { - uint32_t id; + uint32_t id = 0; sscanf(idstr.c_str(), "%08x", &id); auto iter = depalCache_.find(id); if (iter == depalCache_.end()) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 304d325ea9..87b7d866b8 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -760,6 +760,14 @@ TessellationDataTransferD3D11::~TessellationDataTransferD3D11() { } } +template +static void DoRelease(T *&ptr) { + if (ptr) { + ptr->Release(); + ptr = nullptr; + } +} + void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { struct TessData { float pos[3]; float pad1; @@ -769,19 +777,24 @@ void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const * int size = size_u * size_v; - if (prevSize < size) { + if (prevSize < size || !buf[0]) { prevSize = size; - if (buf[0]) buf[0]->Release(); - if (view[0]) view[0]->Release(); + DoRelease(buf[0]); + DoRelease(view[0]); desc.ByteWidth = size * sizeof(TessData); desc.StructureByteStride = sizeof(TessData); device_->CreateBuffer(&desc, nullptr, &buf[0]); - device_->CreateShaderResourceView(buf[0], nullptr, &view[0]); + if (buf[0]) + device_->CreateShaderResourceView(buf[0], nullptr, &view[0]); + if (!buf[0] || !view[0]) + return; context_->VSSetShaderResources(0, 1, &view[0]); } - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(buf[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + D3D11_MAPPED_SUBRESOURCE map{}; + HRESULT hr = context_->Map(buf[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + if (FAILED(hr)) + return; uint8_t *data = (uint8_t *)map.pData; float *pos = (float *)(data); @@ -796,34 +809,42 @@ void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const * using Spline::Weight; // Weights U - if (prevSizeWU < weights.size_u) { + if (prevSizeWU < weights.size_u || !buf[1]) { prevSizeWU = weights.size_u; - if (buf[1]) buf[1]->Release(); - if (view[1]) view[1]->Release(); + DoRelease(buf[1]); + DoRelease(view[1]); desc.ByteWidth = weights.size_u * sizeof(Weight); desc.StructureByteStride = sizeof(Weight); device_->CreateBuffer(&desc, nullptr, &buf[1]); - device_->CreateShaderResourceView(buf[1], nullptr, &view[1]); + if (buf[1]) + device_->CreateShaderResourceView(buf[1], nullptr, &view[1]); + if (!buf[1] || !view[1]) + return; context_->VSSetShaderResources(1, 1, &view[1]); } - context_->Map(buf[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, weights.u, weights.size_u * sizeof(Weight)); + hr = context_->Map(buf[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + if (SUCCEEDED(hr)) + memcpy(map.pData, weights.u, weights.size_u * sizeof(Weight)); context_->Unmap(buf[1], 0); // Weights V if (prevSizeWV < weights.size_v) { prevSizeWV = weights.size_v; - if (buf[2]) buf[2]->Release(); - if (view[2]) view[2]->Release(); + DoRelease(buf[2]); + DoRelease(view[2]); desc.ByteWidth = weights.size_v * sizeof(Weight); desc.StructureByteStride = sizeof(Weight); device_->CreateBuffer(&desc, nullptr, &buf[2]); - device_->CreateShaderResourceView(buf[2], nullptr, &view[2]); + if (buf[2]) + device_->CreateShaderResourceView(buf[2], nullptr, &view[2]); + if (!buf[2] || !view[2]) + return; context_->VSSetShaderResources(2, 1, &view[2]); } - context_->Map(buf[2], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, weights.v, weights.size_v * sizeof(Weight)); + hr = context_->Map(buf[2], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + if (SUCCEEDED(hr)) + memcpy(map.pData, weights.v, weights.size_v * sizeof(Weight)); context_->Unmap(buf[2], 0); } diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 486ad9417f..b8e799b476 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -314,7 +314,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { // We don't yet have mip generation, so clamp the number of levels to the ones we can load directly. levels = std::min(plan.levelsToCreate, plan.levelsToLoad); - ID3D11Texture2D *tex; + ID3D11Texture2D *tex = nullptr; D3D11_TEXTURE2D_DESC desc{}; desc.CPUAccessFlags = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -329,7 +329,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { ASSERT_SUCCESS(device_->CreateTexture2D(&desc, nullptr, &tex)); texture = tex; } else { - ID3D11Texture3D *tex; + ID3D11Texture3D *tex = nullptr; D3D11_TEXTURE3D_DESC desc{}; desc.CPUAccessFlags = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -504,6 +504,8 @@ bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level ID3D11Texture2D *stagingCopy = nullptr; device_->CreateTexture2D(&desc, nullptr, &stagingCopy); + if (!stagingCopy) + return false; context_->CopyResource(stagingCopy, texture); D3D11_MAPPED_SUBRESOURCE map; diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index e5fa0b7d1d..391b031974 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -373,6 +373,8 @@ static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) { bool isDrawnVRAM = false; uint32_t start = (addr >> DIRTY_VRAM_SHIFT) & DIRTY_VRAM_MASK; uint32_t blocks = (sizeInRAM + DIRTY_VRAM_ROUND) >> DIRTY_VRAM_SHIFT; + if (start + blocks >= DIRTY_VRAM_SIZE) + return 0; bool startEven = (addr & DIRTY_VRAM_ROUND) == 0; bool endEven = ((addr + sizeInRAM) & DIRTY_VRAM_ROUND) == 0; for (uint32_t i = 0; i < blocks; ++i) { diff --git a/Windows/DSoundStream.cpp b/Windows/DSoundStream.cpp index 96265d5eac..9144a3be4f 100644 --- a/Windows/DSoundStream.cpp +++ b/Windows/DSoundStream.cpp @@ -183,6 +183,8 @@ bool DSoundAudioBackend::Init(HWND window, StreamCallback _callback, int sampleR sampleRate_ = sampleRate; threadData_ = 0; hThread_ = (HANDLE)_beginthreadex(0, 0, soundThread, (void *)this, 0, 0); + if (!hThread_) + return false; SetThreadPriority(hThread_, THREAD_PRIORITY_ABOVE_NORMAL); return true; } diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index c7b98f52c5..00a7b1ed51 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -901,8 +901,8 @@ void CDisasm::ProcessUpdateDialog() { // Update Debug Counter if (PSP_IsInited()) { - wchar_t tempTicks[24]; - _snwprintf(tempTicks, 24, L"%lld", CoreTiming::GetTicks() - lastTicks); + wchar_t tempTicks[24]{}; + _snwprintf(tempTicks, 23, L"%lld", CoreTiming::GetTicks() - lastTicks); SetDlgItemText(m_hDlg, IDC_DEBUG_COUNT, tempTicks); } diff --git a/Windows/Debugger/DumpMemoryWindow.cpp b/Windows/Debugger/DumpMemoryWindow.cpp index 1f852611c2..884ba3bccf 100644 --- a/Windows/Debugger/DumpMemoryWindow.cpp +++ b/Windows/Debugger/DumpMemoryWindow.cpp @@ -229,8 +229,8 @@ void DumpMemoryWindow::changeMode(HWND hwnd, Mode newMode) if (filenameChosen_ == false) SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),"Custom.dump"); } else { - u32 start, size; - const char* defaultFileName; + u32 start = 0, size = 0; + const char *defaultFileName = ""; switch (selectedMode) { diff --git a/Windows/GPU/WindowsGLContext.h b/Windows/GPU/WindowsGLContext.h index df8190f9dc..2909be60f1 100644 --- a/Windows/GPU/WindowsGLContext.h +++ b/Windows/GPU/WindowsGLContext.h @@ -47,7 +47,4 @@ private: volatile bool resumeRequested; HANDLE pauseEvent; HANDLE resumeEvent; - - int xres; - int yres; }; diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 1eb68f441f..9f3a66e090 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -195,7 +195,7 @@ namespace MainWindow if (g_Config.UseFullScreen() || inFullscreenResize) return; - WINDOWPLACEMENT placement; + WINDOWPLACEMENT placement{}; GetWindowPlacement(hwndMain, &placement); if (placement.showCmd == SW_SHOWNORMAL) { RECT rc; diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index b9853c1a79..6a5d779203 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -379,15 +379,21 @@ namespace WindowsRawInput { } LRESULT Process(HWND hWnd, WPARAM wParam, LPARAM lParam) { - UINT dwSize; + UINT dwSize = 0; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); if (!rawInputBuffer) { rawInputBuffer = malloc(dwSize); + if (!rawInputBuffer) + return DefWindowProc(hWnd, WM_INPUT, wParam, lParam); memset(rawInputBuffer, 0, dwSize); rawInputBufferSize = dwSize; } if (dwSize > rawInputBufferSize) { - rawInputBuffer = realloc(rawInputBuffer, dwSize); + void *newBuf = realloc(rawInputBuffer, dwSize); + if (!newBuf) + return DefWindowProc(hWnd, WM_INPUT, wParam, lParam); + rawInputBuffer = newBuf; + rawInputBufferSize = dwSize; memset(rawInputBuffer, 0, dwSize); } GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawInputBuffer, &dwSize, sizeof(RAWINPUTHEADER)); diff --git a/Windows/TouchInputHandler.cpp b/Windows/TouchInputHandler.cpp index d27850c759..d0f00e59f6 100644 --- a/Windows/TouchInputHandler.cpp +++ b/Windows/TouchInputHandler.cpp @@ -15,15 +15,12 @@ #include "Windows/MainWindow.h" TouchInputHandler::TouchInputHandler() { - touchInfo = (getTouchInputProc) GetProcAddress( - GetModuleHandle(TEXT("User32.dll")), - "GetTouchInputInfo"); - closeTouch = (closeTouchInputProc) GetProcAddress( - GetModuleHandle(TEXT("User32.dll")), - "CloseTouchInputHandle"); - registerTouch = (registerTouchProc) GetProcAddress( - GetModuleHandle(TEXT("User32.dll")), - "RegisterTouchWindow"); + HMODULE user32 = GetModuleHandle(TEXT("User32.dll")); + if (!user32) + return; + touchInfo = (getTouchInputProc)GetProcAddress(user32, "GetTouchInputInfo"); + closeTouch = (closeTouchInputProc)GetProcAddress(user32, "CloseTouchInputHandle"); + registerTouch = (registerTouchProc)GetProcAddress(user32, "RegisterTouchWindow"); } int TouchInputHandler::ToTouchID(int windowsID, bool allowAllocate) { diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp index 4d9d101e41..2d7399f2e2 100644 --- a/Windows/W32Util/Misc.cpp +++ b/Windows/W32Util/Misc.cpp @@ -71,12 +71,14 @@ namespace W32Util // Lock the handle and copy the text to the buffer. wchar_t *lptstrCopy = (wchar_t *)GlobalLock(hglbCopy); - wcscpy(lptstrCopy, wtext.c_str()); - lptstrCopy[wtext.size()] = (wchar_t) 0; // null character - GlobalUnlock(hglbCopy); - SetClipboardData(CF_UNICODETEXT, hglbCopy); + if (lptstrCopy) { + wcscpy(lptstrCopy, wtext.c_str()); + lptstrCopy[wtext.size()] = (wchar_t) 0; // null character + GlobalUnlock(hglbCopy); + SetClipboardData(CF_UNICODETEXT, hglbCopy); + } CloseClipboard(); - return TRUE; + return lptstrCopy ? TRUE : FALSE; } void MakeTopMost(HWND hwnd, bool topMost) { diff --git a/Windows/W32Util/ShellUtil.cpp b/Windows/W32Util/ShellUtil.cpp index bd53935d27..2111a24674 100644 --- a/Windows/W32Util/ShellUtil.cpp +++ b/Windows/W32Util/ShellUtil.cpp @@ -33,7 +33,9 @@ namespace W32Util auto idList = SHBrowseForFolder(&info); HMODULE shell32 = GetModuleHandle(L"shell32.dll"); typedef BOOL (WINAPI *SHGetPathFromIDListEx_f)(PCIDLIST_ABSOLUTE pidl, PWSTR pszPath, DWORD cchPath, GPFIDL_FLAGS uOpts); - SHGetPathFromIDListEx_f SHGetPathFromIDListEx_ = (SHGetPathFromIDListEx_f)GetProcAddress(shell32, "SHGetPathFromIDListEx"); + SHGetPathFromIDListEx_f SHGetPathFromIDListEx_ = nullptr; + if (shell32) + SHGetPathFromIDListEx_ = (SHGetPathFromIDListEx_f)GetProcAddress(shell32, "SHGetPathFromIDListEx"); std::string result; if (SHGetPathFromIDListEx_) { @@ -156,7 +158,9 @@ namespace W32Util std::string result; HMODULE shell32 = GetModuleHandle(L"shell32.dll"); typedef HRESULT(WINAPI *SHGetKnownFolderPath_f)(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); - SHGetKnownFolderPath_f SHGetKnownFolderPath_ = (SHGetKnownFolderPath_f)GetProcAddress(shell32, "SHGetKnownFolderPath"); + SHGetKnownFolderPath_f SHGetKnownFolderPath_ = nullptr; + if (shell32) + SHGetKnownFolderPath_ = (SHGetKnownFolderPath_f)GetProcAddress(shell32, "SHGetKnownFolderPath"); if (SHGetKnownFolderPath_) { PWSTR path = nullptr; if (SHGetKnownFolderPath_(FOLDERID_Documents, 0, nullptr, &path) == S_OK) { diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp index 6079c030de..53f02245b9 100644 --- a/Windows/WASAPIStream.cpp +++ b/Windows/WASAPIStream.cpp @@ -159,16 +159,13 @@ public: __uuidof(IMMDeviceEnumerator), (void**)&_pEnumerator); } - if (hr == S_OK) - { + if (hr == S_OK && _pEnumerator) { hr = _pEnumerator->GetDevice(pwstrId, &pDevice); } - if (hr == S_OK) - { + if (hr == S_OK && pDevice) { hr = pDevice->OpenPropertyStore(STGM_READ, &pProps); } - if (hr == S_OK) - { + if (hr == S_OK && pProps) { // Get the endpoint device's friendly-name property. hr = pProps->GetValue(PKEY_Device_FriendlyName, &varString); } @@ -224,6 +221,8 @@ bool WASAPIAudioBackend::Init(HWND window, StreamCallback callback, int sampleRa callback_ = callback; sampleRate_ = sampleRate; hThread_ = (HANDLE)_beginthreadex(0, 0, soundThread, (void *)this, 0, 0); + if (!hThread_) + return false; SetThreadPriority(hThread_, THREAD_PRIORITY_ABOVE_NORMAL); return true; } @@ -333,7 +332,7 @@ void WASAPIAudioThread::ShutdownAudioDevice() { } bool WASAPIAudioThread::DetectFormat() { - if (!ValidateFormat(deviceFormat_)) { + if (deviceFormat_ && !ValidateFormat(deviceFormat_)) { // Last chance, let's try to ask for one we support instead. WAVEFORMATEXTENSIBLE fmt{}; fmt.Format.cbSize = sizeof(fmt); @@ -356,7 +355,8 @@ bool WASAPIAudioThread::DetectFormat() { CoTaskMemFree(closest); CoTaskMemFree(deviceFormat_); deviceFormat_ = (WAVEFORMATEXTENSIBLE *)CoTaskMemAlloc(sizeof(fmt)); - memcpy(deviceFormat_, &fmt, sizeof(fmt)); + if (deviceFormat_) + memcpy(deviceFormat_, &fmt, sizeof(fmt)); // In case something above gets out of date. return ValidateFormat(deviceFormat_); @@ -387,6 +387,8 @@ bool WASAPIAudioThread::ValidateFormat(const WAVEFORMATEXTENSIBLE *fmt) { // Don't know if PCM16 ever shows up here, the documentation only talks about float... but let's blindly // try to support it :P format_ = Format::UNKNOWN; + if (!fmt) + return false; if (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { if (!memcmp(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(fmt->SubFormat))) { @@ -572,7 +574,8 @@ void WASAPIAudioThread::Run() { } int WASAPIAudioBackend::RunThread() { - CoInitializeEx(nullptr, COINIT_MULTITHREADED); + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + _dbg_assert_(SUCCEEDED(hr)); SetCurrentThreadName("WASAPI_audio"); if (threadData_ == 0) { diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 610b79890b..06e9ef1662 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -269,7 +269,7 @@ void WindowsHost::BootDone() { } static Path SymbolMapFilename(const Path ¤tFilename, const char *ext) { - File::FileInfo info; + File::FileInfo info{}; // can't fail, definitely exists if it gets this far File::GetFileInfo(currentFilename, &info); if (info.isDirectory) { @@ -311,14 +311,16 @@ bool WindowsHost::IsDebuggingEnabled() { // http://msdn.microsoft.com/en-us/library/aa969393.aspx HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc) { HRESULT hres; - IShellLink* psl; - CoInitializeEx(NULL, COINIT_MULTITHREADED); + IShellLink *psl = nullptr; + hres = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (FAILED(hres)) + return hres; // Get a pointer to the IShellLink interface. It is assumed that CoInitialize // has already been called. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); - if (SUCCEEDED(hres)) { - IPersistFile* ppf; + if (SUCCEEDED(hres) && psl) { + IPersistFile *ppf = nullptr; // Set the path to the shortcut target and add the description. psl->SetPath(lpszPathObj); @@ -329,7 +331,7 @@ HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathL // shortcut in persistent storage. hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); - if (SUCCEEDED(hres)) { + if (SUCCEEDED(hres) && ppf) { // Save the link by calling IPersistFile::Save. hres = ppf->Save(lpszPathLink, TRUE); ppf->Release(); diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index b9d73c8ecd..3e82015921 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -38,7 +38,7 @@ static XInputGetState_t PPSSPP_XInputGetState = nullptr; static XInputSetState_t PPSSPP_XInputSetState = nullptr; static XInputGetCapabilitiesEx_t PPSSPP_XInputGetCapabilitiesEx = nullptr; static DWORD PPSSPP_XInputVersion = 0; -static HMODULE s_pXInputDLL = 0; +static HMODULE s_pXInputDLL = nullptr; static int s_XInputDLLRefCount = 0; static void UnloadXInputDLL(); @@ -105,7 +105,7 @@ static void UnloadXInputDLL() { if ( s_pXInputDLL ) { if (--s_XInputDLLRefCount == 0) { FreeLibrary( s_pXInputDLL ); - s_pXInputDLL = NULL; + s_pXInputDLL = nullptr; } } } @@ -206,7 +206,7 @@ void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATIO if (!notified[pad]) { notified[pad] = true; #if !PPSSPP_PLATFORM(UWP) - XINPUT_CAPABILITIES_EX caps; + XINPUT_CAPABILITIES_EX caps{}; if (PPSSPP_XInputGetCapabilitiesEx != nullptr && PPSSPP_XInputGetCapabilitiesEx(1, pad, 0, &caps) == ERROR_SUCCESS) { KeyMap::NotifyPadConnected(DEVICE_ID_XINPUT_0 + pad, StringFromFormat("Xbox 360 Pad: %d/%d", caps.vendorId, caps.productId)); } else { diff --git a/Windows/main.cpp b/Windows/main.cpp index 6584f0cf65..dc790cd7f8 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -113,7 +113,7 @@ void OpenDirectory(const char *path) { // SHParseDisplayName can't handle relative paths, so normalize first. std::string resolved = ReplaceAll(File::ResolvePath(path), "/", "\\"); - SFGAOF flags; + SFGAOF flags{}; PIDLIST_ABSOLUTE pidl = nullptr; HRESULT hr = SHParseDisplayName(ConvertUTF8ToWString(resolved).c_str(), nullptr, &pidl, 0, &flags); @@ -174,8 +174,8 @@ std::string GetVideoCardDriverVersion() { IEnumWbemClassObject* pEnum; hr = pIWbemServices->ExecQuery(bstrWQL, bstrPath, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum); - ULONG uReturned; - VARIANT var; + ULONG uReturned = 0; + VARIANT var{}; IWbemClassObject* pObj = NULL; if (!FAILED(hr)) { hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &uReturned); @@ -372,16 +372,8 @@ void System_SendMessage(const char *command, const char *parameter) { std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error")); MessageBox(MainWindow::GetHWND(), full_error.c_str(), title.c_str(), MB_OK); } else if (!strcmp(command, "setclipboardtext")) { - if (OpenClipboard(MainWindow::GetDisplayHWND())) { - std::wstring data = ConvertUTF8ToWString(parameter); - HANDLE handle = GlobalAlloc(GMEM_MOVEABLE, (data.size() + 1) * sizeof(wchar_t)); - wchar_t *wstr = (wchar_t *)GlobalLock(handle); - memcpy(wstr, data.c_str(), (data.size() + 1) * sizeof(wchar_t)); - GlobalUnlock(wstr); - SetClipboardData(CF_UNICODETEXT, handle); - GlobalFree(handle); - CloseClipboard(); - } + std::wstring data = ConvertUTF8ToWString(parameter); + W32Util::CopyTextToClipboard(MainWindow::GetDisplayHWND(), data); } else if (!strcmp(command, "browse_file")) { MainWindow::BrowseAndBoot(""); } else if (!strcmp(command, "browse_folder")) { @@ -411,6 +403,8 @@ void EnableCrashingOnCrashes() { const DWORD EXCEPTION_SWALLOWING = 0x1; HMODULE kernel32 = LoadLibrary(L"kernel32.dll"); + if (!kernel32) + return; tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, @@ -773,7 +767,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin break; } - if (!TranslateAccelerator(wnd, accel, &msg)) { + if (!wnd || !accel || !TranslateAccelerator(wnd, accel, &msg)) { if (!DialogManager::IsDialogMessage(&msg)) { //and finally translate and dispatch TranslateMessage(&msg); From 18106922366ff5ddf8d1995919f231334b9d4b76 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 21:12:36 -0800 Subject: [PATCH 663/715] Global: Cleanup some type/range checks. --- Common/Buffer.cpp | 4 +++- Common/RiscVEmitter.cpp | 4 ++-- Core/Util/DisArm64.cpp | 8 ++++---- GPU/Common/FramebufferManagerCommon.cpp | 2 +- Windows/CaptureDevice.cpp | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Common/Buffer.cpp b/Common/Buffer.cpp index 6dc6b74c5a..58a485593c 100644 --- a/Common/Buffer.cpp +++ b/Common/Buffer.cpp @@ -67,7 +67,9 @@ int Buffer::TakeLineCRLF(std::string *dest) { if (after_next_line < 0) { return after_next_line; } else { - Take(after_next_line - 2, dest); + _dbg_assert_(after_next_line >= 2); + if (after_next_line != 2) + Take((size_t)after_next_line - 2, dest); Skip(2); // Skip the CRLF return after_next_line - 2; } diff --git a/Common/RiscVEmitter.cpp b/Common/RiscVEmitter.cpp index 3f0d47499b..6849acbd19 100644 --- a/Common/RiscVEmitter.cpp +++ b/Common/RiscVEmitter.cpp @@ -615,7 +615,7 @@ const u8 *RiscVEmitter::AlignCode16() { const u8 *RiscVEmitter::AlignCodePage() { int page_size = GetMemoryProtectPageSize(); - int c = int((u64)code_ & (page_size - 1)); + int c = int((intptr_t)code_ & ((intptr_t)page_size - 1)); if (c) ReserveCodeSpace(page_size - c); return code_; @@ -747,7 +747,7 @@ void RiscVEmitter::SetRegToImmediate(RiscVReg rd, uint64_t value, RiscVReg temp) if (SignReduce64(v, 32) == v || force) { int32_t lower = (int32_t)SignReduce64(svalue, 12); int32_t upper = ((v - lower) >> 12) << 12; - _assert_msg_(force || upper + lower == v, "Upper + ADDI immediate math mistake?"); + _assert_msg_(force || (int64_t)upper + lower == v, "Upper + ADDI immediate math mistake?"); // Should be fused on some processors. (this->*upperOp)(rd, upper); diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index eac1edaed5..050589f2f0 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -421,14 +421,14 @@ static void DataProcessingRegister(uint32_t w, uint64_t addr, Instruction *instr const char *op = opcode2 >= 8 ? "unk" : opname[opcode]; snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d", op, r, Rd, r, Rn); } else if (((w >> 21) & 0x2FF) == 0x0D6) { - const char *opname[32] = { + const char *opname[64] = { 0, 0, "udiv", "sdiv", 0, 0, 0, 0, "lslv", "lsrv", "asrv", "rorv", 0, 0, 0, 0, "crc32b", "crc32h", "crc32w", 0, "crc32cb", "crc32ch", "crc32cw", 0, }; int opcode = (w >> 10) & 0x3F; // Data processing (2 source) - snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opname[opcode], r, Rd, r, Rn, r, Rm); + snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opname[opcode] ? opname[opcode] : "?", r, Rd, r, Rn, r, Rm); } else if (((w >> 24) & 0x1f) == 0xA) { // Logical (shifted register) int shift = (w >> 22) & 0x3; @@ -929,9 +929,9 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) { snprintf(instr->text, sizeof(instr->text), "(float cond compare %08x)", w); } else if (((w >> 10) & 3) == 2) { int opc = (w >> 12) & 0xf; - const char *opnames[9] = { "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul" }; + const char *opnames[16] = { "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul" }; char r = ((w >> 22) & 1) ? 'd' : 's'; - snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opnames[opc], r, Rd, r, Rn, r, Rm); + snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opnames[opc] ? opnames[opc] : "?", r, Rd, r, Rn, r, Rm); } else if (((w >> 10) & 3) == 3) { char fr = ((w >> 22) & 1) ? 'd' : 's'; int cond = (w >> 12) & 0xf; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index d3bfa8677f..1fa20e2733 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1999,7 +1999,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p } } - if (!candidates.empty()) { + if (best) { *rect = *best; return true; } else { diff --git a/Windows/CaptureDevice.cpp b/Windows/CaptureDevice.cpp index e522c7b24e..7b61fa6fa0 100644 --- a/Windows/CaptureDevice.cpp +++ b/Windows/CaptureDevice.cpp @@ -716,7 +716,7 @@ std::vector WindowsCaptureDevice::getDeviceList(bool forceEnum, int // Get the size needed first dwMinSize = WideCharToMultiByte(CP_UTF8, NULL, pwstrName, -1, nullptr, 0, nullptr, FALSE); if (dwMinSize == 0) - hr = -1; + hr = E_FAIL; } if (SUCCEEDED(hr)) { cstrName = new char[dwMinSize]; From c9f3878e9dac73fa61aa0af1176805db9abbd598 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Dec 2022 21:12:58 -0800 Subject: [PATCH 664/715] Core: Correct a use after free. --- Core/Loaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 37722fe0cf..5657bd281c 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -392,8 +392,8 @@ bool UmdReplace(const Path &filepath, std::string &error) { FileLoader *loadedFile = ConstructFileLoader(filepath); if (!loadedFile->Exists()) { - delete loadedFile; error = loadedFile->GetPath().ToVisualString() + " doesn't exist"; + delete loadedFile; return false; } UpdateLoadedFile(loadedFile); From 095e234999a141dda9dc7c6c27d6539c32ae9e54 Mon Sep 17 00:00:00 2001 From: leoxxx <5364709+leoxxx@users.noreply.github.com> Date: Sun, 11 Dec 2022 15:06:45 +0800 Subject: [PATCH 665/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 63f8e5d692..c6f81d5b1f 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -246,7 +246,7 @@ JIT debug tools = JIT调试工具 Log Dropped Frame Statistics = 记录丢弃帧统计信息 Log Level = 日志等级 Log View = 日志视图 -Logging Channels = 日志通道 +Logging Channels = 记录日志分类 Next = 下一个 No block = 没有内存块 Prev = 之前 From e48a1599d4fd48e888e05a37a75fc7bea77b349d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Dec 2022 10:01:46 +0100 Subject: [PATCH 666/715] Delete a few obsolete lines of code --- Core/Debugger/DebugInterface.h | 17 ++--------------- Core/MIPS/MIPSDebugInterface.h | 1 - 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Core/Debugger/DebugInterface.h b/Core/Debugger/DebugInterface.h index a92c8bab26..5422dc5798 100644 --- a/Core/Debugger/DebugInterface.h +++ b/Core/Debugger/DebugInterface.h @@ -23,16 +23,8 @@ struct MemMap; -enum { - GPR_SIZE_32, - GPR_SIZE_64, -}; - -class DebugInterface -{ +class DebugInterface { public: - virtual ~DebugInterface() {} - virtual const char *disasm(unsigned int address, unsigned int align) {return "NODEBUGGER";} virtual int getInstructionSize(int instruction) {return 1;} @@ -52,16 +44,13 @@ public: virtual bool initExpression(const char* exp, PostfixExpression& dest) { return false; }; virtual bool parseExpression(PostfixExpression& exp, u32& dest) { return false; }; - virtual u32 GetHi() { return 0; }; virtual u32 GetLo() { return 0; }; virtual void SetHi(u32 val) { }; virtual void SetLo(u32 val) { }; virtual const char *GetName() = 0; - virtual int GetGPRSize() = 0; //32 or 64 virtual u32 GetGPR32Value(int reg) {return 0;} virtual void SetGPR32Value(int reg) {} - virtual void SetGPR64Value(int reg) {} virtual u32 GetPC() = 0; virtual void SetPC(u32 _pc) = 0; virtual u32 GetLR() {return GetPC();} @@ -71,11 +60,9 @@ public: virtual int GetNumRegsInCategory(int cat) {return 0;} virtual const char *GetCategoryName(int cat) {return 0;} virtual const char *GetRegName(int cat, int index) {return 0;} - virtual void PrintRegValue(int cat, int index, char *out) - { + virtual void PrintRegValue(int cat, int index, char *out) { sprintf(out,"%08X",GetGPR32Value(index)); } virtual u32 GetRegValue(int cat, int index) {return 0;} virtual void SetRegValue(int cat, int index, u32 value) {} - }; diff --git a/Core/MIPS/MIPSDebugInterface.h b/Core/MIPS/MIPSDebugInterface.h index 088256e802..03324a36c2 100644 --- a/Core/MIPS/MIPSDebugInterface.h +++ b/Core/MIPS/MIPSDebugInterface.h @@ -48,7 +48,6 @@ public: //overridden functions const char *GetName() override; - int GetGPRSize() override { return GPR_SIZE_32; } u32 GetGPR32Value(int reg) override { return cpu->r[reg]; } u32 GetPC() override { return cpu->pc; } u32 GetLR() override { return cpu->r[MIPS_REG_RA]; } From a8985d8dda4e090a6c6570b2d79b5dc19db858b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Dec 2022 10:02:21 +0100 Subject: [PATCH 667/715] Windows: Fix shutdown order (stop the main thread before the window gets destroyed) --- Windows/MainWindow.cpp | 4 +++- Windows/main.cpp | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 9f3a66e090..de6b09baed 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -968,6 +968,7 @@ namespace MainWindow break; case WM_CLOSE: + MainThread_Stop(); InputDevice::StopPolling(); WindowsRawInput::Shutdown(); return DefWindowProc(hWnd,message,wParam,lParam); @@ -976,8 +977,9 @@ namespace MainWindow KillTimer(hWnd, TIMER_CURSORUPDATE); KillTimer(hWnd, TIMER_CURSORMOVEUPDATE); KillTimer(hWnd, TIMER_WHEELRELEASE); + // Main window is gone, this tells the message loop to exit. PostQuitMessage(0); - break; + return 0; case WM_USER + 1: NotifyDebuggerMapLoaded(); diff --git a/Windows/main.cpp b/Windows/main.cpp index dc790cd7f8..9351202bee 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -776,8 +776,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin } } - MainThread_Stop(); - VFSShutdown(); MainWindow::DestroyDebugWindows(); From 4c6f8d2b5858a3882e95a38f590c7782ebc5652c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Dec 2022 11:35:31 +0100 Subject: [PATCH 668/715] Fix memory issues in homebrew store Lots of problems in a few lines of code. We retained references to the filtered vector that lived temporarily in the load function... Plus, the "hidden" flag is utterly broken and could only ever work on the last entry, due to the above issue, and even then only if lucky. So I'm banning it from use, pointless anyway. --- UI/Store.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/UI/Store.cpp b/UI/Store.cpp index b6000e9d3b..ede13f18fc 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -198,7 +198,7 @@ public: StoreEntry GetEntry() const { return entry_; } private: - const StoreEntry &entry_; + const StoreEntry entry_; }; // This is a "details" view of a game. Lets you install it. @@ -441,7 +441,7 @@ void StoreScreen::ParseListing(std::string json) { e.size = game.getInt("size"); e.downloadURL = game.getString("download-url", ""); e.iconURL = game.getString("icon-url", ""); - e.hidden = game.getBool("hidden", false); + e.hidden = false; // NOTE: Handling of the "hidden" flag is broken in old versions of PPSSPP. Do not use. const char *file = game.getString("file", nullptr); if (!file) continue; @@ -484,8 +484,7 @@ void StoreScreen::CreateViews() { scrollItemView_ = new LinearLayoutList(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); leftScroll->Add(scrollItemView_); - std::vector entries = FilterEntries(); - for (size_t i = 0; i < entries.size(); i++) { + for (size_t i = 0; i < entries_.size(); i++) { scrollItemView_->Add(new ProductItemView(entries_[i]))->OnClick.Handle(this, &StoreScreen::OnGameSelected); } @@ -511,9 +510,7 @@ void StoreScreen::CreateViews() { std::vector StoreScreen::FilterEntries() { std::vector filtered; for (size_t i = 0; i < entries_.size(); i++) { - // TODO: Actually filter by category etc. - if (!entries_[i].hidden) - filtered.push_back(entries_[i]); + filtered.push_back(entries_[i]); } return filtered; } From 58ad49b79cb8d8ed5a55a5c852609b26f63beabd Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 11 Dec 2022 12:35:52 +0100 Subject: [PATCH 669/715] OpenXR - Default color correction adjusted --- Core/Config.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 864568f2ef..af4dd75c7f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -517,16 +517,7 @@ static bool DefaultEnableStateUndo() { } static float DefaultUISaturation() { - std::string device = System_GetProperty(SYSPROP_NAME); - if (IsVREnabled() && startsWith(device, "Pico")) { - return 1.5f; - } else if (IsVREnabled() && startsWith(device, "Oculus")) { - return 1.25f; - } else if (IsVREnabled() && startsWith(device, "Meta")) { - return 1.25f; - } else { - return 1.0f; - } + return IsVREnabled() ? 1.5f : 1.0f; } struct ConfigSectionSettings { @@ -1420,15 +1411,27 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } } - auto postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting")->ToMap(); + // Default values for post process shaders + bool postShadersInitialized = iniFile.HasSection("PostShaderList"); + Section *postShaderChain = iniFile.GetOrCreateSection("PostShaderList"); + Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); + if (IsVREnabled() && !postShadersInitialized) { + postShaderChain->Set("PostShader1", "ColorCorrection"); + postShaderSetting->Set("ColorCorrectionSettingValue1",1.0f); + postShaderSetting->Set("ColorCorrectionSettingValue2",1.5f); + postShaderSetting->Set("ColorCorrectionSettingValue3",1.1f); + postShaderSetting->Set("ColorCorrectionSettingValue4",1.0f); + } + + // Load post process shader values mPostShaderSetting.clear(); - for (auto it : postShaderSetting) { + for (const auto& it : postShaderSetting->ToMap()) { mPostShaderSetting[it.first] = std::stof(it.second); } - auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + // Load post process shader names vPostShaderNames.clear(); - for (auto it : postShaderChain) { + for (const auto& it : postShaderChain->ToMap()) { if (it.second != "Off") vPostShaderNames.push_back(it.second); } From 5bbedd2d227777ce4180e23f1f858b93bee02388 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Sun, 11 Dec 2022 16:52:46 +0300 Subject: [PATCH 670/715] Update Russian translation --- assets/lang/ru_RU.ini | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 04396dd888..156dd22ca3 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -458,6 +458,7 @@ Aggressive = Принудительно Alternative Speed = Другая скорость (в %, 0 = без ограничений) Alternative Speed 2 = Другая скорость 2 (в %, 0 = без ограничений) Anisotropic Filtering = Анизотропная фильтрация +Antialiasing (MSAA) = Сглаживание (MSAA) Aspect Ratio = Соотношение сторон Auto = Авто Auto (1:1) = Авто (1:1) @@ -794,9 +795,9 @@ Undo last save = Отменить последнее сохранение [PostShaders] (duplicated setting, previous slider will be used) = (дублированная настройка, используется предыдущий ползунок) -4xHqGLSL = 4xHQ pixel art upscaler -5xBR = 5xBR pixel art upscaler -5xBR-lv2 = 5xBR-lv2 pixel art upscaler +4xHqGLSL = Апскейлер пиксель-арта 4xHQ +5xBR = Апскейлер пиксель-арта 5xBR +5xBR-lv2 = Апскейлер пиксель-арта 5xBR-lv2 AAColor = AA-цвета Amount = Размер Animation speed (0 -> disable) = Скорость анимации (0 -> disable) From 5a9c5bed5d209ed0e29f6c5d3d366158b9335d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Sun, 11 Dec 2022 23:26:44 +0800 Subject: [PATCH 671/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 162 +++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 7458167121..1bb2028ab2 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -122,98 +122,98 @@ Refresh Rate = 重新整理速率 # If your language does not show well with the default font, you can use Font to specify a different one. # Just add it to your language's ini file and uncomment it (remove the # by Font). Font = Microsoft JhengHei -About PPSSPP... = 關於 PPSSPP (&A)… -Auto = 自動 (&A) -Auto Max Quality = 自動最高品質 (&Q) -Backend = 轉譯後端 (需要重新啟動) (&b) -Bicubic = 雙立方 (&B) +About PPSSPP... = 關於 PPSSPP(&A)… +Auto = 自動(&A) +Auto Max Quality = 自動最高品質(&Q) +Backend = 轉譯後端 (需要重新啟動)(&B) +Bicubic = 雙立方(&B) Break = 中斷 Break on Load = 載入時中斷 -Buy Gold = 購買黃金版 (&G) -Control Mapping... = 控制對應 (&O)… -Debugging = 偵錯 (&D) -Deposterize = 色調混合 (&D) -Direct3D9 = Direct3D 9 (&9) -Direct3D11 = Direct3D 11 (&11) -Disassembly = 反組譯碼 (&D)… +Buy Gold = 購買黃金版(&G) +Control Mapping... = 控制對應(&O)… +Debugging = 偵錯(&D) +Deposterize = 色調混合(&D) +Direct3D9 = Direct3D 9(&9) +Direct3D11 = Direct3D 11(&11) +Disassembly = 反組譯碼(&D)… Discord = Discord Display Layout && Effects = 顯示版面配置與效果… Display Rotation = 顯示旋轉 -Dump Next Frame to Log = 傾印下一影格至記錄 (&U) -Emulation = 模擬 (&E) -Enable Cheats = 啟用密技 (&C) -Enable Sound = 啟用音效 (&O) -Exit = 離開 (&X) -Extract File... = 擷取檔案 (&X)… -File = 檔案 (&F) -Frame Skipping = 影格跳過 (&F) +Dump Next Frame to Log = 傾印下一影格至記錄(&U) +Emulation = 模擬(&E) +Enable Cheats = 啟用密技(&C) +Enable Sound = 啟用音效(&O) +Exit = 離開(&X) +Extract File... = 擷取檔案(&X)… +File = 檔案(&F) +Frame Skipping = 影格跳過(&F) Frame Skipping Type = 影格跳過類型 -Fullscreen = 全螢幕 (&L) -Game Settings = 遊戲設定 (&G) -GE Debugger... = GE 偵錯工具 (&R)… +Fullscreen = 全螢幕(&L) +Game Settings = 遊戲設定(&G) +GE Debugger... = GE 偵錯工具(&R)… GitHub = Git&Hub -Hardware Transform = 硬體轉換 (&H) -Help = 說明 (&H) -Hybrid = 混合 (&H) -Hybrid + Bicubic = 混合 + 雙立方 (&Y) -Ignore Illegal Reads/Writes = 忽略非法存取 (&I) +Hardware Transform = 硬體轉換(&H) +Help = 說明(&H) +Hybrid = 混合(&H) +Hybrid + Bicubic = 混合 + 雙立方(&Y) +Ignore Illegal Reads/Writes = 忽略非法存取(&I) Ignore Windows Key = 忽略 Windows 按鍵 -Keep PPSSPP On Top = 保持 PPSSPP 視窗在最上層 (&K) +Keep PPSSPP On Top = 保持 PPSSPP 視窗在最上層(&K) Landscape = 橫向 Landscape reversed = 橫向反轉 -Language... = 語言 (&N)… -Linear = 線性 (&L) -Load = 載入 (&L)… -Load .sym File... = 載入 .sym 檔案 (&A)… -Load Map File... = 載入對應檔案 (&M)… -Load State = 載入存檔 (&O) -Load State File... = 載入存檔檔案 (&L)… -Log Console = 記錄主控台 (&L) -Memory View... = 記憶體檢視 (&V)… -More Settings... = 更多設定 (&M)… -Nearest = 鄰近取樣 (&N) -Skip Buffer Effects = 跳過緩衝區效果 (&S) -Off = 關閉 (&O) +Language... = 語言(&N)… +Linear = 線性(&L) +Load = 載入(&L)… +Load .sym File... = 載入 .sym 檔案(&A)… +Load Map File... = 載入對應檔案(&M)… +Load State = 載入存檔(&O) +Load State File... = 載入存檔檔案(&L)… +Log Console = 記錄主控台(&L) +Memory View... = 記憶體檢視(&V)… +More Settings... = 更多設定(&M)… +Nearest = 鄰近取樣(&N) +Skip Buffer Effects = 跳過緩衝區效果(&S) +Off = 關閉(&O) Open Chat = 開啟聊天 -Open Directory... = 開啟目錄 (&D)… -Open from MS:/PSP/GAME... = 開啟自 MS:/PSP/GAME (&P)… -Open Memory Stick = 開啟記憶棒 (&M) +Open Directory... = 開啟目錄(&D)… +Open from MS:/PSP/GAME... = 開啟自 MS:/PSP/GAME(&P)… +Open Memory Stick = 開啟記憶棒(&M) Open New Instance = 開啟新執行個體 -OpenGL = OpenGL (&O) -Pause = 暫停 (&P) -Pause When Not Focused = 未聚焦時暫停 (&P) +OpenGL = OpenGL(&O) +Pause = 暫停(&P) +Pause When Not Focused = 未聚焦時暫停(&P) Portrait = 直向 Portrait reversed = 直向反轉 -PPSSPP Forums = PPSSPP 論壇 (&F) -Record = 錄製 (&R) -Record Audio = 錄製音訊 (&A) -Record Display = 錄製視訊 (&D) -Rendering Mode = 轉譯模式 (&O) -Rendering Resolution = 轉譯解析度 (&R) -Reset = 重設 (&E) -Reset Symbol Table = 重設符號表 (&Y) -Run = 執行 (&R) -Save .sym File... = 儲存 .sym 檔案 (&E)… -Save Map File... = 儲存對應檔案 (&S)… -Save State = 儲存存檔 (&A) -Save State File... = 儲存存檔檔案 (&S)… -Savestate Slot = 存檔插槽 (&T) -Screen Scaling Filter = 螢幕縮放濾鏡 (&E) -Show Debug Statistics = 顯示偵錯統計資料 (&G) -Show FPS Counter = 顯示 FPS 計數器 (&F) +PPSSPP Forums = PPSSPP 論壇(&F) +Record = 錄製(&R) +Record Audio = 錄製音訊(&A) +Record Display = 錄製視訊(&D) +Rendering Mode = 轉譯模式(&O) +Rendering Resolution = 轉譯解析度(&R) +Reset = 重設(&E) +Reset Symbol Table = 重設符號表(&Y) +Run = 執行(&R) +Save .sym File... = 儲存 .sym 檔案(&E)… +Save Map File... = 儲存對應檔案(&S)… +Save State = 儲存存檔(&A) +Save State File... = 儲存存檔檔案(&S)… +Savestate Slot = 存檔插槽(&T) +Screen Scaling Filter = 螢幕縮放濾鏡(&E) +Show Debug Statistics = 顯示偵錯統計資料(&G) +Show FPS Counter = 顯示 FPS 計數器(&F) Skip Number of Frames = 跳過影格數 Skip Percent of FPS = 跳過 FPS 百分比 -Stop = 停止 (&S) +Stop = 停止(&S) Switch UMD = 切換 UMD -Take Screenshot = 擷取螢幕畫面 (&T) -Texture Filtering = 紋理過濾 (&X) -Texture Scaling = 紋理縮放 (&T) -Use Lossless Video Codec (FFV1) = 使用不失真視訊轉碼器 (FFV1) (&U) +Take Screenshot = 擷取螢幕畫面(&T) +Texture Filtering = 紋理過濾(&X) +Texture Scaling = 紋理縮放(&T) +Use Lossless Video Codec (FFV1) = 使用不失真視訊轉碼器 (FFV1)(&U) Use output buffer for video = 為視訊使用輸出緩衝區 -Vertex Cache = 頂點快取 (&V) -VSync = 垂直同步 (&Y) +Vertex Cache = 頂點快取(&V) +VSync = 垂直同步(&Y) Vulkan = Vulkan -Window Size = 視窗大小 (&W) +Window Size = 視窗大小(&W) www.ppsspp.org = 造訪 www.&ppsspp.org xBRZ = &xBRZ @@ -313,8 +313,8 @@ Load completed = 載入完成 Loading = 正在載入\n請稍候… LoadingFailed = 無法載入資料 Move = 移動 -Move Down = Move Down -Move Up = Move Up +Move Down = 下移 +Move Up = 上移 Network Connection = 網路連線 NEW DATA = 新存檔 No = 否 @@ -322,7 +322,7 @@ ObtainingIP = 正在取得 IP 位址\n請稍候… OK = 確定 Old savedata detected = 偵測到舊版存檔資料 Options = 選項 -Remove = Remove +Remove = 移除 Reset = 重設 Resize = 調整大小 Retry = 重試 @@ -615,7 +615,7 @@ SavesAreTemporary = PPSSPP 正在儲存於暫時儲存空間 SavesAreTemporaryGuidance = 將 PPSSPP 擷取至其他位置以永久儲存 SavesAreTemporaryIgnore = 忽略警告 UnpinPath = 取消釘選 -UseBrowseOrLoad = 使用「瀏覽」以選擇資料夾,或載入以選擇檔案 +UseBrowseOrLoad = 使用「瀏覽」以選擇資料夾,或「載入」以選擇檔案 www.ppsspp.org = 官方網站 [MainSettings] @@ -794,9 +794,9 @@ Undo last save = 復原上次儲存 [PostShaders] (duplicated setting, previous slider will be used) = (重複的設定,將使用上一個滑桿) -4xHqGLSL = 4xHQ pixel art upscaler -5xBR = 5xBR pixel art upscaler -5xBR-lv2 = 5xBR-lv2 pixel art upscaler +4xHqGLSL = 4xHQ 畫素藝術放大 +5xBR = 5xBR 畫素藝術放大 +5xBR-lv2 = 5xBR-lv2 畫素藝術放大 AAColor = AA-Color Amount = 數量 Black border = 黑色框線 @@ -1034,7 +1034,7 @@ CPU Name = CPU 名稱 D3DCompiler Version = D3DCompiler 版本 Debug = 偵錯 Debugger Present = 偵錯工具呈現 -Depth buffer format = Depth buffer format +Depth buffer format = 深度緩衝區格式 Device Info = 裝置資訊 Directories = 目錄 Display Information = 顯示器資訊 From 155f73f72de8608d7193ef31955d184409f40a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Dec 2022 17:15:38 +0100 Subject: [PATCH 672/715] Fix Hz strings for translation, LCD persistence too --- UI/DevScreens.cpp | 6 +++--- assets/lang/en_US.ini | 4 ++++ assets/lang/pl_PL.ini | 1 - assets/lang/sv_SE.ini | 21 ++++++++++++--------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 23b238848a..a496b0cdeb 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -569,13 +569,13 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem(si->T("PPSSPP build"), build)); deviceSpecs->Add(new ItemHeader(si->T("Audio Information"))); - deviceSpecs->Add(new InfoItem(si->T("Sample rate"), StringFromFormat("%d Hz", System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE)))); + deviceSpecs->Add(new InfoItem(si->T("Sample rate"), StringFromFormat(si->T("%d Hz"), System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE)))); int framesPerBuffer = System_GetPropertyInt(SYSPROP_AUDIO_FRAMES_PER_BUFFER); if (framesPerBuffer > 0) { deviceSpecs->Add(new InfoItem(si->T("Frames per buffer"), StringFromFormat("%d", framesPerBuffer))); } #if PPSSPP_PLATFORM(ANDROID) - deviceSpecs->Add(new InfoItem(si->T("Optimal sample rate"), StringFromFormat("%d Hz", System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE)))); + deviceSpecs->Add(new InfoItem(si->T("Optimal sample rate"), StringFromFormat(si->T("%d Hz"), System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE)))); deviceSpecs->Add(new InfoItem(si->T("Optimal frames per buffer"), StringFromFormat("%d", System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_FRAMES_PER_BUFFER)))); #endif @@ -592,7 +592,7 @@ void SystemInfoScreen::CreateViews() { #if !PPSSPP_PLATFORM(WINDOWS) // Don't show on Windows, since it's always treated as 60 there. - deviceSpecs->Add(new InfoItem(si->T("Refresh rate"), StringFromFormat("%0.3f Hz", (float)System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE)))); + deviceSpecs->Add(new InfoItem(si->T("Refresh rate"), StringFromFormat(si->T("%0.2f Hz"), (float)System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE)))); #endif deviceSpecs->Add(new ItemHeader(si->T("Version Information"))); diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 5d4213d734..7399cbed9e 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -482,6 +482,7 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -835,6 +836,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off @@ -1041,6 +1043,8 @@ Uninstall = Uninstall [SysInfo] %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz +%0.2f Hz = %0.2f hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index dd1f625d0d..74d76804ef 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -470,7 +470,6 @@ Balanced = Zbalansowane Bicubic = Bicubic (Dwusześcienne) Both = Oba Buffer graphics commands (faster, input lag) = Bufor komand grafiki (szybsze, może powodować lagi sterowania) -Buffered Rendering = Renderowanie buforowe BufferedRenderingRequired = Uwaga: Ta gra wymaga włączonej opcji "Renderowanie buforowe". Camera = Kamera Camera Device = Kamera diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index a5cea55f8e..6ef9966500 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -798,10 +798,10 @@ Undo last save = Ångra senaste spar 5xBR = 5xBR pixel art upscaler 5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AAColor -Amount = Amount +Amount = Mängd Animation speed (0 -> disable) = Animation speed (0 -> disable) -Black border = Black border -Bloom = Bloom +Black border = Svart kant +Bloom = Bloom-effekt Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler @@ -811,25 +811,26 @@ Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Gamma = Gamma -GreenLevel = Green level -Intensity = Intensity +GreenLevel = Grön-nivå +Intensity = Intensitet +LCDPersistence = LCD-persistens MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural NaturalA = Natural Colors (no blur) Off = Off -Power = Power +Power = Styrka PSPColor = PSP color RedBlue = Röd/Blå glasögon Saturation = Saturation -Scanlines = Scanlines -Sharpen = Sharpen +Scanlines = Scan-linjer +Sharpen = Skärpa SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleSpline36 = UpscaleSpline36 VideoSmoothingAA = VideoSmoothingAA -Vignette = Vignette +Vignette = Vignett [PSPCredits] all the forum mods = all the forum mods @@ -1024,6 +1025,8 @@ Uninstall = Avinstallera [SysInfo] %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d hz +%0.2f Hz = %0.2f hz (none detected) = (none detected) 3D API = 3D API ABI = ABI From c9eac0d7976ba3a9996f6bdfb8dff1228e18bd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Dec 2022 18:13:41 +0100 Subject: [PATCH 673/715] Copy new lines to more translations --- assets/lang/ar_AE.ini | 4 ++++ assets/lang/az_AZ.ini | 4 ++++ assets/lang/bg_BG.ini | 4 ++++ assets/lang/ca_ES.ini | 4 ++++ assets/lang/cz_CZ.ini | 4 ++++ assets/lang/da_DK.ini | 4 ++++ assets/lang/de_DE.ini | 4 ++++ assets/lang/dr_ID.ini | 4 ++++ assets/lang/es_ES.ini | 4 ++++ assets/lang/es_LA.ini | 4 ++++ assets/lang/fa_IR.ini | 4 ++++ assets/lang/fi_FI.ini | 4 ++++ assets/lang/fr_FR.ini | 4 ++++ assets/lang/gl_ES.ini | 4 ++++ assets/lang/gr_EL.ini | 4 ++++ assets/lang/he_IL.ini | 4 ++++ assets/lang/he_IL_invert.ini | 4 ++++ assets/lang/hr_HR.ini | 4 ++++ assets/lang/hu_HU.ini | 4 ++++ assets/lang/id_ID.ini | 4 ++++ assets/lang/it_IT.ini | 4 ++++ assets/lang/ja_JP.ini | 4 ++++ assets/lang/jv_ID.ini | 4 ++++ assets/lang/ko_KR.ini | 4 ++++ assets/lang/lo_LA.ini | 4 ++++ assets/lang/lt-LT.ini | 4 ++++ assets/lang/ms_MY.ini | 4 ++++ assets/lang/nl_NL.ini | 4 ++++ assets/lang/no_NO.ini | 4 ++++ assets/lang/pl_PL.ini | 4 ++++ assets/lang/pt_BR.ini | 4 ++++ assets/lang/pt_PT.ini | 4 ++++ assets/lang/ro_RO.ini | 4 ++++ assets/lang/ru_RU.ini | 3 +++ assets/lang/sv_SE.ini | 1 + assets/lang/tg_PH.ini | 4 ++++ assets/lang/th_TH.ini | 4 ++++ assets/lang/tr_TR.ini | 4 ++++ assets/lang/uk_UA.ini | 4 ++++ assets/lang/vi_VN.ini | 4 ++++ assets/lang/zh_CN.ini | 4 ++++ assets/lang/zh_TW.ini | 4 ++++ 42 files changed, 164 insertions(+) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 0d636970f9..2efc0edb5f 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -466,6 +466,7 @@ Aggressive = ‎عنيف Alternative Speed = سرعة ثانوية (في %, 0 = ‎غير محدود) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ‎فلتر الحواف +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = ‎تلقائي Auto (1:1) = ‎تلقائي (1:1) @@ -850,6 +851,7 @@ FXAA = ‎FXAA منعم الحواف Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = ‎الألوان الحقيقية NaturalA = Natural Colors (no blur) @@ -1030,8 +1032,10 @@ Size = ‎الحجم Uninstall = ‎إلغاء التثبيت [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index f113e191af..6c2bb577ce 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 45755b3357..55d6c71bfa 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Алтернативна скорост Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic филтриране +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Автоматично Auto (1:1) = Автоматично (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Големина Uninstall = Деинсталирай [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 4a96b71296..abd9a97d7b 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtrat anisotròpic +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index cc316cb2ba..19973c0c85 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -458,6 +458,7 @@ Aggressive = Agresivní Alternative Speed = Alternativní rychlost (v %, 0 = neomezeno) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anizotropní filtrování +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automaticky Auto (1:1) = Automatické (1:1) @@ -842,6 +843,7 @@ FXAA = Vyhlazování hran FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Přirozené barvy NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Velikost Uninstall = Odinstalovat [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index d7a79a5173..1b4a0fef98 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -458,6 +458,7 @@ Aggressive = Aggressiv Alternative Speed = Alternativ hastighed (i %, 0 = ubegrænset) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropisk filtrering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automatisk Auto (1:1) = Automatisk (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturlige farver NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Størrelse Uninstall = Afinstaller [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 4ff46ac564..324b257f25 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -458,6 +458,7 @@ Aggressive = Aggressiv Alternative Speed = Alternative Geschwindigkeit Alternative Speed 2 = Alternative Geschwindigkeit 2 (in %, 0 = unlimitiert) Anisotropic Filtering = Anisotropischer Filter +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automatisch Auto (1:1) = Automatisch (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natürliche Farben NaturalA = Natürliche Farben (kein Blur) @@ -1022,8 +1024,10 @@ Size = Größe Uninstall = Deinstallieren [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d pro Kern, %d Kerne) %d bytes = %d Byte +%d Hz = %d Hz (none detected) = (nichts gefunden) 3D API = 3D API ABI = ABI diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index cf02bd536c..8e3932ff22 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Lassi to leko'napa Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Panyaring Anisotropic +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Ia mesa Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 2ba2f033d1..084e638663 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -458,6 +458,7 @@ Aggressive = Agresivo Alternative Speed = Velocidad alternativa (%, 0 = ilimitada) Alternative Speed 2 = Velocidad alternativa 2 (%, 0 = ilimitada) Anisotropic Filtering = Filtrado anisotrópico +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) @@ -842,6 +843,7 @@ FXAA = Antialiasing por FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensidad +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Colores naturales NaturalA = Colores naturales (sin difuminar) @@ -1022,8 +1024,10 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (ninguno detectado) 3D API = API 3D ABI = Arquitectura diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index cfa059c136..9cf4a49fc7 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -458,6 +458,7 @@ Aggressive = Agresivo Alternative Speed = Velocidad alternativa (en %, 0 = ilimitada) Alternative Speed 2 = Velocidad alternativa 2 (en %, 0 = ilimitada) Anisotropic Filtering = Filtrado Anisotrópico +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) @@ -842,6 +843,7 @@ FXAA = Antialiasing por FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensidad +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Colores naturales NaturalA = Colores naturales (sin desenfoques) @@ -1022,8 +1024,10 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (No se ha detectado) 3D API = API 3D ABI = Arquitectura diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 19dd0501ce..e0586632ce 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -458,6 +458,7 @@ Aggressive = ‎شدید Alternative Speed = ‎سرعت ثانویه Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ‎Anisotropic فیلتر +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = ‎اتوماتیک Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 26e994dd7e..d8a0e1f6dc 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Vaihtoehtoinen nopeus Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotrooppisen suodatus +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 41875c547b..e16b0f6a4b 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -458,6 +458,7 @@ Aggressive = Agressif Alternative Speed = Vitesse alternative 1 (en %, 0 = illimitée) Alternative Speed 2 = Vitesse alternative 2 (en %, 0 = illimitée) Anisotropic Filtering = Filtrage anisotrope +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automatique Auto (1:1) = Automatique (1:1) @@ -842,6 +843,7 @@ FXAA = Anticrénelage FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensité +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Couleurs naturelles NaturalA = Couleurs naturelles (sans flou) @@ -1013,8 +1015,10 @@ Size = Taille Uninstall = Désinstaller [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d par cœur, %d cœurs) %d bytes = %d octets +%d Hz = %d Hz (none detected) = (aucun détecté) 3D API = API 3D ABI = ABI diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index d202f17fcb..ac788ec3b9 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -458,6 +458,7 @@ Aggressive = Agresivo Alternative Speed = Velocidade alternativa (%, 0 = ilimitada) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtrado anisotrópico +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) @@ -842,6 +843,7 @@ FXAA = Antialiasing FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Cores naturais NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 240c2b50ed..1c23ebf194 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -458,6 +458,7 @@ Aggressive = Εξαναγκαστική Alternative Speed = Εναλακτική προβολή ταχύτητας (στα %, 0 = απεριόριστη) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Ανισοτροπικό Φιλτράρισμα +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Αυτόματο Auto (1:1) = Αυτόματο (1:1) @@ -842,6 +843,7 @@ FXAA = Εξομάλυνση κορυφών FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Φυσικά Χρώματα NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Μέγεθος Uninstall = Απεγκατάσταση [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d ανά πυρήνα, %d πυρήνες) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (δεν βρέθηκε) 3D API = 3D API ABI = ABI diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 9239455c89..813e0b227d 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = הגבלת מהירות Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = אוטומטי Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 1d42057032..6942c28bf9 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = תוריהמ תלבגה Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = יטמוטוא Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 066ba47e75..c925b7dd3d 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -458,6 +458,7 @@ Aggressive = Agresivno Alternative Speed = Alternativna brzina (u %, 0 = unlimited) Alternative Speed 2 = Alternativna brzina 2 (u %, 0 = unlimited) Anisotropic Filtering = Anizotropno filtriranje +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Prirodne boje NaturalA = Prirodne boje (bez zamućivanja) @@ -1022,8 +1024,10 @@ Size = Veličina Uninstall = Deinstaliraj [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d po jezgri, %d jezgre) %d bytes = %d bajtova +%d Hz = %d Hz (none detected) = (nijedna uočena) 3D API = 3D API ABI = ABI diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 0579abd7c7..4c8276bf24 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -458,6 +458,7 @@ Aggressive = Agresszív Alternative Speed = Alternatív sebesség Alternative Speed 2 = Alternatív sebesség 2 (%-ban, 0 = korlátlan) Anisotropic Filtering = Anizotropikus szűrés +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA élsimítás Gamma = Gamma GreenLevel = Green level Intensity = Erősség +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Természetes színek NaturalA = Természetes színek (elmosódás nélkül) @@ -1022,8 +1024,10 @@ Size = Méret Uninstall = Eltávolítás [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d magonként, %d db mag) %d bytes = %d bájt +%d Hz = %d Hz (none detected) = (nem észlelve) 3D API = 3D API ABI = ABI diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 2355e6feed..2ddbc3c069 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -458,6 +458,7 @@ Aggressive = Agresif Alternative Speed = Kecepatan alternatif (dalam %, 0 = tak terbatas) Alternative Speed 2 = Kecepatan alternatif 2 (dalam %, 0 = tak terbatas) Anisotropic Filtering = Pemfilteran anisotropik +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Otomatis Auto (1:1) = Otomatis (1:1) @@ -842,6 +843,7 @@ FXAA = Mengurangi Artifak Distorsi (FXAA) Gamma = Gamma GreenLevel = Green level Intensity = Intensitas +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna Natural NaturalA = Warna Natural (tidak kabur) @@ -1022,8 +1024,10 @@ Size = Ukuran Uninstall = Mencopot pemasangan [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d perinti, %d inti) %d bytes = %d bit +%d Hz = %d Hz (none detected) = (tidak ada yang terdeteksi) 3D API = 3D API ABI = ABI diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 14cafefb42..f6e992d719 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -458,6 +458,7 @@ Aggressive = Aggressivo Alternative Speed = Velocità Alternativa (in %, 0 = illimitata) Alternative Speed 2 = Velocità Alternativa 2 (in %, 0 = illimitata) Anisotropic Filtering = Filtro Anisotropico +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automatico Auto (1:1) = Automatico (1:1) @@ -814,6 +815,7 @@ FXAA = Antialiasing FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensità +LCDPersistence = LCD Persistence MitchellNetravali = Upscaler Bicubico (Mitchell-Netravali) Natural = Colori naturali NaturalA = Colori naturali (nessuna sfocatura) @@ -1023,8 +1025,10 @@ Size = Dimensioni Uninstall = Disinstalla [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d core) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (niente rilevato) 3D API = API 3D ABI = ABI diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index f420a0646e..09ef93cd97 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -458,6 +458,7 @@ Aggressive = 最大限 Alternative Speed = カスタム速度1 (%で指定、0 = 無制限) Alternative Speed 2 = カスタム速度2 (%で指定、0 = 無制限) Anisotropic Filtering = 異方性フィルタリング +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = 自動 Auto (1:1) = 自動 (1:1) @@ -813,6 +814,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = サイズ Uninstall = アンインストールする [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (1コアあたり %d, コア数 %d) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (未検出) 3D API = 3D API ABI = ABI diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 320fd6ba87..4a5030d7ee 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -458,6 +458,7 @@ Aggressive = Agresif Alternative Speed = Kacepetan Alternatif Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Penyaring Anisotropis +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Otomatis Auto (1:1) = Otomatis (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna Natural NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Ukuran Uninstall = Copot [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index c99e778885..2378be9c3b 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -458,6 +458,7 @@ Aggressive = 과격 Alternative Speed = 대체 속도 (%, 0 = 무제한) Alternative Speed 2 = 대체 속도 2 (%, 0 = 무제한) Anisotropic Filtering = 비등방성 필터링 +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = 자동 Auto (1:1) = 자동 (1:1) @@ -811,6 +812,7 @@ FXAA = FXAA 안티 에일리어싱 Gamma = 감마 GreenLevel = Green level Intensity = 강도 +LCDPersistence = LCD Persistence Natural = 자연스러운 색상 NaturalA = 자연스러운 색상 (흐림 없음) Off = 끔 @@ -1035,8 +1037,10 @@ Size = 크기 Uninstall = 제거 [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (코어 당 %d, 코어 %d 개) %d bytes = %d 바이트 +%d Hz = %d Hz (none detected) = (감지되지 않음) 3D API = 3D API ABI = ABI diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index c1458dbc36..b44c2e813b 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -458,6 +458,7 @@ Aggressive = ຮຸນແຮງ Alternative Speed = ຄວາມໄວເສີມ (ໃນ %, 0 = ບໍ່ຈຳກັດ) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ກຳຈັດຄວາມບໍ່ຄົມຊັດ +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = ອັດຕະໂນມັດ Auto (1:1) = ອັດຕະໂນມັດ (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = ຂະໜາດ Uninstall = ຖອນການຕິດຕັ້ງ [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 646f2900a5..7955fd6e6f 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Alternatyvus greitis (procentais, 0 procentų = neribotas) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = "Anisotropic" filtravimas +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automatinis Auto (1:1) = Automatinė (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturalios spalvos NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Dydis Uninstall = Išinstaliuoti [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index d991357c5c..83e084993f 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Kelajuan alternatif Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Anti aliasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna asli NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Saiz Uninstall = Nyahpasang [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 249efacdb9..2dc11eb11e 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -458,6 +458,7 @@ Aggressive = Agressief Alternative Speed = Alternatieve snelheid (in %, 0 = onbeperkt) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropische filter +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automatisch Auto (1:1) = Automatisch (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA-antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natuurlijke kleuren NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Grootte Uninstall = Deïnstalleren [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (niets gedetecteerd) 3D API = 3D-API ABI = ABI diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index bc11cc40a7..d47aba9973 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -458,6 +458,7 @@ Aggressive = Aggressive Alternative Speed = Alternativ hastighet Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropisk filtrering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 74d76804ef..0658a22646 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -458,6 +458,7 @@ Aggressive = Agresywne Alternative Speed = Alternatywna prędkość (w %, 0 = bez limitu) Alternative Speed 2 = Alternatywna prędkość 2 (w %, 0 = bez limitu) Anisotropic Filtering = Filtrowanie anizotropowe +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automatyczne Auto (1:1) = Automatyczna (1:1) @@ -842,6 +843,7 @@ FXAA = Wygładzanie FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturalne kolory NaturalA = Naturalne kolory (bez rozmycia) @@ -1022,8 +1024,10 @@ Size = Rozmiar Uninstall = Odinstaluj [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d na rdzeń, %d rdzenie) %d bytes = %d bajtów +%d Hz = %d Hz (none detected) = (nie wykryto) 3D API = 3D API ABI = ABI diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 85916ba0d8..086943b36a 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -482,6 +482,7 @@ Aggressive = Agressivo Alternative Speed = Velocidade alternativa (em %, 0 = ilimitada) Alternative Speed 2 = Velocidade alternativa 2 (em %, 0 = ilimitada) Anisotropic Filtering = Filtragem anisotrópica +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Proporção do Aspecto Auto = Auto Auto (1:1) = Auto (1:1) @@ -835,6 +836,7 @@ FXAA = Anti-aliasing do FXAA Gamma = Gama GreenLevel = Nível verde Intensity = Intensidade +LCDPersistence = LCD Persistence Natural = Cores naturais NaturalA = Cores naturais (sem borrão) Off = Desligado @@ -1039,8 +1041,10 @@ Size = Tamanho Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (nenhum detectado) 3D API = API 3D ABI = ABI diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index ed04174528..7c4c476dae 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -482,6 +482,7 @@ Aggressive = Agressivo Alternative Speed = Velocidade alternativa (em %, 0 = ilimitada) Alternative Speed 2 = Segunda Velocidade alternativa (em %, 0 = ilimitada) Anisotropic Filtering = Filtragem anisotrópica +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) @@ -835,6 +836,7 @@ FXAA = Anti-aliasing do FXAA Gamma = Gama GreenLevel = Green level Intensity = Intensidade +LCDPersistence = LCD Persistence Natural = Cores naturais NaturalA = Cores naturais (sem borrão) Off = Desligado @@ -1039,8 +1041,10 @@ Size = Tamanho Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (nenhum detectado) 3D API = API 3D ABI = ABI diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 2ac9cbe570..7947da0236 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -458,6 +458,7 @@ Aggressive = Agresiv Alternative Speed = Viteză alternativă (în %, 0 = nelimitat) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtru Anisotropic +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Automat Auto (1:1) = Automat (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Culori Naturale NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Mărime Uninstall = Dezinstalare [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 156dd22ca3..d68dde3095 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -814,6 +814,7 @@ FXAA = Сглаживание FXAA Gamma = Gamma GreenLevel = Green level Intensity = Интенсивность +LCDPersistence = LCD Persistence MitchellNetravali = Бикубический (Mitchell-Netravali) апскейлер Natural = Естественные цвета NaturalA = Естественные цвета (без размытия) @@ -1023,8 +1024,10 @@ Size = Размер Uninstall = Удалить [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d на ядро, ядер: %d) %d bytes = %d байт +%d Hz = %d Hz (none detected) = (не обнаружено) 3D API = 3D API ABI = ABI diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 6ef9966500..410c8b92fa 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -458,6 +458,7 @@ Aggressive = Aggressiv Alternative Speed = Alternativ hastighet Alternative Speed 2 = Alternativ hastighet 2 (%, 0 = obegränsad) Anisotropic Filtering = Anisotropisk filtrering +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Sidförhållande Auto = Auto Auto (1:1) = Auto (1:1) diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 93272cd417..15f748c29e 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -458,6 +458,7 @@ Aggressive = Agresibo Alternative Speed = Alternatibong bilis Alternative Speed 2 = Alternatibong bilis 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropikong Pagsala +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Awto Auto (1:1) = Awto (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA Antialiasing Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) @@ -1022,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 179a6e4bdf..72c56589cb 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -458,6 +458,7 @@ Aggressive = รุนแรง Alternative Speed = เพิ่ม-ลดระดับความเร็ว (ใน %, 0 = ไม่จำกัด) Alternative Speed 2 = เพิ่ม-ลดระดับความเร็ว 2 (ใน %, 0 = ไม่จำกัด) Anisotropic Filtering = ตัวกรองขจัดความไม่คมชัดของพื้นผิว +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = อัตโนมัติ Auto (1:1) = อัตโนมัติ (1:1) @@ -842,6 +843,7 @@ FXAA = ภาพเน้นลบขอบรอยหยัก Gamma = แกมม่า GreenLevel = ระดับสีเขียว Intensity = ความเข้มของแสง +LCDPersistence = LCD Persistence MitchellNetravali = ภาพอัพสเกลแบบไบคิวบิค (มิทเชลล์-เนทราวาลิ) Natural = ภาพเน้นสีธรรมชาติ NaturalA = ภาพเน้นสีธรรมชาติ (ไม่เบลอ) @@ -1022,8 +1024,10 @@ Size = ขนาด Uninstall = ถอนการติดตั้ง [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d เธรด ต่อคอร์, %d คอร์) %d bytes = %d ไบต์ +%d Hz = %d Hz (none detected) = (ไม่พบ) 3D API = แอพพลิเคชั่น โปรแกรม อินเตอร์เฟซ สามมิติ ABI = แอพพลิเคชั่น ไบนารี่ อินเตอร์เฟซ diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 379752394b..44f70eeb87 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -460,6 +460,7 @@ Aggressive = Agresif Alternative Speed = Alternatif Hız (% 0 = sınırsız) Alternative Speed 2 = Alternatif Hız 2 (% 0 = sınırsız) Anisotropic Filtering = Anizotropik filtreleme +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Otomatik Auto (1:1) = Otomatik (1:1) @@ -843,6 +844,7 @@ FXAA = FXAA Kenar Yumuşatma Gamma = Gamma GreenLevel = Green level Intensity = Yoğunluk +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Doğal Renkler NaturalA = Doğal Renkler (bulanıklık yok) @@ -1023,8 +1025,10 @@ Size = Boyut Uninstall = Sil [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (çekirdek başına %d , %d çekirdek ) %d bytes = %d bayt +%d Hz = %d Hz (none detected) = (hiç bulunamadı) 3D API = 3D API ABI = ABI diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 0981be9a88..8a08c3533d 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -458,6 +458,7 @@ Aggressive = Примусово Alternative Speed = Альтернативна шв. (к %, 0 = необмежено) Alternative Speed 2 = Альтернативна шв. 2 (к %, 0 = необмежено) Anisotropic Filtering = Анізотропна фільтрація +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Авто Auto (1:1) = Авто (1:1) @@ -842,6 +843,7 @@ FXAA = FXAA згладжування Gamma = Гамма GreenLevel = Green level Intensity = Інтенсивність +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Натуральні кольори NaturalA = Натуральні кольори (без розмиття) @@ -1022,8 +1024,10 @@ Size = Розмір Uninstall = Видалити [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d на ядро, ядер: %d) %d bytes = %d байт +%d Hz = %d Hz (none detected) = (не виявлено) 3D API = 3D API ABI = ABI diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 1e73d69f8a..35be090baa 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -458,6 +458,7 @@ Aggressive = Xâm lược Alternative Speed = Tốc độ luân phiên Alternative Speed 2 = Tốc độ luân phiên 2 (trong %, 0 = không giới hạn) Anisotropic Filtering = Lọc không cùng hướng +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = Aspect Ratio Auto = Tự động Auto (1:1) = Tự động (1:1) @@ -842,6 +843,7 @@ FXAA = Chống răng cưa FXAA Gamma = Gamma GreenLevel = Green level Intensity = Intensity +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Màu tự nhiên (mờ) NaturalA = Màu tự nhiên (không mờ) @@ -1022,8 +1024,10 @@ Size = Kích cỡ Uninstall = Gỡ [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (không phát hiện) 3D API = 3D API ABI = ABI diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index c6f81d5b1f..389cef19e1 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -458,6 +458,7 @@ Aggressive = 激进 Alternative Speed = 自定义速度 Alternative Speed 2 = 自定义速度2 Anisotropic Filtering = 各向异性过滤 +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = 宽高比 Auto = 自动 Auto (1:1) = 自动(1:1) @@ -842,6 +843,7 @@ FXAA = FXAA (快速近似抗锯齿) Gamma = 伽马值 GreenLevel = Green level Intensity = 强度 +LCDPersistence = LCD Persistence Natural = 自然色 NaturalA = 自然色(无模糊) Off = 关闭 @@ -1016,8 +1018,10 @@ Size = 大小 Uninstall = 卸载 [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (每核心%d线程, %d核心) %d bytes = %d字节 +%d Hz = %d Hz (none detected) = (未检测到) 3D API = 3D API ABI = ABI diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 1bb2028ab2..b7f2cdfbc9 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -458,6 +458,7 @@ Aggressive = 積極 Alternative Speed = 替代速度 (於 %,0 = 無限制) Alternative Speed 2 = 替代速度 2 (於 %,0 = 無限制) Anisotropic Filtering = 非等向性過濾 +Antialiasing (MSAA) = Antialiasing (MSAA) Aspect Ratio = 長寬比 Auto = 自動 Auto (1:1) = 自動 (1:1) @@ -811,6 +812,7 @@ FXAA = FXAA 消除鋸齒 Gamma = 色差補正 GreenLevel = 綠色色階 Intensity = 濃度 +LCDPersistence = LCD Persistence Natural = 自然色彩 NaturalA = 自然色彩 (無模糊) Off = 關閉 @@ -1015,8 +1017,10 @@ Size = 大小 Uninstall = 解除安裝 [SysInfo] +%0.2f Hz = %0.2f hz %d (%d per core, %d cores) = %d (每核心 %d 執行緒,%d 核心) %d bytes = %d 位元組 +%d Hz = %d Hz (none detected) = (未偵測到) 3D API = 3D API ABI = ABI From 675c282286ddc83248200b8549017742ce17759f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Dec 2022 20:55:09 +0100 Subject: [PATCH 674/715] Hides the D3D9 option on Intel Xe graphics. For whatever reason, it really doesn't work for me, while all three other backends work perfectly. So let's just hide it. You can still enable it through the ini file for debugging purposes. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 6 ++++++ Common/GPU/D3D9/thin3d_d3d9.cpp | 21 ++++++++++++++++----- Common/GPU/OpenGL/thin3d_gl.cpp | 8 ++++++++ Common/GPU/Vulkan/thin3d_vulkan.cpp | 8 ++++++++ Common/GPU/thin3d.h | 3 +++ UI/GameSettingsScreen.cpp | 7 +++++-- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index faafc4998e..aa52c919dd 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -312,6 +312,12 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.isTilingGPU = false; + // Hide D3D9 when we know it likely won't work well. + caps_.supportsD3D9 = true; + if (!strcmp(adapterDesc_.c_str(), "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } + // Temp texture for read-back of small images. Custom textures are created on demand for larger ones. // TODO: Should really benchmark if this extra complexity has any benefit. D3D11_TEXTURE2D_DESC packDesc{}; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index bc0135e834..a4d668e369 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -773,6 +773,11 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.textureNPOTFullySupported = true; } + caps_.supportsD3D9 = true; + if (!strcmp(identifier_.Description, "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } + // VS range culling (killing triangles in the vertex shader using NaN) causes problems on Intel. // Also causes problems on old NVIDIA. switch (caps_.vendor) { @@ -1254,10 +1259,10 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { D3D9Framebuffer *fbo = new D3D9Framebuffer(desc.width, desc.height); fbo->depthstenciltex = nullptr; - HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, NULL); + HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, nullptr); if (FAILED(rtResult)) { ERROR_LOG(G3D, "Failed to create render target"); - delete fbo; + fbo->Release(); return NULL; } fbo->tex->GetSurfaceLevel(0, &fbo->surf); @@ -1286,9 +1291,15 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { } D3D9Framebuffer::~D3D9Framebuffer() { - tex->Release(); - surf->Release(); - depthstencil->Release(); + if (tex) { + tex->Release(); + } + if (surf) { + surf->Release(); + } + if (depthstencil) { + depthstencil->Release(); + } if (depthstenciltex) { depthstenciltex->Release(); } diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index c9edb68502..b7737bd919 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -611,6 +611,14 @@ OpenGLContext::OpenGLContext() { break; } + // Hide D3D9 when we know it likely won't work well. +#if PPSSPP_PLATFORM(WINDOWS) + caps_.supportsD3D9 = true; + if (!strcmp(gl_extensions.model, "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } +#endif + // Very rough heuristic! caps_.isTilingGPU = gl_extensions.IsGLES && caps_.vendor != GPUVendor::VENDOR_NVIDIA && caps_.vendor != GPUVendor::VENDOR_INTEL; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 4cc760f429..422c288083 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -861,6 +861,14 @@ VKContext::VKContext(VulkanContext *vulkan) } caps_.isTilingGPU = hasLazyMemory && caps_.vendor != GPUVendor::VENDOR_APPLE; + // Hide D3D9 when we know it likely won't work well. +#if PPSSPP_PLATFORM(WINDOWS) + caps_.supportsD3D9 = true; + if (!strcmp(deviceProps.deviceName, "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } +#endif + // VkSampleCountFlagBits is arranged correctly for our purposes. // Only support MSAA levels that have support for all three of color, depth, stencil. if (!caps_.isTilingGPU) { diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 76afa314be..5d68541f3e 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -578,6 +578,9 @@ struct DeviceCaps { bool isTilingGPU; // This means that it benefits from correct store-ops, msaa without backing memory, etc. bool sampleRateShadingSupported; + // From the other backends, we can detect if D3D9 support is known bad (like on Xe) and disable it. + bool supportsD3D9; + u32 multiSampleLevelsMask; // Bit n is set if (1 << n) is a valid multisample level. Bit 0 is always set. std::string deviceName; // The device name to use when creating the thin3d context, to get the same one. }; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 9ca9ce1282..536a5f4426 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -262,9 +262,14 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new ItemHeader(gr->T("Rendering Mode"))); + Draw::DrawContext *draw = screenManager()->getDrawContext(); + #if !PPSSPP_PLATFORM(UWP) static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" }; PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager())); + if (g_Config.iGPUBackend != (int)GPUBackend::DIRECT3D9 && !draw->GetDeviceCaps().supportsD3D9) { + renderingBackendChoice->HideChoice(1); + } renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend); if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL)) @@ -282,8 +287,6 @@ void GameSettingsScreen::CreateViews() { } #endif - Draw::DrawContext *draw = screenManager()->getDrawContext(); - // Backends that don't allow a device choice will only expose one device. if (draw->GetDeviceList().size() > 1) { std::string *deviceNameSetting = GPUDeviceNameSetting(); From af06fa9194fb14916ccc11136b4523db325a795f Mon Sep 17 00:00:00 2001 From: iota97 Date: Sun, 11 Dec 2022 21:20:38 +0100 Subject: [PATCH 675/715] Fix Hz casing --- assets/lang/ar_AE.ini | 2 +- assets/lang/az_AZ.ini | 2 +- assets/lang/bg_BG.ini | 2 +- assets/lang/ca_ES.ini | 2 +- assets/lang/cz_CZ.ini | 2 +- assets/lang/da_DK.ini | 2 +- assets/lang/de_DE.ini | 2 +- assets/lang/dr_ID.ini | 2 +- assets/lang/en_US.ini | 2 +- assets/lang/es_ES.ini | 2 +- assets/lang/es_LA.ini | 2 +- assets/lang/fa_IR.ini | 2 +- assets/lang/fi_FI.ini | 2 +- assets/lang/fr_FR.ini | 2 +- assets/lang/gl_ES.ini | 2 +- assets/lang/gr_EL.ini | 2 +- assets/lang/he_IL.ini | 2 +- assets/lang/he_IL_invert.ini | 2 +- assets/lang/hr_HR.ini | 2 +- assets/lang/hu_HU.ini | 2 +- assets/lang/id_ID.ini | 2 +- assets/lang/it_IT.ini | 2 +- assets/lang/ja_JP.ini | 2 +- assets/lang/jv_ID.ini | 2 +- assets/lang/ko_KR.ini | 2 +- assets/lang/lo_LA.ini | 2 +- assets/lang/lt-LT.ini | 2 +- assets/lang/ms_MY.ini | 2 +- assets/lang/nl_NL.ini | 2 +- assets/lang/no_NO.ini | 2 +- assets/lang/pl_PL.ini | 2 +- assets/lang/pt_BR.ini | 2 +- assets/lang/pt_PT.ini | 2 +- assets/lang/ro_RO.ini | 2 +- assets/lang/ru_RU.ini | 2 +- assets/lang/sv_SE.ini | 2 +- assets/lang/tg_PH.ini | 2 +- assets/lang/th_TH.ini | 2 +- assets/lang/tr_TR.ini | 2 +- assets/lang/uk_UA.ini | 2 +- assets/lang/vi_VN.ini | 2 +- assets/lang/zh_CN.ini | 2 +- assets/lang/zh_TW.ini | 2 +- 43 files changed, 43 insertions(+), 43 deletions(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 2efc0edb5f..ca6ee2f2a5 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -1032,7 +1032,7 @@ Size = ‎الحجم Uninstall = ‎إلغاء التثبيت [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 6c2bb577ce..a45fe54efa 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 55d6c71bfa..ea30998564 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -1024,7 +1024,7 @@ Size = Големина Uninstall = Деинсталирай [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index abd9a97d7b..5b43c0be1e 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 19973c0c85..6a946ac451 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -1024,7 +1024,7 @@ Size = Velikost Uninstall = Odinstalovat [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 1b4a0fef98..2b131b3edc 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -1024,7 +1024,7 @@ Size = Størrelse Uninstall = Afinstaller [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 324b257f25..1616da144d 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -1024,7 +1024,7 @@ Size = Größe Uninstall = Deinstallieren [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d pro Kern, %d Kerne) %d bytes = %d Byte %d Hz = %d Hz diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 8e3932ff22..b8ad29812b 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 7399cbed9e..ba83532c2a 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -1044,7 +1044,7 @@ Uninstall = Uninstall %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 084e638663..b21677e66c 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -1024,7 +1024,7 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 9cf4a49fc7..cd2831b267 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -1024,7 +1024,7 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index e0586632ce..499dff93b2 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index d8a0e1f6dc..c2a35832b2 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index e16b0f6a4b..b1bfec51a4 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -1015,7 +1015,7 @@ Size = Taille Uninstall = Désinstaller [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d par cœur, %d cœurs) %d bytes = %d octets %d Hz = %d Hz diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index ac788ec3b9..a2a2f27553 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -1024,7 +1024,7 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 1c23ebf194..11e7840167 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -1024,7 +1024,7 @@ Size = Μέγεθος Uninstall = Απεγκατάσταση [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d ανά πυρήνα, %d πυρήνες) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 813e0b227d..821036d929 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 6942c28bf9..ca4233a80a 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index c925b7dd3d..e58183275c 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -1024,7 +1024,7 @@ Size = Veličina Uninstall = Deinstaliraj [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d po jezgri, %d jezgre) %d bytes = %d bajtova %d Hz = %d Hz diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 4c8276bf24..2ae7447a73 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -1024,7 +1024,7 @@ Size = Méret Uninstall = Eltávolítás [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d magonként, %d db mag) %d bytes = %d bájt %d Hz = %d Hz diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 2ddbc3c069..a6f15acfb5 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -1024,7 +1024,7 @@ Size = Ukuran Uninstall = Mencopot pemasangan [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d perinti, %d inti) %d bytes = %d bit %d Hz = %d Hz diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index f6e992d719..2723d05977 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -1025,7 +1025,7 @@ Size = Dimensioni Uninstall = Disinstalla [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d core) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 09ef93cd97..074e477256 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -1024,7 +1024,7 @@ Size = サイズ Uninstall = アンインストールする [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (1コアあたり %d, コア数 %d) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 4a5030d7ee..fd05d3aa80 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -1024,7 +1024,7 @@ Size = Ukuran Uninstall = Copot [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 2378be9c3b..740988315f 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -1037,7 +1037,7 @@ Size = 크기 Uninstall = 제거 [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (코어 당 %d, 코어 %d 개) %d bytes = %d 바이트 %d Hz = %d Hz diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index b44c2e813b..ba4a067705 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -1024,7 +1024,7 @@ Size = ຂະໜາດ Uninstall = ຖອນການຕິດຕັ້ງ [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 7955fd6e6f..35241f4db8 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -1024,7 +1024,7 @@ Size = Dydis Uninstall = Išinstaliuoti [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 83e084993f..7b271dbdfd 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -1024,7 +1024,7 @@ Size = Saiz Uninstall = Nyahpasang [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 2dc11eb11e..aee4d59ea8 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -1024,7 +1024,7 @@ Size = Grootte Uninstall = Deïnstalleren [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index d47aba9973..6b61af3c4a 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 0658a22646..e9d371a870 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -1024,7 +1024,7 @@ Size = Rozmiar Uninstall = Odinstaluj [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d na rdzeń, %d rdzenie) %d bytes = %d bajtów %d Hz = %d Hz diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 086943b36a..d914a68d81 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -1041,7 +1041,7 @@ Size = Tamanho Uninstall = Desinstalar [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 7c4c476dae..0b231bbc1b 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -1041,7 +1041,7 @@ Size = Tamanho Uninstall = Desinstalar [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 7947da0236..fa6ad784ef 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -1024,7 +1024,7 @@ Size = Mărime Uninstall = Dezinstalare [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index d68dde3095..ef389b5607 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -1024,7 +1024,7 @@ Size = Размер Uninstall = Удалить [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d на ядро, ядер: %d) %d bytes = %d байт %d Hz = %d Hz diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 410c8b92fa..d2751a26fb 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -1027,7 +1027,7 @@ Uninstall = Avinstallera %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d hz -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 15f748c29e..7b4d6d1a7f 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -1024,7 +1024,7 @@ Size = Size Uninstall = Uninstall [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 72c56589cb..fe9256980a 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -1024,7 +1024,7 @@ Size = ขนาด Uninstall = ถอนการติดตั้ง [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d เธรด ต่อคอร์, %d คอร์) %d bytes = %d ไบต์ %d Hz = %d Hz diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 44f70eeb87..98952e53d2 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1025,7 +1025,7 @@ Size = Boyut Uninstall = Sil [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (çekirdek başına %d , %d çekirdek ) %d bytes = %d bayt %d Hz = %d Hz diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 8a08c3533d..ecd8cf8794 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -1024,7 +1024,7 @@ Size = Розмір Uninstall = Видалити [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d на ядро, ядер: %d) %d bytes = %d байт %d Hz = %d Hz diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 35be090baa..eaa35f2eb2 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -1024,7 +1024,7 @@ Size = Kích cỡ Uninstall = Gỡ [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes %d Hz = %d Hz diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 389cef19e1..8ed7531d78 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1018,7 +1018,7 @@ Size = 大小 Uninstall = 卸载 [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (每核心%d线程, %d核心) %d bytes = %d字节 %d Hz = %d Hz diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index b7f2cdfbc9..b6984f5e80 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -1017,7 +1017,7 @@ Size = 大小 Uninstall = 解除安裝 [SysInfo] -%0.2f Hz = %0.2f hz +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (每核心 %d 執行緒,%d 核心) %d bytes = %d 位元組 %d Hz = %d Hz From 5ef78c2838205ab6d43f548d6baa918d7e62c7d5 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Mon, 12 Dec 2022 00:37:52 +0300 Subject: [PATCH 676/715] Update Russian translation --- assets/lang/ru_RU.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index ef389b5607..0c19be0b88 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -599,7 +599,7 @@ Browse = Обзор... Buy PPSSPP Gold = PPSSPP Gold Choose folder = Выберите папку Credits = Авторы -PPSSPP Homebrew Store = магазина хоумбрю PPSSPP +PPSSPP Homebrew Store = Магазин хоумбрю PPSSPP Exit = Выход Game Settings = Настройки Games = Игры @@ -814,7 +814,7 @@ FXAA = Сглаживание FXAA Gamma = Gamma GreenLevel = Green level Intensity = Интенсивность -LCDPersistence = LCD Persistence +LCDPersistence = Остаточное изображение ЖК-дисплея MitchellNetravali = Бикубический (Mitchell-Netravali) апскейлер Natural = Естественные цвета NaturalA = Естественные цвета (без размытия) @@ -1024,10 +1024,10 @@ Size = Размер Uninstall = Удалить [SysInfo] -%0.2f Hz = %0.2f Hz +%0.2f Hz = %0.2f Гц %d (%d per core, %d cores) = %d (%d на ядро, ядер: %d) %d bytes = %d байт -%d Hz = %d Hz +%d Hz = %d Гц (none detected) = (не обнаружено) 3D API = 3D API ABI = ABI From 9f5430b819837dff90f930a8275e89cd9768db2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Dec 2022 00:09:04 +0100 Subject: [PATCH 677/715] Make the string "PPSSPP Homebrew Store" translatable in one more place No new string needed. Also removed changing the title of the homebrew store when downloading, we already show a progress bar, that's enough (and saves us two more translation strings). --- UI/Store.cpp | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/UI/Store.cpp b/UI/Store.cpp index ede13f18fc..5eff6e4178 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -403,19 +403,6 @@ void StoreScreen::update() { // Forget the listing. listing_.reset(); } - - const char *storeName = "PPSSPP Homebrew Store"; - switch (g_GameManager.GetState()) { - case GameManagerState::DOWNLOADING: - titleText_->SetText(std::string(storeName) + " - downloading"); - break; - case GameManagerState::INSTALLING: - titleText_->SetText(std::string(storeName) + " - installing"); - break; - default: - titleText_->SetText(storeName); - break; - } } void StoreScreen::ParseListing(std::string json) { @@ -458,11 +445,12 @@ void StoreScreen::CreateViews() { auto di = GetI18NCategory("Dialog"); auto st = GetI18NCategory("Store"); + auto mm = GetI18NCategory("MainMenu"); // Top bar LinearLayout *topBar = root_->Add(new LinearLayout(ORIENT_HORIZONTAL)); topBar->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); - titleText_ = new TextView("PPSSPP Homebrew Store"); + titleText_ = new TextView(mm->T("PPSSPP Homebrew Store")); topBar->Add(titleText_); UI::Drawable solid(0xFFbd9939); topBar->SetBG(solid); @@ -471,7 +459,10 @@ void StoreScreen::CreateViews() { if (connectionError_ || loading_) { content = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f)); content->Add(new TextView(loading_ ? std::string(st->T("Loading...")) : StringFromFormat("%s: %d", st->T("Connection Error"), resultCode_))); - content->Add(new Button(di->T("Retry")))->OnClick.Handle(this, &StoreScreen::OnRetry); + if (!loading_) { + content->Add(new Button(di->T("Retry")))->OnClick.Handle(this, &StoreScreen::OnRetry); + + } content->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); scrollItemView_ = nullptr; From eb65f586ec3203250dfd8ce63c536cb1bdb48a4b Mon Sep 17 00:00:00 2001 From: nassau-tk Date: Mon, 12 Dec 2022 11:23:15 +0900 Subject: [PATCH 678/715] jpn0_fix.pgf --- assets/flash0/font/jpn0.pgf | Bin 4316452 -> 4316280 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/flash0/font/jpn0.pgf b/assets/flash0/font/jpn0.pgf index e3acf4c62ac21c427e24315ff6db581a66663fa8..7e191ef62cf528e16f8b4dc0d04d39c579eddb00 100644 GIT binary patch delta 261268 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

uXrsH8wIei7pr>5V8 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 Date: Mon, 12 Dec 2022 10:23:27 +0100 Subject: [PATCH 679/715] langtool: improve insertion of missing sections (logging, empty line) --- Tools/langtool/src/inifile.rs | 4 ++++ Tools/langtool/src/main.rs | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Tools/langtool/src/inifile.rs b/Tools/langtool/src/inifile.rs index ac109af0f7..c70f4636ec 100644 --- a/Tools/langtool/src/inifile.rs +++ b/Tools/langtool/src/inifile.rs @@ -111,6 +111,10 @@ impl IniFile { } } // Reached the end for some reason? Add it. + // Also add an empty line to the previous section. + if let Some(last) = self.sections.last_mut() { + last.lines.push("".into()); + } self.sections.push(section.clone()); true } diff --git a/Tools/langtool/src/main.rs b/Tools/langtool/src/main.rs index 7b59706822..99107fff3a 100644 --- a/Tools/langtool/src/main.rs +++ b/Tools/langtool/src/main.rs @@ -47,6 +47,10 @@ fn copy_missing_lines(reference_ini: &IniFile, target_ini: &mut IniFile) -> io:: //target_section.remove_lines_if_not_in(reference_section); target_section.comment_out_lines_if_not_in(reference_section); } + } else { + // Note: insert_section_if_missing will copy the entire section, + // no need to loop over the lines here. + println!("Inserted missing section: {}", reference_section.name); } } Ok(()) @@ -114,7 +118,8 @@ fn main() { let root = "../../assets/lang"; let reference_ini_filename = "en_US.ini"; - let mut reference_ini = IniFile::parse(&format!("{}/{}", root, reference_ini_filename)).unwrap(); + let mut reference_ini = + IniFile::parse(&format!("{}/{}", root, reference_ini_filename)).unwrap(); if filenames.is_empty() { // Grab them all. From c1f544f976c403cfbe87c44813f25697473c5945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Dec 2022 10:24:38 +0100 Subject: [PATCH 680/715] Add VR section to en_US --- assets/lang/en_US.ini | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index ba83532c2a..47ac574420 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -1249,3 +1249,17 @@ Choices: = Choices: List: = List: Progress: %1% = Progress: %1% Screen representation = Screen representation + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers From e8f321fe25b4e90a50c9bcdeeb6296a76ac2e896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Dec 2022 10:25:23 +0100 Subject: [PATCH 681/715] Copy the VR section to all the other translations (th_TH already had it) --- assets/lang/ar_AE.ini | 14 ++++++++++++++ assets/lang/az_AZ.ini | 14 ++++++++++++++ assets/lang/bg_BG.ini | 14 ++++++++++++++ assets/lang/ca_ES.ini | 14 ++++++++++++++ assets/lang/cz_CZ.ini | 14 ++++++++++++++ assets/lang/da_DK.ini | 14 ++++++++++++++ assets/lang/de_DE.ini | 14 ++++++++++++++ assets/lang/dr_ID.ini | 14 ++++++++++++++ assets/lang/es_ES.ini | 14 ++++++++++++++ assets/lang/es_LA.ini | 14 ++++++++++++++ assets/lang/fa_IR.ini | 14 ++++++++++++++ assets/lang/fi_FI.ini | 14 ++++++++++++++ assets/lang/fr_FR.ini | 14 ++++++++++++++ assets/lang/gl_ES.ini | 14 ++++++++++++++ assets/lang/gr_EL.ini | 14 ++++++++++++++ assets/lang/he_IL.ini | 14 ++++++++++++++ assets/lang/he_IL_invert.ini | 14 ++++++++++++++ assets/lang/hr_HR.ini | 14 ++++++++++++++ assets/lang/hu_HU.ini | 14 ++++++++++++++ assets/lang/id_ID.ini | 14 ++++++++++++++ assets/lang/it_IT.ini | 14 ++++++++++++++ assets/lang/ja_JP.ini | 14 ++++++++++++++ assets/lang/jv_ID.ini | 14 ++++++++++++++ assets/lang/ko_KR.ini | 14 ++++++++++++++ assets/lang/lo_LA.ini | 14 ++++++++++++++ assets/lang/lt-LT.ini | 14 ++++++++++++++ assets/lang/ms_MY.ini | 14 ++++++++++++++ assets/lang/nl_NL.ini | 14 ++++++++++++++ assets/lang/no_NO.ini | 14 ++++++++++++++ assets/lang/pl_PL.ini | 14 ++++++++++++++ assets/lang/pt_BR.ini | 14 ++++++++++++++ assets/lang/pt_PT.ini | 14 ++++++++++++++ assets/lang/ro_RO.ini | 14 ++++++++++++++ assets/lang/ru_RU.ini | 14 ++++++++++++++ assets/lang/sv_SE.ini | 14 ++++++++++++++ assets/lang/tg_PH.ini | 14 ++++++++++++++ assets/lang/th_TH.ini | 1 + assets/lang/tr_TR.ini | 14 ++++++++++++++ assets/lang/uk_UA.ini | 14 ++++++++++++++ assets/lang/vi_VN.ini | 14 ++++++++++++++ assets/lang/zh_CN.ini | 14 ++++++++++++++ assets/lang/zh_TW.ini | 14 ++++++++++++++ 42 files changed, 575 insertions(+) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index ca6ee2f2a5..f5ef62b556 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -1232,3 +1232,17 @@ Details = Details Dismiss = ‎إلغاء Download = ‎تحميل New version of PPSSPP available = ‎تتوفر نسخة جديدة من البرنامج + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index a45fe54efa..490862373a 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index ea30998564..945fd274a4 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Откажи Download = Свали New version of PPSSPP available = Налична е нова версия на PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 5b43c0be1e..a14b220e4b 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 6a946ac451..2520baa821 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Později Download = Stáhnout New version of PPSSPP available = Je dostupná nová verze PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 2b131b3edc..4eba607452 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Afvis Download = Download New version of PPSSPP available = Ny version af PPSSPP tilgængelig + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 1616da144d..2dfc37987a 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Überspringen Download = Herunterladen New version of PPSSPP available = Neue PPSSPP Version verfügbar + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index b8ad29812b..f83994a38b 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index b21677e66c..cd74f8837b 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -1224,3 +1224,17 @@ Details = Detalles Dismiss = Cancelar Download = Descargar New version of PPSSPP available = Nueva versión de PPSSPP disponible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index cd2831b267..67f3418944 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -1224,3 +1224,17 @@ Details = Detalles Dismiss = Cancelar Download = Descargar New version of PPSSPP available = Nueva versión de PPSSPP disponible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 499dff93b2..2779016c4e 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index c2a35832b2..3dddf029cc 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index b1bfec51a4..9a0db6f84e 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -1215,3 +1215,17 @@ Details = Détails Dismiss = Ignorer Download = Télécharger New version of PPSSPP available = Nouvelle version de PPSSPP disponible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index a2a2f27553..87ab725d79 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Cancelar Download = Descargar New version of PPSSPP available = Nova versión de PPSSPP dispoñible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 11e7840167..174241a6ee 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Απόρριψη Download = Κατέβασμα New version of PPSSPP available = Νέα διαθέσιμη έκδοση PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 821036d929..8d01a00e32 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index ca4233a80a..a96b45ad00 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index e58183275c..c78c6187eb 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Zanemari Download = Instaliraj New version of PPSSPP available = Nova verzija PPSSPP-a je dostupna + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 2ae7447a73..6d93830448 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Kihagyás Download = Letöltés New version of PPSSPP available = Elérhető a PPSSPP egy újabb verziója + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index a6f15acfb5..84334eb1a4 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -1224,3 +1224,17 @@ Details = Rincian Dismiss = Abaikan Download = Unduh New version of PPSSPP available = Versi baru PPSSPP tersedia + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 2723d05977..3b136ec880 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -1225,3 +1225,17 @@ Details = Dettagli Dismiss = Ignora Download = Scarica New version of PPSSPP available = È disponibile una nuova versione di PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 074e477256..f7d7f29b7c 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = 無視 Download = ダウンロード New version of PPSSPP available = 新しいバージョンのPPSSPPを利用できます + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index fd05d3aa80..db13726e6b 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Ngilangi Download = Unduh New version of PPSSPP available = Versi anyar PPSSPP mpun ono monggo di comot + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 740988315f..730edd76a8 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -1245,3 +1245,17 @@ Choices: = 선택: List: = 목록: Progress: %1% = 진행율: %1% Screen representation = 화면 표현 + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index ba4a067705..4b80bad664 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = ຍົກເລີກ Download = ດາວໂຫຼດ New version of PPSSPP available = ເວີຊັ່ນໃໝ່ຂອງ PPSSPP ພ້ອມໃຫ້ໂຫຼດແລ້ວ! + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 35241f4db8..61c035ec75 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Atmesti Download = Parsisiūsti New version of PPSSPP available = Galima nauja "PPSSPP" versija + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 7b271dbdfd..b97cfcc78a 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Abaikan Download = Muat turun New version of PPSSPP available = Versi terbaru PPSSPP tersedia + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index aee4d59ea8..c22080e159 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Annuleren Download = Downloaden New version of PPSSPP available = Er is een nieuwe versie van PPSSPP beschikbaar + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 6b61af3c4a..55c98402d6 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index e9d371a870..b71c8075d6 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Odrzuć Download = Pobierz New version of PPSSPP available = Dostępna jest nowa wersja PPSSPP! + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index d914a68d81..016bad4ed5 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -1250,3 +1250,17 @@ Choices: = Escolhas: List: = Lista: Progress: %1% = Progresso: %1% Screen representation = Representação da tela + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 0b231bbc1b..2d1561c7f3 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -1250,3 +1250,17 @@ Choices: = Escolhas: List: = Lista: Progress: %1% = Progresso: %1% Screen representation = Representação da tela + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index fa6ad784ef..48341c5f18 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Ignoră Download = Descarcă New version of PPSSPP available = Nouă versiune de PPSSPP disponibilă. + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 0c19be0b88..5c286a6f62 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -1224,3 +1224,17 @@ Details = Подробности Dismiss = Отклонить Download = Загрузить New version of PPSSPP available = Доступна новая версия PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index d2751a26fb..3ed2d4c3e8 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -1224,3 +1224,17 @@ Details = Detaljer Dismiss = Stäng Download = Ladda ner New version of PPSSPP available = Ny version av PPSSPP tillgänglig + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 7b4d6d1a7f..d9661191a8 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -1224,3 +1224,17 @@ Details = Detalye Dismiss = Dismiss Download = Download New version of PPSSPP available = Meron nang bagong bersiyon ang PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index fe9256980a..bf972ade0b 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -1232,6 +1232,7 @@ New version of PPSSPP available = PPSSPP เวอร์ชั่นใหม่ Distance to 2D menus and scenes = ระยะห่างจากเมนูสองมิติ และฉาก Field of view scale = สเกลของมุมมองพื้นที่รอบตัว Force 72Hz update = บังคับการอัพเดทรีเฟรชเรทที่ 72Hz +Heads-up display scale = Heads-up display scale Map controller movements to keys = เซ็ตปุ่มควบคุมด้วยท่าทางผ่านจอย Motion needed to generate action = จำเป็นต้องขยับท่าทางเพื่อเซ็ตปุ่มที่ต้องการ Stereoscopic vision (Experimental) = มุมมองภาพแบบสามมิติ (ขั้นทดสอบ) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 98952e53d2..d346a92b5e 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1225,3 +1225,17 @@ Details = Detaylar Dismiss = Reddet Download = İndir New version of PPSSPP available = PPSSPP'nin yeni versiyonu mevcut + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index ecd8cf8794..2d60d05558 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Відхилити Download = Завантажити New version of PPSSPP available = Доступна нова версія PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index eaa35f2eb2..8b3c2aa73e 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -1224,3 +1224,17 @@ Details = Details Dismiss = Bỏ qua Download = Tải về New version of PPSSPP available = Đã có phiên bản mới của PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 8ed7531d78..94a23dc3ea 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1226,3 +1226,17 @@ Find settings = 搜索设置 Filter = 筛选 Clear filter = 清除筛选结果 No settings matched '%1' = 未找到设置'%1' + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index b6984f5e80..7d2388c25a 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -1225,3 +1225,17 @@ Choices: = 選擇: List: = 清單: Progress: %1% = 進度:%1% Screen representation = 螢幕呈現 + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers From 4ce8c0962dd9f0904e516da08e53d30e33a9d837 Mon Sep 17 00:00:00 2001 From: Benjamin Benda Gates Date: Mon, 12 Dec 2022 17:43:37 +0700 Subject: [PATCH 682/715] Update th_TH.ini --- assets/lang/th_TH.ini | 74 ++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index bf972ade0b..5c4544d9df 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -137,7 +137,7 @@ Direct3D9 = ไดเร็คท์ 3D 9 Direct3D11 = ไดเร็คท์ 3D 11 Disassembly = การแยกองค์ประกอบ... Discord = ไปที่ Discord -Display Layout && Effects = แก้ไขรูปแบบของหน้าจอ... +Display Layout && Effects = รูปแบบหน้าจอ และเอฟเฟ็คท์ Display Rotation = การสลับหมุนหน้าจอ Dump Next Frame to Log = ดึงข้อมูลของเฟรมถัดไปเพื่อเก็บบันทึกค่า Emulation = การจำลอง @@ -198,7 +198,7 @@ Save Map File... = บันทึกไฟล์ Map... Save State = เซฟสเตทเกม Save State File... = ไฟล์เซฟสเตทเกม... Savestate Slot = ช่องเซฟสเตทเกม -Screen Scaling Filter = ตัวกรองขนาดของหน้าจอ +Screen Scaling Filter = ตัวกรองปรับสเกลหน้าจอ Show Debug Statistics = แสดงค่าทางสถิติการแก้ไขจุดบกพร่อง Show FPS Counter = แสดงตัวจับค่าเฟรมเรท/วินาที Skip Number of Frames = อิงจากค่าจำนวนเฟรม @@ -313,8 +313,8 @@ Load completed = โหลดข้อมูลสำเร็จ Loading = กำลังโหลด\nโปรดรอ... LoadingFailed = ไม่สามารถโหลดข้อมูลนี้ได้ Move = ย้าย -Move Down = Move Down -Move Up = Move Up +Move Down = ย้ายลงล่าง +Move Up = ย้ายขึ้นบน Network Connection = การเชื่อมต่อเครือข่าย NEW DATA = ข้อมูลใหม่ No = ไม่ใช่ @@ -322,8 +322,8 @@ ObtainingIP = กำลังรับไอพี\nโปรดรอสัก OK = ตกลง Old savedata detected = ตรวจพบข้อมูลเซฟเก่า Options = ตัวเลือก -Remove = Remove -Reset = ตั้งค่าใหม่ +Remove = ลบออก +Reset = รีเซ็ต Resize = ขนาด Retry = ลองใหม่ Save = บันทึก @@ -458,8 +458,8 @@ Aggressive = รุนแรง Alternative Speed = เพิ่ม-ลดระดับความเร็ว (ใน %, 0 = ไม่จำกัด) Alternative Speed 2 = เพิ่ม-ลดระดับความเร็ว 2 (ใน %, 0 = ไม่จำกัด) Anisotropic Filtering = ตัวกรองขจัดความไม่คมชัดของพื้นผิว -Antialiasing (MSAA) = Antialiasing (MSAA) -Aspect Ratio = Aspect Ratio +Antialiasing (MSAA) = ลดรอยหยักภาพ (แบบ MSAA) +Aspect Ratio = สัดส่วนหน้าจอ Auto = อัตโนมัติ Auto (1:1) = อัตโนมัติ (1:1) Auto (same as Rendering) = อัตโนมัติ (ค่าเดียวกับที่ใช้แสดงผลภาพ) @@ -488,7 +488,7 @@ Device = การ์ดจอ Direct3D 9 = ไดเร็คท์ 3D 9 Direct3D 11 = ไดเร็คท์ 3D 11 Disabled = ปิดการใช้งาน -Display Layout && Effects = แก้ไขรูปแบบของหน้าจอ +Display Layout && Effects = รูปแบบหน้าจอ และเอฟเฟ็คท์ Display Resolution (HW scaler) = ความละเอียดหน้าจอ (ตามฮาร์ดแวร์) Enable Cardboard VR = เปิดการทำงานแว่นการ์ดบอร์ด VR FPS = เฟรมต่อวิ @@ -502,7 +502,7 @@ Hack Settings = ตั้งค่าการปรับแฮ็ค (อา Hardware Tessellation = ฮาร์ดแวร์ เทสเซลเลชั่น Hardware Transform = ใช้ฮาร์ดแวร์ในการแปลงค่าประมวลผล hardware transform error - falling back to software = การแปลงค่าจากฮาร์ดแวร์ล้มเหลว กลับไปใช้การแปลงค่าจากซอฟต์แวร์ -HardwareTessellation Tip = ใช้ฮาร์ดแวร์ในการสร้างเส้นโค้ง Spline/Bezier ช่วยปรับปรุงคุณภาพเส้นให้คงที่ +HardwareTessellation Tip = ใช้ฮาร์ดแวร์ในการสร้างเส้นโค้ง High = สูง Hybrid = ไฮบริด Hybrid + Bicubic = ไฮบริด + ไบคิวบิค @@ -513,8 +513,8 @@ Lazy texture caching Tip = เร็วขึ้น แต่อาจจะท Linear = แบบเชิงเส้น Low = ต่ำ LowCurves = ระดับของเส้นโค้ง Spline/Bezier -LowCurves Tip = ปรับเพิ่ม-ลดคุณภาพในการแสดงผลของเส้นโค้ง Spline/Bezier -Lower resolution for effects (reduces artifacts) = ลดความละเอียดของเอฟเฟ็คต์ให้ต่ำลง (แก้ภาพสว่างจ้า) +LowCurves Tip = ใช้แค่ในบางเกม ช่วยปรับคุณภาพของเส้นโค้งให้มีความเรียบเนียนขึ้น +Lower resolution for effects (reduces artifacts) = ลดความละเอียดของเอฟเฟ็คต์ให้ต่ำลง (ลดขอบภาพสว่าง) Manual Scaling = กำหนดขนาดเอง Medium = ปานกลาง Mode = โหมด @@ -537,7 +537,7 @@ Render duplicate frames to 60hz = แสดงผลเฟรมซ้ำให RenderDuplicateFrames Tip = ช่วยให้ภาพดูลื่นตาขึ้น ในเกมที่ใช้เฟรมเรทต่ำ Rendering Mode = โหมดที่ใช้ในการแสดงผล Rendering Resolution = ความละเอียดในการแสดงผลภาพ -RenderingMode NonBuffered Tip = เร็วขึ้นก็จริง แต่มีผลข้างเคียงในบางเกมอาจเกิดอาการจอดำ +RenderingMode NonBuffered Tip = เร็วขึ้นก็จริง แต่กราฟิกอาจจะขาดหายไปในบางเกม Rotation = หมุนจอ Safe = ปลอดภัย Screen Scaling Filter = ตัวกรองปรับสเกลหน้าจอ @@ -556,7 +556,7 @@ Texture Filter = ตัวกรองพื้นผิว Texture Filtering = การกรองพื้นผิว Texture Scaling = การปรับสเกลพื้นผิว Texture Shader = โทนแสงสีพื้นผิว -Turn off Hardware Tessellation - unsupported = ปิด "ฮาร์ดแวร์ เทสเซลเลชั่น" เนื่องจากไม่สนับสนุนการทำงาน +Turn off Hardware Tessellation - unsupported = ปิด "ฮาร์ดแวร์ เทสเซลเลชั่น" แล้ว เนื่องจากไม่สนับสนุนการทำงาน Unlimited = ไม่จำกัด Up to 1 = เพิ่มไปที่ 1 Up to 2 = เพิ่มไปที่ 2 @@ -595,7 +595,7 @@ Show PSP = แสดง PSP You can press ESC to cancel. = คุณสามารถกด ESC เพื่อยกเลิกได้ [MainMenu] -Browse = เรียกใช้... +Browse = เรียกดู... Buy PPSSPP Gold = ซื้อ PPSSPP Gold Choose folder = เลือกโฟลเดอร์ Credits = เครดิต @@ -606,17 +606,17 @@ Give PPSSPP permission to access storage = อนุญาตให้สิท Homebrew & Demos = เกมโฮมบริว&&เกมทดลองเล่น How to get games = ต้องทำอย่างไรถึงจะได้รอมเกมมา? How to get homebrew & demos = วิธีการรับเกมโฮมบริว&&เกมทดลองเล่น? -Load = โหลดเกม... +Load = โหลด... Loading... = กำลังโหลด... PinPath = ปักหมุด PPSSPP can't load games or save right now = --- ไม่สามารถโหลดเข้าเกมหรือข้อมูลเซฟได้ในขณะนี้ --- -PPSSPP Homebrew Store = ดาวน์โหลดจาก PPSSPP โฮมบริวสโตร์ +PPSSPP Homebrew Store = PPSSPP โฮมบริวสโตร์ Recent = เกมที่พึ่งเล่นล่าสุด SavesAreTemporary = PPSSPP จะเซฟข้อมูลในโฟลเดอร์ชั่วคราว SavesAreTemporaryGuidance = แนะนำให้แตกไฟล์ PPSSPP ก่อนที่จะใช้งานนะจ้ะ เซฟจะได้ไม่บิน SavesAreTemporaryIgnore = ไม่สนคำเตือน UnpinPath = ถอนหมุด -UseBrowseOrLoad = ใช้ตัวเลือก เรียกใช้... เพื่อเลือกโฟลเดอร์ หรือ โหลด... เพื่อเลือกไฟล์ +UseBrowseOrLoad = ใช้ตัวเลือก เรียกดู... เพื่อเลือกโฟลเดอร์ หรือ โหลด... เพื่อเลือกไฟล์ www.ppsspp.org = เว็บไซต์หลัก PPSSPP [MainSettings] @@ -636,6 +636,7 @@ An.Left = อนาล็อก(ซ้าย)ซ้าย An.Right = อนาล็อก(ซ้าย)ขวา An.Up = อนาล็อก(ซ้าย)ขึ้น Analog limiter = ตัวจำกัดปุ่มอนาล็อก +Analog speed = ความเร็วอนาล็อก Analog Stick = ปุ่มอนาล็อก Audio/Video Recording = อัดบันทึกวีดีโอ/เสียง AxisSwap = สลับด้านแกน @@ -752,8 +753,8 @@ Center Left = มุมกลางซ้ายจอ Center Right = มุมกลางขวาจอ Change Mac Address = เปลี่ยนค่าที่อยู่ Mac Change proAdhocServer Address = เปลี่ยนไอพีที่อยู่ของเซิร์ฟเวอร์ Pro Adhoc (localhost = แลนในเครื่องเดียวกัน) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +ChangeMacSaveConfirm = ต้องการสร้างค่า MAC address ใหม่? +ChangeMacSaveWarning = บางเกมจะตรวจสอบค่า MAC address ตอนโหลดข้อมูลเซฟ เพราะงั้นอาจจะทำให้เซฟอันเก่าใช้งานไม่ได้ Chat = แชท Chat Button Position = ปุ่มตำแหน่งแชท Chat Here = แชทที่นี่ @@ -819,17 +820,18 @@ Rewind = โหลดสเตทพื้นหลัง Save State = เซฟสเตทเกม Settings = การตั้งค่า Switch UMD = สลับแผ่น UMD -Undo last load = เลิกทำโหลดครั้งล่าสุด -Undo last save = เลิกทำเซฟครั้งล่าสุด +Undo last load = ย้อนคืนโหลดครั้งล่าสุด +Undo last save = ย้อนคืนเซฟครั้งล่าสุด [PostShaders] (duplicated setting, previous slider will be used) = (การตั้งค่าที่ซ้ำซ้อนกัน อาจจะใช้แถบเลื่อนก่อนหน้า) -4xHqGLSL = ภาพคมชัดคูณ 4 -5xBR = ภาพคมชัดคูณ 5 -5xBR-lv2 = ภาพคมชัดคูณ 5 (เวอร์ชั่น 2) +4xHqGLSL = ภาพอัพสเกลพิกเซลอาร์ตคูณ 4 +5xBR = ภาพอัพสเกลพิกเซลอาร์ตคูณ 5 +5xBR-lv2 = ภาพอัพสเกลพิกเซลอาร์ตคูณ 5 (เวอร์ชั่น 2) AAColor = ภาพดูมีสีสัน Amount = ระดับ Animation speed (0 -> disable) = ความเร็วอนิเมชั่น (0 = ปิดใช้งาน) +Aspect = ทิศทาง Black border = ขอบดำ Bloom = ภาพสว่างขึ้น Brightness = แสงสว่าง @@ -843,7 +845,8 @@ FXAA = ภาพเน้นลบขอบรอยหยัก Gamma = แกมม่า GreenLevel = ระดับสีเขียว Intensity = ความเข้มของแสง -LCDPersistence = LCD Persistence +InverseColors = ภาพสีกลับ +LCDPersistence = ภาพ LCD แบบค้างคา MitchellNetravali = ภาพอัพสเกลแบบไบคิวบิค (มิทเชลล์-เนทราวาลิ) Natural = ภาพเน้นสีธรรมชาติ NaturalA = ภาพเน้นสีธรรมชาติ (ไม่เบลอ) @@ -856,6 +859,7 @@ Scanlines = ภาพออกมัวเป็นเส้นแนวนอ Sharpen = ภาพเน้นขอบคมขึ้น SideBySide = ภาพแยกสองจอแบบสามมิติ SSAA(Gauss) = ภาพเน้นความละเอียดให้สูงขึ้น +Strength = ความเด่นชัด Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleSpline36 = ภาพลดความละเอียด เน้นสเกลคมขึ้น @@ -1012,6 +1016,7 @@ Filter = ตัวกรอง Filtering settings by '%1' = ตัวกรองตั้งค่าที่ค้นพบโดย '%1' Find settings = ค้นหาตัวเลือกตั้งค่า No settings matched '%1' = ไม่มีตั้งค่าที่ตรงกันกับ '%1' +Search term = คำที่ต้องการค้นหา [Store] Already Installed = ติดตั้งเรียบร้อยแล้ว @@ -1024,11 +1029,11 @@ Size = ขนาด Uninstall = ถอนการติดตั้ง [SysInfo] -%0.2f Hz = %0.2f Hz +%0.2f Hz = %0.2f เฮิร์ต %d (%d per core, %d cores) = %d (%d เธรด ต่อคอร์, %d คอร์) %d bytes = %d ไบต์ -%d Hz = %d Hz -(none detected) = (ไม่พบ) +%d Hz = %d เฮิร์ต +(none detected) = (ไม่มีการตรวจพบ) 3D API = แอพพลิเคชั่น โปรแกรม อินเตอร์เฟซ สามมิติ ABI = แอพพลิเคชั่น ไบนารี่ อินเตอร์เฟซ API Version = เวอร์ชั่นของแอพพลิเคชั่น โปรแกรม อินเตอร์เฟซ @@ -1045,7 +1050,7 @@ CPU Name = ชื่อหน่วยประมวลผลหลัก D3DCompiler Version = เวอร์ชั่นตัวคอมไพล์ของ D3D Debug = แก้ไขบั๊ก Debugger Present = ตัวช่วยแก้ไขบั๊ก -Depth buffer format = Depth buffer format +Depth buffer format = รูปแบบบัฟเฟอร์ความลึก Device Info = ข้อมูลอุปกรณ์ Directories = เส้นทางเก็บข้อมูล Display Color Formats = รูปแบบสีของหน้าจอแสดงผล @@ -1054,9 +1059,11 @@ Driver bugs = ไดรเวอร์บั๊ก Driver Version = เวอร์ชั่นของไดรเวอร์ EGL Extensions = ส่วนขยายอีจีแอล Frames per buffer = จำนวนเฟรมต่อบัฟเฟอร์ +GPU Flags = แฟล็กของหน่วยประมวลผลกราฟิก GPU Information = ข้อมูลของหน่วยประมวลผลกราฟิก High precision float range = ขอบเขตจำนวนทศนิยมช่วงค่าความแม่นยำสูง High precision int range = ขอบเขตจำนวนเต็มช่วงค่าความแม่นยำสูง +JIT available = JIT ใช้งานได้ Lang/Region = ภาษา/ภูมิภาค Memory Page Size = ขนาดหน้าของหน่วยความจำ Native Resolution = ความละเอียดดั้งเดิม @@ -1085,6 +1092,7 @@ Vendor (detected) = ผู้จัดจำหน่าย (ที่ตรว Version Information = ข้อมูลของเวอร์ชั่น Vulkan Extensions = ส่วนขยายของวัลแคน Vulkan Features = ฟีเจอร์วัลแคน +UI Resolution = ความละเอียดของอินเตอร์เฟซ [System] (broken) = (เสียหาย) @@ -1128,7 +1136,7 @@ Fast Memory = หน่วยความจำทำงานได้เร็ Floating symbols = สัญลักษณ์ปุ่มจอยลอยไปมา Force real clock sync (slower, less lag) = บังคับการซิงค์สัญญาณความถี่ (ช้ากว่า, เเล็กน้อยลง) frames, 0:off = เฟรม, 0 = ปิด -Game crashed = เกมเด้งจ้า +Game crashed = Game crashed Games list settings = การตั้งค่าในรายการเกม General = ทั่วไป Grid icon size = ขนาดของไอคอนเกม @@ -1231,8 +1239,8 @@ New version of PPSSPP available = PPSSPP เวอร์ชั่นใหม่ 6DoF movement = การเคลื่อนไหวแบบ 6DoF Distance to 2D menus and scenes = ระยะห่างจากเมนูสองมิติ และฉาก Field of view scale = สเกลของมุมมองพื้นที่รอบตัว -Force 72Hz update = บังคับการอัพเดทรีเฟรชเรทที่ 72Hz -Heads-up display scale = Heads-up display scale +Force 72Hz update = บังคับรีเฟรชเรทไปที่ 72Hz +Heads-up display scale = สเกลขนาดของ HUD Map controller movements to keys = เซ็ตปุ่มควบคุมด้วยท่าทางผ่านจอย Motion needed to generate action = จำเป็นต้องขยับท่าทางเพื่อเซ็ตปุ่มที่ต้องการ Stereoscopic vision (Experimental) = มุมมองภาพแบบสามมิติ (ขั้นทดสอบ) From 5c9cca4f487af6c1a900428a04cd3bf62a502cb3 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Mon, 12 Dec 2022 14:56:46 +0300 Subject: [PATCH 683/715] Update Russian translation --- assets/lang/ru_RU.ini | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 5c286a6f62..7774899cc3 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -232,7 +232,7 @@ Disabled JIT functionality = Отключение функционала JIT Draw Frametimes Graph = Отрисовывать график времени кадров Dump Decrypted Eboot = Дамп дешифрованного EBOOT.BIN при запуске Dump next frame to log = Сохранить следующий кадр в логе -Enable driver bug workarounds = Включить обход багов драйвера +Enable driver bug workarounds = Включить обход ошибок драйвера Enable Logging = Включить отладочное логирование Enter address = Ввести адрес FPU = FPU @@ -252,7 +252,7 @@ No block = Нет блока Prev = Предыдущий Random = Случайный Replace textures = Подменять текстуры -Reset = Reset +Reset = Сбросить Reset limited logging = Сбросить ограниченное логирование RestoreDefaultSettings = "Вы уверены, что хотите сбросить настройки\n(кроме управления) на стандартные?\nВы не сможете это отменить.\nПожалуйста, перезапустите PPSSPP после сброса." RestoreGameDefaultSettings = Вы уверены, что хотите вернуть все параметры игры к стандартным? @@ -313,8 +313,8 @@ Load completed = Загрузка завершена Loading = Загрузка\nПожалуйста, подождите... LoadingFailed = Невозможно загрузить даные. Move = Положение -Move Down = Move Down -Move Up = Move Up +Move Down = Сдвинуть вверх +Move Up = Сдвинуть вниз Network Connection = Сетевое подключение NEW DATA = Новое сохранение No = Нет @@ -322,7 +322,7 @@ ObtainingIP = Получение IP-адреса.\nПожалуйста, под OK = OK Old savedata detected = Старый формат сохранений обнаружен Options = Опции -Remove = Remove +Remove = Удалить Reset = Сбросить Resize = Размер Retry = Снова @@ -656,10 +656,10 @@ D-pad left = D-pad влево D-pad right = D-pad вправо D-pad up = D-pad вверх DevMenu = Меню разраб. -Display Landscape = Display Landscape -Display Landscape Reversed = Display Landscape Reversed -Display Portrait = Display Portrait -Display Portrait Reversed = Display Portrait Reversed +Display Landscape = Альбомная ориентация +Display Landscape Reversed = Альбомная ориентация (перевернутая) +Display Portrait = Портретная ориентация +Display Portrait Reversed = Портретная ориентация (перевернутая) Double tap button = Двойное нажатие на кнопку Down = Вниз Dpad = Крестовина @@ -818,7 +818,7 @@ LCDPersistence = Остаточное изображение ЖК-дисплея MitchellNetravali = Бикубический (Mitchell-Netravali) апскейлер Natural = Естественные цвета NaturalA = Естественные цвета (без размытия) -Off = Выключена +Off = Выключено Power = Сила PSPColor = Цвета PSP RedBlue = Красно-синие очки @@ -1209,16 +1209,16 @@ Tex4xBRZ = Tex4xBRZ Default = По умолчанию [UI Elements] -%1 button = %1 button -%1 checkbox = %1 checkbox -%1 choice = %1 choice -%1 heading = %1 heading -%1 radio button = %1 radio button -%1 text field = %1 text field -Choices: = Choices: -List: = List: -Progress: %1% = Progress: %1% -Screen representation = Screen representation +%1 button = %1 кнопка +%1 checkbox = %1 чекбокс +%1 choice = %1 выбор +%1 heading = %1 указание +%1 radio button = %1 радиокнопка +%1 text field = %1 текстовое поле +Choices: = Выборы: +List: = Список: +Progress: %1% = Прогресс: %1% +Screen representation = Представление экрана [Upgrade] Details = Подробности Dismiss = Отклонить @@ -1226,15 +1226,15 @@ Download = Загрузить New version of PPSSPP available = Доступна новая версия PPSSPP [VR] -% of native FoV = % of native FoV -6DoF movement = 6DoF movement -Distance to 2D menus and scenes = Distance to 2D menus and scenes -Field of view scale = Field of view scale -Force 72Hz update = Force 72Hz update -Heads-up display scale = Heads-up display scale -Map controller movements to keys = Map controller movements to keys -Motion needed to generate action = Motion needed to generate action -Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) -Virtual reality = Virtual reality -VR camera = VR camera -VR controllers = VR controllers +% of native FoV = % стандартного угла обзора +6DoF movement = Движение 6DoF +Distance to 2D menus and scenes = Расстояние до 2D-меню и сцен +Field of view scale = Масштаб угла обзора +Force 72Hz update = Принудительная частота обновления 72 Гц +Heads-up display scale = Масштаб HUD +Map controller movements to keys = Назначить движения контроллера на клавиши +Motion needed to generate action = Необходимо движение для создания действия +Stereoscopic vision (Experimental) = Стереоизображение (экспериментально) +Virtual reality = Виртуальная реальность +VR camera = Камера ВР +VR controllers = Контроллеры ВР From aac30d75f9d4fdf5a6ddc9a1620b00336abd46e9 Mon Sep 17 00:00:00 2001 From: nassau-tk <48179091+nassau-tk@users.noreply.github.com> Date: Mon, 12 Dec 2022 21:07:40 +0900 Subject: [PATCH 684/715] Translation ja_JP.ini update (#16557) * Translation ja_JP.ini update * Update ja_JP.ini Add [VR] --- assets/lang/ja_JP.ini | 126 +++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index f7d7f29b7c..78be44d9a8 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -2,7 +2,7 @@ Alternate speed volume = カスタム速度時のボリューム Audio backend = オーディオのバックエンド (再起動が必要) Audio Error = オーディオエラー -AudioBufferingForBluetooth = Bluetoothに適したバッファ (低速) +AudioBufferingForBluetooth = Bluetoothに適したバッファ (低遅延) Auto = 自動 Device = デバイス Disabled = Disabled @@ -252,7 +252,7 @@ No block = ブロックなし Prev = 前へ Random = ランダム Replace textures = テクスチャを置き換える -Reset = Reset +Reset = リセット Reset limited logging = Reset limited logging RestoreDefaultSettings = 全ての設定 (キーの設定は除く) をデフォルトに戻しますか?\nやり直すことはできません。\n変更を反映させるにはPPSSPPを再起動してください。 RestoreGameDefaultSettings = ゲームの設定をPPSSPPのデフォルトに\n戻しますか? @@ -284,10 +284,10 @@ Choose PPSSPP save folder = PPSSPPのセーブ用フォルダを選択する Confirm Overwrite = データを上書きしますか? Confirm Save = データをセーブしますか? ConfirmLoad = データをロードしますか? -ConnectingAP = Connecting to the access point.\nPlease wait... -ConnectingPleaseWait = Connecting.\nPlease wait... -ConnectionName = Connection name -Corrupted Data = Corrupted data +ConnectingAP = アクセスポイントに接続中.\nしばらくお待ちください... +ConnectingPleaseWait = 接続中.\nしばらくお待ちください... +ConnectionName = 接続名 +Corrupted Data = 破損したデータ Delete = 削除 Delete all = 全て削除 Delete completed = 削除が完了しました。 @@ -313,8 +313,8 @@ Load completed = ロードが完了しました。 Loading = ロード中です。\nしばらくお待ちください... LoadingFailed = データをロードできませんでした。 Move = 移動 -Move Down = Move Down -Move Up = Move Up +Move Down = 下へ移動 +Move Up = 上へ移動 Network Connection = ネットワーク接続 NEW DATA = 新しいデータ No = いいえ @@ -322,7 +322,7 @@ ObtainingIP = IPアドレスの取得中。 \nしばらくお待ちください. OK = OK Old savedata detected = 古いセーブデータを検出しました Options = オプション -Remove = Remove +Remove = 削除 Reset = リセット Resize = リサイズ Retry = リトライ @@ -330,10 +330,10 @@ Save = セーブ Save completed = セーブが完了しました。 Saving = セーブ中です。\nしばらくお待ちください... SavingFailed = データをセーブできませんでした。 -Search = Search -Select = Select -Shift = Shift -Skip = Skip +Search = 検索 +Select = セレクト +Shift = シフト +Skip = スキップ Snap = グリッドに吸着 Space = スペース SSID = SSID @@ -458,13 +458,13 @@ Aggressive = 最大限 Alternative Speed = カスタム速度1 (%で指定、0 = 無制限) Alternative Speed 2 = カスタム速度2 (%で指定、0 = 無制限) Anisotropic Filtering = 異方性フィルタリング -Antialiasing (MSAA) = Antialiasing (MSAA) -Aspect Ratio = Aspect Ratio +Antialiasing (MSAA) = アンチエイリアス (MSAA) +Aspect Ratio = アスペクト比 Auto = 自動 Auto (1:1) = 自動 (1:1) Auto (same as Rendering) = 自動 (レンダリング解像度と同じ) Auto FrameSkip = オートフレームスキップ -Auto Max Quality = Auto Max Quality +Auto Max Quality = 自動最高品質 Auto Scaling = 自動的に拡大 Backend = バックエンド Balanced = バランス @@ -496,8 +496,8 @@ Frame Rate Control = フレームレートのコントロール Frame Skipping = フレームスキップ Frame Skipping Type = フレームスキップのタイプ FullScreen = フルスクリーン -Geometry shader culling = Geometry shader culling -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +Geometry shader culling = ジオメトリシェーダーのカリング +GPUReadbackRequired = 警告: このゲームは"GPUリードバックのスキップ"をオフにする必要があります。 Hack Settings = ハックの設定 (不具合あり) Hardware Tessellation = ハードウェアテッセレーション Hardware Transform = ハードウェアトランスフォーム @@ -532,7 +532,7 @@ Partial Stretch = 部分的に拡大 Percent of FPS = FPS中のパーセント Performance = パフォーマンス Postprocessing shaders = 後処理シェーダ -Recreate Activity = Recreate activity +Recreate Activity = アクティビティを再作成する Render duplicate frames to 60hz = フレームを複製して60Hzでレンダリングする RenderDuplicateFrames Tip = フレームレートが低いゲームでフレームレートをよりスムーズにできます Rendering Mode = レンダリングモード @@ -543,14 +543,14 @@ Safe = セーフ Screen Scaling Filter = 画像スケーリングのフィルタ Show Debug Statistics = デバッグ情報を表示する Show FPS Counter = FPSを表示する -Skip GPU Readbacks = Skip GPU Readbacks +Skip GPU Readbacks = GPUリードバックのスキップ Software Rendering = ソフトウェアレンダリング (実験的) Software Skinning = ソフトウェアスキニング SoftwareSkinning Tip = スキンモデルの描画をCPUでまとめて行う。ほとんどのゲームが高速化します Speed = 速度 Speed Hacks = Speed Hacks (不具合あり) -Stereo display shader = Stereo display shader -Stereo rendering = Stereo rendering +Stereo display shader = ステレオディスプレイシェーダー +Stereo rendering = ステレオレンダリング Stretch = 拡大 Texture Filter = テクスチャフィルタ Texture Filtering = テクスチャフィルタリング @@ -624,7 +624,7 @@ Audio = オーディオ Controls = コントロール Graphics = グラフィックス Networking = ネットワーク -Search = Search +Search = 検索 System = システム Tools = ツール @@ -714,7 +714,7 @@ Wlan = WLAN [Networking] AdHoc Server = アドホックサーバ AdhocServer Failed to Bind Port = アドホックサーバーがポートのバインドに失敗しました -AM: Data from Unknown Port = AM: Data from Unknown Port +AM: Data from Unknown Port = AM: 不明なポートからのデータ Auto = 自動 Bottom Center = 下中央 Bottom Left = 左下 @@ -723,12 +723,12 @@ Center Left = 左中央 Center Right = 右中央 Change Mac Address = MACアドレスを変更する Change proAdhocServer Address = PROアドホックサーバのIPアドレスを変更する (localhost = multiple instances) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +ChangeMacSaveConfirm = 新しいMACアドレスを生成しますか? +ChangeMacSaveWarning = いくつかのゲームのセーブデータはMACアドレスを照合します。一致しない場合データが使用不可、または破損する場合があります。 Chat = チャット Chat Button Position = チャットボタンの位置 Chat Here = ここにチャットを入力する -Chat message = Chat message +Chat message = チャットメーッセージ Chat Screen Position = チャット画面の位置 Disconnected from AdhocServer = アドホックサーバーから切断する DNS Error Resolving = DNSエラーの解決 @@ -748,13 +748,13 @@ Failed to Bind Localhost IP = ローカルホストIPのバインドに失敗し Failed to Bind Port = ポートのバインドに失敗しました Failed to connect to Adhoc Server = アドホックサーバーに接続できませんでした Forced First Connect = 強制初期接続 (より速い接続) -GM: Data from Unknown Port = GM: Data from Unknown Port -Hostname = Hostname +GM: Data from Unknown Port = GM: 不明なポートからのデータ +Hostname = ホストネーム Invalid IP or hostname = 無効なIPまたはホスト名 Minimum Timeout = 最小タイムアウト (低遅延をオーバーライド、単位ms) Misc = その他 (デフォルト = PSP互換) Network Initialized = ネットワークを初期化 -None = None +None = 無し Please change your Port Offset = ポートオフセットを変更してください Port offset = ポートオフセット (0 = PSP互換) Open PPSSPP Multiplayer Wiki Page = PPSSPPのアドホック接続Wikiページを開く (英語) @@ -874,24 +874,24 @@ website = ウェブサイトはこちら: written = 速度と移植性を保つためにC++で書かれています [MemStick] -Already contains PSP data = Already contains PSP data -Current = Current +Already contains PSP data = 既にPSPデータが存在しています。 +Current = 現在の DataWillStay = 保存データはPPSSPPをアンインストールしても残る。 DataCanBeShared = 通常版/ゴールド間でのデータの共有が可能。 DataCannotBeShared = 通常版/ゴールド間でのデータの共有が「できない」。 -Done! = Done! +Done! = 完了! EasyUSBAccess = PCとのUSB接続でフォルダにアクセスが簡単にできる。 -Failed to move some files! = Failed to move some files! -Failed to save config = Failed to save config -Free space = Free space -Manually specify PSP folder = Manually specify PSP folder -Move Data = Move Data -No data will be changed = No data will be changed -PPSSPP will restart after the change = PPSSPP will restart after the change -Selected PSP Data Folder = Selected PSP Data Folder -Skip for now = Skip for now -Starting move... = Starting move... -That folder doesn't work as a memstick folder. = That folder doesn't work as a memstick folder. +Failed to move some files! = いくつかのファイルの移動に失敗しました! +Failed to save config = セーブコンフィグに失敗しました! +Free space = 空き容量 +Manually specify PSP folder = PSPフォルダーを手動で設定する +Move Data = データ移動 +No data will be changed = データに変更はありません +PPSSPP will restart after the change = PPSSPPは変更後に再起動します +Selected PSP Data Folder = 選択されたPSPフォルダー +Skip for now = 今はスキップする +Starting move... = 移動開始... +That folder doesn't work as a memstick folder. = そのフォルダーはメモリースティックフォルダーとしては使用できません。 USBAccessThrough = USB接続は Android/data/org.ppsspp.ppsspp/files を通して行う。 USBAccessThroughGold = USB接続は Android/data/org.ppsspp.ppssppgold/files を通して行う。 DataWillBeLostOnUninstall = 警告! PPSSPPをアンインストールすると保存データも削除されます! @@ -899,8 +899,8 @@ MemoryStickDescription = PSPデータの保存先の選択(メモリースティ Create or Choose a PSP folder = フォルダの新規作成または既存フォルダの選択 Use App Private Data = アプリのプライベートフォルダに保存 Use PSP folder at root of storage = デバイスの内部ストレージのルートに保存 -Welcome to PPSSPP! = Welcome to PPSSPP! -WhatsThis = What's this? +Welcome to PPSSPP! = ようこそPPSSPPへ! +WhatsThis = What's This?! [RemoteISO] Browse Games = ゲームをブラウズする @@ -1007,11 +1007,11 @@ State load undone = ステートロードが取り消されました。 Untitled PSP game = 無題のPSPゲーム [Search] -No settings matched '%1' = No settings matched '%1' -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -Filter = Filter -Clear filter = Clear filter +No settings matched '%1' = この検索ワードにマッチするものはありませんでした '%1' +Filtering settings by '%1' = この検索ワードに設定しました '%1' +Find settings = メニュー内の設定項目の検索 +Filter = 検索する文字(ここをクリック) +Clear filter = 検索文字のクリア [Store] Already Installed = インストール済み @@ -1226,15 +1226,15 @@ Download = ダウンロード New version of PPSSPP available = 新しいバージョンのPPSSPPを利用できます [VR] -% of native FoV = % of native FoV -6DoF movement = 6DoF movement -Distance to 2D menus and scenes = Distance to 2D menus and scenes -Field of view scale = Field of view scale -Force 72Hz update = Force 72Hz update -Heads-up display scale = Heads-up display scale -Map controller movements to keys = Map controller movements to keys -Motion needed to generate action = Motion needed to generate action -Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) -Virtual reality = Virtual reality -VR camera = VR camera -VR controllers = VR controllers +% of native FoV = ネイティブ視野角(FoV)の % +6DoF movement = 6DoF動作 +Distance to 2D menus and scenes = 2Dメニューと空間までの距離 +Field of view scale = 視野角のスケール +Force 72Hz update = 72Hzに強制的に更新 +Heads-up display scale = ヘッドアップディスプレイスケール +Map controller movements to keys = コントローラーの動きをキーにマッピングする +Motion needed to generate action = アクションを生成するために必要なモーション +Stereoscopic vision (Experimental) = 立体映像 (実験的機能) +Virtual reality = バーチャルリアリティー +VR camera = VRカメラ +VR controllers = VRコントローラー From ff4971ff626612bab0f67371baa950d457295d62 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Mon, 12 Dec 2022 17:30:08 +0300 Subject: [PATCH 685/715] Update URL to HTTPS (#16561) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a9a7bc744..5afe074ce9 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Looking for [older news](history.md)? Adhoc support ------------- -Not fully functional, but some games work. Check the [Ad-Hoc section of the forum](http://forums.ppsspp.org/forumdisplay.php?fid=34) for help. +Not fully functional, but some games work. Check the [Ad-Hoc section of the forum](https://forums.ppsspp.org/forumdisplay.php?fid=34) for help. Credit goes to: - ANR2ME From 58098057dbd8ef425e734046947f8e2906d4baaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 23:58:51 +0100 Subject: [PATCH 686/715] Update README.md for 1.14 --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index 5afe074ce9..27e2423eab 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,47 @@ If you want to download regularly updated builds for Android, Windows x86 and x6 For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). +What's new in 1.14 +================== +* Massive number of rendering fixes + - Water in Outrun 2006 and DiRT 2 now renders correctly (logic op fixes) + - Split/Second now renders all effects correctly + - Killzone color effect now renders efficiently and correctly (in-game only, not title screen) + - Ridge Racer speedometers and lens flares fixed + - Lens flare effect fixed in Burnout Dominator, Ridge Racer, Colin McRae, several others + - Shadows in Colin McRae are no longer flickering (side effect of other fixes) + - Spongebob: Yellow Avenger renders correctly (previously very broken) + - Cars: Race-o-Rama, and MX vs ATV Reflex render correctly (at 1x resolution only) ([#15898], [#15907]) + - Asphalt 2 depth occlusion problems fixed ([#15854]) + - Silent Hill games are less broken + - Depth occlusion problems fixed in Kurohyou (both games) and Ratchet & Clank ([#15772], [#15728], [#15859]) + - Other rendering problems fixed in Kurohyou ([#16454]) + - Misshitsu no Sacrifice intro animation and Macross water rendering fixed (3d texture) ([#15727]) + - Tekken 6 Nancy laser beam fixed, plus line rendering fixes in other games + - Multiple workarounds for clipping/culling, both through clip planes and geometry shaders, fixing + graphical issues in many games + - Many, many others +* Software renderer performance and accuracy improvements + - Better performance + - Clipping improvements, various fixes ([#16384], [#16385]) +* New features + - Initial VR support added (Quest and PICO only for now, PC in the future) + - MSAA antialiasing added to the Vulkan backend (desktop only) ([#16458]) +* UI improvements + - New interactive Display Layout & Effects screen, replacing the old Display Layout Editor + - Game being played can now be seen as a background in most menus ([#16404], more) +* Stability fixes + - Workaround for hangs on older Adreno GPUs ([#16422]) + - Many others +* IR interpreter bug fixes + - Metal Gear Solid - Peace Walker no longer bugged out ([#16396]) + - VFPU fixes ([#16302]) +* Performance improvements + - Vulkan bandwidth and synchronization optimizations ([#16434]) + - Assorted minor other improvements +* Other compatibility fixes (Twinbee, Shining Ark) +* GE debugger improvements + What's new in 1.13.2 ==================== * Crashfix on Android 12 when playing certain background music ([#15990]) From e533be471a9ac95cc231034f421d7665bb792e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Dec 2022 23:41:06 +0100 Subject: [PATCH 687/715] More README updates, issue links, move to history.md --- README.md | 122 ++++++++++------------------------------------------- history.md | 82 +++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 27e2423eab..6516f823ed 100644 --- a/README.md +++ b/README.md @@ -28,42 +28,47 @@ For game compatibility, see [community compatibility feedback](https://report.pp What's new in 1.14 ================== * Massive number of rendering fixes - - Water in Outrun 2006 and DiRT 2 now renders correctly (logic op fixes) + - Water in Outrun 2006 and DiRT 2 now renders correctly (logic op fixes) ([#15960], [#16208], [#16032], [#16024], [#15967]) - Split/Second now renders all effects correctly - - Killzone color effect now renders efficiently and correctly (in-game only, not title screen) - - Ridge Racer speedometers and lens flares fixed - - Lens flare effect fixed in Burnout Dominator, Ridge Racer, Colin McRae, several others + - Multiple fixes workarounds for clipping/culling, both through clip planes and geometry shaders, fixing + graphical issues in many, many games and getting rid of hacks ([#16142], [#16504], [#16442], [#16383], [#16165], many others) + - Killzone color effect now renders efficiently and correctly (in-game only, not title screen) ([#15934]) + - Ridge Racer speedometers and lens flares fixed ([#16084], [#16188], [#16115]) + - Lens flare effect fixed in Burnout Dominator, Ridge Racer, Colin McRae, several others ([#16014], [#16081], [#16076], [#16073]) - Shadows in Colin McRae are no longer flickering (side effect of other fixes) - - Spongebob: Yellow Avenger renders correctly (previously very broken) + - Spongebob: Yellow Avenger renders correctly (previously very broken) ([#15907], [#15903]) - Cars: Race-o-Rama, and MX vs ATV Reflex render correctly (at 1x resolution only) ([#15898], [#15907]) - - Asphalt 2 depth occlusion problems fixed ([#15854]) + - Asphalt 2 depth occlusion problems fixed ([#15854], [#15853]) + - Fix performance regression in Juiced 2 while also fixing the graphics ([#15888]) - Silent Hill games are less broken - Depth occlusion problems fixed in Kurohyou (both games) and Ratchet & Clank ([#15772], [#15728], [#15859]) - Other rendering problems fixed in Kurohyou ([#16454]) - Misshitsu no Sacrifice intro animation and Macross water rendering fixed (3d texture) ([#15727]) - - Tekken 6 Nancy laser beam fixed, plus line rendering fixes in other games - - Multiple workarounds for clipping/culling, both through clip planes and geometry shaders, fixing - graphical issues in many games - - Many, many others + - Tekken 6 Nancy laser beam fixed, plus line rendering fixes in other games ([#16067]) + - Many, many others like ([#16265], [#16043]) * Software renderer performance and accuracy improvements - - Better performance - - Clipping improvements, various fixes ([#16384], [#16385]) + - Better performance, various fixes ([#16384], [#16385]) + - Clipping improvements ([#16231], [#16384], [#16440], [#16402], more) * New features - Initial VR support added (Quest and PICO only for now, PC in the future) - MSAA antialiasing added to the Vulkan backend (desktop only) ([#16458]) + - New API for plugins to access aspect ratio, scaling and fast-forward ([#16441]) + - Read texture replacement packs directly from ZIP files ([#16304]) * UI improvements - New interactive Display Layout & Effects screen, replacing the old Display Layout Editor - Game being played can now be seen as a background in most menus ([#16404], more) * Stability fixes - Workaround for hangs on older Adreno GPUs ([#16422]) - - Many others * IR interpreter bug fixes - Metal Gear Solid - Peace Walker no longer bugged out ([#16396]) - - VFPU fixes ([#16302]) + - VFPU fixes ([#16302], [#16305], [#16306]) * Performance improvements - - Vulkan bandwidth and synchronization optimizations ([#16434]) - - Assorted minor other improvements -* Other compatibility fixes (Twinbee, Shining Ark) + - Vulkan bandwidth and synchronization optimizations ([#16434], [#16099], [#16090], [#16072], [#16061], [#16060], [#16035], [#15917]) + - Lighting "ubershader" optimization ([#16104]) + - Assorted minor other improvements ([#16190]) +* Other + - Minor compatibility workarounds (Twinbee [#16388], Shining Ark) + - HLE accuracy improvments ([#16413], [#16257], [#16070], [#16058], [#15930], more) * GE debugger improvements What's new in 1.13.2 @@ -125,89 +130,6 @@ UI * Fix input focus bug ([#15560]) * New GE debugger features and other UI fixes ([#15393], [#15324], [#15377], [#15424], [#15402], [#15378], [#15338]), etc. -What's new in 1.12.3 -==================== -* Fix background music speed. A couple translation fixes. - -What's new in 1.12.2 -==================== -* Fix joystick detection bug on Android. - -What's new in 1.12.1 -==================== -* Bug fixes (control mapping fix, popup menus in the Windows debugger, a few crashfixes) - -What's new in 1.12 -================== - -Platform support: -* Add support for Android 12 Scoped Storage restrictions ([#11997]) -* iOS: Fix multitouch tracking ([#5099]) -* Android: Fix screenshot orientation on Vulkan ([#14053]) -* Linux: Improve support for system FFmpeg 3.1+ ([#14176], [#14188], [#14199]) -* libretro: Always enable function hooks ([#14145]) -* AMD: Enable Vulkan rendering on a thread ([#13864]) -* Add iOS version detection, turn off JIT on bootup if >= 14.3. ([#14201]) -* iOS: Try a different JIT detection method, thanks Halo-Michael ([#14241]) -* Windows: Restore window size correctly ([#14317]) - -Game fixes: -* Fix NBA Live 08 loading ([#8288]) -* Display Open Season title screen correctly ([#13252]) -* Fix Metal Gear Solid Peace Walker Chinese Patched blue screen ([#14127]) -* Load Ape Academy 2 correctly ([#14271]) -* Many more... - -Graphics and Sound: -* Add new texture filtering mode "Auto Max Quality" ([#14789]) -* Fix Princess Maker 5 Portable half screen in Vulkan ([#13741]) -* Fix Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off ([#14167]) -* Support texture replacement filtering overrides ([#14230]) -* Fix Yarudora Portable: Double Cast's FMVs artifacting ([#13759]) -* Fix Sims 2 Castaway/Pets EA Logo glitched out ([#13146]) -* Fix bad size & position on Japanese & Numbers & Alphabets ([#14209]) -* Implement basic depth texturing for OpenGL ([#14042]) -* Google Cardboard fixes ([#14966], [#14768]) -* Correct mini-map update in Z.H.P. ([#14069]) -* Fix crash in vertex jit on ARM32 ([#14879]) -* Add a setting for reverb volume ([#14711]) -* Option to switch to new devices or not, on Windows. - -UI: -* Add a setting for choosing background animation in PPSSPP's menus ([#14313], [#14818], [#14810], [#14347]) -* Add CRC calculation on game info screen and feedback screen ([#14000], [#14041]) -* Add a Storage tab to System Information with some path info ([#14224], [#14238]) -* Track and show memory allocation / usage information in debugger ([#14056]) -* Allow searching within the savedata manager ([#14237]) -* Enable postshaders to access previous frame ([#14528]) -* Add missing Japanese keyboard symbol ([#14548]) -* Add Reset button on crash screen, allow load state and related ([#14708]) -* Implement save state load and save undo ([#14676], [#14679], [#14697]) -* A lot of minor debugger improvements - -Controls: -* New analog stick calibration menu ([#14596]) -* Improved combo button and moved settings to Customize Touch Control -> Customize -> Custom button ([#13869]) -* Improved tilt control, allow to change axis ([#12530]) -* Add a visual means of control mapping ([#14769]) -* Add basic motion gesture support ([#13107]) -* Fix touch control DPAD not getting input when dragged over, and make touch analog drag not activate other buttons ([#14843]) -* Allow adjusting touch control analog stick head size ([#14480]) - -Adhoc/Network: -* Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data ([#14140]) -* Always enable TCPNoDelay to improve response time ([#14235]) -* Fix Teenage Mutant Ninja Turtles multiplayer ([#14284]) -* Fix FlatOut Head On multiplayer ([#14290]) -* Prevent flooding Adhoc Server with connection attempts ([#14335]) -* Fix crashing issue when leaving a multiplayer game room (ie. GTA Vice City Stories) ([#14342]) -* Fix stuck issue when scanning AP to Recruit on MGS:PW ([#14345]) -* Fix possible crash issue on blocking socket implementation (ie. Kao Challengers) ([#14466]) -* Create GameMode's socket after Master and all Replicas have been created (ie. Fading Shadows) ([#14492]) -* Reduce HLE delays due to multiplayer performance regressions (ie. Ys vs. Sora no Kiseki) ([#14513]) -* Fix socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy ([#14849]) - - Looking for [older news](history.md)? diff --git a/history.md b/history.md index 2191439617..da014fd17d 100644 --- a/history.md +++ b/history.md @@ -1,5 +1,87 @@ This is history moved out from README.md, which was getting a bit long. +What's new in 1.12.3 +==================== +* Fix background music speed. A couple translation fixes. + +What's new in 1.12.2 +==================== +* Fix joystick detection bug on Android. + +What's new in 1.12.1 +==================== +* Bug fixes (control mapping fix, popup menus in the Windows debugger, a few crashfixes) + +What's new in 1.12 +================== + +Platform support: +* Add support for Android 12 Scoped Storage restrictions ([#11997]) +* iOS: Fix multitouch tracking ([#5099]) +* Android: Fix screenshot orientation on Vulkan ([#14053]) +* Linux: Improve support for system FFmpeg 3.1+ ([#14176], [#14188], [#14199]) +* libretro: Always enable function hooks ([#14145]) +* AMD: Enable Vulkan rendering on a thread ([#13864]) +* Add iOS version detection, turn off JIT on bootup if >= 14.3. ([#14201]) +* iOS: Try a different JIT detection method, thanks Halo-Michael ([#14241]) +* Windows: Restore window size correctly ([#14317]) + +Game fixes: +* Fix NBA Live 08 loading ([#8288]) +* Display Open Season title screen correctly ([#13252]) +* Fix Metal Gear Solid Peace Walker Chinese Patched blue screen ([#14127]) +* Load Ape Academy 2 correctly ([#14271]) +* Many more... + +Graphics and Sound: +* Add new texture filtering mode "Auto Max Quality" ([#14789]) +* Fix Princess Maker 5 Portable half screen in Vulkan ([#13741]) +* Fix Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off ([#14167]) +* Support texture replacement filtering overrides ([#14230]) +* Fix Yarudora Portable: Double Cast's FMVs artifacting ([#13759]) +* Fix Sims 2 Castaway/Pets EA Logo glitched out ([#13146]) +* Fix bad size & position on Japanese & Numbers & Alphabets ([#14209]) +* Implement basic depth texturing for OpenGL ([#14042]) +* Google Cardboard fixes ([#14966], [#14768]) +* Correct mini-map update in Z.H.P. ([#14069]) +* Fix crash in vertex jit on ARM32 ([#14879]) +* Add a setting for reverb volume ([#14711]) +* Option to switch to new devices or not, on Windows. + +UI: +* Add a setting for choosing background animation in PPSSPP's menus ([#14313], [#14818], [#14810], [#14347]) +* Add CRC calculation on game info screen and feedback screen ([#14000], [#14041]) +* Add a Storage tab to System Information with some path info ([#14224], [#14238]) +* Track and show memory allocation / usage information in debugger ([#14056]) +* Allow searching within the savedata manager ([#14237]) +* Enable postshaders to access previous frame ([#14528]) +* Add missing Japanese keyboard symbol ([#14548]) +* Add Reset button on crash screen, allow load state and related ([#14708]) +* Implement save state load and save undo ([#14676], [#14679], [#14697]) +* A lot of minor debugger improvements + +Controls: +* New analog stick calibration menu ([#14596]) +* Improved combo button and moved settings to Customize Touch Control -> Customize -> Custom button ([#13869]) +* Improved tilt control, allow to change axis ([#12530]) +* Add a visual means of control mapping ([#14769]) +* Add basic motion gesture support ([#13107]) +* Fix touch control DPAD not getting input when dragged over, and make touch analog drag not activate other buttons ([#14843]) +* Allow adjusting touch control analog stick head size ([#14480]) + +Adhoc/Network: +* Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data ([#14140]) +* Always enable TCPNoDelay to improve response time ([#14235]) +* Fix Teenage Mutant Ninja Turtles multiplayer ([#14284]) +* Fix FlatOut Head On multiplayer ([#14290]) +* Prevent flooding Adhoc Server with connection attempts ([#14335]) +* Fix crashing issue when leaving a multiplayer game room (ie. GTA Vice City Stories) ([#14342]) +* Fix stuck issue when scanning AP to Recruit on MGS:PW ([#14345]) +* Fix possible crash issue on blocking socket implementation (ie. Kao Challengers) ([#14466]) +* Create GameMode's socket after Master and all Replicas have been created (ie. Fading Shadows) ([#14492]) +* Reduce HLE delays due to multiplayer performance regressions (ie. Ys vs. Sora no Kiseki) ([#14513]) +* Fix socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy ([#14849]) + What's new in 1.11.3 ==================== * Fix for graphics glitches in the on-screen keyboard From 04f59a0913ec75a8219a5ae4d1d3e740deeec45c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Dec 2022 14:55:58 -0800 Subject: [PATCH 688/715] README: Add some pull #s, more 1.14 updates. --- README.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6516f823ed..aee8d27fe6 100644 --- a/README.md +++ b/README.md @@ -47,34 +47,38 @@ What's new in 1.14 - Tekken 6 Nancy laser beam fixed, plus line rendering fixes in other games ([#16067]) - Many, many others like ([#16265], [#16043]) * Software renderer performance and accuracy improvements - - Better performance, various fixes ([#16384], [#16385]) - - Clipping improvements ([#16231], [#16384], [#16440], [#16402], more) + - Better performance ([#15998], [#16001], [#16011], [#16039], [#16054], [#16080], [#16085], [#16094], [#16102], [#16387], [#16486], [#16502], [#16518]) + - Improved accuracy, clipping ([#15999], [#16005], [#16042], [#16086], [#16117], [#16231], [#16241], [#16265], [#16274], [#16469], [#16470], [#16478], [#16480], [#16485]) * New features - - Initial VR support added (Quest and PICO only for now, PC in the future) + - Initial VR support added (Quest and PICO only for now, PC in the future) ([#15659], [#15901], [#16246], [#16262], [#16273]) - MSAA antialiasing added to the Vulkan backend (desktop only) ([#16458]) - New API for plugins to access aspect ratio, scaling and fast-forward ([#16441]) - Read texture replacement packs directly from ZIP files ([#16304]) * UI improvements - - New interactive Display Layout & Effects screen, replacing the old Display Layout Editor + - New interactive Display Layout & Effects screen, replacing the old Display Layout Editor ([#16409], [#16415], [#16417], [#16445]) - Game being played can now be seen as a background in most menus ([#16404], more) + - Reorganize speed hack settings ([#16346], [#16347], [#16348], [#16432]) * Stability fixes - Workaround for hangs on older Adreno GPUs ([#16422]) -* IR interpreter bug fixes + - Input handling fixes for deadzones and touch controls ([#16419], [#16450]) + - Avoid game bugs in Twinbee Portable ([#16388]) and Shining Ark ([#16449]) +* IR interpreter (iOS, etc.) bug fixes - Metal Gear Solid - Peace Walker no longer bugged out ([#16396]) - - VFPU fixes ([#16302], [#16305], [#16306]) + - VFPU fixes for Dissidia, others ([#16302], [#16305], [#16306]) * Performance improvements - Vulkan bandwidth and synchronization optimizations ([#16434], [#16099], [#16090], [#16072], [#16061], [#16060], [#16035], [#15917]) - - Lighting "ubershader" optimization ([#16104]) - - Assorted minor other improvements ([#16190]) -* Other - - Minor compatibility workarounds (Twinbee [#16388], Shining Ark) - - HLE accuracy improvments ([#16413], [#16257], [#16070], [#16058], [#15930], more) -* GE debugger improvements + - Lighting "ubershader" optimization to prevent hitches ([#16104], [#16111]) + - Assorted minor other improvements ([#15589], [#15843], [#16190]) + - Improve texture replacement memory usage ([#15884], [#16304], [#16314]) +* Other + - HLE accuracy improvements ([#16413], [#16070], [#16058], [#15930], more) + - GE debugger improvements ([#15839], [#15851], [#15894], [#15925], [#15974], [#16007], [#16047], [#16096], [#16201]) + - Optional memory alignment validation in IR mode ([#15879], [#15880]) What's new in 1.13.2 ==================== * Crashfix on Android 12 when playing certain background music ([#15990]) -* Fix Star Ocean battles in D3D backends (#[15889]) +* Fix Star Ocean battles in D3D backends ([#15889]) * Minor fixes that might fix some other crashes What's new in 1.13.1 From 630b7830fa225b6707166482d84e912d874344bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 00:27:22 +0100 Subject: [PATCH 689/715] Improve background drag behavior on display layout screen If you moved into and mouse-up-ed over one of the menus while dragging the background, it stopped registering movement and "up events" which felt really awkward. This is not super pretty, better would be a win32-SetCapture-like mechanism but works okay. --- Common/UI/ViewGroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f7b6f49d11..f8405fbb97 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -95,7 +95,7 @@ bool ViewGroup::Touch(const TouchInput &input) { if ((*iter)->GetVisibility() == V_VISIBLE) { bool touch = (*iter)->Touch(input); any = any || touch; - if (exclusiveTouch_ && touch) { + if (exclusiveTouch_ && touch && (input.flags & TOUCH_DOWN)) { break; } } From 5ae321459a6c67258995a5e5ac3be592768c2168 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Dec 2022 18:43:57 -0800 Subject: [PATCH 690/715] README: Add more for 1.14, note game names more. --- README.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index aee8d27fe6..5d6ff26823 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ What's new in 1.14 - Water in Outrun 2006 and DiRT 2 now renders correctly (logic op fixes) ([#15960], [#16208], [#16032], [#16024], [#15967]) - Split/Second now renders all effects correctly - Multiple fixes workarounds for clipping/culling, both through clip planes and geometry shaders, fixing - graphical issues in many, many games and getting rid of hacks ([#16142], [#16504], [#16442], [#16383], [#16165], many others) + graphical issues in many, many games and getting rid of hacks ([#16142], [#16504], [#16442], [#16383], [#16165], [#16162], [#16049], others) - Killzone color effect now renders efficiently and correctly (in-game only, not title screen) ([#15934]) - Ridge Racer speedometers and lens flares fixed ([#16084], [#16188], [#16115]) - Lens flare effect fixed in Burnout Dominator, Ridge Racer, Colin McRae, several others ([#16014], [#16081], [#16076], [#16073]) @@ -40,28 +40,30 @@ What's new in 1.14 - Cars: Race-o-Rama, and MX vs ATV Reflex render correctly (at 1x resolution only) ([#15898], [#15907]) - Asphalt 2 depth occlusion problems fixed ([#15854], [#15853]) - Fix performance regression in Juiced 2 while also fixing the graphics ([#15888]) - - Silent Hill games are less broken - - Depth occlusion problems fixed in Kurohyou (both games) and Ratchet & Clank ([#15772], [#15728], [#15859]) - - Other rendering problems fixed in Kurohyou ([#16454]) - - Misshitsu no Sacrifice intro animation and Macross water rendering fixed (3d texture) ([#15727]) - - Tekken 6 Nancy laser beam fixed, plus line rendering fixes in other games ([#16067]) - - Many, many others like ([#16265], [#16043]) + - Silent Hill games are less broken ([#16127]) + - Depth occlusion and other problems fixed in Kurohyou (both games) and Ratchet & Clank ([#16454], [#15772], [#15728], [#15859]) + - Misshitsu no Sacrifice intro animation and Macross water rendering fixed (3D texture) ([#15727]) + - Tekken 6 Nancy laser beam fixed, plus line rendering fixes in rRootage and other games ([#16067]) + - Tiger & Bunny, Yu-Gi-Oh, GEB, and PlayView games - JPEG image display issues ([#16179], [#16184], [#15924]) + - Many, many others like Hunter x Hunter, Crash: Mind over Mutant, Boundless Trails, etc. ([#16265], [#16043], [#16379], [#15822], [#16358]) * Software renderer performance and accuracy improvements - Better performance ([#15998], [#16001], [#16011], [#16039], [#16054], [#16080], [#16085], [#16094], [#16102], [#16387], [#16486], [#16502], [#16518]) - Improved accuracy, clipping ([#15999], [#16005], [#16042], [#16086], [#16117], [#16231], [#16241], [#16265], [#16274], [#16469], [#16470], [#16478], [#16480], [#16485]) * New features - Initial VR support added (Quest and PICO only for now, PC in the future) ([#15659], [#15901], [#16246], [#16262], [#16273]) - MSAA antialiasing added to the Vulkan backend (desktop only) ([#16458]) - - New API for plugins to access aspect ratio, scaling and fast-forward ([#16441]) + - New API for plugins to access aspect ratio, scaling and fast-forward ([#16441]), other new APIs & improvements ([#15748], [#16121], [#16187], [#16198], [#16389]) - Read texture replacement packs directly from ZIP files ([#16304]) * UI improvements - New interactive Display Layout & Effects screen, replacing the old Display Layout Editor ([#16409], [#16415], [#16417], [#16445]) + - Add default shader for LCD persistence simulation ([#16531]) - Game being played can now be seen as a background in most menus ([#16404], more) - Reorganize speed hack settings ([#16346], [#16347], [#16348], [#16432]) * Stability fixes - Workaround for hangs on older Adreno GPUs ([#16422]) - Input handling fixes for deadzones and touch controls ([#16419], [#16450]) - Avoid game bugs in Twinbee Portable ([#16388]) and Shining Ark ([#16449]) + - Fixes to D3D9 backend issues ([#15723], [#15815], [#15926], [#16100], [#16232], [#16550]) * IR interpreter (iOS, etc.) bug fixes - Metal Gear Solid - Peace Walker no longer bugged out ([#16396]) - VFPU fixes for Dissidia, others ([#16302], [#16305], [#16306]) @@ -70,10 +72,12 @@ What's new in 1.14 - Lighting "ubershader" optimization to prevent hitches ([#16104], [#16111]) - Assorted minor other improvements ([#15589], [#15843], [#16190]) - Improve texture replacement memory usage ([#15884], [#16304], [#16314]) + - Texture upscaling speedup and fixes ([#15803], [#16125]) * Other - - HLE accuracy improvements ([#16413], [#16070], [#16058], [#15930], more) - - GE debugger improvements ([#15839], [#15851], [#15894], [#15925], [#15974], [#16007], [#16047], [#16096], [#16201]) + - HLE/CPU accuracy improvements helping Brooktown High, Frontier Gate, Madoka Magicka, some language patches ([#16413], [#16070], [#16052], [#15930], [#15952], [#15957], more) + - Many GE debugger improvements ([#15839], [#15851], [#15894], [#15925], [#15974], [#16007], [#16047], [#16096], [#16201]) - Optional memory alignment validation in IR mode ([#15879], [#15880]) + - Fix netplay assertion in Cars ([#16089]) What's new in 1.13.2 ==================== From f202029d0bdc9546f8f5ca390b2521f79d3359e4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Dec 2022 19:09:14 -0800 Subject: [PATCH 691/715] Postshader: Don't save default setting values. This way the defaults can change in the future without problems. --- GPU/Common/PostShader.cpp | 6 ------ GPU/Common/PresentationCommon.cpp | 16 ++++++++++++---- UI/DisplayLayoutScreen.cpp | 7 ++++++- UI/GameSettingsScreen.cpp | 7 ++++++- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index a29525b2f4..831bc1bf85 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -174,12 +174,6 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct section.Get(StringFromFormat("SettingMinValue%d", i + 1).c_str(), &setting.minValue, -1.0f); section.Get(StringFromFormat("SettingMaxValue%d", i + 1).c_str(), &setting.maxValue, 1.0f); section.Get(StringFromFormat("SettingStep%d", i + 1).c_str(), &setting.step, 0.01f); - - // Populate the default setting value. - std::string section = StringFromFormat("%sSettingValue%d", info.section.c_str(), i + 1); - if (!setting.name.empty() && g_Config.mPostShaderSetting.find(section) == g_Config.mPostShaderSetting.end()) { - g_Config.mPostShaderSetting.emplace(section, setting.value); - } } // Let's ignore shaders we can't support. TODO: Not a very good check diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 00975e72d6..b61ac97503 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -172,6 +172,14 @@ void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettin cardboardSettings->screenHeight = cardboardScreenHeight; } +static float GetShaderSettingValue(const ShaderInfo *shaderInfo, int i, const char *nameSuffix) { + std::string key = shaderInfo->section + nameSuffix; + auto it = g_Config.mPostShaderSetting.find(key); + if (it != g_Config.mPostShaderSetting.end()) + return it->second; + return shaderInfo->settings[i].value; +} + void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) const { float u_delta = 1.0f / bufferWidth; float v_delta = 1.0f / bufferHeight; @@ -196,10 +204,10 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer uniforms->gl_HalfPixel[0] = u_pixel_delta * 0.5f; uniforms->gl_HalfPixel[1] = v_pixel_delta * 0.5f; - uniforms->setting[0] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue1"]; - uniforms->setting[1] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue2"]; - uniforms->setting[2] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue3"]; - uniforms->setting[3] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue4"]; + uniforms->setting[0] = GetShaderSettingValue(shaderInfo, 0, "SettingValue1"); + uniforms->setting[1] = GetShaderSettingValue(shaderInfo, 1, "SettingValue2"); + uniforms->setting[2] = GetShaderSettingValue(shaderInfo, 2, "SettingValue3"); + uniforms->setting[3] = GetShaderSettingValue(shaderInfo, 3, "SettingValue4"); } static std::string ReadShaderSrc(const Path &filename) { diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 380208d42c..a554510b28 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -418,7 +418,12 @@ void DisplayLayoutScreen::CreateViews() { auto &setting = shaderInfo->settings[i]; if (!setting.name.empty()) { // This map lookup will create the setting in the mPostShaderSetting map if it doesn't exist, with a default value of 0.0. - auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; + std::string key = StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1); + bool keyExisted = g_Config.mPostShaderSetting.find(key) != g_Config.mPostShaderSetting.end(); + auto &value = g_Config.mPostShaderSetting[key]; + if (!keyExisted) + value = setting.value; + if (duplicated) { auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); PopupSliderChoiceFloat *settingValue = settingContainer->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 536a5f4426..16dd2af93a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1817,7 +1817,12 @@ void DeveloperToolsScreen::CreateViews() { for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { auto &setting = shaderInfo->settings[i]; if (!setting.name.empty()) { - auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; + std::string key = StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1); + bool keyExisted = g_Config.mPostShaderSetting.find(key) != g_Config.mPostShaderSetting.end(); + auto &value = g_Config.mPostShaderSetting[key]; + if (!keyExisted) + value = setting.value; + PopupSliderChoiceFloat *settingValue = list->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); settingValue->SetEnabledFunc([=] { return !g_Config.bSkipBufferEffects && enableStereo(); From fe470c790eedac229203129ab5bf7209681022fe Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Dec 2022 19:11:20 -0800 Subject: [PATCH 692/715] Postshader: Reset ini keys for defaults. Should fix the Vignette shader defaults, see #16562. --- Core/Config.cpp | 8 ++++---- Core/CwCheat.cpp | 10 +++++----- GPU/Common/PresentationCommon.cpp | 8 ++++---- UI/DisplayLayoutScreen.cpp | 2 +- UI/GameSettingsScreen.cpp | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index e5b5283f02..795763c9ab 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1417,10 +1417,10 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); if (IsVREnabled() && !postShadersInitialized) { postShaderChain->Set("PostShader1", "ColorCorrection"); - postShaderSetting->Set("ColorCorrectionSettingValue1",1.0f); - postShaderSetting->Set("ColorCorrectionSettingValue2",1.5f); - postShaderSetting->Set("ColorCorrectionSettingValue3",1.1f); - postShaderSetting->Set("ColorCorrectionSettingValue4",1.0f); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue1", 1.0f); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue2", 1.5f); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue3", 1.1f); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue4", 1.0f); } // Load post process shader values diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 6f5dc789a2..14dc27d86f 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -962,7 +962,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, auto shaderChain = GetFullPostShadersChain(g_Config.vPostShaderNames); if (op.PostShaderUniform.shader < shaderChain.size()) { std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section; - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = op.PostShaderUniform.value.f; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = op.PostShaderUniform.value.f; } } break; @@ -979,16 +979,16 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section; switch (op.PostShaderUniform.format) { case 0: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x000000FF; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x000000FF; break; case 1: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x0000FFFF; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x0000FFFF; break; case 2: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u; break; case 3: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.f; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.f; break; } } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index b61ac97503..4341961214 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -204,10 +204,10 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer uniforms->gl_HalfPixel[0] = u_pixel_delta * 0.5f; uniforms->gl_HalfPixel[1] = v_pixel_delta * 0.5f; - uniforms->setting[0] = GetShaderSettingValue(shaderInfo, 0, "SettingValue1"); - uniforms->setting[1] = GetShaderSettingValue(shaderInfo, 1, "SettingValue2"); - uniforms->setting[2] = GetShaderSettingValue(shaderInfo, 2, "SettingValue3"); - uniforms->setting[3] = GetShaderSettingValue(shaderInfo, 3, "SettingValue4"); + uniforms->setting[0] = GetShaderSettingValue(shaderInfo, 0, "SettingCurrentValue1"); + uniforms->setting[1] = GetShaderSettingValue(shaderInfo, 1, "SettingCurrentValue2"); + uniforms->setting[2] = GetShaderSettingValue(shaderInfo, 2, "SettingCurrentValue3"); + uniforms->setting[3] = GetShaderSettingValue(shaderInfo, 3, "SettingCurrentValue4"); } static std::string ReadShaderSrc(const Path &filename) { diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index a554510b28..ab9dd58d86 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -418,7 +418,7 @@ void DisplayLayoutScreen::CreateViews() { auto &setting = shaderInfo->settings[i]; if (!setting.name.empty()) { // This map lookup will create the setting in the mPostShaderSetting map if it doesn't exist, with a default value of 0.0. - std::string key = StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1); + std::string key = StringFromFormat("%sSettingCurrentValue%d", shaderInfo->section.c_str(), i + 1); bool keyExisted = g_Config.mPostShaderSetting.find(key) != g_Config.mPostShaderSetting.end(); auto &value = g_Config.mPostShaderSetting[key]; if (!keyExisted) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 16dd2af93a..32c71aedf9 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1817,7 +1817,7 @@ void DeveloperToolsScreen::CreateViews() { for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { auto &setting = shaderInfo->settings[i]; if (!setting.name.empty()) { - std::string key = StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1); + std::string key = StringFromFormat("%sSettingCurrentValue%d", shaderInfo->section.c_str(), i + 1); bool keyExisted = g_Config.mPostShaderSetting.find(key) != g_Config.mPostShaderSetting.end(); auto &value = g_Config.mPostShaderSetting[key]; if (!keyExisted) From fb96d7989560b281a2d559167625ee359601c5f9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Dec 2022 22:31:46 -0800 Subject: [PATCH 693/715] UI: Avoid crash on axis input during shutdown. (#16564) --- UI/NativeApp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 3c5c6a1b24..9d127c155a 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1431,6 +1431,8 @@ bool NativeAxis(const AxisInput &axis) { default: // Don't take over completely! + if (!screenManager) + return false; return screenManager->axis(axis); } From ad1cd40ff7beac55e5f1977252435855d20d434d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 08:45:20 +0100 Subject: [PATCH 694/715] Bump shader cache versions before release, just to be safe. --- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index fa5cc0d2d4..6c26199290 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -931,7 +931,7 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT // as sometimes these features might have an effect on the ID bits. #define CACHE_HEADER_MAGIC 0x83277592 -#define CACHE_VERSION 16 +#define CACHE_VERSION 17 struct CacheHeader { uint32_t magic; uint32_t version; diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 89e3744f4a..e8f58ea9c2 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -493,7 +493,7 @@ VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 31 +#define CACHE_VERSION 32 struct VulkanCacheHeader { uint32_t magic; uint32_t version; From f7e28d1ba33ba613e295f196d6ca19fc66639212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 08:47:53 +0100 Subject: [PATCH 695/715] compat.ini: Add MX vs ATV to "ForceLowerResolutionForEffectsOff". --- assets/compat.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assets/compat.ini b/assets/compat.ini index 1d32831437..28f6f255ba 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1255,6 +1255,11 @@ ULES01333 = true ULES01375 = true ULUS10429 = true +# MX vs ATV Untamed +ULUS10330 = true +ULES00993 = true +ULKS46176 = true + # Spongebob: The Yellow Avenger ULES00280 = true ULUS10092 = true From 44340e752a40d19dd03435e3b1e5d8cf5facf964 Mon Sep 17 00:00:00 2001 From: iota97 Date: Tue, 13 Dec 2022 09:58:47 +0100 Subject: [PATCH 696/715] add links --- README.md | 204 +++++++++++++++++++++++++++++++++++++---------------- history.md | 63 +++++++++++++++++ 2 files changed, 205 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 5d6ff26823..1fc89d2439 100644 --- a/README.md +++ b/README.md @@ -154,68 +154,6 @@ Credit goes to: [comment]: # (LINK_LIST_BEGIN_HERE) -[#11997]: https://github.com/hrydgard/ppsspp/issues/11997 "Android 12 scoped storage hell" -[#5099]: https://github.com/hrydgard/ppsspp/issues/5099 "IOS touch controls problems." -[#14053]: https://github.com/hrydgard/ppsspp/issues/14053 "Toggle screenshot minor issue." -[#14176]: https://github.com/hrydgard/ppsspp/issues/14176 "Remove deprecated API calls for new FFmpeg 4.3.x" -[#14188]: https://github.com/hrydgard/ppsspp/issues/14188 "Additional fixes for FFmpeg 3.1+" -[#14199]: https://github.com/hrydgard/ppsspp/issues/14199 "Mpeg: Set low latency flag for video decode" -[#14145]: https://github.com/hrydgard/ppsspp/issues/14145 "libretro: Remove \"Unsafe FuncReplacements\" option." -[#13864]: https://github.com/hrydgard/ppsspp/issues/13864 "Vulkan: Remove #10097 hack for newer AMD drivers" -[#14201]: https://github.com/hrydgard/ppsspp/issues/14201 "Add iOS version detection, turn off JIT on bootup if >= 14.3." -[#14241]: https://github.com/hrydgard/ppsspp/issues/14241 "iOS: Try a different JIT detection method, thanks Halo-Michael." -[#14317]: https://github.com/hrydgard/ppsspp/issues/14317 "Window size restarts on closing" -[#8288]: https://github.com/hrydgard/ppsspp/issues/8288 "NBA live 08 Invalid address and hang" -[#14069]: https://github.com/hrydgard/ppsspp/issues/14069 "Mini-Map in Z.H.P. Updates Incorrectly Without Software Rendering" -[#13252]: https://github.com/hrydgard/ppsspp/issues/13252 "Open Season Title Screen does not display" -[#14127]: https://github.com/hrydgard/ppsspp/issues/14127 "Metal Gear Solid Peace Walker Chinese Patched blue screen" -[#14271]: https://github.com/hrydgard/ppsspp/issues/14271 "Ape Academy 2 is broken on versions after 1.8.0(?) - tested on latest nightly and 1.11.3" -[#13741]: https://github.com/hrydgard/ppsspp/issues/13741 "Princess Maker 5 Portable half screen in Vulkan" -[#14167]: https://github.com/hrydgard/ppsspp/issues/14167 "[Android] Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off" -[#14230]: https://github.com/hrydgard/ppsspp/issues/14230 "Support texture replacement filtering overrides" -[#13759]: https://github.com/hrydgard/ppsspp/issues/13759 "Yarudora Portable: Double Cast" -[#13146]: https://github.com/hrydgard/ppsspp/issues/13146 "Sims 2 Castaway/Pets EA Logo glitched out - 1.10.2" -[#14789]: https://github.com/hrydgard/ppsspp/issues/14789 "Add new texture filtering mode \"Auto Max Quality\"" -[#14209]: https://github.com/hrydgard/ppsspp/issues/14209 "Fix Size & Position jpn0.pgf/ltn0.pgf/ltn2.pgf/ltn4.pgf/ltn6.pgf" -[#14042]: https://github.com/hrydgard/ppsspp/issues/14042 "Implement basic depth texturing for OpenGL" -[#14966]: https://github.com/hrydgard/ppsspp/issues/14966 "Config: Correct cardboard setting ini load" -[#14768]: https://github.com/hrydgard/ppsspp/issues/14768 "Fix the math in cardboard VR mode for wide aspect ratios" -[#14879]: https://github.com/hrydgard/ppsspp/issues/14879 "vertexjit: Correct morph flag alpha check assert" -[#14313]: https://github.com/hrydgard/ppsspp/issues/14313 "Add a setting for choosing background animation in PPSSPP's menus" -[#14818]: https://github.com/hrydgard/ppsspp/issues/14818 "Focus based moving background" -[#14810]: https://github.com/hrydgard/ppsspp/issues/14810 "Wave animation" -[#14347]: https://github.com/hrydgard/ppsspp/issues/14347 "UI: Add BG animation for recent games" -[#14041]: https://github.com/hrydgard/ppsspp/issues/14041 "UI: Add button to show CRC on feedback screen" -[#14224]: https://github.com/hrydgard/ppsspp/issues/14224 "Add a Storage tab to System Information with some path info" -[#14238]: https://github.com/hrydgard/ppsspp/issues/14238 "UI: Wrap long info items and cleanup storage display" -[#14056]: https://github.com/hrydgard/ppsspp/issues/14056 "Track memory allocations and writes for debug info" -[#14237]: https://github.com/hrydgard/ppsspp/issues/14237 "Add initial search to savedata manager" -[#14528]: https://github.com/hrydgard/ppsspp/issues/14528 "Postshader: Let shaders use the previous frame" -[#14548]: https://github.com/hrydgard/ppsspp/issues/14548 "Add some PPSSPP's Japanese keyboard" -[#14708]: https://github.com/hrydgard/ppsspp/issues/14708 "Add Reset button on crash screen, allow load state and related" -[#14676]: https://github.com/hrydgard/ppsspp/issues/14676 "Add savestate undo UI" -[#14679]: https://github.com/hrydgard/ppsspp/issues/14679 "Savestate load undo" -[#14697]: https://github.com/hrydgard/ppsspp/issues/14697 "Add undo last save as well" -[#14596]: https://github.com/hrydgard/ppsspp/issues/14596 "Replace the \"Test Analogs\" screen with a new screen that lets you directly try the settings." -[#13869]: https://github.com/hrydgard/ppsspp/issues/13869 "Make combo button more generic" -[#12530]: https://github.com/hrydgard/ppsspp/issues/12530 "Allow tilt input on Z instead of X" -[#14000]: https://github.com/hrydgard/ppsspp/issues/14000 "Add CRC32 calc" -[#14769]: https://github.com/hrydgard/ppsspp/issues/14769 "Add a visual means of control mapping" -[#13107]: https://github.com/hrydgard/ppsspp/issues/13107 "Basic mappable motion gesture" -[#14843]: https://github.com/hrydgard/ppsspp/issues/14843 "DPad drag fixes" -[#14480]: https://github.com/hrydgard/ppsspp/issues/14480 "Configurable analog head size" -[#14140]: https://github.com/hrydgard/ppsspp/issues/14140 "[Adhoc] Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data" -[#14235]: https://github.com/hrydgard/ppsspp/issues/14235 "[Adhoc] Always enable TCPNoDelay to improve response time" -[#14284]: https://github.com/hrydgard/ppsspp/issues/14284 "[Adhoc] Fix Teenage Mutant Ninja Turtles Multiplayer" -[#14290]: https://github.com/hrydgard/ppsspp/issues/14290 "Fix FlatOut Head On multiplayer." -[#14335]: https://github.com/hrydgard/ppsspp/issues/14335 "[Adhoc] Prevent flooding Adhoc Server with connection attempts" -[#14342]: https://github.com/hrydgard/ppsspp/issues/14342 "[AdhocMatching] Fix crashing issue when leaving a multiplayer game room" -[#14345]: https://github.com/hrydgard/ppsspp/issues/14345 "[APctl] Fix stuck issue when scanning AP to Recruit on MGS:PW" -[#14466]: https://github.com/hrydgard/ppsspp/issues/14466 "[Adhoc] Fix possible crash issue on blocking socket implementation." -[#14492]: https://github.com/hrydgard/ppsspp/issues/14492 "[AdhocGameMode] Create GameMode's socket after Master and all Replicas have been created" -[#14513]: https://github.com/hrydgard/ppsspp/issues/14513 "[Adhoc] Reducing HLE delays due to Mutiplayer performance regressions" -[#14849]: https://github.com/hrydgard/ppsspp/issues/14849 "[Adhoc] Fix Socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy" -[#14711]: https://github.com/hrydgard/ppsspp/issues/14711 "Sas: Add option to control reverb volume" [#15237]: https://github.com/hrydgard/ppsspp/issues/15237 "Path: Check for PSP case insensitively" [#15487]: https://github.com/hrydgard/ppsspp/issues/15487 "Save textures on background tasks when texture dumping is enabled." [#15645]: https://github.com/hrydgard/ppsspp/issues/15645 "UI: Add analog speed limit mapping" @@ -277,3 +215,145 @@ Credit goes to: [#15740]: https://github.com/hrydgard/ppsspp/issues/15740 "Replacement: Clear cache on disable" [#15734]: https://github.com/hrydgard/ppsspp/issues/15734 "Better pt-pt translation" [#15733]: https://github.com/hrydgard/ppsspp/issues/15733 "Fix bug in blue-to-alpha - alpha blending could be on when it shouldn't be." +[#15960]: https://github.com/hrydgard/ppsspp/issues/15960 "Enable logic op emulation in-shader" +[#16208]: https://github.com/hrydgard/ppsspp/issues/16208 "GPU: Respect stencil state in shader blend" +[#16032]: https://github.com/hrydgard/ppsspp/issues/16032 "Fix the water in Outrun when no logic ops" +[#16024]: https://github.com/hrydgard/ppsspp/issues/16024 "GPU: Fix simulating logicop with blend and shader" +[#15967]: https://github.com/hrydgard/ppsspp/issues/15967 "Fix BlueToAlpha mode, re-enable it for Outrun and DiRT" +[#16142]: https://github.com/hrydgard/ppsspp/issues/16142 "Implement geometry shader for range culling" +[#16504]: https://github.com/hrydgard/ppsspp/issues/16504 "GPU: Use accurate depth for depth range hack" +[#16442]: https://github.com/hrydgard/ppsspp/issues/16442 "Vulkan: Only use geometry shaders with accurate depth" +[#16383]: https://github.com/hrydgard/ppsspp/issues/16383 "GPU: Automatically reduce depth range on == test" +[#16165]: https://github.com/hrydgard/ppsspp/issues/16165 "Vulkan: Clip clamped depth in geometry shader" +[#16162]: https://github.com/hrydgard/ppsspp/issues/16162 "Implement negative Z clipping in geometry shader" +[#16049]: https://github.com/hrydgard/ppsspp/issues/16049 "GPU: Clip depth properly when also clamping" +[#15934]: https://github.com/hrydgard/ppsspp/issues/15934 "Split the main framebuffer in Killzone, to avoid texturing-from-current-rendertarget" +[#16084]: https://github.com/hrydgard/ppsspp/issues/16084 "Fix Ridge Racer lens flares - ignore stride if texHeight == 1, when matching tex/fb" +[#16188]: https://github.com/hrydgard/ppsspp/issues/16188 "Fix depal bounds with dynamic CLUT. Fixes lens flare glitches in Ridge Racer" +[#16115]: https://github.com/hrydgard/ppsspp/issues/16115 "Add compatibility flag for loading pixels on framebuffer create using nearest filtering" +[#16014]: https://github.com/hrydgard/ppsspp/issues/16014 "Texture depal using CLUT loaded from framebuffers, and more. Fixes Burnout Dominator lens flare" +[#16081]: https://github.com/hrydgard/ppsspp/issues/16081 "Fix green flashes with Burnout Dominator lens flare" +[#16076]: https://github.com/hrydgard/ppsspp/issues/16076 "Don't try to replace or scale CLUT8-on-GPU textures." +[#16073]: https://github.com/hrydgard/ppsspp/issues/16073 "CLUTs can be loaded from small rectangular textures. Need to linearize." +[#15907]: https://github.com/hrydgard/ppsspp/issues/15907 "Reinterpret between 32 and 16 bit texture formats" +[#15903]: https://github.com/hrydgard/ppsspp/issues/15903 "Remove support for framebuffers changing stride (already unreachable)." +[#15898]: https://github.com/hrydgard/ppsspp/issues/15898 "Rendering issues in Tantalus Media games (Spongebob, MX ATV, etc)" +[#15854]: https://github.com/hrydgard/ppsspp/issues/15854 "Use sequence numbers instead of a tracking array for depth buffers" +[#15853]: https://github.com/hrydgard/ppsspp/issues/15853 "Framebuffer-bind sequence numbers" +[#15888]: https://github.com/hrydgard/ppsspp/issues/15888 "Copy color from overlapping framebuffers on bind, under certain conditions" +[#16127]: https://github.com/hrydgard/ppsspp/issues/16127 "Fixes for Silent Hill: Origins (depth buffer reassignment, eliminate readback)" +[#16454]: https://github.com/hrydgard/ppsspp/issues/16454 "GPU: Support framebuf depal from rendered CLUT" +[#15772]: https://github.com/hrydgard/ppsspp/issues/15772 "Add support for binding the depth buffer as a color target. Fixes Kurohyo depth sorting" +[#15728]: https://github.com/hrydgard/ppsspp/issues/15728 "Better ways to deal with overlapping render targets" +[#15859]: https://github.com/hrydgard/ppsspp/issues/15859 "Allow binding depth as 565" +[#15727]: https://github.com/hrydgard/ppsspp/issues/15727 "Implement the PSP's equal-size mips \"3D texturing\"" +[#16067]: https://github.com/hrydgard/ppsspp/issues/16067 "GPU: Account for w properly in lines, fixing width" +[#16179]: https://github.com/hrydgard/ppsspp/issues/16179 "Correct size and YUV order for jpeg decoding" +[#16184]: https://github.com/hrydgard/ppsspp/issues/16184 "GPU: Hook Gods Eater Burst avatar read" +[#15924]: https://github.com/hrydgard/ppsspp/issues/15924 "Add support for reading depth buffers to the PackFramebufferSync function" +[#16265]: https://github.com/hrydgard/ppsspp/issues/16265 "GPU: Respect world matrix and reverse flag w/o normals" +[#16043]: https://github.com/hrydgard/ppsspp/issues/16043 "Consider the Adreno and Mali stencil-discard bugs the same." +[#16379]: https://github.com/hrydgard/ppsspp/issues/16379 "Fix alpha/stencil replace on Adreno when color masked" +[#15822]: https://github.com/hrydgard/ppsspp/issues/15822 "GPU: Write stencil fail to alpha is RGB masked" +[#16358]: https://github.com/hrydgard/ppsspp/issues/16358 "TexCache: Fix 16->32 colors with CLUT start pos" +[#15998]: https://github.com/hrydgard/ppsspp/issues/15998 "softgpu: Allow almost flat rectangles to go fast" +[#16001]: https://github.com/hrydgard/ppsspp/issues/16001 "softgpu: Check depth test early on simple stencil" +[#16011]: https://github.com/hrydgard/ppsspp/issues/16011 "Detect more triangles as rectangles in softgpu" +[#16039]: https://github.com/hrydgard/ppsspp/issues/16039 "softgpu: Run early Z tests in fast rect path" +[#16054]: https://github.com/hrydgard/ppsspp/issues/16054 "softgpu: Reduce some flushing / flushing cost" +[#16080]: https://github.com/hrydgard/ppsspp/issues/16080 "softgpu: Avoid unnecessary flushing for curves" +[#16085]: https://github.com/hrydgard/ppsspp/issues/16085 "softgpu: Cache reused indexed verts" +[#16094]: https://github.com/hrydgard/ppsspp/issues/16094 "softgpu: Optimize rectangle sampling/blending used in bloom" +[#16102]: https://github.com/hrydgard/ppsspp/issues/16102 "softgpu: Avoid waiting for a thread to drain" +[#16387]: https://github.com/hrydgard/ppsspp/issues/16387 "softgpu: Use threads on self-render if safe" +[#16486]: https://github.com/hrydgard/ppsspp/issues/16486 "softgpu: Apply optimizations to states generically" +[#16502]: https://github.com/hrydgard/ppsspp/issues/16502 "A few more softgpu optimizations for alpha blend/test" +[#16518]: https://github.com/hrydgard/ppsspp/issues/16518 "softgpu: Expand fast path to all fb formats" +[#15999]: https://github.com/hrydgard/ppsspp/issues/15999 "softgpu: Clamp/wrap textures at 512 pixels" +[#16005]: https://github.com/hrydgard/ppsspp/issues/16005 "softgpu: Correct accuracy of fog calculation" +[#16042]: https://github.com/hrydgard/ppsspp/issues/16042 "softgpu: Refactor imm prim handling to support fog/color1" +[#16086]: https://github.com/hrydgard/ppsspp/issues/16086 "softgpu: Fix self-render detect in Ridge Racer" +[#16117]: https://github.com/hrydgard/ppsspp/issues/16117 "Correct texture projection issues, mainly in softgpu" +[#16231]: https://github.com/hrydgard/ppsspp/issues/16231 "softgpu: Cull a triangle with all negative w" +[#16241]: https://github.com/hrydgard/ppsspp/issues/16241 "softgpu: Correct linear interp for uneven positions" +[#16274]: https://github.com/hrydgard/ppsspp/issues/16274 "Correct accuracy of bounding box test" +[#16469]: https://github.com/hrydgard/ppsspp/issues/16469 "Correct block transfer overlap and wrapping behavior" +[#16470]: https://github.com/hrydgard/ppsspp/issues/16470 "softgpu: Correctly fix inversions, matching tests" +[#16478]: https://github.com/hrydgard/ppsspp/issues/16478 "softgpu: Interpolate Z for 3D lines" +[#16480]: https://github.com/hrydgard/ppsspp/issues/16480 "softgpu: Cull verts outside post-viewport Z" +[#16485]: https://github.com/hrydgard/ppsspp/issues/16485 "softgpu: Handle infnan fog coefficients better" +[#15659]: https://github.com/hrydgard/ppsspp/issues/15659 "Oculus Quest native support" +[#15901]: https://github.com/hrydgard/ppsspp/issues/15901 "OpenXR - Stereoscopic rendering" +[#16246]: https://github.com/hrydgard/ppsspp/issues/16246 "VR: Add the VR code to all builds. Remove IsVRBuild calls from the renderer." +[#16262]: https://github.com/hrydgard/ppsspp/issues/16262 "OpenXR - Add an option to adjust camera distance" +[#16273]: https://github.com/hrydgard/ppsspp/issues/16273 "Vulkan multiview rendering" +[#16458]: https://github.com/hrydgard/ppsspp/issues/16458 "Implement MSAA support for desktop GPUs in Vulkan" +[#16441]: https://github.com/hrydgard/ppsspp/issues/16441 "Exposed more emulator things to devctl api" +[#15748]: https://github.com/hrydgard/ppsspp/issues/15748 "Windows: Add a simple window message to get the base pointer." +[#16121]: https://github.com/hrydgard/ppsspp/issues/16121 "Debugger: Add API to scan memory for funcs" +[#16187]: https://github.com/hrydgard/ppsspp/issues/16187 "Remote API: hle.func.removeRange added" +[#16198]: https://github.com/hrydgard/ppsspp/issues/16198 "Readback stencil buffer for debugger on GLES" +[#16389]: https://github.com/hrydgard/ppsspp/issues/16389 "Make breakpoints work better in interpreter" +[#16304]: https://github.com/hrydgard/ppsspp/issues/16304 "Improve texture replacement cache and allow read from zip" +[#16409]: https://github.com/hrydgard/ppsspp/issues/16409 "Preserve framebuffer on pause screen even if render resolution is changed" +[#16415]: https://github.com/hrydgard/ppsspp/issues/16415 "Display layout editor - Remove editing widget, just use the background directly" +[#16417]: https://github.com/hrydgard/ppsspp/issues/16417 "Move post processing settings to the Display Layout Editor" +[#16445]: https://github.com/hrydgard/ppsspp/issues/16445 "New screen size controls on Display Layout & Effects screen" +[#16531]: https://github.com/hrydgard/ppsspp/issues/16531 "iota97's \"Motion blur\" - LCD persistence shader, plus fixes to make it work with OpenGL" +[#16404]: https://github.com/hrydgard/ppsspp/issues/16404 "Make the pause screen \"transparent\"" +[#16346]: https://github.com/hrydgard/ppsspp/issues/16346 "Change the \"Retain changed textures\" option into a compat.ini option." +[#16347]: https://github.com/hrydgard/ppsspp/issues/16347 "Always skin in decode for software transform and rendering" +[#16348]: https://github.com/hrydgard/ppsspp/issues/16348 "Speed hack setting reorganization" +[#16432]: https://github.com/hrydgard/ppsspp/issues/16432 "Cleanup graphics settings list" +[#16422]: https://github.com/hrydgard/ppsspp/issues/16422 "Add compat flag / bug check for games on old Adreno/GL affected" +[#16419]: https://github.com/hrydgard/ppsspp/issues/16419 "Stick input: Fix issue where deadzone noise from one device could drown out signal from another." +[#16450]: https://github.com/hrydgard/ppsspp/issues/16450 "UI: Fix right analog with single button" +[#16388]: https://github.com/hrydgard/ppsspp/issues/16388 "Twinbee Portable: Add compat flag to avoid game bug with some languages" +[#16449]: https://github.com/hrydgard/ppsspp/issues/16449 "Blind workaround for Shining Ark circle button problem" +[#15723]: https://github.com/hrydgard/ppsspp/issues/15723 "D3D9 state cache cleanup" +[#15815]: https://github.com/hrydgard/ppsspp/issues/15815 "Depth blit using raster" +[#15926]: https://github.com/hrydgard/ppsspp/issues/15926 "Implement shader blending for D3D9" +[#16100]: https://github.com/hrydgard/ppsspp/issues/16100 "D3D9: Allow INTZ depth buffers more correctly" +[#16232]: https://github.com/hrydgard/ppsspp/issues/16232 "D3D9: Correct scissor state cache in Draw" +[#16550]: https://github.com/hrydgard/ppsspp/issues/16550 "Hide the D3D9 option on Intel Xe graphics." +[#16396]: https://github.com/hrydgard/ppsspp/issues/16396 "Correct misbehavior on uninitialized values in IR" +[#16302]: https://github.com/hrydgard/ppsspp/issues/16302 "Handle vrot overlap and vscl/vmscl prefixes more accurately" +[#16305]: https://github.com/hrydgard/ppsspp/issues/16305 "irjit: Fix unordered float compares" +[#16306]: https://github.com/hrydgard/ppsspp/issues/16306 "irjit: Correct prefix validation" +[#16434]: https://github.com/hrydgard/ppsspp/issues/16434 "Vulkan: Use stencil export when available" +[#16099]: https://github.com/hrydgard/ppsspp/issues/16099 "Vulkan: Avoid allocating depth images for stuff like temp copies, depal buffers etc." +[#16090]: https://github.com/hrydgard/ppsspp/issues/16090 "Simplify synchronization in VulkanRenderManager" +[#16072]: https://github.com/hrydgard/ppsspp/issues/16072 "Vulkan: Don't have renderpasses store/load depth buffers when we don't use them" +[#16061]: https://github.com/hrydgard/ppsspp/issues/16061 "Vulkan: Submit main command buffer before acquiring the swapchain image" +[#16060]: https://github.com/hrydgard/ppsspp/issues/16060 "Vulkan FrameData refactor" +[#16035]: https://github.com/hrydgard/ppsspp/issues/16035 "Vulkan: \"Acquire\" the image from the swapchain as late as possible in the frame" +[#15917]: https://github.com/hrydgard/ppsspp/issues/15917 "Vulkan bandwidth optimizations (configure renderpass load/store better)" +[#16104]: https://github.com/hrydgard/ppsspp/issues/16104 "Generate \"Ubershaders\" that can handle all lighting configurations" +[#16111]: https://github.com/hrydgard/ppsspp/issues/16111 "Always do the vertex shader part of the fog computation." +[#15589]: https://github.com/hrydgard/ppsspp/issues/15589 "Vulkan: Parallelize GLSL compilation" +[#15843]: https://github.com/hrydgard/ppsspp/issues/15843 "GPU: Skip fb create upload when clearing" +[#16190]: https://github.com/hrydgard/ppsspp/issues/16190 "Reduce IO primarily during save operations" +[#15884]: https://github.com/hrydgard/ppsspp/issues/15884 "Replacement: Read files only within time budget" +[#16314]: https://github.com/hrydgard/ppsspp/issues/16314 "UI: Install textures as a zip if supported" +[#15803]: https://github.com/hrydgard/ppsspp/issues/15803 "Reimplement bicubic upscaling." +[#16125]: https://github.com/hrydgard/ppsspp/issues/16125 "Remove alpha ignore in xbrz texture shaders." +[#16413]: https://github.com/hrydgard/ppsspp/issues/16413 "Kernel: Respect partition param in heap funcs" +[#16070]: https://github.com/hrydgard/ppsspp/issues/16070 "Kernel: Match index lookup behavior for tls" +[#16052]: https://github.com/hrydgard/ppsspp/issues/16052 "HLE: sceKernelAllocPartitionMemory volatile memory support (partition 5)" +[#15930]: https://github.com/hrydgard/ppsspp/issues/15930 "Fix sceKernelUnlockMutex timing" +[#15952]: https://github.com/hrydgard/ppsspp/issues/15952 "interp: Handle jumps in branch delay slots better" +[#15957]: https://github.com/hrydgard/ppsspp/issues/15957 "Handle branch/jump in branch delay slots more accurately" +[#15839]: https://github.com/hrydgard/ppsspp/issues/15839 "GE debugger: Allow displaying two tabs at once, separate DL view" +[#15851]: https://github.com/hrydgard/ppsspp/issues/15851 "After recording a GE dump, open an explorer window pointing at the file" +[#15894]: https://github.com/hrydgard/ppsspp/issues/15894 "GE Debugger: Record only one flip if display framebuf not changed, step on vsync" +[#15925]: https://github.com/hrydgard/ppsspp/issues/15925 "GE Debugger: Improve display list disasm" +[#15974]: https://github.com/hrydgard/ppsspp/issues/15974 "Add breakpoint conditions to GE debugger" +[#16007]: https://github.com/hrydgard/ppsspp/issues/16007 "GE Debugger: Add fields to register expressions" +[#16047]: https://github.com/hrydgard/ppsspp/issues/16047 "GE Debugger: Allow search" +[#16096]: https://github.com/hrydgard/ppsspp/issues/16096 "GE Debugger: Add option to track pixel in preview" +[#16201]: https://github.com/hrydgard/ppsspp/issues/16201 "GE Debugger: Normalize framebuffer texture preview" +[#15879]: https://github.com/hrydgard/ppsspp/issues/15879 "irjit: Validate alignment in slow memory mode" +[#15880]: https://github.com/hrydgard/ppsspp/issues/15880 "Core: Show exception on misaligned jump" +[#16089]: https://github.com/hrydgard/ppsspp/issues/16089 "[AdhocMatching] Fix assertion issue when playing Cars over public adhoc server." +[#15990]: https://github.com/hrydgard/ppsspp/issues/15990 "Atrac3+: Allocate some extra" +[#15889]: https://github.com/hrydgard/ppsspp/issues/15889 "Correct D3D viewport offset sign in sw transform" \ No newline at end of file diff --git a/history.md b/history.md index da014fd17d..153f8f96b5 100644 --- a/history.md +++ b/history.md @@ -865,3 +865,66 @@ go to see there http://forums.ppsspp.org/showthread.php?tid=3595&pid=59241#pid59 [#14132]: https://github.com/hrydgard/ppsspp/issues/14132 "Io: Truncate reads/writes to valid memory" [#14134]: https://github.com/hrydgard/ppsspp/issues/14134 "Android: Ensure shutdown waits for render" [#14129]: https://github.com/hrydgard/ppsspp/issues/14129 "GPU: Force reinterpret off without copy image" +[#11997]: https://github.com/hrydgard/ppsspp/issues/11997 "Android 12 scoped storage hell" +[#5099]: https://github.com/hrydgard/ppsspp/issues/5099 "IOS touch controls problems." +[#14053]: https://github.com/hrydgard/ppsspp/issues/14053 "Toggle screenshot minor issue." +[#14176]: https://github.com/hrydgard/ppsspp/issues/14176 "Remove deprecated API calls for new FFmpeg 4.3.x" +[#14188]: https://github.com/hrydgard/ppsspp/issues/14188 "Additional fixes for FFmpeg 3.1+" +[#14199]: https://github.com/hrydgard/ppsspp/issues/14199 "Mpeg: Set low latency flag for video decode" +[#14145]: https://github.com/hrydgard/ppsspp/issues/14145 "libretro: Remove \"Unsafe FuncReplacements\" option." +[#13864]: https://github.com/hrydgard/ppsspp/issues/13864 "Vulkan: Remove #10097 hack for newer AMD drivers" +[#14201]: https://github.com/hrydgard/ppsspp/issues/14201 "Add iOS version detection, turn off JIT on bootup if >= 14.3." +[#14241]: https://github.com/hrydgard/ppsspp/issues/14241 "iOS: Try a different JIT detection method, thanks Halo-Michael." +[#14317]: https://github.com/hrydgard/ppsspp/issues/14317 "Window size restarts on closing" +[#8288]: https://github.com/hrydgard/ppsspp/issues/8288 "NBA live 08 Invalid address and hang" +[#13252]: https://github.com/hrydgard/ppsspp/issues/13252 "Open Season Title Screen does not display" +[#14127]: https://github.com/hrydgard/ppsspp/issues/14127 "Metal Gear Solid Peace Walker Chinese Patched blue screen" +[#14271]: https://github.com/hrydgard/ppsspp/issues/14271 "Ape Academy 2 is broken on versions after 1.8.0(?) - tested on latest nightly and 1.11.3" +[#14789]: https://github.com/hrydgard/ppsspp/issues/14789 "Add new texture filtering mode \"Auto Max Quality\"" +[#13741]: https://github.com/hrydgard/ppsspp/issues/13741 "Princess Maker 5 Portable half screen in Vulkan" +[#14167]: https://github.com/hrydgard/ppsspp/issues/14167 "[Android] Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off" +[#14230]: https://github.com/hrydgard/ppsspp/issues/14230 "Support texture replacement filtering overrides" +[#13759]: https://github.com/hrydgard/ppsspp/issues/13759 "Yarudora Portable: Double Cast" +[#13146]: https://github.com/hrydgard/ppsspp/issues/13146 "Sims 2 Castaway/Pets EA Logo glitched out - 1.10.2" +[#14209]: https://github.com/hrydgard/ppsspp/issues/14209 "Fix Size & Position jpn0.pgf/ltn0.pgf/ltn2.pgf/ltn4.pgf/ltn6.pgf" +[#14042]: https://github.com/hrydgard/ppsspp/issues/14042 "Implement basic depth texturing for OpenGL" +[#14966]: https://github.com/hrydgard/ppsspp/issues/14966 "Config: Correct cardboard setting ini load" +[#14768]: https://github.com/hrydgard/ppsspp/issues/14768 "Fix the math in cardboard VR mode for wide aspect ratios" +[#14069]: https://github.com/hrydgard/ppsspp/issues/14069 "Mini-Map in Z.H.P. Updates Incorrectly Without Software Rendering" +[#14879]: https://github.com/hrydgard/ppsspp/issues/14879 "vertexjit: Correct morph flag alpha check assert" +[#14711]: https://github.com/hrydgard/ppsspp/issues/14711 "Sas: Add option to control reverb volume" +[#14313]: https://github.com/hrydgard/ppsspp/issues/14313 "Add a setting for choosing background animation in PPSSPP's menus" +[#14818]: https://github.com/hrydgard/ppsspp/issues/14818 "Focus based moving background" +[#14810]: https://github.com/hrydgard/ppsspp/issues/14810 "Wave animation" +[#14347]: https://github.com/hrydgard/ppsspp/issues/14347 "UI: Add BG animation for recent games" +[#14000]: https://github.com/hrydgard/ppsspp/issues/14000 "Add CRC32 calc" +[#14041]: https://github.com/hrydgard/ppsspp/issues/14041 "UI: Add button to show CRC on feedback screen" +[#14224]: https://github.com/hrydgard/ppsspp/issues/14224 "Add a Storage tab to System Information with some path info" +[#14238]: https://github.com/hrydgard/ppsspp/issues/14238 "UI: Wrap long info items and cleanup storage display" +[#14056]: https://github.com/hrydgard/ppsspp/issues/14056 "Track memory allocations and writes for debug info" +[#14237]: https://github.com/hrydgard/ppsspp/issues/14237 "Add initial search to savedata manager" +[#14528]: https://github.com/hrydgard/ppsspp/issues/14528 "Postshader: Let shaders use the previous frame" +[#14548]: https://github.com/hrydgard/ppsspp/issues/14548 "Add some PPSSPP's Japanese keyboard" +[#14708]: https://github.com/hrydgard/ppsspp/issues/14708 "Add Reset button on crash screen, allow load state and related" +[#14676]: https://github.com/hrydgard/ppsspp/issues/14676 "Add savestate undo UI" +[#14679]: https://github.com/hrydgard/ppsspp/issues/14679 "Savestate load undo" +[#14697]: https://github.com/hrydgard/ppsspp/issues/14697 "Add undo last save as well" +[#14596]: https://github.com/hrydgard/ppsspp/issues/14596 "Replace the \"Test Analogs\" screen with a new screen that lets you directly try the settings." +[#13869]: https://github.com/hrydgard/ppsspp/issues/13869 "Make combo button more generic" +[#12530]: https://github.com/hrydgard/ppsspp/issues/12530 "Allow tilt input on Z instead of X" +[#14769]: https://github.com/hrydgard/ppsspp/issues/14769 "Add a visual means of control mapping" +[#13107]: https://github.com/hrydgard/ppsspp/issues/13107 "Basic mappable motion gesture" +[#14843]: https://github.com/hrydgard/ppsspp/issues/14843 "DPad drag fixes" +[#14480]: https://github.com/hrydgard/ppsspp/issues/14480 "Configurable analog head size" +[#14140]: https://github.com/hrydgard/ppsspp/issues/14140 "[Adhoc] Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data" +[#14235]: https://github.com/hrydgard/ppsspp/issues/14235 "[Adhoc] Always enable TCPNoDelay to improve response time" +[#14284]: https://github.com/hrydgard/ppsspp/issues/14284 "[Adhoc] Fix Teenage Mutant Ninja Turtles Multiplayer" +[#14290]: https://github.com/hrydgard/ppsspp/issues/14290 "Fix FlatOut Head On multiplayer." +[#14335]: https://github.com/hrydgard/ppsspp/issues/14335 "[Adhoc] Prevent flooding Adhoc Server with connection attempts" +[#14342]: https://github.com/hrydgard/ppsspp/issues/14342 "[AdhocMatching] Fix crashing issue when leaving a multiplayer game room" +[#14345]: https://github.com/hrydgard/ppsspp/issues/14345 "[APctl] Fix stuck issue when scanning AP to Recruit on MGS:PW" +[#14466]: https://github.com/hrydgard/ppsspp/issues/14466 "[Adhoc] Fix possible crash issue on blocking socket implementation." +[#14492]: https://github.com/hrydgard/ppsspp/issues/14492 "[AdhocGameMode] Create GameMode's socket after Master and all Replicas have been created" +[#14513]: https://github.com/hrydgard/ppsspp/issues/14513 "[Adhoc] Reducing HLE delays due to Mutiplayer performance regressions" +[#14849]: https://github.com/hrydgard/ppsspp/issues/14849 "[Adhoc] Fix Socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy" +[#11974]: https://github.com/hrydgard/ppsspp/issues/11974 "[Linux] [Vulkan] Toggle fullscreen doesn't update display properly" \ No newline at end of file From fdb61859ece5870ec182ce273224635c4e46716d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 10:11:17 +0100 Subject: [PATCH 697/715] Re-link the readme --- README.md | 204 ++++++++++++++++++++++++++++++++++--------------- link_readme.py | 3 + 2 files changed, 145 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 5d6ff26823..1fc89d2439 100644 --- a/README.md +++ b/README.md @@ -154,68 +154,6 @@ Credit goes to: [comment]: # (LINK_LIST_BEGIN_HERE) -[#11997]: https://github.com/hrydgard/ppsspp/issues/11997 "Android 12 scoped storage hell" -[#5099]: https://github.com/hrydgard/ppsspp/issues/5099 "IOS touch controls problems." -[#14053]: https://github.com/hrydgard/ppsspp/issues/14053 "Toggle screenshot minor issue." -[#14176]: https://github.com/hrydgard/ppsspp/issues/14176 "Remove deprecated API calls for new FFmpeg 4.3.x" -[#14188]: https://github.com/hrydgard/ppsspp/issues/14188 "Additional fixes for FFmpeg 3.1+" -[#14199]: https://github.com/hrydgard/ppsspp/issues/14199 "Mpeg: Set low latency flag for video decode" -[#14145]: https://github.com/hrydgard/ppsspp/issues/14145 "libretro: Remove \"Unsafe FuncReplacements\" option." -[#13864]: https://github.com/hrydgard/ppsspp/issues/13864 "Vulkan: Remove #10097 hack for newer AMD drivers" -[#14201]: https://github.com/hrydgard/ppsspp/issues/14201 "Add iOS version detection, turn off JIT on bootup if >= 14.3." -[#14241]: https://github.com/hrydgard/ppsspp/issues/14241 "iOS: Try a different JIT detection method, thanks Halo-Michael." -[#14317]: https://github.com/hrydgard/ppsspp/issues/14317 "Window size restarts on closing" -[#8288]: https://github.com/hrydgard/ppsspp/issues/8288 "NBA live 08 Invalid address and hang" -[#14069]: https://github.com/hrydgard/ppsspp/issues/14069 "Mini-Map in Z.H.P. Updates Incorrectly Without Software Rendering" -[#13252]: https://github.com/hrydgard/ppsspp/issues/13252 "Open Season Title Screen does not display" -[#14127]: https://github.com/hrydgard/ppsspp/issues/14127 "Metal Gear Solid Peace Walker Chinese Patched blue screen" -[#14271]: https://github.com/hrydgard/ppsspp/issues/14271 "Ape Academy 2 is broken on versions after 1.8.0(?) - tested on latest nightly and 1.11.3" -[#13741]: https://github.com/hrydgard/ppsspp/issues/13741 "Princess Maker 5 Portable half screen in Vulkan" -[#14167]: https://github.com/hrydgard/ppsspp/issues/14167 "[Android] Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off" -[#14230]: https://github.com/hrydgard/ppsspp/issues/14230 "Support texture replacement filtering overrides" -[#13759]: https://github.com/hrydgard/ppsspp/issues/13759 "Yarudora Portable: Double Cast" -[#13146]: https://github.com/hrydgard/ppsspp/issues/13146 "Sims 2 Castaway/Pets EA Logo glitched out - 1.10.2" -[#14789]: https://github.com/hrydgard/ppsspp/issues/14789 "Add new texture filtering mode \"Auto Max Quality\"" -[#14209]: https://github.com/hrydgard/ppsspp/issues/14209 "Fix Size & Position jpn0.pgf/ltn0.pgf/ltn2.pgf/ltn4.pgf/ltn6.pgf" -[#14042]: https://github.com/hrydgard/ppsspp/issues/14042 "Implement basic depth texturing for OpenGL" -[#14966]: https://github.com/hrydgard/ppsspp/issues/14966 "Config: Correct cardboard setting ini load" -[#14768]: https://github.com/hrydgard/ppsspp/issues/14768 "Fix the math in cardboard VR mode for wide aspect ratios" -[#14879]: https://github.com/hrydgard/ppsspp/issues/14879 "vertexjit: Correct morph flag alpha check assert" -[#14313]: https://github.com/hrydgard/ppsspp/issues/14313 "Add a setting for choosing background animation in PPSSPP's menus" -[#14818]: https://github.com/hrydgard/ppsspp/issues/14818 "Focus based moving background" -[#14810]: https://github.com/hrydgard/ppsspp/issues/14810 "Wave animation" -[#14347]: https://github.com/hrydgard/ppsspp/issues/14347 "UI: Add BG animation for recent games" -[#14041]: https://github.com/hrydgard/ppsspp/issues/14041 "UI: Add button to show CRC on feedback screen" -[#14224]: https://github.com/hrydgard/ppsspp/issues/14224 "Add a Storage tab to System Information with some path info" -[#14238]: https://github.com/hrydgard/ppsspp/issues/14238 "UI: Wrap long info items and cleanup storage display" -[#14056]: https://github.com/hrydgard/ppsspp/issues/14056 "Track memory allocations and writes for debug info" -[#14237]: https://github.com/hrydgard/ppsspp/issues/14237 "Add initial search to savedata manager" -[#14528]: https://github.com/hrydgard/ppsspp/issues/14528 "Postshader: Let shaders use the previous frame" -[#14548]: https://github.com/hrydgard/ppsspp/issues/14548 "Add some PPSSPP's Japanese keyboard" -[#14708]: https://github.com/hrydgard/ppsspp/issues/14708 "Add Reset button on crash screen, allow load state and related" -[#14676]: https://github.com/hrydgard/ppsspp/issues/14676 "Add savestate undo UI" -[#14679]: https://github.com/hrydgard/ppsspp/issues/14679 "Savestate load undo" -[#14697]: https://github.com/hrydgard/ppsspp/issues/14697 "Add undo last save as well" -[#14596]: https://github.com/hrydgard/ppsspp/issues/14596 "Replace the \"Test Analogs\" screen with a new screen that lets you directly try the settings." -[#13869]: https://github.com/hrydgard/ppsspp/issues/13869 "Make combo button more generic" -[#12530]: https://github.com/hrydgard/ppsspp/issues/12530 "Allow tilt input on Z instead of X" -[#14000]: https://github.com/hrydgard/ppsspp/issues/14000 "Add CRC32 calc" -[#14769]: https://github.com/hrydgard/ppsspp/issues/14769 "Add a visual means of control mapping" -[#13107]: https://github.com/hrydgard/ppsspp/issues/13107 "Basic mappable motion gesture" -[#14843]: https://github.com/hrydgard/ppsspp/issues/14843 "DPad drag fixes" -[#14480]: https://github.com/hrydgard/ppsspp/issues/14480 "Configurable analog head size" -[#14140]: https://github.com/hrydgard/ppsspp/issues/14140 "[Adhoc] Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data" -[#14235]: https://github.com/hrydgard/ppsspp/issues/14235 "[Adhoc] Always enable TCPNoDelay to improve response time" -[#14284]: https://github.com/hrydgard/ppsspp/issues/14284 "[Adhoc] Fix Teenage Mutant Ninja Turtles Multiplayer" -[#14290]: https://github.com/hrydgard/ppsspp/issues/14290 "Fix FlatOut Head On multiplayer." -[#14335]: https://github.com/hrydgard/ppsspp/issues/14335 "[Adhoc] Prevent flooding Adhoc Server with connection attempts" -[#14342]: https://github.com/hrydgard/ppsspp/issues/14342 "[AdhocMatching] Fix crashing issue when leaving a multiplayer game room" -[#14345]: https://github.com/hrydgard/ppsspp/issues/14345 "[APctl] Fix stuck issue when scanning AP to Recruit on MGS:PW" -[#14466]: https://github.com/hrydgard/ppsspp/issues/14466 "[Adhoc] Fix possible crash issue on blocking socket implementation." -[#14492]: https://github.com/hrydgard/ppsspp/issues/14492 "[AdhocGameMode] Create GameMode's socket after Master and all Replicas have been created" -[#14513]: https://github.com/hrydgard/ppsspp/issues/14513 "[Adhoc] Reducing HLE delays due to Mutiplayer performance regressions" -[#14849]: https://github.com/hrydgard/ppsspp/issues/14849 "[Adhoc] Fix Socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy" -[#14711]: https://github.com/hrydgard/ppsspp/issues/14711 "Sas: Add option to control reverb volume" [#15237]: https://github.com/hrydgard/ppsspp/issues/15237 "Path: Check for PSP case insensitively" [#15487]: https://github.com/hrydgard/ppsspp/issues/15487 "Save textures on background tasks when texture dumping is enabled." [#15645]: https://github.com/hrydgard/ppsspp/issues/15645 "UI: Add analog speed limit mapping" @@ -277,3 +215,145 @@ Credit goes to: [#15740]: https://github.com/hrydgard/ppsspp/issues/15740 "Replacement: Clear cache on disable" [#15734]: https://github.com/hrydgard/ppsspp/issues/15734 "Better pt-pt translation" [#15733]: https://github.com/hrydgard/ppsspp/issues/15733 "Fix bug in blue-to-alpha - alpha blending could be on when it shouldn't be." +[#15960]: https://github.com/hrydgard/ppsspp/issues/15960 "Enable logic op emulation in-shader" +[#16208]: https://github.com/hrydgard/ppsspp/issues/16208 "GPU: Respect stencil state in shader blend" +[#16032]: https://github.com/hrydgard/ppsspp/issues/16032 "Fix the water in Outrun when no logic ops" +[#16024]: https://github.com/hrydgard/ppsspp/issues/16024 "GPU: Fix simulating logicop with blend and shader" +[#15967]: https://github.com/hrydgard/ppsspp/issues/15967 "Fix BlueToAlpha mode, re-enable it for Outrun and DiRT" +[#16142]: https://github.com/hrydgard/ppsspp/issues/16142 "Implement geometry shader for range culling" +[#16504]: https://github.com/hrydgard/ppsspp/issues/16504 "GPU: Use accurate depth for depth range hack" +[#16442]: https://github.com/hrydgard/ppsspp/issues/16442 "Vulkan: Only use geometry shaders with accurate depth" +[#16383]: https://github.com/hrydgard/ppsspp/issues/16383 "GPU: Automatically reduce depth range on == test" +[#16165]: https://github.com/hrydgard/ppsspp/issues/16165 "Vulkan: Clip clamped depth in geometry shader" +[#16162]: https://github.com/hrydgard/ppsspp/issues/16162 "Implement negative Z clipping in geometry shader" +[#16049]: https://github.com/hrydgard/ppsspp/issues/16049 "GPU: Clip depth properly when also clamping" +[#15934]: https://github.com/hrydgard/ppsspp/issues/15934 "Split the main framebuffer in Killzone, to avoid texturing-from-current-rendertarget" +[#16084]: https://github.com/hrydgard/ppsspp/issues/16084 "Fix Ridge Racer lens flares - ignore stride if texHeight == 1, when matching tex/fb" +[#16188]: https://github.com/hrydgard/ppsspp/issues/16188 "Fix depal bounds with dynamic CLUT. Fixes lens flare glitches in Ridge Racer" +[#16115]: https://github.com/hrydgard/ppsspp/issues/16115 "Add compatibility flag for loading pixels on framebuffer create using nearest filtering" +[#16014]: https://github.com/hrydgard/ppsspp/issues/16014 "Texture depal using CLUT loaded from framebuffers, and more. Fixes Burnout Dominator lens flare" +[#16081]: https://github.com/hrydgard/ppsspp/issues/16081 "Fix green flashes with Burnout Dominator lens flare" +[#16076]: https://github.com/hrydgard/ppsspp/issues/16076 "Don't try to replace or scale CLUT8-on-GPU textures." +[#16073]: https://github.com/hrydgard/ppsspp/issues/16073 "CLUTs can be loaded from small rectangular textures. Need to linearize." +[#15907]: https://github.com/hrydgard/ppsspp/issues/15907 "Reinterpret between 32 and 16 bit texture formats" +[#15903]: https://github.com/hrydgard/ppsspp/issues/15903 "Remove support for framebuffers changing stride (already unreachable)." +[#15898]: https://github.com/hrydgard/ppsspp/issues/15898 "Rendering issues in Tantalus Media games (Spongebob, MX ATV, etc)" +[#15854]: https://github.com/hrydgard/ppsspp/issues/15854 "Use sequence numbers instead of a tracking array for depth buffers" +[#15853]: https://github.com/hrydgard/ppsspp/issues/15853 "Framebuffer-bind sequence numbers" +[#15888]: https://github.com/hrydgard/ppsspp/issues/15888 "Copy color from overlapping framebuffers on bind, under certain conditions" +[#16127]: https://github.com/hrydgard/ppsspp/issues/16127 "Fixes for Silent Hill: Origins (depth buffer reassignment, eliminate readback)" +[#16454]: https://github.com/hrydgard/ppsspp/issues/16454 "GPU: Support framebuf depal from rendered CLUT" +[#15772]: https://github.com/hrydgard/ppsspp/issues/15772 "Add support for binding the depth buffer as a color target. Fixes Kurohyo depth sorting" +[#15728]: https://github.com/hrydgard/ppsspp/issues/15728 "Better ways to deal with overlapping render targets" +[#15859]: https://github.com/hrydgard/ppsspp/issues/15859 "Allow binding depth as 565" +[#15727]: https://github.com/hrydgard/ppsspp/issues/15727 "Implement the PSP's equal-size mips \"3D texturing\"" +[#16067]: https://github.com/hrydgard/ppsspp/issues/16067 "GPU: Account for w properly in lines, fixing width" +[#16179]: https://github.com/hrydgard/ppsspp/issues/16179 "Correct size and YUV order for jpeg decoding" +[#16184]: https://github.com/hrydgard/ppsspp/issues/16184 "GPU: Hook Gods Eater Burst avatar read" +[#15924]: https://github.com/hrydgard/ppsspp/issues/15924 "Add support for reading depth buffers to the PackFramebufferSync function" +[#16265]: https://github.com/hrydgard/ppsspp/issues/16265 "GPU: Respect world matrix and reverse flag w/o normals" +[#16043]: https://github.com/hrydgard/ppsspp/issues/16043 "Consider the Adreno and Mali stencil-discard bugs the same." +[#16379]: https://github.com/hrydgard/ppsspp/issues/16379 "Fix alpha/stencil replace on Adreno when color masked" +[#15822]: https://github.com/hrydgard/ppsspp/issues/15822 "GPU: Write stencil fail to alpha is RGB masked" +[#16358]: https://github.com/hrydgard/ppsspp/issues/16358 "TexCache: Fix 16->32 colors with CLUT start pos" +[#15998]: https://github.com/hrydgard/ppsspp/issues/15998 "softgpu: Allow almost flat rectangles to go fast" +[#16001]: https://github.com/hrydgard/ppsspp/issues/16001 "softgpu: Check depth test early on simple stencil" +[#16011]: https://github.com/hrydgard/ppsspp/issues/16011 "Detect more triangles as rectangles in softgpu" +[#16039]: https://github.com/hrydgard/ppsspp/issues/16039 "softgpu: Run early Z tests in fast rect path" +[#16054]: https://github.com/hrydgard/ppsspp/issues/16054 "softgpu: Reduce some flushing / flushing cost" +[#16080]: https://github.com/hrydgard/ppsspp/issues/16080 "softgpu: Avoid unnecessary flushing for curves" +[#16085]: https://github.com/hrydgard/ppsspp/issues/16085 "softgpu: Cache reused indexed verts" +[#16094]: https://github.com/hrydgard/ppsspp/issues/16094 "softgpu: Optimize rectangle sampling/blending used in bloom" +[#16102]: https://github.com/hrydgard/ppsspp/issues/16102 "softgpu: Avoid waiting for a thread to drain" +[#16387]: https://github.com/hrydgard/ppsspp/issues/16387 "softgpu: Use threads on self-render if safe" +[#16486]: https://github.com/hrydgard/ppsspp/issues/16486 "softgpu: Apply optimizations to states generically" +[#16502]: https://github.com/hrydgard/ppsspp/issues/16502 "A few more softgpu optimizations for alpha blend/test" +[#16518]: https://github.com/hrydgard/ppsspp/issues/16518 "softgpu: Expand fast path to all fb formats" +[#15999]: https://github.com/hrydgard/ppsspp/issues/15999 "softgpu: Clamp/wrap textures at 512 pixels" +[#16005]: https://github.com/hrydgard/ppsspp/issues/16005 "softgpu: Correct accuracy of fog calculation" +[#16042]: https://github.com/hrydgard/ppsspp/issues/16042 "softgpu: Refactor imm prim handling to support fog/color1" +[#16086]: https://github.com/hrydgard/ppsspp/issues/16086 "softgpu: Fix self-render detect in Ridge Racer" +[#16117]: https://github.com/hrydgard/ppsspp/issues/16117 "Correct texture projection issues, mainly in softgpu" +[#16231]: https://github.com/hrydgard/ppsspp/issues/16231 "softgpu: Cull a triangle with all negative w" +[#16241]: https://github.com/hrydgard/ppsspp/issues/16241 "softgpu: Correct linear interp for uneven positions" +[#16274]: https://github.com/hrydgard/ppsspp/issues/16274 "Correct accuracy of bounding box test" +[#16469]: https://github.com/hrydgard/ppsspp/issues/16469 "Correct block transfer overlap and wrapping behavior" +[#16470]: https://github.com/hrydgard/ppsspp/issues/16470 "softgpu: Correctly fix inversions, matching tests" +[#16478]: https://github.com/hrydgard/ppsspp/issues/16478 "softgpu: Interpolate Z for 3D lines" +[#16480]: https://github.com/hrydgard/ppsspp/issues/16480 "softgpu: Cull verts outside post-viewport Z" +[#16485]: https://github.com/hrydgard/ppsspp/issues/16485 "softgpu: Handle infnan fog coefficients better" +[#15659]: https://github.com/hrydgard/ppsspp/issues/15659 "Oculus Quest native support" +[#15901]: https://github.com/hrydgard/ppsspp/issues/15901 "OpenXR - Stereoscopic rendering" +[#16246]: https://github.com/hrydgard/ppsspp/issues/16246 "VR: Add the VR code to all builds. Remove IsVRBuild calls from the renderer." +[#16262]: https://github.com/hrydgard/ppsspp/issues/16262 "OpenXR - Add an option to adjust camera distance" +[#16273]: https://github.com/hrydgard/ppsspp/issues/16273 "Vulkan multiview rendering" +[#16458]: https://github.com/hrydgard/ppsspp/issues/16458 "Implement MSAA support for desktop GPUs in Vulkan" +[#16441]: https://github.com/hrydgard/ppsspp/issues/16441 "Exposed more emulator things to devctl api" +[#15748]: https://github.com/hrydgard/ppsspp/issues/15748 "Windows: Add a simple window message to get the base pointer." +[#16121]: https://github.com/hrydgard/ppsspp/issues/16121 "Debugger: Add API to scan memory for funcs" +[#16187]: https://github.com/hrydgard/ppsspp/issues/16187 "Remote API: hle.func.removeRange added" +[#16198]: https://github.com/hrydgard/ppsspp/issues/16198 "Readback stencil buffer for debugger on GLES" +[#16389]: https://github.com/hrydgard/ppsspp/issues/16389 "Make breakpoints work better in interpreter" +[#16304]: https://github.com/hrydgard/ppsspp/issues/16304 "Improve texture replacement cache and allow read from zip" +[#16409]: https://github.com/hrydgard/ppsspp/issues/16409 "Preserve framebuffer on pause screen even if render resolution is changed" +[#16415]: https://github.com/hrydgard/ppsspp/issues/16415 "Display layout editor - Remove editing widget, just use the background directly" +[#16417]: https://github.com/hrydgard/ppsspp/issues/16417 "Move post processing settings to the Display Layout Editor" +[#16445]: https://github.com/hrydgard/ppsspp/issues/16445 "New screen size controls on Display Layout & Effects screen" +[#16531]: https://github.com/hrydgard/ppsspp/issues/16531 "iota97's \"Motion blur\" - LCD persistence shader, plus fixes to make it work with OpenGL" +[#16404]: https://github.com/hrydgard/ppsspp/issues/16404 "Make the pause screen \"transparent\"" +[#16346]: https://github.com/hrydgard/ppsspp/issues/16346 "Change the \"Retain changed textures\" option into a compat.ini option." +[#16347]: https://github.com/hrydgard/ppsspp/issues/16347 "Always skin in decode for software transform and rendering" +[#16348]: https://github.com/hrydgard/ppsspp/issues/16348 "Speed hack setting reorganization" +[#16432]: https://github.com/hrydgard/ppsspp/issues/16432 "Cleanup graphics settings list" +[#16422]: https://github.com/hrydgard/ppsspp/issues/16422 "Add compat flag / bug check for games on old Adreno/GL affected" +[#16419]: https://github.com/hrydgard/ppsspp/issues/16419 "Stick input: Fix issue where deadzone noise from one device could drown out signal from another." +[#16450]: https://github.com/hrydgard/ppsspp/issues/16450 "UI: Fix right analog with single button" +[#16388]: https://github.com/hrydgard/ppsspp/issues/16388 "Twinbee Portable: Add compat flag to avoid game bug with some languages" +[#16449]: https://github.com/hrydgard/ppsspp/issues/16449 "Blind workaround for Shining Ark circle button problem" +[#15723]: https://github.com/hrydgard/ppsspp/issues/15723 "D3D9 state cache cleanup" +[#15815]: https://github.com/hrydgard/ppsspp/issues/15815 "Depth blit using raster" +[#15926]: https://github.com/hrydgard/ppsspp/issues/15926 "Implement shader blending for D3D9" +[#16100]: https://github.com/hrydgard/ppsspp/issues/16100 "D3D9: Allow INTZ depth buffers more correctly" +[#16232]: https://github.com/hrydgard/ppsspp/issues/16232 "D3D9: Correct scissor state cache in Draw" +[#16550]: https://github.com/hrydgard/ppsspp/issues/16550 "Hide the D3D9 option on Intel Xe graphics." +[#16396]: https://github.com/hrydgard/ppsspp/issues/16396 "Correct misbehavior on uninitialized values in IR" +[#16302]: https://github.com/hrydgard/ppsspp/issues/16302 "Handle vrot overlap and vscl/vmscl prefixes more accurately" +[#16305]: https://github.com/hrydgard/ppsspp/issues/16305 "irjit: Fix unordered float compares" +[#16306]: https://github.com/hrydgard/ppsspp/issues/16306 "irjit: Correct prefix validation" +[#16434]: https://github.com/hrydgard/ppsspp/issues/16434 "Vulkan: Use stencil export when available" +[#16099]: https://github.com/hrydgard/ppsspp/issues/16099 "Vulkan: Avoid allocating depth images for stuff like temp copies, depal buffers etc." +[#16090]: https://github.com/hrydgard/ppsspp/issues/16090 "Simplify synchronization in VulkanRenderManager" +[#16072]: https://github.com/hrydgard/ppsspp/issues/16072 "Vulkan: Don't have renderpasses store/load depth buffers when we don't use them" +[#16061]: https://github.com/hrydgard/ppsspp/issues/16061 "Vulkan: Submit main command buffer before acquiring the swapchain image" +[#16060]: https://github.com/hrydgard/ppsspp/issues/16060 "Vulkan FrameData refactor" +[#16035]: https://github.com/hrydgard/ppsspp/issues/16035 "Vulkan: \"Acquire\" the image from the swapchain as late as possible in the frame" +[#15917]: https://github.com/hrydgard/ppsspp/issues/15917 "Vulkan bandwidth optimizations (configure renderpass load/store better)" +[#16104]: https://github.com/hrydgard/ppsspp/issues/16104 "Generate \"Ubershaders\" that can handle all lighting configurations" +[#16111]: https://github.com/hrydgard/ppsspp/issues/16111 "Always do the vertex shader part of the fog computation." +[#15589]: https://github.com/hrydgard/ppsspp/issues/15589 "Vulkan: Parallelize GLSL compilation" +[#15843]: https://github.com/hrydgard/ppsspp/issues/15843 "GPU: Skip fb create upload when clearing" +[#16190]: https://github.com/hrydgard/ppsspp/issues/16190 "Reduce IO primarily during save operations" +[#15884]: https://github.com/hrydgard/ppsspp/issues/15884 "Replacement: Read files only within time budget" +[#16314]: https://github.com/hrydgard/ppsspp/issues/16314 "UI: Install textures as a zip if supported" +[#15803]: https://github.com/hrydgard/ppsspp/issues/15803 "Reimplement bicubic upscaling." +[#16125]: https://github.com/hrydgard/ppsspp/issues/16125 "Remove alpha ignore in xbrz texture shaders." +[#16413]: https://github.com/hrydgard/ppsspp/issues/16413 "Kernel: Respect partition param in heap funcs" +[#16070]: https://github.com/hrydgard/ppsspp/issues/16070 "Kernel: Match index lookup behavior for tls" +[#16052]: https://github.com/hrydgard/ppsspp/issues/16052 "HLE: sceKernelAllocPartitionMemory volatile memory support (partition 5)" +[#15930]: https://github.com/hrydgard/ppsspp/issues/15930 "Fix sceKernelUnlockMutex timing" +[#15952]: https://github.com/hrydgard/ppsspp/issues/15952 "interp: Handle jumps in branch delay slots better" +[#15957]: https://github.com/hrydgard/ppsspp/issues/15957 "Handle branch/jump in branch delay slots more accurately" +[#15839]: https://github.com/hrydgard/ppsspp/issues/15839 "GE debugger: Allow displaying two tabs at once, separate DL view" +[#15851]: https://github.com/hrydgard/ppsspp/issues/15851 "After recording a GE dump, open an explorer window pointing at the file" +[#15894]: https://github.com/hrydgard/ppsspp/issues/15894 "GE Debugger: Record only one flip if display framebuf not changed, step on vsync" +[#15925]: https://github.com/hrydgard/ppsspp/issues/15925 "GE Debugger: Improve display list disasm" +[#15974]: https://github.com/hrydgard/ppsspp/issues/15974 "Add breakpoint conditions to GE debugger" +[#16007]: https://github.com/hrydgard/ppsspp/issues/16007 "GE Debugger: Add fields to register expressions" +[#16047]: https://github.com/hrydgard/ppsspp/issues/16047 "GE Debugger: Allow search" +[#16096]: https://github.com/hrydgard/ppsspp/issues/16096 "GE Debugger: Add option to track pixel in preview" +[#16201]: https://github.com/hrydgard/ppsspp/issues/16201 "GE Debugger: Normalize framebuffer texture preview" +[#15879]: https://github.com/hrydgard/ppsspp/issues/15879 "irjit: Validate alignment in slow memory mode" +[#15880]: https://github.com/hrydgard/ppsspp/issues/15880 "Core: Show exception on misaligned jump" +[#16089]: https://github.com/hrydgard/ppsspp/issues/16089 "[AdhocMatching] Fix assertion issue when playing Cars over public adhoc server." +[#15990]: https://github.com/hrydgard/ppsspp/issues/15990 "Atrac3+: Allocate some extra" +[#15889]: https://github.com/hrydgard/ppsspp/issues/15889 "Correct D3D viewport offset sign in sw transform" \ No newline at end of file diff --git a/link_readme.py b/link_readme.py index 25cd951b4f..0927769afe 100755 --- a/link_readme.py +++ b/link_readme.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# Requirement: +# python3 -m pip install lxml + import re from time import sleep from urllib.request import urlopen From 73cd9fac7dd42249035f9cbcd4cc8a3ce4f6551f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 15:16:11 +0100 Subject: [PATCH 698/715] Tiny optimization in PipelineDesc --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 5 ++++- Common/GPU/Vulkan/VulkanRenderManager.h | 3 ++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 2 +- GPU/Vulkan/PipelineManagerVulkan.cpp | 7 ++----- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index fab538a0a4..b635ff75da 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -86,12 +86,15 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR ms.minSampleShading = 1.0f; } + VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + inputAssembly.topology = desc->topology; + // We will use dynamic viewport state. pipe.pVertexInputState = &desc->vis; pipe.pViewportState = &desc->views; pipe.pTessellationState = nullptr; pipe.pDynamicState = &desc->ds; - pipe.pInputAssemblyState = &desc->inputAssembly; + pipe.pInputAssemblyState = &inputAssembly; pipe.pMultisampleState = &ms; pipe.layout = desc->pipelineLayout; pipe.basePipelineHandle = VK_NULL_HANDLE; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index e4845f9924..064f1684c9 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -75,6 +75,7 @@ struct BoundingRect { }; // All the data needed to create a graphics pipeline. +// TODO: Compress this down greatly. struct VKRGraphicsPipelineDesc : Draw::RefCountedObject { VkPipelineCache pipelineCache = VK_NULL_HANDLE; VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; @@ -95,7 +96,7 @@ struct VKRGraphicsPipelineDesc : Draw::RefCountedObject { std::string fragmentShaderSource; std::string geometryShaderSource; - VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + VkPrimitiveTopology topology; VkVertexInputAttributeDescription attrs[8]{}; VkVertexInputBindingDescription ibd{}; VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 422c288083..19277ec94b 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1216,7 +1216,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char raster->ToVulkan(&gDesc.rs); // Copy bindings from input layout. - gDesc.inputAssembly.topology = primToVK[(int)desc.prim]; + gDesc.topology = primToVK[(int)desc.prim]; // We treat the three stencil states as a unit in other places, so let's do that here too. const VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK }; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index bd4b4f0204..c912bc71a8 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -121,7 +121,7 @@ void GPU_Vulkan::CancelReady() { void GPU_Vulkan::LoadCache(const Path &filename) { if (!g_Config.bShaderCache) { - INFO_LOG(G3D, "Shader cache disabled. Not loading."); + WARN_LOG(G3D, "!!!! Shader cache disabled. Not loading."); return; } diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index f5ba269229..cb945fc4f0 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -266,12 +266,9 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, desc->geometryShaderSource = gs->GetShaderString(SHADER_STRING_SOURCE_CODE); } - VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly; - inputAssembly.flags = 0; - inputAssembly.topology = (VkPrimitiveTopology)key.topology; - inputAssembly.primitiveRestartEnable = false; - int vertexStride = 0; + desc->topology = (VkPrimitiveTopology)key.topology; + int vertexStride = 0; VkVertexInputAttributeDescription *attrs = &desc->attrs[0]; int attributeCount; From 80a0c97e9ef40dfe05bad458378d1955b57eb6fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 15:16:46 +0100 Subject: [PATCH 699/715] Drop the input attachment descriptor from the layout when unused --- GPU/Vulkan/DrawEngineVulkan.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index fdb9c263f7..bf3a21ce71 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -125,6 +125,7 @@ void DrawEngineVulkan::InitDeviceObjects() { bindings[8].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; bindings[8].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; bindings[8].binding = DRAW_BINDING_TESS_STORAGE_BUF_WV; + // Note: This binding is not included if !gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH), using bindingCount below. bindings[9].descriptorCount = 1; bindings[9].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; bindings[9].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; @@ -134,7 +135,7 @@ void DrawEngineVulkan::InitDeviceObjects() { VkDevice device = vulkan->GetDevice(); VkDescriptorSetLayoutCreateInfo dsl{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; - dsl.bindingCount = ARRAY_SIZE(bindings); + dsl.bindingCount = gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH) ? ARRAY_SIZE(bindings) : ARRAY_SIZE(bindings) - 1; dsl.pBindings = bindings; VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_); _dbg_assert_(VK_SUCCESS == res); From 427cae67cba9cab39ba281536c1255deaac2638b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 16:26:38 +0100 Subject: [PATCH 700/715] Enable some wordwrapping in shader viewer, show variant bitmask --- GPU/Vulkan/PipelineManagerVulkan.cpp | 18 +++++++++++------- UI/DevScreens.cpp | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index cb945fc4f0..401056f786 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -475,13 +475,14 @@ std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugSha VulkanPipelineKey pipelineKey; pipelineKey.FromString(id); - VulkanPipeline *iter = pipelines_.Get(pipelineKey); - if (!iter) { - return ""; + VulkanPipeline *pipeline = pipelines_.Get(pipelineKey); + if (!pipeline) { + return "N/A (missing)"; } + u32 variants = pipeline->GetVariantsBitmask(); - std::string str = pipelineKey.GetDescription(stringType); - return StringFromFormat("%p: %s", iter, str.c_str()); + std::string keyDescription = pipelineKey.GetDescription(stringType); + return StringFromFormat("%s. v: %08x", keyDescription.c_str(), variants); } std::string VulkanPipelineKey::GetDescription(DebugShaderStringType stringType) const { @@ -672,6 +673,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha uint32_t size = 0; if (loadRawPipelineCache) { + NOTICE_LOG(G3D, "WARNING: Using the badly tested raw pipeline cache path!!!!"); // WARNING: Do not use this path until after reading and implementing https://zeux.io/2019/07/17/serializing-pipeline-cache/ ! bool success = fread(&size, sizeof(size), 1, file) == 1; if (!size || !success) { @@ -707,12 +709,14 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha } else { vkMergePipelineCaches(vulkan_->GetDevice(), pipelineCache_, 1, &cache); } - NOTICE_LOG(G3D, "Loaded Vulkan pipeline cache (%d bytes).", (int)size); + NOTICE_LOG(G3D, "Loaded Vulkan binary pipeline cache (%d bytes).", (int)size); + // Note that after loading the cache, it's still a good idea to pre-create the various pipelines. } else { if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); if (res != VK_SUCCESS) { + WARN_LOG(G3D, "vkCreatePipelineCache failed (%08x), highly unexpected", (u32)res); return false; } } @@ -721,7 +725,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha // Read the number of pipelines. bool failed = fread(&size, sizeof(size), 1, file) != 1; - NOTICE_LOG(G3D, "Creating %d pipelines...", size); + NOTICE_LOG(G3D, "Creating %d pipelines from cache...", size); int pipelineCreateFailCount = 0; for (uint32_t i = 0; i < size; i++) { if (failed || cancelCache_) { diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index a496b0cdeb..cd233f2e47 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -1215,7 +1215,7 @@ void ShaderViewScreen::CreateViews() { LinearLayout *layout = new LinearLayout(ORIENT_VERTICAL); root_ = layout; - layout->Add(new TextView(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SHORT_DESC))); + layout->Add(new TextView(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SHORT_DESC), FLAG_DYNAMIC_ASCII | FLAG_WRAP_TEXT, false)); ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0)); scroll->SetTag("DevShaderView"); @@ -1229,7 +1229,7 @@ void ShaderViewScreen::CreateViews() { SplitString(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SOURCE_CODE), '\n', lines); for (auto line : lines) { - lineLayout->Add(new TextView(line, FLAG_DYNAMIC_ASCII, true)); + lineLayout->Add(new TextView(line, FLAG_DYNAMIC_ASCII | FLAG_WRAP_TEXT, true)); } layout->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); From 30e1bc0540808ea1f2b67cf8c0a13371f8eac982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 16:28:06 +0100 Subject: [PATCH 701/715] Some logging improvements --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index b635ff75da..0bc5341f12 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -106,10 +106,11 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR VkResult result = vkCreateGraphicsPipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &pipe, nullptr, &vkpipeline); double taken_ms = (time_now_d() - start) * 1000.0; - if (taken_ms < 0.1) - DEBUG_LOG(G3D, "Pipeline creation time: %0.2f ms (fast)", taken_ms); - else - INFO_LOG(G3D, "Pipeline creation time: %0.2f ms", taken_ms); + if (taken_ms < 0.1) { + INFO_LOG(G3D, "Pipeline creation time: %0.2f ms (fast) rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str()); + } else { + INFO_LOG(G3D, "Pipeline creation time: %0.2f ms rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str()); + } bool success = true; if (result == VK_INCOMPLETE) { @@ -355,10 +356,7 @@ void VulkanRenderManager::CompileThreadFunc() { break; } - if (!toCompile.empty()) { - INFO_LOG(G3D, "Compilation thread has %d pipelines to create", (int)toCompile.size()); - } - + double time = time_now_d(); // TODO: Here we can sort the pending pipelines by vertex and fragment shaders, // and split up further. // Those with the same pairs of shaders should be on the same thread. @@ -372,6 +370,12 @@ void VulkanRenderManager::CompileThreadFunc() { break; } } + + double delta = time_now_d() - time; + if (delta > 0.005f) { + INFO_LOG(G3D, "CompileThreadFunc: Creating %d pipelines took %0.3f ms", (int)toCompile.size(), delta * 1000.0f); + } + queueRunner_.NotifyCompileDone(); } } From 313a2b13272771fabd641744f729fd4be3daab50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 16:35:02 +0100 Subject: [PATCH 702/715] Improve shader cache logging --- GPU/Vulkan/GPU_Vulkan.cpp | 3 +++ GPU/Vulkan/ShaderManagerVulkan.cpp | 29 +++++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index c912bc71a8..11a5bf9bde 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -135,6 +135,9 @@ void GPU_Vulkan::LoadCache(const Path &filename) { // It's when recreating the pipelines that the pipeline cache is useful - in the ideal case, // it can just memcpy the finished shader binaries out of the pipeline cache file. bool result = shaderManagerVulkan_->LoadCache(f); + if (!result) { + WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache."); + } if (result) { // WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true. result = pipelineManager_->LoadCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout()); diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index e8f58ea9c2..4e614b2681 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -507,19 +507,25 @@ struct VulkanCacheHeader { bool ShaderManagerVulkan::LoadCache(FILE *f) { VulkanCacheHeader header{}; bool success = fread(&header, sizeof(header), 1, f) == 1; - if (!success || header.magic != CACHE_HEADER_MAGIC) + if (!success || header.magic != CACHE_HEADER_MAGIC) { + WARN_LOG(G3D, "Shader cache magic mismatch"); return false; - if (header.version != CACHE_VERSION) + } + if (header.version != CACHE_VERSION) { + WARN_LOG(G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION); return false; - if (header.useFlags != gstate_c.useFlags) + } + if (header.useFlags != gstate_c.useFlags) { + WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.useFlags); return false; + } VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); for (int i = 0; i < header.numVertexShaders; i++) { VShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated"); - break; + ERROR_LOG(G3D, "Vulkan shader cache truncated (in VertexShaders)"); + return false; } bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM); std::string genErrorString; @@ -527,6 +533,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { uint64_t uniformMask = 0; VertexShaderFlags flags; if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString)) { + WARN_LOG(G3D, "Failed to generate vertex shader during cache load"); return false; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); @@ -538,13 +545,14 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numFragmentShaders; i++) { FShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated"); - break; + ERROR_LOG(G3D, "Vulkan shader cache truncated (in FragmentShaders)"); + return false; } std::string genErrorString; uint64_t uniformMask = 0; FragmentShaderFlags flags; if (!GenerateFragmentShader(id, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString)) { + WARN_LOG(G3D, "Failed to generate fragment shader during cache load"); return false; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); @@ -555,11 +563,12 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numGeometryShaders; i++) { GShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated"); - break; + ERROR_LOG(G3D, "Vulkan shader cache truncated (in GeometryShaders)"); + return false; } std::string genErrorString; if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) { + WARN_LOG(G3D, "Failed to generate geometry shader during cache load"); return false; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_)); @@ -567,7 +576,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { gsCache_.Insert(id, gs); } - NOTICE_LOG(G3D, "Loaded %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders); + NOTICE_LOG(G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders); return true; } From ee19db091fa707356a001dfd23ef10a00ef8a230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 16:53:53 +0100 Subject: [PATCH 703/715] Add accessor for UseFlags --- GPU/D3D11/DrawEngineD3D11.cpp | 2 +- GPU/D3D11/GPU_D3D11.cpp | 2 +- GPU/Directx9/GPU_DX9.cpp | 2 +- GPU/GLES/GPU_GLES.cpp | 4 ++-- GPU/GLES/ShaderManagerGLES.cpp | 6 +++--- GPU/GPUCommon.cpp | 4 ++-- GPU/GPUState.h | 18 +++++++++++++++--- GPU/Vulkan/GPU_Vulkan.cpp | 4 ++-- GPU/Vulkan/ShaderManagerVulkan.cpp | 6 +++--- UI/DevScreens.cpp | 2 +- 10 files changed, 31 insertions(+), 19 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 87b7d866b8..ce6c3cfec6 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -712,7 +712,7 @@ rotateVBO: uint8_t clearStencil = clearColor >> 24; draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil); - if ((gstate_c.useFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 86340fc6d8..947a76af55 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -82,7 +82,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // No need to flush before the tex scale/offset commands if we are baking // the tex scale/offset into the vertices anyway. UpdateCmdInfo(); - gstate_c.useFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); BuildReportingInfo(); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index c5559f379a..e60167db71 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -81,7 +81,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // No need to flush before the tex scale/offset commands if we are baking // the tex scale/offset into the vertices anyway. UpdateCmdInfo(); - gstate_c.useFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); BuildReportingInfo(); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 380fe2d2c7..43ea2a97dc 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -55,7 +55,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), drawEngine_(draw), fragmentTestCache_(draw) { UpdateVsyncInterval(true); - gstate_c.useFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); shaderManagerGL_ = new ShaderManagerGLES(draw); framebufferManagerGL_ = new FramebufferManagerGLES(draw); @@ -146,7 +146,7 @@ GPU_GLES::~GPU_GLES() { delete textureCacheGL_; // Clear features so they're not visible in system info. - gstate_c.useFlags = 0; + gstate_c.SetUseFlags(0); } // Take the raw GL extension and versioning data and turn into feature flags. diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 6c26199290..15c9422273 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -195,7 +195,7 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, initialize.push_back({ &u_tess_weights_v, 0, TEX_SLOT_SPLINE_WEIGHTS_V }); GLRProgramFlags flags{}; - flags.supportDualSource = (gstate_c.useFlags & GPU_USE_DUALSOURCE_BLEND) != 0; + flags.supportDualSource = gstate_c.Use(GPU_USE_DUALSOURCE_BLEND); if (!VSID.Bit(VS_BIT_IS_THROUGH) && gstate_c.Use(GPU_USE_DEPTH_CLAMP)) { flags.useClipDistance0 = true; if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_USE_CLIP_DISTANCE)) @@ -952,7 +952,7 @@ void ShaderManagerGLES::Load(const Path &filename) { if (!f.ReadArray(&header, 1)) { return; } - if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.useFlags != gstate_c.useFlags) { + if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.useFlags != gstate_c.GetUseFlags()) { return; } diskCachePending_.start = time_now_d(); @@ -1108,7 +1108,7 @@ void ShaderManagerGLES::Save(const Path &filename) { header.magic = CACHE_HEADER_MAGIC; header.version = CACHE_VERSION; header.reserved = 0; - header.useFlags = gstate_c.useFlags; + header.useFlags = gstate_c.GetUseFlags(); header.numVertexShaders = GetNumVertexShaders(); header.numFragmentShaders = GetNumFragmentShaders(); header.numLinkedPrograms = GetNumPrograms(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index bbfa7f3090..6682c4b5d8 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -636,7 +636,7 @@ void GPUCommon::ClearCacheNextFrame() { void GPUCommon::CheckConfigChanged() { if (configChanged_) { ClearCacheNextFrame(); - gstate_c.useFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); drawEngineCommon_->NotifyConfigChanged(); textureCache_->NotifyConfigChanged(); framebufferManager_->NotifyConfigChanged(); @@ -1244,7 +1244,7 @@ void GPUCommon::BeginFrame() { if (drawEngineCommon_->EverUsedExactEqualDepth() && !sawExactEqualDepth_) { sawExactEqualDepth_ = true; - gstate_c.useFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); } } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index bc889e542f..e95c13558b 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -524,8 +524,8 @@ enum class SubmitType { }; struct GPUStateCache { - bool Use(u32 flags) { return (useFlags & flags) != 0; } // Return true if ANY of flags are true. - bool UseAll(u32 flags) { return (useFlags & flags) == flags; } // Return true if ALL flags are true. + bool Use(u32 flags) { return (useFlags_ & flags) != 0; } // Return true if ANY of flags are true. + bool UseAll(u32 flags) { return (useFlags_ & flags) == flags; } // Return true if ALL flags are true. uint64_t GetDirtyUniforms() { return dirty & DIRTY_ALL_UNIFORMS; } void Dirty(u64 what) { @@ -578,9 +578,21 @@ struct GPUStateCache { Dirty(DIRTY_FRAGMENTSHADER_STATE); } } + void SetUseFlags(u32 newFlags) { + if (newFlags != useFlags_) { + useFlags_ = newFlags; + // Recompile shaders and stuff? + } + } - u32 useFlags; + // When checking for a single flag, use Use()/UseAll(). + u32 GetUseFlags() const { + return useFlags_; + } +private: + u32 useFlags_; +public: u32 vertexAddr; u32 indexAddr; u32 offsetAddr; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 11a5bf9bde..c6ad8ca43c 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -52,7 +52,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), drawEngine_(draw) { - gstate_c.useFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); drawEngine_.InitDeviceObjects(); VulkanContext *vulkan = (VulkanContext *)gfxCtx->GetAPIContext(); @@ -497,7 +497,7 @@ void GPU_Vulkan::DeviceRestore() { GPUCommon::DeviceRestore(); InitDeviceObjects(); - gstate_c.useFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); BuildReportingInfo(); UpdateCmdInfo(); diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 4e614b2681..327392ad7c 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -515,8 +515,8 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { WARN_LOG(G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION); return false; } - if (header.useFlags != gstate_c.useFlags) { - WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.useFlags); + if (header.useFlags != gstate_c.GetUseFlags()) { + WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags()); return false; } @@ -584,7 +584,7 @@ void ShaderManagerVulkan::SaveCache(FILE *f) { VulkanCacheHeader header{}; header.magic = CACHE_HEADER_MAGIC; header.version = CACHE_VERSION; - header.useFlags = gstate_c.useFlags; + header.useFlags = gstate_c.GetUseFlags(); header.reserved = 0; header.numVertexShaders = (int)vsCache_.size(); header.numFragmentShaders = (int)fsCache_.size(); diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index cd233f2e47..66df64c2ab 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -619,7 +619,7 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem("Moga", moga)); #endif - if (gstate_c.useFlags != 0) { + if (gstate_c.GetUseFlags()) { // We're in-game, and can determine these. // TODO: Call a static version of GPUCommon::CheckGPUFeatures() and derive them here directly. From 65c721dce6512b458b40149a883690156d7b8742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 19:18:20 +0100 Subject: [PATCH 704/715] Rename Save/LoadCache to Save/LoadPipelineCache --- GPU/Vulkan/GPU_Vulkan.cpp | 6 +++--- GPU/Vulkan/PipelineManagerVulkan.cpp | 4 ++-- GPU/Vulkan/PipelineManagerVulkan.h | 4 ++-- GPU/Vulkan/ShaderManagerVulkan.cpp | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index c6ad8ca43c..16e4b32cd8 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -139,8 +139,8 @@ void GPU_Vulkan::LoadCache(const Path &filename) { WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache."); } if (result) { - // WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true. - result = pipelineManager_->LoadCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout()); + // WARNING: See comment in LoadPipelineCache if you are tempted to flip the second parameter to true. + result = pipelineManager_->LoadPipelineCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout()); } fclose(f); if (!result) { @@ -169,7 +169,7 @@ void GPU_Vulkan::SaveCache(const Path &filename) { return; shaderManagerVulkan_->SaveCache(f); // WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true. - pipelineManager_->SaveCache(f, false, shaderManagerVulkan_, draw_); + pipelineManager_->SavePipelineCache(f, false, shaderManagerVulkan_, draw_); INFO_LOG(G3D, "Saved Vulkan pipeline cache"); fclose(f); } diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 401056f786..8fe15d88a1 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -578,7 +578,7 @@ struct StoredVulkanPipelineKey { // If you're looking for how to invalidate the cache, it's done in ShaderManagerVulkan, look for CACHE_VERSION and increment it. // (Header of the same file this is stored in). -void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) { +void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); @@ -667,7 +667,7 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha } } -bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout) { +bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 5b5400ff1b..6f5866fbfb 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -98,8 +98,8 @@ public: std::vector DebugGetObjectIDs(DebugShaderType type); // Saves data for faster creation next time. - void SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext); - bool LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout); + void SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext); + bool LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout); void CancelCache(); private: diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 327392ad7c..11f27f362b 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -515,6 +515,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { WARN_LOG(G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION); return false; } + if (header.useFlags != gstate_c.GetUseFlags()) { WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags()); return false; From 00ebf4957fec4134122a7a538926f3187e073246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 23:06:57 +0100 Subject: [PATCH 705/715] Make shader cache loading a bit more lenient. --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 21 +++++++++--------- GPU/Vulkan/PipelineManagerVulkan.cpp | 26 ++++++++++++++++++----- GPU/Vulkan/ShaderManagerVulkan.cpp | 19 ++++++++++++----- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 0bc5341f12..25edb75682 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -546,17 +546,18 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe RenderPassType rpType = (RenderPassType)i; // Sanity check - don't compile incompatible types (could be caused by corrupt caches, changes in data structures, etc). - if (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) { - if (!RenderPassTypeHasDepth(rpType)) { - WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type"); - continue; - } + if ((pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) && !RenderPassTypeHasDepth(rpType)) { + WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type"); + continue; } - if (pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) { - if (!RenderPassTypeHasInput(rpType)) { - WARN_LOG(G3D, "Not compiling pipeline that requires input attachment, for non input renderpass type"); - continue; - } + if ((pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) && !RenderPassTypeHasInput(rpType)) { + WARN_LOG(G3D, "Not compiling pipeline that requires input attachment, for non input renderpass type"); + continue; + } + // Shouldn't hit this, these should have been filtered elsewhere. However, still a good check to do. + if (sampleCount == VK_SAMPLE_COUNT_1_BIT && RenderPassTypeHasMultisample(rpType)) { + WARN_LOG(G3D, "Not compiling single sample pipeline for a multisampled render pass type"); + continue; } pipeline->pipeline[i] = Promise::CreateEmpty(); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 8fe15d88a1..44cff72b84 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -671,6 +671,8 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); + cancelCache_ = false; + uint32_t size = 0; if (loadRawPipelineCache) { NOTICE_LOG(G3D, "WARNING: Using the badly tested raw pipeline cache path!!!!"); @@ -727,6 +729,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa NOTICE_LOG(G3D, "Creating %d pipelines from cache...", size); int pipelineCreateFailCount = 0; + int shaderFailCount = 0; for (uint32_t i = 0; i < size; i++) { if (failed || cancelCache_) { break; @@ -734,21 +737,33 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa StoredVulkanPipelineKey key; failed = failed || fread(&key, sizeof(key), 1, file) != 1; if (failed) { - ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file"); - continue; + ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file, stopping."); + break; } VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID); VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID); VulkanGeometryShader *gs = shaderManager->GetGeometryShaderFromID(key.gShaderID); if (!vs || !fs || (!gs && key.gShaderID.Bit(GS_BIT_ENABLED))) { - failed = true; - ERROR_LOG(G3D, "Failed to find vs or fs in of pipeline %d in cache", (int)i); + // We just ignore this one, it'll get created later if needed. + // Probably some useFlags mismatch. + WARN_LOG(G3D, "Failed to find vs or fs in pipeline %d in cache, skipping pipeline", (int)i); continue; } + // Avoid creating multisampled shaders if it's not enabled, as that results in an invalid combination. + u32 variantsToBuild = key.variants; + if (g_Config.iMultiSampleLevel == 0) { + for (u32 i = 0; i < (int)RenderPassType::TYPE_COUNT; i++) { + if (RenderPassTypeHasMultisample((RenderPassType)i)) { + variantsToBuild &= ~(1 << i); + } + } + } + DecVtxFormat fmt; fmt.InitializeFromID(key.vtxFmtId); - VulkanPipeline *pipeline = GetOrCreatePipeline(rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, key.variants); + VulkanPipeline *pipeline = GetOrCreatePipeline( + rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, variantsToBuild); if (!pipeline) { pipelineCreateFailCount += 1; } @@ -757,6 +772,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa rm->NudgeCompilerThread(); NOTICE_LOG(G3D, "Recreated Vulkan pipeline cache (%d pipelines, %d failed).", (int)size, pipelineCreateFailCount); + // We just ignore any failures. return true; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 11f27f362b..bec74abcff 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -517,10 +517,13 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { } if (header.useFlags != gstate_c.GetUseFlags()) { + // This can simply be a result of sawExactEqualDepth_ having been flipped to true in the previous run. + // Let's just keep going. WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags()); - return false; } + int failCount = 0; + VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); for (int i = 0; i < header.numVertexShaders; i++) { VShaderID id; @@ -535,7 +538,9 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { VertexShaderFlags flags; if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString)) { WARN_LOG(G3D, "Failed to generate vertex shader during cache load"); - return false; + // We just ignore this one and carry on. + failCount++; + continue; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, flags, codeBuffer_, useHWTransform); @@ -554,7 +559,9 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { FragmentShaderFlags flags; if (!GenerateFragmentShader(id, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString)) { WARN_LOG(G3D, "Failed to generate fragment shader during cache load"); - return false; + // We just ignore this one and carry on. + failCount++; + continue; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan, id, flags, codeBuffer_); @@ -570,14 +577,16 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { std::string genErrorString; if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) { WARN_LOG(G3D, "Failed to generate geometry shader during cache load"); - return false; + // We just ignore this one and carry on. + failCount++; + continue; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_)); VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_); gsCache_.Insert(id, gs); } - NOTICE_LOG(G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders); + NOTICE_LOG(G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders (failed %d)", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders, failCount); return true; } From 69819852d469138085b86f922ccfb4f95ccde3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Dec 2022 23:10:32 +0100 Subject: [PATCH 706/715] Disable geometry shader culling by default Geometry shaders allow us to fix some clipping and culling issues in a neat way on Mali and other platforms that don't support cull/clip planes, plus allow us to take care of some esoteric edge cases (triangle inversion), but unfortunately, at least on my Galaxy S20 with 32.1 drivers, they're just incredibly slow to compile. Around 100ms per shader, which leads to multi-second stutters on first run in Wipeout for example. Until we can either reduce the number of shaders drastically, or we find a driver version that's faster at compiling that we can cut this off at, let's not default to them on. They are still available for use, and I'll put something on the website to explain the issue... --- Core/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 795763c9ab..42183dc05d 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -881,7 +881,7 @@ static ConfigSetting graphicsSettings[] = { #endif ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", true, false), ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false), - ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, true, true, true), + ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, false, true, true), ReportedConfigSetting("SkipBufferEffects", &g_Config.bSkipBufferEffects, false, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), ConfigSetting("SoftwareRendererJit", &g_Config.bSoftwareRenderingJit, true, true, true), From 2168188cb8c5df3153ce5542aa6553768404a992 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 13 Dec 2022 18:24:59 -0800 Subject: [PATCH 707/715] Config: Remove unused values. --- Core/Config.cpp | 4 ---- Core/ConfigValues.h | 7 ------- 2 files changed, 11 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 795763c9ab..1e059016de 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -666,10 +666,6 @@ static int DefaultFastForwardMode() { #endif } -static int DefaultZoomType() { - return (int)SmallDisplayZoom::AUTO; -} - static int DefaultAndroidHwScale() { #ifdef __ANDROID__ if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19 || System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_TV) { diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 9018653aab..f8e88be931 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -105,13 +105,6 @@ enum IOTimingMethods { IOTIMING_REALISTIC = 2, }; -enum class SmallDisplayZoom { - STRETCH = 0, - PARTIAL_STRETCH = 1, - AUTO = 2, - MANUAL = 3, -}; - enum class AutoLoadSaveState { OFF = 0, OLDEST = 1, From 8c1a247b7b351b28dbdb99cd10082a308ba0efaf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 13 Dec 2022 18:29:23 -0800 Subject: [PATCH 708/715] Vulkan: Cleanup some logspam. --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 25edb75682..1d3e9f93da 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -107,7 +107,7 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR double taken_ms = (time_now_d() - start) * 1000.0; if (taken_ms < 0.1) { - INFO_LOG(G3D, "Pipeline creation time: %0.2f ms (fast) rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str()); + DEBUG_LOG(G3D, "Pipeline creation time: %0.2f ms (fast) rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str()); } else { INFO_LOG(G3D, "Pipeline creation time: %0.2f ms rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str()); } diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 16e4b32cd8..c7b74d71c8 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -121,7 +121,7 @@ void GPU_Vulkan::CancelReady() { void GPU_Vulkan::LoadCache(const Path &filename) { if (!g_Config.bShaderCache) { - WARN_LOG(G3D, "!!!! Shader cache disabled. Not loading."); + WARN_LOG(G3D, "Shader cache disabled. Not loading."); return; } From d8cf7ce30c5b1d624f68c9f96e9d29c8e04bb517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Dec 2022 16:10:21 +0100 Subject: [PATCH 709/715] Add stub symbol for 'utimensat', making it work on Android 2.3 again --- android/jni/app-android.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index ee0cf4c198..a79f558285 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -199,6 +199,15 @@ AndroidGraphicsContext *graphicsContext; #define MessageBox(a, b, c, d) __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s %s", (b), (c)); +#if PPSSPP_ARCH(ARMV7) +// Old Android workaround +extern "C" { +int utimensat(int fd, const char *path, const struct timespec times[2]) { + return -1; +} +} +#endif + void AndroidLogger::Log(const LogMessage &message) { int mode; switch (message.level) { From 41e5b1e95a996b3bf34ad9e739cd6572b159c08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Dec 2022 14:29:18 +0100 Subject: [PATCH 710/715] Plumb through multiSampleLevel so PipelineManager doesn't read config. --- GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++-- GPU/Vulkan/GPU_Vulkan.cpp | 2 +- GPU/Vulkan/PipelineManagerVulkan.cpp | 12 ++++++------ GPU/Vulkan/PipelineManagerVulkan.h | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index bf3a21ce71..d79bcadacc 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -788,7 +788,7 @@ void DrawEngineVulkan::DoFlush() { } _dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader"); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0, g_Config.iMultiSampleLevel); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. return; @@ -917,7 +917,7 @@ void DrawEngineVulkan::DoFlush() { shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0, g_Config.iMultiSampleLevel); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. decodedVerts_ = 0; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index c7b74d71c8..bda3c3844f 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -140,7 +140,7 @@ void GPU_Vulkan::LoadCache(const Path &filename) { } if (result) { // WARNING: See comment in LoadPipelineCache if you are tempted to flip the second parameter to true. - result = pipelineManager_->LoadPipelineCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout()); + result = pipelineManager_->LoadPipelineCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout(), g_Config.iMultiSampleLevel); } fclose(f); if (!result) { diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 44cff72b84..9d9b116e43 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -324,7 +324,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, return vulkanPipeline; } -VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) { +VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask, int multiSampleLevel) { if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); @@ -355,7 +355,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * pipelineFlags |= PipelineFlags::USES_MULTIVIEW; } - VkSampleCountFlagBits sampleCount = MultiSampleLevelToFlagBits(g_Config.iMultiSampleLevel); + VkSampleCountFlagBits sampleCount = MultiSampleLevelToFlagBits(multiSampleLevel); VulkanPipeline *pipeline = CreateVulkanPipeline( renderManager, pipelineCache_, layout, pipelineFlags, sampleCount, @@ -370,7 +370,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * } } -std::vector PipelineManagerVulkan::DebugGetObjectIDs(DebugShaderType type) { +std::vector PipelineManagerVulkan::DebugGetObjectIDs(DebugShaderType type) const { std::vector ids; switch (type) { case SHADER_TYPE_PIPELINE: @@ -667,7 +667,7 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa } } -bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout) { +bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, int multiSampleLevel) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); @@ -752,7 +752,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa // Avoid creating multisampled shaders if it's not enabled, as that results in an invalid combination. u32 variantsToBuild = key.variants; - if (g_Config.iMultiSampleLevel == 0) { + if (multiSampleLevel == 0) { for (u32 i = 0; i < (int)RenderPassType::TYPE_COUNT; i++) { if (RenderPassTypeHasMultisample((RenderPassType)i)) { variantsToBuild &= ~(1 << i); @@ -763,7 +763,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa DecVtxFormat fmt; fmt.InitializeFromID(key.vtxFmtId); VulkanPipeline *pipeline = GetOrCreatePipeline( - rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, variantsToBuild); + rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, variantsToBuild, multiSampleLevel); if (!pipeline) { pipelineCreateFailCount += 1; } diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 6f5866fbfb..cb1cc4fb88 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -84,7 +84,7 @@ public: ~PipelineManagerVulkan(); // variantMask is only used when loading pipelines from cache. - VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask); + VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask, int multiSampleLevel); int GetNumPipelines() const { return (int)pipelines_.size(); } void Clear(); @@ -95,11 +95,11 @@ public: void InvalidateMSAAPipelines(); std::string DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType); - std::vector DebugGetObjectIDs(DebugShaderType type); + std::vector DebugGetObjectIDs(DebugShaderType type) const; // Saves data for faster creation next time. void SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext); - bool LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout); + bool LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, int multiSampleLevel); void CancelCache(); private: From 11366a2ded1ccaa7bbcc23b03b6b514f6b3efea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Dec 2022 15:15:31 +0100 Subject: [PATCH 711/715] Don't refer directly to g_Config.iMultiSampleLevel, it can contain unsupported modes. --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 6 ++++++ GPU/Common/FramebufferManagerCommon.cpp | 18 ++++++++---------- GPU/Common/FramebufferManagerCommon.h | 10 +++++++--- GPU/D3D11/GPU_D3D11.cpp | 2 +- GPU/Directx9/GPU_DX9.cpp | 2 +- GPU/GLES/GPU_GLES.cpp | 2 +- GPU/GPUCommon.cpp | 16 +++++++++++++++- GPU/GPUCommon.h | 9 +++++++++ GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++-- GPU/Vulkan/GPU_Vulkan.cpp | 7 ++++--- GPU/Vulkan/PipelineManagerVulkan.cpp | 2 +- 11 files changed, 55 insertions(+), 23 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 1d3e9f93da..6eb24de9ef 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -48,6 +48,12 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR return false; } + if (!compatibleRenderPass) { + ERROR_LOG(G3D, "Failed creating graphics pipeline - compatible render pass was null"); + // We're kinda screwed here? + return false; + } + uint32_t stageCount = 2; VkPipelineShaderStageCreateInfo ss[3]{}; ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 1fa20e2733..9a372da426 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -82,14 +82,14 @@ FramebufferManagerCommon::~FramebufferManagerCommon() { delete presentation_; } -void FramebufferManagerCommon::Init() { +void FramebufferManagerCommon::Init(int msaaLevel) { // We may need to override the render size if the shader is upscaling or SSAA. NotifyDisplayResized(); - NotifyRenderResized(); + NotifyRenderResized(msaaLevel); } -bool FramebufferManagerCommon::UpdateRenderSize() { - const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight || msaaLevel_ != g_Config.iMultiSampleLevel; +bool FramebufferManagerCommon::UpdateRenderSize(int msaaLevel) { + const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight || msaaLevel_ != msaaLevel; int effectiveBloomHack = g_Config.iBloomHack; if (PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn) { @@ -104,7 +104,7 @@ bool FramebufferManagerCommon::UpdateRenderSize() { renderWidth_ = (float)PSP_CoreParameter().renderWidth; renderHeight_ = (float)PSP_CoreParameter().renderHeight; renderScaleFactor_ = (float)PSP_CoreParameter().renderScaleFactor; - msaaLevel_ = g_Config.iMultiSampleLevel; + msaaLevel_ = msaaLevel; bloomHack_ = effectiveBloomHack; useBufferedRendering_ = newBuffered; @@ -1670,9 +1670,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, char tag[128]; size_t len = FormatFramebufferName(vfb, tag, sizeof(tag)); - int msaaLevel = g_Config.iMultiSampleLevel; - - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), msaaLevel, true, tag }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), msaaLevel_, true, tag }); if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) { NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len); } @@ -2406,7 +2404,7 @@ void FramebufferManagerCommon::NotifyDisplayResized() { updatePostShaders_ = true; } -void FramebufferManagerCommon::NotifyRenderResized() { +void FramebufferManagerCommon::NotifyRenderResized(int msaaLevel) { gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; int w, h, scaleFactor; @@ -2415,7 +2413,7 @@ void FramebufferManagerCommon::NotifyRenderResized() { PSP_CoreParameter().renderHeight = h; PSP_CoreParameter().renderScaleFactor = scaleFactor; - if (UpdateRenderSize()) { + if (UpdateRenderSize(msaaLevel)) { DestroyAllFBOs(); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 27380df454..b900104b7e 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -272,7 +272,7 @@ public: drawEngine_ = td; } - virtual void Init(); + void Init(int msaaLevel); virtual void BeginFrame(); void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format); void DestroyFramebuf(VirtualFramebuffer *v); @@ -398,7 +398,7 @@ public: } void SetSafeSize(u16 w, u16 h); - void NotifyRenderResized(); + void NotifyRenderResized(int msaaLevel); virtual void NotifyDisplayResized(); void NotifyConfigChanged(); @@ -445,6 +445,10 @@ public: void ReleasePipelines(); + int GetMSAALevel() const { + return msaaLevel_; + } + protected: virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); // Used for when a shader is required, such as GLES. @@ -457,7 +461,7 @@ protected: void CopyToColorFromOverlappingFramebuffers(VirtualFramebuffer *dest); void CopyToDepthFromOverlappingFramebuffers(VirtualFramebuffer *dest); - bool UpdateRenderSize(); + bool UpdateRenderSize(int msaaLevel); void FlushBeforeCopy(); virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 947a76af55..124171978f 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -70,7 +70,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerD3D11_->SetTextureCache(textureCacheD3D11_); framebufferManagerD3D11_->SetShaderManager(shaderManagerD3D11_); framebufferManagerD3D11_->SetDrawEngine(&drawEngine_); - framebufferManagerD3D11_->Init(); + framebufferManagerD3D11_->Init(msaaLevel_); textureCacheD3D11_->SetFramebufferManager(framebufferManagerD3D11_); textureCacheD3D11_->SetShaderManager(shaderManagerD3D11_); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index e60167db71..2026b70989 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -69,7 +69,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerDX9_->SetTextureCache(textureCacheDX9_); framebufferManagerDX9_->SetShaderManager(shaderManagerDX9_); framebufferManagerDX9_->SetDrawEngine(&drawEngine_); - framebufferManagerDX9_->Init(); + framebufferManagerDX9_->Init(msaaLevel_); textureCacheDX9_->SetFramebufferManager(framebufferManagerDX9_); textureCacheDX9_->SetShaderManager(shaderManagerDX9_); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 43ea2a97dc..17f0f79552 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -74,7 +74,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerGL_->SetTextureCache(textureCacheGL_); framebufferManagerGL_->SetShaderManager(shaderManagerGL_); framebufferManagerGL_->SetDrawEngine(&drawEngine_); - framebufferManagerGL_->Init(); + framebufferManagerGL_->Init(msaaLevel_); textureCacheGL_->SetFramebufferManager(framebufferManagerGL_); textureCacheGL_->SetShaderManager(shaderManagerGL_); textureCacheGL_->SetDrawEngine(&drawEngine_); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6682c4b5d8..b95f969985 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -428,6 +428,8 @@ GPUCommon::GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : ResetMatrices(); PPGeSetDrawContext(draw); + + UpdateMSAALevel(draw); } GPUCommon::~GPUCommon() { @@ -484,6 +486,8 @@ void GPUCommon::BeginHostFrame() { gstate_c.Dirty(DIRTY_ALL); UpdateCmdInfo(); + + UpdateMSAALevel(draw_); CheckConfigChanged(); CheckDisplayResized(); CheckRenderResized(); @@ -659,7 +663,7 @@ void GPUCommon::CheckDisplayResized() { void GPUCommon::CheckRenderResized() { if (renderResized_) { - framebufferManager_->NotifyRenderResized(); + framebufferManager_->NotifyRenderResized(msaaLevel_); renderResized_ = false; } } @@ -3575,3 +3579,13 @@ u32 GPUCommon::CheckGPUFeaturesLate(u32 features) const { return features; } + +void GPUCommon::UpdateMSAALevel(Draw::DrawContext *draw) { + int level = g_Config.iMultiSampleLevel; + if (draw->GetDeviceCaps().multiSampleLevelsMask & (1 << level)) { + msaaLevel_ = level; + } else { + // Didn't support the configured level, so revert to 0. + msaaLevel_ = 0; + } +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 26442c09bd..28c09034ed 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -261,6 +261,10 @@ public: fullInfo = reportingFullInfo_; } + int MSAALevel() const { + return msaaLevel_; + } + protected: void DeviceLost() override; void DeviceRestore() override; @@ -319,6 +323,8 @@ protected: virtual void BuildReportingInfo() = 0; + void UpdateMSAALevel(Draw::DrawContext *draw); + FramebufferManagerCommon *framebufferManager_ = nullptr; TextureCacheCommon *textureCache_ = nullptr; DrawEngineCommon *drawEngineCommon_ = nullptr; @@ -405,6 +411,8 @@ protected: std::string reportingPrimaryInfo_; std::string reportingFullInfo_; + int msaaLevel_ = 0; + private: void CheckDepthUsage(VirtualFramebuffer *vfb); void DoExecuteCall(u32 target); @@ -415,6 +423,7 @@ private: // Debug stats. double timeSteppingStarted_; double timeSpentStepping_; + int lastVsync_ = -1; }; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index d79bcadacc..a8387e3720 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -788,7 +788,7 @@ void DrawEngineVulkan::DoFlush() { } _dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader"); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0, g_Config.iMultiSampleLevel); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0, framebufferManager_->GetMSAALevel()); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. return; @@ -917,7 +917,7 @@ void DrawEngineVulkan::DoFlush() { shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0, g_Config.iMultiSampleLevel); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0, framebufferManager_->GetMSAALevel()); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. decodedVerts_ = 0; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index bda3c3844f..b3ad3c7689 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -76,7 +76,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_); framebufferManagerVulkan_->SetDrawEngine(&drawEngine_); framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_); - framebufferManagerVulkan_->Init(); + framebufferManagerVulkan_->Init(msaaLevel_); textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_); textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_); textureCacheVulkan_->SetDrawEngine(&drawEngine_); @@ -140,9 +140,10 @@ void GPU_Vulkan::LoadCache(const Path &filename) { } if (result) { // WARNING: See comment in LoadPipelineCache if you are tempted to flip the second parameter to true. - result = pipelineManager_->LoadPipelineCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout(), g_Config.iMultiSampleLevel); + result = pipelineManager_->LoadPipelineCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout(), msaaLevel_); } fclose(f); + if (!result) { WARN_LOG(G3D, "Incompatible Vulkan pipeline cache - rebuilding."); // Bad cache file for this GPU/Driver/etc. Delete it. @@ -274,7 +275,7 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { // We need to turn off framebuffer fetch through input attachments if MSAA is on for now. // This is fixable, just needs some shader generator work (subpassInputMS). - if (g_Config.iMultiSampleLevel != 0) { + if (msaaLevel_ != 0) { features &= ~GPU_USE_FRAMEBUFFER_FETCH; } diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 9d9b116e43..e8ae8d9db6 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -727,7 +727,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa // Read the number of pipelines. bool failed = fread(&size, sizeof(size), 1, file) != 1; - NOTICE_LOG(G3D, "Creating %d pipelines from cache...", size); + NOTICE_LOG(G3D, "Creating %d pipelines from cache (%dx MSAA)...", size, (1 << multiSampleLevel)); int pipelineCreateFailCount = 0; int shaderFailCount = 0; for (uint32_t i = 0; i < size; i++) { From b70a9993d89c65b21f1fd2afc8ab33b8e5ef63ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Dec 2022 16:43:29 +0100 Subject: [PATCH 712/715] SoftGPU fix --- GPU/GPUCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index b95f969985..3727f9fcf0 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3582,7 +3582,7 @@ u32 GPUCommon::CheckGPUFeaturesLate(u32 features) const { void GPUCommon::UpdateMSAALevel(Draw::DrawContext *draw) { int level = g_Config.iMultiSampleLevel; - if (draw->GetDeviceCaps().multiSampleLevelsMask & (1 << level)) { + if (draw && draw->GetDeviceCaps().multiSampleLevelsMask & (1 << level)) { msaaLevel_ = level; } else { // Didn't support the configured level, so revert to 0. From a44af59f3a8eef23ca5fcfa016f7ce5983394f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 14 Dec 2022 16:59:20 +0100 Subject: [PATCH 713/715] Use vendor instead of lazy memory to detect tiling GPUs. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 19277ec94b..fbb5fbb3e8 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -853,13 +853,16 @@ VKContext::VKContext(VulkanContext *vulkan) break; } - bool hasLazyMemory = false; - for (u32 i = 0; i < vulkan->GetMemoryProperties().memoryTypeCount; i++) { - if (vulkan->GetMemoryProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) { - hasLazyMemory = true; - } + switch (caps_.vendor) { + case GPUVendor::VENDOR_ARM: + case GPUVendor::VENDOR_IMGTEC: + case GPUVendor::VENDOR_QUALCOMM: + caps_.isTilingGPU = true; + break; + default: + caps_.isTilingGPU = false; + break; } - caps_.isTilingGPU = hasLazyMemory && caps_.vendor != GPUVendor::VENDOR_APPLE; // Hide D3D9 when we know it likely won't work well. #if PPSSPP_PLATFORM(WINDOWS) From b75d6a1eab38d5727ebc63a0430b9377c6ecac22 Mon Sep 17 00:00:00 2001 From: xujibbs <79200793+xujibbs@users.noreply.github.com> Date: Thu, 15 Dec 2022 07:54:26 +0800 Subject: [PATCH 714/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 94a23dc3ea..b20cabbdfc 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1134,7 +1134,7 @@ Host (bugs, less lag) = 主机(较少延迟,有错误) Ignore bad memory accesses = 忽略错误的内存访问 Increase size = 增大尺寸 Interpreter = 解释器 -IO timing method = I/O计时方法 +IO timing method = I/O 计时方法 IR Interpreter = IR解释器 Memory Stick Folder = 记忆棒文件夹 Memory Stick inserted = 记忆棒已插入 @@ -1143,7 +1143,7 @@ MMDDYYYY = 月/日/年 Moving background = 动态壁纸 Newest Save = 最新的即时存档 No animation = 静态壁纸 -Not a PSP game = 这不是一个PSP游戏 +Not a PSP game = 这不是一个 PSP 游戏 Off = 关闭 Oldest Save = 最旧的即时存档 Path does not exist! = 路径不存在! @@ -1156,7 +1156,7 @@ Recent games = 最近的游戏 Record Audio = 录制音频 Record Display = 录制视频 Reset Recording on Save/Load State = 保存/载入存档时重置录制 -Restore Default Settings = 恢复默认PPSSPP设置 +Restore Default Settings = 恢复默认 PPSSPP 设置 Rewind Snapshot Frequency = 倒带自动即时存档频率 Save path in installed.txt = 存档路径在installed.txt Save path in My Documents = 存档路径在我的文档 @@ -1166,7 +1166,7 @@ Screenshots as PNG = 将截图保存为PNG格式 Set UI background... = 设置界面背景... Show ID = 显示游戏ID Show region flag = 显示游戏区域标识 -Simulate UMD delays = 模拟UMD延迟 +Simulate UMD delays = 模拟 UMD 延迟 Slot 1 = 插槽1 Slot 2 = 插槽2 Slot 3 = 插槽3 @@ -1180,7 +1180,7 @@ UI background animation = 界面背景效果 UI Sound = 界面声音 undo %c = 备份 %c USB = USB -Use Lossless Video Codec (FFV1) = 使用无损视频编解码器(FFV1) +Use Lossless Video Codec (FFV1) = 使用无损视频编解码器 (FFV1) Use O to confirm = 使用按钮O确认 Use output buffer (with overlay) for recording = 录制时使用输出缓冲(包括叠加信息) Use system native keyboard = 使用系统本机键盘 @@ -1218,7 +1218,7 @@ Screen representation = 屏幕表现 Details = 详细内容 Dismiss = 忽略 Download = 下载 -New version of PPSSPP available = 新版本PPSSPP可用 +New version of PPSSPP available = 新版本 PPSSPP 可用 [Search] Filtering settings by '%1' = 设置筛选'%1' @@ -1228,15 +1228,15 @@ Clear filter = 清除筛选结果 No settings matched '%1' = 未找到设置'%1' [VR] -% of native FoV = % of native FoV -6DoF movement = 6DoF movement -Distance to 2D menus and scenes = Distance to 2D menus and scenes -Field of view scale = Field of view scale -Force 72Hz update = Force 72Hz update -Heads-up display scale = Heads-up display scale -Map controller movements to keys = Map controller movements to keys -Motion needed to generate action = Motion needed to generate action -Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) -Virtual reality = Virtual reality -VR camera = VR camera -VR controllers = VR controllers +% of native FoV = % of 原生 FoV +6DoF movement = 6自由度移动 +Distance to 2D menus and scenes = 2D 菜单和场景的距离 +Field of view scale = 视野比例 +Force 72Hz update = 强制72赫兹更新 +Heads-up display scale = 平视显示比例 +Map controller movements to keys = 映射控制器移动到关键点 +Motion needed to generate action = 运动捕捉所需的行动 +Stereoscopic vision (Experimental) = 立体视觉(试验性) +Virtual reality = 虚拟现实 +VR camera = VR 摄像 +VR controllers = VR 控制器 From e6b7817cc6babc378dcb87b316ca0e958bf5fb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 15 Dec 2022 11:24:32 +0100 Subject: [PATCH 715/715] Disable pre-rotation for 270 degree transform (inverse landscape). Causes bizarre issues, see #15773 --- Common/GPU/Vulkan/VulkanContext.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 33d27b40fb..8e523d0bf2 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -1109,9 +1109,14 @@ bool VulkanContext::InitSwapchain() { std::string currentTransform = surface_transforms_to_string(surfCapabilities_.currentTransform); g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); + + uint32_t allowedRotations = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + // Hack: Don't allow 270 degrees pretransform (inverse landscape), it creates bizarre issues on some devices (see #15773). + allowedRotations &= ~VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + if (surfCapabilities_.currentTransform & (VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR | VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR)) { preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - } else if (surfCapabilities_.currentTransform & (VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR)) { + } else if (surfCapabilities_.currentTransform & allowedRotations) { // Normal, sensible rotations. Let's handle it. preTransform = surfCapabilities_.currentTransform; g_display_rot_matrix.setIdentity(); @@ -1134,12 +1139,11 @@ bool VulkanContext::InitSwapchain() { _dbg_assert_(false); } } else { - // Let the OS rotate the image (potentially slow on many Android devices) + // Let the OS rotate the image (potentially slower on many Android devices) preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } std::string preTransformStr = surface_transforms_to_string(preTransform); - INFO_LOG(G3D, "Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str()); if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) {

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 z 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 z%0A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

7(9XJ8raRxOgx~w=N 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

5^37YWIErY(dzv0D#!pj`M$V&=@ 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 ZemU#=>{A+Yzl~Z3<6XG@XDlTTyE3q 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 diff --git a/source_assets/image/trashcan.png b/source_assets/image/trashcan.png new file mode 100644 index 0000000000000000000000000000000000000000..d761236539a34ff1d35e04b438ed363e821e3d65 GIT binary patch literal 1062 zcmV+>1ljwEP)Fu$xu_XWj06I$s;@|-C2L}iD!eGVn^74B)j8+e=FSOk3 z?CdomghNEs>2%g6Cntw-4ok!U^i?XAFQSxhZf?#3xB_4RK!2AF0I*h9SC9H{Z*Tt` zisndJ0T!A%KR^F!u~__32*IV4oQRl|k`YmVE|(jPq6&hb0YHZ1l?3OEF{UVrVuWqv zy6z*!n8O$&&UwH&4-`d_i;Ih&jgOC)0R(C^*fh;c`F#FnhAdsq(C3)2d_I3QslhbO zOHm+^5a~EheQ$5?7tixlB6`g*j2lEmjIpc*oeC+X9o@Dna zsO#(N9}^MTwtWY{MF1BvT3-(vux7L*w}b~dV2ao6iBUB`+RF_>+4df^m@eY?CgBE zySw}S%F4={-F~E$K*E`lnvpn$hKAlK6biQipin5h1mJG~+Th^eH;l19&-2Ov{sN#` zmh~k7?l{hU0Dp!q7yuAaVrDXDBnX0|qHQ*t(YPbd_x-0hAw;~;qwjwve~tW?LQ?VKE{zZ(vGK**HJqnUm05_Ysz+<9XPjy{Cw)w*c)WuW-tDq|3o32a{>UvFs_e`j9gE1 za9Z>_N0NldR;%@}Uax;Egy2LJ2q6yAoJ%R&LI^jlPp8vqYMR!rR;v$?@Tlrl$sDIU g?6UrHpqL%QV-6wK>3n*Bp#T5?07*qoM6N<$f*-}^H~;_u literal 0 HcmV?d00001 diff --git a/ui_atlasscript.txt b/ui_atlasscript.txt index cbb3a2b22a..14d0cd2ac9 100644 --- a/ui_atlasscript.txt +++ b/ui_atlasscript.txt @@ -60,3 +60,4 @@ image I_SQUARE_SHAPE source_assets/image/square_shape.png copy image I_SQUARE_SHAPE_LINE source_assets/image/square_shape_line.png copy image I_FOLDER_OPEN source_assets/image/folder_open_line.png copy image I_WARNING source_assets/image/warning.png copy +image I_TRASHCAN source_assets/image/trashcan.png copy \ No newline at end of file From 5230fc7c411a278f7ef923daef40c4f53c0e305a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 12:22:59 +0100 Subject: [PATCH 362/715] Joystick input: Ignore in-deadzone events from a different device than previous events Fixes #15465 --- Common/Input/InputState.h | 1 + Core/ControlMapper.cpp | 115 ++++++++++++++++++++++-------------- Core/ControlMapper.h | 14 +++-- UI/ControlMappingScreen.cpp | 1 + UI/EmuScreen.cpp | 3 - UI/GamepadEmu.cpp | 28 ++++----- UI/GamepadEmu.h | 8 +-- 7 files changed, 99 insertions(+), 71 deletions(-) diff --git a/Common/Input/InputState.h b/Common/Input/InputState.h index faa6416e30..f5d43e209d 100644 --- a/Common/Input/InputState.h +++ b/Common/Input/InputState.h @@ -33,6 +33,7 @@ enum { DEVICE_ID_ACCELEROMETER = 30, DEVICE_ID_XR_CONTROLLER_LEFT = 40, DEVICE_ID_XR_CONTROLLER_RIGHT = 41, + DEVICE_ID_TOUCH = 42, }; //number of contiguous generic joypad IDs diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index b19c29dbda..b6d1dc3d0d 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -15,6 +15,7 @@ static float MapAxisValue(float v) { const float invDeadzone = g_Config.fAnalogInverseDeadzone; const float sensitivity = g_Config.fAnalogSensitivity; const float sign = v >= 0.0f ? 1.0f : -1.0f; + return sign * Clamp(invDeadzone + (abs(v) - deadzone) / (1.0f - deadzone) * (sensitivity - invDeadzone), 0.0f, 1.0f); } @@ -49,24 +50,48 @@ void ControlMapper::SetRawCallback(std::function setRaw setRawAnalog_ = setRawAnalog; } - -void ControlMapper::SetPSPAxis(char axis, float value, int stick) { - static float history[2][2] = {}; - +void ControlMapper::SetPSPAxis(int device, char axis, float value, int stick) { int axisId = axis == 'X' ? 0 : 1; - history[stick][axisId] = value; + float position[2]; + position[0] = history[stick][0]; + position[1] = history[stick][1]; - float x = history[stick][0]; - float y = history[stick][1]; + position[axisId] = value; + + float x = position[0]; + float y = position[1]; if (setRawAnalog_) { setRawAnalog_(stick, x, y); } - ConvertAnalogStick(x, y); + // NOTE: We need to use single-axis checks, since the other axis might be from another device, + // so we'll add a little leeway. + bool inDeadZone = fabsf(value) < g_Config.fAnalogDeadzone * 0.7f; - setPSPAnalog_(stick, x, y); + bool ignore = false; + + if (inDeadZone && lastNonDeadzoneDeviceID_[stick] != device) { + // Ignore this event! See issue #15465 + NOTICE_LOG(COMMON, "Ignoring deadzone event from device %d (%d, %f)", device, axis, value); + ignore = true; + } + + if (!inDeadZone) { + NOTICE_LOG(COMMON, "Got a non deadzone event from device %d (%d, %f > %f)", device, axis, value, g_Config.fAnalogDeadzone); + lastNonDeadzoneDeviceID_[stick] = device; + } + + if (!ignore) { + history[stick][axisId] = value; + + float x = history[stick][0]; + float y = history[stick][1]; + + ConvertAnalogStick(x, y); + setPSPAnalog_(stick, x, y); + } } bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) { @@ -79,7 +104,7 @@ bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) { } for (size_t i = 0; i < pspKeys.size(); i++) { - pspKey(pspKeys[i], key.flags); + pspKey(key.deviceId, pspKeys[i], key.flags); } DEBUG_LOG(SYSTEM, "Key: %d DeviceId: %d", key.keyCode, key.deviceId); @@ -155,7 +180,7 @@ static int RotatePSPKeyCode(int x) { } } -void ControlMapper::setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero) { +void ControlMapper::setVKeyAnalog(int deviceId, char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero) { // The down events can repeat, so just trust the virtKeys array. bool minDown = virtKeys[virtualKeyMin - VIRTKEY_FIRST]; bool maxDown = virtKeys[virtualKeyMax - VIRTKEY_FIRST]; @@ -167,11 +192,11 @@ void ControlMapper::setVKeyAnalog(char axis, int stick, int virtualKeyMin, int v if (maxDown) value += scale; if (setZero || minDown || maxDown) { - SetPSPAxis(axis, value, stick); + SetPSPAxis(deviceId, axis, value, stick); } } -void ControlMapper::pspKey(int pspKeyCode, int flags) { +void ControlMapper::pspKey(int deviceId, int pspKeyCode, int flags) { int rotations = 0; switch (g_Config.iInternalScreenRotation) { case ROTATION_LOCKED_HORIZONTAL180: @@ -193,11 +218,11 @@ void ControlMapper::pspKey(int pspKeyCode, int flags) { int vk = pspKeyCode - VIRTKEY_FIRST; if (flags & KEY_DOWN) { virtKeys[vk] = true; - onVKeyDown(pspKeyCode); + onVKeyDown(deviceId, pspKeyCode); } if (flags & KEY_UP) { virtKeys[vk] = false; - onVKeyUp(pspKeyCode); + onVKeyUp(deviceId, pspKeyCode); } } else { // INFO_LOG(SYSTEM, "pspKey %i %i", pspKeyCode, flags); @@ -208,32 +233,32 @@ void ControlMapper::pspKey(int pspKeyCode, int flags) { } } -void ControlMapper::onVKeyDown(int vkey) { +void ControlMapper::onVKeyDown(int deviceId, int vkey) { switch (vkey) { case VIRTKEY_AXIS_X_MIN: case VIRTKEY_AXIS_X_MAX: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); break; case VIRTKEY_AXIS_Y_MIN: case VIRTKEY_AXIS_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); break; case VIRTKEY_AXIS_RIGHT_X_MIN: case VIRTKEY_AXIS_RIGHT_X_MAX: - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); break; case VIRTKEY_AXIS_RIGHT_Y_MIN: case VIRTKEY_AXIS_RIGHT_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); break; case VIRTKEY_ANALOG_LIGHTLY: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); break; case VIRTKEY_ANALOG_ROTATE_CW: @@ -252,32 +277,32 @@ void ControlMapper::onVKeyDown(int vkey) { } } -void ControlMapper::onVKeyUp(int vkey) { +void ControlMapper::onVKeyUp(int deviceId, int vkey) { switch (vkey) { case VIRTKEY_AXIS_X_MIN: case VIRTKEY_AXIS_X_MAX: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); break; case VIRTKEY_AXIS_Y_MIN: case VIRTKEY_AXIS_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); break; case VIRTKEY_AXIS_RIGHT_X_MIN: case VIRTKEY_AXIS_RIGHT_X_MAX: - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); break; case VIRTKEY_AXIS_RIGHT_Y_MIN: case VIRTKEY_AXIS_RIGHT_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); break; case VIRTKEY_ANALOG_LIGHTLY: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); break; case VIRTKEY_ANALOG_ROTATE_CW: @@ -312,29 +337,29 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { float value = fabs(axis.value) * scale; switch (result) { case VIRTKEY_AXIS_X_MIN: - SetPSPAxis('X', -value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_X_MAX: - SetPSPAxis('X', value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_Y_MIN: - SetPSPAxis('Y', -value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_Y_MAX: - SetPSPAxis('Y', value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_RIGHT_X_MIN: - SetPSPAxis('X', -value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_RIGHT); break; case VIRTKEY_AXIS_RIGHT_X_MAX: - SetPSPAxis('X', value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_RIGHT); break; case VIRTKEY_AXIS_RIGHT_Y_MIN: - SetPSPAxis('Y', -value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_RIGHT); break; case VIRTKEY_AXIS_RIGHT_Y_MAX: - SetPSPAxis('Y', value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_RIGHT); break; case VIRTKEY_SPEED_ANALOG: @@ -366,22 +391,22 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { if (axisState != 0) { for (size_t i = 0; i < results.size(); i++) { if (!IsAnalogStickKey(results[i])) - pspKey(results[i], KEY_DOWN); + pspKey(axis.deviceId, results[i], KEY_DOWN); } // Also unpress the other direction (unless both directions press the same key.) for (size_t i = 0; i < resultsOpposite.size(); i++) { if (!IsAnalogStickKey(resultsOpposite[i]) && std::find(results.begin(), results.end(), resultsOpposite[i]) == results.end()) - pspKey(resultsOpposite[i], KEY_UP); + pspKey(axis.deviceId, resultsOpposite[i], KEY_UP); } } else if (axisState == 0) { // Release both directions, trying to deal with some erratic controllers that can cause it to stick. for (size_t i = 0; i < results.size(); i++) { if (!IsAnalogStickKey(results[i])) - pspKey(results[i], KEY_UP); + pspKey(axis.deviceId, results[i], KEY_UP); } for (size_t i = 0; i < resultsOpposite.size(); i++) { if (!IsAnalogStickKey(resultsOpposite[i])) - pspKey(resultsOpposite[i], KEY_UP); + pspKey(axis.deviceId, resultsOpposite[i], KEY_UP); } } } diff --git a/Core/ControlMapper.h b/Core/ControlMapper.h index d930c56f8b..f837bc73c0 100644 --- a/Core/ControlMapper.h +++ b/Core/ControlMapper.h @@ -16,7 +16,7 @@ public: void Update(); bool Key(const KeyInput &key, bool *pauseTrigger); - void pspKey(int pspKeyCode, int flags); + void pspKey(int deviceId, int pspKeyCode, int flags); bool Axis(const AxisInput &axis); // Required callbacks @@ -30,13 +30,13 @@ public: private: void processAxis(const AxisInput &axis, int direction); - void setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true); + void setVKeyAnalog(int deviceId, char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true); - void SetPSPAxis(char axis, float value, int stick); + void SetPSPAxis(int deviceId, char axis, float value, int stick); void ProcessAnalogSpeed(const AxisInput &axis, bool opposite); - void onVKeyDown(int vkey); - void onVKeyUp(int vkey); + void onVKeyDown(int deviceId, int vkey); + void onVKeyUp(int deviceId, int vkey); // To track mappable virtual keys. We can have as many as we want. bool virtKeys[VIRTKEY_COUNT]{}; @@ -44,6 +44,10 @@ private: // De-noise mapped axis updates int axisState_[JOYSTICK_AXIS_MAX]{}; + int lastNonDeadzoneDeviceID_[2]{}; + + float history[2][2] = {}; + // Mappable auto-rotation. Useful for keyboard/dpad->analog in a few games. bool autoRotatingAnalogCW_ = false; bool autoRotatingAnalogCCW_ = false; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 1461220625..d68ae2baba 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -583,6 +583,7 @@ void JoystickHistoryView::Update() { AnalogSetupScreen::AnalogSetupScreen() { mapper_.SetCallbacks([](int vkey) {}, [](int vkey) {}, [&](int stick, float x, float y) { + NOTICE_LOG(COMMON, "analog value from mapper: %f %f", x, y); analogX_[stick] = x; analogY_[stick] = y; }); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index a0b898663c..a52ba14fd8 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -136,8 +136,6 @@ static void __EmuScreenVblank() } // Handles control rotation due to internal screen rotation. -// TODO: This should be a callback too, so we don't actually call the __Ctrl functions -// from settings screens, etc. static void SetPSPAnalog(int stick, float x, float y) { switch (g_Config.iInternalScreenRotation) { case ROTATION_LOCKED_HORIZONTAL: @@ -164,7 +162,6 @@ static void SetPSPAnalog(int stick, float x, float y) { default: break; } - __CtrlSetAnalogXY(stick, x, y); } diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index 809f2cf31f..bb1eb01f3b 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -205,7 +205,7 @@ void ComboKey::Touch(const TouchInput &input) { if (!repeat_) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, (on_ && toggle_) ? KEY_UP : KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, (on_ && toggle_) ? KEY_UP : KEY_DOWN); } } } @@ -214,7 +214,7 @@ void ComboKey::Touch(const TouchInput &input) { if (!repeat_) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, KEY_UP); } } } @@ -235,13 +235,13 @@ void ComboKey::Update() { } else if (pressedFrames_ == DOWN_FRAME) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, KEY_UP); } } } else if (on_ && pressedFrames_ == 0) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, KEY_DOWN); } } pressedFrames_ = 1; @@ -912,7 +912,7 @@ void GestureGamepad::Touch(const TouchInput &input) { const float now = time_now_d(); if (now - lastTapRelease_ < 0.3f && !haveDoubleTapped_) { if (g_Config.iDoubleTapGesture != 0 ) - controllMapper_->pspKey(GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_DOWN); haveDoubleTapped_ = true; } @@ -935,7 +935,7 @@ void GestureGamepad::Touch(const TouchInput &input) { if (haveDoubleTapped_) { if (g_Config.iDoubleTapGesture != 0) - controllMapper_->pspKey(GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_UP); haveDoubleTapped_ = false; } } @@ -948,37 +948,37 @@ void GestureGamepad::Update() { float dy = deltaY_ * g_dpi_scale_y * g_Config.fSwipeSensitivity; if (g_Config.iSwipeRight != 0) { if (dx > th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeRight-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_DOWN); swipeRightReleased_ = false; } else if (!swipeRightReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeRight-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_UP); swipeRightReleased_ = true; } } if (g_Config.iSwipeLeft != 0) { if (dx < -th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_DOWN); swipeLeftReleased_ = false; } else if (!swipeLeftReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_UP); swipeLeftReleased_ = true; } } if (g_Config.iSwipeUp != 0) { if (dy < -th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeUp-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeUp-1], KEY_DOWN); swipeUpReleased_ = false; } else if (!swipeUpReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeUp-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeUp-1], KEY_UP); swipeUpReleased_ = true; } } if (g_Config.iSwipeDown != 0) { if (dy > th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeDown-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeDown-1], KEY_DOWN); swipeDownReleased_ = false; } else if (!swipeDownReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeDown-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeDown-1], KEY_UP); swipeDownReleased_ = true; } } diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index 978425cd4d..bb8da30ea7 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -170,7 +170,7 @@ const int baseActionButtonSpacing = 60; class ComboKey : public MultiTouchButton { public: ComboKey(uint64_t pspButtonBit, const char *key, bool toggle, bool repeat, ControlMapper* controllMapper, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, bool invertedContextDimension, UI::LayoutParams *layoutParams) - : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit), toggle_(toggle), repeat_(repeat), controllMapper_(controllMapper), on_(false), invertedContextDimension_(invertedContextDimension) { + : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit), toggle_(toggle), repeat_(repeat), controlMapper_(controllMapper), on_(false), invertedContextDimension_(invertedContextDimension) { } void Touch(const TouchInput &input) override; void Update() override; @@ -182,14 +182,14 @@ private: bool toggle_; bool repeat_; int pressedFrames_ = 0; - ControlMapper* controllMapper_; + ControlMapper* controlMapper_; bool on_; bool invertedContextDimension_; // Swap width and height }; class GestureGamepad : public UI::View { public: - GestureGamepad(ControlMapper* controllMapper) : controllMapper_(controllMapper) {}; + GestureGamepad(ControlMapper* controllMapper) : controlMapper_(controllMapper) {}; void Touch(const TouchInput &input) override; void Update() override; @@ -208,7 +208,7 @@ protected: bool swipeUpReleased_ = true; bool swipeDownReleased_ = true; bool haveDoubleTapped_ = false; - ControlMapper* controllMapper_; + ControlMapper* controlMapper_; }; // Just edit this to add new image, shape or button function From 287da42d5e6e634431091df84627dd1ea71abd75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 12:42:44 +0100 Subject: [PATCH 363/715] Add GAS/BRAKE keymappings to Xinput default maps. Fixes #15992 --- Core/KeyMapDefaults.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/KeyMapDefaults.cpp b/Core/KeyMapDefaults.cpp index d6d21639cb..8fc2c19a42 100644 --- a/Core/KeyMapDefaults.cpp +++ b/Core/KeyMapDefaults.cpp @@ -128,6 +128,8 @@ static const DefMappingStruct defaultXInputKeyMap[] = { {VIRTKEY_SPEED_TOGGLE, NKCODE_BUTTON_THUMBR}, {VIRTKEY_PAUSE , JOYSTICK_AXIS_LTRIGGER, +1}, {VIRTKEY_PAUSE, NKCODE_HOME}, + {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_GAS, +1}, + {VIRTKEY_PAUSE , JOYSTICK_AXIS_BRAKE, +1}, }; static const DefMappingStruct defaultShieldKeyMap[] = { @@ -188,6 +190,8 @@ static const DefMappingStruct defaultAndroidXboxControllerMap[] = { {CTRL_RTRIGGER , NKCODE_BUTTON_R1}, {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_RTRIGGER, +1}, {VIRTKEY_PAUSE , JOYSTICK_AXIS_LTRIGGER, +1}, + {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_GAS, +1}, + {VIRTKEY_PAUSE , JOYSTICK_AXIS_BRAKE, +1}, {VIRTKEY_AXIS_X_MIN, JOYSTICK_AXIS_X, -1}, {VIRTKEY_AXIS_X_MAX, JOYSTICK_AXIS_X, +1}, {VIRTKEY_AXIS_Y_MIN, JOYSTICK_AXIS_Y, +1}, @@ -242,6 +246,8 @@ static const DefMappingStruct defaultPadMapAndroid[] = { {VIRTKEY_FASTFORWARD , NKCODE_BUTTON_R2}, {VIRTKEY_PAUSE , JOYSTICK_AXIS_LTRIGGER, +1}, {VIRTKEY_PAUSE , NKCODE_BUTTON_L2 }, + {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_GAS, +1}, + {VIRTKEY_PAUSE , JOYSTICK_AXIS_BRAKE, +1}, {VIRTKEY_AXIS_X_MIN, JOYSTICK_AXIS_X, -1}, {VIRTKEY_AXIS_X_MAX, JOYSTICK_AXIS_X, +1}, {VIRTKEY_AXIS_Y_MIN, JOYSTICK_AXIS_Y, +1}, From 0319824a0e8bd412ad8e4d0c5eff4c9d36115d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 15:09:06 +0100 Subject: [PATCH 364/715] Forgot to commit the svg --- source_assets/image/buttons.svg | 111 ++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 11 deletions(-) diff --git a/source_assets/image/buttons.svg b/source_assets/image/buttons.svg index edcca85473..d9ad2b43e5 100644 --- a/source_assets/image/buttons.svg +++ b/source_assets/image/buttons.svg @@ -1795,7 +1795,7 @@ inkscape:label="Drop Shadow"> + x="-5.226912" + y="-5.6735277" /> + + + + + + + + + + + + + From 7eee7f2573d628dbd3ebcbe5fe29d2da4227fdc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 10 Nov 2022 12:14:06 +0100 Subject: [PATCH 365/715] Fix shader debug description issue. --- GPU/Common/ShaderId.cpp | 2 +- GPU/Common/VertexShaderGenerator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 0f034c7709..705ce77cb9 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -256,7 +256,7 @@ std::string FragmentShaderDesc(const FShaderID &id) { else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc << "TestDiscardToZero "; if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc << "StencilDiscardWorkaround "; - if (id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) desc << "ReplaceLogic "; + if ((id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc << "ReplaceLogic "; if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc << "TexArray "; if (id.Bit(FS_BIT_STEREO)) desc << "Stereo "; return desc.str(); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 7e9d2cadb8..f5e01fbc36 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -300,8 +300,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } WRITE(p, "layout (location = 3) out highp float v_fogdepth;\n"); - WRITE(p, "invariant gl_Position;\n"); + WRITE(p, "invariant gl_Position;\n"); } else if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) { // Note: These two share some code after this hellishly large if/else. if (compat.shaderLanguage == HLSL_D3D11) { From 4c29f54b71b1a313d7af8707f4b26397b3f3dca1 Mon Sep 17 00:00:00 2001 From: Benjamin Benda Gates Date: Wed, 23 Nov 2022 21:53:54 +0700 Subject: [PATCH 366/715] Update th_TH.ini --- assets/lang/th_TH.ini | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 2f48108dd7..20a42b064d 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -184,7 +184,7 @@ Pause = หยุดชั่วคราว Pause When Not Focused = หยุดชั่วคราวเมื่อไม่ได้เล่น Portrait = แนวตั้ง Portrait reversed = แนวตั้งกลับด้าน -Postprocessing Shader = กระบวนการทำงานไล่ปรับเฉดแสงสี +Postprocessing Shader = กระบวนการทำงานปรับเฉดแสงสี PPSSPP Forums = เว็บ PPSSPP Forums Record = การอัดบันทึก Record Audio = อัดบันทึกเสียง @@ -263,12 +263,12 @@ Resume = เล่นต่อ Run CPU Tests = เรียกใช้การทดสอบซีพียู Save language ini = บันทึกไฟล์ภาษา (.ini) Save new textures = บันทึกพื้นผิวลงในแหล่งที่เก็บข้อมูล -Shader Viewer = มุมมองการปรับไล่เฉดแสงสี +Shader Viewer = มุมมองการปรับเฉดแสงสี Show Developer Menu = แสดงเมนูสำหรับนักพัฒนา Show on-screen messages = แสดงข้อความการแจ้งเตือนต่างๆ Stats = สถิติ System Information = ข้อมูลโดยรวมของระบบ -Texture ini file created = Texture ini file created +Texture ini file created = ไฟล์ Texture.ini ได้ถูกสร้างแล้ว Texture Replacement = การแทนที่พื้นผิว Toggle Audio Debug = แก้ไขจุดบกพร่องของเสียง Toggle Freeze = ปุ่มแช่แข็ง @@ -496,8 +496,9 @@ Frame Rate Control = การควบคุมเฟรมเรท Frame Skipping = ข้ามเฟรม Frame Skipping Type = รูปแบบการข้ามเฟรม FullScreen = เต็มหน้าจอ +Geometry shader culling = การคัดแยกเฉดสีเชิงเรขาคณิต GPU log profiler = ตัวแสดงค่าโปรไฟล์ GPU -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +GPUReadbackRequired = คำเตือน: เกมนี้จำเป็นต้องติ๊กตั้งค่า "ข้ามการอ่านข้อมูลส่งกลับไปยัง GPU" ออกด้วย Hack Settings = ตั้งค่าการปรับแฮ็ค (อาจแสดงผลผิดพลาด) Hardware Tessellation = ฮาร์ดแวร์ เทสเซลเลชั่น Hardware Transform = ใช้ฮาร์ดแวร์ในการแปลงค่าประมวลผล @@ -531,8 +532,8 @@ Overlay Information = การแสดงข้อมูลซ้อนทั Partial Stretch = แนวตั้งดึงเต็มจอ Percent of FPS = อิงจากเปอร์เซ็นต์เฟรมต่อวิ Performance = ประสิทธิภาพ -Postprocessing effect = กระบวนการทำงานไล่ปรับเอฟเฟ็คท์ -Postprocessing Shader = กระบวนการทำงานไล่ปรับเฉดแสงสี +Postprocessing effect = กระบวนการทำงานปรับเอฟเฟ็คท์ +Postprocessing Shader = กระบวนการทำงานปรับเฉดแสงสี Recreate Activity = สร้างกิจกรรมใหม่ Render duplicate frames to 60hz = แสดงผลเฟรมซ้ำให้ถึง 60 เฮิร์ตซ RenderDuplicateFrames Tip = ช่วยให้ภาพดูลื่นตาขึ้น ในเกมที่ใช้เฟรมเรทต่ำ @@ -545,12 +546,14 @@ Screen layout = เค้าโครงหน้าจอ Screen Scaling Filter = ตัวกรองปรับสเกลหน้าจอ Show Debug Statistics = แสดงค่าทางสถิติการแก้ไขจุดบกพร่อง Show FPS Counter = แสดงค่าเฟรมเรท และความเร็ว/วินาที -Skip GPU Readbacks = Skip GPU Readbacks -Software Rendering = ใช้ซอฟต์แวร์ในการแสดงผล (ช้า) +Skip GPU Readbacks = ข้ามการอ่านข้อมูลส่งกลับไปยัง GPU +Software Rendering = ใช้ซอฟต์แวร์ในการแสดงผล (ช้า แต่แม่นยำ) Software Skinning = ซอฟต์แวร์ สกินนิ่ง SoftwareSkinning Tip = ผสานโมเดลพื้นผิวให้เขียนผ่านซีพียู ซึ่งเกมส่วนใหญ่ปรับใช้แล้วไวขึ้น Speed = ความเร็ว -Speed Hacks = Speed Hacks (อาจแสดงผลผิดพลาด) +Speed Hacks = แฮ็คความเร็ว (อาจแสดงผลผิดพลาด) +Stereo display shader = เฉดแสงสีของภาพแบบสามมิติ +Stereo rendering = การแสดงผลแบบสามมิติ Stretching = ดึงเต็มจอ Texture Filter = ตัวกรองพื้นผิว Texture Filtering = การกรองพื้นผิว @@ -836,11 +839,13 @@ Brightness = แสงสว่าง Cartoon = ภาพออกแนวการ์ตูน CatmullRom = ภาพอัพสเกลแบบไบคิวบิค (แคทมิว-รอม) ColorCorrection = ภาพสีสมจริง +ColorPreservation = การเก็บรักษาสีเดิม Contrast = ความคมชัด CRT = ภาพออกโทนเหลืองขึ้นเส้น FXAA = ภาพเน้นลบขอบรอยหยัก Gamma = แกมม่า Grayscale = ภาพโทนสีเทา +GreenLevel = ระดับสีเขียว Intensity = ความเข้มของแสง InverseColors = ภาพสีกลับ MitchellNetravali = ภาพอัพสเกลแบบไบคิวบิค (มิทเชลล์-เนทราวาลิ) @@ -849,9 +854,11 @@ NaturalA = ภาพเน้นสีธรรมชาติ (ไม่เบ Off = ปิด Power = ความเข้ม PSPColor = ภาพสีแบบเครื่อง PSP +RedBlue = ภาพแว่นแดงฟ้า (สามมิติแบบซ้อนเหลื่อม) Saturation = ความอิ่มตัวของสี Scanlines = ภาพออกมัวเป็นเส้นแนวนอน Sharpen = ภาพเน้นขอบคมขึ้น +SideBySize = ภาพแยกสองจอแบบสามมิติ SSAA(Gauss) = ภาพเน้นความละเอียดให้สูงขึ้น Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1044,7 +1051,7 @@ Device Info = ข้อมูลอุปกรณ์ Directories = เส้นทางเก็บข้อมูล Display Color Formats = รูปแบบสีของหน้าจอแสดงผล Display Information = ข้อมูลของหน้าจอแสดงผล -Driver bugs = Driver bugs +Driver bugs = ไดรเวอร์บั๊ก Driver Version = เวอร์ชั่นของไดรเวอร์ EGL Extensions = ส่วนขยายอีจีแอล Frames per buffer = จำนวนเฟรมต่อบัฟเฟอร์ @@ -1054,7 +1061,7 @@ High precision int range = ขอบเขตจำนวนเต็มช่ Lang/Region = ภาษา/ภูมิภาค Memory Page Size = ขนาดหน้าของหน่วยความจำ Native Resolution = ความละเอียดดั้งเดิม -No GPU driver bugs detected = No GPU driver bugs detected +No GPU driver bugs detected = ไม่พบไดรเวอร์บั๊กใน GPU รุ่นนี้ OGL Extensions = ส่วนขยายโอจีแอล OpenGL ES 2.0 Extensions = ส่วนขยายของโอเพ่นจีแอล อีเอส 2.0 OpenGL ES 3.0 Extensions = ส่วนขยายของโอเพ่นจีแอล อีเอส 3.0 @@ -1122,6 +1129,7 @@ Fast Memory = หน่วยความจำทำงานได้เร็ Floating symbols = สัญลักษณ์ปุ่มจอยลอยไปมา Force real clock sync (slower, less lag) = บังคับการซิงค์สัญญาณความถี่ (ช้ากว่า, เเล็กน้อยลง) frames, 0:off = เฟรม, 0 = ปิด +Game crashed = เกมเด้งจ้า Games list settings = การตั้งค่าในรายการเกม General = ทั่วไป Grid icon size = ขนาดของไอคอนเกม @@ -1217,3 +1225,16 @@ Details = รายละเอียด Dismiss = ยกเลิก Download = ดาวน์โหลด New version of PPSSPP available = PPSSPP เวอร์ชั่นใหม่พร้อมให้ดาวน์โหลดแล้ว! + +[VR] +% of native FoV = % ของค่า FoV ดั้งเดิม +6DoF movement = การเคลื่อนไหวแบบ 6DoF +Distance to 2D menus and scenes = ระยะห่างจากเมนูสองมิติ และฉาก +Field of view scale = สเกลของมุมมองพื้นที่รอบตัว +Force 72Hz update = บังคับการอัพเดทรีเฟรชเรทที่ 72Hz +Map controller movements to keys = เซ็ตปุ่มควบคุมด้วยท่าทางผ่านจอย +Motion needed to generate action = จำเป็นต้องขยับท่าทางเพื่อเซ็ตปุ่มที่ต้องการ +Stereoscopic vision (Experimental) = มุมมองภาพแบบสามมิติ (ขั้นทดสอบ) +Virtual reality = ความเป็นจริงเสมือน +VR camera = กล้อง VR +VR controllers = จอยควบคุม VR From f6fcc9e9a714cc565eb2bc39847d4b91a23dcafa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 10 Nov 2022 21:05:08 +0100 Subject: [PATCH 367/715] Add a way to view the "GPU_USE_" flags at runtime. Useful for sanity checking on-device. --- Common/GPU/DataFormat.h | 3 +++ Common/GPU/OpenGL/thin3d_gl.cpp | 1 - Common/GPU/thin3d.cpp | 21 ++++++++++++++++ GPU/GLES/GPU_GLES.cpp | 3 +++ GPU/GPUState.cpp | 43 +++++++++++++++++++++++++++++++++ GPU/GPUState.h | 4 +++ UI/DevScreens.cpp | 14 +++++++++++ 7 files changed, 88 insertions(+), 1 deletion(-) diff --git a/Common/GPU/DataFormat.h b/Common/GPU/DataFormat.h index 0c8a93e627..b116ac9ab1 100644 --- a/Common/GPU/DataFormat.h +++ b/Common/GPU/DataFormat.h @@ -76,6 +76,9 @@ inline bool DataFormatIsColor(DataFormat fmt) { return !DataFormatIsDepthStencil(fmt); } +// Limited format support for now. +const char *DataFormatToString(DataFormat fmt); + void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format); void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format); void ConvertToD32F(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format); diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index f004cbdc08..9878886fd0 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -525,7 +525,6 @@ static bool HasIntelDualSrcBug(int versions[4]) { } OpenGLContext::OpenGLContext() { - // TODO: Detect more caps if (gl_extensions.IsGLES) { if (gl_extensions.OES_packed_depth_stencil || gl_extensions.OES_depth24) { caps_.preferredDepthBufferFormat = DataFormat::D24_S8; diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index 3aad02abc6..fab4e665d1 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -56,6 +56,27 @@ size_t DataFormatSizeInBytes(DataFormat fmt) { } } +const char *DataFormatToString(DataFormat fmt) { + switch (fmt) { + case DataFormat::R8_UNORM: return "R8_UNORM"; + case DataFormat::R8G8_UNORM: return "R8G8_UNORM"; + case DataFormat::R8G8B8A8_UNORM: return "R8G8B8A8_UNORM"; + case DataFormat::B8G8R8A8_UNORM: return "B8G8R8A8_UNORM"; + case DataFormat::R16_UNORM: return "R16_UNORM"; + case DataFormat::R16_FLOAT: return "R16_FLOAT"; + case DataFormat::R32_FLOAT: return "R32_FLOAT"; + + case DataFormat::S8: return "S8"; + case DataFormat::D16: return "D16"; + case DataFormat::D24_S8: return "D24_S8"; + case DataFormat::D32F: return "D32F"; + case DataFormat::D32F_S8: return "D32F_S8"; + + default: + return "(N/A)"; + } +} + bool DataFormatIsDepthStencil(DataFormat fmt) { switch (fmt) { case DataFormat::D16: diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index cec35c21d7..a43cdd2467 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -144,6 +144,9 @@ GPU_GLES::~GPU_GLES() { shaderManagerGL_ = nullptr; delete framebufferManagerGL_; delete textureCacheGL_; + + // Clear features so they're not visible in system info. + gstate_c.useFlags = 0; } // Take the raw GL extension and versioning data and turn into feature flags. diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index bae93b34b1..95568e1e93 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -367,3 +367,46 @@ void GPUStateCache::DoState(PointerWrap &p) { Do(p, savedContextVersion); } } + +static const char *const gpuUseFlagNames[32] = { + "GPU_USE_DUALSOURCE_BLEND", + "GPU_USE_LIGHT_UBERSHADER", + "GPU_USE_FRAGMENT_TEST_CACHE", + "GPU_USE_VS_RANGE_CULLING", + "GPU_USE_BLEND_MINMAX", + "GPU_USE_LOGIC_OP", + "GPU_USE_DEPTH_RANGE_HACK", + "GPU_USE_TEXTURE_NPOT", + "GPU_USE_ANISOTROPY", + "GPU_USE_CLEAR_RAM_HACK", + "GPU_USE_INSTANCE_RENDERING", + "GPU_USE_VERTEX_TEXTURE_FETCH", + "GPU_USE_TEXTURE_FLOAT", + "GPU_USE_16BIT_FORMATS", + "GPU_USE_DEPTH_CLAMP", + "GPU_USE_TEXTURE_LOD_CONTROL", + "GPU_USE_DEPTH_TEXTURE", + "GPU_USE_ACCURATE_DEPTH", + "GPU_USE_GS_CULLING", + "GPU_USE_REVERSE_COLOR_ORDER", + "GPU_USE_FRAMEBUFFER_FETCH", + "GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT", + "GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT", + "GPU_ROUND_DEPTH_TO_16BIT", + "GPU_USE_CLIP_DISTANCE", + "GPU_USE_CULL_DISTANCE", + "N/A", // bit 26 + "N/A", // bit 27 + "N/A", // bit 28 + "GPU_USE_VIRTUAL_REALITY", + "GPU_USE_SINGLE_PASS_STEREO", + "GPU_USE_SIMPLE_STEREO_PERSPECTIVE", +}; + +const char *GpuUseFlagToString(int useFlag) { + if ((u32)useFlag < 32) { + return gpuUseFlagNames[useFlag]; + } else { + return "N/A"; + } +} \ No newline at end of file diff --git a/GPU/GPUState.h b/GPU/GPUState.h index d7b25ac911..02fba9c309 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -470,6 +470,7 @@ struct UVScale { // location. Sometimes we need to take things into account in multiple places, it helps // to centralize into flags like this. They're also fast to check since the cache line // will be hot. +// NOTE: Do not forget to update the string array at the end of GPUState.cpp! enum { GPU_USE_DUALSOURCE_BLEND = FLAG_BIT(0), GPU_USE_LIGHT_UBERSHADER = FLAG_BIT(1), @@ -504,6 +505,9 @@ enum { GPU_USE_SIMPLE_STEREO_PERSPECTIVE = FLAG_BIT(31), }; +// Note that this take a flag index, not the bit value. +const char *GpuUseFlagToString(int useFlag); + struct KnownVertexBounds { u16 minU; u16 minV; diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 9d219eb1c8..9e6830e682 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -553,6 +553,7 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem(si->T("High precision float range"), temp)); } } + deviceSpecs->Add(new InfoItem(si->T("Depth buffer format"), DataFormatToString(draw->GetDeviceCaps().preferredDepthBufferFormat))); deviceSpecs->Add(new ItemHeader(si->T("OS Information"))); deviceSpecs->Add(new InfoItem(si->T("Memory Page Size"), StringFromFormat(si->T("%d bytes"), GetMemoryProtectPageSize()))); deviceSpecs->Add(new InfoItem(si->T("RW/RX exclusive"), PlatformIsWXExclusive() ? di->T("Active") : di->T("Inactive"))); @@ -617,6 +618,19 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem("Moga", moga)); #endif + if (gstate_c.useFlags != 0) { + // We're in-game, and can determine these. + // TODO: Call a static version of GPUCommon::CheckGPUFeatures() and derive them here directly. + + deviceSpecs->Add(new ItemHeader(si->T("GPU Flags"))); + + for (int i = 0; i < 32; i++) { + if (gstate_c.Use((1 << i))) { + deviceSpecs->Add(new TextView(GpuUseFlagToString(i), new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); + } + } + } + ViewGroup *storageScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); storageScroll->SetTag("DevSystemInfoBuildConfig"); LinearLayout *storage = new LinearLayout(ORIENT_VERTICAL); From 976597fa3ab3dc69dbcd3a3bb2e6a995c087cf9a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 23 Nov 2022 17:56:34 -0800 Subject: [PATCH 368/715] iOS: Allow using interpreter. --- Core/Config.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 4b75a46c54..35a05ba910 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1467,7 +1467,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { // Override ppsspp.ini JIT value to prevent crashing if (DefaultCpuCore() != (int)CPUCore::JIT && g_Config.iCpuCore == (int)CPUCore::JIT) { jitForcedOff = true; - g_Config.iCpuCore = (int)CPUCore::INTERPRETER; + g_Config.iCpuCore = (int)CPUCore::IR_JIT; } // Automatically silence secondary instances. Could be an option I guess, but meh. @@ -1589,11 +1589,8 @@ bool Config::Save(const char *saveReason) { } if (jitForcedOff) { // force JIT off again just in case Config::Save() is called without exiting PPSSPP -#if PPSSPP_PLATFORM(IOS) - g_Config.iCpuCore = (int)CPUCore::IR_JIT; -#else - g_Config.iCpuCore = (int)CPUCore::INTERPRETER; -#endif + if (g_Config.iCpuCore != (int)CPUCore::INTERPRETER) + g_Config.iCpuCore = (int)CPUCore::IR_JIT; } return true; } From 39f2ddd128a4ad83585c588c2bc59e0d4ee75fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 17:32:32 +0100 Subject: [PATCH 369/715] Add compat flag / bug check for games on old Adreno/GL affected by #16015 See #16015 Partly derived from https://github.com/hrydgard/ppsspp/compare/master...unknownbrackets:ppsspp:adreno-deadlock But this one surgically activates it only for the known affected games, to avoid any additional performance regressions in the release. Entirely untested. --- Common/GPU/OpenGL/thin3d_gl.cpp | 5 ++++ Common/GPU/thin3d.cpp | 2 ++ Common/GPU/thin3d.h | 1 + Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + GPU/GLES/GPU_GLES.cpp | 6 +++++ assets/compat.ini | 44 ++++++++++++++++++++++++++++++++- 7 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 9878886fd0..18da422ca2 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -645,6 +645,11 @@ OpenGLContext::OpenGLContext() { bugs_.Infest(Bugs::PVR_GENMIPMAP_HEIGHT_GREATER); } + if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { + if (gl_extensions.modelNumber < 600) + bugs_.Infest(Bugs::ADRENO_RESOURCE_DEADLOCK); + } + #if PPSSPP_PLATFORM(IOS) // For some reason, this bug does not appear on M1. if (caps_.vendor == GPUVendor::VENDOR_APPLE) { diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index fab4e665d1..2713aef555 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -733,6 +733,8 @@ const char *Bugs::GetBugName(uint32_t bug) { case RASPBERRY_SHADER_COMP_HANG: return "RASPBERRY_SHADER_COMP_HANG"; case MALI_CONSTANT_LOAD_BUG: return "MALI_CONSTANT_LOAD_BUG"; case SUBPASS_FEEDBACK_BROKEN: return "SUBPASS_FEEDBACK_BROKEN"; + case GEOMETRY_SHADERS_SLOW_OR_BROKEN: return "GEOMETRY_SHADERS_SLOW_OR_BROKEN"; + case ADRENO_RESOURCE_DEADLOCK: return "ADRENO_RESOURCE_DEADLOCK"; default: return "(N/A)"; } } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 53d35250ce..0f1a8b86bb 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -339,6 +339,7 @@ public: MALI_CONSTANT_LOAD_BUG = 9, SUBPASS_FEEDBACK_BROKEN = 10, GEOMETRY_SHADERS_SLOW_OR_BROKEN = 11, + ADRENO_RESOURCE_DEADLOCK = 12, MAX_BUG, }; diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index d3d65861e0..6541cc53b3 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -120,6 +120,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "NearestFilteringOnFramebufferCreate", &flags_.NearestFilteringOnFramebufferCreate); CheckSetting(iniFile, gameID, "SecondaryTextureCache", &flags_.SecondaryTextureCache); CheckSetting(iniFile, gameID, "EnglishOrJapaneseOnly", &flags_.EnglishOrJapaneseOnly); + CheckSetting(iniFile, gameID, "OldAdrenoPixelDepthRoundingGL", &flags_.OldAdrenoPixelDepthRoundingGL); } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 6755afe7a9..aee9f2c41b 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -91,6 +91,7 @@ struct CompatFlags { bool NearestFilteringOnFramebufferCreate; bool SecondaryTextureCache; bool EnglishOrJapaneseOnly; + bool OldAdrenoPixelDepthRoundingGL; }; struct VRCompat { diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index a43cdd2467..50f80b6247 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -189,6 +189,12 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_USE_SINGLE_PASS_STEREO; } + if (draw_->GetBugs().Has(Draw::Bugs::ADRENO_RESOURCE_DEADLOCK)) { + if (PSP_CoreParameter().compat.flags().OldAdrenoPixelDepthRoundingGL) { + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } + } + features = CheckGPUFeaturesLate(features); // This is a bit ugly, but lets us reuse most of the depth logic in GPUCommon. diff --git a/assets/compat.ini b/assets/compat.ini index 425164cf58..34f3369c2e 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1269,4 +1269,46 @@ NPJH50408 = true # Twinbee Portable, see issue #16382 ULAS42089 = true ULJM05221 = true -ULJM05323 = true \ No newline at end of file +ULJM05323 = true + +[OldAdrenoPixelDepthRoundingGL] +# See #16015 + +# Naruto Shippuden: Ultimate Ninja Impact +ULUS10582 = true +ULES01537 = true +ULJS00390 = true +ULAS42297 = true +ULJS19071 = true +NPJH50435 = true +NPJH50435 = true + +# Kingdom Hearts - Birth By Sleep +ULES01441 = true +ULJM05600 = true +ULUS10505 = true +ULJM05775 = true # Final MIX +PSPJ30012 = true +UCAS40295 = true +UCKS45143 = true +UCAS40317 = true +UCAS40326 = true +UCKS45168 = true +ULJM06213 = true +ULJM06214 = true + +# Monster Hunter Portable 3rd +NPJB40001 = true +NPJH55800 = true +ULJM05800 = true +ULJM08058 = true + +# Persona 3 Portable +ULES01523 = true +ULUS10512 = true +UCAS40288 = true +ULJM05489 = true +UCKS45140 = true +ULJM08044 = true +NPJH50040 = true +UCKS45175 = true \ No newline at end of file From 9bc0d662c903d87913672de9396d0384335122bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 10:09:47 +0100 Subject: [PATCH 370/715] Add more affected games to compat setting. Reorder checks, and check vendor flag. --- GPU/GLES/GPU_GLES.cpp | 6 +++--- assets/compat.ini | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 50f80b6247..c110380c91 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -189,14 +189,14 @@ u32 GPU_GLES::CheckGPUFeatures() const { features |= GPU_USE_SINGLE_PASS_STEREO; } - if (draw_->GetBugs().Has(Draw::Bugs::ADRENO_RESOURCE_DEADLOCK)) { + features = CheckGPUFeaturesLate(features); + + if (draw_->GetBugs().Has(Draw::Bugs::ADRENO_RESOURCE_DEADLOCK) && g_Config.bVendorBugChecksEnabled) { if (PSP_CoreParameter().compat.flags().OldAdrenoPixelDepthRoundingGL) { features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; } } - features = CheckGPUFeaturesLate(features); - // This is a bit ugly, but lets us reuse most of the depth logic in GPUCommon. if (features & GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT) { if (gl_extensions.IsGLES && !gl_extensions.GLES3) { diff --git a/assets/compat.ini b/assets/compat.ini index 34f3369c2e..0f334cb6d9 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1311,4 +1311,25 @@ ULJM05489 = true UCKS45140 = true ULJM08044 = true NPJH50040 = true -UCKS45175 = true \ No newline at end of file +UCKS45175 = true + +# Hack/Link +ULJS00266 = true +ULJS00279 = true +ULJS19058 = true + +# Midnight Club: LA Remix +ULUS10383 = true +ULES01144 = true +ULJS00180 = true +ULJS00267 = true +ULJM05904 = true +NPJH50440 = true + +# ModNation Racers +UCES01327 = true +UCUS98741 = true +UCAS40306 = true +UCJS10112 = true +NPJG00116 = true +NPUG70097 = true # Demo From 7b154d6895192caaa3af8f620b97e2b2f09be340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 08:18:03 +0100 Subject: [PATCH 371/715] Don't forget to rebind the framebuffer after copying a framebuffer to CLUT. --- GPU/Common/TextureCacheCommon.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 03e530381e..86134f14c6 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1308,6 +1308,8 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { chosenFramebuffer->fbo, 0.0f, 0.0f, 512.0f * chosenFramebuffer->renderScaleFactor, 1.0f, dynamicClutTemp_, 0.0f, 0.0f, 512.0f, 1.0f, false, chosenFramebuffer->renderScaleFactor, framebufferManager_->Get2DPipeline(DRAW2D_COPY_COLOR_RECT2LIN), "copy_clut_to_temp"); + + framebufferManager_->RebindFramebuffer("after_copy_clut_to_temp"); clutRenderFormat_ = chosenFramebuffer->fb_format; } NotifyMemInfo(MemBlockFlags::ALLOC, clutAddr, loadBytes, "CLUT"); From eea0b2632c14c2581f06170368756c042ed617b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 10:03:16 +0100 Subject: [PATCH 372/715] Add checks against rendering with depth against non-depth targets. --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 24 ++++++++++++++++++----- Common/GPU/Vulkan/VulkanRenderManager.h | 14 +++++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index d4497aeb6e..d828c277ca 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -218,6 +218,10 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas bool hasDepth = RenderPassTypeHasDepth(rpType); views[0] = color.rtView; // 2D array texture if multilayered. if (hasDepth) { + if (!depth.rtView) { + WARN_LOG(G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", depth.image, depth.texAllLayersView, depth.format, tag_.c_str(), width, height); + // Will probably crash, depending on driver. + } views[1] = depth.rtView; } fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); @@ -271,7 +275,9 @@ VKRFramebuffer::~VKRFramebuffer() { } } -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { +// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. +// This requires a different sampling path! +void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { // We don't support more exotic layer setups for now. Mono or stereo. _dbg_assert_(numLayers == 1 || numLayers == 2); @@ -313,7 +319,6 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int ivci.subresourceRange.levelCount = 1; res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.rtView); vulkan->SetDebugName(img.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); - _dbg_assert_(res == VK_SUCCESS); // Separate view for texture sampling all layers together. @@ -757,6 +762,12 @@ void VulkanRenderManager::EndCurRenderStep() { curRenderStep_->render.pipelineFlags = curPipelineFlags_; bool depthStencil = (curPipelineFlags_ & PipelineFlags::USES_DEPTH_STENCIL) != 0; RenderPassType rpType = depthStencil ? RenderPassType::HAS_DEPTH : RenderPassType::DEFAULT; + + if (curRenderStep_->render.framebuffer && (rpType & RenderPassType::HAS_DEPTH) && !curRenderStep_->render.framebuffer->HasDepth()) { + WARN_LOG(G3D, "Trying to render with a depth-writing pipeline to a framebuffer without depth: %s", curRenderStep_->render.framebuffer->Tag()); + rpType = RenderPassType::DEFAULT; + } + if (!curRenderStep_->render.framebuffer) { rpType = RenderPassType::BACKBUFFER; } else { @@ -772,8 +783,6 @@ void VulkanRenderManager::EndCurRenderStep() { } } - // TODO: Also add render pass types for depth/stencil-less. - VKRRenderPass *renderPass = queueRunner_.GetRenderPass(key); curRenderStep_->render.renderPassType = rpType; @@ -1095,6 +1104,7 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); if (!clearMask) return; + // If this is the first drawing command or clears everything, merge it into the pass. int allAspects = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; if (curRenderStep_->render.numDraws == 0 || clearMask == allAspects) { @@ -1106,7 +1116,11 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten curRenderStep_->render.stencilLoad = (clearMask & VK_IMAGE_ASPECT_STENCIL_BIT) ? VKRRenderPassLoadAction::CLEAR : VKRRenderPassLoadAction::KEEP; if (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL; + if (curRenderStep_->render.framebuffer && !curRenderStep_->render.framebuffer->HasDepth()) { + WARN_LOG(G3D, "Trying to clear depth/stencil on a non-depth framebuffer: %s", curRenderStep_->render.framebuffer->Tag()); + } else { + curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL; + } } // In case there were commands already. diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 5e519f4641..04daa5966e 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -50,10 +50,6 @@ struct VKRImage { std::string tag; }; -// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. -// This requires a different sampling path! -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); - class VKRFramebuffer { public: VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag); @@ -74,9 +70,15 @@ public: void UpdateTag(const char *newTag); + bool HasDepth() const { + return depth.image != VK_NULL_HANDLE; + } + // TODO: Hide. VulkanContext *vulkan_; private: + static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); + VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{}; std::string tag_; @@ -295,6 +297,10 @@ public: pipelinesToCheck_.push_back(pipeline); data.graphics_pipeline.pipeline = pipeline; data.graphics_pipeline.pipelineLayout = pipelineLayout; + // This can be used to debug cases where depth/stencil rendering is used on color-only framebuffers. + // if ((flags & PipelineFlags::USES_DEPTH_STENCIL) && curRenderStep_->render.framebuffer && !curRenderStep_->render.framebuffer->HasDepth()) { + // DebugBreak(); + // } curPipelineFlags_ |= flags; curRenderStep_->commands.push_back(data); } From a1c61abdda3879b4c69d7744720a58436881344b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Nov 2022 23:15:37 +0100 Subject: [PATCH 373/715] Vulkan validation: One more false positive related to input attachments See comment in code --- Common/GPU/Vulkan/VulkanDebug.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp index 12bd0f4d6f..7a3d3a079f 100644 --- a/Common/GPU/Vulkan/VulkanDebug.cpp +++ b/Common/GPU/Vulkan/VulkanDebug.cpp @@ -42,7 +42,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( // UNASSIGNED return false; } - if (messageCode == 606910136 || messageCode == -392708513) { + if (messageCode == 606910136 || messageCode == -392708513 || messageCode == -384083808) { // VUID-vkCmdDraw-None-02686 // Kinda false positive, or at least very unnecessary, now that I solved the real issue. // See https://github.com/hrydgard/ppsspp/pull/16354 @@ -92,6 +92,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( } else { WARN_LOG(G3D, "VKDEBUG: %s", msg.c_str()); } + // false indicates that layer should not bail-out of an // API call that had validation failures. This may mean that the // app dies inside the driver due to invalid parameter(s). From 70d1d8fa07947291baf146fac7e905b034a971d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 10:38:49 +0100 Subject: [PATCH 374/715] Replace the "GetCurrentStepId"-based state invalidation with callbacks --- CMakeLists.txt | 1 + Common/Common.vcxproj | 1 + Common/Common.vcxproj.filters | 3 ++ Common/GPU/D3D11/thin3d_d3d11.cpp | 15 +++--- Common/GPU/D3D9/thin3d_d3d9.cpp | 18 ++++--- Common/GPU/MiscTypes.h | 11 ++++ Common/GPU/OpenGL/GLRenderManager.cpp | 8 +-- Common/GPU/OpenGL/GLRenderManager.h | 15 +++--- Common/GPU/OpenGL/thin3d_gl.cpp | 8 +-- Common/GPU/Vulkan/VulkanRenderManager.cpp | 10 ++-- Common/GPU/Vulkan/VulkanRenderManager.h | 15 +++--- Common/GPU/Vulkan/thin3d_vulkan.cpp | 8 +-- Common/GPU/thin3d.h | 5 +- GPU/D3D11/DrawEngineD3D11.cpp | 21 ++++---- GPU/D3D11/DrawEngineD3D11.h | 2 + GPU/Directx9/DrawEngineDX9.cpp | 18 +++---- GPU/Directx9/DrawEngineDX9.h | 1 + GPU/GLES/DrawEngineGLES.cpp | 24 +++++---- GPU/GLES/DrawEngineGLES.h | 3 +- GPU/Vulkan/DrawEngineVulkan.cpp | 63 ++++++++++------------- GPU/Vulkan/DrawEngineVulkan.h | 5 +- 21 files changed, 140 insertions(+), 115 deletions(-) create mode 100644 Common/GPU/MiscTypes.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2072a5d003..0eee60a31e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -606,6 +606,7 @@ add_library(Common STATIC Common/File/FileDescriptor.cpp Common/File/FileDescriptor.h Common/GPU/DataFormat.h + Common/GPU/MiscTypes.h Common/GPU/thin3d.cpp Common/GPU/thin3d.h Common/GPU/thin3d_create.h diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index d59ae3136e..15b6197cfd 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -432,6 +432,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index ac2fde0155..12a2b04191 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -452,6 +452,9 @@ Render + + GPU + diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 46713b53f3..57afa60de2 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -163,8 +163,8 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - int GetCurrentStepId() const override { - return stepId_; + void SetInvalidationCallback(InvalidationCallback callback) override { + invalidationCallback_ = callback; } private: @@ -177,7 +177,6 @@ private: ID3D11DeviceContext *context_; ID3D11Device1 *device1_; ID3D11DeviceContext1 *context1_; - int stepId_ = -1; ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED ID3D11RenderTargetView *bbRenderTargetView_ = nullptr; @@ -216,6 +215,8 @@ private: ID3D11Buffer *nextIndexBuffer_ = nullptr; int nextIndexBufferOffset_ = 0; + InvalidationCallback invalidationCallback_; + // Dynamic state float blendFactor_[4]{}; bool blendFactorDirty_ = false; @@ -399,7 +400,6 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1 // Make sure that we don't eliminate the next time the render target is set. curRenderTargetView_ = nullptr; curDepthStencilView_ = nullptr; - stepId_ = 0; break; } } @@ -1500,13 +1500,11 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x D3D11_BOX srcBox{ (UINT)x, (UINT)y, (UINT)z, (UINT)(x + width), (UINT)(y + height), (UINT)(z + depth) }; context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox); } - stepId_++; } bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) { // Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead. Crash(); - stepId_++; return false; } @@ -1652,7 +1650,6 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel if (!useGlobalPacktex) { packTex->Release(); } - stepId_++; return true; } @@ -1699,7 +1696,9 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren context_->ClearDepthStencilView(curDepthStencilView_, mask, rp.clearDepth, rp.clearStencil); } - stepId_++; + if (invalidationCallback_) { + invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + } } void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 8de75b09d0..7b38c1a3a2 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -610,18 +610,17 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - int GetCurrentStepId() const override { - return stepId_; - } - void InvalidateCachedState() override; + void SetInvalidationCallback(InvalidationCallback callback) override { + invalidationCallback_ = callback; + } + private: LPDIRECT3D9 d3d_; LPDIRECT3D9EX d3dEx_; LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9EX deviceEx_; - int stepId_ = -1; int adapterId_ = -1; D3DADAPTER_IDENTIFIER9 identifier_{}; D3DCAPS9 d3dCaps_; @@ -647,6 +646,8 @@ private: // Dynamic state uint8_t stencilRef_ = 0; + + InvalidationCallback invalidationCallback_; }; void D3D9Context::InvalidateCachedState() { @@ -1319,7 +1320,10 @@ void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPa dxstate.scissorRect.restore(); dxstate.scissorTest.restore(); dxstate.viewport.restore(); - stepId_++; + + if (invalidationCallback_) { + invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + } } uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) { @@ -1398,7 +1402,6 @@ bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int } else { return false; } - stepId_++; return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, (filter == FB_BLIT_LINEAR && channelBits == FB_COLOR_BIT) ? D3DTEXF_LINEAR : D3DTEXF_POINT)); } @@ -1519,7 +1522,6 @@ void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, voi device_->GetDepthStencilSurface(&deviceDSsurf); break; case Event::PRESENTED: - stepId_ = 0; break; } } diff --git a/Common/GPU/MiscTypes.h b/Common/GPU/MiscTypes.h new file mode 100644 index 0000000000..fd3d90dbb5 --- /dev/null +++ b/Common/GPU/MiscTypes.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Common/Common.h" + +enum class InvalidationFlags { + RENDER_PASS_STATE = 1, + COMMAND_BUFFER_STATE = 2, +}; +ENUM_CLASS_BITOPS(InvalidationFlags); + +typedef std::function InvalidationCallback; diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index f3eb5f59eb..034f4c672e 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -354,6 +354,10 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende step->dependencies.insert(fb); } } + + if (invalidationCallback_) { + invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + } } void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit) { @@ -480,7 +484,6 @@ void GLRenderManager::BeginFrame() { // In GL, we have to do deletes on the submission thread. insideFrame_ = true; - renderStepOffset_ = 0; } void GLRenderManager::Finish() { @@ -612,9 +615,6 @@ void GLRenderManager::Run(int frame) { } void GLRenderManager::FlushSync() { - // TODO: Reset curRenderStep_? - renderStepOffset_ += (int)steps_.size(); - int curFrame = curFrame_; FrameData &frameData = frameData_[curFrame]; { diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 135f776361..905fd70826 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -10,6 +10,7 @@ #include #include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/MiscTypes.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Log.h" #include "GLQueueRunner.h" @@ -368,6 +369,9 @@ public: GLRenderManager() {} ~GLRenderManager(); + void SetInvalidationCallback(InvalidationCallback callback) { + invalidationCallback_ = callback; + } void SetErrorCallback(ErrorCallbackFn callback, void *userdata) { queueRunner_.SetErrorCallback(callback, userdata); } @@ -980,12 +984,6 @@ public: skipGLCalls_ = true; } - // Gets a frame-unique ID of the current step being recorded. Can be used to figure out - // when the current step has changed, which means the caller will need to re-record its state. - int GetCurrentStepId() const { - return renderStepOffset_ + (int)steps_.size(); - } - private: void BeginSubmitFrame(int frame); void EndSubmitFrame(int frame); @@ -1033,8 +1031,7 @@ private: // Submission time state bool insideFrame_ = false; - // This is the offset within this frame, in case of a mid-frame sync. - int renderStepOffset_ = 0; + GLRStep *curRenderStep_ = nullptr; std::vector steps_; std::vector initSteps_; @@ -1074,4 +1071,6 @@ private: GLRProgram *curProgram_ = nullptr; #endif Draw::DeviceCaps caps_{}; + + InvalidationCallback invalidationCallback_; }; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 18da422ca2..3d68c9352f 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -466,12 +466,12 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override {} - int GetCurrentStepId() const override { - return renderManager_.GetCurrentStepId(); - } - void InvalidateCachedState() override; + void SetInvalidationCallback(InvalidationCallback callback) { + renderManager_.SetInvalidationCallback(callback); + } + private: void ApplySamplers(); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index d828c277ca..df3f5e5539 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -668,8 +668,6 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling, bool enableLogProfile insideFrame_ = true; vulkan_->BeginFrame(enableLogProfiler ? GetInitCmd() : VK_NULL_HANDLE); - renderStepOffset_ = 0; - frameData.profile.timestampDescriptions.clear(); if (frameData.profilingEnabled_) { // For various reasons, we need to always use an init cmd buffer in this case to perform the vkCmdResetQueryPool, @@ -956,6 +954,10 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR data.clear.clearMask = lateClearMask; curRenderStep_->commands.push_back(data); } + + if (invalidationCallback_) { + invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE); + } } bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { @@ -1414,7 +1416,9 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { // Called from main thread. void VulkanRenderManager::FlushSync() { - renderStepOffset_ += (int)steps_.size(); + if (invalidationCallback_) { + invalidationCallback_(InvalidationFlags::COMMAND_BUFFER_STATE); + } int curFrame = vulkan_->GetCurFrame(); FrameData &frameData = frameData_[curFrame]; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 04daa5966e..ca22dbab29 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -19,6 +19,7 @@ #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Math/math_util.h" #include "Common/GPU/DataFormat.h" +#include "Common/GPU/MiscTypes.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" // Forward declaration @@ -235,6 +236,10 @@ public: // Zaps queued up commands. Use if you know there's a risk you've queued up stuff that has already been deleted. Can happen during in-game shutdown. void Wipe(); + void SetInvalidationCallback(InvalidationCallback callback) { + invalidationCallback_ = callback; + } + // This starts a new step containing a render pass (unless it can be trivially merged into the previous one, which is pretty common). // // After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce @@ -475,12 +480,6 @@ public: VkCommandBuffer GetInitCmd(); - // Gets a frame-unique ID of the current step being recorded. Can be used to figure out - // when the current step has changed, which means the caller will need to re-record its state. - int GetCurrentStepId() const { - return renderStepOffset_ + (int)steps_.size(); - } - bool CreateBackbuffers(); void DestroyBackbuffers(); @@ -520,7 +519,6 @@ private: void DrainCompileQueue(); void Run(VKRRenderThreadTask &task); - void BeginSubmitFrame(int frame); // Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot). void FlushSync(); @@ -548,7 +546,6 @@ private: bool run_ = false; // This is the offset within this frame, in case of a mid-frame sync. - int renderStepOffset_ = 0; VKRStep *curRenderStep_ = nullptr; bool curStepHasViewport_ = false; bool curStepHasScissor_ = false; @@ -587,4 +584,6 @@ private: SimpleStat initTimeMs_; SimpleStat totalGPUTimeMs_; SimpleStat renderCPUTimeMs_; + + std::function invalidationCallback_; }; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index f055ad9499..2af40fda3a 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -498,14 +498,14 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - int GetCurrentStepId() const override { - return renderManager_.GetCurrentStepId(); - } - void InvalidateCachedState() override; void InvalidateFramebuffer(FBInvalidationStage stage, uint32_t channels) override; + void SetInvalidationCallback(InvalidationCallback callback) { + renderManager_.SetInvalidationCallback(callback); + } + private: VulkanTexture *GetNullTexture(); VulkanContext *vulkan_ = nullptr; diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 0f1a8b86bb..de3c9cc49d 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -16,6 +16,7 @@ #include "Common/Common.h" #include "Common/GPU/DataFormat.h" #include "Common/GPU/Shader.h" +#include "Common/GPU/MiscTypes.h" #include "Common/Data/Collections/Slice.h" namespace Lin { @@ -769,7 +770,9 @@ public: // This is called when we launch a new game, so any collected internal stats in the backends don't carry over. virtual void ResetStats() {} - virtual int GetCurrentStepId() const = 0; + // Used by the DrawEngines to know when they have to re-apply some state. + // Not very elegant, but more elegant than the old passId hack. + virtual void SetInvalidationCallback(InvalidationCallback callback) = 0; protected: ShaderModule *vsPresets_[VS_MAX_PRESET]; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index b702d15250..37343f852a 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -113,6 +113,8 @@ void DrawEngineD3D11::InitDeviceObjects() { tessDataTransferD3D11 = new TessellationDataTransferD3D11(context_, device_); tessDataTransfer = tessDataTransferD3D11; + + draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1)); } void DrawEngineD3D11::ClearTrackedVertexArrays() { @@ -136,6 +138,8 @@ void DrawEngineD3D11::NotifyConfigChanged() { } void DrawEngineD3D11::DestroyDeviceObjects() { + draw_->SetInvalidationCallback(InvalidationCallback()); + ClearTrackedVertexArrays(); ClearInputLayoutMap(); delete tessDataTransferD3D11; @@ -322,19 +326,18 @@ VertexArrayInfoD3D11::~VertexArrayInfoD3D11() { ebo->Release(); } +// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. +void DrawEngineD3D11::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::RENDER_PASS_STATE) { + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + textureCache_->ForgetLastTexture(); + } +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineD3D11::DoFlush() { gpuStats.numFlushes++; - // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. - int curRenderStepId = draw_->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); - lastRenderStepId_ = curRenderStepId; - } - bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 03f5f47ad7..8245cae6a4 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -155,6 +155,8 @@ public: void ClearInputLayoutMap(); private: + void Invalidate(InvalidationFlags flags); + void DoFlush(); void ApplyDrawState(int prim); diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 8a9de7ef79..e22d5577d2 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -126,10 +126,11 @@ DrawEngineDX9::~DrawEngineDX9() { } void DrawEngineDX9::InitDeviceObjects() { - + draw_->SetInvalidationCallback(std::bind(&DrawEngineDX9::Invalidate, this, std::placeholders::_1)); } void DrawEngineDX9::DestroyDeviceObjects() { + draw_->SetInvalidationCallback(InvalidationCallback()); ClearTrackedVertexArrays(); } @@ -310,18 +311,17 @@ void DrawEngineDX9::BeginFrame() { lastRenderStepId_ = -1; } +// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. +void DrawEngineDX9::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::RENDER_PASS_STATE) { + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + } +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineDX9::DoFlush() { gpuStats.numFlushes++; - // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. - int curRenderStepId = draw_->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - lastRenderStepId_ = curRenderStepId; - } - bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 9ef5b37c65..aa2baf5cfc 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -144,6 +144,7 @@ protected: void DecimateTrackedVertexArrays(); private: + void Invalidate(InvalidationFlags flags); void DoFlush(); void ApplyDrawState(int prim); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 8b842f1dd2..098dc4d26c 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -117,9 +117,13 @@ void DrawEngineGLES::InitDeviceObjects() { entries.push_back({ ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, offsetof(TransformedVertex, color1) }); entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, fog) }); softwareInputLayout_ = render_->CreateInputLayout(entries); + + draw_->SetInvalidationCallback(std::bind(&DrawEngineGLES::Invalidate, this, std::placeholders::_1)); } void DrawEngineGLES::DestroyDeviceObjects() { + draw_->SetInvalidationCallback(InvalidationCallback()); + // Beware: this could be called twice in a row, sometimes. for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { if (!frameData_[i].pushVertex && !frameData_[i].pushIndex) @@ -238,22 +242,22 @@ void *DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bind return dest; } +// A new render step means we need to flush any dynamic state. Really, any state that is reset in +// GLQueueRunner::PerformRenderPass. +void DrawEngineGLES::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::RENDER_PASS_STATE) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + textureCache_->ForgetLastTexture(); + } +} + void DrawEngineGLES::DoFlush() { PROFILE_THIS_SCOPE("flush"); FrameData &frameData = frameData_[render_->GetCurFrame()]; gpuStats.numFlushes++; - // A new render step means we need to flush any dynamic state. Really, any state that is reset in - // GLQueueRunner::PerformRenderPass. - int curRenderStepId = render_->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); - lastRenderStepId_ = curRenderStepId; - } - bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index d843c83ff4..ed8e18f292 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -84,7 +84,6 @@ public: void BeginFrame(); void EndFrame(); - // So that this can be inlined void Flush() { if (!numDrawCalls) @@ -117,6 +116,8 @@ protected: bool UpdateUseHWTessellation(bool enable) override; private: + void Invalidate(InvalidationFlags flags); + void InitDeviceObjects(); void DestroyDeviceObjects(); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index a26b14320f..b4aa4532b7 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Profiler/Profiler.h" @@ -150,7 +151,7 @@ void DrawEngineVulkan::InitDeviceObjects() { dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; dpTypes[3].descriptorCount = DEFAULT_DESC_POOL_SIZE; // TODO: Use a separate layout when no spline stuff is needed to reduce the need for these. dpTypes[3].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; - dpTypes[4].descriptorCount = 1; // For the frame global uniform buffer. + dpTypes[4].descriptorCount = DEFAULT_DESC_POOL_SIZE; // For the frame global uniform buffer. Might need to allocate multiple times. dpTypes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; @@ -204,6 +205,8 @@ void DrawEngineVulkan::InitDeviceObjects() { tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan); tessDataTransfer = tessDataTransferVulkan; + + draw_->SetInvalidationCallback(std::bind(&DrawEngineVulkan::Invalidate, this, std::placeholders::_1)); } DrawEngineVulkan::~DrawEngineVulkan() { @@ -234,7 +237,14 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) { } void DrawEngineVulkan::DestroyDeviceObjects() { - VulkanContext *vulkan = draw_ ? (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT) : nullptr; + if (!draw_) { + // We've already done this from LostDevice. + return; + } + + VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); + + draw_->SetInvalidationCallback(InvalidationCallback()); delete tessDataTransferVulkan; tessDataTransfer = nullptr; @@ -283,8 +293,6 @@ void DrawEngineVulkan::BeginFrame() { lastPipeline_ = nullptr; - lastRenderStepId_ = -1; - FrameData *frame = &GetCurFrame(); // First reset all buffers, then begin. This is so that Reset can free memory and Begin can allocate it, @@ -536,6 +544,21 @@ void MarkUnreliable(VertexArrayInfoVulkan *vai) { // For now we just leave it in the pushbuffer. } +void DrawEngineVulkan::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::COMMAND_BUFFER_STATE) { + GetCurFrame().frameDescSetUpdated = false; + } + if (flags & InvalidationFlags::RENDER_PASS_STATE) { + // If have a new render pass, dirty our dynamic state so it gets re-set. + // We have to do this again after the last possible place in DoFlush that can cause a renderpass switch + // like a shader blend blit or similar. But before we actually set the state! + // + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + lastPipeline_ = nullptr; + } +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineVulkan::DoFlush() { VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); @@ -545,18 +568,6 @@ void DrawEngineVulkan::DoFlush() { gpuStats.numFlushes++; - // If have a new render pass, dirty our dynamic state so it gets re-set. - // We have to do this again after the last possible place in DoFlush that can cause a renderpass switch - // like a shader blend blit or similar. But before we actually set the state! - int curRenderStepId = renderManager->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); - lastRenderStepId_ = curRenderStepId; - lastPipeline_ = nullptr; - } - bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE; bool textureNeedsApply = false; @@ -785,16 +796,6 @@ void DrawEngineVulkan::DoFlush() { } BindShaderBlendTex(); // This might cause copies so important to do before BindPipeline. - // If have a new render pass, dirty our dynamic state so it gets re-set. - // WARNING: We have to do this AFTER the last possible place in DoFlush that can cause a renderpass switch - // like a shader blend blit or similar. But before we actually set the state! - int curRenderStepId = renderManager->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE); - lastRenderStepId_ = curRenderStepId; - } - renderManager->BindPipeline(pipeline->pipeline, pipeline->pipelineFlags, pipelineLayout_); if (pipeline != lastPipeline_) { if (lastPipeline_ && !(lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant())) { @@ -928,16 +929,6 @@ void DrawEngineVulkan::DoFlush() { } BindShaderBlendTex(); // This might cause copies so super important to do before BindPipeline. - // If have a new render pass, dirty our dynamic state so it gets re-set. - // WARNING: We have to do this AFTER the last possible place in DoFlush that can cause a renderpass switch - // like a shader blend blit or similar. But before we actually set the state! - int curRenderStepId = renderManager->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE); - lastRenderStepId_ = curRenderStepId; - } - renderManager->BindPipeline(pipeline->pipeline, pipeline->pipelineFlags, pipelineLayout_); if (pipeline != lastPipeline_) { if (lastPipeline_ && !lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant()) { diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 7d069c4305..d9f1339e5b 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -43,6 +43,7 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Vulkan/StateMappingVulkan.h" +#include "GPU/Vulkan/VulkanRenderManager.h" struct DecVtxFormat; struct UVScale; @@ -208,6 +209,8 @@ public: } private: + void Invalidate(InvalidationFlags flags); + struct FrameData; void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant); void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState); @@ -308,6 +311,4 @@ private: // Hardware tessellation TessellationDataTransferVulkan *tessDataTransferVulkan; - - int lastRenderStepId_ = -1; }; From 3dd45c65618069a64ace5b68fa887964900fd698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 11:02:21 +0100 Subject: [PATCH 375/715] Can't forget the texture in the callback, breaks texture-from-framebuffer-copy. Was probably redundant anyway. --- GPU/D3D11/DrawEngineD3D11.cpp | 1 - GPU/GLES/DrawEngineGLES.cpp | 1 - GPU/Vulkan/DrawEngineVulkan.cpp | 2 -- 3 files changed, 4 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 37343f852a..3d66b8c37d 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -330,7 +330,6 @@ VertexArrayInfoD3D11::~VertexArrayInfoD3D11() { void DrawEngineD3D11::Invalidate(InvalidationFlags flags) { if (flags & InvalidationFlags::RENDER_PASS_STATE) { gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); } } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 098dc4d26c..e250da4be2 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -248,7 +248,6 @@ void DrawEngineGLES::Invalidate(InvalidationFlags flags) { if (flags & InvalidationFlags::RENDER_PASS_STATE) { // Dirty everything that has dynamic state that will need re-recording. gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); } } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index b4aa4532b7..8256ea8916 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -550,8 +550,6 @@ void DrawEngineVulkan::Invalidate(InvalidationFlags flags) { } if (flags & InvalidationFlags::RENDER_PASS_STATE) { // If have a new render pass, dirty our dynamic state so it gets re-set. - // We have to do this again after the last possible place in DoFlush that can cause a renderpass switch - // like a shader blend blit or similar. But before we actually set the state! // // Dirty everything that has dynamic state that will need re-recording. gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); From 55b1dc6ef456d4317d48fd78bcaeb35aeeb47fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 12:14:52 +0100 Subject: [PATCH 376/715] Warning fixes --- Common/GPU/OpenGL/thin3d_gl.cpp | 2 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 3d68c9352f..f58f55ac95 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -468,7 +468,7 @@ public: void InvalidateCachedState() override; - void SetInvalidationCallback(InvalidationCallback callback) { + void SetInvalidationCallback(InvalidationCallback callback) override { renderManager_.SetInvalidationCallback(callback); } diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 2af40fda3a..dc1b0738e0 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -502,7 +502,7 @@ public: void InvalidateFramebuffer(FBInvalidationStage stage, uint32_t channels) override; - void SetInvalidationCallback(InvalidationCallback callback) { + void SetInvalidationCallback(InvalidationCallback callback) override { renderManager_.SetInvalidationCallback(callback); } From 75040f0cb1471dff1e587e4383744cc6a0f2b6ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 12:47:13 +0100 Subject: [PATCH 377/715] Remove some logspam, oops --- Core/ControlMapper.cpp | 2 -- UI/ControlMappingScreen.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index b6d1dc3d0d..8cc14209d7 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -74,12 +74,10 @@ void ControlMapper::SetPSPAxis(int device, char axis, float value, int stick) { if (inDeadZone && lastNonDeadzoneDeviceID_[stick] != device) { // Ignore this event! See issue #15465 - NOTICE_LOG(COMMON, "Ignoring deadzone event from device %d (%d, %f)", device, axis, value); ignore = true; } if (!inDeadZone) { - NOTICE_LOG(COMMON, "Got a non deadzone event from device %d (%d, %f > %f)", device, axis, value, g_Config.fAnalogDeadzone); lastNonDeadzoneDeviceID_[stick] = device; } diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 978b7a97f4..1d54f582ef 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -583,7 +583,6 @@ void JoystickHistoryView::Update() { AnalogSetupScreen::AnalogSetupScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { mapper_.SetCallbacks([](int vkey) {}, [](int vkey) {}, [&](int stick, float x, float y) { - NOTICE_LOG(COMMON, "analog value from mapper: %f %f", x, y); analogX_[stick] = x; analogY_[stick] = y; }); From 2af55d37ad4131b2a64f9ee7c8a8bb70ed75155d Mon Sep 17 00:00:00 2001 From: GABO1423 <35014183+GABO1423@users.noreply.github.com> Date: Wed, 23 Nov 2022 22:34:52 -0400 Subject: [PATCH 378/715] (Libretro) Huge MSVC Build Overhaul --- libretro/Makefile | 151 +++--------------------------------- libretro/README_WINDOWS.txt | 57 +++++++------- libretro/VSWhere.sh | 2 + 3 files changed, 43 insertions(+), 167 deletions(-) create mode 100644 libretro/VSWhere.sh diff --git a/libretro/Makefile b/libretro/Makefile index 088ad22267..c6e3856373 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -311,28 +311,28 @@ else ifeq ($(platform), emscripten) -Drglgen_resolve_symbols=mupen_rglgen_resolve_symbols PLATFORM_EXT = unix -# Windows MSVC 2017 all architectures -else ifneq (,$(findstring windows_msvc2017,$(platform))) +# Windows MSVC all architectures +else ifneq (,$(findstring windows_msvc,$(platform))) - PlatformSuffix = $(subst windows_msvc2017_,,$(platform)) + PlatformSuffix = $(subst windows_msvc_,,$(platform)) ifneq (,$(findstring desktop,$(PlatformSuffix))) WinPartition = desktop - MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 + MSVCCompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 LDFLAGS += -MANIFEST -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib else ifneq (,$(findstring uwp,$(PlatformSuffix))) WinPartition = uwp - MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB + MSVCCompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO LIBS += WindowsApp.lib endif ifeq ($(DEBUG), 1) - MSVC2017CompileFlags += -DEBUG + MSVCCompileFlags += -DEBUG endif - CFLAGS += $(MSVC2017CompileFlags) -nologo - CXXFLAGS += $(MSVC2017CompileFlags) -nologo -EHsc -DARMIPS_USE_STD_FILESYSTEM + CFLAGS += $(MSVCCompileFlags) -nologo + CXXFLAGS += $(MSVCCompileFlags) -nologo -EHsc -DARMIPS_USE_STD_FILESYSTEM TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) @@ -349,10 +349,9 @@ else ifneq (,$(findstring windows_msvc2017,$(platform))) reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>/dev/null))) fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) - b1 := ( - b2 := ) - ProgramFiles86w := $(ProgramFiles$(b1)x86$(b2)) - ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") + VSCommand := bash VSWhere.sh -latest -property installationPath + VSInstallPathw := $(shell cmd /c "$(VSCommand)") + VSInstallPath := $(shell cygpath "$(VSInstallPathw)") WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) @@ -363,133 +362,7 @@ else ifneq (,$(findstring windows_msvc2017,$(platform))) WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) WindowsSDKVersion := $(WindowsSDKVersion) - VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools - VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise - VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional - VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community - - VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) - endif - VsInstallRoot := $(VsInstallRoot) - - VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') - VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) - VcCompilerLibDir := $(VcCompilerToolsDir)/lib/$(TargetArchMoniker) - - WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared") - WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt") - WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um") - WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)") - WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)") - - LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerLibDir)") - INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include") - - # For some reason the HostX86 compiler doesn't like compiling for x64 - # ("no such file" opening a shared library), and vice-versa. - # Work around it for now by using the strictly x86 compiler for x86, and x64 for x64. - # NOTE: What about ARM? - ifneq (,$(findstring x64,$(TargetArchMoniker))) - override TARGET_ARCH = x86_64 - VCCompilerToolsBinDir := $(VcCompilerToolsDir)/bin/HostX64/$(TargetArchMoniker) - LIB := $(LIB);$(CORE_DIR)/dx9sdk/Lib/x64 - else - override TARGET_ARCH = x86 - VCCompilerToolsBinDir := $(VcCompilerToolsDir)/bin/HostX86/$(TargetArchMoniker) - LIB := $(LIB);$(CORE_DIR)/dx9sdk/Lib/x86 - endif - - PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)"):$(PATH) - PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE") - - export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir) - export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir);$(FFMPEGDIR)/Windows/$(TARGET_ARCH)/lib - TARGET := $(TARGET_NAME)_libretro.dll - PSS_STYLE :=2 - LDFLAGS += -DLL - PLATFORM_EXT = win32 - FFMPEGINCFLAGS += -I$(FFMPEGDIR)/Windows/$(TARGET_ARCH)/include - FFMPEGLIBDIR := $(FFMPEGDIR)/Windows/$(TARGET_ARCH)/lib - FFMPEGLDFLAGS += -LIBPATH:$(FFMPEGLIBDIR) - GL_LIB := opengl32.lib - LDFLAGS += ws2_32.lib user32.lib shell32.lib avcodec.lib avutil.lib swresample.lib swscale.lib avformat.lib advapi32.lib winmm.lib gdi32.lib d3d9.lib d3dx9.lib Iphlpapi.lib - -# Windows MSVC 2019 all architectures -else ifneq (,$(findstring windows_msvc2019,$(platform))) - - PlatformSuffix = $(subst windows_msvc2019_,,$(platform)) - ifneq (,$(findstring desktop,$(PlatformSuffix))) - WinPartition = desktop - MSVC2019CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 - LDFLAGS += -MANIFEST -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 - LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib - else ifneq (,$(findstring uwp,$(PlatformSuffix))) - WinPartition = uwp - MSVC2019CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB - LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO - LIBS += WindowsApp.lib - endif - - ifeq ($(DEBUG), 1) - MSVC2019CompileFlags += -DEBUG - endif - - CFLAGS += $(MSVC2019CompileFlags) -nologo - CXXFLAGS += $(MSVC2019CompileFlags) -nologo -EHsc -DARMIPS_USE_STD_FILESYSTEM - - TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) - - CC = cl.exe - CXX = cl.exe - - SPACE := - SPACE := $(SPACE) $(SPACE) - BACKSLASH := - BACKSLASH := \$(BACKSLASH) - filter_out1 = $(filter-out $(firstword $1),$1) - filter_out2 = $(call filter_out1,$(call filter_out1,$1)) - - reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>/dev/null))) - fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) - - b1 := ( - b2 := ) - ProgramFiles86w := $(ProgramFiles$(b1)x86$(b2)) - ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") - - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir := $(WindowsSdkDir) - - WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) - WindowsSDKVersion := $(WindowsSDKVersion) - - VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2019/BuildTools - VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2019/Enterprise - VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2019/Professional - VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2019/Community - - VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) - endif - VsInstallRoot := $(VsInstallRoot) + VsInstallRoot := $(VSInstallPath) VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) diff --git a/libretro/README_WINDOWS.txt b/libretro/README_WINDOWS.txt index 4e8f6236af..f1f1f18907 100644 --- a/libretro/README_WINDOWS.txt +++ b/libretro/README_WINDOWS.txt @@ -1,28 +1,29 @@ -Install msys. - -Follow the guide here to set up your MSYS installation for retroarch compilation: - -https://docs.libretro.com/development/retroarch/compilation/windows/ - -You can probably really skip most of the packages but you need make: - -pacman -S make - -"Install" the plugin in Retroarch. - -Then use the following in msys: - -cd libretro -make platform=windows_msvc2019_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores - -Note that the latter part copies the DLL/PDB into wherever retroarch reads it from. Might need to adjust the path, -and adjust -j32 depending on your number of logical CPUs - might not need that many threads (or you might need more...). - -(plain make without a platform parameter doesn't work - g++ isn't able to build the D3D11 stuff, or at least it fails to link). - -To debug from within MSVC, open retroarch.exe (or retroarch_debug.exe) as a Project/Solution, then open a few of the cpp files, -set some breakpoints and just launch using F5. - -Useful libretro/vulkan sample code: - -https://github.com/libretro/libretro-samples/blob/master/video/vulkan/vk_rendering/libretro-test.c +Install msys. + +Follow the guide here to set up your MSYS installation for retroarch compilation: + +https://docs.libretro.com/development/retroarch/compilation/windows/ + +You can probably really skip most of the packages but you need make: + +pacman -S make + +"Install" the plugin in Retroarch. + +Then use the following in msys: + +cd libretro + +make platform=windows_msvc_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores + +Note that the latter part copies the DLL/PDB into wherever retroarch reads it from. Might need to adjust the path, +and adjust -j32 depending on your number of logical CPUs - might not need that many threads (or you might need more...). + +(plain make without a platform parameter doesn't work - g++ isn't able to build the D3D11 stuff, or at least it fails to link). + +To debug from within MSVC, open retroarch.exe (or retroarch_debug.exe) as a Project/Solution, then open a few of the cpp files, +set some breakpoints and just launch using F5. + +Useful libretro/vulkan sample code: + +https://github.com/libretro/libretro-samples/blob/master/video/vulkan/vk_rendering/libretro-test.c diff --git a/libretro/VSWhere.sh b/libretro/VSWhere.sh new file mode 100644 index 0000000000..7ae8b0933e --- /dev/null +++ b/libretro/VSWhere.sh @@ -0,0 +1,2 @@ +#!/bin/sh +"$(cygpath "$(env | awk -F= '/^ProgramFiles\(x86\)=/ { print $2; }')/Microsoft Visual Studio/Installer/vswhere.exe")" "$@" \ No newline at end of file From 23590a6dd0d4550a0063faa96b673fc6015dcb7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 18:15:56 +0100 Subject: [PATCH 379/715] Force LowerResolutionForEffects in Motorstorm, looks just fine See #16429 --- assets/compat.ini | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/assets/compat.ini b/assets/compat.ini index 0f334cb6d9..70ff01fcf4 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1216,6 +1216,15 @@ ULJM05494 = true NPJH50143 = true ULJM05738 = true +# Motorstorm - See #16429 +UCES01250 = true +UCAS40266 = true +UCUS98743 = true +UCES01250 = true +UCKS45124 = true +UCJS10104 = true +NPJG00047 = true + [NearestFilteringOnFramebufferCreate] # Ridge Racer speedometer dynamic CLUT problem - they rely on some palette entries # from memory, and render to the rest of the palette. The palette entries loaded from memory From 5e4492b43f0a7e432c59fc3b9b987c5ecdbd6c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Moraz=C3=A1n?= <35014183+GABO1423@users.noreply.github.com> Date: Thu, 24 Nov 2022 13:51:13 -0400 Subject: [PATCH 380/715] Libretro Buildbot Fix --- libretro/Makefile | 4 ++-- libretro/README_WINDOWS.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libretro/Makefile b/libretro/Makefile index c6e3856373..e732ddfba2 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -312,9 +312,9 @@ else ifeq ($(platform), emscripten) PLATFORM_EXT = unix # Windows MSVC all architectures -else ifneq (,$(findstring windows_msvc,$(platform))) +else ifneq (,$(findstring windows_msvc2019,$(platform))) - PlatformSuffix = $(subst windows_msvc_,,$(platform)) + PlatformSuffix = $(subst windows_msvc2019_,,$(platform)) ifneq (,$(findstring desktop,$(PlatformSuffix))) WinPartition = desktop MSVCCompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 diff --git a/libretro/README_WINDOWS.txt b/libretro/README_WINDOWS.txt index f1f1f18907..b126a8f9af 100644 --- a/libretro/README_WINDOWS.txt +++ b/libretro/README_WINDOWS.txt @@ -14,7 +14,7 @@ Then use the following in msys: cd libretro -make platform=windows_msvc_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores +make platform=windows_msvc2019_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores Note that the latter part copies the DLL/PDB into wherever retroarch reads it from. Might need to adjust the path, and adjust -j32 depending on your number of logical CPUs - might not need that many threads (or you might need more...). From 0c03f5bad79feb13087a54cb5c798d2a763bd230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 19:06:07 +0100 Subject: [PATCH 381/715] Move the screen scaling filter to the DisplayLayoutEditor --- UI/DisplayLayoutScreen.cpp | 3 +++ UI/GameSettingsScreen.cpp | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 57a1d28896..38a539b2af 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -270,6 +270,9 @@ void DisplayLayoutScreen::CreateViews() { }); rightColumn->Add(rotation); + static const char *bufFilters[] = { "Linear", "Nearest", }; + rightColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); + rightColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); Draw::DrawContext *draw = screenManager()->getDrawContext(); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index ef7d5b6c3a..afaaaeaff3 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -569,9 +569,6 @@ void GameSettingsScreen::CreateViews() { static const char *texFilters[] = { "Auto", "Nearest", "Linear", "Auto Max Quality"}; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexFiltering, gr->T("Texture Filter"), texFilters, 1, ARRAY_SIZE(texFilters), gr->GetName(), screenManager())); - static const char *bufFilters[] = { "Linear", "Nearest", }; - graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); - #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) bool showCardboardSettings = deviceType != DEVICE_TYPE_VR; #else From 0e2fd7c2a2ee05d94f55b019e58c84762bc4670d Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 24 Nov 2022 19:17:00 +0100 Subject: [PATCH 382/715] OpenXR - Fix HUD in many games which breaks postprocess effects --- Common/VR/PPSSPPVR.cpp | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 423b74bd27..0fba20ac61 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -727,7 +727,7 @@ bool Is2DVRObject(float* projMatrix, bool ortho) { if (!identity && !ortho) { vr3DGeometryCount++; } - return identity; + return identity || ortho; } void UpdateVRParams(float* projMatrix, float* viewMatrix) { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 7195bcd8af..aed35841f8 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -385,12 +385,11 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu // Set HUD mode if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - bool is3D = gstate.isDepthWriteEnabled(); - bool hud = is2D && !is3D && !flatScreen && - gstate.isModeThrough() && //2D content requires orthographic projection + bool hud = is2D && !flatScreen && gstate.isAlphaBlendEnabled() && //2D content has to be blended !gstate.isLightingEnabled() && //2D content cannot be rendered with lights on - !gstate.isFogEnabled(); //2D content cannot be rendered with fog on + !gstate.isFogEnabled() && //2D content cannot be rendered with fog on + !gstate.isDepthWriteEnabled(); //This breaks minimap in GTA but works elsewhere if (hud) { float scale = 0.5f; render_->SetUniformF1(&u_scaleX, scale); From 24ab2232fcf538b8a86395f90e5d46127ac59b5f Mon Sep 17 00:00:00 2001 From: iota97 Date: Thu, 24 Nov 2022 20:13:43 +0100 Subject: [PATCH 383/715] Snap from screen center --- UI/TouchControlLayoutScreen.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 3432d76d26..47a4b918d6 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -22,6 +22,7 @@ #include "Common/Render/DrawBuffer.h" #include "Common/Data/Text/I18n.h" #include "Common/Math/math_util.h" +#include "Common/System/Display.h" #include "Common/UI/Context.h" #include "Common/CommonTypes.h" @@ -327,10 +328,19 @@ public: dc.BeginNoTex(); float xOffset = bounds_.x; float yOffset = bounds_.y; - for (int x = x1; x < x2; x += g_Config.iTouchSnapGridSize) + + dc.Draw()->Rect((x1+x2)/2 + xOffset - pixel_in_dps_x, y1 + yOffset, 3.0*pixel_in_dps_x, y2-y1, col); + for (int x = (x1+x2)/2 - g_Config.iTouchSnapGridSize; x > 0; x -= g_Config.iTouchSnapGridSize) dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col); - for (int y = y1; y < y2; y += g_Config.iTouchSnapGridSize) + for (int x = (x1+x2)/2 + g_Config.iTouchSnapGridSize; x < x2; x += g_Config.iTouchSnapGridSize) + dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col); + + dc.Draw()->Rect(x1 + xOffset, (y1+y2)/2 + yOffset - pixel_in_dps_y, x2-x1, 3.0*pixel_in_dps_y, col); + for (int y = (y1+y2)/2 - g_Config.iTouchSnapGridSize; y > 0; y -= g_Config.iTouchSnapGridSize) dc.Draw()->hLine(x1 + xOffset, y + yOffset, x2 + xOffset, col); + for (int y = (y1+y2)/2 + g_Config.iTouchSnapGridSize; y < y2; y += g_Config.iTouchSnapGridSize) + dc.Draw()->hLine(x1 + xOffset, y + yOffset, x2 + xOffset, col); + dc.Flush(); dc.Begin(); } @@ -401,8 +411,8 @@ void ControlLayoutView::Touch(const TouchInput &touch) { newPos.x = startObjectX_ + (touch.x - startDragX_); newPos.y = startObjectY_ + (touch.y - startDragY_); if (g_Config.bTouchSnapToGrid) { - newPos.x -= fmod(newPos.x, g_Config.iTouchSnapGridSize); - newPos.y -= fmod(newPos.y, g_Config.iTouchSnapGridSize); + newPos.x -= fmod(newPos.x - validRange.w/2, g_Config.iTouchSnapGridSize); + newPos.y -= fmod(newPos.y - validRange.h/2, g_Config.iTouchSnapGridSize); } newPos = ClampTo(newPos, validRange); From ed68304b6339b2ce75700c6d50d1d3967faa0a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:03:17 +0100 Subject: [PATCH 384/715] Move some settings around, delete a dupe --- UI/DevScreens.cpp | 1 + UI/GameSettingsScreen.cpp | 68 ++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 9e6830e682..7e6bf0aac3 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -106,6 +106,7 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { items->Add(new CheckBox(&g_Config.bShowGpuProfile, dev->T("GPU Profile"))); } items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenuScreen::OnFreezeFrame); + items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenuScreen::OnDumpFrame); items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenuScreen::OnToggleAudioDebug); #ifdef USE_PROFILER diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index afaaaeaff3..d7b71b34a5 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -303,6 +303,33 @@ void GameSettingsScreen::CreateViews() { softwareGPU->SetEnabled(!PSP_IsInited()); } + static const char *internalResolutions[] = { "Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP", "6x PSP", "7x PSP", "8x PSP", "9x PSP", "10x PSP" }; + resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), gr->GetName(), screenManager())); + resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange); + resolutionChoice_->SetEnabledFunc([] { + return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects; + }); + +#if PPSSPP_PLATFORM(ANDROID) + if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) { + static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" }; + int max_res_temp = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2; + if (max_res_temp == 3) + max_res_temp = 4; // At least allow 2x + int max_res = std::min(max_res_temp, (int)ARRAY_SIZE(deviceResolutions)); + UI::PopupMultiChoice *hwscale = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAndroidHwScale, gr->T("Display Resolution (HW scaler)"), deviceResolutions, 0, max_res, gr->GetName(), screenManager())); + hwscale->OnChoice.Handle(this, &GameSettingsScreen::OnHwScaleChange); // To refresh the display mode + } +#endif + +#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) + CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); + vSync->OnClick.Add([=](EventParams &e) { + NativeResized(); + return UI::EVENT_CONTINUE; + }); +#endif + graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control"))); static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"}; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), gr->GetName(), screenManager())); @@ -441,33 +468,6 @@ void GameSettingsScreen::CreateViews() { } graphicsSettings->Add(new ItemHeader(gr->T("Performance"))); - static const char *internalResolutions[] = { "Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP", "6x PSP", "7x PSP", "8x PSP", "9x PSP", "10x PSP" }; - resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), gr->GetName(), screenManager())); - resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange); - resolutionChoice_->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects; - }); - -#if PPSSPP_PLATFORM(ANDROID) - if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) { - static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" }; - int max_res_temp = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2; - if (max_res_temp == 3) - max_res_temp = 4; // At least allow 2x - int max_res = std::min(max_res_temp, (int)ARRAY_SIZE(deviceResolutions)); - UI::PopupMultiChoice *hwscale = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAndroidHwScale, gr->T("Display Resolution (HW scaler)"), deviceResolutions, 0, max_res, gr->GetName(), screenManager())); - hwscale->OnChoice.Handle(this, &GameSettingsScreen::OnHwScaleChange); // To refresh the display mode - } -#endif - -#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) - CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); - vSync->OnClick.Add([=](EventParams &e) { - NativeResized(); - return UI::EVENT_CONTINUE; - }); -#endif - CheckBox *frameDuplication = graphicsSettings->Add(new CheckBox(&g_Config.bRenderDuplicateFrames, gr->T("Render duplicate frames to 60hz"))); frameDuplication->OnClick.Add([=](EventParams &e) { settingInfo_->Show(gr->T("RenderDuplicateFrames Tip", "Can make framerate smoother in games that run at lower framerates"), e.v); @@ -606,13 +606,6 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new PopupMultiChoice(&g_Config.iShowFPSCounter, gr->T("Show FPS Counter"), fpsChoices, 0, ARRAY_SIZE(fpsChoices), gr->GetName(), screenManager())); graphicsSettings->Add(new CheckBox(&g_Config.bShowDebugStats, gr->T("Show Debug Statistics")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting); - // Developer tools are not accessible ingame, so it goes here. - graphicsSettings->Add(new ItemHeader(gr->T("Debugging"))); - Choice *dump = graphicsSettings->Add(new Choice(gr->T("Dump next frame to log"))); - dump->OnClick.Handle(this, &GameSettingsScreen::OnDumpNextFrameToLog); - if (!PSP_IsInited()) - dump->SetEnabled(false); - // Audio LinearLayout *audioSettings = AddTab("GameSettingsAudio", ms->T("Audio")); @@ -1299,13 +1292,6 @@ UI::EventReturn GameSettingsScreen::OnHwScaleChange(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnDumpNextFrameToLog(UI::EventParams &e) { - if (gpu) { - gpu->DumpNextFrame(); - } - return UI::EVENT_DONE; -} - void GameSettingsScreen::update() { UIScreen::update(); From 01beb52f90002bb919f0b830381938a7d031df9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:12:01 +0100 Subject: [PATCH 385/715] Consolidate translation strings --- UI/DevScreens.cpp | 2 +- assets/lang/ar_AE.ini | 3 +-- assets/lang/az_AZ.ini | 3 +-- assets/lang/bg_BG.ini | 3 +-- assets/lang/ca_ES.ini | 3 +-- assets/lang/cz_CZ.ini | 3 +-- assets/lang/da_DK.ini | 3 +-- assets/lang/de_DE.ini | 3 +-- assets/lang/dr_ID.ini | 3 +-- assets/lang/es_ES.ini | 3 +-- assets/lang/es_LA.ini | 3 +-- assets/lang/fa_IR.ini | 3 +-- assets/lang/fi_FI.ini | 3 +-- assets/lang/fr_FR.ini | 3 +-- assets/lang/gl_ES.ini | 3 +-- assets/lang/gr_EL.ini | 3 +-- assets/lang/he_IL.ini | 3 +-- assets/lang/he_IL_invert.ini | 3 +-- assets/lang/hr_HR.ini | 3 +-- assets/lang/hu_HU.ini | 3 +-- assets/lang/id_ID.ini | 3 +-- assets/lang/it_IT.ini | 3 +-- assets/lang/ja_JP.ini | 3 +-- assets/lang/jv_ID.ini | 3 +-- assets/lang/ko_KR.ini | 3 +-- assets/lang/lo_LA.ini | 3 +-- assets/lang/lt-LT.ini | 3 +-- assets/lang/ms_MY.ini | 3 +-- assets/lang/nl_NL.ini | 3 +-- assets/lang/no_NO.ini | 3 +-- assets/lang/pl_PL.ini | 3 +-- assets/lang/pt_BR.ini | 3 +-- assets/lang/pt_PT.ini | 3 +-- assets/lang/ro_RO.ini | 3 +-- assets/lang/ru_RU.ini | 3 +-- assets/lang/sv_SE.ini | 3 +-- assets/lang/tg_PH.ini | 3 +-- assets/lang/th_TH.ini | 3 +-- assets/lang/tr_TR.ini | 3 +-- assets/lang/uk_UA.ini | 3 +-- assets/lang/vi_VN.ini | 3 +-- assets/lang/zh_CN.ini | 3 +-- assets/lang/zh_TW.ini | 3 +-- 43 files changed, 43 insertions(+), 85 deletions(-) diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 7e6bf0aac3..23b238848a 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -107,7 +107,7 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { } items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenuScreen::OnFreezeFrame); - items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenuScreen::OnDumpFrame); + items->Add(new Choice(dev->T("Dump next frame to log")))->OnClick.Handle(this, &DevMenuScreen::OnDumpFrame); items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenuScreen::OnToggleAudioDebug); #ifdef USE_PROFILER items->Add(new CheckBox(&g_Config.bShowFrameProfiler, dev->T("Frame Profiler"), "")); diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 2dc5aa69f1..381717f390 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -240,7 +240,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = ‎تفعيل سجل التصحيح Enter address = ‎أدخل العنوان @@ -497,7 +497,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = ‎التحكم في معدل الإطارات diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 383ec9b5d4..eeffab31c0 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 853d40a580..4ee8a0dacb 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = Кадри в сек. Frame Rate Control = Framerate control diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 393796df05..21862b3eb9 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Aboca «EBOOT.BIN» desxifrat quan s'iniciï el joc -Dump Frame GPU Commands = Aboca ordres del marc GPU +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Activa el registre Enter address = Inseriu adreça @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 78ce12bd2e..aba4d3d3f9 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Vypsat dešifrovaný EBOOT.BIN při načtení hry -Dump Frame GPU Commands = Vypsat příkazy snímku pro grafický procesor +Dump next frame to log = Vypsat příští snímek do záznamu Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Povolit záznam při ladění Enter address = Zadejte adresu @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Zobrazit editor rozvržení Display Resolution (HW scaler) = Rozlišení obrazovky (Hardwarové zvětšení) -Dump next frame to log = Vypsat příští snímek do záznamu Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Kontrola frekvence snímků diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 02e61c6366..8a8b8d9665 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump dekrypteret EBOOT.BIN ved spil boot -Dump Frame GPU Commands = Drop frame GPU kommandoer +Dump next frame to log = Gem næste frame i loggen Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Aktiver fejlfindingslogning Enter address = Indtast adresse @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Skærmopløsning (HW scaler) -Dump next frame to log = Gem næste frame i loggen Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Frameratekontrol diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index bb01cfeacd..ad40e018c8 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -232,7 +232,7 @@ DevMenu = Entwicklermenü Disabled JIT functionality = Deaktivierte JIT Funktionalität Draw Frametimes Graph = Zeichne frametimes Graphen Dump Decrypted Eboot = Entschlüsselte EBOOT.BIN abspeichern (falls verschlüsselt) -Dump Frame GPU Commands = GPU Befehle des Frames ausgeben +Dump next frame to log = Nächsten Frame im Log speichern Enable driver bug workarounds = Aktiviere Driver-Fehler workarounds Enable Logging = Aktiviere Logging Enter address = Adresse eingeben @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Deaktiviert Display layout editor = Bildschirmlayout Editor Display Resolution (HW scaler) = Bildschirmauflösung (HW Skalierung) -Dump next frame to log = Nächsten Frame im Log speichern Enable Cardboard VR = Cardboard VR aktivieren FPS = FPS Frame Rate Control = Frameratenkontrolle diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 1988cada18..c9b2d4f724 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Palakoi log to gambara' undipa Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Padenni Log Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Palakoi log to gambara' undipa Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Atoro'i FRna diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 7d587aa8e3..f50bb31558 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Desactivar funcionalidad JIT Draw Frametimes Graph = Dibujar gráfico de cuadros Dump Decrypted Eboot = Volcar "EBOOT.BIN" descifrado al iniciar el juego -Dump Frame GPU Commands = Volcar comandos GPU del cuadro +Dump next frame to log = Volcar siguiente cuadro al registro Enable driver bug workarounds = Activar arreglos alternativos para fallos de drivers Enable Logging = Activar registro Enter address = Insertar dirección @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Desactivado Display layout editor = Editor del área de pantalla Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) -Dump next frame to log = Volcar siguiente cuadro al registro Enable Cardboard VR = Activar Cardboard VR FPS = FPS Frame Rate Control = Control de tasa de cuadros (FPS) diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 59019321b3..185c56837a 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -232,7 +232,7 @@ DevMenu = Menú Depuración Disabled JIT functionality = Apagar funcionalidad de JIT Draw Frametimes Graph = Mostrar gráfica de tiempos de frames Dump Decrypted Eboot = Volcar EBOOT.BIN descifrado al iniciar el juego -Dump Frame GPU Commands = Volcar comandos GPU del cuadro +Dump next frame to log = Volcar siguiente cuadro al registro Enable driver bug workarounds = Activar arreglos alternativos para fallos de drivers Enable Logging = Activar registro Enter address = Insertar dirección @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Apagado Display layout editor = Editor del área de pantalla Display Resolution (HW scaler) = Resolución de pantalla (escalado por HW) -Dump next frame to log = Volcar siguiente cuadro al registro Enable Cardboard VR = Activar Cardboard VR FPS = FPS Frame Rate Control = Control de Framerate diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 925f48c1a7..a1ccb5729a 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = ‎ریختن فریم بعدی به فایل لاگ Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = ‎روشن کردن لاگ باگ ها Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = ‎ویرایشگر چیدمان صفحه Display Resolution (HW scaler) = ‎رزولوشن صفحه -Dump next frame to log = ‎ریختن فریم بعدی به فایل لاگ Enable Cardboard VR = Enable Cardboard VR FPS = ‎فریم بر ثانیه Frame Rate Control = ‎کنترل سرعت فریم diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 6d3d8eb412..8cccf303c1 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ota virheenkorjauksen kirjaaminen käyttöön Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 8f4dd25f7e..ac00e20090 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -232,7 +232,7 @@ DevMenu = MenuDev Disabled JIT functionality = Fonctionnalité JIT désactivée Draw Frametimes Graph = Dessiner le graphique des temps d'image Dump Decrypted Eboot = Créer un EBOOT.BIN déchiffré au lancement du jeu -Dump Frame GPU Commands = Dump des commandes GPU de l'image +Dump next frame to log = Dump de l'image suivante dans le journal Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Activer le journal de débogage Enter address = Entrer une adresse @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Désactivé Display layout editor = Éditeur d'affichage Display Resolution (HW scaler) = Définition d'affichage (mise à l'échelle matérielle) -Dump next frame to log = Dump de l'image suivante dans le journal Enable Cardboard VR = Activer Cardboard VR FPS = FPS Frame Rate Control = Contrôle de la fréquence de rafraîchissement des images diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 1ec4ad468d..1ea3f50876 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Volcar EBOOT.BIN descifrado ó iniciar o xogo -Dump Frame GPU Commands = Volcar comandos GPU do cadro +Dump next frame to log = Volcar seguinte cadro ó rexistro Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Activar rexistro Enter address = Insertar dirección @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) -Dump next frame to log = Volcar seguinte cadro ó rexistro Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Control de tasa de cadros (FPS) diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 38f61cd2a0..5b199aab8f 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Εξαγωγή αποκρυπτογραφημένου EBOOT.BIN κατά την έναρξη -Dump Frame GPU Commands = Εξαγωγή εντολών frame GPU +Dump next frame to log = Αποτύπωση πλαισίου σε καταγραφέα Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ενεργοποίηση καταγραφής αποσφαλμάτωσης Enter address = Διεύθυνση Enter @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Απενεργοποιημένο Display layout editor = Επεξεργασία διάταξης οθόνης Display Resolution (HW scaler) = Ανάλυση οθόνης (Κλιμακοτής hardware) -Dump next frame to log = Αποτύπωση πλαισίου σε καταγραφέα Enable Cardboard VR = Ενεργοποίηση Cardboard VR FPS = FPS Frame Rate Control = Ρυθμίσεις Ρυθμού Καρέ diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index ecad06a830..86c86d4f24 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = בחר את הפריים הבא כדי לדווח Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = אפשר דיווח באגים Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = בחר את הפריים הבא כדי לדווח Enable Cardboard VR = Enable Cardboard VR FPS = כמות פריימים לשנייה Frame Rate Control = שליטה על קצב פריימים diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 97fb5347a6..3792056b37 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = חוודל ידכ אבה םיירפה תא רחב Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = םיגאב חוויד רשפא Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = חוודל ידכ אבה םיירפה תא רחב Enable Cardboard VR = Enable Cardboard VR FPS = היינשל םימיירפ תומכ Frame Rate Control = םימיירפ בצק לע הטילש diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 5fc79d26e0..66e78c5c80 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Isključena JIT funkcionalnost Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Odbaci sljedeći frame u log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Uključi debug logging Enter address = Upiši adresu @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Isključeno Display layout editor = Prikaz layout uređivača Display Resolution (HW scaler) = Prikaz rezolucije (HW mjeritelj) -Dump next frame to log = Odbaci sljedeći frame u log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate kontrole diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index c5f9433ce2..9ba8b050bb 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Kikapcsolt JIT funkcionalitások Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Visszafejtett EBOOT.BIN írása játék indításakor -Dump Frame GPU Commands = Képkocka GPU parancsok írása +Dump next frame to log = Következő képkocka kiírása naplófájlba Enable Logging = Naplózás engedélyezése Enable driver bug workarounds = Enable driver bug workarounds Enter address = Cím megadása @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Letiltva Display layout editor = Elrendezés szerkesztő Display Resolution (HW scaler) = Megjelenítési felbontás (HW skálázó) -Dump next frame to log = Következő képkocka kiírása naplófájlba Enable Cardboard VR = Cardboard VR engedélyezése FPS = FPS Frame Rate Control = Képkocka sebesség szabályozása diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 3e75cd0a93..e46f6299a0 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -232,7 +232,7 @@ DevMenu = Menu pengembang Disabled JIT functionality = Fungsi JIT dinonaktifkan Draw Frametimes Graph = Gambar grafis sketsa waktu Dump Decrypted Eboot = Buang EBOOT.BIN yang didekripsi pada pengaktifan ulang permainan -Dump Frame GPU Commands = Buang perintah laju bingkai GPU +Dump next frame to log = Buang laju bingkai selanjutnya untuk masuk Enable driver bug workarounds = Aktifkan solusi masalah driver Enable Logging = Hidupkan pencatat awakutu Enter address = Masukkan alamat @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Nonaktif Display layout editor = Penyesuaian tata letak tampilan Display Resolution (HW scaler) = Resolusi tampilan (penskala HW) -Dump next frame to log = Buang laju bingkai selanjutnya untuk masuk Enable Cardboard VR = Aktifkan Cardboard VR FPS = FPS Frame Rate Control = Kontrol laju bingkai diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index ed9fda0f09..17decf0dc1 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disattivata Funzionalità JIT Draw Frametimes Graph = Disegna grafica dei frametimes Dump Decrypted Eboot = Crea EBOOT.BIN decriptato all'avvio del gioco -Dump Frame GPU Commands = Comandi GPU Dump frame +Dump next frame to log = Crea Log del Frame Successivo Enable driver bug workarounds = Abilita espediente per superare i bug dei driver Enable Logging = Attiva Log del Debug Enter address = Inserire indirizzo @@ -490,7 +490,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabilitato Display layout editor = Editor Display Display Resolution (HW scaler) = Risoluzione Display (scaler HW) -Dump next frame to log = Crea Log del Frame Successivo Enable Cardboard VR = Attiva Cardboard VR FPS = FPS Frame Rate Control = Controllo Framerate diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index cc152ab6f3..ebab479d65 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -232,7 +232,7 @@ DevMenu = 開発者用メニュー Disabled JIT functionality = 無効されたJIT機能 Draw Frametimes Graph = フレームタイムグラフを描く Dump Decrypted Eboot = 復号したEBOOT.BINを起動時にダンプする -Dump Frame GPU Commands = フレームGPUコマンドをダンプする +Dump next frame to log = 次のフレームをログにダンプする Enable driver bug workarounds = ドライバーバグの回避の有効化 Enable Logging = デバッグログを有効にする Enter address = アドレスを入力する @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = 無効 Display layout editor = 画面のレイアウトを編集する Display Resolution (HW scaler) = 画面解像度 (HWスケーラー) -Dump next frame to log = 次のフレームをログにダンプする Enable Cardboard VR = Cardboard VRを有効にする FPS = FPS Frame Rate Control = フレームレートのコントロール diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 43b9d219cb..b9c0a7a7ed 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Mbucal EBOOT.BIN decrypted ing boot dolanan -Dump Frame GPU Commands = Mbucal printah pigura GPU +Dump next frame to log = Mbucal pigura jejere log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ngatifke ngangkut barang Enter address = Ketik alamat @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Tata letak Tampilan editor Display Resolution (HW scaler) = Resolusi tampilan (HW scaler) -Dump next frame to log = Mbucal pigura jejere log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Kontrol Frame-rate diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index c9074383ce..a1ccd3ee35 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -232,7 +232,7 @@ DevMenu = 개발메뉴 Disabled JIT functionality = 비활성화된 JIT 기능 Draw Frametimes Graph = 프레임 시간 그래프 그리기 Dump Decrypted Eboot = 게임 부팅 시 해독된 EBOOT.BIN 덤프 -Dump Frame GPU Commands = 덤프 프레임 GPU 명령 +Dump next frame to log = 다음 프레임을 로그로 덤프 Enable driver bug workarounds = 드라이버 버그 해결 방법 활성화 Enable Logging = 디버그 로깅 활성화 Enter address = 주소 입력 @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = 비활성화 Display layout editor = 화면 레이아웃 편집기 Display Resolution (HW scaler) = 화면 해상도(HW 스케일러) -Dump next frame to log = 다음 프레임을 로그로 덤프 Enable Cardboard VR = 카드보드 VR 활성화 FPS = FPS Frame Rate Control = 프레임속도 제어 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 64f175d367..64e14396e7 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = ດຶງໄຟລ໌ EBOOT.BIN ອອກມາເກັບໄວ້ເມື່ອເລີ່ມເກມ -Dump Frame GPU Commands = ດຶງຄ່າເຟຣມຄຳສັ່ງຂອງ GPU +Dump next frame to log = ດຶງຂໍ້ມູນຂອງເຟຣມຕໍ່ໄປເພື່ອເກັບບັນທຶກຄ່າ Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = ເປີດໃຊ້ງານ logging Enter address = ໃສ່ຄ່າທີ່ຢູ່ @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = ແກ້ໄຂຮູບແບບໜ້າຈໍ Display Resolution (HW scaler) = ຄວາມລະອຽດໜ້າຈໍ (ຕາມຮາດແວຣ໌) -Dump next frame to log = ດຶງຂໍ້ມູນຂອງເຟຣມຕໍ່ໄປເພື່ອເກັບບັນທຶກຄ່າ Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = ຄວບຄຸມເຟຣມເຣດ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index b2d3a3c81f..9f0ab2a8fa 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = "Rašyti" atrakintą "EBOOT.BIN" failą žaidimui kraunantis -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = "Rašyti" kitą kadrą į statusą Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Įjungti testinio režimo statuso rašymą į failus Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Ekrano rezoliucija ("HW" ištiesinimas) -Dump next frame to log = "Rašyti" kitą kadrą į statusą Enable Cardboard VR = Enable Cardboard VR FPS = Kadrai per sekundę Frame Rate Control = Kadrų kontrolė diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 32dc995720..3418284348 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Fungsi JIT yang dilumpuhkan Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Letak frame berikutnya ke log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Upayakan log pepijat Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Letak frame berikutnya ke log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Kawalan kadar Frame diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 9ec6b9a017..0eaaae39f4 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -232,7 +232,7 @@ DevMenu = Ontwikkelaarsmenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Gedecodeerde EBOOT.BIN opslaan tijdens starten -Dump Frame GPU Commands = FPU-commando's van frame opslaan +Dump next frame to log = Volgende frame in logboek plaatsen Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Foutlogboek inschakelen Enter address = Adres invoeren @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Schermweergave bewerken Display Resolution (HW scaler) = Schermresolutie (hardware) -Dump next frame to log = Volgende frame in logboek plaatsen Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerateinstellingen diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 5baf3a6c55..a13dce63ec 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Debugloggning Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 98ffd7fd04..7c1f5b1abd 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Wyłącz funkcje JIT Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Zachowuj odszyfrowany EBOOT.BIN przy starcie -Dump Frame GPU Commands = Zrzuć klatkę komend GPU +Dump next frame to log = Zrzuć następną klatkę do dziennika zdarzeń Enable driver bug workarounds = Uruchom obejścia błędów sterownika Enable Logging = Włącz dziennik zdarzeń debugera Enter address = Wprowadź adres @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Wył. Display layout editor = Edytor położenia obrazu Display Resolution (HW scaler) = Rozdzielczość ekranu (skaler sprz.) -Dump next frame to log = Zrzuć następną klatkę do dziennika zdarzeń Enable Cardboard VR = Enable Cardboard VR FPS = Tylko FPS Frame Rate Control = Kontrola klatek na sekundę diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 7827800c21..8718270edb 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -256,7 +256,7 @@ DevMenu = Menu do DEV Disabled JIT functionality = Funcionalidade do JIT desativada Draw Frametimes Graph = Desenhar gráfico dos tempos dos frames Dump Decrypted Eboot = Dumpar EBOOT.BIN decriptado no boot do jogo -Dump Frame GPU Commands = Dumpar comandos dos frames da GPU +Dump next frame to log = Dumpa o próximo frame no log Enable driver bug workarounds = Ativar soluções alternativas pros bugs dos drivers Enable Logging = Ativar log do debug Enter address = Inserir endereço @@ -513,7 +513,6 @@ Direct3D 11 = Direct3D 11 Disabled = Desativado Display layout editor = Exibe o editor dos esquemas Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) -Dump next frame to log = Dumpa o próximo frame no log Enable Cardboard VR = Ativa o VR Cardboard FPS = FPS Frame Rate Control = Controle da taxa dos frames diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 21262dea6e..a36495e779 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -256,7 +256,7 @@ DevMenu = Menu de Desenvolvedor Disabled JIT functionality = Funcionalidade do JIT desabilitada Draw Frametimes Graph = Desenhar gráfico dos tempos dos quadros Dump Decrypted Eboot = Guardar EBOOT.BIN decriptado no boot do jogo -Dump Frame GPU Commands = Guardar comandos dos quadros da GPU +Dump next frame to log = Guardar o próximo frame no log Enable driver bug workarounds = Ativar soluções alternativas para erros dos Drivers Enable Logging = Ativar log do depurador Enter address = Inserir endereço @@ -513,7 +513,6 @@ Direct3D 11 = Direct3D 11 Disabled = Desativado Display layout editor = Mostrar o editor dos esquemas Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) -Dump next frame to log = Guardar o próximo frame no log Enable Cardboard VR = Ativar o VR Cardboard FPS = FPS (Quadros Por Segundo) Frame Rate Control = Controle da taxa dos quadros diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 22bc711b1d..64cfe450d5 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Rezoluție ecran (scalare HW) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Control rată de cadre diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index a3a421559c..a9fa079e3c 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -232,7 +232,7 @@ DevMenu = Меню разраб. Disabled JIT functionality = Отключение функционала JIT Draw Frametimes Graph = Отрисовывать график времени кадров Dump Decrypted Eboot = Дамп дешифрованного EBOOT.BIN при запуске -Dump Frame GPU Commands = Сохранить команды ГП для кадра +Dump next frame to log = Сохранить следующий кадр в логе Enable driver bug workarounds = Включить обход багов драйвера Enable Logging = Включить отладочное логирование Enter address = Ввести адрес @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Отключено Display layout editor = Редактор расположения экрана Display Resolution (HW scaler) = Разрешение экрана (аппаратное) -Dump next frame to log = Сохранить следующий кадр в логе Enable Cardboard VR = Включить Cardboard VR #Features = Возможности FPS = FPS diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 2e38abbc3b..e0ddb1c0f1 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dumpa decrypterad EBOOT.BIN när spelet startar -Dump Frame GPU Commands = Dumpa GPU-kommandon för en frame +Dump next frame to log = Dumpa nästa frame till log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Debugloggning Enter address = Address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Avstängd Display layout editor = Skärmlayouteditor Display Resolution (HW scaler) = Skärmupplösning (HW scaler) -Dump next frame to log = Dumpa nästa frame till log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate-kontroll diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 624644a464..0b894f0e4b 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -232,7 +232,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = I-refresh ang set-up Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Paganahin ang Debug Logging Enter address = Ilagay ang address @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = Display layout editor Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = I-refresh ang set-up Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Pag kontrol ng frame rate diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 20a42b064d..a42da9ebac 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -232,7 +232,7 @@ DevMenu = เมนูผู้พัฒนา Disabled JIT functionality = ปิดฟังก์ชั่นการทำงานของระบบ JIT Draw Frametimes Graph = กราฟแสดงจำนวนเฟรม Dump Decrypted Eboot = ดึงไฟล์ EBOOT.BIN ออกมาเก็บไว้เมื่อเริ่มเกม -Dump Frame GPU Commands = ดึงค่าเฟรมคำสั่งของ GPU +Dump next frame to log = ดึงข้อมูลของเฟรมถัดไปเก็บบันทึกค่า Enable Logging = เปิดใช้งานการเก็บค่าแก้ไขจุดบกพร่อง Enable driver bug workarounds = เปิดใช้งานการแก้ขัดปัญหาไดรเวอร์บั๊ก Enter address = ใส่ค่าที่อยู่ @@ -489,7 +489,6 @@ Direct3D 11 = ไดเร็คท์ 3D 11 Disabled = ปิดการใช้งาน Display layout editor = แก้ไขรูปแบบของหน้าจอ Display Resolution (HW scaler) = ความละเอียดหน้าจอ (ตามฮาร์ดแวร์) -Dump next frame to log = ดึงข้อมูลของเฟรมถัดไปเก็บบันทึกค่า Enable Cardboard VR = เปิดการทำงานแว่นการ์ดบอร์ด VR FPS = เฟรมต่อวิ Frame Rate Control = การควบคุมเฟรมเรท diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 6183381f8b..ab9bfb4eb5 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -234,7 +234,7 @@ DevMenu = DevMenu Disabled JIT functionality = JIT işlevselliğini devre dışı bırakın Draw Frametimes Graph = Kare süreleri grafiğini çizin Dump Decrypted Eboot = Şifresi çözülmüş EBOOT.BIN'i oyun açılışında temizleyin -Dump Frame GPU Commands = Kare GPU komutlarını temizleyin +Dump next frame to log = Sonraki kareyi günlüğe dökümle Enable driver bug workarounds = Sürücü hatası geçici çözümlerini etkinleştirin Enable Logging = Hata ayıklama günlüğünü etkinleştirin Enter address = Adres Gir @@ -491,7 +491,6 @@ Direct3D 11 = Direct3D 11 Disabled = Devre dışı Display layout editor = Görüntü Düzeni Düzenleyicisi Display Resolution (HW scaler) = Görüntü Çözünürlüğü (HW scaler) -Dump next frame to log = Sonraki kareyi günlüğe dökümle Enable Cardboard VR = Cardboard VR'ı Etkinleştirin FPS = FPS Frame Rate Control = Kare hızı denetimi diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index d27fc056b1..d1f5687288 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -232,7 +232,7 @@ DevMenu = Меню розроб. Disabled JIT functionality = Вимкнений функціонал JIT Draw Frametimes Graph = Намалюйте графік фрагментів Dump Decrypted Eboot = Дамп дешифрування Eboot.bin при паузі -Dump Frame GPU Commands = Дамп команд GPU кадру +Dump next frame to log = Зберегти кадр у лог Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ввімкнути логування Enter address = Введіть адресу @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Вимкнено Display layout editor = Редактор розташування екрану Display Resolution (HW scaler) = Розширення екрану (HW масштабування) -Dump next frame to log = Зберегти кадр у лог Enable Cardboard VR = Увімкнути Cardboard VR FPS = FPS Frame Rate Control = Управління частотою кадрів diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 0aeebfb027..b1042a00b1 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -232,7 +232,7 @@ DevMenu = Menu NPH Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Đưa file vào EBOOT.BIN để khởi động trò chơi -Dump Frame GPU Commands = Đưa lệnh vào khung GPU +Dump next frame to log = Đưa khung hình kế tiếp vào nhật ký Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Cho phép ghi nhật ký debug Enter address = Nhập địa chỉ @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Vô hiệu hóa Display layout editor = Chỉnh bố trí hiển thị Display Resolution (HW scaler) = Độ phân giải màn hình (HW scaler) -Dump next frame to log = Đưa khung hình kế tiếp vào nhật ký Enable Cardboard VR = Enable Cardboard VR FPS = FPS (khung hình/giây) Frame Rate Control = Điều khiển tốc độ khung hình diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index f51aa2c856..20fdb30bc0 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -232,7 +232,7 @@ DevMenu = 开发者菜单 Disabled JIT functionality = 已禁用的JIT功能 Draw Frametimes Graph = 显示帧时间统计图 Dump Decrypted Eboot = 当载入游戏时转储已解密的EBOOT.BIN -Dump Frame GPU Commands = 转储帧GPU命令 +Dump next frame to log = 转储下一帧到日志 Enable driver bug workarounds = 启用驱动程序错误解决方法 Enable Logging = 启用调试日志 Enter address = 输入地址 @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = 禁用 Display layout editor = 显示布局编辑器 Display Resolution (HW scaler) = 显示分辨率(硬件缩放) -Dump next frame to log = 转储下一帧到日志 Enable Cardboard VR = 启用Cardboard VR FPS = 每秒帧数 (FPS) Frame Rate Control = 帧率控制 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index d3ecc84266..548fb04764 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -232,7 +232,7 @@ DevMenu = 開發選單 Disabled JIT functionality = 停用 JIT 功能 Draw Frametimes Graph = 繪製影格時間圖形 Dump Decrypted Eboot = 遊戲啟動時傾印已解密的 EBOOT.BIN -Dump Frame GPU Commands = 傾印影格 GPU 命令 +Dump next frame to log = 將下一個影格傾印至記錄 Enable driver bug workarounds = 啟用驅動程式錯誤因應措施 Enable Logging = 啟用偵錯記錄 Enter address = 輸入位址 @@ -489,7 +489,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display layout editor = 顯示版面配置編輯器 Display Resolution (HW scaler) = 顯示解析度 (硬體縮放) -Dump next frame to log = 將下一個影格傾印至記錄 Enable Cardboard VR = 啟用 Cardboard VR FPS = FPS Frame Rate Control = 影格速率控制 From 6df5b5acb6abff8dfc692ec1c136fbc72e77dd3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:13:49 +0100 Subject: [PATCH 386/715] Move more common settings to top --- UI/GameSettingsScreen.cpp | 73 +++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index d7b71b34a5..24e160ce6a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -330,6 +330,42 @@ void GameSettingsScreen::CreateViews() { }); #endif + if (deviceType != DEVICE_TYPE_VR) { +#if !defined(MOBILE_DEVICE) + graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); + if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { + CheckBox *fullscreenMulti = new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays")); + fullscreenMulti->SetEnabledFunc([] { + return g_Config.UseFullScreen(); + }); + graphicsSettings->Add(fullscreenMulti)->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenMultiChange); + } +#endif + // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. + displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor"))); + displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + screenManager()->push(new DisplayLayoutScreen(gamePath_)); + return UI::EVENT_DONE; + }); + +#if PPSSPP_PLATFORM(ANDROID) + // Hide insets option if no insets, or OS too old. + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 28 && + (System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) != 0.0f)) { + graphicsSettings->Add(new CheckBox(&g_Config.bIgnoreScreenInsets, gr->T("Ignore camera notch when centering"))); + } + + // Hide Immersive Mode on pre-kitkat Android + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) { + // Let's reuse the Fullscreen translation string from desktop. + graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange); + } +#endif + } + graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control"))); static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"}; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), gr->GetName(), screenManager())); @@ -430,43 +466,6 @@ void GameSettingsScreen::CreateViews() { } } - if (deviceType != DEVICE_TYPE_VR) { - graphicsSettings->Add(new ItemHeader(gr->T("Screen layout"))); -#if !defined(MOBILE_DEVICE) - graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); - if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { - CheckBox *fullscreenMulti = new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays")); - fullscreenMulti->SetEnabledFunc([] { - return g_Config.UseFullScreen(); - }); - graphicsSettings->Add(fullscreenMulti)->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenMultiChange); - } -#endif - // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. - displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor"))); - displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { - screenManager()->push(new DisplayLayoutScreen(gamePath_)); - return UI::EVENT_DONE; - }); - -#if PPSSPP_PLATFORM(ANDROID) - // Hide insets option if no insets, or OS too old. - if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 28 && - (System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) != 0.0f || - System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) != 0.0f || - System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) != 0.0f || - System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) != 0.0f)) { - graphicsSettings->Add(new CheckBox(&g_Config.bIgnoreScreenInsets, gr->T("Ignore camera notch when centering"))); - } - - // Hide Immersive Mode on pre-kitkat Android - if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) { - // Let's reuse the Fullscreen translation string from desktop. - graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange); - } -#endif - } - graphicsSettings->Add(new ItemHeader(gr->T("Performance"))); CheckBox *frameDuplication = graphicsSettings->Add(new CheckBox(&g_Config.bRenderDuplicateFrames, gr->T("Render duplicate frames to 60hz"))); frameDuplication->OnClick.Add([=](EventParams &e) { From 2e0feb4efe2c360e7b7fe1d6efa0782bf4223db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:14:01 +0100 Subject: [PATCH 387/715] Remove unneeded translation string --- assets/lang/ar_AE.ini | 1 - assets/lang/az_AZ.ini | 1 - assets/lang/bg_BG.ini | 1 - assets/lang/ca_ES.ini | 1 - assets/lang/cz_CZ.ini | 1 - assets/lang/da_DK.ini | 1 - assets/lang/de_DE.ini | 1 - assets/lang/dr_ID.ini | 1 - assets/lang/es_ES.ini | 1 - assets/lang/es_LA.ini | 1 - assets/lang/fa_IR.ini | 1 - assets/lang/fi_FI.ini | 1 - assets/lang/fr_FR.ini | 1 - assets/lang/gl_ES.ini | 1 - assets/lang/gr_EL.ini | 1 - assets/lang/he_IL.ini | 1 - assets/lang/he_IL_invert.ini | 1 - assets/lang/hr_HR.ini | 1 - assets/lang/hu_HU.ini | 1 - assets/lang/id_ID.ini | 1 - assets/lang/it_IT.ini | 1 - assets/lang/ja_JP.ini | 1 - assets/lang/jv_ID.ini | 1 - assets/lang/ko_KR.ini | 1 - assets/lang/lo_LA.ini | 1 - assets/lang/lt-LT.ini | 1 - assets/lang/ms_MY.ini | 1 - assets/lang/nl_NL.ini | 1 - assets/lang/no_NO.ini | 1 - assets/lang/pl_PL.ini | 1 - assets/lang/pt_BR.ini | 1 - assets/lang/pt_PT.ini | 1 - assets/lang/ro_RO.ini | 1 - assets/lang/ru_RU.ini | 1 - assets/lang/sv_SE.ini | 1 - assets/lang/tg_PH.ini | 1 - assets/lang/th_TH.ini | 1 - assets/lang/tr_TR.ini | 1 - assets/lang/uk_UA.ini | 1 - assets/lang/vi_VN.ini | 1 - assets/lang/zh_CN.ini | 1 - assets/lang/zh_TW.ini | 1 - 42 files changed, 42 deletions(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 381717f390..6906884d20 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -548,7 +548,6 @@ Rendering Resolution = ‎حجم التصيير RenderingMode NonBuffered Tip = ‎أسرع, لكن يمكن أن لا يظهر أي شئ في بعض الألعاب Rotation = ‎الدوران Safe = ‎أمن -Screen layout = Screen layout Screen Scaling Filter = ‎فلتر تكبير حجم الشاشة Show Debug Statistics = ‎أظهر معلومات التصحيح Show FPS Counter = ‎أظهر عداد الـFPS diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index eeffab31c0..2fa30be8d3 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 4ee8a0dacb..fe99615ac6 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Покажи debug инфо Show FPS Counter = Покажи брояча за кадри в сек. diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 21862b3eb9..7e93b3b4dd 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index aba4d3d3f9..81dbf5aa2d 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rozlišení vykreslování RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Otočení Safe = Bezpečné -Screen layout = Screen layout Screen Scaling Filter = Filtr změny velikosti obrazovky Show Debug Statistics = Zobrazit statistiky ladění Show FPS Counter = Zobrazit počítadlo diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 8a8b8d9665..fa05f3da14 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -540,7 +540,6 @@ Rendering Resolution = Render opløsning RenderingMode NonBuffered Tip = Hurtigere, men intet vises i nogle spil Rotation = Rotation Safe = Sikker -Screen layout = Screen layout Screen Scaling Filter = Skærmskaleringsfilter Show Debug Statistics = Vis debugstatistik Show FPS Counter = Vis FPS diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index ad40e018c8..b9af72f822 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -540,7 +540,6 @@ Rendering Resolution = Renderauflösung RenderingMode NonBuffered Tip = Schneller, aber keine Anzeige in einigen Spielen Rotation = Drehung Safe = Sicher -Screen layout = Screen layout Screen Scaling Filter = Filter für Bildskalierung Show Debug Statistics = Debugstatistiken anzeigen Show FPS Counter = FPS anzeigen diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index c9b2d4f724..0ec1b8acd1 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Padenni Debugna Show FPS Counter = Padenni FPSna diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index f50bb31558..a323b90b1a 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -540,7 +540,6 @@ Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Rápido, pero no se verá nada en algunos juegos. Rotation = Rotación Safe = Seguro -Screen layout = Diseño de pantalla Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 185c56837a..978465cdef 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -540,7 +540,6 @@ Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Acelera, pero no podrá generar gráficos en algunos juegos. Rotation = Rotación Safe = Seguro -Screen layout = Disposición de pantalla Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index a1ccb5729a..3dcef7b698 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -540,7 +540,6 @@ Rendering Resolution = ‎رزولوشن رندرینگ RenderingMode NonBuffered Tip = ‎سریع تر، اما در بعضی بازی ها ممکن است چیزی نشان ندهد Rotation = ‎چرخش Safe = ‎امن -Screen layout = Screen layout Screen Scaling Filter = ‎فیلتر تغییر ساز صفحه Show Debug Statistics = ‎نمایش اطلاعات دیباگ Show FPS Counter = ‎نمایش شمارنده فریم بر ثانیه diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 8cccf303c1..f0b1b957a9 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Näytä virheenkorjaustilastot Show FPS Counter = Näytä FPS-laskuri diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index ac00e20090..06a5dde549 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -540,7 +540,6 @@ Rendering Resolution = Définition du rendu RenderingMode NonBuffered Tip = Plus rapide, mais pour certains jeux rien ne s'affichera Rotation = Rotation Safe = Prudent -Screen layout = Disposition de l'écran Screen Scaling Filter = Filtre de mise à l'échelle de l'écran Show Debug Statistics = Montrer les statistiques de débogage Show FPS Counter = Montrer les compteurs diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 1ea3f50876..9ffa57c477 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -540,7 +540,6 @@ Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Seguro -Screen layout = Screen layout Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 5b199aab8f..29408a0887 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -540,7 +540,6 @@ Rendering Resolution = Ανάλυση Απεικόνισης RenderingMode NonBuffered Tip = Γρηγορότερο, αλλά σε μερικά αιχνίδια μπορεί να μην εμφανίζει τίποτα Rotation = Περιστροφή Safe = Ασφαλής -Screen layout = Screen layout Screen Scaling Filter = Φίλτο κλιμάκωσης οθόνης Show Debug Statistics = Εμφάνιση στατιστικών αποσφαλμάτωσης Show FPS Counter = Εμφάνιση μετρητή FPS diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 86c86d4f24..b4aa66d602 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = הצג סטטיסטיקת באגים Show FPS Counter = הצג מונה diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 3792056b37..49ef7404b5 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = םיגאב תקיטסיטטס גצה Show FPS Counter = הנומ גצה diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 66e78c5c80..8335b02963 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rezolucija prikaza RenderingMode NonBuffered Tip = Brže, ali ništa može uvući neke igre Rotation = Rotacija Safe = Sigurno -Screen layout = Screen layout Screen Scaling Filter = Mjerenje filtriranje zaslona Show Debug Statistics = Pokaži statistike otklanjanja grešaka Show FPS Counter = Pokaži FPS counter diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 9ba8b050bb..4a351724f2 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -540,7 +540,6 @@ Rendering Resolution = Renderelés felbontása RenderingMode NonBuffered Tip = Gyorsabb, de egyes játékokban nem rajzol ki semmit. Rotation = Forgatás Safe = Biztonságos -Screen layout = Screen layout Screen Scaling Filter = Képernyő skálázási szűrő Show Debug Statistics = Hibakeresési statisztikák mutatása Show FPS Counter = FPS számláló mutatása diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index e46f6299a0..5322e8c54a 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -540,7 +540,6 @@ Rendering Resolution = Resolusi pelukisan RenderingMode NonBuffered Tip = Lebih cepat, namun mungkin tidak ada gambar di beberapa permainan Rotation = Rotasi Safe = Aman -Screen layout = Tata letak layar Screen Scaling Filter = Pemfilteran penskala layar Show Debug Statistics = Tampilkan statistik awakutu Show FPS Counter = Tampilkan penghitung FPS diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 17decf0dc1..66d98e4e13 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -541,7 +541,6 @@ Rendering Resolution = Rendering della Risoluzione RenderingMode NonBuffered Tip = Veloce, ma potrebbe generare dei glitch in alcuni giochi Rotation = Rotazione Safe = Sicuro -Screen layout = Disposizione dello schermo Screen Scaling Filter = Filtro Scalatura Schermo Show Debug Statistics = Mostra Statistiche Debug Show FPS Counter = Mostra FPS diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index ebab479d65..36266a6d7f 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -540,7 +540,6 @@ Rendering Resolution = レンダリング解像度 RenderingMode NonBuffered Tip = 高速ですが何も表示されなくなるゲームがあるかもしれません Rotation = 向き Safe = セーフ -Screen layout = 画面のレイアウト Screen Scaling Filter = 画像スケーリングのフィルタ Show Debug Statistics = デバッグ情報を表示する Show FPS Counter = FPSを表示する diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index b9c0a7a7ed..22677ae81e 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering résolusi RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotasi Safe = Aman -Screen layout = Screen layout Screen Scaling Filter = Layar njongko Filter Show Debug Statistics = Tampilno statistik debug Show FPS Counter = Tampilno penghitung FPS diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index a1ccd3ee35..f955213c14 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -539,7 +539,6 @@ Rendering Resolution = 렌더링 해상도 RenderingMode NonBuffered Tip = 더 빠르지만 일부 게임에서는 아무 것도 표현되지 않을 수 있습니다. Rotation = 회전 Safe = 안전 -Screen layout = 화면 레이아웃 Screen Scaling Filter = 화면 크기 조정 필터 Show Debug Statistics = 디버그 통계 표시 Show FPS Counter = FPS 카운터 표시 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 64e14396e7..c78d18ea43 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -540,7 +540,6 @@ Rendering Resolution = ຄວາມລະອຽດຂອງການສະແດ RenderingMode NonBuffered Tip = ໄວຂຶ້ນແທ້, ແຕ່ອາດມີອາການຈໍດຳໃນບາງເກມ Rotation = ໝຸນຈໍ Safe = ປອດໄພ -Screen layout = Screen layout Screen Scaling Filter = ໂຕຕອງປັບສເກລໜ້າຈໍ Show Debug Statistics = ສະແດງຄ່າທາງສະຖິຕິການແກ້ໄຂຈຸດບົກພ່ອງ Show FPS Counter = ສະແດງຄ່າເຟຣມເຣດ ແລະ ຄວາມໄວ/ວິນາທີ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 9f0ab2a8fa..f661aaaa56 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rodymo rezoliucija RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Rodyti testinio režimo statistikas Show FPS Counter = Rodyti kadrų per sekundę rodmenis diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 3418284348..c83073e859 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -540,7 +540,6 @@ Rendering Resolution = Resolusi rendering RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Papar statistik pepijat Show FPS Counter = Papar penghitung FPS diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 0eaaae39f4..0118839088 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -540,7 +540,6 @@ Rendering Resolution = Renderresolutie RenderingMode NonBuffered Tip = Sneller, maar mogelijk wordt in sommige games niets gerenderd Rotation = Rotatie Safe = Veilig -Screen layout = Screen layout Screen Scaling Filter = Beeldschalingsfilter Show Debug Statistics = Foutopsporingsstatistieken weergeven Show FPS Counter = FPS-teller weergeven diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index a13dce63ec..eebeb8c36e 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Vis debugstatistik Show FPS Counter = Vis FPS-teller diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 7c1f5b1abd..f7dfe09c8e 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rozdzielczość renderowania RenderingMode NonBuffered Tip = Szybsze, ale niektóre gry mogą się nie wyświetlać Rotation = Obrót Safe = Bezpieczne -Screen layout = Screen layout Screen Scaling Filter = Filtrowanie skalowania ekranu Show Debug Statistics = Pokaż statystyki debugowania Show FPS Counter = Pokaż licznik FPS diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 8718270edb..7514417417 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -563,7 +563,6 @@ Rendering Resolution = Resolução da renderização RenderingMode NonBuffered Tip = Mais rápido, mas nada pode ser desenhado em alguns jogos Rotation = Rotação Safe = Seguro -Screen layout = Esquema da tela Screen Scaling Filter = Filtro do dimensionamento da tela Show Debug Statistics = Mostrar estatísticas do debug Show FPS Counter = Mostrar contador de FPS diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index a36495e779..3e06c33fa9 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -563,7 +563,6 @@ Rendering Resolution = Resolução da renderização RenderingMode NonBuffered Tip = Mais rápido, mas poderá não ser desenhado nada em alguns jogos Rotation = Rotação Safe = Seguro -Screen layout = Esquema da tela Screen Scaling Filter = Filtro do dimensionamento da tela Show Debug Statistics = Mostrar estatísticas de depuração Show FPS Counter = Mostrar contador de FPS diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 64cfe450d5..b4d57b9f72 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -540,7 +540,6 @@ Rendering Resolution = Rezoluție Afișare RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Sigur -Screen layout = Screen layout Screen Scaling Filter = Filtrul de scalare al ecranului Show Debug Statistics = Arată statistici de depanare Show FPS Counter = Arată FPS diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index a9fa079e3c..eb292c1003 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -541,7 +541,6 @@ Rendering Resolution = Разрешение рендеринга RenderingMode NonBuffered Tip = Быстрее, но ничего не отображает в некоторых играх Rotation = Ориентация Safe = Безопасно -Screen layout = Расположение экрана Screen Scaling Filter = Фильтр масштабирования экрана Show Debug Statistics = Отображать отладочную информацию Show FPS Counter = Показывать счетчик FPS diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index e0ddb1c0f1..05ec276397 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -540,7 +540,6 @@ Rendering Resolution = Renderingsupplösning RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Skärmskalningsfilter Show Debug Statistics = Visa debugstatistik Show FPS Counter = Visa FPS-räknare diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 0b894f0e4b..b94af6ea3d 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -540,7 +540,6 @@ Rendering Resolution = Resolusyon ng rendering RenderingMode NonBuffered Tip = Mabilis, pero minsan wala kang makikita sa laro, blanko Rotation = Rotasyon Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen Scaling Filter Show Debug Statistics = Ipakita ang debug statistics Show FPS Counter = Ipakita ang FPS diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index a42da9ebac..04124d620d 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -541,7 +541,6 @@ Rendering Resolution = ความละเอียดในการแสด RenderingMode NonBuffered Tip = เร็วขึ้นก็จริง แต่มีผลข้างเคียงในบางเกมอาจเกิดอาการจอดำ Rotation = หมุนจอ Safe = ปลอดภัย -Screen layout = เค้าโครงหน้าจอ Screen Scaling Filter = ตัวกรองปรับสเกลหน้าจอ Show Debug Statistics = แสดงค่าทางสถิติการแก้ไขจุดบกพร่อง Show FPS Counter = แสดงค่าเฟรมเรท และความเร็ว/วินาที diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index ab9bfb4eb5..4c8ef5a0be 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -542,7 +542,6 @@ Rendering Resolution = İşleme çözünürlüğü RenderingMode NonBuffered Tip = Daha hızlıdır, ancak bazı oyunlarda hiçbir şey çizilmeyebilir Rotation = Rotasyon Safe = Güvenli -Screen layout = Ekran düzeni Screen Scaling Filter = Ekran ölçekleme filtresi Show Debug Statistics = Hata ayıklama istatistiklerini göster Show FPS Counter = FPS sayacını göster diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index d1f5687288..50f70815be 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -540,7 +540,6 @@ Rendering Resolution = Розширення рендерингу RenderingMode NonBuffered Tip = Швидше, але в деяких іграх нічого не може Rotation = Орієнтація: Safe = Безпечно -Screen layout = Screen layout Screen Scaling Filter = Фільтр обчислення екрану Show Debug Statistics = Відоброжати зневадження Show FPS Counter = Показати FPS diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index b1042a00b1..64991b2ebc 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -540,7 +540,6 @@ Rendering Resolution = Độ phân giải kết xuất RenderingMode NonBuffered Tip = Nhanh hơn, nhưng một số trò chơi thì bị lỗi Rotation = Xoay màn hình Safe = An toàn -Screen layout = Screen layout Screen Scaling Filter = Bộ lọc họa tiết rộng Show Debug Statistics = Hiện thông số debug Show FPS Counter = Hiện thông số FPS diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 20fdb30bc0..7fcbfbaf1d 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -540,7 +540,6 @@ Rendering Resolution = 渲染分辨率 RenderingMode NonBuffered Tip = 更快,但可能在某些游戏中丢失特效 Rotation = 旋转 Safe = 安全 -Screen layout = 屏幕布局 Screen Scaling Filter = 屏幕缩放滤镜 Show Debug Statistics = 显示调试信息 Show FPS Counter = 显示FPS计数器 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 548fb04764..cac288dd1c 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -539,7 +539,6 @@ Rendering Resolution = 轉譯解析度 RenderingMode NonBuffered Tip = 更快,但在某些遊戲中可能無法繪圖 Rotation = 旋轉 Safe = 安全 -Screen layout = 螢幕版面配置 Screen Scaling Filter = 螢幕縮放濾鏡 Show Debug Statistics = 顯示偵錯統計資料 Show FPS Counter = 顯示 FPS 計數器 From a87cf02dbfd48452a7ed2073c72e09f729fd577e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:43:49 +0100 Subject: [PATCH 388/715] Rename "Display layout editor" to "Display Layout && Effects" --- UI/GameSettingsScreen.cpp | 12 ++++++------ UI/PauseScreen.cpp | 2 +- Windows/ppsspp.rc | 2 +- assets/lang/ar_AE.ini | 4 ++-- assets/lang/az_AZ.ini | 4 ++-- assets/lang/bg_BG.ini | 4 ++-- assets/lang/ca_ES.ini | 4 ++-- assets/lang/cz_CZ.ini | 4 ++-- assets/lang/da_DK.ini | 4 ++-- assets/lang/de_DE.ini | 4 ++-- assets/lang/dr_ID.ini | 4 ++-- assets/lang/en_US.ini | 4 ++-- assets/lang/es_ES.ini | 4 ++-- assets/lang/es_LA.ini | 4 ++-- assets/lang/fa_IR.ini | 4 ++-- assets/lang/fi_FI.ini | 4 ++-- assets/lang/fr_FR.ini | 4 ++-- assets/lang/gl_ES.ini | 4 ++-- assets/lang/gr_EL.ini | 4 ++-- assets/lang/he_IL.ini | 4 ++-- assets/lang/he_IL_invert.ini | 4 ++-- assets/lang/hr_HR.ini | 4 ++-- assets/lang/hu_HU.ini | 4 ++-- assets/lang/id_ID.ini | 4 ++-- assets/lang/it_IT.ini | 4 ++-- assets/lang/ja_JP.ini | 4 ++-- assets/lang/jv_ID.ini | 4 ++-- assets/lang/ko_KR.ini | 4 ++-- assets/lang/lo_LA.ini | 4 ++-- assets/lang/lt-LT.ini | 4 ++-- assets/lang/ms_MY.ini | 4 ++-- assets/lang/nl_NL.ini | 4 ++-- assets/lang/no_NO.ini | 4 ++-- assets/lang/pl_PL.ini | 4 ++-- assets/lang/pt_BR.ini | 4 ++-- assets/lang/pt_PT.ini | 4 ++-- assets/lang/ro_RO.ini | 4 ++-- assets/lang/ru_RU.ini | 4 ++-- assets/lang/sv_SE.ini | 4 ++-- assets/lang/tg_PH.ini | 4 ++-- assets/lang/th_TH.ini | 4 ++-- assets/lang/tr_TR.ini | 4 ++-- assets/lang/uk_UA.ini | 4 ++-- assets/lang/vi_VN.ini | 4 ++-- assets/lang/zh_CN.ini | 4 ++-- assets/lang/zh_TW.ini | 4 ++-- 46 files changed, 94 insertions(+), 94 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 24e160ce6a..65f8c86a02 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -341,12 +341,6 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(fullscreenMulti)->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenMultiChange); } #endif - // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. - displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor"))); - displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { - screenManager()->push(new DisplayLayoutScreen(gamePath_)); - return UI::EVENT_DONE; - }); #if PPSSPP_PLATFORM(ANDROID) // Hide insets option if no insets, or OS too old. @@ -364,6 +358,12 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange); } #endif + // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. + displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display Layout && Effects"))); + displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + screenManager()->push(new DisplayLayoutScreen(gamePath_)); + return UI::EVENT_DONE; + }); } graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control"))); diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index c45d6b7920..2ff43b61ab 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -326,7 +326,7 @@ void GamePauseScreen::CreateViews() { rightColumnItems->Add(new Choice(pa->T("Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); rightColumnItems->Add(new Choice(pa->T("Create Game Config")))->OnClick.Handle(this, &GamePauseScreen::OnCreateConfig); } - UI::Choice *displayEditor_ = rightColumnItems->Add(new Choice(gr->T("Display layout editor"))); + UI::Choice *displayEditor_ = rightColumnItems->Add(new Choice(gr->T("Display Layout && Effects"))); displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { screenManager()->push(new DisplayLayoutScreen(gamePath_)); return UI::EVENT_DONE; diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 27437ef9f1..54951ee77a 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -547,7 +547,7 @@ BEGIN MENUITEM "Ignore Windows Key", ID_OPTIONS_IGNOREWINKEY MENUITEM "Language...", ID_OPTIONS_LANGUAGE MENUITEM "Control Mapping...", ID_OPTIONS_CONTROLS - MENUITEM "Display Layout Editor", ID_OPTIONS_DISPLAY_LAYOUT + MENUITEM "Display Layout && Effects", ID_OPTIONS_DISPLAY_LAYOUT MENUITEM "More Settings...", ID_OPTIONS_MORE_SETTINGS MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Fullscreen", ID_OPTIONS_FULLSCREEN diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 6906884d20..48600b4cb2 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -145,7 +145,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = ‎&التفكيك... Discord = Discord -Display Layout Editor = ‎أظهر مُعدل النسق... +Display Layout && Effects = ‎أظهر مُعدل النسق... Display Rotation = ‎تدوير العرض Dump Next Frame to Log = ‎تصحيح الفريم التالي إلي سجل Emulation = ‎&محاكاة @@ -495,7 +495,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = ‎أظهر مُعدل النسق Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 2fa30be8d3..050dd00d9f 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index fe99615ac6..d2b1f1b29d 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Емулация @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = Кадри в сек. diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 7e93b3b4dd..b292886162 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Editeu la posició dels botons... +Display Layout && Effects = Editeu la posició dels botons... Display Rotation = Rotació de la pantalla Dump Next Frame to Log = Aboca el següent marc al registre Emulation = &Emulació @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 81dbf5aa2d..e6ae26f20a 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = R&ozebrání strojového kódu... Discord = Discord -Display Layout Editor = Zobrazit editor rozvržení... +Display Layout && Effects = Zobrazit editor rozvržení... Display Rotation = Otočení obrazovky Dump Next Frame to Log = &Vypsat příští snímek do záznamu Emulation = &Emulace @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Zobrazit editor rozvržení +Display Layout && Effects = Zobrazit editor rozvržení Display Resolution (HW scaler) = Rozlišení obrazovky (Hardwarové zvětšení) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index fa05f3da14..c5520585ac 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = G&em næste frame i loggen Emulation = &Emulation @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Skærmopløsning (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index b9af72f822..4cab3724b1 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D11 Disassembly = Disassembler... Discord = Discord -Display Layout Editor = Bildschirmlayout Editor... +Display Layout && Effects = Bildschirmlayout Editor... Display Rotation = Bildschirmdrehung Dump Next Frame to Log = Nächsten Frame im Log speichern Emulation = Emulation @@ -487,7 +487,7 @@ Device = Gerät Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Deaktiviert -Display layout editor = Bildschirmlayout Editor +Display Layout && Effects = Bildschirmlayout Editor Display Resolution (HW scaler) = Bildschirmauflösung (HW Skalierung) Enable Cardboard VR = Cardboard VR aktivieren FPS = FPS diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 0ec1b8acd1..becd6fe013 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = Ca'b&eranni lako log Emulation = &Emulasi @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 802cf62e42..c4623160cc 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -161,7 +161,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump next frame to log Emulation = &Emulation @@ -512,7 +512,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index a323b90b1a..348b03e155 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Editar posición de botones... +Display Layout && Effects = Editar posición de botones... Display Rotation = Rotación de pantalla Dump Next Frame to Log = &Volcar siguiente cuadro a registro Emulation = &Emulación @@ -487,7 +487,7 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desactivado -Display layout editor = Editor del área de pantalla +Display Layout && Effects = Editor del área de pantalla Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) Enable Cardboard VR = Activar Cardboard VR FPS = FPS diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 978465cdef..c6be121d60 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D 9 Direct3D11 = Direct3D &11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Editar posición de botones... +Display Layout && Effects = Editar posición de botones... Display Rotation = Rotación de pantalla Dump Next Frame to Log = &Volcar siguiente cuadro a registro Emulation = &Emulación @@ -487,7 +487,7 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Apagado -Display layout editor = Editor del área de pantalla +Display Layout && Effects = Editor del área de pantalla Display Resolution (HW scaler) = Resolución de pantalla (escalado por HW) Enable Cardboard VR = Activar Cardboard VR FPS = FPS diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 3dcef7b698..a6b34a1ffc 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = ‎...جداسازی قطعات Discord = Discord -Display Layout Editor = ‎ویرایشگر چیدمان صفحه +Display Layout && Effects = ‎ویرایشگر چیدمان صفحه Display Rotation = ‎چرخش صفحه Dump Next Frame to Log = ‎تخلیه فریم بعدی به فایل لاگ Emulation = ‎شبیه سازی @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = ‎ویرایشگر چیدمان صفحه +Display Layout && Effects = ‎ویرایشگر چیدمان صفحه Display Resolution (HW scaler) = ‎رزولوشن صفحه Enable Cardboard VR = Enable Cardboard VR FPS = ‎فریم بر ثانیه diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index f0b1b957a9..ca90f9ee59 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 06a5dde549..b0ee687e0f 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = Dés&assembleur Discord = Discord -Display Layout Editor = Éditeur d'affichage... +Display Layout && Effects = Éditeur d'affichage... Display Rotation = Rotation de l'affichage Dump Next Frame to Log = &Dump de l'image suivante dans le journal Emulation = &Émulation @@ -487,7 +487,7 @@ Device = Appareil Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Désactivé -Display layout editor = Éditeur d'affichage +Display Layout && Effects = Éditeur d'affichage Display Resolution (HW scaler) = Définition d'affichage (mise à l'échelle matérielle) Enable Cardboard VR = Activer Cardboard VR FPS = FPS diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 9ffa57c477..0eae2bdca3 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = &Volcar seguinte cadro a rexistro Emulation = &Emulación @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 29408a0887..ba97120998 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = Αποσυναρμολόγηση... Discord = Discord -Display Layout Editor = Επεξεργασία διάταξης οθόνης... +Display Layout && Effects = Επεξεργασία διάταξης οθόνης... Display Rotation = Περιστροφή Οθόνης Dump Next Frame to Log = Αποτύπωση πλαισίου σε καταγραφέα Emulation = Εξομοίωση @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Απενεργοποιημένο -Display layout editor = Επεξεργασία διάταξης οθόνης +Display Layout && Effects = Επεξεργασία διάταξης οθόνης Display Resolution (HW scaler) = Ανάλυση οθόνης (Κλιμακοτής hardware) Enable Cardboard VR = Ενεργοποίηση Cardboard VR FPS = FPS diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index b4aa66d602..8f044514f2 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &פירוק... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &סימולציה @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = כמות פריימים לשנייה diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 49ef7404b5..0757a585e2 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = היינשל םימיירפ תומכ diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 8335b02963..7fe5d2de2a 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Prikaži uređivanje kontroli... +Display Layout && Effects = Prikaži uređivanje kontroli... Display Rotation = Rotacija prikaza Dump Next Frame to Log = O&dloži sljedeći frame na log Emulation = &Emulacija @@ -487,7 +487,7 @@ Device = Uređaj Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Isključeno -Display layout editor = Prikaz layout uređivača +Display Layout && Effects = Prikaz layout uređivača Display Resolution (HW scaler) = Prikaz rezolucije (HW mjeritelj) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 4a351724f2..078b25d446 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D 1&1 Disassembly = &Disassembly… Discord = &Discord -Display Layout Editor = Elrendezés szerkesztő… +Display Layout && Effects = Elrendezés szerkesztő… Display Rotation = Megjelenítés forgatása Dump Next Frame to Log = Kö&vetkező képkocka kiírása naplófájlba Emulation = &Emuláció @@ -487,7 +487,7 @@ Device = Eszköz Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Letiltva -Display layout editor = Elrendezés szerkesztő +Display Layout && Effects = Elrendezés szerkesztő Display Resolution (HW scaler) = Megjelenítési felbontás (HW skálázó) Enable Cardboard VR = Cardboard VR engedélyezése FPS = FPS diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 5322e8c54a..3334854770 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = &Pembongkaran... Discord = Discord -Display Layout Editor = Penyunting tata letak tampilan... +Display Layout && Effects = Penyunting tata letak tampilan... Display Rotation = Rotasi tampilan Dump Next Frame to Log = B&uang laju bingkai berikutnya untuk masuk Emulation = &Emulasi @@ -487,7 +487,7 @@ Device = Perangkat Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Nonaktif -Display layout editor = Penyesuaian tata letak tampilan +Display Layout && Effects = Penyesuaian tata letak tampilan Display Resolution (HW scaler) = Resolusi tampilan (penskala HW) Enable Cardboard VR = Aktifkan Cardboard VR FPS = FPS diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 66d98e4e13..98cae99ab4 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D &11 Disassembly = Disassemblatore... Discord = Discord -Display Layout Editor = Editor visualizzazione layout... +Display Layout && Effects = Editor visualizzazione layout... Display Rotation = Rotazione display Dump Next Frame to Log = Salva Log Frame Successivo Emulation = Emulazione @@ -488,7 +488,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 #Disable slower effects (speedup) = Disattiva gli effetti più lenti (veloce) Disabled = Disabilitato -Display layout editor = Editor Display +Display Layout && Effects = Editor Display Display Resolution (HW scaler) = Risoluzione Display (scaler HW) Enable Cardboard VR = Attiva Cardboard VR FPS = FPS diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 36266a6d7f..b71db3088f 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = 逆アセンブル(&D)... Discord = Discord -Display Layout Editor = 画面のレイアウトを編集する... +Display Layout && Effects = 画面のレイアウトを編集する... Display Rotation = 画面の向き Dump Next Frame to Log = 次のフレームをログにダンプする(&U) Emulation = エミュレーション(&E) @@ -487,7 +487,7 @@ Device = デバイス Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 無効 -Display layout editor = 画面のレイアウトを編集する +Display Layout && Effects = 画面のレイアウトを編集する Display Resolution (HW scaler) = 画面解像度 (HWスケーラー) Enable Cardboard VR = Cardboard VRを有効にする FPS = FPS diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 22677ae81e..11d8a9f749 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = Mbucal Frame Sabanjure kanggo Mlebu Emulation = &Emulasi @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Tata letak Tampilan editor +Display Layout && Effects = Tata letak Tampilan editor Display Resolution (HW scaler) = Resolusi tampilan (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index f955213c14..ed99fe419f 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D 9(&9) Direct3D11 = Direct3D 11(&1) Disassembly = 역어셈블리(&D)... Discord = 디스코드 -Display Layout Editor = 레이아웃 편집기 표시... +Display Layout && Effects = 레이아웃 편집기 표시... Display Rotation = 화면 회전 Dump Next Frame to Log = 로그에 다음 프레임 덤프(&U) Emulation = 에뮬레이션(&E) @@ -487,7 +487,7 @@ Device = 장치 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 비활성화 -Display layout editor = 화면 레이아웃 편집기 +Display Layout && Effects = 화면 레이아웃 편집기 Display Resolution (HW scaler) = 화면 해상도(HW 스케일러) Enable Cardboard VR = 카드보드 VR 활성화 FPS = FPS diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index c78d18ea43..5c7d4a9b38 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = &Direct3D11 Disassembly = &ການແຍກອົງປະກອບ... Discord = Discord -Display Layout Editor = ແກ້ໄຂຮູບແບບສະແດງຜົນ... +Display Layout && Effects = ແກ້ໄຂຮູບແບບສະແດງຜົນ... Display Rotation = ການໝຸນໜ້າຈໍ Dump Next Frame to Log = &ດຶງຂໍ້ມູນຂອງເຟຣມຕໍ່ໄປເພື່ອເກັບບັນທຶກຄ່າ Emulation = &ການຈຳລອງ @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = ແກ້ໄຂຮູບແບບໜ້າຈໍ +Display Layout && Effects = ແກ້ໄຂຮູບແບບໜ້າຈໍ Display Resolution (HW scaler) = ຄວາມລະອຽດໜ້າຈໍ (ຕາມຮາດແວຣ໌) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index f661aaaa56..175b803d95 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = "&Ardyti..." Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = "R&ašyti" kitą kadrą į "statusą" Emulation = &Emulation @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Ekrano rezoliucija ("HW" ištiesinimas) Enable Cardboard VR = Enable Cardboard VR FPS = Kadrai per sekundę diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index c83073e859..d0a92de800 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Pasangkan... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Putaran skrin Dump Next Frame to Log = L&etak frame berikutnya ke log Emulation = &Emulasi @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 0118839088..a607f67e07 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Demonteren... Discord = Discord -Display Layout Editor = Schermweergave aanpassen... +Display Layout && Effects = Schermweergave aanpassen... Display Rotation = Schermrotatie Dump Next Frame to Log = &Volgende frame in logboek plaatsen Emulation = &Emulatie @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Schermweergave bewerken +Display Layout && Effects = Schermweergave bewerken Display Resolution (HW scaler) = Schermresolutie (hardware) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index eebeb8c36e..090ee1b011 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index f7dfe09c8e..5aca263510 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = Dezasembluj... Discord = Discord -Display Layout Editor = Edytor położenia obrazu... +Display Layout && Effects = Edytor położenia obrazu... Display Rotation = Obracanie ekranu Dump Next Frame to Log = Zrzuć następną klatkę do dziennika zdarzeń Emulation = &Emulacja @@ -487,7 +487,7 @@ Device = Urządzenie Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Wył. -Display layout editor = Edytor położenia obrazu +Display Layout && Effects = Edytor położenia obrazu Display Resolution (HW scaler) = Rozdzielczość ekranu (skaler sprz.) Enable Cardboard VR = Enable Cardboard VR FPS = Tylko FPS diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 7514417417..2a4e744237 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -161,7 +161,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Exibir o editor do esquema... +Display Layout && Effects = Exibir o editor do esquema... Display Rotation = Rotação da exibição Dump Next Frame to Log = D&umpar o frame seguinte no log Emulation = &Emulação @@ -511,7 +511,7 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desativado -Display layout editor = Exibe o editor dos esquemas +Display Layout && Effects = Exibe o editor dos esquemas Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) Enable Cardboard VR = Ativa o VR Cardboard FPS = FPS diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 3e06c33fa9..79c47b939a 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -161,7 +161,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Exibir o editor de esquema... +Display Layout && Effects = Exibir o editor de esquema... Display Rotation = Rotação da exibição Dump Next Frame to Log = G&uardar o frame seguinte no Log Emulation = &Emulação @@ -511,7 +511,7 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desativado -Display layout editor = Mostrar o editor dos esquemas +Display Layout && Effects = Mostrar o editor dos esquemas Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) Enable Cardboard VR = Ativar o VR Cardboard FPS = FPS (Quadros Por Segundo) diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index b4d57b9f72..475d0ab361 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -137,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Rezoluție ecran (scalare HW) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index eb292c1003..92149ba8b9 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = &Direct3D 11 Disassembly = &Дизассемблер... Discord = Discord -Display Layout Editor = Редактор расположения экрана... +Display Layout && Effects = Редактор расположения экрана... Display Rotation = Ориентация экрана Dump Next Frame to Log = Сохранить &кадр в логе Emulation = &Эмуляция @@ -487,7 +487,7 @@ Device = Устройство Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Отключено -Display layout editor = Редактор расположения экрана +Display Layout && Effects = Редактор расположения экрана Display Resolution (HW scaler) = Разрешение экрана (аппаратное) Enable Cardboard VR = Включить Cardboard VR #Features = Возможности diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 05ec276397..4c9e9adc9f 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D &11 Disassembly = Disassemblera Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Skärmlayout && effekter... Display Rotation = Skärmrotation Dump Next Frame to Log = Dump Next Frame to Log Emulation = Emulering @@ -487,7 +487,7 @@ Device = Enhet Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Avstängd -Display layout editor = Skärmlayouteditor +Display Layout && Effects = Skärmlayout och effekter Display Resolution (HW scaler) = Skärmupplösning (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index b94af6ea3d..77e0214328 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D 11 Disassembly = Disassembly... Discord = Discord -Display Layout Editor = Display Layout Editor... +Display Layout && Effects = Display Layout & Effects... Display Rotation = Display rotation Dump Next Frame to Log = Dump Next Frame to Log Emulation = Emulasyon @@ -487,7 +487,7 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 04124d620d..3ea8b61435 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -137,7 +137,7 @@ Direct3D9 = ไดเร็คท์ 3D 9 Direct3D11 = ไดเร็คท์ 3D 11 Disassembly = การแยกองค์ประกอบ... Discord = ไปที่ Discord -Display Layout Editor = แก้ไขรูปแบบของหน้าจอ... +Display Layout && Effects = แก้ไขรูปแบบของหน้าจอ... Display Rotation = การสลับหมุนหน้าจอ Dump Next Frame to Log = ดึงข้อมูลของเฟรมถัดไปเพื่อเก็บบันทึกค่า Emulation = การจำลอง @@ -487,7 +487,7 @@ Device = การ์ดจอ Direct3D 9 = ไดเร็คท์ 3D 9 Direct3D 11 = ไดเร็คท์ 3D 11 Disabled = ปิดการใช้งาน -Display layout editor = แก้ไขรูปแบบของหน้าจอ +Display Layout && Effects = แก้ไขรูปแบบของหน้าจอ Display Resolution (HW scaler) = ความละเอียดหน้าจอ (ตามฮาร์ดแวร์) Enable Cardboard VR = เปิดการทำงานแว่นการ์ดบอร์ด VR FPS = เฟรมต่อวิ diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 4c8ef5a0be..55db3ef6e2 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -139,7 +139,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Ekran düzeni düzenleyici... +Display Layout && Effects = Ekran düzeni düzenleyici... Display Rotation = Ekran rotasyonu Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emülasyon @@ -489,7 +489,7 @@ Device = Cihaz Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Devre dışı -Display layout editor = Görüntü Düzeni Düzenleyicisi +Display Layout && Effects = Görüntü Düzeni Düzenleyicisi Display Resolution (HW scaler) = Görüntü Çözünürlüğü (HW scaler) Enable Cardboard VR = Cardboard VR'ı Etkinleştirin FPS = FPS diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 50f70815be..7a24e1f523 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Розбирання... Discord = Discord -Display Layout Editor = Редактор розташування екрану... +Display Layout && Effects = Редактор розташування екрану... Display Rotation = Орієнтація екрану Dump Next Frame to Log = Зберегти &кадр у лог Emulation = &Емуляція @@ -487,7 +487,7 @@ Device = Пристрій Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Вимкнено -Display layout editor = Редактор розташування екрану +Display Layout && Effects = Редактор розташування екрану Display Resolution (HW scaler) = Розширення екрану (HW масштабування) Enable Cardboard VR = Увімкнути Cardboard VR FPS = FPS diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 64991b2ebc..3cbb0d9d93 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D11 Disassembly = Disassembly (Tháo gỡ)... Discord = Discord -Display Layout Editor = Hiện nút chỉnh sửa bố cục... +Display Layout && Effects = Hiện nút chỉnh sửa bố cục... Display Rotation = Hiện nút xoay màn hình Dump Next Frame to Log = Dump Next Frame to Log Emulation = Giả lập @@ -487,7 +487,7 @@ Device = Thiết bị Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Vô hiệu hóa -Display layout editor = Chỉnh bố trí hiển thị +Display Layout && Effects = Chỉnh bố trí hiển thị Display Resolution (HW scaler) = Độ phân giải màn hình (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS (khung hình/giây) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 7fcbfbaf1d..c40a89a968 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D 9 (&9) Direct3D11 = Direct3D11 (&11) Disassembly = 反汇编 (&D)... Discord = Discord -Display Layout Editor = 显示布局编辑器... +Display Layout && Effects = 显示布局编辑器... Display Rotation = 显示旋转 Dump Next Frame to Log = 转储下一帧到日志 (&U) Emulation = 模拟 (&E) @@ -487,7 +487,7 @@ Device = 设备 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 禁用 -Display layout editor = 显示布局编辑器 +Display Layout && Effects = 显示布局编辑器 Display Resolution (HW scaler) = 显示分辨率(硬件缩放) Enable Cardboard VR = 启用Cardboard VR FPS = 每秒帧数 (FPS) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index cac288dd1c..cc0fe865b1 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D 9 (&9) Direct3D11 = Direct3D 11 (&11) Disassembly = 反組譯碼 (&D)… Discord = Discord -Display Layout Editor = 顯示版面配置編輯器… +Display Layout && Effects = 顯示版面配置編輯器… Display Rotation = 顯示旋轉 Dump Next Frame to Log = 傾印下一影格至記錄 (&U) Emulation = 模擬 (&E) @@ -487,7 +487,7 @@ Device = 裝置 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = 顯示版面配置編輯器 +Display Layout && Effects = 顯示版面配置編輯器 Display Resolution (HW scaler) = 顯示解析度 (硬體縮放) Enable Cardboard VR = 啟用 Cardboard VR FPS = FPS From 692c972e774d745f18d65973a1f68f13cea82b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:48:32 +0100 Subject: [PATCH 389/715] A couple more reorderings --- UI/GameSettingsScreen.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 65f8c86a02..0d7d491250 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -298,11 +298,6 @@ void GameSettingsScreen::CreateViews() { } } - if (deviceType != DEVICE_TYPE_VR) { - CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); - softwareGPU->SetEnabled(!PSP_IsInited()); - } - static const char *internalResolutions[] = { "Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP", "6x PSP", "7x PSP", "8x PSP", "9x PSP", "10x PSP" }; resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), gr->GetName(), screenManager())); resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange); @@ -322,13 +317,10 @@ void GameSettingsScreen::CreateViews() { } #endif -#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) - CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); - vSync->OnClick.Add([=](EventParams &e) { - NativeResized(); - return UI::EVENT_CONTINUE; - }); -#endif + if (deviceType != DEVICE_TYPE_VR) { + CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); + softwareGPU->SetEnabled(!PSP_IsInited()); + } if (deviceType != DEVICE_TYPE_VR) { #if !defined(MOBILE_DEVICE) @@ -342,6 +334,14 @@ void GameSettingsScreen::CreateViews() { } #endif +#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) + CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); + vSync->OnClick.Add([=](EventParams &e) { + NativeResized(); + return UI::EVENT_CONTINUE; + }); +#endif + #if PPSSPP_PLATFORM(ANDROID) // Hide insets option if no insets, or OS too old. if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 28 && From 920bd45ddc09e404f0cf22c25404e435b077c496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:54:05 +0100 Subject: [PATCH 390/715] Move stereo settings to developer tools, until developed further --- UI/GameSettingsScreen.cpp | 82 ++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 0d7d491250..269eb7a2a4 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -136,10 +136,10 @@ static bool UsingHardwareTextureScaling() { } static std::string TextureTranslateName(const char *value) { - auto ps = GetI18NCategory("TextureShaders"); + auto ts = GetI18NCategory("TextureShaders"); const TextureShaderInfo *info = GetTextureShaderInfo(value); if (info) { - return ps->T(value, info ? info->name.c_str() : value); + return ts->T(value, info ? info->name.c_str() : value); } else { return value; } @@ -429,43 +429,6 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_CONTINUE; }); - graphicsSettings->Add(new ItemHeader(gr->T("Stereo rendering"))); - - bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; - - auto enableStereo = [=]() -> bool { - return g_Config.bStereoRendering && multiViewSupported; - }; - - if (draw->GetDeviceCaps().multiViewSupported) { - graphicsSettings->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering"))); - std::vector stereoShaderNames; - - ChoiceWithValueDisplay *stereoShaderChoice = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, "Stereo display shader", &PostShaderTranslateName)); - stereoShaderChoice->SetEnabledFunc(enableStereo); - stereoShaderChoice->OnClick.Add([=](EventParams &e) { - auto gr = GetI18NCategory("Graphics"); - auto procScreen = new PostProcScreen(gr->T("Stereo display shader"), 0, true); - if (e.v) - procScreen->SetPopupOrigin(e.v); - screenManager()->push(procScreen); - return UI::EVENT_DONE; - }); - const ShaderInfo *shaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); - if (shaderInfo) { - for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { - auto &setting = shaderInfo->settings[i]; - if (!setting.name.empty()) { - auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; - PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); - settingValue->SetEnabledFunc([=] { - return !g_Config.bSkipBufferEffects && enableStereo(); - }); - } - } - } - } - graphicsSettings->Add(new ItemHeader(gr->T("Performance"))); CheckBox *frameDuplication = graphicsSettings->Add(new CheckBox(&g_Config.bRenderDuplicateFrames, gr->T("Render duplicate frames to 60hz"))); frameDuplication->OnClick.Add([=](EventParams &e) { @@ -1741,6 +1704,7 @@ void DeveloperToolsScreen::CreateViews() { auto gr = GetI18NCategory("Graphics"); auto a = GetI18NCategory("Audio"); auto sy = GetI18NCategory("System"); + auto ps = GetI18NCategory("PostShaders"); AddStandardBack(root_); @@ -1798,6 +1762,46 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures"))); list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures"))); + Draw::DrawContext *draw = screenManager()->getDrawContext(); + + // Experimental, will move to main graphics settings later. + list->Add(new ItemHeader(gr->T("Stereo rendering"))); + + bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; + + auto enableStereo = [=]() -> bool { + return g_Config.bStereoRendering && multiViewSupported; + }; + + if (draw->GetDeviceCaps().multiViewSupported) { + list->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering"))); + std::vector stereoShaderNames; + + ChoiceWithValueDisplay *stereoShaderChoice = list->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, "Stereo display shader", &PostShaderTranslateName)); + stereoShaderChoice->SetEnabledFunc(enableStereo); + stereoShaderChoice->OnClick.Add([=](EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto procScreen = new PostProcScreen(gr->T("Stereo display shader"), 0, true); + if (e.v) + procScreen->SetPopupOrigin(e.v); + screenManager()->push(procScreen); + return UI::EVENT_DONE; + }); + const ShaderInfo *shaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); + if (shaderInfo) { + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; + PopupSliderChoiceFloat *settingValue = list->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetEnabledFunc([=] { + return !g_Config.bSkipBufferEffects && enableStereo(); + }); + } + } + } + } + // Makes it easy to get savestates out of an iOS device. The file listing shown in MacOS doesn't allow // you to descend into directories. #if PPSSPP_PLATFORM(IOS) From ca86d8d267c1b515ca5782391b1aa82fa52b200f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Nov 2022 22:55:22 +0100 Subject: [PATCH 391/715] Remove "Load language ini" / "Save language ini" from devtools --- UI/GameSettingsScreen.cpp | 13 ------------- UI/GameSettingsScreen.h | 2 -- assets/lang/ar_AE.ini | 3 --- assets/lang/az_AZ.ini | 3 --- assets/lang/bg_BG.ini | 3 --- assets/lang/ca_ES.ini | 3 --- assets/lang/cz_CZ.ini | 3 --- assets/lang/da_DK.ini | 3 --- assets/lang/de_DE.ini | 3 --- assets/lang/dr_ID.ini | 3 --- assets/lang/es_ES.ini | 3 --- assets/lang/es_LA.ini | 3 --- assets/lang/fa_IR.ini | 3 --- assets/lang/fi_FI.ini | 3 --- assets/lang/fr_FR.ini | 3 --- assets/lang/gl_ES.ini | 3 --- assets/lang/gr_EL.ini | 3 --- assets/lang/he_IL.ini | 3 --- assets/lang/he_IL_invert.ini | 3 --- assets/lang/hr_HR.ini | 3 --- assets/lang/hu_HU.ini | 3 --- assets/lang/id_ID.ini | 3 --- assets/lang/it_IT.ini | 3 --- assets/lang/ja_JP.ini | 3 --- assets/lang/jv_ID.ini | 3 --- assets/lang/ko_KR.ini | 3 --- assets/lang/lo_LA.ini | 3 --- assets/lang/lt-LT.ini | 3 --- assets/lang/ms_MY.ini | 3 --- assets/lang/nl_NL.ini | 3 --- assets/lang/no_NO.ini | 3 --- assets/lang/pl_PL.ini | 3 --- assets/lang/pt_BR.ini | 3 --- assets/lang/pt_PT.ini | 3 --- assets/lang/ro_RO.ini | 3 --- assets/lang/ru_RU.ini | 3 --- assets/lang/sv_SE.ini | 3 --- assets/lang/tg_PH.ini | 3 --- assets/lang/th_TH.ini | 3 --- assets/lang/tr_TR.ini | 3 --- assets/lang/uk_UA.ini | 3 --- assets/lang/vi_VN.ini | 3 --- assets/lang/zh_CN.ini | 3 --- assets/lang/zh_TW.ini | 3 --- 44 files changed, 141 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 269eb7a2a4..9c483cf750 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1755,9 +1755,6 @@ void DeveloperToolsScreen::CreateViews() { if (GetGPUBackend() == GPUBackend::VULKAN) { list->Add(new CheckBox(&g_Config.bGpuLogProfiler, gr->T("GPU log profiler"))); } - list->Add(new ItemHeader(dev->T("Language"))); - list->Add(new Choice(dev->T("Load language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoadLanguageIni); - list->Add(new Choice(dev->T("Save language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSaveLanguageIni); list->Add(new ItemHeader(dev->T("Texture Replacement"))); list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures"))); list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures"))); @@ -1869,16 +1866,6 @@ UI::EventReturn DeveloperToolsScreen::OnRunCPUTests(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn DeveloperToolsScreen::OnSaveLanguageIni(UI::EventParams &e) { - i18nrepo.SaveIni(g_Config.sLanguageIni); - return UI::EVENT_DONE; -} - -UI::EventReturn DeveloperToolsScreen::OnLoadLanguageIni(UI::EventParams &e) { - i18nrepo.LoadIni(g_Config.sLanguageIni); - return UI::EVENT_DONE; -} - UI::EventReturn DeveloperToolsScreen::OnOpenTexturesIniFile(UI::EventParams &e) { std::string gameID = g_paramSFO.GetDiscID(); Path generatedFilename; diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 80e2f45b30..a3fcd0ddc3 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -168,8 +168,6 @@ protected: private: UI::EventReturn OnRunCPUTests(UI::EventParams &e); UI::EventReturn OnLoggingChanged(UI::EventParams &e); - UI::EventReturn OnLoadLanguageIni(UI::EventParams &e); - UI::EventReturn OnSaveLanguageIni(UI::EventParams &e); UI::EventReturn OnOpenTexturesIniFile(UI::EventParams &e); UI::EventReturn OnLogConfig(UI::EventParams &e); UI::EventReturn OnJitAffectingSetting(UI::EventParams &e); diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 48600b4cb2..d0bafd4a94 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -252,8 +252,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = ‎اللغة -Load language ini = ‎تحميل ملف اللغة Log Dropped Frame Statistics = ‎سجل التفاصيل للفريمات المتدنية Log Level = ‎مستوي السجل Log View = ‎أظهر السجل @@ -269,7 +267,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = ‎شغل فحوص المعالج -Save language ini = ‎إحفظ ملف اللغة Save new textures = ‎حفظ الرسم الجديد Shader Viewer = ‎مستعرض الرسوميات Show Developer Menu = ‎أظهر قائمة المطور diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 050dd00d9f..2b88959617 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Dil faylı yüklə(.ini) Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Dil faylını qeyd et (.ini) Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index d2b1f1b29d..ab980217e2 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Език -Load language ini = Зареди езиков ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Сигурни ли сте, че искате да въ RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Запази езиков ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Покажи developer меню diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index b292886162..4b49794b2b 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Comparació Jit JIT debug tools = JIT debug tools -Language = Llengua -Load language ini = Carrega INI d'idioma Log Dropped Frame Statistics = Registra estadístiques de caigudes de marcs Log Level = Nivell del registre Log View = Vegeu el registre @@ -261,7 +259,6 @@ RestoreDefaultSettings = Esteu segur que voleu restablir els ajustaments de fàb RestoreGameDefaultSettings = Esteu segur que voleu restablir els paràmetres de joc\na els paràmetres per defecte de PPSSPP? Resume = Resume Run CPU Tests = Proves de CPU -Save language ini = Desa l'INI de l'idioma Save new textures = Desa les noves textures Shader Viewer = Visualitzador de shader Show Developer Menu = Mostra el menú de desenvolupament diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index e6ae26f20a..3d4ffd360c 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Porovnání JIT JIT debug tools = JIT debug tools -Language = Jazyk -Load language ini = Načíst ini s jazykem Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Úroveň záznamu Log View = Zobrazení záznamu @@ -261,7 +259,6 @@ RestoreDefaultSettings = Jste si jisti obnovou všech nastavení zpět na jejich RestoreGameDefaultSettings = Jste si jisti obnovou nastavení hry\nzpět na výchozí hodnoty PPSSPP? Resume = Resume Run CPU Tests = Spustit zkoušky CPU -Save language ini = Uložit ini s jazykem Save new textures = Save new textures Shader Viewer = Prohlížeč shaderů Show Developer Menu = Zobrazit nabídku pro vývojáře diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index c5520585ac..961d4cdb86 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit sammenlign JIT debug tools = JIT debug tools -Language = Sprog -Load language ini = Hent sprog ini Log Dropped Frame Statistics = Log Droppede Frames Statistik Log Level = Logniveau Log View = Log visning @@ -261,7 +259,6 @@ RestoreDefaultSettings = Er du sikker på at du vil sætte indstillinger tilbage RestoreGameDefaultSettings = Er du sikker på at du vil nustille de spilspecifikke\nindstillinger tilbage til standard? Resume = Resume Run CPU Tests = Kør CPU test -Save language ini = Gem sprog ini Save new textures = Gem nye textures Shader Viewer = Shader viewer Show Developer Menu = Vis udviklermenu diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 4cab3724b1..6e5ecb80ab 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU Profil Jit Compare = JIT-Vergleich JIT debug tools = JIT Debug Werkzeuge -Language = Sprache -Load language ini = Sprachdatei laden Log Dropped Frame Statistics = Statistik für fehlende Einzelbilder loggen Log Level = Loglevel Log View = Logbuch @@ -261,7 +259,6 @@ RestoreDefaultSettings = Sind Sie sicher, dass Sie alle Standardeinstellungen\n( RestoreGameDefaultSettings = Wollen Sie wirklich die spielspezifischen Einstellungen\nauf die Werkseinstellungen von PPSSPP zurücksetzen? Resume = Resume Run CPU Tests = CPU Test starten -Save language ini = Sprachdatei speichern Save new textures = Speichere neue Texturen Shader Viewer = Shader-Anzeige Show Developer Menu = Zeige Entwicklermenü diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index becd6fe013..b58310d930 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Bahasa -Load language ini = Bukka' filena to bahasa Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Pajalanni tes CPU -Save language ini = Annai filena to bahasa Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 348b03e155..3535c000ff 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = Perfil GPU Jit Compare = Comparación JIT JIT debug tools = Herramientas de depuración JIT -Language = Idioma -Load language ini = Cargar INI de idioma Log Dropped Frame Statistics = Registrar estadísticas de caídas de fotogramas Log Level = Nivel de registro Log View = Ver el registro @@ -261,7 +259,6 @@ RestoreDefaultSettings = ¿Seguro que quieres volver a los ajustes de fábrica?\ RestoreGameDefaultSettings = ¿Seguro que quieres reestablecer los ajustes del juego\na los ajustes por defecto de PPSSPP? Resume = Reanudar Run CPU Tests = Pruebas de CPU -Save language ini = Guardar INI de idioma Save new textures = Guardar texturas nuevas Shader Viewer = Visor de shader Show Developer Menu = Mostrar menú de desarrollo diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index c6be121d60..b70659e928 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = Perfil de GPU Jit Compare = Comparar JIT JIT debug tools = Herr. de depuración de JIT -Language = Idioma -Load language ini = Cargar INI de idioma Log Dropped Frame Statistics = Registrar estadísticas de frames caídos Log Level = Nivel de registro Log View = Ver el registro @@ -261,7 +259,6 @@ RestoreDefaultSettings = ¿Seguro que quieres volver a los ajustes de fábrica?\ RestoreGameDefaultSettings = ¿Seguro que quieres reestablecer los ajustes del juego\na los ajustes por defecto de PPSSPP? Resume = Reanudar Run CPU Tests = Ejecutando pruebas de CPU -Save language ini = Guardar INI de idioma Save new textures = Guardar nuevas texturas Shader Viewer = Visor de shader Show Developer Menu = Mostrar menú de desarrollador diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index a6b34a1ffc..be7146f4d8 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = ‎زبان -Load language ini = ‎ini بارگیری فایل زبان با فرمت Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = ‎آیا شما می خواهید که تمامی تن RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = ‎CPU اجرای تست -Save language ini = ‎ini ذخیره فایل زبان با فرمت Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index ca90f9ee59..b14de050e4 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Lataa kielipaketti Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Suorita suoritin testi -Save language ini = Tallenna kielipaketti Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index b0ee687e0f..c383bb1e01 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = Profilage du GPU Jit Compare = Comparaison JIT JIT debug tools = Outils de débogage JIT -Language = Langue -Load language ini = Charger fichier de langue Log Dropped Frame Statistics = Enregistrer les statistiques sur les pertes d'images Log Level = Niveau du journal Log View = Voir le journal @@ -261,7 +259,6 @@ RestoreDefaultSettings = Êtes-vous sûr de vouloir restaurer tous les paramètr RestoreGameDefaultSettings = Êtes-vous sûr de vouloir restaurer tous les paramètres\nspécifiques au jeu à leur valeur par défaut de PPSSPP ? Resume = Reprendre Run CPU Tests = Exécuter des tests CPU -Save language ini = Sauvegarder fichier de langue Save new textures = Sauvegarder les nouvelles textures Shader Viewer = Visionneur de shader Show Developer Menu = Montrer le menu développeur "MenuDev" diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 0eae2bdca3..68cb80b771 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Comparación JIT JIT debug tools = JIT debug tools -Language = Idioma -Load language ini = Cargar INI de idioma Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Nivel de rexistro Log View = Ver o rexistro @@ -261,7 +259,6 @@ RestoreDefaultSettings = Seguro que queres volver ós axustes de fábrica?\nOs c RestoreGameDefaultSettings = Seguro que queres reestablecer os axustes do xogo\nós axustes por defecto de PPSSPP? Resume = Resume Run CPU Tests = Probas de CPU -Save language ini = Gardar INI de idioma Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Mostrar menú de desenrolo diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index ba97120998..f986ec024d 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Σύγκριση Jit JIT debug tools = JIT debug tools -Language = Γλώσσα -Load language ini = Φόρτωση ini γλώσσας Log Dropped Frame Statistics = Καταγραφή Στατιστικών για Dropped Frames Log Level = Επίπεδο καταγραφής Log View = Εμφάνιση καταγραφέα @@ -261,7 +259,6 @@ RestoreDefaultSettings = Είστε σίγουροι ότι θέλετε να ε RestoreGameDefaultSettings = Είστε σίγουροι ότι θέλετε να επαναφέρετε τις ρυθμίσεις παιχνιδιού\nστις προεπιλεγμένες του PPSSPP; Resume = Resume Run CPU Tests = Εκκίνηση τέστ CPU -Save language ini = Αποθήκευση ini γλώσσας Save new textures = Αποθήκευση νέων υφών Shader Viewer = Προβολέας Shader Show Developer Menu = Εμφάνιση μενού προγραμματιστών diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 8f044514f2..50bb2049b2 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = שפה -Load language ini = טען קובץ שפה Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = הרץ בדיקות מעבד -Save language ini = שמור קובץ שפה Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 0757a585e2..5e94eea165 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = הפש -Load language ini = הפש ץבוק ןעט Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = דבעמ תוקידב ץרה -Save language ini = הפש ץבוק רומש Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 7fe5d2de2a..33f465633e 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profil Jit Compare = JIT uspoređivanje JIT debug tools = JIT debug alati -Language = Jezik -Load language ini = Učitaj language ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log pregled @@ -261,7 +259,6 @@ RestoreDefaultSettings = Jesi li siguran da želiš vratiti sve postavke na zada RestoreGameDefaultSettings = Jesi li siguran da želiš vratiti igrom-specifične postavke \nna PPSSPP zadane postavke? Resume = Resume Run CPU Tests = Pokreni CPU testove -Save language ini = Spremi language ini Save new textures = Spremi nove teksture Shader Viewer = Pregled sjenčanja Show Developer Menu = Prikaži developer izbornik diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 078b25d446..0a7fdae059 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profil Jit Compare = JIT összehasonlítás JIT debug tools = JIT hibakereső eszközök -Language = Nyelv -Load language ini = Nyelvi .ini betöltése Log Dropped Frame Statistics = Eldobott képkockák statisztikáinak naplózása Log Level = Naplózási szint Log View = Nápló megtekintése @@ -261,7 +259,6 @@ RestoreDefaultSettings = Biztos vagy benne, hogy mindent az alapértelmezettre RestoreGameDefaultSettings = Biztos vagy benne, hogy minden játék-specifikus beállítást\nvisszaállítáasz a PPSSPP alapértelmezettre? Resume = Resume Run CPU Tests = CPU tesztek futtatása -Save language ini = Nyelvi .ini mentése Save new textures = Új textúrák mentése Shader Viewer = Shader megjelenítő Show Developer Menu = Fejlesztői menü megjelenítése diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 3334854770..0c86521812 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = Profil GPU Jit Compare = Bandingkan Jit JIT debug tools = Alat awakutu JIT -Language = Bahasa -Load language ini = Muat *.ini bahasa Log Dropped Frame Statistics = Log statistik laju bingkai yang jatuh Log Level = Tingkatan pencatat Log View = Tampilan pencatat @@ -261,7 +259,6 @@ RestoreDefaultSettings = Apakah Anda yakin ingin mengembalikan semua pengaturan RestoreGameDefaultSettings = Apakah Anda yakin ingin mengembalikan pengaturan permainan\nkembali ke pengaturan awal PPSSPP? Resume = Lanjutkan Run CPU Tests = Jalankan pengujian CPU -Save language ini = Simpan *.ini bahasa Save new textures = Simpan tekstur baru Shader Viewer = Penampil shader Show Developer Menu = Tampilkan menu pengembang diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 98cae99ab4..024e59c236 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = Profilo GPU Jit Compare = Confronto Jit JIT debug tools = Strumenti di debug JIT -Language = Lingua -Load language ini = Carica *.ini della lingua Log Dropped Frame Statistics = Statistiche dei Frame persi Log Level = Livello del Log Log View = Visualizza Log @@ -261,7 +259,6 @@ RestoreDefaultSettings = Si desidera davvero ripristinare le impostazioni?\nImpo RestoreGameDefaultSettings = Si desidera davvero ripristinare le impostazioni specifiche per il gioco\nai valori predefiniti? Resume = Ripristina Run CPU Tests = Fai Test CPU -Save language ini = Salva *.ini della lingua Save new textures = Salva nuove texture Shader Viewer = Visualizzatore shader Show Developer Menu = Mostra Menu Sviluppatore diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index b71db3088f..18235dca8e 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -244,8 +244,6 @@ GPU Profile = GPUプロファイル GPU Log Profiler = GPUログプロファイラ Jit Compare = JIT 比較 JIT debug tools = JITデバッグツール -Language = 言語 -Load language ini = 言語のiniファイルをロードする Log Dropped Frame Statistics = ドロップしたフレームの統計を記録する Log Level = ログレベル Log View = ログビュー @@ -261,7 +259,6 @@ RestoreDefaultSettings = 全ての設定 (キーの設定は除く) をデフォ RestoreGameDefaultSettings = ゲームの設定をPPSSPPのデフォルトに\n戻しますか? Resume = Resume Run CPU Tests = CPUテストを実行する -Save language ini = 言語のiniファイルをセーブする Save new textures = 新しいテクスチャを保存する Shader Viewer = シェーダビューワ Show Developer Menu = 開発者向けメニューを表示する diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 11d8a9f749..62d4c8eaba 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit mbandhingake JIT debug tools = JIT debug tools -Language = Basa -Load language ini = Mbukak file basa Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Tingkat Log Log View = Tampilan Log @@ -261,7 +259,6 @@ RestoreDefaultSettings = Apa panjenengan yakin arep mulihake kabeh setelan bali RestoreGameDefaultSettings = Apa panjenengan yakin arep mulihake setelan-game tartamtu back kanggo awal PPSSPP? Resume = Resume Run CPU Tests = Mbukak Tes CPU -Save language ini = Simpen berkas basa Save new textures = Save new textures Shader Viewer = Tampilan shader Show Developer Menu = Tampilno menu pengembang diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index ed99fe419f..b7b3a20308 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -244,8 +244,6 @@ GPU Profile = GPU 프로파일 GPU Log Profiler = GPU 로그 프로파일러 Jit Compare = JIT 비교 JIT debug tools = JIT 디버그 도구 -Language = 언어 -Load language ini = 언어 ini 불러오기 Log Dropped Frame Statistics = 삭제된 프레임 통계 기록 Log Level = 로그 레벨 Log View = 로그 보기 @@ -261,7 +259,6 @@ RestoreDefaultSettings = 모든 설정을 기본값으로 되돌리겠습니까? RestoreGameDefaultSettings = 게임별 설정을\nPPSSPP 기본값으로 복원하겠습니까? Resume = 다시 시작 Run CPU Tests = CPU 테스트 실행 -Save language ini = 언어 ini 저장 Save new textures = 새로운 텍스처 저장 Shader Viewer = 셰이더 뷰어 Show Developer Menu = 개발자 메뉴 표시 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 5c7d4a9b38..d1413e8535 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = ພາສາ -Load language ini = ໂຫຼດໄຟລ໌ພາສາ (.ini) Log Dropped Frame Statistics = ເກັບຄ່າສະຖິຕິເຟຣມເຣດຕົກ Log Level = ເກັບຄ່າລະດັບ Log View = ເກັບຄ່າມຸມມອງ @@ -261,7 +259,6 @@ RestoreDefaultSettings = ເຈົ້າແນ່ໃຈຫຼືບໍ່ວ່ RestoreGameDefaultSettings = ເຈົ້າແນ່ໃຈຫຼືບໍ່ວ່າຕ້ອງການຄືນຄ່າການຕັ້ງຄ່າເກມໂດຍສະເພາະ\nກັບສູ່ຄ່າເລີ່ມຕົ້ນ PPSSPP ຫຼືບໍ່? Resume = Resume Run CPU Tests = ເອີ້ນໃຊ້ການທົດສອບ CPU -Save language ini = ບັນທຶກພາສາຂອງ ini Save new textures = ບັນທຶກພື້ນຜິວໃໝ່ Shader Viewer = ມຸມມອງການປັບໄລ່ເສດສີ Show Developer Menu = ສະແດງເມນູສຳລັບນັກພັດທະນາ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 175b803d95..92dddc81dc 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Kalba -Load language ini = Krauti kalbos .ini failą Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Ar atstatyti "PPSSPP" parametrus į numatytuosius?\nVal RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Atidaryti pagrindinio procesoriaus testus -Save language ini = Išsaugoti kalbos .ini failą Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Rodyti kūrėjų meniu diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index d0a92de800..1482e2e6b7 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = Alat pepijat JIT -Language = Bahasa -Load language ini = Muatkan bahasa ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Anda pasti menetapkan semua tetapan kecuali pemetaan ka RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Jalankan percubaan CPU -Save language ini = Simpan bahasa .ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Papar menu pembangun diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index a607f67e07..36a99debca 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit vergelijken JIT debug tools = JIT debug tools -Language = Taal -Load language ini = Taal-ini laden Log Dropped Frame Statistics = Overgeslagen framestatistieken vastleggen Log Level = Logniveau Log View = Logboekoverzicht @@ -261,7 +259,6 @@ RestoreDefaultSettings = Weet u zeker dat u alle instellingen wilt herstellen\nn RestoreGameDefaultSettings = Weet u zeker dat u de game-specifieke instellingen wilt\nherstellen naar de standaardwaarden van PPSSPP? Resume = Resume Run CPU Tests = CPU-controles uitvoeren -Save language ini = Taal-ini opslaan Save new textures = Nieuwe textures opslaan Shader Viewer = Shader weergeven Show Developer Menu = Ontwikkelaarsmenu weergeven diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 090ee1b011..44c86118f0 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Åpne språk-ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Kjør CPU-test -Save language ini = Lagre språk-ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 5aca263510..cd1469f063 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -244,8 +244,6 @@ GPU Log Profiler = Profilowanie logów GPU GPU Profile = Profil GPU Jit Compare = Porównywanie JIT JIT debug tools = Narzędzia debugowania JIT -Language = Język -Load language ini = Wczytaj plik ini języka Log Dropped Frame Statistics = Loguj statystyki pominiętych klatek Log Level = Poziom dziennika zdarzeń Log View = Pokaż dziennik zdarzeń @@ -261,7 +259,6 @@ RestoreDefaultSettings = Czy na pewno chcesz przywrócić domyślne ustawienia?\ RestoreGameDefaultSettings = Czy na pewno chcesz przywrócić ustawienia specyficzne dla danych gier\npowrót do ustawień domyślnych PPSSPP? Resume = Wznów Run CPU Tests = Uruchom testy CPU -Save language ini = Zapisz plik ini języka Save new textures = Zapisz nową teksturę Shader Viewer = Podgląd Shaderów Show Developer Menu = Pokaż przycisk menu dewelopera diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 2a4e744237..990f23cb4f 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -268,8 +268,6 @@ GPU Profile = Perfil da GPU GPU Log Profiler = Criador do Perfil do Registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de debug do JIT -Language = Idioma -Load language ini = Carregar o ini do idioma Log Dropped Frame Statistics = Pôr no log as estátisticas da queda dos frames Log Level = Nível do log Log View = Visualização do log @@ -285,7 +283,6 @@ RestoreDefaultSettings = Você tem certeza que você quer restaurar todas as con RestoreGameDefaultSettings = Você tem certeza que você quer restaurar as configurações específicas do jogo\nde volta para os padrões do PPSSPP? Resume = Resumo Run CPU Tests = Executar testes da CPU -Save language ini = Salvar o ini do idioma Save new textures = Salvar novas texturas Shader Viewer = Visualizador dos shaders Show Developer Menu = Mostrar menu do desenvolvedor diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 79c47b939a..832dd499cb 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -268,8 +268,6 @@ GPU Profile = Perfil da GPU GPU Log Profiler = Criador do Perfil do Registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de depuração do JIT -Language = Idioma -Load language ini = Carregar o .ini do Idioma Log Dropped Frame Statistics = Guardar no log as estátisticas da queda dos quadros Log Level = Nível do log Log View = Visualização do log @@ -285,7 +283,6 @@ RestoreDefaultSettings = Tens a certeza que queres restaurar todas as Definiçõ RestoreGameDefaultSettings = Tens a certeza que queres restaurar as Definições específicas do jogo\nde volta para os padrões do PPSSPP? Resume = Resumir Run CPU Tests = Executar testes da CPU -Save language ini = Guardar o .ini do Idioma Save new textures = Guardar novas texturas Shader Viewer = Visualizador dos Shaders Show Developer Menu = Mostrar Menu de Desenvolvedor diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 475d0ab361..ab9d3b8c82 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Limbă -Load language ini = Deschide fişier ini limbă Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Salvează fişier ini limbă Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 92149ba8b9..b85e620042 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = Профиль ГП Jit Compare = Сравнение с JIT JIT debug tools = Инструменты отладки JIT -Language = Язык -Load language ini = Загрузить языковой .ini файл Log Dropped Frame Statistics = Логировать статистику пропущенных кадров Log Level = Уровень отладки Log View = Отображение логов @@ -261,7 +259,6 @@ RestoreDefaultSettings = "Вы уверены, что хотите сброси RestoreGameDefaultSettings = Вы уверены, что хотите вернуть все параметры игры к стандартным? Resume = Resume Run CPU Tests = Запустить тесты ЦП -Save language ini = Сохранить языковой .ini файл Save new textures = Сохранять новые текстуры Shader Viewer = Просмотрщик шейдеров Show Developer Menu = Показывать меню разработчика diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 4c9e9adc9f..28e8763f58 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Jit-jämförare JIT debug tools = JIT debug tools -Language = Språk -Load language ini = Ladda språk-ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Loggnivå Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Kör CPU-tester -Save language ini = Spara språk-ini Save new textures = Spara nya texturer Shader Viewer = Shader-visare Show Developer Menu = Visa Developer-menyn diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 77e0214328..e9ed4eaaf6 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = Ipagkumpara ang JIT JIT debug tools = JIT debug tools -Language = Wika -Load language ini = i-Load ang Language ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Level ng Log Log View = Log view @@ -261,7 +259,6 @@ RestoreDefaultSettings = Sigurado ka bang ibalik ang Ssetting sa dati?\nAng Cont RestoreGameDefaultSettings = Sigurado ka bang ibalik sa dati\nang Setting ng isang spesipikong laro?\n\n\nHindi mo na ito maibabalik.\nPaki-restart ang PPSSPP para makita ang mga binago. Resume = Resume Run CPU Tests = Magsagawa ng CPU Tests -Save language ini = Save Language ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Ipakita ang Developer Menu diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 3ea8b61435..d1d4a73702 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -244,8 +244,6 @@ GPU Log Profiler = ตัวแสดงค่าโปรไฟล์ GPU GPU Profile = โปรไฟล์ GPU Jit Compare = เปรียบเทียบระบบ JIT JIT debug tools = เครื่องมือตรวจสอบระบบ JIT -Language = ภาษา -Load language ini = โหลดไฟล์ภาษา (.ini) Log Dropped Frame Statistics = เก็บสถิติค่าเฟรมเรทตก Log Level = เก็บค่าระดับ Log View = เก็บค่ามุมมอง @@ -261,7 +259,6 @@ RestoreDefaultSettings = คุณแน่ใจรึว่าต้องก RestoreGameDefaultSettings = คุณแน่ใจรึว่าต้องการรีเซ็ตตั้งค่าเฉพาะเกม?\nการตั้งค่าของเกมนี้จะกลับไปใช้ค่าเริ่มต้นของ PPSSPP? Resume = เล่นต่อ Run CPU Tests = เรียกใช้การทดสอบซีพียู -Save language ini = บันทึกไฟล์ภาษา (.ini) Save new textures = บันทึกพื้นผิวลงในแหล่งที่เก็บข้อมูล Shader Viewer = มุมมองการปรับเฉดแสงสี Show Developer Menu = แสดงเมนูสำหรับนักพัฒนา diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 55db3ef6e2..c27b4c31f4 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -246,8 +246,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profili Jit Compare = Jit karşılaştırma JIT debug tools = JIT hata ayıklama araçları -Language = Dil -Load language ini = Dil Dosyası Yükle(.ini) Log Dropped Frame Statistics = Düşen kare istatistiklerini günlüğe kaydet Log Level = Günlük seviyesi Log View = Günlük görünümü @@ -263,7 +261,6 @@ RestoreDefaultSettings = Bütün ayarları varsayılanlarına döndürmek istedi RestoreGameDefaultSettings = Oyun için ayarlanmış olan özel ayarları PPSSPP varsayılanlarına döndürmek istediğinden emin misin? Resume = Devam ettir Run CPU Tests = İşlemci testlerini başlat -Save language ini = Dil Dosyası Kaydet (.ini) Save new textures = Yeni dokuları kaydet Shader Viewer = Shader Görüntüleyici Show Developer Menu = Geliştirici Menüsünü Göster diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 7a24e1f523..32ac166a5f 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = Профіль GPU Jit Compare = Порівняння з Jit JIT debug tools = Інструменти налагодження JIT -Language = Мова -Load language ini = Завантажити мовний .ini файл Log Dropped Frame Statistics = Лог статистики пропущених кадрів Log Level = Лог рівня Log View = Лог виду @@ -261,7 +259,6 @@ RestoreDefaultSettings = "Ви впевненні,що хочете скинут RestoreGameDefaultSettings = Ви впевнені, що хочете повернути всі параметри гри до стардартних\nповернути PPSSPP за замовчуванням ? Resume = Resume Run CPU Tests = Запустити тести CPU -Save language ini = Зберегти мовний .ini файл Save new textures = Зберегти нові текстури Shader Viewer = Переглядач шейдеру Show Developer Menu = Показати меню розробника diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 3cbb0d9d93..84a268878f 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU Log Profiler GPU Profile = GPU profile Jit Compare = So sánh Jit JIT debug tools = JIT debug tools -Language = Ngôn ngữ -Load language ini = Tải file ngôn ngữ .ini Log Dropped Frame Statistics = Khung nhật ký thống kê Log Level = Cấp nhật ký Log View = Xem nhật ký @@ -261,7 +259,6 @@ RestoreDefaultSettings = Bạn có muốn khôi phục các thiết lập về m RestoreGameDefaultSettings = Bạn có muốn khôi phục cài đặt trò chơi\nPPSSPP sẽ trở về mặc định? Resume = Resume Run CPU Tests = Chạy thử CPU -Save language ini = Lưu file ngôn ngữ .ini Save new textures = Lưu file textures mới Shader Viewer = Xem trước đỗ bóng Show Developer Menu = Hiện menu NPH diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index c40a89a968..060454ef5a 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -244,8 +244,6 @@ GPU Log Profiler = GPU日志分析器 GPU Profile = GPU分析器 Jit Compare = Jit比较 JIT debug tools = JIT调试工具 -Language = 语言设置 -Load language ini = 载入语言配置 Log Dropped Frame Statistics = 记录丢弃帧统计信息 Log Level = 日志等级 Log View = 日志视图 @@ -261,7 +259,6 @@ RestoreDefaultSettings = 您确定要将所有设置恢复到默认? (按键映 RestoreGameDefaultSettings = 您确定要将此游戏设置\n恢复为PPSSPP默认吗? Resume = 恢复 Run CPU Tests = 运行CPU测试 -Save language ini = 保存语言配置 Save new textures = 保存新纹理 Shader Viewer = 着色器查看器 Show Developer Menu = 显示开发者菜单 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index cc0fe865b1..26d9db1834 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -244,8 +244,6 @@ GPU Profile = GPU 設定檔 GPU Log Profiler = GPU 記錄分析工具 Jit Compare = JIT 比較 JIT debug tools = JIT 偵錯工具 -Language = 語言 -Load language ini = 載入語言 ini 檔案 Log Dropped Frame Statistics = 記錄捨棄影格統計資料 Log Level = 記錄層級 Log View = 記錄檢視 @@ -261,7 +259,6 @@ RestoreDefaultSettings = 您確定要將所有設定還原為預設值嗎?\n RestoreGameDefaultSettings = 您確定要將遊戲特定設定\n還原為 PPSSPP 預設值嗎? Resume = 恢復 Run CPU Tests = 執行 CPU 測試 -Save language ini = 儲存語言 ini 檔案 Save new textures = 儲存新紋理 Shader Viewer = 著色器檢視器 Show Developer Menu = 顯示開發人員選單 From d243d45741114e029ec5a2977bf289abefbaba6f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Nov 2022 16:33:31 -0800 Subject: [PATCH 392/715] GPU: Upload stencil to latest buffer. Just being safe. --- GPU/Common/StencilCommon.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 682d8a1f0c..0f454bd076 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -135,10 +135,11 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, return false; } - VirtualFramebuffer *dstBuffer = 0; + VirtualFramebuffer *dstBuffer = nullptr; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { + // TODO: Maybe we should broadcast to all? Most of the time, there's only one. + if (vfb->fb_address == addr && (!dstBuffer || dstBuffer->colorBindSeq < vfb->colorBindSeq)) { dstBuffer = vfb; } } From b33662550f0b792edd2e34219de7d18c98cd7bbf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Nov 2022 18:48:46 -0800 Subject: [PATCH 393/715] Vulkan: Use stencil export when available. This prevents multiple passes to upload stencil buffers. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + Common/GPU/D3D9/thin3d_d3d9.cpp | 1 + Common/GPU/OpenGL/GLFeatures.cpp | 1 + Common/GPU/OpenGL/GLFeatures.h | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 1 + Common/GPU/Vulkan/thin3d_vulkan.cpp | 1 + Common/GPU/thin3d.h | 1 + GPU/Common/StencilCommon.cpp | 111 +++++++++++++++++----------- GPU/Common/StencilCommon.h | 2 +- unittest/TestShaderGenerators.cpp | 26 ++++--- 10 files changed, 91 insertions(+), 55 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 46713b53f3..8b1d5c00e7 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -268,6 +268,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.anisoSupported = true; caps_.textureNPOTFullySupported = true; caps_.fragmentShaderDepthWriteSupported = true; + caps_.fragmentShaderStencilWriteSupported = false; caps_.blendMinMaxSupported = true; D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 8de75b09d0..207a09e676 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -758,6 +758,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.framebufferSeparateDepthCopySupported = false; caps_.texture3DSupported = true; caps_.fragmentShaderDepthWriteSupported = true; + caps_.fragmentShaderStencilWriteSupported = false; caps_.blendMinMaxSupported = true; if ((caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && caps.MaxAnisotropy > 1) { diff --git a/Common/GPU/OpenGL/GLFeatures.cpp b/Common/GPU/OpenGL/GLFeatures.cpp index ecec49c82e..06ef1ead3b 100644 --- a/Common/GPU/OpenGL/GLFeatures.cpp +++ b/Common/GPU/OpenGL/GLFeatures.cpp @@ -371,6 +371,7 @@ void CheckGLExtensions() { gl_extensions.ARB_uniform_buffer_object = g_set_gl_extensions.count("GL_ARB_uniform_buffer_object") != 0; gl_extensions.ARB_explicit_attrib_location = g_set_gl_extensions.count("GL_ARB_explicit_attrib_location") != 0; gl_extensions.ARB_texture_non_power_of_two = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0; + gl_extensions.ARB_shader_stencil_export = g_set_gl_extensions.count("GL_ARB_shader_stencil_export") != 0; if (gl_extensions.IsGLES) { gl_extensions.EXT_blend_func_extended = g_set_gl_extensions.count("GL_EXT_blend_func_extended") != 0; gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_OES_texture_npot") != 0; diff --git a/Common/GPU/OpenGL/GLFeatures.h b/Common/GPU/OpenGL/GLFeatures.h index 0e07fd266f..a2d20b178f 100644 --- a/Common/GPU/OpenGL/GLFeatures.h +++ b/Common/GPU/OpenGL/GLFeatures.h @@ -72,6 +72,7 @@ struct GLExtensions { bool ARB_uniform_buffer_object; bool ARB_texture_non_power_of_two; bool ARB_stencil_texturing; + bool ARB_shader_stencil_export; // EXT bool EXT_swap_control_tear; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 9878886fd0..ba55d642a5 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -575,6 +575,7 @@ OpenGLContext::OpenGLContext() { } else { caps_.fragmentShaderDepthWriteSupported = true; } + caps_.fragmentShaderStencilWriteSupported = gl_extensions.ARB_shader_stencil_export; // GLES has no support for logic framebuffer operations. There doesn't even seem to exist any such extensions. caps_.logicOpSupported = !gl_extensions.IsGLES; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index f055ad9499..819b154905 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -809,6 +809,7 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.fragmentShaderInt32Supported = true; caps_.textureNPOTFullySupported = true; caps_.fragmentShaderDepthWriteSupported = true; + caps_.fragmentShaderStencilWriteSupported = vulkan->Extensions().EXT_shader_stencil_export; caps_.blendMinMaxSupported = true; caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0; caps_.multiViewSupported = vulkan->GetDeviceFeatures().enabled.multiview.multiview != 0; diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 53d35250ce..106e6ec5dc 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -570,6 +570,7 @@ struct DeviceCaps { bool fragmentShaderInt32Supported; bool textureNPOTFullySupported; bool fragmentShaderDepthWriteSupported; + bool fragmentShaderStencilWriteSupported; bool textureDepthSupported; bool blendMinMaxSupported; bool multiViewSupported; diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 0f454bd076..c879154e46 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -58,6 +58,34 @@ static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { return bits >> 24; } +static bool CheckStencilBits(const u8 *src, const VirtualFramebuffer *dstBuffer, int &values, u8 &usedBits) { + switch (dstBuffer->fb_format) { + case GE_FORMAT_565: + // Well, this doesn't make much sense. + return false; + case GE_FORMAT_5551: + usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 2; + break; + case GE_FORMAT_4444: + usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 16; + break; + case GE_FORMAT_8888: + usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 256; + break; + case GE_FORMAT_INVALID: + case GE_FORMAT_DEPTH16: + case GE_FORMAT_CLUT8: + // Inconceivable. + _assert_(false); + return false; + } + + return true; +} + struct StencilUB { float stencilValue; }; @@ -83,8 +111,12 @@ static const SamplerDef samplers[1] = { { 0, "tex" }, }; -void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { - ShaderWriter writer(buffer, lang, ShaderStage::Fragment); +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs, bool useExport) { + std::vector extensions; + if (useExport) + extensions.push_back("#extension GL_ARB_shader_stencil_export : require"); + + ShaderWriter writer(buffer, lang, ShaderStage::Fragment, extensions); writer.HighPrecisionFloat(); writer.DeclareSamplers(samplers); @@ -98,9 +130,13 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.C(" vec4 index = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a. - writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); - // Bitwise operations on floats, ugh. - writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n"); + if (useExport) { + writer.C(" gl_FragStencilRefARB = int(roundAndScaleTo255f(index.a));\n"); + } else { + writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); + // Bitwise operations on floats, ugh. + writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n"); + } if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { writer.C(" gl_FragDepth = gl_FragCoord.z;\n"); @@ -149,34 +185,15 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, int values = 0; u8 usedBits = 0; + bool useExportShader = draw_->GetDeviceCaps().fragmentShaderStencilWriteSupported; const u8 *src = Memory::GetPointer(addr); if (!src) return false; - switch (dstBuffer->fb_format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. + // Could skip this when doing useExportShader, but then we couldn't optimize usedBits == 0. + if (!CheckStencilBits(src, dstBuffer, values, usedBits)) return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - case GE_FORMAT_DEPTH16: - case GE_FORMAT_CLUT8: - // Inconceivable. - _assert_(false); - break; - } if (usedBits == 0) { if (flags & WriteStencil::STENCIL_IS_ZERO) { @@ -202,7 +219,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, char *fsCode = new char[8192]; char *vsCode = new char[8192]; - GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs()); + GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs(), useExportShader); GenerateStencilVs(vsCode, shaderLanguageDesc); _assert_msg_(strlen(fsCode) < 8192, "StenFS length error: %d", (int)strlen(fsCode)); @@ -304,24 +321,32 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, draw_->SetScissorRect(0, 0, w, h); draw_->BindPipeline(stencilWritePipeline_); - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } + if (useExportShader) { + // We only need to do one pass if using an export shader. StencilUB ub{}; - if (dstBuffer->fb_format == GE_FORMAT_4444) { - draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF); - ub.stencilValue = i * (16.0f / 255.0f); - } else if (dstBuffer->fb_format == GE_FORMAT_5551) { - draw_->SetStencilParams(0xFF, 0xFF, 0xFF); - ub.stencilValue = i * (128.0f / 255.0f); - } else { - draw_->SetStencilParams(0xFF, i, 0xFF); - ub.stencilValue = i * (1.0f / 255.0f); - } + draw_->SetStencilParams(0xFF, 0xFF, 0xFF); draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); draw_->DrawUP(positions, 3); + } else { + for (int i = 1; i < values; i += i) { + if (!(usedBits & i)) { + // It's already zero, let's skip it. + continue; + } + StencilUB ub{}; + if (dstBuffer->fb_format == GE_FORMAT_4444) { + draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF); + ub.stencilValue = i * (16.0f / 255.0f); + } else if (dstBuffer->fb_format == GE_FORMAT_5551) { + draw_->SetStencilParams(0xFF, 0xFF, 0xFF); + ub.stencilValue = i * (128.0f / 255.0f); + } else { + draw_->SetStencilParams(0xFF, i, 0xFF); + ub.stencilValue = i * (1.0f / 255.0f); + } + draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); + draw_->DrawUP(positions, 3); + } } if (useBlit) { diff --git a/GPU/Common/StencilCommon.h b/GPU/Common/StencilCommon.h index e9746012a6..a8c16732e0 100644 --- a/GPU/Common/StencilCommon.h +++ b/GPU/Common/StencilCommon.h @@ -5,5 +5,5 @@ #include "Common/GPU/thin3d.h" // Exposed for automated tests -void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs); +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs, bool useExport); void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang); diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index 6701e162fd..7722c9f947 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -291,17 +291,21 @@ bool TestStencilShaders() { ShaderLanguageDesc desc(languages[k]); std::string errorMessage; - // Generate all despite failures - it's only 6. - GenerateStencilFs(buffer, desc, bugs); - if (strlen(buffer) >= 8192) { - printf("Stencil fragment shader exceeded buffer:\n\n%s\n", LineNumberString(buffer).c_str()); - failed = true; - } - if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { - printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); - failed = true; - } else { - printf("===\n%s\n===\n", buffer); + // Generate all despite failures - it's only a few. + // Only use export on Vulkan, because GLSL_3xx is ES which doesn't support stencil export. + bool allowUseExport = languages[k] == ShaderLanguage::GLSL_VULKAN; + for (int useExport = 0; useExport <= (allowUseExport ? 1 : 0); ++useExport) { + GenerateStencilFs(buffer, desc, bugs, useExport == 1); + if (strlen(buffer) >= 8192) { + printf("Stencil fragment shader (useExport=%d) exceeded buffer:\n\n%s\n", useExport, LineNumberString(buffer).c_str()); + failed = true; + } + if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { + printf("Error compiling stencil shader (useExport=%d):\n\n%s\n\n%s\n", useExport, LineNumberString(buffer).c_str(), errorMessage.c_str()); + failed = true; + } else { + printf("===\n%s\n===\n", buffer); + } } GenerateStencilVs(buffer, desc); From 9fcccd789a40b3d73c98e13183f9f5df8f1ecaf2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 24 Nov 2022 19:09:42 -0800 Subject: [PATCH 394/715] Vulkan: Correct displayed depth/stencil format. Also corrects handling of non-24 bit depth when reducing the range. --- Common/GPU/DataFormat.h | 1 + Common/GPU/Vulkan/thin3d_vulkan.cpp | 24 +++++++++++++++++++++++- Common/GPU/thin3d.cpp | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Common/GPU/DataFormat.h b/Common/GPU/DataFormat.h index b116ac9ab1..32463d3a16 100644 --- a/Common/GPU/DataFormat.h +++ b/Common/GPU/DataFormat.h @@ -65,6 +65,7 @@ enum class DataFormat : uint8_t { S8, D16, + D16_S8, D24_S8, D32F, D32F_S8, diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 819b154905..1626958e91 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -592,6 +592,8 @@ static int GetBpp(VkFormat format) { static VkFormat DataFormatToVulkan(DataFormat format) { switch (format) { case DataFormat::D16: return VK_FORMAT_D16_UNORM; + case DataFormat::D16_S8: return VK_FORMAT_D16_UNORM_S8_UINT; + case DataFormat::D24_S8: return VK_FORMAT_D24_UNORM_S8_UINT; case DataFormat::D32F: return VK_FORMAT_D32_SFLOAT; case DataFormat::D32F_S8: return VK_FORMAT_D32_SFLOAT_S8_UINT; case DataFormat::S8: return VK_FORMAT_S8_UINT; @@ -784,6 +786,25 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur return true; } +static DataFormat DataFormatFromVulkanDepth(VkFormat fmt) { + switch (fmt) { + case VK_FORMAT_D24_UNORM_S8_UINT: + return DataFormat::D24_S8; + case VK_FORMAT_D16_UNORM: + return DataFormat::D16; + case VK_FORMAT_D32_SFLOAT: + return DataFormat::D32F; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return DataFormat::D32F_S8; + case VK_FORMAT_D16_UNORM_S8_UINT: + return DataFormat::D16_S8; + default: + break; + } + + return DataFormat::UNDEFINED; +} + VKContext::VKContext(VulkanContext *vulkan) : vulkan_(vulkan), renderManager_(vulkan) { shaderLanguageDesc_.Init(GLSL_VULKAN); @@ -803,7 +824,8 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.framebufferStencilBlitSupported = caps_.framebufferDepthBlitSupported; caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case. - caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. + // This doesn't affect what depth/stencil format is actually used, see VulkanQueueRunner. + caps_.preferredDepthBufferFormat = DataFormatFromVulkanDepth(vulkan->GetDeviceInfo().preferredDepthStencilFormat); caps_.texture3DSupported = true; caps_.textureDepthSupported = true; caps_.fragmentShaderInt32Supported = true; diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index fab4e665d1..a93a876766 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -46,6 +46,7 @@ size_t DataFormatSizeInBytes(DataFormat fmt) { case DataFormat::S8: return 1; case DataFormat::D16: return 2; + case DataFormat::D16_S8: return 3; case DataFormat::D24_S8: return 4; case DataFormat::D32F: return 4; // Or maybe 8... @@ -68,6 +69,7 @@ const char *DataFormatToString(DataFormat fmt) { case DataFormat::S8: return "S8"; case DataFormat::D16: return "D16"; + case DataFormat::D16_S8: return "D16_S8"; case DataFormat::D24_S8: return "D24_S8"; case DataFormat::D32F: return "D32F"; case DataFormat::D32F_S8: return "D32F_S8"; @@ -80,6 +82,7 @@ const char *DataFormatToString(DataFormat fmt) { bool DataFormatIsDepthStencil(DataFormat fmt) { switch (fmt) { case DataFormat::D16: + case DataFormat::D16_S8: case DataFormat::D24_S8: case DataFormat::S8: case DataFormat::D32F: From 5417e828de7f77c62c7ec314996e7f07fc24ade4 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 09:05:48 +0100 Subject: [PATCH 395/715] OpenXR - Do not rescale the postprocess effects --- GPU/GLES/ShaderManagerGLES.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index aed35841f8..446413014e 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -385,7 +385,8 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu // Set HUD mode if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - bool hud = is2D && !flatScreen && + bool postprocess = ((gstate_c.curTextureWidth % 480 == 0) && (gstate_c.curTextureHeight % 272 == 0)) || gstate_c.textureFullAlpha; + bool hud = is2D && !flatScreen && !postprocess && gstate.isAlphaBlendEnabled() && //2D content has to be blended !gstate.isLightingEnabled() && //2D content cannot be rendered with lights on !gstate.isFogEnabled() && //2D content cannot be rendered with fog on From a58ea86318bd236d3b02c65cd715f86cfed1a225 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 09:18:16 +0100 Subject: [PATCH 396/715] OpenXR - HUD scale option added --- Core/Config.cpp | 1 + Core/Config.h | 1 + GPU/GLES/ShaderManagerGLES.cpp | 5 ++--- UI/GameSettingsScreen.cpp | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 35a05ba910..5ba047389d 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1214,6 +1214,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), + ConfigSetting("VRHeadUpDidplayScale", &g_Config.fHeadUpDidplayScale, 0.5f), ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f), ConfigSetting(false), diff --git a/Core/Config.h b/Core/Config.h index af20f6289e..e99db82d10 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -471,6 +471,7 @@ public: float fCameraSide; float fCanvasDistance; float fFieldOfViewPercentage; + float fHeadUpDidplayScale; float fMotionLength; // Debugger diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 446413014e..5458342ad9 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -392,9 +392,8 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu !gstate.isFogEnabled() && //2D content cannot be rendered with fog on !gstate.isDepthWriteEnabled(); //This breaks minimap in GTA but works elsewhere if (hud) { - float scale = 0.5f; - render_->SetUniformF1(&u_scaleX, scale); - render_->SetUniformF1(&u_scaleY, scale / 480.0f * 272.0f); + render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale); + render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDidplayScale / 480.0f * 272.0f); } else { render_->SetUniformF1(&u_scaleX, 1.0f); render_->SetUniformF1(&u_scaleY, 1.0f); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index ef7d5b6c3a..f444c0e23c 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1103,6 +1103,7 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadUpDidplayScale, 0.2f, 1.0f, vr->T("Head up display scale"), 0.1f, screenManager(), "")); vrSettings->Add(new ItemHeader(vr->T("VR controllers"))); vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); From 08432dd4e1bee5fd7b3c862f989e5606416afa16 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 09:25:23 +0100 Subject: [PATCH 397/715] OpenXR - Camera controls adjust HUD instead of FOV --- Common/VR/PPSSPPVR.cpp | 6 +++--- Core/Config.cpp | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 0fba20ac61..7e9241042f 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -316,9 +316,9 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); break; case JOYSTICK_AXIS_Z: - if (axis.second < -0.75f) g_Config.fFieldOfViewPercentage -= 1.0f; - if (axis.second > 0.75f) g_Config.fFieldOfViewPercentage += 1.0f; - g_Config.fFieldOfViewPercentage = clampFloat(g_Config.fFieldOfViewPercentage, 100.0f, 200.0f); + if (axis.second < -0.75f) g_Config.fHeadUpDidplayScale -= 0.01f; + if (axis.second > 0.75f) g_Config.fHeadUpDidplayScale += 0.01f; + g_Config.fHeadUpDidplayScale = clampFloat(g_Config.fHeadUpDidplayScale, 0.2f, 1.0f); break; case JOYSTICK_AXIS_RZ: if (axis.second > 0.75f) g_Config.fCameraDistance -= 0.1f; diff --git a/Core/Config.cpp b/Core/Config.cpp index 5ba047389d..49b2e953ba 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1214,7 +1214,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), - ConfigSetting("VRHeadUpDidplayScale", &g_Config.fHeadUpDidplayScale, 0.5f), + ConfigSetting("VRHeadUpDidplayScale", &g_Config.fHeadUpDidplayScale, 0.3f), ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f), ConfigSetting(false), diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 5458342ad9..698e7afd49 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -392,8 +392,8 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu !gstate.isFogEnabled() && //2D content cannot be rendered with fog on !gstate.isDepthWriteEnabled(); //This breaks minimap in GTA but works elsewhere if (hud) { - render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale); - render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDidplayScale / 480.0f * 272.0f); + render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale * 480.0f / 272.0f); + render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDidplayScale); } else { render_->SetUniformF1(&u_scaleX, 1.0f); render_->SetUniformF1(&u_scaleY, 1.0f); From e4234bcfaf2739852721da9b68f6d7e60f9d6405 Mon Sep 17 00:00:00 2001 From: iota97 Date: Fri, 25 Nov 2022 09:31:30 +0100 Subject: [PATCH 398/715] Solve easy exercise left to the reader --- UI/TouchControlLayoutScreen.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 47a4b918d6..31fffd6ff4 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -330,15 +330,11 @@ public: float yOffset = bounds_.y; dc.Draw()->Rect((x1+x2)/2 + xOffset - pixel_in_dps_x, y1 + yOffset, 3.0*pixel_in_dps_x, y2-y1, col); - for (int x = (x1+x2)/2 - g_Config.iTouchSnapGridSize; x > 0; x -= g_Config.iTouchSnapGridSize) - dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col); - for (int x = (x1+x2)/2 + g_Config.iTouchSnapGridSize; x < x2; x += g_Config.iTouchSnapGridSize) - dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col); - dc.Draw()->Rect(x1 + xOffset, (y1+y2)/2 + yOffset - pixel_in_dps_y, x2-x1, 3.0*pixel_in_dps_y, col); - for (int y = (y1+y2)/2 - g_Config.iTouchSnapGridSize; y > 0; y -= g_Config.iTouchSnapGridSize) - dc.Draw()->hLine(x1 + xOffset, y + yOffset, x2 + xOffset, col); - for (int y = (y1+y2)/2 + g_Config.iTouchSnapGridSize; y < y2; y += g_Config.iTouchSnapGridSize) + + for (int x = x1 + (x1+x2)/2 % g_Config.iTouchSnapGridSize; x < x2; x += g_Config.iTouchSnapGridSize) + dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col); + for (int y = y1 + (y1+y2)/2 % g_Config.iTouchSnapGridSize; y < y2; y += g_Config.iTouchSnapGridSize) dc.Draw()->hLine(x1 + xOffset, y + yOffset, x2 + xOffset, col); dc.Flush(); From 3aae47c331961ad6d9ad81a5803e7c1ae9f11d45 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 09:31:44 +0100 Subject: [PATCH 399/715] OpenXR - Add a TODO for follow-up PR --- GPU/GLES/ShaderManagerGLES.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 698e7afd49..064abbeeb7 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -390,7 +390,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu gstate.isAlphaBlendEnabled() && //2D content has to be blended !gstate.isLightingEnabled() && //2D content cannot be rendered with lights on !gstate.isFogEnabled() && //2D content cannot be rendered with fog on - !gstate.isDepthWriteEnabled(); //This breaks minimap in GTA but works elsewhere + !gstate.isDepthWriteEnabled(); //TODO:this needs to be improved! (GTA-LC, Tekken 6, Sonic Rivals) if (hud) { render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale * 480.0f / 272.0f); render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDidplayScale); From 38fa30b42ddc094bcd4aac57a2aa032c8e4bd1d5 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 09:43:12 +0100 Subject: [PATCH 400/715] OpenXR - Camera adjust reset fixed --- Common/VR/PPSSPPVR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 7e9241042f..4152eb3896 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -430,7 +430,7 @@ bool UpdateVRKeys(const KeyInput &key) { g_Config.fCameraHeight = 0; g_Config.fCameraSide = 0; g_Config.fCameraDistance = 0; - g_Config.fFieldOfViewPercentage = 100; + g_Config.fHeadUpDidplayScale = 0.3f; } //block keys by camera adjust From 23ba0d05155ce25091256e87430873c11205bd07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Nov 2022 10:23:59 +0100 Subject: [PATCH 401/715] Fix layout issues in AbstractChoiceWithValueDisplay. Remove title text from post shaders to fit. --- Common/UI/UIScreen.cpp | 34 ++++++++++++++++++++++------------ Common/UI/View.cpp | 2 +- UI/DisplayLayoutScreen.cpp | 3 ++- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 41ec1bb76d..c56d09856a 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -849,20 +849,30 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { dc.SetFontStyle(dc.theme->uiFont); const std::string valueText = ValueText(); - // Assume we want at least 20% of the size for the label, at a minimum. - float availWidth = (bounds_.w - paddingX * 2) * 0.8f; - float scale = CalculateValueScale(dc, valueText, availWidth); - float w, h; - Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); - textPadding_.right = w + paddingX; + // If there is a label, assume we want at least 20% of the size for it, at a minimum. - Choice::Draw(dc); - dc.SetFontScale(scale, scale); - Bounds valueBounds(bounds_.x2() - textPadding_.right, bounds_.y, w, bounds_.h); - dc.DrawTextRect(valueText.c_str(), valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); - dc.SetFontScale(1.0f, 1.0f); + if (!text_.empty()) { + float availWidth = (bounds_.w - paddingX * 2) * 0.8f; + float scale = CalculateValueScale(dc, valueText, availWidth); + + float w, h; + Bounds availBounds(0, 0, availWidth, bounds_.h); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + textPadding_.right = w + paddingX; + + Choice::Draw(dc); + dc.SetFontScale(scale, scale); + Bounds valueBounds(bounds_.x2() - textPadding_.right, bounds_.y, w, bounds_.h); + dc.DrawTextRect(valueText.c_str(), valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.SetFontScale(1.0f, 1.0f); + } else { + Choice::Draw(dc); + float scale = CalculateValueScale(dc, valueText, bounds_.w); + dc.SetFontScale(scale, scale); + dc.DrawTextRect(valueText.c_str(), bounds_.Expand(-paddingX, 0.0f), style.fgColor, ALIGN_LEFT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.SetFontScale(1.0f, 1.0f); + } } float AbstractChoiceWithValueDisplay::CalculateValueScale(const UIContext &dc, const std::string &valueText, float availWidth) const { diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 4ca46140a2..efc8cd13e4 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -483,7 +483,7 @@ void Choice::Draw(UIContext &dc) { if (image_.isValid() && text_.empty()) { dc.Draw()->DrawImageRotated(image_, bounds_.centerX(), bounds_.centerY(), imgScale_, imgRot_, style.fgColor, imgFlipH_); - } else { + } else if (!text_.empty()) { dc.SetFontStyle(dc.theme->uiFont); int paddingX = 12; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 38a539b2af..2eb008e2d1 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -287,7 +287,8 @@ void DisplayLayoutScreen::CreateViews() { for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; - postProcChoice_ = rightColumn->Add(new ChoiceWithValueDisplay(&shaderNames_[i], StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1), &PostShaderTranslateName)); + rightColumn->Add(new ItemHeader(StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1))); + postProcChoice_ = rightColumn->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName)); postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); From 8c31625fdc262f7bedbd8389c93c09155997919c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Nov 2022 10:28:03 +0100 Subject: [PATCH 402/715] Make post-shader parameter values update live --- UI/DisplayLayoutScreen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 2eb008e2d1..a126f70d8d 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -321,6 +321,8 @@ void DisplayLayoutScreen::CreateViews() { settingValue->SetEnabled(false); } else { PopupSliderChoiceFloat *settingValue = rightColumn->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetLiveUpdate(true); + settingValue->SetHasDropShadow(false); settingValue->SetEnabledFunc([=] { return !g_Config.bSkipBufferEffects && !enableStereo(); }); From d38019ee6a77d17d161791dd6fd696a75fb1610e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Nov 2022 10:48:24 +0100 Subject: [PATCH 403/715] Add basic CI support for build-testing the Android-based VR build. Note: Doesn't do APK generation, to keep things simple, instead using the old NDK build. Later should run gradle on github CI too, I guess. Fixes #15981 --- .github/workflows/build.yml | 12 ++++++++++++ android/jni/Android.mk | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d38a1ac0db..c4e7c10155 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,6 +151,18 @@ jobs: cxx: clang++ args: cd android && ./ab.sh -j2 APP_ABI=x86_64 UNITTEST=1 HEADLESS=1 id: android-x86_64 + - os: ubuntu-latest + extra: android + cc: clang + cxx: clang++ + args: cd android && ./ab.sh -j2 APP_ABI=arm64-v8a OPENXR=1 OPENXR_PLATFORM_QUEST=1 + id: android-vr-quest + - os: ubuntu-latest + extra: android + cc: clang + cxx: clang++ + args: cd android && ./ab.sh -j2 APP_ABI=arm64-v8a OPENXR=1 OPENXR_PLATFORM_PICO=1 + id: android-vr-pico - os: ubuntu-latest extra: android cc: clang diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 2fc73c6168..cc507e101d 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -739,6 +739,18 @@ ifeq ($(HEADLESS),1) include $(BUILD_EXECUTABLE) endif +ifeq ($(OPENXR),1) + LOCAL_CFLAGS += -DOPENXR +endif + +ifeq ($(OPENXR_PLATFORM_QUEST),1) + LOCAL_CFLAGS += -DOPENXR_PLATFORM_QUEST +endif + +ifeq ($(OPENXR_PLATFORM_PICO),1) + LOCAL_CFLAGS += -DOPENXR_PLATFORM_PICO +endif + ifeq ($(UNITTEST),1) include $(CLEAR_VARS) include $(LOCAL_PATH)/Locals.mk From 0b089dd1e54eaac06c53c2328dba3dbad1c1b75f Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 11:08:49 +0100 Subject: [PATCH 404/715] OpenXR - HUD support improved --- GPU/GLES/ShaderManagerGLES.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 064abbeeb7..d9c6ebea42 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -385,12 +385,16 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu // Set HUD mode if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - bool postprocess = ((gstate_c.curTextureWidth % 480 == 0) && (gstate_c.curTextureHeight % 272 == 0)) || gstate_c.textureFullAlpha; + bool postprocess = gstate.isClearModeColorMask() || gstate_c.textureFullAlpha || + //rendering framebuffer on screen + (gstate_c.curTextureWidth % 480 == 0) && (gstate_c.curTextureHeight % 272 == 0) || + //rendering far plane + (fabs(gstate.viewMatrix[9]) > 1000) || (fabs(gstate.viewMatrix[11]) > 1000); + bool hud = is2D && !flatScreen && !postprocess && gstate.isAlphaBlendEnabled() && //2D content has to be blended !gstate.isLightingEnabled() && //2D content cannot be rendered with lights on - !gstate.isFogEnabled() && //2D content cannot be rendered with fog on - !gstate.isDepthWriteEnabled(); //TODO:this needs to be improved! (GTA-LC, Tekken 6, Sonic Rivals) + !gstate.isFogEnabled(); //2D content cannot be rendered with fog on if (hud) { render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale * 480.0f / 272.0f); render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDidplayScale); From 390ee28cd90543f9f1d99ca5df0b3172a02db0b5 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 12:01:51 +0100 Subject: [PATCH 405/715] OpenXR - HUD fixes --- GPU/GLES/ShaderManagerGLES.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index d9c6ebea42..29ba2ad227 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -385,16 +385,29 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu // Set HUD mode if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - bool postprocess = gstate.isClearModeColorMask() || gstate_c.textureFullAlpha || - //rendering framebuffer on screen - (gstate_c.curTextureWidth % 480 == 0) && (gstate_c.curTextureHeight % 272 == 0) || - //rendering far plane - (fabs(gstate.viewMatrix[9]) > 1000) || (fabs(gstate.viewMatrix[11]) > 1000); - bool hud = is2D && !flatScreen && !postprocess && - gstate.isAlphaBlendEnabled() && //2D content has to be blended - !gstate.isLightingEnabled() && //2D content cannot be rendered with lights on - !gstate.isFogEnabled(); //2D content cannot be rendered with fog on + bool hud = true; + //HUD cannot be rendered in flatscreen + if (flatScreen) hud = false; + //HUD has to be 2D + else if (!is2D) hud = false; + //HUD has to be blended + else if (!gstate.isAlphaBlendEnabled()) hud = false; + //HUD cannot be rendered with clear color mask + else if (gstate.isClearModeColorMask()) hud = false; + //HUD cannot be rendered with fog on + else if (gstate.isFogEnabled()) hud = false; + //HUD cannot be rendered with lights on + else if (gstate.isLightingEnabled()) hud = false; + //HUD texture has to contain alpha channel + else if (!gstate.isTextureAlphaUsed()) hud = false; + //HUD cannot have full alpha + else if (gstate_c.textureFullAlpha) hud = false; + //HUD cannot render FB screenshot + else if (gstate_c.curTextureHeight == 272) hud = false; + //HUD cannot render far plane + if ((fabs(gstate.viewMatrix[9]) > 1000) || (fabs(gstate.viewMatrix[11]) > 1000)) hud = false; + if (hud) { render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale * 480.0f / 272.0f); render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDidplayScale); From 1ef036d07cf62d309eafb016c320179054dd3d89 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 13:28:45 +0100 Subject: [PATCH 406/715] OpenXR - Farplane distance limit adjusted --- GPU/GLES/ShaderManagerGLES.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 29ba2ad227..99d3393955 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -406,7 +406,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu //HUD cannot render FB screenshot else if (gstate_c.curTextureHeight == 272) hud = false; //HUD cannot render far plane - if ((fabs(gstate.viewMatrix[9]) > 1000) || (fabs(gstate.viewMatrix[11]) > 1000)) hud = false; + if ((fabs(gstate.viewMatrix[9]) > 100) || (fabs(gstate.viewMatrix[11]) > 100)) hud = false; if (hud) { render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale * 480.0f / 272.0f); From b2d809f4cdafd12a576326edd141128c3d316364 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 15:58:51 +0100 Subject: [PATCH 407/715] typos fixed --- Common/VR/PPSSPPVR.cpp | 8 ++++---- Core/Config.cpp | 2 +- Core/Config.h | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 4 ++-- UI/GameSettingsScreen.cpp | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 4152eb3896..0a0ac9dd2f 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -316,9 +316,9 @@ void UpdateVRInput(bool(*NativeAxis)(const AxisInput &axis), bool(*NativeKey)(co g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); break; case JOYSTICK_AXIS_Z: - if (axis.second < -0.75f) g_Config.fHeadUpDidplayScale -= 0.01f; - if (axis.second > 0.75f) g_Config.fHeadUpDidplayScale += 0.01f; - g_Config.fHeadUpDidplayScale = clampFloat(g_Config.fHeadUpDidplayScale, 0.2f, 1.0f); + if (axis.second < -0.75f) g_Config.fHeadUpDisplayScale -= 0.01f; + if (axis.second > 0.75f) g_Config.fHeadUpDisplayScale += 0.01f; + g_Config.fHeadUpDisplayScale = clampFloat(g_Config.fHeadUpDisplayScale, 0.2f, 1.0f); break; case JOYSTICK_AXIS_RZ: if (axis.second > 0.75f) g_Config.fCameraDistance -= 0.1f; @@ -430,7 +430,7 @@ bool UpdateVRKeys(const KeyInput &key) { g_Config.fCameraHeight = 0; g_Config.fCameraSide = 0; g_Config.fCameraDistance = 0; - g_Config.fHeadUpDidplayScale = 0.3f; + g_Config.fHeadUpDisplayScale = 0.3f; } //block keys by camera adjust diff --git a/Core/Config.cpp b/Core/Config.cpp index 49b2e953ba..cb17b4881e 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1214,7 +1214,7 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 6.0f), ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), - ConfigSetting("VRHeadUpDidplayScale", &g_Config.fHeadUpDidplayScale, 0.3f), + ConfigSetting("VRHeadUpDisplayScale", &g_Config.fHeadUpDisplayScale, 0.3f), ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f), ConfigSetting(false), diff --git a/Core/Config.h b/Core/Config.h index e99db82d10..8b517889b0 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -471,7 +471,7 @@ public: float fCameraSide; float fCanvasDistance; float fFieldOfViewPercentage; - float fHeadUpDidplayScale; + float fHeadUpDisplayScale; float fMotionLength; // Debugger diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 99d3393955..f94e849d74 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -409,8 +409,8 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu if ((fabs(gstate.viewMatrix[9]) > 100) || (fabs(gstate.viewMatrix[11]) > 100)) hud = false; if (hud) { - render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDidplayScale * 480.0f / 272.0f); - render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDidplayScale); + render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDisplayScale * 480.0f / 272.0f); + render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDisplayScale); } else { render_->SetUniformF1(&u_scaleX, 1.0f); render_->SetUniformF1(&u_scaleY, 1.0f); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index f444c0e23c..111c4cbd37 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1103,7 +1103,7 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadUpDidplayScale, 0.2f, 1.0f, vr->T("Head up display scale"), 0.1f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadUpDisplayScale, 0.2f, 1.0f, vr->T("Heads-up display scale"), 0.1f, screenManager(), "")); vrSettings->Add(new ItemHeader(vr->T("VR controllers"))); vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); From aa66b93124d9c1c45a08ad9d5b798de2354ed5ea Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 25 Nov 2022 16:05:30 +0100 Subject: [PATCH 408/715] MOve VR heuristics into a standalone method --- GPU/GLES/ShaderManagerGLES.cpp | 52 ++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index f94e849d74..d36a68fe7a 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -353,6 +353,33 @@ static inline void FlipProjMatrix(Matrix4x4 &in, bool useBufferedRendering) { } } +static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { + + bool hud = true; + //HUD cannot be rendered in flatscreen + if (flatScreen) hud = false; + //HUD has to be 2D + else if (!is2D) hud = false; + //HUD has to be blended + else if (!gstate.isAlphaBlendEnabled()) hud = false; + //HUD cannot be rendered with clear color mask + else if (gstate.isClearModeColorMask()) hud = false; + //HUD cannot be rendered with fog on + else if (gstate.isFogEnabled()) hud = false; + //HUD cannot be rendered with lights on + else if (gstate.isLightingEnabled()) hud = false; + //HUD texture has to contain alpha channel + else if (!gstate.isTextureAlphaUsed()) hud = false; + //HUD cannot have full alpha + else if (gstate_c.textureFullAlpha) hud = false; + //HUD cannot render FB screenshot + else if (gstate_c.curTextureHeight == 272) hud = false; + //HUD cannot render far plane + else if ((fabs(gstate.viewMatrix[9]) > 100) || (fabs(gstate.viewMatrix[11]) > 100)) hud = false; + + return hud; +} + void LinkedShader::use(const ShaderID &VSID) { render_->BindProgram(program); // Note that we no longer track attr masks here - we do it for the input layouts instead. @@ -385,30 +412,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu // Set HUD mode if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - - bool hud = true; - //HUD cannot be rendered in flatscreen - if (flatScreen) hud = false; - //HUD has to be 2D - else if (!is2D) hud = false; - //HUD has to be blended - else if (!gstate.isAlphaBlendEnabled()) hud = false; - //HUD cannot be rendered with clear color mask - else if (gstate.isClearModeColorMask()) hud = false; - //HUD cannot be rendered with fog on - else if (gstate.isFogEnabled()) hud = false; - //HUD cannot be rendered with lights on - else if (gstate.isLightingEnabled()) hud = false; - //HUD texture has to contain alpha channel - else if (!gstate.isTextureAlphaUsed()) hud = false; - //HUD cannot have full alpha - else if (gstate_c.textureFullAlpha) hud = false; - //HUD cannot render FB screenshot - else if (gstate_c.curTextureHeight == 272) hud = false; - //HUD cannot render far plane - if ((fabs(gstate.viewMatrix[9]) > 100) || (fabs(gstate.viewMatrix[11]) > 100)) hud = false; - - if (hud) { + if (GuessVRDrawingHUD(is2D, flatScreen)) { render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDisplayScale * 480.0f / 272.0f); render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDisplayScale); } else { From f4b78bacd70301ae54190b7c32fb88caa480bc3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 26 Nov 2022 10:38:23 +0100 Subject: [PATCH 409/715] MacOSX: Apply potential fix for #16376 See #16376. Tested not to break anything on MacOS Mojave. Unfortunately I can't test on Ventura on my x64 mac, it's too old. --- Common/ExceptionHandlerSetup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 5594f9a5ce..deb78eb139 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -127,7 +127,7 @@ static void ExceptionThread(mach_port_t port) { #pragma pack() memset(&msg_in, 0xee, sizeof(msg_in)); memset(&msg_out, 0xee, sizeof(msg_out)); - mach_msg_header_t* send_msg = nullptr; + mach_msg_header_t* send_msg = &msg_out.Head; mach_msg_size_t send_size = 0; mach_msg_option_t option = MACH_RCV_MSG; while (true) { From 0b375bb357b86c826c446dee50e5b2223b26b1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 26 Nov 2022 18:53:13 +0100 Subject: [PATCH 410/715] Colin McRae: Use compat flag to avoid GPU readbacks for VRAM->VRAM copies. Improves performance when the sun is visible, see #7810 --- GPU/Common/FramebufferManagerCommon.cpp | 20 ++++++++++++-------- assets/compat.ini | 6 ++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index a2f466da68..32a5156ffd 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1353,10 +1353,12 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { shaderManager_->DirtyLastShader(); if (displayFramebufPtr_ == 0) { - if (Core_IsStepping()) - VERBOSE_LOG(FRAMEBUF, "Display disabled, displaying only black"); - else - DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); + if (GetUIState() != UISTATE_PAUSEMENU) { + if (Core_IsStepping()) + VERBOSE_LOG(FRAMEBUF, "Display disabled, displaying only black"); + else + DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); + } // No framebuffer to display! Clear to black. if (useBufferedRendering_) { draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput"); @@ -1444,10 +1446,12 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { displayFramebuf_ = vfb; if (vfb->fbo) { - if (Core_IsStepping()) - VERBOSE_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); - else - DEBUG_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + if (GetUIState() != UISTATE_PAUSEMENU) { + if (Core_IsStepping()) + VERBOSE_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + else + DEBUG_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + } float u0 = offsetX / (float)vfb->bufferWidth; float v0 = offsetY / (float)vfb->bufferHeight; diff --git a/assets/compat.ini b/assets/compat.ini index 70ff01fcf4..85e7e9c693 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -678,6 +678,12 @@ ULJS00233 = true NPJH90089 = true # (demo) NPJH90065 = true # Unknown +# Colin McRae 2005 (sun effect, see #7810) +ULES00111 = true +ULKS46010 = true +ULJM05223 = true +ULJM05362 = true + # Note! This whole flag is disabled temporarily by appending "Disabled" to its name). See 7914 [YugiohSaveFixDisabled] # The cause of Yu-gi-oh series 's bad save (cannot save) are load "save status" and use cwcheat, From 2e1e11f116cb2f87a9bc72c93d83badaf5d9a25d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Nov 2022 12:03:21 -0800 Subject: [PATCH 411/715] PPGe: Respect 512 texture limit. If a message ends up rendering wider than 512 (which can happen because we use higher quality fonts than 1x), draw in tiles to avoid accessing texels outside 512. Fixes an issue in Sakura Taisen in the software renderer. --- Core/Util/PPGeDraw.cpp | 63 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index d7559c0fa1..9d0c6f832c 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -913,12 +913,20 @@ static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, const PP return; } + // Sometimes our texture can be larger than 512 wide, which means we need to tile it. int bufw = ((im.entry.bmWidth + 31) / 32) * 32; - int wp2 = GetPow2(im.entry.bmWidth); + int tile1bmWidth = std::min(512, im.entry.bmWidth); + int tile2bmWidth = tile1bmWidth == 512 ? im.entry.bmWidth - 512 : 0; + bool hasTile2 = tile2bmWidth != 0; + + // Now figure the tile shift value. + int tile1wp2 = GetPow2(tile1bmWidth); + int tile2wp2 = hasTile2 ? GetPow2(tile2bmWidth) : 0; int hp2 = GetPow2(im.entry.bmHeight); + WriteCmd(GE_CMD_TEXADDR0, im.ptr & 0xFFFFF0); WriteCmd(GE_CMD_TEXBUFWIDTH0, bufw | ((im.ptr & 0xFF000000) >> 8)); - WriteCmd(GE_CMD_TEXSIZE0, wp2 | (hp2 << 8)); + WriteCmd(GE_CMD_TEXSIZE0, tile1wp2 | (hp2 << 8)); WriteCmd(GE_CMD_TEXFLUSH, 0); float w = im.entry.width * style.scale; @@ -934,21 +942,62 @@ static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, const PP y -= h; BeginVertexData(); - float u1 = (float)im.entry.width / (1 << wp2); + float tile2x = 512 * style.scale; + float tile1w = hasTile2 ? 512.0f * style.scale : w; + float tile2w = hasTile2 ? w - tile1w : 0.0f; + float tile1u1 = hasTile2 ? 1.0f : (float)im.entry.width / (1 << tile1wp2); + float tile2u1 = hasTile2 ? (float)(im.entry.width - 512) / (1 << tile2wp2) : 0.0f; float v1 = (float)im.entry.height / (1 << hp2); if (style.hasShadow) { // Draw more shadows for a blurrier shadow. + u32 shadowColor = alphaMul(style.shadowColor, 0.35f); for (float dy = 0.0f; dy <= 2.0f; dy += 1.0f) { for (float dx = 0.0f; dx <= 1.0f; dx += 0.5f) { if (dx == 0.0f && dy == 0.0f) continue; - Vertex(x + dx, y + dy, 0, 0, 1 << wp2, 1 << hp2, alphaMul(style.shadowColor, 0.35f)); - Vertex(x + dx + w, y + dy + h, u1, v1, 1 << wp2, 1 << hp2, alphaMul(style.shadowColor, 0.35f)); + + Vertex(x + dx, y + dy, 0, 0, 1 << tile1wp2, 1 << hp2, shadowColor); + Vertex(x + dx + tile1w, y + dy + h, tile1u1, v1, 1 << tile1wp2, 1 << hp2, shadowColor); } } + + // Did we need another tile? + if (hasTile2) { + // Flush to change to tile2. + EndVertexDataAndDraw(GE_PRIM_RECTANGLES); + BeginVertexData(); + WriteCmd(GE_CMD_TEXADDR0, (im.ptr & 0xFFFFF0) + 256); + WriteCmd(GE_CMD_TEXSIZE0, tile2wp2 | (hp2 << 8)); + + for (float dy = 0.0f; dy <= 2.0f; dy += 1.0f) { + for (float dx = 0.0f; dx <= 1.0f; dx += 0.5f) { + if (dx == 0.0f && dy == 0.0f) + continue; + + Vertex(x + tile2x + dx, y + dy, 0, 0, 1 << tile2wp2, 1 << hp2, shadowColor); + Vertex(x + tile2x + dx + tile2w, y + dy + h, tile2u1, v1, 1 << tile2wp2, 1 << hp2, shadowColor); + } + } + + // Return to tile1 for the text. + EndVertexDataAndDraw(GE_PRIM_RECTANGLES); + BeginVertexData(); + WriteCmd(GE_CMD_TEXADDR0, im.ptr & 0xFFFFF0); + WriteCmd(GE_CMD_TEXSIZE0, tile1wp2 | (hp2 << 8)); + } + } + + Vertex(x, y, 0, 0, 1 << tile1wp2, 1 << hp2, style.color); + Vertex(x + tile1w, y + h, tile1u1, v1, 1 << tile1wp2, 1 << hp2, style.color); + if (hasTile2) { + EndVertexDataAndDraw(GE_PRIM_RECTANGLES); + BeginVertexData(); + WriteCmd(GE_CMD_TEXADDR0, (im.ptr & 0xFFFFF0) + 256); + WriteCmd(GE_CMD_TEXSIZE0, tile2wp2 | (hp2 << 8)); + + Vertex(x + tile2x, y, 0, 0, 1 << tile2wp2, 1 << hp2, style.color); + Vertex(x + tile2x + tile2w, y + h, tile2u1, v1, 1 << tile2wp2, 1 << hp2, style.color); } - Vertex(x, y, 0, 0, 1 << wp2, 1 << hp2, style.color); - Vertex(x + w, y + h, u1, v1, 1 << wp2, 1 << hp2, style.color); EndVertexDataAndDraw(GE_PRIM_RECTANGLES); PPGeSetDefaultTexture(); From 909f3feaea04267ddbac1ccc1f8b84d098f0690b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Nov 2022 12:11:56 -0800 Subject: [PATCH 412/715] softgpu: Allow inversions when w >= -1.0. This seems to match desired cases well, see #16131. Likely still inaccurate to what hardware actually does. --- GPU/Software/Clipper.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index f7fb78405a..ccfd8f5a76 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -50,13 +50,16 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, } inline void clip_interpolate(ClipVertexData &dest, float t, const ClipVertexData &a, const ClipVertexData &b) { - dest.Lerp(t, a, b); if (different_signs(a.clippos.w, b.clippos.w)) { - dest.v.screenpos.x = 0x7FFFFFFF; - } else { - dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos); - dest.v.clipw = dest.clippos.w; + if (a.clippos.w < -1.0f || b.clippos.w < -1.0f) { + dest.v.screenpos.x = 0x7FFFFFFF; + return; + } } + + dest.Lerp(t, a, b); + dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos); + dest.v.clipw = dest.clippos.w; } #define CLIP_POLY( PLANE_BIT, A, B, C, D ) \ From 223ca5888e299e49a4f6db7f6bdb75d5bfbffd94 Mon Sep 17 00:00:00 2001 From: ThirteenAG Date: Sat, 26 Nov 2022 16:55:45 +0300 Subject: [PATCH 413/715] exposed more emulator things to devctl api added EMULATOR_DEVCTL__TOGGLE_FASTFORWARD EMULATOR_DEVCTL__GET_ASPECT_RATIO EMULATOR_DEVCTL__GET_SCALE --- Core/HLE/sceIo.cpp | 52 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index f4c98dfb6b..ca1a72160b 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -70,6 +70,8 @@ extern "C" { // For headless screenshots. #include "Core/HLE/sceDisplay.h" +// For EMULATOR_DEVCTL__GET_SCALE +#include static const int ERROR_ERRNO_IO_ERROR = 0x80010005; static const int ERROR_MEMSTICK_DEVCTL_BAD_PARAMS = 0x80220081; @@ -1980,12 +1982,29 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o if (!strcmp(name, "kemulator:") || !strcmp(name, "emulator:")) { // Emulator special tricks! + + enum + { + EMULATOR_DEVCTL__GET_HAS_DISPLAY = 1, + EMULATOR_DEVCTL__SEND_OUTPUT, + EMULATOR_DEVCTL__IS_EMULATOR, + EMULATOR_DEVCTL__VERIFY_STATE, + + EMULATOR_DEVCTL__EMIT_SCREENSHOT = 0x20, + + EMULATOR_DEVCTL__TOGGLE_FASTFORWARD = 0x30, + EMULATOR_DEVCTL__GET_ASPECT_RATIO, + EMULATOR_DEVCTL__GET_SCALE, + EMULATOR_DEVCTL__GET_LTRIGGER, + EMULATOR_DEVCTL__GET_RTRIGGER + }; + switch (cmd) { - case 1: // EMULATOR_DEVCTL__GET_HAS_DISPLAY + case EMULATOR_DEVCTL__GET_HAS_DISPLAY: if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(PSP_CoreParameter().headLess ? 0 : 1, outPtr); return 0; - case 2: // EMULATOR_DEVCTL__SEND_OUTPUT + case EMULATOR_DEVCTL__SEND_OUTPUT: { std::string data(Memory::GetCharPointer(argAddr), argLen); if (PSP_CoreParameter().printfEmuLog) { @@ -1999,17 +2018,17 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o } return 0; } - case 3: // EMULATOR_DEVCTL__IS_EMULATOR + case EMULATOR_DEVCTL__IS_EMULATOR: if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(1, outPtr); return 0; - case 4: // EMULATOR_DEVCTL__VERIFY_STATE + case EMULATOR_DEVCTL__VERIFY_STATE: // Note that this is async, and makes sure the save state matches up. SaveState::Verify(); // TODO: Maybe save/load to a file just to be sure? return 0; - case 0x20: // EMULATOR_DEVCTL__EMIT_SCREENSHOT + case EMULATOR_DEVCTL__EMIT_SCREENSHOT: { PSPPointer topaddr; u32 linesize; @@ -2019,6 +2038,29 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o host->SendDebugScreenshot(topaddr, linesize, 272); return 0; } + case EMULATOR_DEVCTL__TOGGLE_FASTFORWARD: + if (argAddr) + PSP_CoreParameter().fastForward = true; + else + PSP_CoreParameter().fastForward = false; + return 0; + case EMULATOR_DEVCTL__GET_ASPECT_RATIO: + if (Memory::IsValidAddress(outPtr)) + { + float ar = static_cast(PSP_CoreParameter().pixelWidth) / static_cast(PSP_CoreParameter().pixelHeight); + Memory::Write_U32(*(reinterpret_cast(&ar)), outPtr); + } + return 0; + case EMULATOR_DEVCTL__GET_SCALE: + if (Memory::IsValidAddress(outPtr)) + Memory::Write_U32(static_cast(dp_xres) / 480.0f, outPtr); + return 0; + case EMULATOR_DEVCTL__GET_LTRIGGER: + //To-do + return 0; + case EMULATOR_DEVCTL__GET_RTRIGGER: + //To-do + return 0; } ERROR_LOG(SCEIO, "sceIoDevCtl: UNKNOWN PARAMETERS"); From 1d0082452818abe409b6b61890ae047d28d3384e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Nov 2022 23:27:59 -0800 Subject: [PATCH 414/715] Vulkan: Only use geometry shaders with accurate z. Just to be safe, since that's what it's most well tested with. --- GPU/Vulkan/GPU_Vulkan.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 48b34baf9d..0c50c361bd 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -232,7 +232,8 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { features |= GPU_USE_TEXTURE_FLOAT; // Fall back to geometry shader culling if we can't do vertex range culling. - if (draw_->GetDeviceCaps().geometryShaderSupported) { + // Checking accurate depth here because the old depth path is uncommon and not well tested for this. + if (draw_->GetDeviceCaps().geometryShaderSupported && (features & GPU_USE_ACCURATE_DEPTH) != 0) { const bool useGeometry = g_Config.bUseGeometryShader && !draw_->GetBugs().Has(Draw::Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN); const bool vertexSupported = draw_->GetDeviceCaps().clipDistanceSupported && draw_->GetDeviceCaps().cullDistanceSupported; if (useGeometry && (!vertexSupported || (features & GPU_USE_VS_RANGE_CULLING) == 0)) { From 31af24a2303f5ef3b3ffea8cf039b636edb1570c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 10:22:37 +0100 Subject: [PATCH 415/715] Break out VKRFramebuffer/VKRRenderpass from VulkanRenderManager --- CMakeLists.txt | 2 + Common/Common.vcxproj | 2 + Common/Common.vcxproj.filters | 6 + Common/GPU/Vulkan/VulkanFramebuffer.cpp | 353 ++++++++++++++++++++++ Common/GPU/Vulkan/VulkanFramebuffer.h | 140 +++++++++ Common/GPU/Vulkan/VulkanQueueRunner.cpp | 145 --------- Common/GPU/Vulkan/VulkanQueueRunner.h | 75 +---- Common/GPU/Vulkan/VulkanRenderManager.cpp | 204 ------------- Common/GPU/Vulkan/VulkanRenderManager.h | 61 +--- android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 11 files changed, 507 insertions(+), 483 deletions(-) create mode 100644 Common/GPU/Vulkan/VulkanFramebuffer.cpp create mode 100644 Common/GPU/Vulkan/VulkanFramebuffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0eee60a31e..07e462e59d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -638,6 +638,8 @@ add_library(Common STATIC Common/GPU/Vulkan/VulkanDebug.h Common/GPU/Vulkan/VulkanContext.cpp Common/GPU/Vulkan/VulkanContext.h + Common/GPU/Vulkan/VulkanFramebuffer.cpp + Common/GPU/Vulkan/VulkanFramebuffer.h Common/GPU/Vulkan/VulkanImage.cpp Common/GPU/Vulkan/VulkanImage.h Common/GPU/Vulkan/VulkanLoader.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 15b6197cfd..d51b49d585 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -450,6 +450,7 @@ + @@ -881,6 +882,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 12a2b04191..18cbbd9985 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -455,6 +455,9 @@ GPU + + GPU\Vulkan + @@ -860,6 +863,9 @@ Render + + GPU\Vulkan + diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp new file mode 100644 index 0000000000..8f277cf676 --- /dev/null +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -0,0 +1,353 @@ +#include "Common/StringUtils.h" +#include "Common/GPU/Vulkan/VulkanFramebuffer.h" +#include "Common/GPU/Vulkan/VulkanQueueRunner.h" + +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag) + : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { + + _dbg_assert_(tag); + + CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + if (createDepthStencilBuffer) { + CreateImage(vulkan_, initCmd, depth, width, height, numLayers, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + } + + UpdateTag(tag); + + // We create the actual framebuffer objects on demand, because some combinations might not make sense. + // Framebuffer objects are just pointers to a set of images, so no biggie. +} + +void VKRFramebuffer::UpdateTag(const char *newTag) { + char name[128]; + snprintf(name, sizeof(name), "fb_color_%s", tag_.c_str()); + vulkan_->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, name); + vulkan_->SetDebugName(color.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); + if (depth.image) { + snprintf(name, sizeof(name), "fb_depth_%s", tag_.c_str()); + vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, name); + vulkan_->SetDebugName(depth.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); + } + for (size_t rpType = 0; rpType < (size_t)RenderPassType::TYPE_COUNT; rpType++) { + if (framebuf[rpType]) { + snprintf(name, sizeof(name), "fb_%s", tag_.c_str()); + vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name); + } + } +} + +VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) { + bool multiview = RenderPassTypeHasMultiView(rpType); + + if (framebuf[(int)rpType]) { + return framebuf[(int)rpType]; + } + + VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + VkImageView views[2]{}; + + bool hasDepth = RenderPassTypeHasDepth(rpType); + views[0] = color.rtView; // 2D array texture if multilayered. + if (hasDepth) { + if (!depth.rtView) { + WARN_LOG(G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", depth.image, depth.texAllLayersView, depth.format, tag_.c_str(), width, height); + // Will probably crash, depending on driver. + } + views[1] = depth.rtView; + } + fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); + fbci.attachmentCount = hasDepth ? 2 : 1; + fbci.pAttachments = views; + fbci.width = width; + fbci.height = height; + fbci.layers = 1; // With multiview, this should be set as 1. + + VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]); + _assert_(res == VK_SUCCESS); + + if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) { + vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str()); + } + + return framebuf[(int)rpType]; +} + +VKRFramebuffer::~VKRFramebuffer() { + // Get rid of the views first, feels cleaner (but in reality doesn't matter). + if (color.rtView) + vulkan_->Delete().QueueDeleteImageView(color.rtView); + if (depth.rtView) + vulkan_->Delete().QueueDeleteImageView(depth.rtView); + if (color.texAllLayersView) + vulkan_->Delete().QueueDeleteImageView(color.texAllLayersView); + if (depth.texAllLayersView) + vulkan_->Delete().QueueDeleteImageView(depth.texAllLayersView); + for (int i = 0; i < 2; i++) { + if (color.texLayerViews[i]) { + vulkan_->Delete().QueueDeleteImageView(color.texLayerViews[i]); + } + if (depth.texLayerViews[i]) { + vulkan_->Delete().QueueDeleteImageView(depth.texLayerViews[i]); + } + } + + if (color.image) { + _dbg_assert_(color.alloc); + vulkan_->Delete().QueueDeleteImageAllocation(color.image, color.alloc); + } + if (depth.image) { + _dbg_assert_(depth.alloc); + vulkan_->Delete().QueueDeleteImageAllocation(depth.image, depth.alloc); + } + for (auto &fb : framebuf) { + if (fb) { + vulkan_->Delete().QueueDeleteFramebuffer(fb); + } + } +} + +// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. +// This requires a different sampling path! +void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { + // We don't support more exotic layer setups for now. Mono or stereo. + _dbg_assert_(numLayers == 1 || numLayers == 2); + + VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + ici.arrayLayers = numLayers; + ici.mipLevels = 1; + ici.extent.width = width; + ici.extent.height = height; + ici.extent.depth = 1; + ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + ici.imageType = VK_IMAGE_TYPE_2D; + ici.samples = VK_SAMPLE_COUNT_1_BIT; + ici.tiling = VK_IMAGE_TILING_OPTIMAL; + ici.format = format; + // Strictly speaking we don't yet need VK_IMAGE_USAGE_SAMPLED_BIT for depth buffers since we do not yet sample depth buffers. + ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + if (color) { + ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + } else { + ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + + VmaAllocationCreateInfo allocCreateInfo{}; + allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + VmaAllocationInfo allocInfo{}; + + VkResult res = vmaCreateImage(vulkan->Allocator(), &ici, &allocCreateInfo, &img.image, &img.alloc, &allocInfo); + _dbg_assert_(res == VK_SUCCESS); + + VkImageAspectFlags aspects = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + VkImageViewCreateInfo ivci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; + ivci.format = ici.format; + ivci.image = img.image; + ivci.viewType = numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY; + ivci.subresourceRange.aspectMask = aspects; + ivci.subresourceRange.layerCount = numLayers; + ivci.subresourceRange.levelCount = 1; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.rtView); + vulkan->SetDebugName(img.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); + _dbg_assert_(res == VK_SUCCESS); + + // Separate view for texture sampling all layers together. + if (!color) { + ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } + + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; // layered for consistency, even if single image. + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texAllLayersView); + vulkan->SetDebugName(img.texAllLayersView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); + + // Create 2D views for both layers. + // Useful when multipassing shaders that don't yet exist in a single-pass-stereo version. + for (int i = 0; i < numLayers; i++) { + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; + ivci.subresourceRange.layerCount = 1; + ivci.subresourceRange.baseArrayLayer = i; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texLayerViews[i]); + if (vulkan->DebugLayerEnabled()) { + char temp[128]; + snprintf(temp, sizeof(temp), "%s_layer%d", tag, i); + vulkan->SetDebugName(img.texLayerViews[i], VK_OBJECT_TYPE_IMAGE_VIEW, temp); + } + _dbg_assert_(res == VK_SUCCESS); + } + + VkPipelineStageFlags dstStage; + VkAccessFlagBits dstAccessMask; + switch (initialLayout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + default: + Crash(); + return; + } + + TransitionImageLayout2(cmd, img.image, 0, 1, numLayers, aspects, + VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, + 0, dstAccessMask); + img.layout = initialLayout; + img.format = format; + img.tag = tag ? tag : "N/A"; + img.numLayers = numLayers; +} + +static VkAttachmentLoadOp ConvertLoadAction(VKRRenderPassLoadAction action) { + switch (action) { + case VKRRenderPassLoadAction::CLEAR: return VK_ATTACHMENT_LOAD_OP_CLEAR; + case VKRRenderPassLoadAction::KEEP: return VK_ATTACHMENT_LOAD_OP_LOAD; + case VKRRenderPassLoadAction::DONT_CARE: return VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + return VK_ATTACHMENT_LOAD_OP_DONT_CARE; // avoid compiler warning +} + +static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) { + switch (action) { + case VKRRenderPassStoreAction::STORE: return VK_ATTACHMENT_STORE_OP_STORE; + case VKRRenderPassStoreAction::DONT_CARE: return VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + return VK_ATTACHMENT_STORE_OP_DONT_CARE; // avoid compiler warning +} + +// Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 +// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies + +VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) { + bool selfDependency = RenderPassTypeHasInput(rpType); + bool isBackbuffer = rpType == RenderPassType::BACKBUFFER; + bool hasDepth = RenderPassTypeHasDepth(rpType); + bool multiview = RenderPassTypeHasMultiView(rpType); + + if (multiview) { + // TODO: Assert that the device has multiview support enabled. + } + + VkAttachmentDescription attachments[2] = {}; + attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; + attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[0].loadOp = ConvertLoadAction(key.colorLoadAction); + attachments[0].storeOp = ConvertStoreAction(key.colorStoreAction); + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].flags = 0; + + if (hasDepth) { + attachments[1].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; + attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[1].loadOp = ConvertLoadAction(key.depthLoadAction); + attachments[1].storeOp = ConvertStoreAction(key.depthStoreAction); + attachments[1].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); + attachments[1].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); + attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[1].flags = 0; + } + + VkAttachmentReference color_reference{}; + color_reference.attachment = 0; + color_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depth_reference{}; + depth_reference.attachment = 1; + depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.flags = 0; + if (selfDependency) { + subpass.inputAttachmentCount = 1; + subpass.pInputAttachments = &color_reference; + } else { + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + } + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_reference; + subpass.pResolveAttachments = nullptr; + if (hasDepth) { + subpass.pDepthStencilAttachment = &depth_reference; + } + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + // Not sure if this is really necessary. + VkSubpassDependency deps[2]{}; + size_t numDeps = 0; + + VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + rp.attachmentCount = hasDepth ? 2 : 1; + rp.pAttachments = attachments; + rp.subpassCount = 1; + rp.pSubpasses = &subpass; + + VkRenderPassMultiviewCreateInfoKHR mv{ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR }; + uint32_t viewMask = 0x3; // Must be outside the 'if (multiview)' scope! + int viewOffset = 0; + if (multiview) { + rp.pNext = &mv; + mv.subpassCount = 1; + mv.pViewMasks = &viewMask; + mv.dependencyCount = 0; + mv.pCorrelationMasks = &viewMask; // same masks + mv.correlationMaskCount = 1; + mv.pViewOffsets = &viewOffset; + } + + if (isBackbuffer) { + deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL; + deps[numDeps].dstSubpass = 0; + deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + deps[numDeps].srcAccessMask = 0; + deps[numDeps].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + numDeps++; + } + + if (selfDependency) { + deps[numDeps].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + deps[numDeps].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + deps[numDeps].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + deps[numDeps].srcSubpass = 0; + deps[numDeps].dstSubpass = 0; + numDeps++; + } + + if (numDeps > 0) { + rp.dependencyCount = (u32)numDeps; + rp.pDependencies = deps; + } + + VkRenderPass pass; + VkResult res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass); + _assert_(res == VK_SUCCESS); + _assert_(pass != VK_NULL_HANDLE); + return pass; +} + +VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType) { + // When we create a render pass, we create all "types" of it immediately, + // practical later when referring to it. Could change to on-demand if it feels motivated + // but I think the render pass objects are cheap. + if (!pass[(int)rpType]) { + pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType); + } + return pass[(int)rpType]; +} diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.h b/Common/GPU/Vulkan/VulkanFramebuffer.h new file mode 100644 index 0000000000..c52e933640 --- /dev/null +++ b/Common/GPU/Vulkan/VulkanFramebuffer.h @@ -0,0 +1,140 @@ +#pragma once + +#include "Common/Common.h" +#include "Common/GPU/Vulkan/VulkanContext.h" + +class VKRRenderPass; + +// Pipelines need to be created for the right type of render pass. +// TODO: Rename to RenderPassFlags? +// When you add more flags, don't forget to update rpTypeDebugNames[]. +enum class RenderPassType { + DEFAULT = 0, + // These eight are organized so that bit 0 is DEPTH and bit 1 is INPUT and bit 2 is MULTIVIEW, so + // they can be OR-ed together in MergeRPTypes. + HAS_DEPTH = 1, + COLOR_INPUT = 2, // input attachment + MULTIVIEW = 4, + + // This is the odd one out, and gets special handling in MergeRPTypes. + // If this flag is set, none of the other flags can be set. + // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible + // so we don't bother with a non-depth version. + BACKBUFFER = 8, + + TYPE_COUNT = BACKBUFFER + 1, +}; +ENUM_CLASS_BITOPS(RenderPassType); + +// Simple independent framebuffer image. +struct VKRImage { + // These four are "immutable". + VkImage image; + + VkImageView rtView; // Used for rendering to, and readbacks of stencil. 2D if single layer, 2D_ARRAY if multiple. Includes both depth and stencil if depth/stencil. + + // This is for texturing all layers at once. If aspect is depth/stencil, does not include stencil. + VkImageView texAllLayersView; + + // If it's a layered image (for stereo), this is two 2D views of it, to make it compatible with shaders that don't yet support stereo. + // If there's only one layer, layerViews[0] only is initialized. + VkImageView texLayerViews[2]{}; + + VmaAllocation alloc; + VkFormat format; + + // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. + VkImageLayout layout; + + int numLayers; + + // For debugging. + std::string tag; +}; + +class VKRFramebuffer { +public: + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag); + ~VKRFramebuffer(); + + VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); + + int width = 0; + int height = 0; + int numLayers = 0; + + VKRImage color{}; // color.image is always there. + VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE. + + const char *Tag() const { + return tag_.c_str(); + } + + void UpdateTag(const char *newTag); + + bool HasDepth() const { + return depth.image != VK_NULL_HANDLE; + } + + // TODO: Hide. + VulkanContext *vulkan_; +private: + static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); + + VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{}; + + std::string tag_; +}; + +inline bool RenderPassTypeHasDepth(RenderPassType type) { + return (type & RenderPassType::HAS_DEPTH) || type == RenderPassType::BACKBUFFER; +} + +inline bool RenderPassTypeHasInput(RenderPassType type) { + return (type & RenderPassType::COLOR_INPUT) != 0; +} + +inline bool RenderPassTypeHasMultiView(RenderPassType type) { + return (type & RenderPassType::MULTIVIEW) != 0; +} + +// Must be the same order as Draw::RPAction +enum class VKRRenderPassLoadAction : uint8_t { + KEEP, // default. avoid when possible. + CLEAR, + DONT_CARE, +}; + +enum class VKRRenderPassStoreAction : uint8_t { + STORE, // default. avoid when possible. + DONT_CARE, +}; + +struct RPKey { + // Only render-pass-compatibility-volatile things can be here. + VKRRenderPassLoadAction colorLoadAction; + VKRRenderPassLoadAction depthLoadAction; + VKRRenderPassLoadAction stencilLoadAction; + VKRRenderPassStoreAction colorStoreAction; + VKRRenderPassStoreAction depthStoreAction; + VKRRenderPassStoreAction stencilStoreAction; +}; + +class VKRRenderPass { +public: + VKRRenderPass(const RPKey &key) : key_(key) {} + + VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType); + void Destroy(VulkanContext *vulkan) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { + if (pass[i]) { + vulkan->Delete().QueueDeleteRenderPass(pass[i]); + } + } + } + +private: + // TODO: Might be better off with a hashmap once the render pass type count grows really large.. + VkRenderPass pass[(size_t)RenderPassType::TYPE_COUNT]{}; + RPKey key_; +}; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index b154a6bc01..617c349b79 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -309,151 +309,6 @@ void VulkanQueueRunner::DestroyBackBuffers() { INFO_LOG(G3D, "Backbuffers destroyed"); } -static VkAttachmentLoadOp ConvertLoadAction(VKRRenderPassLoadAction action) { - switch (action) { - case VKRRenderPassLoadAction::CLEAR: return VK_ATTACHMENT_LOAD_OP_CLEAR; - case VKRRenderPassLoadAction::KEEP: return VK_ATTACHMENT_LOAD_OP_LOAD; - case VKRRenderPassLoadAction::DONT_CARE: return VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - return VK_ATTACHMENT_LOAD_OP_DONT_CARE; // avoid compiler warning -} - -static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) { - switch (action) { - case VKRRenderPassStoreAction::STORE: return VK_ATTACHMENT_STORE_OP_STORE; - case VKRRenderPassStoreAction::DONT_CARE: return VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - return VK_ATTACHMENT_STORE_OP_DONT_CARE; // avoid compiler warning -} - -// Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 -// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies - -VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) { - bool selfDependency = RenderPassTypeHasInput(rpType); - bool isBackbuffer = rpType == RenderPassType::BACKBUFFER; - bool hasDepth = RenderPassTypeHasDepth(rpType); - bool multiview = RenderPassTypeHasMultiView(rpType); - - if (multiview) { - // TODO: Assert that the device has multiview support enabled. - } - - VkAttachmentDescription attachments[2] = {}; - attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = ConvertLoadAction(key.colorLoadAction); - attachments[0].storeOp = ConvertStoreAction(key.colorStoreAction); - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].flags = 0; - - if (hasDepth) { - attachments[1].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; - attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[1].loadOp = ConvertLoadAction(key.depthLoadAction); - attachments[1].storeOp = ConvertStoreAction(key.depthStoreAction); - attachments[1].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); - attachments[1].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); - attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].flags = 0; - } - - VkAttachmentReference color_reference{}; - color_reference.attachment = 0; - color_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference depth_reference{}; - depth_reference.attachment = 1; - depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass{}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - if (selfDependency) { - subpass.inputAttachmentCount = 1; - subpass.pInputAttachments = &color_reference; - } else { - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = nullptr; - } - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_reference; - subpass.pResolveAttachments = nullptr; - if (hasDepth) { - subpass.pDepthStencilAttachment = &depth_reference; - } - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = nullptr; - - // Not sure if this is really necessary. - VkSubpassDependency deps[2]{}; - size_t numDeps = 0; - - VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; - rp.attachmentCount = hasDepth ? 2 : 1; - rp.pAttachments = attachments; - rp.subpassCount = 1; - rp.pSubpasses = &subpass; - - VkRenderPassMultiviewCreateInfoKHR mv{ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR }; - uint32_t viewMask = 0x3; // Must be outside the 'if (multiview)' scope! - int viewOffset = 0; - if (multiview) { - rp.pNext = &mv; - mv.subpassCount = 1; - mv.pViewMasks = &viewMask; - mv.dependencyCount = 0; - mv.pCorrelationMasks = &viewMask; // same masks - mv.correlationMaskCount = 1; - mv.pViewOffsets = &viewOffset; - } - - if (isBackbuffer) { - deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL; - deps[numDeps].dstSubpass = 0; - deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - deps[numDeps].srcAccessMask = 0; - deps[numDeps].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - numDeps++; - } - - if (selfDependency) { - deps[numDeps].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - deps[numDeps].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - deps[numDeps].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - deps[numDeps].srcSubpass = 0; - deps[numDeps].dstSubpass = 0; - numDeps++; - } - - if (numDeps > 0) { - rp.dependencyCount = (u32)numDeps; - rp.pDependencies = deps; - } - - VkRenderPass pass; - VkResult res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass); - _assert_(res == VK_SUCCESS); - _assert_(pass != VK_NULL_HANDLE); - return pass; -} - -VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType) { - // When we create a render pass, we create all "types" of it immediately, - // practical later when referring to it. Could change to on-demand if it feels motivated - // but I think the render pass objects are cheap. - if (!pass[(int)rpType]) { - pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType); - } - return pass[(int)rpType]; -} // Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 // Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 6b7242cadf..0f844bbd88 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -9,6 +9,7 @@ #include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/GPU/Vulkan/VulkanBarrier.h" #include "Common/GPU/Vulkan/VulkanFrameData.h" +#include "Common/GPU/Vulkan/VulkanFramebuffer.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Data/Collections/TinySet.h" #include "Common/GPU/DataFormat.h" @@ -53,39 +54,6 @@ enum class PipelineFlags : u8 { }; ENUM_CLASS_BITOPS(PipelineFlags); -// Pipelines need to be created for the right type of render pass. -// TODO: Rename to RenderPassFlags? -// When you add more flags, don't forget to update rpTypeDebugNames[]. -enum class RenderPassType { - DEFAULT = 0, - // These eight are organized so that bit 0 is DEPTH and bit 1 is INPUT and bit 2 is MULTIVIEW, so - // they can be OR-ed together in MergeRPTypes. - HAS_DEPTH = 1, - COLOR_INPUT = 2, // input attachment - MULTIVIEW = 4, - - // This is the odd one out, and gets special handling in MergeRPTypes. - // If this flag is set, none of the other flags can be set. - // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible - // so we don't bother with a non-depth version. - BACKBUFFER = 8, - - TYPE_COUNT = BACKBUFFER + 1, -}; -ENUM_CLASS_BITOPS(RenderPassType); - -inline bool RenderPassTypeHasDepth(RenderPassType type) { - return (type & RenderPassType::HAS_DEPTH) || type == RenderPassType::BACKBUFFER; -} - -inline bool RenderPassTypeHasInput(RenderPassType type) { - return (type & RenderPassType::COLOR_INPUT) != 0; -} - -inline bool RenderPassTypeHasMultiView(RenderPassType type) { - return (type & RenderPassType::MULTIVIEW) != 0; -} - struct VkRenderData { VKRRenderCommand cmd; union { @@ -168,18 +136,6 @@ enum class VKRStepType : uint8_t { READBACK_IMAGE, }; -// Must be the same order as Draw::RPAction -enum class VKRRenderPassLoadAction : uint8_t { - KEEP, // default. avoid when possible. - CLEAR, - DONT_CARE, -}; - -enum class VKRRenderPassStoreAction : uint8_t { - STORE, // default. avoid when possible. - DONT_CARE, -}; - struct TransitionRequest { VKRFramebuffer *fb; VkImageAspectFlags aspect; // COLOR or DEPTH @@ -252,35 +208,6 @@ struct VKRStep { }; }; -struct RPKey { - // Only render-pass-compatibility-volatile things can be here. - VKRRenderPassLoadAction colorLoadAction; - VKRRenderPassLoadAction depthLoadAction; - VKRRenderPassLoadAction stencilLoadAction; - VKRRenderPassStoreAction colorStoreAction; - VKRRenderPassStoreAction depthStoreAction; - VKRRenderPassStoreAction stencilStoreAction; -}; - -class VKRRenderPass { -public: - VKRRenderPass(const RPKey &key) : key_(key) {} - - VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType); - void Destroy(VulkanContext *vulkan) { - for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { - if (pass[i]) { - vulkan->Delete().QueueDeleteRenderPass(pass[i]); - } - } - } - -private: - // TODO: Might be better off with a hashmap once the render pass type count grows really large.. - VkRenderPass pass[(size_t)RenderPassType::TYPE_COUNT]{}; - RPKey key_; -}; - // These are enqueued from the main thread, // and the render thread pops them off struct VKRRenderThreadTask { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index df3f5e5539..2b67cbfeb9 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -171,210 +171,6 @@ bool VKRComputePipeline::Create(VulkanContext *vulkan) { return success; } -VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag) - : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { - - _dbg_assert_(tag); - - CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); - if (createDepthStencilBuffer) { - CreateImage(vulkan_, initCmd, depth, width, height, numLayers, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); - } - - UpdateTag(tag); - - // We create the actual framebuffer objects on demand, because some combinations might not make sense. - // Framebuffer objects are just pointers to a set of images, so no biggie. -} - -void VKRFramebuffer::UpdateTag(const char *newTag) { - char name[128]; - snprintf(name, sizeof(name), "fb_color_%s", tag_.c_str()); - vulkan_->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, name); - vulkan_->SetDebugName(color.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); - if (depth.image) { - snprintf(name, sizeof(name), "fb_depth_%s", tag_.c_str()); - vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, name); - vulkan_->SetDebugName(depth.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); - } - for (size_t rpType = 0; rpType < (size_t)RenderPassType::TYPE_COUNT; rpType++) { - if (framebuf[rpType]) { - snprintf(name, sizeof(name), "fb_%s", tag_.c_str()); - vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name); - } - } -} - -VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) { - bool multiview = RenderPassTypeHasMultiView(rpType); - - if (framebuf[(int)rpType]) { - return framebuf[(int)rpType]; - } - - VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - VkImageView views[2]{}; - - bool hasDepth = RenderPassTypeHasDepth(rpType); - views[0] = color.rtView; // 2D array texture if multilayered. - if (hasDepth) { - if (!depth.rtView) { - WARN_LOG(G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", depth.image, depth.texAllLayersView, depth.format, tag_.c_str(), width, height); - // Will probably crash, depending on driver. - } - views[1] = depth.rtView; - } - fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); - fbci.attachmentCount = hasDepth ? 2 : 1; - fbci.pAttachments = views; - fbci.width = width; - fbci.height = height; - fbci.layers = 1; // With multiview, this should be set as 1. - - VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]); - _assert_(res == VK_SUCCESS); - - if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) { - vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str()); - } - - return framebuf[(int)rpType]; -} - -VKRFramebuffer::~VKRFramebuffer() { - // Get rid of the views first, feels cleaner (but in reality doesn't matter). - if (color.rtView) - vulkan_->Delete().QueueDeleteImageView(color.rtView); - if (depth.rtView) - vulkan_->Delete().QueueDeleteImageView(depth.rtView); - if (color.texAllLayersView) - vulkan_->Delete().QueueDeleteImageView(color.texAllLayersView); - if (depth.texAllLayersView) - vulkan_->Delete().QueueDeleteImageView(depth.texAllLayersView); - for (int i = 0; i < 2; i++) { - if (color.texLayerViews[i]) { - vulkan_->Delete().QueueDeleteImageView(color.texLayerViews[i]); - } - if (depth.texLayerViews[i]) { - vulkan_->Delete().QueueDeleteImageView(depth.texLayerViews[i]); - } - } - - if (color.image) { - _dbg_assert_(color.alloc); - vulkan_->Delete().QueueDeleteImageAllocation(color.image, color.alloc); - } - if (depth.image) { - _dbg_assert_(depth.alloc); - vulkan_->Delete().QueueDeleteImageAllocation(depth.image, depth.alloc); - } - for (auto &fb : framebuf) { - if (fb) { - vulkan_->Delete().QueueDeleteFramebuffer(fb); - } - } -} - -// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. -// This requires a different sampling path! -void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { - // We don't support more exotic layer setups for now. Mono or stereo. - _dbg_assert_(numLayers == 1 || numLayers == 2); - - VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - ici.arrayLayers = numLayers; - ici.mipLevels = 1; - ici.extent.width = width; - ici.extent.height = height; - ici.extent.depth = 1; - ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - ici.imageType = VK_IMAGE_TYPE_2D; - ici.samples = VK_SAMPLE_COUNT_1_BIT; - ici.tiling = VK_IMAGE_TILING_OPTIMAL; - ici.format = format; - // Strictly speaking we don't yet need VK_IMAGE_USAGE_SAMPLED_BIT for depth buffers since we do not yet sample depth buffers. - ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - if (color) { - ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - } else { - ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } - - VmaAllocationCreateInfo allocCreateInfo{}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - VmaAllocationInfo allocInfo{}; - - VkResult res = vmaCreateImage(vulkan->Allocator(), &ici, &allocCreateInfo, &img.image, &img.alloc, &allocInfo); - _dbg_assert_(res == VK_SUCCESS); - - VkImageAspectFlags aspects = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); - - VkImageViewCreateInfo ivci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; - ivci.format = ici.format; - ivci.image = img.image; - ivci.viewType = numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY; - ivci.subresourceRange.aspectMask = aspects; - ivci.subresourceRange.layerCount = numLayers; - ivci.subresourceRange.levelCount = 1; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.rtView); - vulkan->SetDebugName(img.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); - _dbg_assert_(res == VK_SUCCESS); - - // Separate view for texture sampling all layers together. - if (!color) { - ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - } - - ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; // layered for consistency, even if single image. - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texAllLayersView); - vulkan->SetDebugName(img.texAllLayersView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); - - // Create 2D views for both layers. - // Useful when multipassing shaders that don't yet exist in a single-pass-stereo version. - for (int i = 0; i < numLayers; i++) { - ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; - ivci.subresourceRange.layerCount = 1; - ivci.subresourceRange.baseArrayLayer = i; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texLayerViews[i]); - if (vulkan->DebugLayerEnabled()) { - char temp[128]; - snprintf(temp, sizeof(temp), "%s_layer%d", tag, i); - vulkan->SetDebugName(img.texLayerViews[i], VK_OBJECT_TYPE_IMAGE_VIEW, temp); - } - _dbg_assert_(res == VK_SUCCESS); - } - - VkPipelineStageFlags dstStage; - VkAccessFlagBits dstAccessMask; - switch (initialLayout) { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - default: - Crash(); - return; - } - - TransitionImageLayout2(cmd, img.image, 0, 1, numLayers, aspects, - VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, - 0, dstAccessMask); - img.layout = initialLayout; - img.format = format; - img.tag = tag ? tag : "N/A"; - img.numLayers = numLayers; -} - VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan), queueRunner_(vulkan), initTimeMs_("initTimeMs"), diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index ca22dbab29..de36633c67 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -21,70 +21,11 @@ #include "Common/GPU/DataFormat.h" #include "Common/GPU/MiscTypes.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" +#include "Common/GPU/Vulkan/VulkanFramebuffer.h" // Forward declaration VK_DEFINE_HANDLE(VmaAllocation); -// Simple independent framebuffer image. -struct VKRImage { - // These four are "immutable". - VkImage image; - - VkImageView rtView; // Used for rendering to, and readbacks of stencil. 2D if single layer, 2D_ARRAY if multiple. Includes both depth and stencil if depth/stencil. - - // This is for texturing all layers at once. If aspect is depth/stencil, does not include stencil. - VkImageView texAllLayersView; - - // If it's a layered image (for stereo), this is two 2D views of it, to make it compatible with shaders that don't yet support stereo. - // If there's only one layer, layerViews[0] only is initialized. - VkImageView texLayerViews[2]{}; - - VmaAllocation alloc; - VkFormat format; - - // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. - VkImageLayout layout; - - int numLayers; - - // For debugging. - std::string tag; -}; - -class VKRFramebuffer { -public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag); - ~VKRFramebuffer(); - - VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); - - int width = 0; - int height = 0; - int numLayers = 0; - - VKRImage color{}; // color.image is always there. - VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE. - - const char *Tag() const { - return tag_.c_str(); - } - - void UpdateTag(const char *newTag); - - bool HasDepth() const { - return depth.image != VK_NULL_HANDLE; - } - - // TODO: Hide. - VulkanContext *vulkan_; -private: - static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); - - VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{}; - - std::string tag_; -}; - struct BoundingRect { int x1; int y1; diff --git a/android/jni/Android.mk b/android/jni/Android.mk index cc507e101d..5168e0c8d7 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -56,6 +56,7 @@ VULKAN_FILES := \ $(SRC)/Common/GPU/Vulkan/VulkanContext.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanDebug.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanImage.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanFramebuffer.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanMemory.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanProfiler.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanBarrier.cpp diff --git a/libretro/Makefile.common b/libretro/Makefile.common index b310680f1f..a3f925b107 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -262,6 +262,7 @@ SOURCES_CXX += \ $(COMMONDIR)/GPU/Vulkan/VulkanContext.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanDebug.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanImage.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanFramebuffer.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanMemory.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanProfiler.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanBarrier.cpp \ From bdfde4cbac900bf2dd9218fdab40bdbfed4d1923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 10:04:26 +0100 Subject: [PATCH 416/715] Implement the new screen sizing parameters --- Core/Config.cpp | 8 +-- Core/Config.h | 13 ++-- Core/HLE/sceIo.cpp | 12 ++-- GPU/Common/PresentationCommon.cpp | 101 +++++++++++++----------------- GPU/GLES/DrawEngineGLES.cpp | 3 + UI/DisplayLayoutScreen.cpp | 93 +++++++-------------------- UI/DisplayLayoutScreen.h | 3 - 7 files changed, 87 insertions(+), 146 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index cb17b4881e..9870745c28 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -911,10 +911,10 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("FullScreenMulti", &g_Config.bFullScreenMulti, false), #endif - ConfigSetting("SmallDisplayZoomType", &g_Config.iSmallDisplayZoomType, &DefaultZoomType, true, true), - ConfigSetting("SmallDisplayOffsetX", &g_Config.fSmallDisplayOffsetX, 0.5f, true, true), - ConfigSetting("SmallDisplayOffsetY", &g_Config.fSmallDisplayOffsetY, 0.5f, true, true), - ConfigSetting("SmallDisplayZoomLevel", &g_Config.fSmallDisplayZoomLevel, 1.0f, true, true), + ConfigSetting("DisplayOffsetX", &g_Config.fDisplayOffsetX, 0.5f, true, true), + ConfigSetting("DisplayOffsetY", &g_Config.fDisplayOffsetY, 0.5f, true, true), + ConfigSetting("DisplayScale", &g_Config.fDisplayScale, 1.0f, true, true), + ConfigSetting("DisplayAspectRatio", &g_Config.fDisplayAspectRatio, 1.0f, true, true), ConfigSetting("ImmersiveMode", &g_Config.bImmersiveMode, true, true, true), ConfigSetting("SustainedPerformanceMode", &g_Config.bSustainedPerformanceMode, false, true, true), ConfigSetting("IgnoreScreenInsets", &g_Config.bIgnoreScreenInsets, true, true, false), diff --git a/Core/Config.h b/Core/Config.h index 8b517889b0..6e8a6e808d 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -171,11 +171,14 @@ public: int iTexFiltering; // 1 = auto , 2 = nearest , 3 = linear , 4 = auto max quality int iBufFilter; // 1 = linear, 2 = nearest - int iSmallDisplayZoomType; // Used to fit display into screen 0 = stretch, 1 = partial stretch, 2 = auto scaling, 3 = manual scaling. - float fSmallDisplayOffsetX; // Along with Y it goes from 0.0 to 1.0, XY (0.5, 0.5) = center of the screen - float fSmallDisplayOffsetY; - float fSmallDisplayZoomLevel; //This is used for zoom values, both in and out. - bool bImmersiveMode; // Mode on Android Kitkat 4.4 that hides the back button etc. + + bool bDisplayStretch; // Automatically matches the aspect ratio of the window. + float fDisplayOffsetX; + float fDisplayOffsetY; + float fDisplayScale; // Relative to the most constraining axis (x or y). + float fDisplayAspectRatio; // Stored relative to the PSP's native ratio, so 1.0 is the normal pixel aspect ratio. + + bool bImmersiveMode; // Mode on Android Kitkat 4.4 and later that hides the back button etc. bool bSustainedPerformanceMode; // Android: Slows clocks down to avoid overheating/speed fluctuations. bool bIgnoreScreenInsets; // Android: Center screen disregarding insets if this is enabled. bool bVSync; diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index ca1a72160b..943ba37721 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -2045,15 +2045,17 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o PSP_CoreParameter().fastForward = false; return 0; case EMULATOR_DEVCTL__GET_ASPECT_RATIO: - if (Memory::IsValidAddress(outPtr)) - { - float ar = static_cast(PSP_CoreParameter().pixelWidth) / static_cast(PSP_CoreParameter().pixelHeight); + if (Memory::IsValidAddress(outPtr)) { + float ar = g_Config.fDisplayAspectRatio * (480.0f / 272.0f); Memory::Write_U32(*(reinterpret_cast(&ar)), outPtr); } return 0; case EMULATOR_DEVCTL__GET_SCALE: - if (Memory::IsValidAddress(outPtr)) - Memory::Write_U32(static_cast(dp_xres) / 480.0f, outPtr); + if (Memory::IsValidAddress(outPtr)) { + // TODO: Maybe do something more sophisticated taking the longest side and screen rotation + // into account, etc. + Memory::Write_U32(static_cast(dp_xres) * g_Config.fDisplayScale / 480.0f, outPtr); + } return 0; case EMULATOR_DEVCTL__GET_LTRIGGER: //To-do diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index ce0ef039fa..f8f7149389 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -75,73 +75,58 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f bool rotated = rotation == ROTATION_LOCKED_VERTICAL || rotation == ROTATION_LOCKED_VERTICAL180; - SmallDisplayZoom zoomType = (SmallDisplayZoom)g_Config.iSmallDisplayZoomType; + bool stretch = g_Config.bDisplayStretch; + + float offsetX = g_Config.fDisplayOffsetX; + float offsetY = g_Config.fDisplayOffsetY; + // Have to invert Y for GL + if (GetGPUBackend() == GPUBackend::OPENGL) { + offsetY = offsetY * -1.0f; + } + + float scale = g_Config.fDisplayScale; + float aspectRatioAdjust = g_Config.fDisplayAspectRatio; if (IsVREnabled()) { - zoomType = SmallDisplayZoom::STRETCH; + stretch = 0; + rotated = false; + offsetX = 0.0f; + offsetY = 0.0f; + scale = 1.0f; + aspectRatioAdjust = 1.0f; } - if (zoomType == SmallDisplayZoom::STRETCH) { - outW = frame.w; - outH = frame.h; - } else { - if (zoomType == SmallDisplayZoom::MANUAL) { - float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frame.w + frame.x; - float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frame.h + frame.y; - // Have to invert Y for GL - if (GetGPUBackend() == GPUBackend::OPENGL) { - offsetY = offsetY * -1.0f; - } - float customZoom = g_Config.fSmallDisplayZoomLevel; - float smallDisplayW = origW * customZoom; - float smallDisplayH = origH * customZoom; - if (!rotated) { - rc->x = floorf(((frame.w - smallDisplayW) / 2.0f) + offsetX); - rc->y = floorf(((frame.h - smallDisplayH) / 2.0f) + offsetY); - rc->w = floorf(smallDisplayW); - rc->h = floorf(smallDisplayH); - return; - } else { - rc->x = floorf(((frame.w - smallDisplayH) / 2.0f) + offsetX); - rc->y = floorf(((frame.h - smallDisplayW) / 2.0f) + offsetY); - rc->w = floorf(smallDisplayH); - rc->h = floorf(smallDisplayW); - return; - } - } else if (zoomType == SmallDisplayZoom::AUTO) { - // Stretch to 1080 for 272*4. But don't distort if not widescreen (i.e. ultrawide of halfwide.) - float pixelCrop = frame.h / 270.0f; - float resCommonWidescreen = pixelCrop - floor(pixelCrop); - if (!rotated && resCommonWidescreen == 0.0f && frame.w >= pixelCrop * 480.0f) { - rc->x = floorf((frame.w - pixelCrop * 480.0f) * 0.5f + frame.x); - rc->y = floorf(-pixelCrop + frame.y); - rc->w = floorf(pixelCrop * 480.0f); - rc->h = floorf(pixelCrop * 272.0f); - return; - } - } + float origRatio = !rotated ? origW / origH : origH / origW; + float frameRatio = frame.w / frame.h; - float origRatio = !rotated ? origW / origH : origH / origW; - float frameRatio = frame.w / frame.h; - - if (origRatio > frameRatio) { - // Image is wider than frame. Center vertically. - outW = frame.w; - outH = frame.w / origRatio; - // Stretch a little bit - if (!rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH) - outH = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 + if (stretch) { + // Automatically set aspect ratio to match the display, IF the rotation matches the output display ratio! Otherwise, just + // sets standard aspect ratio because actually stretching will just look silly. + bool globalRotated = g_display_rotation == DisplayRotation::ROTATE_90 || g_display_rotation == DisplayRotation::ROTATE_270; + if (rotated == dp_yres > dp_xres) { + origRatio = frameRatio; } else { - // Image is taller than frame. Center horizontally. - outW = frame.h * origRatio; - outH = frame.h; - if (rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH) - outW = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 + origRatio *= aspectRatioAdjust; } + } else { + origRatio *= aspectRatioAdjust; } - rc->x = floorf((frame.w - outW) / 2.0f + frame.x); - rc->y = floorf((frame.h - outH) / 2.0f + frame.y); + float scaledWidth = frame.w * scale; + float scaledHeight = frame.h * scale; + + if (origRatio > frameRatio) { + // Image is wider than frame. Center vertically. + outW = scaledWidth; + outH = scaledWidth / origRatio; + } else { + // Image is taller than frame. Center horizontally. + outW = scaledHeight * origRatio; + outH = scaledHeight; + } + + rc->x = floorf(frame.x + frame.w * offsetX - outW * 0.5f); + rc->y = floorf(frame.y + frame.h * offsetY - outH * 0.5f); rc->w = floorf(outW); rc->h = floorf(outH); } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index e250da4be2..56051f6a35 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -122,6 +122,9 @@ void DrawEngineGLES::InitDeviceObjects() { } void DrawEngineGLES::DestroyDeviceObjects() { + if (!draw_) { + return; + } draw_->SetInvalidationCallback(InvalidationCallback()); // Beware: this could be called twice in a row, sometimes. diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index a126f70d8d..4244244bf9 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -88,9 +88,6 @@ bool DisplayLayoutScreen::touch(const TouchInput &touch) { using namespace UI; int mode = mode_ ? mode_->GetSelection() : 0; - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - mode = -1; - } const Bounds &screenBounds = screenManager()->getUIContext()->GetBounds(); if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { @@ -100,15 +97,15 @@ bool DisplayLayoutScreen::touch(const TouchInput &touch) { switch (mode) { case MODE_MOVE: { - g_Config.fSmallDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX * 0.5f / screenBounds.w; - g_Config.fSmallDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY * 0.5f / screenBounds.h; + g_Config.fDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX / screenBounds.w; + g_Config.fDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY / screenBounds.h; break; } case MODE_RESIZE: { // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction float diffYProp = -relativeTouchY * 0.007f; - g_Config.fSmallDisplayZoomLevel = startScale_ * powf(2.0f, diffYProp); + g_Config.fDisplayScale = startScale_ * powf(2.0f, diffYProp); break; } } @@ -118,9 +115,9 @@ bool DisplayLayoutScreen::touch(const TouchInput &touch) { dragging_ = true; startX_ = touch.x; startY_ = touch.y; - startDisplayOffsetX_ = g_Config.fSmallDisplayOffsetX; - startDisplayOffsetY_ = g_Config.fSmallDisplayOffsetY; - startScale_ = g_Config.fSmallDisplayZoomLevel; + startDisplayOffsetX_ = g_Config.fDisplayOffsetX; + startDisplayOffsetY_ = g_Config.fDisplayOffsetY; + startScale_ = g_Config.fDisplayScale; } if ((touch.flags & TOUCH_UP) != 0 && dragging_) { @@ -134,29 +131,6 @@ void DisplayLayoutScreen::onFinish(DialogResult reason) { g_Config.Save("DisplayLayoutScreen::onFinish"); } -UI::EventReturn DisplayLayoutScreen::OnCenter(UI::EventParams &e) { - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - RecreateViews(); - return UI::EVENT_DONE; -}; - -UI::EventReturn DisplayLayoutScreen::OnZoomTypeChange(UI::EventParams &e) { - switch (g_Config.iSmallDisplayZoomType) { - case (int)SmallDisplayZoom::AUTO: - case (int)SmallDisplayZoom::PARTIAL_STRETCH: - case (int)SmallDisplayZoom::STRETCH: - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - break; - default: - // Not SmallDisplayZoom::MANUAL - break; - } - RecreateViews(); - return UI::EVENT_DONE; -}; - void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult result) { RecreateViews(); } @@ -218,50 +192,27 @@ void DisplayLayoutScreen::CreateViews() { bRotated_ = true; } - mode_ = nullptr; - if (g_Config.iSmallDisplayZoomType >= (int)SmallDisplayZoom::AUTO) { // Scaling - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - float autoBound = bounds.h / 270.0f; - // Case of screen rotated ~ only works with buffered rendering - if (bRotated_) { - autoBound = bounds.h / 480.0f; - } else { // Without rotation in common cases like 1080p we cut off 2 pixels of height, this reflects other cases - float resCommonWidescreen = autoBound - floor(autoBound); - if (resCommonWidescreen != 0.0f) { - float ratio = bounds.w / bounds.h; - if (ratio < orgRatio) { - autoBound = bounds.w / 480.0f; - } - else { - autoBound = bounds.h / 272.0f; - } - } - } - g_Config.fSmallDisplayZoomLevel = autoBound; - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - } else { // Manual Scaling - Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 74)); - center->OnClick.Handle(this, &DisplayLayoutScreen::OnCenter); - root_->Add(center); - float minZoom = 1.0f; - PopupSliderChoiceFloat *zoomlvl = new PopupSliderChoiceFloat(&g_Config.fSmallDisplayZoomLevel, minZoom, 10.0f, di->T("Zoom"), 1.0f, screenManager(), di->T("* PSP res"), new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); - root_->Add(zoomlvl); - mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); - mode_->AddChoice(di->T("Move")); - mode_->AddChoice(di->T("Resize")); - mode_->SetSelection(0, false); - } - } + Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 74)); + center->OnClick.Add([&](UI::EventParams &) { + g_Config.fDisplayOffsetX = 0.5f; + g_Config.fDisplayOffsetY = 0.5f; + return UI::EVENT_DONE; + }); + root_->Add(center); + PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); + root_->Add(aspectRatio); + + mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); + mode_->AddChoice(di->T("Move")); + mode_->AddChoice(di->T("Resize")); + mode_->SetSelection(0, false); if (mode_) { root_->Add(mode_); } - static const char *zoomLevels[] = { "Stretching", "Partial Stretch", "Auto Scaling", "Manual Scaling" }; - auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, gr->T("Mode"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, NONE, NONE, 10)); - zoom->OnChoice.Handle(this, &DisplayLayoutScreen::OnZoomTypeChange); - rightColumn->Add(zoom); + auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretched")); + rightColumn->Add(stretch); static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 520e2a8f6d..6fe0f0f50e 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -38,9 +38,6 @@ public: const char *tag() const override { return "DisplayLayout"; } protected: - virtual UI::EventReturn OnCenter(UI::EventParams &e); - virtual UI::EventReturn OnZoomTypeChange(UI::EventParams &e); - UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); void sendMessage(const char *message, const char *value) override; From d667bd84a3990eb0016aa211c095656a792dad95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 15:56:15 +0100 Subject: [PATCH 417/715] Add back the old stretch-if-close-to-16:9 hack --- GPU/Common/PresentationCommon.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index f8f7149389..40c13beaae 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -96,6 +96,14 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f aspectRatioAdjust = 1.0f; } + // Ye olde 1080p hack, new version: If everything is setup to exactly cover the screen (defaults), and the screen display aspect ratio is 16:9, + // stretch the PSP's aspect ratio veeery slightly to fill it completely. + if (scale == 1.0f && offsetX == 0.5f && offsetY == 0.5f && aspectRatioAdjust == 1.0f) { + if (fabsf(frame.w / frame.h - 16.0f / 9.0f) < 0.0001f) { + aspectRatioAdjust = (frame.w / frame.h) / (480.0f / 272.0f); + } + } + float origRatio = !rotated ? origW / origH : origH / origW; float frameRatio = frame.w / frame.h; From d8ff6876cd6bdf6d9e2fa3cc9cf5f2a33501a8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 15:37:43 +0100 Subject: [PATCH 418/715] Rework UI a bit (first step, will clean up more). --- UI/DisplayLayoutScreen.cpp | 44 +++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 4244244bf9..f39bb50728 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -178,48 +178,52 @@ void DisplayLayoutScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); + ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL); + leftScrollView->Add(leftColumn); + root_->Add(leftScrollView); + ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 10.f, 10.f, 10.f, false)); ViewGroup *rightColumn = new LinearLayout(ORIENT_VERTICAL); rightScrollView->Add(rightColumn); root_->Add(rightScrollView); - // We manually implement insets here for the buttons. This file defied refactoring :( - float leftInset = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT); - bool displayRotEnable = !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; bRotated_ = false; if (displayRotEnable && (g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180)) { bRotated_ = true; } - Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 74)); - center->OnClick.Add([&](UI::EventParams &) { - g_Config.fDisplayOffsetX = 0.5f; - g_Config.fDisplayOffsetY = 0.5f; - return UI::EVENT_DONE; - }); - root_->Add(center); + PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); + leftColumn->Add(aspectRatio); - PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); - root_->Add(aspectRatio); + auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); + leftColumn->Add(stretch); - mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); + mode_ = new ChoiceStrip(ORIENT_VERTICAL); mode_->AddChoice(di->T("Move")); mode_->AddChoice(di->T("Resize")); mode_->SetSelection(0, false); - if (mode_) { - root_->Add(mode_); - } - - auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretched")); - rightColumn->Add(stretch); + leftColumn->Add(mode_); static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); rotation->SetEnabledFunc([] { return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; }); - rightColumn->Add(rotation); + leftColumn->Add(rotation); + + leftColumn->Add(new Spacer(12.0f)); + + Choice *center = new Choice(di->T("Reset")); + center->OnClick.Add([&](UI::EventParams &) { + g_Config.fDisplayAspectRatio = 1.0f; + g_Config.fDisplayScale = 1.0f; + g_Config.fDisplayOffsetX = 0.5f; + g_Config.fDisplayOffsetY = 0.5f; + return UI::EVENT_DONE; + }); + leftColumn->Add(center); static const char *bufFilters[] = { "Linear", "Nearest", }; rightColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); From d310636eb40d96e98aa46035d7d8384a320b5222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 15:57:13 +0100 Subject: [PATCH 419/715] Break out the background into a separate view. --- UI/DisplayLayoutScreen.cpp | 108 +++++++++++++++++++------------------ UI/DisplayLayoutScreen.h | 11 ---- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index f39bb50728..4b3cfe02de 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -55,6 +55,61 @@ static Bounds FRectToBounds(FRect rc) { return b; } +class DisplayLayoutBackground : public UI::View { +public: + DisplayLayoutBackground(UI::ChoiceStrip *mode, UI::LayoutParams *layoutParams) : UI::View(layoutParams), mode_(mode) {} + + void Touch(const TouchInput &touch) { + int mode = mode_ ? mode_->GetSelection() : 0; + + const Bounds &screenBounds = bounds_; + if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { + float relativeTouchX = touch.x - startX_; + float relativeTouchY = touch.y - startY_; + + switch (mode) { + case MODE_MOVE: + { + g_Config.fDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX / screenBounds.w; + g_Config.fDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY / screenBounds.h; + break; + } + case MODE_RESIZE: + { + // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction + float diffYProp = -relativeTouchY * 0.007f; + g_Config.fDisplayScale = startScale_ * powf(2.0f, diffYProp); + break; + } + } + } + + if ((touch.flags & TOUCH_DOWN) != 0 && !dragging_) { + dragging_ = true; + startX_ = touch.x; + startY_ = touch.y; + startDisplayOffsetX_ = g_Config.fDisplayOffsetX; + startDisplayOffsetY_ = g_Config.fDisplayOffsetY; + startScale_ = g_Config.fDisplayScale; + } + + if ((touch.flags & TOUCH_UP) != 0 && dragging_) { + dragging_ = false; + } + } + +private: + UI::ChoiceStrip *mode_; + bool dragging_ = false; + + // Touch down state for drag to resize etc + float startX_ = 0.0f; + float startY_ = 0.0f; + float startScale_ = -1.0f; + float startDisplayOffsetX_ = -1.0f; + float startDisplayOffsetY_ = -1.0f; +}; + DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) { // Ignore insets - just couldn't get the logic to work. ignoreInsets_ = true; @@ -82,51 +137,6 @@ void DisplayLayoutScreen::DrawBackground(UIContext &dc) { } } -bool DisplayLayoutScreen::touch(const TouchInput &touch) { - UIScreen::touch(touch); - - using namespace UI; - - int mode = mode_ ? mode_->GetSelection() : 0; - - const Bounds &screenBounds = screenManager()->getUIContext()->GetBounds(); - if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { - float relativeTouchX = touch.x - startX_; - float relativeTouchY = touch.y - startY_; - - switch (mode) { - case MODE_MOVE: - { - g_Config.fDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX / screenBounds.w; - g_Config.fDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY / screenBounds.h; - break; - } - case MODE_RESIZE: - { - // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction - float diffYProp = -relativeTouchY * 0.007f; - g_Config.fDisplayScale = startScale_ * powf(2.0f, diffYProp); - break; - } - } - } - - if ((touch.flags & TOUCH_DOWN) != 0 && !dragging_) { - dragging_ = true; - startX_ = touch.x; - startY_ = touch.y; - startDisplayOffsetX_ = g_Config.fDisplayOffsetX; - startDisplayOffsetY_ = g_Config.fDisplayOffsetY; - startScale_ = g_Config.fDisplayScale; - } - - if ((touch.flags & TOUCH_UP) != 0 && dragging_) { - dragging_ = false; - } - - return true; -} - void DisplayLayoutScreen::onFinish(DialogResult reason) { g_Config.Save("DisplayLayoutScreen::onFinish"); } @@ -188,12 +198,6 @@ void DisplayLayoutScreen::CreateViews() { rightScrollView->Add(rightColumn); root_->Add(rightScrollView); - bool displayRotEnable = !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; - bRotated_ = false; - if (displayRotEnable && (g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180)) { - bRotated_ = true; - } - PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); leftColumn->Add(aspectRatio); @@ -290,4 +294,6 @@ void DisplayLayoutScreen::CreateViews() { Choice *back = new Choice(di->T("Back"), "", false); back->OnClick.Handle(this, &UIScreen::OnBack); rightColumn->Add(back); + + root_->Add(new DisplayLayoutBackground(mode_, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, 0.0f, 0.0f, 0.0f, 0.0f))); } diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 6fe0f0f50e..690bbfde55 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -25,7 +25,6 @@ class DisplayLayoutScreen : public UIDialogScreenWithGameBackground { public: DisplayLayoutScreen(const Path &filename); void CreateViews() override; - bool touch(const TouchInput &touch) override; void dialogFinished(const Screen *dialog, DialogResult result) override; void onFinish(DialogResult reason) override; @@ -46,14 +45,4 @@ private: UI::ChoiceStrip *mode_ = nullptr; UI::Choice *postProcChoice_ = nullptr; std::string shaderNames_[256]; - - bool dragging_ = false; - bool bRotated_ = false; - - // Touch down state for drag to resize etc - float startX_ = 0.0f; - float startY_ = 0.0f; - float startScale_ = -1.0f; - float startDisplayOffsetX_ = -1.0f; - float startDisplayOffsetY_ = -1.0f; }; From 0a3d78221e5a01189c6cc80e20bb95bff8f99c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 16:15:16 +0100 Subject: [PATCH 420/715] Fix drag-background-through-buttons problem by adding "touch exclusive" mode to viewgroups. Not using universally because I don't want to debug all the issues... --- Common/UI/View.cpp | 42 ++++++++++++++++--------- Common/UI/View.h | 16 +++++----- Common/UI/ViewGroup.cpp | 19 ++++++++--- Common/UI/ViewGroup.h | 6 ++-- UI/DisplayLayoutScreen.cpp | 8 ++++- UI/GamepadEmu.cpp | 56 ++++++++++++++++++++------------- UI/GamepadEmu.h | 18 +++++------ UI/MainScreen.cpp | 5 +-- UI/TouchControlLayoutScreen.cpp | 5 +-- 9 files changed, 111 insertions(+), 64 deletions(-) diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index efc8cd13e4..cf741f5884 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -226,11 +226,13 @@ void Clickable::FocusChanged(int focusFlags) { } } -void Clickable::Touch(const TouchInput &input) { +bool Clickable::Touch(const TouchInput &input) { + bool contains = bounds_.Contains(input.x, input.y); + if (!IsEnabled()) { dragging_ = false; down_ = false; - return; + return contains; } if (input.flags & TOUCH_DOWN) { @@ -255,6 +257,7 @@ void Clickable::Touch(const TouchInput &input) { downCountDown_ = 0; dragging_ = false; } + return contains; } static bool MatchesKeyDef(const std::vector &defs, const KeyInput &key) { @@ -350,21 +353,24 @@ bool Clickable::Key(const KeyInput &key) { return ret; } -void StickyChoice::Touch(const TouchInput &input) { +bool StickyChoice::Touch(const TouchInput &touch) { + bool contains = bounds_.Contains(touch.x, touch.y); dragging_ = false; if (!IsEnabled()) { down_ = false; - return; + return contains; } - if (input.flags & TOUCH_DOWN) { - if (bounds_.Contains(input.x, input.y)) { + if (touch.flags & TOUCH_DOWN) { + if (contains) { if (IsFocusMovementEnabled()) SetFocusedView(this); down_ = true; Click(); + return true; } } + return false; } bool StickyChoice::Key(const KeyInput &key) { @@ -1069,12 +1075,14 @@ static std::string FirstLine(const std::string &text) { return text; } -void TextEdit::Touch(const TouchInput &touch) { +bool TextEdit::Touch(const TouchInput &touch) { if (touch.flags & TOUCH_DOWN) { if (bounds_.Contains(touch.x, touch.y)) { SetFocusedView(this, true); + return true; } } + return false; } bool TextEdit::Key(const KeyInput &input) { @@ -1259,14 +1267,15 @@ void Spinner::Draw(UIContext &dc) { } } -void TriggerButton::Touch(const TouchInput &input) { +bool TriggerButton::Touch(const TouchInput &input) { + bool contains = bounds_.Contains(input.x, input.y); if (input.flags & TOUCH_DOWN) { - if (bounds_.Contains(input.x, input.y)) { + if (contains) { down_ |= 1 << input.id; } } if (input.flags & TOUCH_MOVE) { - if (bounds_.Contains(input.x, input.y)) + if (contains) down_ |= 1 << input.id; else down_ &= ~(1 << input.id); @@ -1281,6 +1290,8 @@ void TriggerButton::Touch(const TouchInput &input) { } else { *bitField_ &= ~bit_; } + + return contains; } void TriggerButton::Draw(UIContext &dc) { @@ -1344,9 +1355,10 @@ bool Slider::ApplyKey(int keyCode) { return true; } -void Slider::Touch(const TouchInput &input) { +bool Slider::Touch(const TouchInput &input) { // Calling it afterwards, so dragging_ hasn't been set false yet when checking it above. - Clickable::Touch(input); + bool contains = Clickable::Touch(input); + if (dragging_) { float relativeX = (input.x - (bounds_.x + paddingLeft_)) / (bounds_.w - paddingLeft_ - paddingRight_); *value_ = floorf(relativeX * (maxValue_ - minValue_) + minValue_ + 0.5f); @@ -1360,6 +1372,7 @@ void Slider::Touch(const TouchInput &input) { // Cancel any key repeat. repeat_ = -1; + return contains; } void Slider::Clamp() { @@ -1470,8 +1483,8 @@ bool SliderFloat::ApplyKey(int keyCode) { return true; } -void SliderFloat::Touch(const TouchInput &input) { - Clickable::Touch(input); +bool SliderFloat::Touch(const TouchInput &input) { + bool contains = Clickable::Touch(input); if (dragging_) { float relativeX = (input.x - (bounds_.x + paddingLeft_)) / (bounds_.w - paddingLeft_ - paddingRight_); *value_ = (relativeX * (maxValue_ - minValue_) + minValue_); @@ -1485,6 +1498,7 @@ void SliderFloat::Touch(const TouchInput &input) { // Cancel any key repeat. repeat_ = -1; + return contains; } void SliderFloat::Clamp() { diff --git a/Common/UI/View.h b/Common/UI/View.h index 6e29c6bdef..64c9cdacf8 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -375,7 +375,7 @@ public: // Can even be called on a different thread! This is to really minimize latency, and decouple // touch response from the frame rate. Same with Key and Axis. virtual bool Key(const KeyInput &input) { return false; } - virtual void Touch(const TouchInput &input) {} + virtual bool Touch(const TouchInput &input) { return true; } virtual void Axis(const AxisInput &input) {} virtual void Update(); @@ -501,7 +501,7 @@ public: : View(layoutParams) {} bool Key(const KeyInput &input) override { return false; } - void Touch(const TouchInput &input) override {} + bool Touch(const TouchInput &input) override { return false; } bool CanBeFocused() const override { return false; } }; @@ -512,7 +512,7 @@ public: Clickable(LayoutParams *layoutParams); bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void FocusChanged(int focusFlags) override; @@ -602,7 +602,7 @@ public: void Draw(UIContext &dc) override; std::string DescribeText() const override; bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; void SetShowPercent(bool s) { showPercent_ = s; } @@ -633,7 +633,7 @@ public: void Draw(UIContext &dc) override; std::string DescribeText() const override; bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -661,7 +661,7 @@ public: TriggerButton(uint32_t *bitField, uint32_t bit, ImageID imageBackground, ImageID imageForeground, LayoutParams *layoutParams) : View(layoutParams), down_(0.0), bitField_(bitField), bit_(bit), imageBackground_(imageBackground), imageForeground_(imageForeground) {} - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -755,7 +755,7 @@ public: : Choice(buttonImage, layoutParams) {} bool Key(const KeyInput &key) override; - void Touch(const TouchInput &touch) override; + bool Touch(const TouchInput &touch) override; void FocusChanged(int focusFlags) override; void Press() { down_ = true; dragging_ = false; } @@ -943,7 +943,7 @@ public: void Draw(UIContext &dc) override; std::string DescribeText() const override; bool Key(const KeyInput &key) override; - void Touch(const TouchInput &touch) override; + bool Touch(const TouchInput &touch) override; Event OnTextChange; Event OnEnter; diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 556f664c9e..e69f6865c8 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -87,13 +87,20 @@ void ViewGroup::PersistData(PersistStatus status, std::string anonId, PersistMap } } -void ViewGroup::Touch(const TouchInput &input) { +bool ViewGroup::Touch(const TouchInput &input) { std::lock_guard guard(modifyLock_); + bool any = false; for (auto iter = views_.begin(); iter != views_.end(); ++iter) { // TODO: If there is a transformation active, transform input coordinates accordingly. - if ((*iter)->GetVisibility() == V_VISIBLE) - (*iter)->Touch(input); + if ((*iter)->GetVisibility() == V_VISIBLE) { + bool touch = (*iter)->Touch(input); + any = any || touch; + if (exclusiveTouch_ && touch) { + break; + } + } } + return any; } void ViewGroup::Query(float x, float y, std::vector &list) { @@ -850,7 +857,7 @@ bool ScrollView::Key(const KeyInput &input) { const float friction = 0.92f; const float stop_threshold = 0.1f; -void ScrollView::Touch(const TouchInput &input) { +bool ScrollView::Touch(const TouchInput &input) { if ((input.flags & TOUCH_DOWN) && scrollTouchId_ == -1) { scrollStart_ = scrollPos_; inertia_ = 0.0f; @@ -884,7 +891,9 @@ void ScrollView::Touch(const TouchInput &input) { } if (!(input.flags & TOUCH_DOWN) || bounds_.Contains(input.x, input.y)) { - ViewGroup::Touch(input2); + return ViewGroup::Touch(input2); + } else { + return false; } } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 5b552c5f0f..c5ee4032dd 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -28,7 +28,7 @@ public: // Pass through external events to children. virtual bool Key(const KeyInput &input) override; - virtual void Touch(const TouchInput &input) override; + virtual bool Touch(const TouchInput &input) override; virtual void Axis(const AxisInput &input) override; // By default, a container will layout to its own bounds. @@ -77,6 +77,7 @@ public: int GetNumSubviews() const { return (int)views_.size(); } void SetHasDropShadow(bool has) { hasDropShadow_ = has; } void SetDropShadowExpand(float s) { dropShadowExpand_ = s; } + void SetExclusiveTouch(bool exclusive) { exclusiveTouch_ = exclusive; } void Lock() { modifyLock_.lock(); } void Unlock() { modifyLock_.unlock(); } @@ -96,6 +97,7 @@ protected: float dropShadowExpand_ = 0.0f; bool hasDropShadow_ = false; bool clip_ = false; + bool exclusiveTouch_ = false; }; // A frame layout contains a single child view (normally). @@ -270,7 +272,7 @@ public: void Layout() override; bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; std::string DescribeLog() const override { return "ScrollView: " + View::DescribeLog(); } diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 4b3cfe02de..9e95b76e1c 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -59,7 +59,7 @@ class DisplayLayoutBackground : public UI::View { public: DisplayLayoutBackground(UI::ChoiceStrip *mode, UI::LayoutParams *layoutParams) : UI::View(layoutParams), mode_(mode) {} - void Touch(const TouchInput &touch) { + bool Touch(const TouchInput &touch) { int mode = mode_ ? mode_->GetSelection() : 0; const Bounds &screenBounds = bounds_; @@ -96,6 +96,8 @@ public: if ((touch.flags & TOUCH_UP) != 0 && dragging_) { dragging_ = false; } + + return true; } private: @@ -188,6 +190,10 @@ void DisplayLayoutScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + // Make it so that a touch can only affect one view. Makes manipulating the background through the buttons + // impossible. + root_->SetExclusiveTouch(true); + ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL); leftScrollView->Add(leftColumn); diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index bb1eb01f3b..5a1450eba5 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -45,8 +45,9 @@ GamepadView::GamepadView(const char *key, UI::LayoutParams *layoutParams) : UI:: lastFrameTime_ = time_now_d(); } -void GamepadView::Touch(const TouchInput &input) { +bool GamepadView::Touch(const TouchInput &input) { secondsWithoutTouch_ = 0.0f; + return true; } void GamepadView::Update() { @@ -96,8 +97,8 @@ void MultiTouchButton::GetContentDimensions(const UIContext &dc, float &w, float } } -void MultiTouchButton::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool MultiTouchButton::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if ((input.flags & TOUCH_DOWN) && bounds_.Contains(input.x, input.y)) { pointerDownMask_ |= 1 << input.id; usedPointerMask |= 1 << input.id; @@ -116,6 +117,7 @@ void MultiTouchButton::Touch(const TouchInput &input) { pointerDownMask_ = 0; usedPointerMask = 0; } + return retval; } void MultiTouchButton::Draw(UIContext &dc) { @@ -152,9 +154,9 @@ void MultiTouchButton::Draw(UIContext &dc) { dc.Draw()->DrawImageRotated(img_, bounds_.centerX(), y, scale, angle_ * (M_PI * 2 / 360.0f), color); } -void BoolButton::Touch(const TouchInput &input) { +bool BoolButton::Touch(const TouchInput &input) { bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); + bool retval = MultiTouchButton::Touch(input); bool down = pointerDownMask_ != 0; if (down != lastDown) { @@ -163,11 +165,12 @@ void BoolButton::Touch(const TouchInput &input) { params.a = down; OnChange.Trigger(params); } + return retval; } -void PSPButton::Touch(const TouchInput &input) { +bool PSPButton::Touch(const TouchInput &input) { bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); + bool retval = MultiTouchButton::Touch(input); bool down = pointerDownMask_ != 0; if (down && !lastDown) { if (g_Config.bHapticFeedback) { @@ -177,6 +180,7 @@ void PSPButton::Touch(const TouchInput &input) { } else if (lastDown && !down) { __CtrlButtonUp(pspButtonBit_); } + return retval; } bool ComboKey::IsDown() { @@ -192,10 +196,10 @@ void ComboKey::GetContentDimensions(const UIContext &dc, float &w, float &h) con } } -void ComboKey::Touch(const TouchInput &input) { +bool ComboKey::Touch(const TouchInput &input) { using namespace CustomKey; bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); + bool retval = MultiTouchButton::Touch(input); bool down = pointerDownMask_ != 0; if (down && !lastDown) { @@ -220,6 +224,7 @@ void ComboKey::Touch(const TouchInput &input) { } on_ = false; } + return retval; } void ComboKey::Update() { @@ -272,8 +277,8 @@ void PSPDpad::GetContentDimensions(const UIContext &dc, float &w, float &h) cons } } -void PSPDpad::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool PSPDpad::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if (input.flags & TOUCH_DOWN) { if (dragPointerId_ == -1 && bounds_.Contains(input.x, input.y)) { @@ -297,6 +302,7 @@ void PSPDpad::Touch(const TouchInput &input) { ProcessTouch(input.x, input.y, false); } } + return retval; } void PSPDpad::ProcessTouch(float x, float y, bool down) { @@ -438,8 +444,8 @@ void PSPStick::Draw(UIContext &dc) { dc.Draw()->DrawImage(stickImageIndex_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f * scale_ * headScale, colorBg, ALIGN_CENTER); } -void PSPStick::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool PSPStick::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if (input.flags & TOUCH_RELEASE_ALL) { dragPointerId_ = -1; centerX_ = bounds_.centerX(); @@ -447,7 +453,7 @@ void PSPStick::Touch(const TouchInput &input) { __CtrlSetAnalogXY(stick_, 0.0f, 0.0f); usedPointerMask = 0; analogPointerMask = 0; - return; + return retval; } if (input.flags & TOUCH_DOWN) { float fac = 0.5f*(stick_ ? g_Config.fRightStickHeadScale : g_Config.fLeftStickHeadScale)-0.5f; @@ -463,11 +469,13 @@ void PSPStick::Touch(const TouchInput &input) { usedPointerMask |= 1 << input.id; analogPointerMask |= 1 << input.id; ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_MOVE) { if (input.id == dragPointerId_) { ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_UP) { @@ -478,8 +486,10 @@ void PSPStick::Touch(const TouchInput &input) { usedPointerMask &= ~(1 << input.id); analogPointerMask &= ~(1 << input.id); ProcessTouch(input.x, input.y, false); + retval = true; } } + return retval; } void PSPStick::ProcessTouch(float x, float y, bool down) { @@ -542,8 +552,8 @@ void PSPCustomStick::Draw(UIContext &dc) { dc.Draw()->DrawImage(stickImageIndex_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f*scale_*g_Config.fRightStickHeadScale, colorBg, ALIGN_CENTER); } -void PSPCustomStick::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool PSPCustomStick::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if (input.flags & TOUCH_RELEASE_ALL) { dragPointerId_ = -1; centerX_ = bounds_.centerX(); @@ -552,7 +562,7 @@ void PSPCustomStick::Touch(const TouchInput &input) { posY_ = 0.0f; usedPointerMask = 0; analogPointerMask = 0; - return; + return false; } if (input.flags & TOUCH_DOWN) { float fac = 0.5f*g_Config.fRightStickHeadScale-0.5f; @@ -568,11 +578,13 @@ void PSPCustomStick::Touch(const TouchInput &input) { usedPointerMask |= 1 << input.id; analogPointerMask |= 1 << input.id; ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_MOVE) { if (input.id == dragPointerId_) { ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_UP) { @@ -583,8 +595,10 @@ void PSPCustomStick::Touch(const TouchInput &input) { usedPointerMask &= ~(1 << input.id); analogPointerMask &= ~(1 << input.id); ProcessTouch(input.x, input.y, false); + retval = true; } } + return true; } void PSPCustomStick::ProcessTouch(float x, float y, bool down) { @@ -890,17 +904,16 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause, bool showPau return root; } - -void GestureGamepad::Touch(const TouchInput &input) { +bool GestureGamepad::Touch(const TouchInput &input) { if (usedPointerMask & (1 << input.id)) { if (input.id == dragPointerId_) dragPointerId_ = -1; - return; + return false; } if (input.flags & TOUCH_RELEASE_ALL) { dragPointerId_ = -1; - return; + return false; } if (input.flags & TOUCH_DOWN) { @@ -940,6 +953,7 @@ void GestureGamepad::Touch(const TouchInput &input) { } } } + return true; } void GestureGamepad::Update() { diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index bb8da30ea7..0eb2a7c60c 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -29,7 +29,7 @@ class GamepadView : public UI::View { public: GamepadView(const char *key, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; bool Key(const KeyInput &input) override { return false; } @@ -50,7 +50,7 @@ public: : GamepadView(key, layoutParams), scale_(scale), bgImg_(bgImg), bgDownImg_(bgDownImg), img_(img) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; virtual bool IsDown() { return pointerDownMask_ != 0; } @@ -78,7 +78,7 @@ public: : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), value_(value) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; bool IsDown() override { return *value_; } UI::Event OnChange; @@ -92,7 +92,7 @@ public: PSPButton(int pspButtonBit, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; bool IsDown() override; private: @@ -103,7 +103,7 @@ class PSPDpad : public GamepadView { public: PSPDpad(ImageID arrowIndex, const char *key, ImageID arrowDownIndex, ImageID overlayIndex, float scale, float spacing, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -124,7 +124,7 @@ class PSPStick : public GamepadView { public: PSPStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, int stick, float scale, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -149,7 +149,7 @@ class PSPCustomStick : public PSPStick { public: PSPCustomStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, float scale, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; private: @@ -172,7 +172,7 @@ public: ComboKey(uint64_t pspButtonBit, const char *key, bool toggle, bool repeat, ControlMapper* controllMapper, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, bool invertedContextDimension, UI::LayoutParams *layoutParams) : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit), toggle_(toggle), repeat_(repeat), controlMapper_(controllMapper), on_(false), invertedContextDimension_(invertedContextDimension) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; bool IsDown() override; @@ -191,7 +191,7 @@ class GestureGamepad : public UI::View { public: GestureGamepad(ControlMapper* controllMapper) : controlMapper_(controllMapper) {}; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; protected: diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index d5ed3ab0a4..cdd1fc4a0c 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -136,8 +136,8 @@ public: void SetHoldEnabled(bool hold) { holdEnabled_ = hold; } - void Touch(const TouchInput &input) override { - UI::Clickable::Touch(input); + bool Touch(const TouchInput &input) override { + bool retval = UI::Clickable::Touch(input); hovering_ = bounds_.Contains(input.x, input.y); if (hovering_ && (input.flags & TOUCH_DOWN)) { holdStart_ = time_now_d(); @@ -145,6 +145,7 @@ public: if (input.flags & TOUCH_UP) { holdStart_ = 0; } + return retval; } bool Key(const KeyInput &key) override { diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 31fffd6ff4..12012332a1 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -359,7 +359,7 @@ public: : UI::AnchorLayout(layoutParams) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void CreateViews(); bool HasCreatedViews() const { return !controls_.empty(); @@ -384,7 +384,7 @@ static Point ClampTo(const Point &p, const Bounds &b) { return Point(clamp_value(p.x, b.x, b.x + b.w), clamp_value(p.y, b.y, b.y + b.h)); } -void ControlLayoutView::Touch(const TouchInput &touch) { +bool ControlLayoutView::Touch(const TouchInput &touch) { using namespace UI; if ((touch.flags & TOUCH_MOVE) && pickedControl_ != nullptr) { @@ -452,6 +452,7 @@ void ControlLayoutView::Touch(const TouchInput &touch) { pickedControl_->SavePosition(); pickedControl_ = 0; } + return true; } void ControlLayoutView::CreateViews() { From 689860b3a0a7364a32a16fd79f686a25891b1519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 17:32:34 +0100 Subject: [PATCH 421/715] Qt buildfix, apply feedback --- Qt/mainwindow.cpp | 2 +- Qt/mainwindow.h | 4 ---- UI/GamepadEmu.cpp | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index fbe4a35c84..ff0947f573 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -589,7 +589,7 @@ void MainWindow::createMenus() MenuTree* gameSettingsMenu = new MenuTree(this, menuBar(), QT_TR_NOOP("&Game settings")); gameSettingsMenu->add(new MenuAction(this, SLOT(languageAct()), QT_TR_NOOP("La&nguage..."))); gameSettingsMenu->add(new MenuAction(this, SLOT(controlMappingAct()), QT_TR_NOOP("C&ontrol mapping..."))); - gameSettingsMenu->add(new MenuAction(this, SLOT(displayLayoutEditorAct()), QT_TR_NOOP("Display layout editor..."))); + gameSettingsMenu->add(new MenuAction(this, SLOT(displayLayoutEditorAct()), QT_TR_NOOP("Display layout & effects..."))); gameSettingsMenu->add(new MenuAction(this, SLOT(moreSettingsAct()), QT_TR_NOOP("&More settings..."))); gameSettingsMenu->addSeparator(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index fa7d3ceb6f..705a3dd004 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -130,10 +130,6 @@ private slots: } void windowGroup_triggered(QAction *action) { SetWindowScale(action->data().toInt()); } - void displayLayoutGroup_triggered(QAction *action) { - g_Config.iSmallDisplayZoomType = action->data().toInt(); - NativeMessageReceived("gpu_displayResized", ""); - } void autoframeskipAct() { g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip; if (g_Config.bSkipBufferEffects) { diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index 5a1450eba5..fcb09cf365 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -598,7 +598,7 @@ bool PSPCustomStick::Touch(const TouchInput &input) { retval = true; } } - return true; + return retval; } void PSPCustomStick::ProcessTouch(float x, float y, bool down) { From 981a8778a4c6d435e277d62e3f13d2cf7bf7678c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 19:27:27 +0100 Subject: [PATCH 422/715] Lang: Remove old stuff, add missing lines --- assets/lang/en_US.ini | 14 ++++++++------ assets/lang/th_TH.ini | 2 +- assets/shaders/defaultshaders.ini | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index c4623160cc..ca9cc76e18 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -173,6 +173,7 @@ File = &File Frame Skipping = &Frame skipping Frame Skipping Type = Frame skipping type Fullscreen = Fu&llscreen +Geometry shader culling = Geometry shader culling Game Settings = &Game settings GE Debugger... = GE debugge&r... GitHub = Git&Hub @@ -256,7 +257,6 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -268,8 +268,6 @@ GPU Profile = GPU profile GPU Log Profiler = GPU Log Profiler Jit Compare = JIT compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Load language ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -285,7 +283,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Save language ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -514,7 +511,6 @@ Direct3D 11 = Direct3D 11 Disabled = Disabled Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control @@ -564,7 +560,6 @@ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter @@ -574,6 +569,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretching = Stretching Texture Filter = Texture filtering Texture Filtering = Texture filtering @@ -829,11 +826,13 @@ Bloom = Bloom Brightness = Brightness Cartoon = Cartoon ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors Natural = Natural Colors @@ -841,9 +840,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1139,6 +1140,7 @@ Fast Memory = Fast memory (unstable) Floating symbols = Floating symbols Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) frames, 0:off = frames, 0 = off +Game crashed = Game crashed Games list settings = Games list settings General = General Grid icon size = Grid icon size diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index d1d4a73702..bbfd27eccd 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -853,7 +853,7 @@ RedBlue = ภาพแว่นแดงฟ้า (สามมิติแบ Saturation = ความอิ่มตัวของสี Scanlines = ภาพออกมัวเป็นเส้นแนวนอน Sharpen = ภาพเน้นขอบคมขึ้น -SideBySize = ภาพแยกสองจอแบบสามมิติ +SideBySide = ภาพแยกสองจอแบบสามมิติ SSAA(Gauss) = ภาพเน้นความละเอียดให้สูงขึ้น Tex4xBRZ = 4xBRZ TexMMPX = MMPX diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index 79bb4bb5e6..2a33454069 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -202,7 +202,7 @@ SettingMinValue2=0.0 SettingStep2=0.05 Fragment=stereo_red_blue.fsh Vertex=fxaa.vsh -[SideBySize] +[SideBySide] Type=StereoToMono Name=SideBySide Stereo Author=Henrik Rydgård From a0f10141abbd818312a4445ed40c4eb12e75bfbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 19:35:13 +0100 Subject: [PATCH 423/715] lang; Stretching->stretch --- assets/lang/ar_AE.ini | 2 +- assets/lang/az_AZ.ini | 2 +- assets/lang/bg_BG.ini | 2 +- assets/lang/ca_ES.ini | 2 +- assets/lang/cz_CZ.ini | 2 +- assets/lang/da_DK.ini | 2 +- assets/lang/de_DE.ini | 2 +- assets/lang/dr_ID.ini | 2 +- assets/lang/en_US.ini | 2 +- assets/lang/es_ES.ini | 2 +- assets/lang/es_LA.ini | 2 +- assets/lang/fa_IR.ini | 2 +- assets/lang/fi_FI.ini | 2 +- assets/lang/fr_FR.ini | 2 +- assets/lang/gl_ES.ini | 2 +- assets/lang/gr_EL.ini | 2 +- assets/lang/he_IL.ini | 2 +- assets/lang/he_IL_invert.ini | 2 +- assets/lang/hr_HR.ini | 2 +- assets/lang/hu_HU.ini | 2 +- assets/lang/id_ID.ini | 2 +- assets/lang/it_IT.ini | 2 +- assets/lang/ja_JP.ini | 2 +- assets/lang/jv_ID.ini | 2 +- assets/lang/ko_KR.ini | 2 +- assets/lang/lo_LA.ini | 2 +- assets/lang/lt-LT.ini | 2 +- assets/lang/ms_MY.ini | 2 +- assets/lang/nl_NL.ini | 2 +- assets/lang/no_NO.ini | 2 +- assets/lang/pl_PL.ini | 2 +- assets/lang/pt_BR.ini | 2 +- assets/lang/pt_PT.ini | 2 +- assets/lang/ro_RO.ini | 2 +- assets/lang/ru_RU.ini | 2 +- assets/lang/sv_SE.ini | 2 +- assets/lang/tg_PH.ini | 2 +- assets/lang/th_TH.ini | 2 +- assets/lang/tr_TR.ini | 2 +- assets/lang/uk_UA.ini | 2 +- assets/lang/vi_VN.ini | 2 +- assets/lang/zh_CN.ini | 2 +- assets/lang/zh_TW.ini | 2 +- 43 files changed, 43 insertions(+), 43 deletions(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index d0bafd4a94..5294f00280 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -554,7 +554,7 @@ Software Skinning = ‎طلاء برمجي SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = ‎السرعة Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = ‎المط +Stretch = ‎المط Texture Filter = ‎منقي الرسوم Texture Filtering = ‎مفلتر الرسوم Texture Scaling = ‎تكبير الرسوم diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 2b88959617..9dd11ca652 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering Texture Scaling = Texture scaling diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index ab980217e2..86228f37c8 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Скорост Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = Текстурно филтриране Texture Filtering = Текстурно филтриране Texture Scaling = Текстурно мащабиране diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 4b49794b2b..8acb5e826e 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering Texture Scaling = Texture scaling diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 3d4ffd360c..d289d1282f 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -546,7 +546,7 @@ Software Skinning = Textury aplikuje software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Rychlost Speed Hacks = Speed Hacks (Mohou způsobit problémy) -Stretching = Roztažení +Stretch = Roztažení Texture Filter = Filtr textur Texture Filtering = Filtrování textur Texture Scaling = Změna velikosti textur diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 961d4cdb86..d0a379a46e 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Kombiner begrænset model tegning af CPU, hurtigere i fleste spil Speed = Hastighed Speed Hacks = Speed Hacks (kan give fejl) -Stretching = Stretching +Stretch = Stretch Texture Filter = Texturfilter Texture Filtering = Texturfiltrering Texture Scaling = Texturskalering diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 6e5ecb80ab..08dd21ca71 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -546,7 +546,7 @@ Software Skinning = Software Skinning SoftwareSkinning Tip = Reduziert Grafikbefehle und schneller in Spielen mit erweiterter Skinning-Technik, in anderen Spielen langsamer Speed = Geschwindigkeit Speed Hacks = Speed Hacks (kann zu Fehlern führen) -Stretching = Strecken +Stretch = Strecken Texture Filter = Texturfilter Texture Filtering = Texturfilterung Texture Scaling = Texturskalierung diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index b58310d930..d992d6fd65 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Lassinna Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = Panyaring Texture Texture Filtering = Saring i Texture Texture Scaling = Petonggoi Texture diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index ca9cc76e18..ebc732d9ca 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -571,7 +571,7 @@ Speed = Speed Speed Hacks = Speed Hacks (can cause rendering errors!) Stereo display shader = Stereo display shader Stereo rendering = Stereo rendering -Stretching = Stretching +Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering Texture Scaling = Texture scaling diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 3535c000ff..9d3c2dd5ed 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -546,7 +546,7 @@ Software Skinning = "Skinning" por software SoftwareSkinning Tip = Reduce la carga de dibujado, rápido en juegos con técnicas de skinning avanzadas, pero lento en otros. Speed = Velocidad Speed Hacks = Speed Hacks (causarán errores gráficos) -Stretching = Estirar +Stretch = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas Texture Scaling = Escalado de texturas diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index b70659e928..674b9e3d29 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -546,7 +546,7 @@ Software Skinning = Skineado por software SoftwareSkinning Tip = Combina dibujados de modelo de skineado en la CPU. Acelera muchos juegos pero ralentiza otros. Speed = Velocidad Speed Hacks = Speed Hacks (puede causar glitches) -Stretching = Estirar +Stretch = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas Texture Scaling = Escalado de texturas diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index be7146f4d8..8566450a84 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = ‎در اکثر بازی ها سریع تر ،CPU دار در skin ترکیب رسم مدل های Speed = ‎سرعت Speed Hacks = Speed Hacks ‎(میتواند باعث باگ شود) -Stretching = ‎کشیدن +Stretch = ‎کشیدن Texture Filter = ‎فیلتر تکسچر Texture Filtering = ‎فیلتر کردن تکسچر Texture Scaling = ‎تغییر سایز تکسچر ها diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index b14de050e4..e05580d325 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Nopeus Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = Tekstuurisuodatin Texture Filtering = Tekstuurin suodatus Texture Scaling = Tekstuurin skaalaus diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index c383bb1e01..3afc81fe12 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -546,7 +546,7 @@ Software Skinning = Enveloppe logicielle SoftwareSkinning Tip = Combine l'affichage des modèles enveloppés sur le CPU, plus rapide dans la plupart des jeux Speed = Vitesse Speed Hacks = Speed Hacks (crée des bugs graphiques) -Stretching = Étirement +Stretch = Étirement Texture Filter = Filtre de textures Texture Filtering = Filtrage des textures Texture Scaling = Mise à l'échelle des textures diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 68cb80b771..314ba6226d 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -546,7 +546,7 @@ Software Skinning = «Skinning» por software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Velocidade Speed Hacks = Speed Hacks (causarán erros gráficos) -Stretching = Stretching +Stretch = Stretch Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas Texture Scaling = Escalado de texturas diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index f986ec024d..5be577a15b 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -546,7 +546,7 @@ Software Skinning = Εκδορά Λογισμικού SoftwareSkinning Tip = Συνδυασμός μοντέλου στην CPU, γρηγορότερο στα περισσότερα παιχνίδια Speed = Ταχύτητα Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Επέκταση +Stretch = Επέκταση Texture Filter = Φίλτρο Υφών Texture Filtering = Φιλτράρισμα Υφών Texture Scaling = Κλιμάκωση Υφών diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 50bb2049b2..1925962c63 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = מהירות Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = קידוד טקסטורה Texture Filtering = קידוד טקסטורה Texture Scaling = מידת טקסטורה diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 5e94eea165..5e5aafc3f9 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = תוריהמ Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = הרוטסקט דודיק Texture Filtering = הרוטסקט דודיק Texture Scaling = הרוטסקט תדימ diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 33f465633e..763b14669d 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -546,7 +546,7 @@ Software Skinning = Skiniranje softvera SoftwareSkinning Tip = Kombiniraj skinirane modele crteža na CPU, brže u većini igara Speed = Brzina Speed Hacks = Speed Hacks (može uzrokovati glitcheve) -Stretching = Rastezanje +Stretch = Rastezanje Texture Filter = Filtar tekstura Texture Filtering = Filtriranje tekstura Texture Scaling = Mjerenje tekstura diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 0a7fdae059..8e27c6db62 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -546,7 +546,7 @@ Software Skinning = Szoftveres "skinning" SoftwareSkinning Tip = "Skinning" művelet elvégzése a processzoron. Sok játék esetében gyorsabb. Speed = Sebesség Speed Hacks = Speed Hacks (ezek HIBÁKAT OKOZHATNAK) -Stretching = Nyújtás +Stretch = Nyújtás Texture Filter = Textúra szűrés Texture Filtering = Textúra szűrés Texture Scaling = Textúra nagyítás diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 0c86521812..ccbdc9ef5b 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -546,7 +546,7 @@ Software Skinning = Pengkulitan perangkat lunak SoftwareSkinning Tip = Menggabungkan model berkulit pada CPU, lebih cepat di kebanyakan permainan Speed = Kecepatan Speed Hacks = Speed Hacks (menyebabkan kecacatan) -Stretching = Peregangan +Stretch = Peregangan Texture Filter = Filter tekstur Texture Filtering = Pemfilteran tekstur Texture Scaling = Penskala tekstur diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 024e59c236..aae3f8e8b6 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -547,7 +547,7 @@ Software Skinning = Software Skinning SoftwareSkinning Tip = Combina la visualizzazione di modelli disegnati dalla CPU, più veloce nella maggior parte dei giochi Speed = Velocità Speed Hacks = Speed Hacks (causerà dei problemi) -Stretching = Adatta al Display +Stretch = Adatta al Display Texture Filter = Filtro delle texture Texture Filtering = Filtraggio delle texture Texture Scaling = Scalatura delle texture diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 18235dca8e..136faaa009 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -546,7 +546,7 @@ Software Skinning = ソフトウェアスキニング SoftwareSkinning Tip = スキンモデルの描画をCPUでまとめて行う。ほとんどのゲームが高速化します Speed = 速度 Speed Hacks = Speed Hacks (不具合あり) -Stretching = 拡大 +Stretch = 拡大 Texture Filter = テクスチャフィルタ Texture Filtering = テクスチャフィルタリング Texture Scaling = テクスチャスケーリング diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 62d4c8eaba..fcf34e2357 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Kacepetan Speed Hacks = Speed Hacks (nyebabake glitches) -Stretching = Stretching +Stretch = Stretch Texture Filter = Penyaring Tekstur Texture Filtering = Penyaring Tekstur Texture Scaling = Skala Tekstur diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index b7b3a20308..92fc7bc847 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -545,7 +545,7 @@ Software Skinning = 소프트웨어 스키닝 SoftwareSkinning Tip = 대부분의 게임에서 더 빠르게 CPU에서 스킨 모델 드로우를 결합합니다. Speed = 속도 Speed Hacks = Speed Hacks (결함을 일으킬 수 있음) -Stretching = 늘이기 +Stretch = 늘이기 Texture Filter = 텍스처 필터링 Texture Filtering = 텍스처 필터링 Texture Scaling = 텍스처 스케일링 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index d1413e8535..94414b5468 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -546,7 +546,7 @@ Software Skinning = ຊ໋ອບແວຣ໌ສກິນນິງ SoftwareSkinning Tip = ປະສານໂມເດລພື້ນຜິວໃຫ້ຂຽນຜ່ານ CPU, ເກມສ່ວນໃຫຍ່ໃຊ້ແລ້ວໄວຂຶ້ນ Speed = ຄວາມໄວ Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = ດຶງເຕັມຈໍ +Stretch = ດຶງເຕັມຈໍ Texture Filter = ໂຕຕອງພື້ນຜິວ Texture Filtering = ຕອງພື້ນຜິວ Texture Scaling = ປັບພື້ນຜິວ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 92dddc81dc..b707b5ebcd 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -546,7 +546,7 @@ Software Skinning = Programinės įrangos "nulupimas" SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Greitis Speed Hacks = Speed Hacks (gali sukelti problemų) -Stretching = Stretching +Stretch = Stretch Texture Filter = Tekstūrų filtravimas Texture Filtering = Tekstūrų filtravimas Texture Scaling = Tekstūrų skalė diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 1482e2e6b7..b1aa99e543 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -546,7 +546,7 @@ Software Skinning = Pembalutan Perisian SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Laju Speed Hacks = Speed Hacks (mungkin menyebabkan gangguan) -Stretching = Stretching +Stretch = Stretch Texture Filter = Penapis Tekstur Texture Filtering = Penapisan Tekstur Texture Scaling = Penskalaan Tekstur diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 36a99debca..492a725a72 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -546,7 +546,7 @@ Software Skinning = Skinning via software SoftwareSkinning Tip = Vermindert aantal renders en is sneller in games die de geavanceerde skinningtechniek gebruiken, maar voor sommige games trager Speed = Snelheid Speed Hacks = Speed Hacks (kan glitches veroorzaken) -Stretching = Uitrekken +Stretch = Uitrekken Texture Filter = Texturefilter Texture Filtering = Texturefilter Texture Scaling = Textures schalen diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 44c86118f0..fad6df3012 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet Speed Hacks = Speed Hacks (can cause rendering errors!) -Stretching = Stretching +Stretch = Stretch Texture Filter = Tekstur filtrering Texture Filtering = Tekstur filtrering Texture Scaling = Teksturskalning diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index cd1469f063..07d732d812 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -546,7 +546,7 @@ Software Skinning = Programowy skinning SoftwareSkinning Tip = Łączy na CPU wywołania rysujące modele z animacjami, przyspieszenie w większości gier Speed = Prędkość (procentowo) Speed Hacks = Speed Hacks (powodują problemy) -Stretching = Rozciąganie +Stretch = Rozciąganie Texture Filter = Filtrowanie tekstur Texture Filtering = Filtrowanie tekstur Texture Scaling = Skalowanie tekstur diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 990f23cb4f..dcba12a8cc 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -569,7 +569,7 @@ Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade Speed Hacks = Speed Hacks (pode causar erros gráficos) -Stretching = Esticamento +Stretch = Esticamento Texture Filter = Filtragem das texturas Texture Filtering = Filtragem das texturas Texture Scaling = Dimensionamento das texturas diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 832dd499cb..b81aeb50f5 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -569,7 +569,7 @@ Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade Speed Hacks = Speed Hacks (pode causar erros gráficos) -Stretching = Esticamento +Stretch = Esticamento Texture Filter = Filtração das texturas Texture Filtering = Filtração das texturas Texture Scaling = Dimensionamento das texturas diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index ab9d3b8c82..7d933f0dbc 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -546,7 +546,7 @@ Software Skinning = Skinning cu software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Viteză Speed Hacks = Speed Hacks (pot cauza stricăciuni) -Stretching = Stretching +Stretch = Stretch Texture Filter = Filtru texturi Texture Filtering = Filtrare texturi Texture Scaling = Scalare texturi diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index b85e620042..eb70f9705f 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -547,7 +547,7 @@ Software Skinning = Программная заливка SoftwareSkinning Tip = Объединяет вызовы отрисовки моделей с заливкой на ЦП, быстрее во многих играх Speed = Скорость Speed Hacks = Speed Hacks (могут вызывать глюки) -Stretching = Растягивание +Stretch = Растягивание Texture Filter = Текстурный фильтр Texture Filtering = Фильтрация текстур Texture Scaling = Масштабирование текстур diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 28e8763f58..76cff02363 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -546,7 +546,7 @@ Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet Speed Hacks = Speed-hacks (kan orsaka renderingsproblem) -Stretching = Stretching +Stretch = Stretch Texture Filter = Texturfilter Texture Filtering = Texturfiltrering Texture Scaling = Texturskalning diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index e9ed4eaaf6..5b44d67dd9 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -546,7 +546,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Bilis Speed Hacks = Speed Hacks (maaring magdulot ng pagloloko sa laro) -Stretching = Iunat +Stretch = Iunat Texture Filter = Panala ng Texture Texture Filtering = Pagsala sa Texture Texture Scaling = Pagsukat sa Texture diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index bbfd27eccd..daf45163b1 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -549,7 +549,7 @@ Speed = ความเร็ว Speed Hacks = แฮ็คความเร็ว (อาจแสดงผลผิดพลาด) Stereo display shader = เฉดแสงสีของภาพแบบสามมิติ Stereo rendering = การแสดงผลแบบสามมิติ -Stretching = ดึงเต็มจอ +Stretch = ดึงเต็มจอ Texture Filter = ตัวกรองพื้นผิว Texture Filtering = การกรองพื้นผิว Texture Scaling = การปรับสเกลพื้นผิว diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index c27b4c31f4..52618a9865 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -548,7 +548,7 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hız Speed Hacks = Hız Hacks (Küçük teknik problemlere neden olabilir.) -Stretching = Serbest tam ekran (sünme) +Stretch = Serbest tam ekran (sünme) Texture Filter = Doku filtreleme Texture Filtering = Doku filtreleme Texture Scaling = Doku ölçekleme diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 32ac166a5f..db4bfd72bb 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -546,7 +546,7 @@ Software Skinning = Програмна заливка SoftwareSkinning Tip = Комбінована модель розібраної моделі яка притягується до процесора, швидше в більшості ігор Speed = Швидкість Speed Hacks = Speed Hacks (можуть викликати глюки) -Stretching = Розтягнення +Stretch = Розтягнення Texture Filter = Фільтр текстур Texture Filtering = Фільтрація текстур Texture Scaling = Масштабування текстур diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 84a268878f..1bb9d8b1da 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -546,7 +546,7 @@ Software Skinning = phủ lớp bằng phần mềm SoftwareSkinning Tip = Mô hình kết hợp vẽ trên CPU, nhanh hơn trong hầu hết các trò chơi Speed = Tốc độ Speed Hacks = Tốc độ Hacks (sẽ bị lỗi) -Stretching = Stretching +Stretch = Stretch Texture Filter = Bộ lọc họa tiết Texture Filtering = Lọc texture Texture Scaling = Họa tiết rộng diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 060454ef5a..60ea9dedbb 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -546,7 +546,7 @@ Software Skinning = 软件蒙皮 SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快 Speed = 运行速度 Speed Hacks = 速度修正 (可能引发故障) -Stretching = 拉伸 +Stretch = 拉伸 Texture Filter = 纹理过滤方式 Texture Filtering = 纹理过滤 Texture Scaling = 纹理缩放 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 26d9db1834..6cd9b323cd 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -545,7 +545,7 @@ Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 Speed Hacks = 速度駭客 (可能會造成轉譯錯誤!) -Stretching = 延伸 +Stretch = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 Texture Scaling = 紋理縮放 From dbd799bce359b3f63cacdbf2ca0a62d5cfb5b06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 19:42:30 +0100 Subject: [PATCH 424/715] Add new translation key "Aspect Ratio" --- Tools/langtool/src/main.rs | 52 +++++++++++++++++++++++++++++++++--- assets/lang/ar_AE.ini | 1 + assets/lang/az_AZ.ini | 1 + assets/lang/bg_BG.ini | 1 + assets/lang/ca_ES.ini | 1 + assets/lang/cz_CZ.ini | 1 + assets/lang/da_DK.ini | 1 + assets/lang/de_DE.ini | 1 + assets/lang/dr_ID.ini | 1 + assets/lang/es_ES.ini | 1 + assets/lang/es_LA.ini | 1 + assets/lang/fa_IR.ini | 1 + assets/lang/fi_FI.ini | 1 + assets/lang/fr_FR.ini | 1 + assets/lang/gl_ES.ini | 1 + assets/lang/gr_EL.ini | 1 + assets/lang/he_IL.ini | 1 + assets/lang/he_IL_invert.ini | 1 + assets/lang/hr_HR.ini | 1 + assets/lang/hu_HU.ini | 1 + assets/lang/id_ID.ini | 1 + assets/lang/it_IT.ini | 1 + assets/lang/ja_JP.ini | 1 + assets/lang/jv_ID.ini | 1 + assets/lang/ko_KR.ini | 1 + assets/lang/lo_LA.ini | 1 + assets/lang/lt-LT.ini | 1 + assets/lang/ms_MY.ini | 1 + assets/lang/nl_NL.ini | 1 + assets/lang/no_NO.ini | 1 + assets/lang/pl_PL.ini | 1 + assets/lang/pt_BR.ini | 1 + assets/lang/pt_PT.ini | 1 + assets/lang/ro_RO.ini | 1 + assets/lang/ru_RU.ini | 1 + assets/lang/sv_SE.ini | 1 + assets/lang/tg_PH.ini | 1 + assets/lang/th_TH.ini | 1 + assets/lang/tr_TR.ini | 1 + assets/lang/uk_UA.ini | 1 + assets/lang/vi_VN.ini | 1 + assets/lang/zh_CN.ini | 1 + assets/lang/zh_TW.ini | 1 + 43 files changed, 90 insertions(+), 4 deletions(-) diff --git a/Tools/langtool/src/main.rs b/Tools/langtool/src/main.rs index 6b99a272d3..f17aab1186 100644 --- a/Tools/langtool/src/main.rs +++ b/Tools/langtool/src/main.rs @@ -18,6 +18,10 @@ enum Command { CopyMissingLines {}, CommentUnknownLines {}, RemoveUnknownLines {}, + AddNewKey { + section: String, + key: String, + }, MoveKey { old: String, new: String, @@ -89,6 +93,15 @@ fn remove_key(target_ini: &mut IniFile, section: &str, key: &str) -> io::Result< Ok(()) } +fn add_new_key(target_ini: &mut IniFile, section: &str, key: &str) -> io::Result<()> { + if let Some(section) = target_ini.get_section_mut(section) { + let _ = section.insert_line_if_missing(&format!("{} = {}", key, key)); + } else { + println!("No section {}", section); + } + Ok(()) +} + fn main() { let opt = Opt::from_args(); @@ -97,15 +110,15 @@ fn main() { let mut filenames = args; let root = "../../assets/lang"; - let reference_file = "en_US.ini"; + let reference_ini_filename = "en_US.ini"; - let reference_ini = IniFile::parse(&format!("{}/{}", root, reference_file)).unwrap(); + let mut reference_ini = IniFile::parse(&format!("{}/{}", root, reference_ini_filename)).unwrap(); if filenames.is_empty() { // Grab them all. for path in std::fs::read_dir(root).unwrap() { let path = path.unwrap(); - if path.file_name() == reference_file { + if path.file_name() == reference_ini_filename { continue; } let filename = path.file_name(); @@ -118,6 +131,7 @@ fn main() { } for filename in filenames { + let reference_ini = &reference_ini; if filename == "langtool" { // Get this from cargo run for some reason. continue; @@ -137,12 +151,16 @@ fn main() { Command::RemoveUnknownLines {} => { deal_with_unknown_lines(&reference_ini, &mut target_ini, true).unwrap(); } + Command::AddNewKey { + ref section, + ref key, + } => add_new_key(&mut target_ini, section, key).unwrap(), Command::MoveKey { ref old, ref new, ref key, } => { - move_key(&mut target_ini, &old, &new, &key).unwrap(); + move_key(&mut target_ini, old, new, key).unwrap(); } Command::RemoveKey { ref section, @@ -155,5 +173,31 @@ fn main() { target_ini.write().unwrap(); } + println!("Langtool processing {}", reference_ini_filename); + + // Some commands also apply to the reference ini. + match opt.cmd { + Command::AddNewKey { + ref section, + ref key, + } => { + add_new_key(&mut reference_ini, section, key).unwrap(); + } + Command::MoveKey { + ref old, + ref new, + ref key, + } => { + move_key(&mut reference_ini, old, new, key).unwrap(); + } + Command::RemoveKey { + ref section, + ref key, + } => { + remove_key(&mut reference_ini, section, key).unwrap(); + } + _ => {} + } + // println!("{:#?}", target_ini); } diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 5294f00280..8bdfcb940e 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -464,6 +464,7 @@ Aggressive = ‎عنيف Alternative Speed = سرعة ثانوية (في %, 0 = ‎غير محدود) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ‎فلتر الحواف +Aspect Ratio = Aspect Ratio Auto = ‎تلقائي Auto (1:1) = ‎تلقائي (1:1) Auto (same as Rendering) = ‎تلقائي (مثل حجم التصيير) diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 9dd11ca652..969a04f2d7 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 86228f37c8..7cc4685339 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Алтернативна скорост Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic филтриране +Aspect Ratio = Aspect Ratio Auto = Автоматично Auto (1:1) = Автоматично (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 8acb5e826e..a983ab7a80 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtrat anisotròpic +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index d289d1282f..6975e025f7 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -456,6 +456,7 @@ Aggressive = Agresivní Alternative Speed = Alternativní rychlost (v %, 0 = neomezeno) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anizotropní filtrování +Aspect Ratio = Aspect Ratio Auto = Automaticky Auto (1:1) = Automatické (1:1) Auto (same as Rendering) = Automaticky (stejné jako rozlišení vykreslování) diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index d0a379a46e..461469846b 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -456,6 +456,7 @@ Aggressive = Aggressiv Alternative Speed = Alternativ hastighed (i %, 0 = ubegrænset) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropisk filtrering +Aspect Ratio = Aspect Ratio Auto = Automatisk Auto (1:1) = Automatisk (1:1) Auto (same as Rendering) = Automatisk (Samme som renderingsopløsning) diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 08dd21ca71..e297baa7b5 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -456,6 +456,7 @@ Aggressive = Aggressiv Alternative Speed = Alternative Geschwindigkeit Alternative Speed 2 = Alternative Geschwindigkeit 2 (in %, 0 = unlimitiert) Anisotropic Filtering = Anisotropischer Filter +Aspect Ratio = Aspect Ratio Auto = Automatisch Auto (1:1) = Automatisch (1:1) Auto (same as Rendering) = Automatisch (Renderauflösung) diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index d992d6fd65..ff3c886a3d 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Lassi to leko'napa Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Panyaring Anisotropic +Aspect Ratio = Aspect Ratio Auto = Ia mesa Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 9d3c2dd5ed..88057e48c2 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -456,6 +456,7 @@ Aggressive = Agresivo Alternative Speed = Velocidad alternativa (%, 0 = ilimitada) Alternative Speed 2 = Velocidad alternativa 2 (%, 0 = ilimitada) Anisotropic Filtering = Filtrado anisotrópico +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Automático (igual a la de renderizado) diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 674b9e3d29..ddd6bbdb1c 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -456,6 +456,7 @@ Aggressive = Agresivo Alternative Speed = Velocidad alternativa (en %, 0 = ilimitada) Alternative Speed 2 = Velocidad alternativa 2 (en %, 0 = ilimitada) Anisotropic Filtering = Filtrado Anisotrópico +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Automático (igual a la de renderizado) diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 8566450a84..054602ab19 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -456,6 +456,7 @@ Aggressive = ‎شدید Alternative Speed = ‎سرعت ثانویه Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ‎Anisotropic فیلتر +Aspect Ratio = Aspect Ratio Auto = ‎اتوماتیک Auto (1:1) = Auto (1:1) Auto (same as Rendering) = ‎خودکار (مانند رزولوشن رندرینگ) diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index e05580d325..4165daf4c7 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Vaihtoehtoinen nopeus Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotrooppisen suodatus +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 3afc81fe12..8fd76658ec 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -456,6 +456,7 @@ Aggressive = Agressif Alternative Speed = Vitesse alternative 1 (en %, 0 = illimitée) Alternative Speed 2 = Vitesse alternative 2 (en %, 0 = illimitée) Anisotropic Filtering = Filtrage anisotrope +Aspect Ratio = Aspect Ratio Auto = Automatique Auto (1:1) = Automatique (1:1) Auto (same as Rendering) = Automatique (comme la définition du rendu) diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 314ba6226d..ede4a3ef4f 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -456,6 +456,7 @@ Aggressive = Agresivo Alternative Speed = Velocidade alternativa (%, 0 = ilimitada) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtrado anisotrópico +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Automático (igual á de renderizado) diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 5be577a15b..a8b7fd0f95 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -456,6 +456,7 @@ Aggressive = Εξαναγκαστική Alternative Speed = Εναλακτική προβολή ταχύτητας (στα %, 0 = απεριόριστη) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Ανισοτροπικό Φιλτράρισμα +Aspect Ratio = Aspect Ratio Auto = Αυτόματο Auto (1:1) = Αυτόματο (1:1) Auto (same as Rendering) = Αυτόματο (ίσο με την Ανάλυση Απεικόνισης) diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 1925962c63..93d2c6431c 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = הגבלת מהירות Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Aspect Ratio = Aspect Ratio Auto = אוטומטי Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 5e5aafc3f9..37757a38df 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = תוריהמ תלבגה Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Aspect Ratio = Aspect Ratio Auto = יטמוטוא Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 763b14669d..8f3b4ba77d 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -456,6 +456,7 @@ Aggressive = Agresivno Alternative Speed = Alternativna brzina (u %, 0 = unlimited) Alternative Speed 2 = Alternativna brzina 2 (u %, 0 = unlimited) Anisotropic Filtering = Anizotropno filtriranje +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (isto kao Prikazna rezolucija) diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 8e27c6db62..5a90a404a9 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -456,6 +456,7 @@ Aggressive = Agresszív Alternative Speed = Alternatív sebesség Alternative Speed 2 = Alternatív sebesség 2 (%-ban, 0 = korlátlan) Anisotropic Filtering = Anizotropikus szűrés +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (renderelési felbontással megegyező) diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index ccbdc9ef5b..565e330e58 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -456,6 +456,7 @@ Aggressive = Agresif Alternative Speed = Kecepatan alternatif (dalam %, 0 = tak terbatas) Alternative Speed 2 = Kecepatan alternatif 2 (dalam %, 0 = tak terbatas) Anisotropic Filtering = Pemfilteran anisotropik +Aspect Ratio = Aspect Ratio Auto = Otomatis Auto (1:1) = Otomatis (1:1) Auto (same as Rendering) = Otomatis (sama dengan resolusi pelukis) diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index aae3f8e8b6..4d6775d5ed 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -456,6 +456,7 @@ Aggressive = Aggressivo Alternative Speed = Velocità Alternativa (in %, 0 = illimitata) Alternative Speed 2 = Velocità Alternativa 2 (in %, 0 = illimitata) Anisotropic Filtering = Filtro Anisotropico +Aspect Ratio = Aspect Ratio Auto = Automatico Auto (1:1) = Automatico (1:1) Auto (same as Rendering) = Automatico (stessa risoluzione del rendering) diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 136faaa009..115eea7545 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -456,6 +456,7 @@ Aggressive = 最大限 Alternative Speed = カスタム速度1 (%で指定、0 = 無制限) Alternative Speed 2 = カスタム速度2 (%で指定、0 = 無制限) Anisotropic Filtering = 異方性フィルタリング +Aspect Ratio = Aspect Ratio Auto = 自動 Auto (1:1) = 自動 (1:1) Auto (same as Rendering) = 自動 (レンダリング解像度と同じ) diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index fcf34e2357..c89ff8fc49 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -456,6 +456,7 @@ Aggressive = Agresif Alternative Speed = Kacepetan Alternatif Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Penyaring Anisotropis +Aspect Ratio = Aspect Ratio Auto = Otomatis Auto (1:1) = Otomatis (1:1) Auto (same as Rendering) = Otomatis (padha Rendering) diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 92fc7bc847..439d97f2e4 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -456,6 +456,7 @@ Aggressive = 과격 Alternative Speed = 대체 속도 (%, 0 = 무제한) Alternative Speed 2 = 대체 속도 2 (%, 0 = 무제한) Anisotropic Filtering = 비등방성 필터링 +Aspect Ratio = Aspect Ratio Auto = 자동 Auto (1:1) = 자동 (1:1) Auto (same as Rendering) = 자동 (렌더링 해상도와 동일) diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 94414b5468..e6706aab2b 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -456,6 +456,7 @@ Aggressive = ຮຸນແຮງ Alternative Speed = ຄວາມໄວເສີມ (ໃນ %, 0 = ບໍ່ຈຳກັດ) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ກຳຈັດຄວາມບໍ່ຄົມຊັດ +Aspect Ratio = Aspect Ratio Auto = ອັດຕະໂນມັດ Auto (1:1) = ອັດຕະໂນມັດ (1:1) Auto (same as Rendering) = ອັດຕະໂນມັດ (ແບບດຽວກັບຄວາມລະອຽດການສະແດງຜົນ) diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index b707b5ebcd..d84ce08ed0 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Alternatyvus greitis (procentais, 0 procentų = neribotas) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = "Anisotropic" filtravimas +Aspect Ratio = Aspect Ratio Auto = Automatinis Auto (1:1) = Automatinė (1:1) Auto (same as Rendering) = Automatinis (kaip Rodymo rezoliucija) diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index b1aa99e543..be200b4ad7 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Kelajuan alternatif Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 492a725a72..da32d41b42 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -456,6 +456,7 @@ Aggressive = Agressief Alternative Speed = Alternatieve snelheid (in %, 0 = onbeperkt) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropische filter +Aspect Ratio = Aspect Ratio Auto = Automatisch Auto (1:1) = Automatisch (1:1) Auto (same as Rendering) = Auto (renderresolutie) diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index fad6df3012..148359afed 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -456,6 +456,7 @@ Aggressive = Aggressive Alternative Speed = Alternativ hastighet Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropisk filtrering +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 07d732d812..6510d8222c 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -456,6 +456,7 @@ Aggressive = Agresywne Alternative Speed = Alternatywna prędkość (w %, 0 = bez limitu) Alternative Speed 2 = Alternatywna prędkość 2 (w %, 0 = bez limitu) Anisotropic Filtering = Filtrowanie anizotropowe +Aspect Ratio = Aspect Ratio Auto = Automatyczne Auto (1:1) = Automatyczna (1:1) Auto (same as Rendering) = Auto (jak roz. renderowania) diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index dcba12a8cc..280e0dc0f2 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -480,6 +480,7 @@ Aggressive = Agressivo Alternative Speed = Velocidade alternativa (em %, 0 = ilimitada) Alternative Speed 2 = Velocidade alternativa 2 (em %, 0 = ilimitada) Anisotropic Filtering = Filtragem anisotrópica +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (a mesma que a da resolução de renderização) diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index b81aeb50f5..b56c82385b 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -480,6 +480,7 @@ Aggressive = Agressivo Alternative Speed = Velocidade alternativa (em %, 0 = ilimitada) Alternative Speed 2 = Segunda Velocidade alternativa (em %, 0 = ilimitada) Anisotropic Filtering = Filtragem anisotrópica +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Auto (a mesma de que a da resolução de renderização) diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 7d933f0dbc..b80373a76a 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -456,6 +456,7 @@ Aggressive = Agresiv Alternative Speed = Viteză alternativă (în %, 0 = nelimitat) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtru Anisotropic +Aspect Ratio = Aspect Ratio Auto = Automat Auto (1:1) = Automat (1:1) Auto (same as Rendering) = Automat (la fel ca rezoluția de afișare) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index eb70f9705f..b52d422a1b 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -456,6 +456,7 @@ Aggressive = Принудительно Alternative Speed = Другая скорость (в %, 0 = без ограничений) Alternative Speed 2 = Другая скорость 2 (в %, 0 = без ограничений) Anisotropic Filtering = Анизотропная фильтрация +Aspect Ratio = Aspect Ratio Auto = Авто Auto (1:1) = Авто (1:1) Auto (same as Rendering) = Авто (как разрешение рендеринга) diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 76cff02363..03ca0d124b 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -456,6 +456,7 @@ Aggressive = Aggressiv Alternative Speed = Alternativ hastighet Alternative Speed 2 = Alternativ hastighet 2 (%, 0 = obegränsad) Anisotropic Filtering = Anisotropisk filtrering +Aspect Ratio = Sidförhållande Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (samma som rendering) diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 5b44d67dd9..bd54f7cb92 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -456,6 +456,7 @@ Aggressive = Agresibo Alternative Speed = Alternatibong bilis Alternative Speed 2 = Alternatibong bilis 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropikong Pagsala +Aspect Ratio = Aspect Ratio Auto = Awto Auto (1:1) = Awto (1:1) Auto (same as Rendering) = Awto (Kapareho sa Renderig Resolution) diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index daf45163b1..2d522a6cdb 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -456,6 +456,7 @@ Aggressive = รุนแรง Alternative Speed = เพิ่ม-ลดระดับความเร็ว (ใน %, 0 = ไม่จำกัด) Alternative Speed 2 = เพิ่ม-ลดระดับความเร็ว 2 (ใน %, 0 = ไม่จำกัด) Anisotropic Filtering = ตัวกรองขจัดความไม่คมชัดของพื้นผิว +Aspect Ratio = Aspect Ratio Auto = อัตโนมัติ Auto (1:1) = อัตโนมัติ (1:1) Auto (same as Rendering) = อัตโนมัติ (ค่าเดียวกับที่ใช้แสดงผลภาพ) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 52618a9865..7b771b4c8d 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -458,6 +458,7 @@ Aggressive = Agresif Alternative Speed = Alternatif Hız (% 0 = sınırsız) Alternative Speed 2 = Alternatif Hız 2 (% 0 = sınırsız) Anisotropic Filtering = Anizotropik filtreleme +Aspect Ratio = Aspect Ratio Auto = Otomatik Auto (1:1) = Otomatik (1:1) Auto (same as Rendering) = Otomatik (İşleme Çözünürlüğüyle Aynı) diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index db4bfd72bb..2b35f5622e 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -456,6 +456,7 @@ Aggressive = Примусово Alternative Speed = Альтернативна шв. (к %, 0 = необмежено) Alternative Speed 2 = Альтернативна шв. 2 (к %, 0 = необмежено) Anisotropic Filtering = Анізотропна фільтрація +Aspect Ratio = Aspect Ratio Auto = Авто Auto (1:1) = Авто (1:1) Auto (same as Rendering) = Авто (таке ж як розширення рендерингу) diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 1bb9d8b1da..d5c697b261 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -456,6 +456,7 @@ Aggressive = Xâm lược Alternative Speed = Tốc độ luân phiên Alternative Speed 2 = Tốc độ luân phiên 2 (trong %, 0 = không giới hạn) Anisotropic Filtering = Lọc không cùng hướng +Aspect Ratio = Aspect Ratio Auto = Tự động Auto (1:1) = Tự động (1:1) Auto (same as Rendering) = Tự động (cùng với kết xuất) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 60ea9dedbb..08780eb749 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -456,6 +456,7 @@ Aggressive = 激进 Alternative Speed = 自定义速度 Alternative Speed 2 = 自定义速度2 Anisotropic Filtering = 各向异性过滤 +Aspect Ratio = Aspect Ratio Auto = 自动 Auto (1:1) = 自动(1:1) Auto (same as Rendering) = 自动(同渲染分辨率) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 6cd9b323cd..6b6400f9c3 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -456,6 +456,7 @@ Aggressive = 積極 Alternative Speed = 替代速度 (於 %,0 = 無限制) Alternative Speed 2 = 替代速度 2 (於 %,0 = 無限制) Anisotropic Filtering = 非等向性過濾 +Aspect Ratio = Aspect Ratio Auto = 自動 Auto (1:1) = 自動 (1:1) Auto (same as Rendering) = 自動 (同於轉譯解析度) From 973eec5b42cfff39c8e2b5242522eabfefc5248b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 19:56:37 +0100 Subject: [PATCH 425/715] Another tweak to the OpenGL adreno bug detection. See #16015 --- Common/GPU/OpenGL/thin3d_gl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index bec5f5b631..ab3c92fa3e 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -10,6 +10,7 @@ #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Math/math_util.h" #include "Common/Math/lin/matrix4x4.h" +#include "Common/System/System.h" #include "Common/Log.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/Shader.h" @@ -647,8 +648,12 @@ OpenGLContext::OpenGLContext() { } if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { - if (gl_extensions.modelNumber < 600) +#if PPSSPP_PLATFORM(ANDROID) + // The bug seems to affect Adreno 3xx and 5xx, and appeared in Android 8.0 Oreo, so API 26. + // See https://github.com/hrydgard/ppsspp/issues/16015#issuecomment-1328316080. + if (gl_extensions.modelNumber < 600 && System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 26) bugs_.Infest(Bugs::ADRENO_RESOURCE_DEADLOCK); +#endif } #if PPSSPP_PLATFORM(IOS) From 7c72fa06ee47257ff7adf99ef551eeb0bb087f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 21:34:51 +0100 Subject: [PATCH 426/715] Fix issue where render resolution wasn't applied correctly. --- UI/GameSettingsScreen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 3cc50182d9..8592d106c4 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1247,6 +1247,7 @@ UI::EventReturn GameSettingsScreen::OnResolutionChange(UI::EventParams &e) { RecreateActivity(); } Reporting::UpdateConfig(); + NativeMessageReceived("gpu_renderResized", ""); return UI::EVENT_DONE; } From 72ec865f7e57db9f940db9908fc12e7140af4387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 21:55:22 +0100 Subject: [PATCH 427/715] Fix for the aspect ratio plugin variable. Disable aspect ratio control in stretch mode. --- Core/HLE/sceIo.cpp | 14 +++++++++++--- UI/DisplayLayoutScreen.cpp | 7 ++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 943ba37721..7425ec2603 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -2046,15 +2046,23 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o return 0; case EMULATOR_DEVCTL__GET_ASPECT_RATIO: if (Memory::IsValidAddress(outPtr)) { - float ar = g_Config.fDisplayAspectRatio * (480.0f / 272.0f); - Memory::Write_U32(*(reinterpret_cast(&ar)), outPtr); + // TODO: Share code with CenterDisplayOutputRect to take a few more things into account. + // I have a planned further refactoring. + float ar; + if (g_Config.bDisplayStretch) { + ar = (float)dp_xres / (float)dp_yres; + } else { + ar = g_Config.fDisplayAspectRatio * (480.0f / 272.0f); + } + Memory::Write_Float(ar, outPtr); } return 0; case EMULATOR_DEVCTL__GET_SCALE: if (Memory::IsValidAddress(outPtr)) { // TODO: Maybe do something more sophisticated taking the longest side and screen rotation // into account, etc. - Memory::Write_U32(static_cast(dp_xres) * g_Config.fDisplayScale / 480.0f, outPtr); + float scale = float(dp_xres) * g_Config.fDisplayScale / 480.0f; + Memory::Write_Float(scale, outPtr); } return 0; case EMULATOR_DEVCTL__GET_LTRIGGER: diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 9e95b76e1c..9b295c3305 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -204,12 +204,13 @@ void DisplayLayoutScreen::CreateViews() { rightScrollView->Add(rightColumn); root_->Add(rightScrollView); - PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); - leftColumn->Add(aspectRatio); - auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); leftColumn->Add(stretch); + PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); + leftColumn->Add(aspectRatio); + aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch); + mode_ = new ChoiceStrip(ORIENT_VERTICAL); mode_->AddChoice(di->T("Move")); mode_->AddChoice(di->T("Resize")); From e02db20a2d3c97d49196da9e21851c8448f71339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 21:59:04 +0100 Subject: [PATCH 428/715] Some more UI fixes. Live update for the aspect slider --- UI/DisplayLayoutScreen.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 9b295c3305..4865a3214b 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -69,16 +69,14 @@ public: switch (mode) { case MODE_MOVE: - { - g_Config.fDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX / screenBounds.w; - g_Config.fDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY / screenBounds.h; + g_Config.fDisplayOffsetX = clamp_value(startDisplayOffsetX_ + relativeTouchX / screenBounds.w, 0.0f, 1.0f); + g_Config.fDisplayOffsetY = clamp_value(startDisplayOffsetY_ + relativeTouchY / screenBounds.h, 0.0f, 1.0f); break; - } case MODE_RESIZE: { // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction float diffYProp = -relativeTouchY * 0.007f; - g_Config.fDisplayScale = startScale_ * powf(2.0f, diffYProp); + g_Config.fDisplayScale = clamp_value(startScale_ * powf(2.0f, diffYProp), 0.2f, 2.0f); break; } } @@ -210,6 +208,8 @@ void DisplayLayoutScreen::CreateViews() { PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); leftColumn->Add(aspectRatio); aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch); + aspectRatio->SetHasDropShadow(false); + aspectRatio->SetLiveUpdate(true); mode_ = new ChoiceStrip(ORIENT_VERTICAL); mode_->AddChoice(di->T("Move")); From 200e2f26c43eed93c88b4e47dce0d0d43fba74dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 22:58:34 +0100 Subject: [PATCH 429/715] OffsetY fix for non-vulkan backends --- GPU/Common/PresentationCommon.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 40c13beaae..0c783b4050 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -79,9 +79,8 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f float offsetX = g_Config.fDisplayOffsetX; float offsetY = g_Config.fDisplayOffsetY; - // Have to invert Y for GL - if (GetGPUBackend() == GPUBackend::OPENGL) { - offsetY = offsetY * -1.0f; + if (GetGPUBackend() != GPUBackend::VULKAN) { + offsetY = 1.0 - offsetY; } float scale = g_Config.fDisplayScale; From 72029b678a36ac59a8b029cccfef267588627db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 23:16:16 +0100 Subject: [PATCH 430/715] Empirical attempt at fixing #15661 Basically, software culling fails in some configuration, like the one we end up with on Mali. As noted by unknownbrackets in #15661, the viewport Z scale, offset is -0.0, 0.0. We end up with CalcCullParams computing minZValue == maxZValue == 1.0f, and with the vertices ending up with z,w == 1.0, 1.0. and as a result, the inside/outside calculations will always decide that it's outside. Changing the comparisons from >= / <= to > / < fixes the problem, but I don't know if this might break something else. Anyhow, here's the simple way to repro on PC: Change the ending of GPU_Vulkan::CheckFeatures to: ```c return GPU_USE_LIGHT_UBERSHADER | GPU_USE_BLEND_MINMAX | GPU_USE_TEXTURE_NPOT | GPU_USE_INSTANCE_RENDERING | GPU_USE_VERTEX_TEXTURE_FETCH | GPU_USE_TEXTURE_FLOAT | GPU_USE_16BIT_FORMATS | GPU_USE_TEXTURE_LOD_CONTROL | GPU_USE_DEPTH_TEXTURE | GPU_USE_ACCURATE_DEPTH; ``` --- GPU/Common/SoftwareTransformCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 67ba97af4c..8a3cbb50dd 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -600,9 +600,9 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy // First, check inside/outside directions for each index. for (int i = 0; i < vertexCount; ++i) { float z = transformed[indsIn[i]].z / transformed[indsIn[i]].pos_w; - if (z >= maxZValue) + if (z > maxZValue) outsideZ[i] = 1; - else if (z <= minZValue) + else if (z < minZValue) outsideZ[i] = -1; else outsideZ[i] = 0; From 21647cd3c1505258a016dfa9f420ee4a1f8b5dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Nov 2022 23:32:43 +0100 Subject: [PATCH 431/715] Blind workaround for Shining Ark circle button problem Seems the game might not handle the case of confirm button being set to cross properly, so force it to circle if this game is running. Fixes #15663 (hopefully..) --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + Core/Dialog/PSPDialog.cpp | 16 ++++++++++++++++ Core/Dialog/PSPDialog.h | 3 +++ Core/Dialog/PSPNetconfDialog.cpp | 4 ++-- Core/Dialog/PSPOskDialog.cpp | 7 ++++--- Core/HLE/sceImpose.cpp | 2 +- Core/HLE/sceUtility.cpp | 2 +- assets/compat.ini | 5 +++++ 9 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 6541cc53b3..8db5e81112 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -121,6 +121,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "SecondaryTextureCache", &flags_.SecondaryTextureCache); CheckSetting(iniFile, gameID, "EnglishOrJapaneseOnly", &flags_.EnglishOrJapaneseOnly); CheckSetting(iniFile, gameID, "OldAdrenoPixelDepthRoundingGL", &flags_.OldAdrenoPixelDepthRoundingGL); + CheckSetting(iniFile, gameID, "ForceCircleButtonConfirm", &flags_.ForceCircleButtonConfirm); } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index aee9f2c41b..aeb6b6996c 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -92,6 +92,7 @@ struct CompatFlags { bool SecondaryTextureCache; bool EnglishOrJapaneseOnly; bool OldAdrenoPixelDepthRoundingGL; + bool ForceCircleButtonConfirm; }; struct VRCompat { diff --git a/Core/Dialog/PSPDialog.cpp b/Core/Dialog/PSPDialog.cpp index 3670d15ac8..a4e6f77abe 100644 --- a/Core/Dialog/PSPDialog.cpp +++ b/Core/Dialog/PSPDialog.cpp @@ -20,6 +20,8 @@ #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/StringUtils.h" +#include "Core/Config.h" +#include "Core/System.h" #include "Core/CoreTiming.h" #include "Core/Dialog/PSPDialog.h" #include "Core/HLE/sceCtrl.h" @@ -305,3 +307,17 @@ void PSPDialog::DisplayButtons(int flags, const char *caption) PPGeDrawText(text, x1 + 14.5f, 252, textStyle); } } + +int PSPDialog::GetConfirmButton() { + if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) { + return CTRL_CIRCLE; + } + return g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS; +} + +int PSPDialog::GetCancelButton() { + if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) { + return CTRL_CIRCLE; + } + return g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; +} diff --git a/Core/Dialog/PSPDialog.h b/Core/Dialog/PSPDialog.h index 673bd54f9b..0489a0d2b8 100644 --- a/Core/Dialog/PSPDialog.h +++ b/Core/Dialog/PSPDialog.h @@ -106,6 +106,9 @@ protected: // TODO: Remove this once all dialogs are updated. virtual bool UseAutoStatus() = 0; + static int GetConfirmButton(); + static int GetCancelButton(); + void StartFade(bool fadeIn_); void UpdateFade(int animSpeed); virtual void FinishFadeOut(); diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index 079ff28358..3ea056e8d2 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -261,9 +261,9 @@ int PSPNetconfDialog::Update(int animSpeed) { if (!hideNotice) { const float WRAP_WIDTH = 254.0f; const ImageID confirmBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CROSS") : ImageID("I_CIRCLE"); - const int confirmBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; + const int confirmBtn = GetConfirmButton(); const ImageID cancelBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CIRCLE") : ImageID("I_CROSS"); - const int cancelBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS; + const int cancelBtn = GetCancelButton(); PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_CENTER, 0.5f); PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f); diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 8eb37918ce..36574f3522 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -941,8 +941,9 @@ int PSPOskDialog::Update(int animSpeed) { return SCE_ERROR_UTILITY_INVALID_STATUS; } - int cancelButton = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS; - int confirmButton = cancelButton == CTRL_CROSS ? CTRL_CIRCLE : CTRL_CROSS; + int cancelButton = GetCancelButton(); + int confirmButton = GetConfirmButton(); + static int cancelBtnFramesHeld = 0; static int confirmBtnFramesHeld = 0; static int leftBtnFramesHeld = 0; @@ -979,7 +980,7 @@ int PSPOskDialog::Update(int animSpeed) { PPGeDrawImage(ImageID("I_SQUARE"), 365, 222, 16, 16, guideStyle); PPGeDrawText(di->T("Space"), 390, 222, actionStyle); - if (g_Config.iButtonPreference != PSP_SYSTEMPARAM_BUTTON_CIRCLE) { + if (GetConfirmButton() != PSP_SYSTEMPARAM_BUTTON_CIRCLE) { PPGeDrawImage(ImageID("I_CROSS"), 45, 222, 16, 16, guideStyle); PPGeDrawImage(ImageID("I_CIRCLE"), 45, 247, 16, 16, guideStyle); } else { diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index bd5f654bc2..6bebff1fde 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -46,7 +46,7 @@ void __ImposeInit() language = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; } } - buttonValue = g_Config.iButtonPreference; + buttonValue = PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm ? PSP_SYSTEMPARAM_BUTTON_CIRCLE : g_Config.iButtonPreference; umdPopup = PSP_UMD_POPUP_DISABLE; backlightOffTime = 0; } diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 35db8740fa..64896ed0fe 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -893,7 +893,7 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) } break; case PSP_SYSTEMPARAM_ID_INT_BUTTON_PREFERENCE: - param = g_Config.iButtonPreference; + param = PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm ? PSP_SYSTEMPARAM_BUTTON_CIRCLE : g_Config.iButtonPreference; break; case PSP_SYSTEMPARAM_ID_INT_LOCK_PARENTAL_LEVEL: param = g_Config.iLockParentalLevel; diff --git a/assets/compat.ini b/assets/compat.ini index 85e7e9c693..feaa62da0e 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1348,3 +1348,8 @@ UCAS40306 = true UCJS10112 = true NPJG00116 = true NPUG70097 = true # Demo + +[ForceCircleButtonConfirm] +# Shining Ark, issue #15663 +NPJH50717 = true +ULJM06223 = true From 89aeb2484e8f5dcce8e4b2f981b55ab04ab035b5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 15:32:56 -0800 Subject: [PATCH 432/715] UI: Fix right analog with single button. Release first, then press so that we press when the opposing direction is mapped to the same button. --- UI/GamepadEmu.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index bb1eb01f3b..21752a3984 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -588,7 +588,10 @@ void PSPCustomStick::Touch(const TouchInput &input) { } void PSPCustomStick::ProcessTouch(float x, float y, bool down) { - static const int button[16] = {CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT}; + static const int buttons[16] = {0, CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT}; + + u32 press = 0; + u32 release = 0; if (down && centerX_ >= 0.0f) { float inv_stick_size = 1.0f / (stick_size_ * scale_); @@ -601,49 +604,54 @@ void PSPCustomStick::ProcessTouch(float x, float y, bool down) { if (g_Config.iRightAnalogRight != 0) { if (dx > 0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) > fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogRight-1]); + press |= buttons[g_Config.iRightAnalogRight]; else - __CtrlButtonUp(button[g_Config.iRightAnalogRight-1]); + release |= buttons[g_Config.iRightAnalogRight]; } if (g_Config.iRightAnalogLeft != 0) { if (dx < -0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) > fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogLeft-1]); + press |= buttons[g_Config.iRightAnalogLeft]; else - __CtrlButtonUp(button[g_Config.iRightAnalogLeft-1]); + release |= buttons[g_Config.iRightAnalogLeft]; } if (g_Config.iRightAnalogUp != 0) { if (dy < -0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) <= fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogUp-1]); + press |= buttons[g_Config.iRightAnalogUp]; else - __CtrlButtonUp(button[g_Config.iRightAnalogUp-1]); + release |= buttons[g_Config.iRightAnalogUp]; } if (g_Config.iRightAnalogDown != 0) { if (dy > 0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) <= fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogDown-1]); + press |= buttons[g_Config.iRightAnalogDown]; else - __CtrlButtonUp(button[g_Config.iRightAnalogDown-1]); + release |= buttons[g_Config.iRightAnalogDown]; } if (g_Config.iRightAnalogPress != 0) - __CtrlButtonDown(button[g_Config.iRightAnalogPress-1]); + press |= buttons[g_Config.iRightAnalogPress]; posX_ = dx; posY_ = dy; } else { if (g_Config.iRightAnalogUp != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogUp-1]); + release |= buttons[g_Config.iRightAnalogUp]; if (g_Config.iRightAnalogDown != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogDown-1]); + release |= buttons[g_Config.iRightAnalogDown]; if (g_Config.iRightAnalogLeft != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogLeft-1]); + release |= buttons[g_Config.iRightAnalogLeft]; if (g_Config.iRightAnalogRight != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogRight-1]); + release |= buttons[g_Config.iRightAnalogRight]; if (g_Config.iRightAnalogPress != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogPress-1]); + release |= buttons[g_Config.iRightAnalogPress]; posX_ = 0.0f; posY_ = 0.0f; } + + if (release != 0) + __CtrlButtonUp(release); + if (press != 0) + __CtrlButtonDown(press); } void InitPadLayout(float xres, float yres, float globalScale) { From 247848891e760da0a720ddfd2da553a2c40dae1a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 15:40:55 -0800 Subject: [PATCH 433/715] UI: Dry out code and check bounds to be safe. --- UI/GamepadEmu.cpp | 58 +++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index 21752a3984..c91ebc43be 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -588,11 +588,21 @@ void PSPCustomStick::Touch(const TouchInput &input) { } void PSPCustomStick::ProcessTouch(float x, float y, bool down) { - static const int buttons[16] = {0, CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT}; + static const int buttons[] = {0, CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT}; u32 press = 0; u32 release = 0; + auto toggle = [&](int config, bool simpleCheck, bool diagCheck = true) { + if (config <= 0 || (size_t)config >= ARRAY_SIZE(buttons)) + return; + + if (simpleCheck && (!g_Config.bRightAnalogDisableDiagonal || diagCheck)) + press |= buttons[config]; + else + release |= buttons[config]; + }; + if (down && centerX_ >= 0.0f) { float inv_stick_size = 1.0f / (stick_size_ * scale_); @@ -602,47 +612,21 @@ void PSPCustomStick::ProcessTouch(float x, float y, bool down) { dx = std::min(1.0f, std::max(-1.0f, dx)); dy = std::min(1.0f, std::max(-1.0f, dy)); - if (g_Config.iRightAnalogRight != 0) { - if (dx > 0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) > fabs(dy))) - press |= buttons[g_Config.iRightAnalogRight]; - else - release |= buttons[g_Config.iRightAnalogRight]; - } - if (g_Config.iRightAnalogLeft != 0) { - if (dx < -0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) > fabs(dy))) - press |= buttons[g_Config.iRightAnalogLeft]; - else - release |= buttons[g_Config.iRightAnalogLeft]; - } - if (g_Config.iRightAnalogUp != 0) { - if (dy < -0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) <= fabs(dy))) - press |= buttons[g_Config.iRightAnalogUp]; - else - release |= buttons[g_Config.iRightAnalogUp]; - } - if (g_Config.iRightAnalogDown != 0) { - if (dy > 0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) <= fabs(dy))) - press |= buttons[g_Config.iRightAnalogDown]; - else - release |= buttons[g_Config.iRightAnalogDown]; - } - if (g_Config.iRightAnalogPress != 0) - press |= buttons[g_Config.iRightAnalogPress]; + toggle(g_Config.iRightAnalogRight, dx > 0.5f, fabs(dx) > fabs(dy)); + toggle(g_Config.iRightAnalogLeft, dx < -0.5f, fabs(dx) > fabs(dy)); + toggle(g_Config.iRightAnalogUp, dy < -0.5f, fabs(dx) <= fabs(dy)); + toggle(g_Config.iRightAnalogDown, dy > 0.5f, fabs(dx) <= fabs(dy)); + toggle(g_Config.iRightAnalogPress, true); posX_ = dx; posY_ = dy; } else { - if (g_Config.iRightAnalogUp != 0) - release |= buttons[g_Config.iRightAnalogUp]; - if (g_Config.iRightAnalogDown != 0) - release |= buttons[g_Config.iRightAnalogDown]; - if (g_Config.iRightAnalogLeft != 0) - release |= buttons[g_Config.iRightAnalogLeft]; - if (g_Config.iRightAnalogRight != 0) - release |= buttons[g_Config.iRightAnalogRight]; - if (g_Config.iRightAnalogPress != 0) - release |= buttons[g_Config.iRightAnalogPress]; + toggle(g_Config.iRightAnalogRight, false); + toggle(g_Config.iRightAnalogLeft, false); + toggle(g_Config.iRightAnalogUp, false); + toggle(g_Config.iRightAnalogDown, false); + toggle(g_Config.iRightAnalogPress, false); posX_ = 0.0f; posY_ = 0.0f; From 5666dc5890df295446a251b1b3abe4e7d1d88df9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 19:17:01 -0800 Subject: [PATCH 434/715] Vulkan: Correct maxAniso handling in Draw. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index e26ed4146a..46be4cf00b 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -683,6 +683,7 @@ public: s.addressModeV = AddressModeToVulkan(desc.wrapV); s.addressModeW = AddressModeToVulkan(desc.wrapW); s.anisotropyEnable = desc.maxAniso > 1.0f; + s.maxAnisotropy = desc.maxAniso; s.magFilter = desc.magFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; s.minFilter = desc.minFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; s.mipmapMode = desc.mipFilter == TextureFilter::LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; From c6992d45ef8cdb1eaf0cd39ea75c8aaba805208d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 19:19:45 -0800 Subject: [PATCH 435/715] UI: Add a slight glow around PSP in control map. This makes it more distinguishable from some dark backgrounds. --- UI/ControlMappingScreen.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 1d54f582ef..9ca3bb5f74 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -881,15 +881,25 @@ public: } void Draw(UIContext &dc) override { + for (float dy = 0.0f; dy <= 4.0f; dy += 1.0f) { + for (float dx = 0.0f; dx <= 4.0f; dx += 1.0f) { + if (dx == 2.0f && dy == 2.0f) + continue; + DrawPSP(dc, dx, dy, 0x06C1B6B6); + } + } + DrawPSP(dc, 2.0f, 2.0f, 0xC01C1818); + } + + void DrawPSP(UIContext &dc, float xoff, float yoff, uint32_t color) { using namespace UI; const AtlasImage *whiteImage = dc.Draw()->GetAtlas()->getImage(dc.theme->whiteImage); float centerU = (whiteImage->u1 + whiteImage->u2) * 0.5f; float centerV = (whiteImage->v1 + whiteImage->v2) * 0.5f; - const uint32_t color = 0xB01C1818; auto V = [&](float x, float y) { - dc.Draw()->V(bounds_.x + x * scale_, bounds_.y + y * scale_, color, centerU, centerV); + dc.Draw()->V(bounds_.x + (x + xoff) * scale_, bounds_.y + (y + yoff) * scale_, color, centerU, centerV); }; auto R = [&](float x1, float y1, float x2, float y2) { V(x1, y1); V(x2, y1); V(x2, y2); @@ -932,8 +942,8 @@ public: } void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { - w = 474.0f * scale_; - h = 200.0f * scale_; + w = 478.0f * scale_; + h = 204.0f * scale_; } protected: From a6bc9acf168d25198581431402dc16b579cf10eb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 19:59:57 -0800 Subject: [PATCH 436/715] GE Debugger: Correct LastVRAM mirror wrap around. Oops, this fixes crashes when textures are used near the edge of VRAM. --- GPU/Debugger/Record.cpp | 43 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 97ed107470..e5fa0b7d1d 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -331,6 +331,39 @@ static Command EmitCommandWithRAM(CommandType t, const void *p, u32 sz, u32 alig return cmd; } +static void UpdateLastVRAM(u32 addr, u32 bytes) { + u32 base = addr & 0x001FFFFF; + if (base + bytes > 0x00200000) { + memcpy(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), 0x00200000 - base); + bytes = base + bytes - 0x00200000; + base = 0; + } + memcpy(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), bytes); +} + +static void ClearLastVRAM(u32 addr, u8 c, u32 bytes) { + u32 base = addr & 0x001FFFFF; + if (base + bytes > 0x00200000) { + memset(&lastVRAM[base], c, 0x00200000 - base); + bytes = base + bytes - 0x00200000; + base = 0; + } + memset(&lastVRAM[base], c, bytes); +} + +static int CompareLastVRAM(u32 addr, u32 bytes) { + u32 base = addr & 0x001FFFFF; + if (base + bytes > 0x00200000) { + int result = memcmp(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), 0x00200000 - base); + if (result != 0) + return result; + + bytes = base + bytes - 0x00200000; + base = 0; + } + return memcmp(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), bytes); +} + static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) { addr &= 0x041FFFFF; const bool isTarget = lastRenderTargets.find(addr) != lastRenderTargets.end(); @@ -358,7 +391,7 @@ static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) { if (isUnknownVRAM && isDirtyVRAM) { // This means it's only UNKNOWN/CLEAN and not known to be actually dirty. // Let's check our shadow copy of what we last sent for this VRAM. - int diff = memcmp(&lastVRAM[addr & 0x001FFFFF], Memory::GetPointerUnchecked(addr), sizeInRAM); + int diff = CompareLastVRAM(addr, sizeInRAM); if (diff == 0) isDirtyVRAM = false; } @@ -404,7 +437,7 @@ static void EmitTextureData(int level, u32 texaddr) { p = &framebufData[0]; if ((flags & 2) == 0) - memcpy(&lastVRAM[texaddr & 0x001FFFFF], Memory::GetPointerUnchecked(texaddr), bytes); + UpdateLastVRAM(texaddr, bytes); // Okay, now we'll just emit this instead. type = CommandType((int)CommandType::FRAMEBUF0 + level); @@ -534,7 +567,7 @@ static void EmitClut(u32 op) { commands.push_back(cmd); if ((flags & 2) == 0) - memcpy(&lastVRAM[addr & 0x001FFFFF], Memory::GetPointerUnchecked(addr), bytes); + UpdateLastVRAM(addr, bytes); } EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes, 16); } @@ -684,7 +717,7 @@ void NotifyMemcpy(u32 dest, u32 src, u32 sz) { sz = Memory::ValidSize(dest, sz); if (sz != 0) { EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointerUnchecked(dest), sz, 1); - memcpy(&lastVRAM[dest & 0x001FFFFF], Memory::GetPointerUnchecked(dest), sz); + UpdateLastVRAM(dest, sz); DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN); } } @@ -711,7 +744,7 @@ void NotifyMemset(u32 dest, int v, u32 sz) { pushbuf.resize(pushbuf.size() + sizeof(data)); memcpy(pushbuf.data() + cmd.ptr, &data, sizeof(data)); commands.push_back(cmd); - memset(&lastVRAM[dest & 0x001FFFFF], v, sz); + ClearLastVRAM(dest, v, sz); DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN); } } From 02e32629bc8e745d01df9693b66354b576e634a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Mon, 28 Nov 2022 13:05:59 +0800 Subject: [PATCH 437/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 6b6400f9c3..66c900168d 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -137,7 +137,7 @@ Direct3D9 = Direct3D 9 (&9) Direct3D11 = Direct3D 11 (&11) Disassembly = 反組譯碼 (&D)… Discord = Discord -Display Layout && Effects = 顯示版面配置編輯器… +Display Layout && Effects = 顯示版面配置與效果… Display Rotation = 顯示旋轉 Dump Next Frame to Log = 傾印下一影格至記錄 (&U) Emulation = 模擬 (&E) @@ -456,7 +456,7 @@ Aggressive = 積極 Alternative Speed = 替代速度 (於 %,0 = 無限制) Alternative Speed 2 = 替代速度 2 (於 %,0 = 無限制) Anisotropic Filtering = 非等向性過濾 -Aspect Ratio = Aspect Ratio +Aspect Ratio = 長寬比 Auto = 自動 Auto (1:1) = 自動 (1:1) Auto (same as Rendering) = 自動 (同於轉譯解析度) @@ -485,7 +485,7 @@ Device = 裝置 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display Layout && Effects = 顯示版面配置編輯器 +Display Layout && Effects = 顯示版面配置與效果 Display Resolution (HW scaler) = 顯示解析度 (硬體縮放) Enable Cardboard VR = 啟用 Cardboard VR FPS = FPS From 194c4b0286956e9da1e1d997fb2e6e6c96bdb460 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 21:15:15 -0800 Subject: [PATCH 438/715] TexCache: Support offset in rendered CLUTs. We already copy to a temp, so just use that copy to normalize out the offset. Should even get RECT2LIN correct, but most cases are 1 pixel high anyway. --- GPU/Common/TextureCacheCommon.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 86134f14c6..fda7533fdf 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1250,6 +1250,10 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { VirtualFramebuffer *chosenFramebuffer = nullptr; for (VirtualFramebuffer *framebuffer : framebuffers) { + // Let's not deal with divide by zero. + if (framebuffer->fb_stride == 0) + continue; + const u32 fb_address = framebuffer->fb_address; const u32 fb_bpp = BufferFormatBytesPerPixel(framebuffer->fb_format); int offset = clutLoadAddr - fb_address; @@ -1302,12 +1306,18 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { dynamicClutTemp_ = draw_->CreateFramebuffer(desc); } + // We'll need to copy from the offset. + const u32 fb_bpp = BufferFormatBytesPerPixel(chosenFramebuffer->fb_format); + const int totalPixelsOffset = clutRenderOffset_ / fb_bpp; + const int clutYOffset = totalPixelsOffset / chosenFramebuffer->fb_stride; + const int clutXOffset = totalPixelsOffset % chosenFramebuffer->fb_stride; + const int scale = chosenFramebuffer->renderScaleFactor; + // Copy the pixels to our temp clut, scaling down if needed and wrapping. - // TODO: Take the clutRenderOffset_ into account here. framebufferManager_->BlitUsingRaster( - chosenFramebuffer->fbo, 0.0f, 0.0f, 512.0f * chosenFramebuffer->renderScaleFactor, 1.0f, + chosenFramebuffer->fbo, clutXOffset * scale, clutYOffset * scale, (clutXOffset + 512.0f) * scale, (clutYOffset + 1.0f) * scale, dynamicClutTemp_, 0.0f, 0.0f, 512.0f, 1.0f, - false, chosenFramebuffer->renderScaleFactor, framebufferManager_->Get2DPipeline(DRAW2D_COPY_COLOR_RECT2LIN), "copy_clut_to_temp"); + false, scale, framebufferManager_->Get2DPipeline(DRAW2D_COPY_COLOR_RECT2LIN), "copy_clut_to_temp"); framebufferManager_->RebindFramebuffer("after_copy_clut_to_temp"); clutRenderFormat_ = chosenFramebuffer->fb_format; From a7c4258e9f6c889fa7bdcaf9581aa6a381bf76d8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 21:16:24 -0800 Subject: [PATCH 439/715] GPU: Support framebuf depal from rendered CLUT. Using a temporary always for simplicity. --- GPU/Common/TextureCacheCommon.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index fda7533fdf..6234740d50 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -570,9 +570,6 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { nextTexture_ = nullptr; nextNeedsRebuild_ = false; - if (hasClutGPU) { - WARN_LOG_ONCE(clut_fb, G3D, "Render-to-CLUT combined with framebuffer texture at %08x - Not yet supported", texaddr); - } SetTextureFramebuffer(bestCandidate); // sets curTexture3D return nullptr; } @@ -2123,7 +2120,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // Shader depal is not supported during 3D texturing or depth texturing, and requires 32-bit integer instructions in the shader. bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && - !depth && + !depth && clutRenderAddress_ == 0xFFFFFFFF && !gstate_c.curTextureIs3D && draw_->GetShaderLanguageDesc().bitwiseOps; @@ -2142,8 +2139,20 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer u32 depthUpperBits = 0; if (need_depalettize) { - clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_); - smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->fb_format, clutTexture.rampLength); + if (clutRenderAddress_ == 0xFFFFFFFF) { + clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_); + smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->fb_format, clutTexture.rampLength); + } else { + // The CLUT texture is dynamic, it's the framebuffer pointed to by clutRenderAddress. + // Instead of texturing directly from that, we copy to a temporary CLUT texture. + GEBufferFormat expectedCLUTBufferFormat = (GEBufferFormat)clutFormat; + + // OK, figure out what format we want our framebuffer in, so it can be reinterpreted if needed. + // If no reinterpretation is needed, we'll automatically just get a copy shader. + float scaleFactorX = 1.0f; + Draw2DPipeline *reinterpret = framebufferManager_->GetReinterpretPipeline(clutRenderFormat_, expectedCLUTBufferFormat, &scaleFactorX); + framebufferManager_->BlitUsingRaster(dynamicClutTemp_, 0.0f, 0.0f, 512.0f, 1.0f, dynamicClutFbo_, 0.0f, 0.0f, scaleFactorX * 512.0f, 1.0f, false, 1.0f, reinterpret, "reinterpret_clut"); + } if (useShaderDepal) { // Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture. @@ -2188,9 +2197,6 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer } if (textureShader) { - const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); - ClutTexture clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_); - bool needsDepthXSwizzle = depthUpperBits == 2; int depalWidth = framebuffer->renderWidth; @@ -2226,7 +2232,11 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer draw_->SetViewports(1, &vp); draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); - draw_->BindTexture(1, clutTexture.texture); + if (clutRenderAddress_ == 0xFFFFFFFF) { + draw_->BindTexture(1, clutTexture.texture); + } else { + draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT, 0); + } Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false); Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(smoothedDepal); draw_->BindSamplerStates(0, 1, &nearest); From 9425d0670a9280110972ee17a010ee704f2ba98a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 27 Nov 2022 21:24:02 -0800 Subject: [PATCH 440/715] GPU: Prevent decimating CLUT framebuffers. Fixes color changing after a few moments in Kurohyo. --- GPU/Common/TextureCacheCommon.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 6234740d50..a6c1582606 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1274,6 +1274,8 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { if (matchRange && !inMargin && offset < (int)clutRenderOffset_) { WARN_LOG_N_TIMES(clutfb, 5, G3D, "Detected LoadCLUT(%d bytes) from framebuffer %08x (%s), byte offset %d", loadBytes, fb_address, GeBufferFormatToString(framebuffer->fb_format), offset); framebuffer->last_frame_clut = gpuStats.numFlips; + // Also mark used so it's not decimated. + framebuffer->last_frame_used = gpuStats.numFlips; framebuffer->usageFlags |= FB_USAGE_CLUT; bestClutAddress = framebuffer->fb_address; clutRenderOffset_ = (u32)offset; From 5b3a993db7010c0786ef82bc0700bb449aa6c905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 09:50:23 +0100 Subject: [PATCH 441/715] Typo fix --- Core/Dialog/PSPDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Dialog/PSPDialog.cpp b/Core/Dialog/PSPDialog.cpp index a4e6f77abe..ffdfcb6f31 100644 --- a/Core/Dialog/PSPDialog.cpp +++ b/Core/Dialog/PSPDialog.cpp @@ -317,7 +317,7 @@ int PSPDialog::GetConfirmButton() { int PSPDialog::GetCancelButton() { if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) { - return CTRL_CIRCLE; + return CTRL_CROSS; } return g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; } From 3e9931a446a8a80c7aad01a4f54f3e718301c29a Mon Sep 17 00:00:00 2001 From: Narugakuruga <31060534+Narugakuruga@users.noreply.github.com> Date: Mon, 28 Nov 2022 17:25:55 +0800 Subject: [PATCH 442/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 08780eb749..f65dd00cea 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1,5 +1,5 @@ [Audio] -Alternate speed volume = 自定义速度下的音量 +Alternate speed volume = 自定义速度时的音量 Audio backend = 音频引擎(需要重启) Audio Error = 音频错误 AudioBufferingForBluetooth = 蓝牙友好缓冲区(更慢) @@ -40,7 +40,7 @@ Calibrated = 校准后 Calibration = 校准 Circular stick input = 环形摇杆输入 Classic = 传统 -Confine Mouse = 在窗口/显示区域内捕获鼠标 +Confine Mouse = 鼠标固定在窗口/显示区域内 Control Mapping = 按键映射 Custom Key Setting = 自定义键位设置 Customize = 自定义 @@ -64,7 +64,7 @@ Ignore Windows Key = 忽略Windows键 Invert Axes = 轴反转 Invert Tilt along X axis = 沿X轴倾斜反转 Invert Tilt along Y axis = 沿Y轴倾斜反转 -Keep this button pressed when right analog is pressed = 按下右摇杆时保持按下此按钮 +Keep this button pressed when right analog is pressed = 按下右摇杆时长按此按键 Keyboard = 键盘控制设定 L/R Trigger Buttons = L/R扳机按钮 Landscape = 横向 @@ -82,7 +82,7 @@ Portrait = 纵向 Portrait Reversed = 纵向反转 PSP Action Buttons = PSP功能键 Raw input = 原始输入 -Repeat mode = 重复模式 +Repeat mode = 连点模式 Reset to defaults = 重置为默认 Screen aligned to ground = 屏幕水平地面 Screen at right angle to ground = 屏幕垂直地面 @@ -90,8 +90,8 @@ Screen Rotation = 屏幕旋转 seconds, 0 : off = 秒, 0 = 不隐藏 Sensitivity (scale) = 灵敏度(倍率) Sensitivity = 灵敏度 -Shape = 形状 -Show Touch Pause Menu Button = 显示暂停菜单按键 +Shape = 外形 +Show Touch Pause Menu Button = 显示暂停按键 Swipe = 滑动 Swipe sensitivity = 滑动灵敏度 Swipe smoothing = 滑动平滑度 @@ -101,12 +101,12 @@ Tilt Input Type = 重力感应替代按键类型 Tilt Sensitivity along X axis = 沿X轴倾斜灵敏度 Tilt Sensitivity along Y axis = 沿Y轴倾斜灵敏度 To Calibrate = 如需校准, 请保证设备在一个平面上,然后按"校准" -Toggle mode = 切换模式 -Touch Control Visibility = 触摸按键可见性 +Toggle mode = 开关模式(只需按一次) +Touch Control Visibility = 可见的触屏按键 Use custom right analog = 自定义右摇杆用途 Use Mouse Control = 使用鼠标控制 -Visibility = 可见性设定 -Visible = 可见性 +Visibility = 按键显示 +Visible = 是否显示 X = X Y = Y @@ -137,7 +137,7 @@ Direct3D9 = Direct3D 9 (&9) Direct3D11 = Direct3D11 (&11) Disassembly = 反汇编 (&D)... Discord = Discord -Display Layout && Effects = 显示布局编辑器... +Display Layout && Effects = 屏幕布局/滤镜编辑... Display Rotation = 显示旋转 Dump Next Frame to Log = 转储下一帧到日志 (&U) Emulation = 模拟 (&E) @@ -172,7 +172,7 @@ Log Console = 控制台日志 (&L) Memory View... = 查看内存 (&V)... More Settings... = 更多设置 (&M)... Nearest = 邻近取样 (&N) -Skip Buffer Effects = 跳过缓冲效果(非缓冲, 更快) (&S) +Skip Buffer Effects = 跳过缓冲效果(不缓冲, 更快) (&S) Off = 关闭 (&O) Open Chat = 打开聊天 Open Directory... = 打开路径(&D)... @@ -456,7 +456,7 @@ Aggressive = 激进 Alternative Speed = 自定义速度 Alternative Speed 2 = 自定义速度2 Anisotropic Filtering = 各向异性过滤 -Aspect Ratio = Aspect Ratio +Aspect Ratio = 宽高比 Auto = 自动 Auto (1:1) = 自动(1:1) Auto (same as Rendering) = 自动(同渲染分辨率) @@ -467,7 +467,7 @@ Backend = 渲染引擎 Balanced = 均衡 Bicubic = 双三次 Both = 全部显示 -Buffer graphics commands (faster, input lag) = 缓冲图形命令(更快, 有输入延迟) +Buffer graphics commands (faster, input lag) = 缓冲图形命令(更快, 增加输入延迟) BufferedRenderingRequired = 警告:此游戏需要将"渲染模式"设置为"缓冲渲染"。 Camera = 摄像头 Camera Device = 摄像头设备 @@ -485,7 +485,7 @@ Device = 设备 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 禁用 -Display Layout && Effects = 显示布局编辑器 +Display Layout && Effects = 屏幕布局/滤镜编辑 Display Resolution (HW scaler) = 显示分辨率(硬件缩放) Enable Cardboard VR = 启用Cardboard VR FPS = 每秒帧数 (FPS) @@ -494,7 +494,7 @@ Frame Skipping = 跳帧 Frame Skipping Type = 跳帧方式 FullScreen = 全屏幕 GPU log profiler = GPU日志分析器 -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +GPUReadbackRequired = 警告: 此游戏需要"跳过GPU回读"设置为关闭 Hack Settings = 渲染修正(可能引发故障) Hardware Tessellation = 硬件曲面细分 Hardware Transform = 硬件几何变换 @@ -519,7 +519,7 @@ Must Restart = 重启PPSSPP才能使这项设置生效。 Native device resolution = 本机原生的分辨率 Nearest = 邻近取样 No buffer = 不缓冲 -Skip Buffer Effects = 跳过缓冲(更快) +Skip Buffer Effects = 跳过缓冲效果(不缓冲, 更快) None = 不显示 Number of Frames = 帧的数量 Off = 关闭 @@ -541,12 +541,12 @@ Safe = 安全 Screen Scaling Filter = 屏幕缩放滤镜 Show Debug Statistics = 显示调试信息 Show FPS Counter = 显示FPS计数器 -Skip GPU Readbacks = Skip GPU Readbacks +Skip GPU Readbacks = 跳过GPU回读 Software Rendering = 软件渲染(慢) Software Skinning = 软件蒙皮 SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快 Speed = 运行速度 -Speed Hacks = 速度修正 (可能引发故障) +Speed Hacks = 提速修正 (引起不稳定性) Stretch = 拉伸 Texture Filter = 纹理过滤方式 Texture Filtering = 纹理过滤 @@ -716,7 +716,7 @@ DataCannotBeShared = 数据无法在普通版/黄金版之间共用! DataWillBeLostOnUninstall = 警告!卸载PPSSPP将丢失全部数据! DataWillStay = 卸载PPSSPP时会保留数据。 Done! = 完成! -EasyUSBAccess = 轻松USB访问 +EasyUSBAccess = USB连接更简单 Failed to move some files! = 无法移动部分文件! Failed to save config = 无法保存配置! Free space = 可用空间 From 59874e31611f222e11365ebc6f870a6a7d3ace0e Mon Sep 17 00:00:00 2001 From: Narugakuruga <31060534+Narugakuruga@users.noreply.github.com> Date: Mon, 28 Nov 2022 17:32:51 +0800 Subject: [PATCH 443/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index f65dd00cea..902cffda67 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -199,7 +199,7 @@ Save Map File... = 保存内存镜像文件 (&S)... Save State = 快速存档 (&a) Save State File... = 保存即时存档 (&S)... Savestate Slot = 即时存档插槽 (&t) -Screen Scaling Filter = 屏幕缩放滤镜 (&e) +Screen Scaling Filter = 屏幕缩放方法 (&e) Show Debug Statistics = 显示调试信息 (&g) Show FPS Counter = 显示FPS计数器 (&F) Skip Number of Frames = 跳过帧的数量 @@ -207,8 +207,8 @@ Skip Percent of FPS = 跳过帧率的百分比 Stop = 停止 (&S) Switch UMD = 切换UMD光盘 Take Screenshot = 屏幕截图 (&T) -Texture Filtering = 纹理过滤方式 (&x) -Texture Scaling = 纹理缩放方式 (&T) +Texture Filtering = 纹理过滤方法 (&x) +Texture Scaling = 纹理缩放方法 (&T) Use Lossless Video Codec (FFV1) = 使用无损视频编解码器(FFV1) (&U) Use output buffer for video = 录制时使用输出缓冲 Vertex Cache = 顶点缓存 (&V) @@ -528,7 +528,7 @@ Overlay Information = 叠加信息 Partial Stretch = 部分拉伸 Percent of FPS = 帧率的百分比 Performance = 性能 -Postprocessing effect = 后处理效果 +Postprocessing effect = 滤镜效果 Postprocessing Shader = 后处理着色器 Recreate Activity = 重建进程 Render duplicate frames to 60hz = 渲染重复帧至60Hz @@ -536,9 +536,9 @@ RenderDuplicateFrames Tip = 在较低帧率的游戏中可以使帧速率更平 Rendering Mode = 渲染模式 Rendering Resolution = 渲染分辨率 RenderingMode NonBuffered Tip = 更快,但可能在某些游戏中丢失特效 -Rotation = 旋转 +Rotation = 方向 Safe = 安全 -Screen Scaling Filter = 屏幕缩放滤镜 +Screen Scaling Filter = 缩放方法 Show Debug Statistics = 显示调试信息 Show FPS Counter = 显示FPS计数器 Skip GPU Readbacks = 跳过GPU回读 @@ -548,7 +548,7 @@ SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏 Speed = 运行速度 Speed Hacks = 提速修正 (引起不稳定性) Stretch = 拉伸 -Texture Filter = 纹理过滤方式 +Texture Filter = 纹理过滤方法 Texture Filtering = 纹理过滤 Texture Scaling = 纹理缩放 Texture Shader = 纹理着色器 @@ -557,7 +557,7 @@ Unlimited = 无限制 Up to 1 = 最高为1 Up to 2 = 最高为2 Upscale Level = 纹理缩放级别 -Upscale Type = 纹理缩放方式 +Upscale Type = 纹理缩放方法 UpscaleLevel Tip = CPU重负载-为避免卡顿, 某些缩放可能会延迟 Use all displays = 使用全部显示器 Vertex Cache = 顶点缓存 From 54e37671ed2c12e8bf98994eabb3fe653d51fbd1 Mon Sep 17 00:00:00 2001 From: Narugakuruga <31060534+Narugakuruga@users.noreply.github.com> Date: Mon, 28 Nov 2022 17:34:43 +0800 Subject: [PATCH 444/715] Update zh_CN.ini --- assets/lang/zh_CN.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 902cffda67..2087073bff 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -485,8 +485,8 @@ Device = 设备 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 禁用 -Display Layout && Effects = 屏幕布局/滤镜编辑 -Display Resolution (HW scaler) = 显示分辨率(硬件缩放) +Display Layout && Effects = 屏幕布局/滤镜 +Display Resolution (HW scaler) = 屏幕分辨率 Enable Cardboard VR = 启用Cardboard VR FPS = 每秒帧数 (FPS) Frame Rate Control = 帧率控制 From 3246baec4bcb040628b0e385a46ec473521122ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 10:39:04 +0100 Subject: [PATCH 445/715] SoftGPU: Range check block copies. Needs testing to verify if we should copy zeroes instead if the src range is partial, etc, quite a few possible edge cases. Though on its own, this probably fixes the crash in #16427. Still don't understand why that one has issues in hardware renderers though since they do bounds-check the copies. --- GPU/Software/SoftGpu.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 2203c14ab9..7a824fe7b0 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -807,15 +807,38 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp; + u32 bytesToCopy = width * height * bpp; + + if (!Memory::IsValidRange(srcLineStartAddr, bytesToCopy)) { + // What should we do here? Memset zeroes to the dest instead? + return; + } + if (!Memory::IsValidRange(dstLineStartAddr, bytesToCopy)) { + // What should we do here? Just not do the write, or partial write if + // some part is in-range? + return; + } + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - memcpy(dstp, srcp, width * height * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * height * bpp); + memcpy(dstp, srcp, bytesToCopy); + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy); } else { for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; + u32 bytesToCopy = width * bpp; + if (!Memory::IsValidRange(srcLineStartAddr, bytesToCopy)) { + // What should we do here? Due to the y loop, in this case we might have + // performed a partial copy. Probably fine. + break; + } + if (!Memory::IsValidRange(dstLineStartAddr, bytesToCopy)) { + // What should we do here? Due to the y loop, in this case we might have + // performed a partial copy. Probably fine. + break; + } const u8 *srcp = Memory::GetPointer(srcLineStartAddr); u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); memcpy(dstp, srcp, width * bpp); From 6c8ccc149e852af8d054a4e14b09d1100639baf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 10:46:45 +0100 Subject: [PATCH 446/715] Stop logspam from bad block transfer corners. --- GPU/GPUCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 37654faff5..1560d3fe49 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3073,11 +3073,11 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { u32 dstLastAddr = dstBasePtr + ((dstY + height - 1) * dstStride + (dstX + width - 1)) * bpp; if (!Memory::IsValidAddress(srcLastAddr)) { - ERROR_LOG_REPORT(G3D, "Bottom-right corner of source of block transfer is at an invalid address: %08x", srcLastAddr); + ERROR_LOG_N_TIMES(bad_xfer_src, 5, G3D, "Bottom-right corner of source of %dx%d src=(%d, %d) block transfer from buffer at %08x is at an invalid address: %08x. Skipping.", width, height, srcX, srcY, srcBasePtr, srcLastAddr); return; } if (!Memory::IsValidAddress(dstLastAddr)) { - ERROR_LOG_REPORT(G3D, "Bottom-right corner of destination of block transfer is at an invalid address: %08x", srcLastAddr); + ERROR_LOG_N_TIMES(bad_xfer_src, 5, G3D, "Bottom-right corner of destination of %dx%d dst=(%d, %d) block transfer to buffer at %08x is at an invalid address: %08x. Skipping.", width, height, dstX, dstY, dstBasePtr, srcLastAddr); return; } From 9bb0c91a75aac739dd9e1124546934e7cce33baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Nov 2022 11:10:28 +0100 Subject: [PATCH 447/715] Sneak in a minor software transform optimization --- Common/Data/Convert/SmallDataConvert.h | 1 - GPU/Common/VertexDecoderCommon.h | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Common/Data/Convert/SmallDataConvert.h b/Common/Data/Convert/SmallDataConvert.h index 95558a17df..740193e739 100644 --- a/Common/Data/Convert/SmallDataConvert.h +++ b/Common/Data/Convert/SmallDataConvert.h @@ -23,7 +23,6 @@ extern const float one_over_255_x4[4]; // NEON intrinsics: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491f/BABDCGGF.html // LSBs in f[0], etc. -// Could be SSE optimized. inline void Uint8x4ToFloat4(float f[4], uint32_t u) { #ifdef _M_SSE __m128i zero = _mm_setzero_si128(); diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 7c2dcb2cfc..f23db789cc 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -23,6 +23,7 @@ #include "Common/CommonTypes.h" #include "Common/Data/Collections/Hashmaps.h" +#include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Log.h" #include "Core/Reporting.h" #include "GPU/ge_constants.h" @@ -181,11 +182,7 @@ public: void ReadColor0(float color[4]) const { switch (decFmt_.c0fmt) { case DEC_U8_4: - { - const u8 *b = (const u8 *)(data_ + decFmt_.c0off); - for (int i = 0; i < 4; i++) - color[i] = b[i] * (1.f / 255.f); - } + Uint8x4ToFloat4(color, *(const u32 *)(data_ + decFmt_.c0off)); break; case DEC_FLOAT_4: memcpy(color, data_ + decFmt_.c0off, 16); From 164c27f5ec79b45474df9d92ca93f51ffc029814 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 28 Nov 2022 19:25:13 +0100 Subject: [PATCH 448/715] OpenXR - Screen stretching fixed --- GPU/Common/PresentationCommon.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 0c783b4050..0c3030b63c 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -86,15 +86,6 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f float scale = g_Config.fDisplayScale; float aspectRatioAdjust = g_Config.fDisplayAspectRatio; - if (IsVREnabled()) { - stretch = 0; - rotated = false; - offsetX = 0.0f; - offsetY = 0.0f; - scale = 1.0f; - aspectRatioAdjust = 1.0f; - } - // Ye olde 1080p hack, new version: If everything is setup to exactly cover the screen (defaults), and the screen display aspect ratio is 16:9, // stretch the PSP's aspect ratio veeery slightly to fill it completely. if (scale == 1.0f && offsetX == 0.5f && offsetY == 0.5f && aspectRatioAdjust == 1.0f) { @@ -132,10 +123,19 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f outH = scaledHeight; } - rc->x = floorf(frame.x + frame.w * offsetX - outW * 0.5f); - rc->y = floorf(frame.y + frame.h * offsetY - outH * 0.5f); - rc->w = floorf(outW); - rc->h = floorf(outH); + if (IsVREnabled()) { + rc->x = 0; + rc->y = 0; + rc->w = floorf(frame.w); + rc->h = floorf(frame.h); + outW = frame.w; + outH = frame.h; + } else { + rc->x = floorf(frame.x + frame.w * offsetX - outW * 0.5f); + rc->y = floorf(frame.y + frame.h * offsetY - outH * 0.5f); + rc->w = floorf(outW); + rc->h = floorf(outH); + } } PresentationCommon::PresentationCommon(Draw::DrawContext *draw) : draw_(draw) { From d466ae161a6789560903f92360804db4c290be05 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 28 Nov 2022 19:46:46 +0100 Subject: [PATCH 449/715] OpenXR - HUD max scale fixed --- GPU/Common/VertexShaderGenerator.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index f5e01fbc36..b797e78b64 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1354,10 +1354,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } // HUD scaling - WRITE(p, " if ((u_scaleX < 0.99) || (u_scaleY < 0.99)) {\n"); - WRITE(p, " %sgl_Position.x *= u_scaleX;\n", compat.vsOutPrefix); - WRITE(p, " %sgl_Position.y *= u_scaleY;\n", compat.vsOutPrefix); - WRITE(p, " }\n"); + WRITE(p, " %sgl_Position.x *= u_scaleX;\n", compat.vsOutPrefix); + WRITE(p, " %sgl_Position.y *= u_scaleY;\n", compat.vsOutPrefix); } if (useSimpleStereo && useHWTransform) { From 804a336a1edadcde0b6b00f66734d0f26b346f38 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 28 Nov 2022 19:58:49 +0100 Subject: [PATCH 450/715] OpenXR - Hide unsupported layout options --- UI/DisplayLayoutScreen.cpp | 60 ++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 4865a3214b..ed741ec6c9 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -26,6 +26,7 @@ #include "Common/Math/math_util.h" #include "Common/System/Display.h" #include "Common/System/NativeApp.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/StringUtils.h" #include "Common/Data/Color/RGBAUtil.h" @@ -202,39 +203,42 @@ void DisplayLayoutScreen::CreateViews() { rightScrollView->Add(rightColumn); root_->Add(rightScrollView); - auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); - leftColumn->Add(stretch); - PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); - leftColumn->Add(aspectRatio); - aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch); - aspectRatio->SetHasDropShadow(false); - aspectRatio->SetLiveUpdate(true); + if (!IsVREnabled()) { + auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); + leftColumn->Add(stretch); - mode_ = new ChoiceStrip(ORIENT_VERTICAL); - mode_->AddChoice(di->T("Move")); - mode_->AddChoice(di->T("Resize")); - mode_->SetSelection(0, false); - leftColumn->Add(mode_); + PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager()); + leftColumn->Add(aspectRatio); + aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch); + aspectRatio->SetHasDropShadow(false); + aspectRatio->SetLiveUpdate(true); - static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; - auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); - rotation->SetEnabledFunc([] { - return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; - }); - leftColumn->Add(rotation); + mode_ = new ChoiceStrip(ORIENT_VERTICAL); + mode_->AddChoice(di->T("Move")); + mode_->AddChoice(di->T("Resize")); + mode_->SetSelection(0, false); + leftColumn->Add(mode_); - leftColumn->Add(new Spacer(12.0f)); + static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; + auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); + rotation->SetEnabledFunc([] { + return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; + }); + leftColumn->Add(rotation); - Choice *center = new Choice(di->T("Reset")); - center->OnClick.Add([&](UI::EventParams &) { - g_Config.fDisplayAspectRatio = 1.0f; - g_Config.fDisplayScale = 1.0f; - g_Config.fDisplayOffsetX = 0.5f; - g_Config.fDisplayOffsetY = 0.5f; - return UI::EVENT_DONE; - }); - leftColumn->Add(center); + leftColumn->Add(new Spacer(12.0f)); + + Choice *center = new Choice(di->T("Reset")); + center->OnClick.Add([&](UI::EventParams &) { + g_Config.fDisplayAspectRatio = 1.0f; + g_Config.fDisplayScale = 1.0f; + g_Config.fDisplayOffsetX = 0.5f; + g_Config.fDisplayOffsetY = 0.5f; + return UI::EVENT_DONE; + }); + leftColumn->Add(center); + } static const char *bufFilters[] = { "Linear", "Nearest", }; rightColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); From 1a7bafd09190515e8dc154e588824780fa22f4df Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Tue, 29 Nov 2022 01:58:23 +0300 Subject: [PATCH 451/715] Update Russian translation --- assets/lang/ru_RU.ini | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index b52d422a1b..8205c2bc4d 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -347,7 +347,7 @@ Yes = Да Zoom = Масштаб [Error] -7z file detected (Require 7-Zip) = файл сжат (7z).\nПожалуйста распакуйте (воспользуйтесь 7-Zip). +7z file detected (Require 7-Zip) = Файл сжат (7z).\nПожалуйста, распакуйте (воспользуйтесь 7-Zip). A PSP game couldn't be found on the disc. = На диске не удалось найти игру для PSP. Cannot boot ELF located outside mountRoot. = Невозможно загрузить ELF, расположенный вне mountRoot. Could not save screenshot file = Не удалось сохранить скриншот. @@ -754,7 +754,7 @@ Network Initialized = Сеть активирована None = Нет Please change your Port Offset = Пожалуйста, измените ваше смещение порта Port offset = Смещение порта (0 = совместимость с PSP) -Open PPSSPP Multiplayer Wiki Page = Open PPSSPP Multiplayer Wiki Page +Open PPSSPP Multiplayer Wiki Page = Открыть wiki-страницу мультиплеера PPSSPP proAdhocServer Address: = Адрес ad-hoc сервера: Quick Chat 1 = Быстрый чат 1 Quick Chat 2 = Быстрый чат 2 @@ -1037,13 +1037,14 @@ CPU Name = Название D3DCompiler Version = Версия D3DCompiler Debug = Отладочная Debugger Present = Отладчик присутствует +Depth buffer format = Формат буфера глубины Device Info = Устройство Directories = Директории Display Color Formats = Display Color Formats Display Information = Информация о дисплее -Driver bugs = Driver bugs +Driver bugs = Ошибки драйвера Driver Version = Версия драйвера -EGL Extensions = Расширенния EGL +EGL Extensions = Расширения EGL Frames per buffer = Кадров на буфер GPU Information = Информация о ГП High precision float range = Диапазон точных дробных чисел @@ -1051,12 +1052,12 @@ High precision int range = Диапазон точных целых чисел Lang/Region = Язык/регион Memory Page Size = Размер страницы памяти Native Resolution = Родное разрешение -No GPU driver bugs detected = Ошибок GPU драйвера не обнаружено +No GPU driver bugs detected = Ошибок драйвера ГП не обнаружено OGL Extensions = Расширения OGL OpenGL ES 2.0 Extensions = Расширения OpenGL ES 2.0 OpenGL ES 3.0 Extensions = Расширения OpenGL ES 3.0 OpenGL Extensions = Расширения OpenGL -Optimal frames per buffer = Оптимально фреймов на буфер +Optimal frames per buffer = Оптимально кадров на буфер Optimal sample rate = Оптимальная частота дискретизации OS Information = Информация об ОС PPSSPP build = Сборка PPSSPP @@ -1088,7 +1089,7 @@ AVI Dump stopped. = Дамп AVI остановлен Cache ISO in RAM = Кэшировать ISO в ОЗУ Change CPU Clock = Эмулируемая частота ЦП PSP (нестабильно) Color Saturation = Насыщенность -Color Tint = Оттенок Цвета +Color Tint = Оттенок цвета Memory Stick folder = Изменить папку с картой памяти Memory Stick size = Изменить размер карты памяти (Гб) Change Nickname = Изменить ник From b9dc206cf0a25f2137acd5d866c633858761b6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 09:42:11 +0100 Subject: [PATCH 452/715] Fix skip buffer effect toggle not taking effect immediately --- UI/GameSettingsScreen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 8592d106c4..81dd9b36ea 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -397,6 +397,7 @@ void GameSettingsScreen::CreateViews() { settingInfo_->Show(gr->T("RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games"), e.v); g_Config.bAutoFrameSkip = false; } + NativeMessageReceived("gpu_renderResized", ""); return UI::EVENT_DONE; }); skipBufferEffects->SetDisabledPtr(&g_Config.bSoftwareRendering); From 4fe8aa71749587eed9af336f93fb32bdc50b54a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 09:52:30 +0100 Subject: [PATCH 453/715] Fix category for "Language" string. Swedish translation improvements --- UI/GameSettingsScreen.cpp | 6 +++--- UI/MiscScreens.cpp | 4 ++-- assets/lang/sv_SE.ini | 31 ++++++++++++++++--------------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 81dd9b36ea..b2552c10fd 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -829,7 +829,7 @@ void GameSettingsScreen::CreateViews() { LinearLayout *systemSettings = AddTab("GameSettingsSystem", ms->T("System")); systemSettings->Add(new ItemHeader(sy->T("UI"))); - systemSettings->Add(new Choice(dev->T("Language", "Language")))->OnClick.Handle(this, &GameSettingsScreen::OnLanguage); + systemSettings->Add(new Choice(sy->T("Language")))->OnClick.Handle(this, &GameSettingsScreen::OnLanguage); systemSettings->Add(new CheckBox(&g_Config.bUISound, sy->T("UI Sound"))); const Path bgPng = GetSysDirectory(DIRECTORY_SYSTEM) / "background.png"; const Path bgJpg = GetSysDirectory(DIRECTORY_SYSTEM) / "background.jpg"; @@ -1592,8 +1592,8 @@ UI::EventReturn GameSettingsScreen::OnChangeMacAddress(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnLanguage(UI::EventParams &e) { - auto dev = GetI18NCategory("Developer"); - auto langScreen = new NewLanguageScreen(dev->T("Language")); + auto sy = GetI18NCategory("System"); + auto langScreen = new NewLanguageScreen(sy->T("Language")); langScreen->OnChoice.Handle(this, &GameSettingsScreen::OnLanguageChange); if (e.v) langScreen->SetPopupOrigin(e.v); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 2a1a418f5b..d5d7ec5f85 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -425,8 +425,8 @@ void HandleCommonMessages(const char *message, const char *value, ScreenManager UpdateUIState(UISTATE_MENU); manager->push(new GameSettingsScreen(Path())); } else if (!strcmp(message, "language screen") && isActiveScreen) { - auto dev = GetI18NCategory("Developer"); - auto langScreen = new NewLanguageScreen(dev->T("Language")); + auto sy = GetI18NCategory("System"); + auto langScreen = new NewLanguageScreen(sy->T("Language")); langScreen->OnChoice.Add([](UI::EventParams &) { NativeMessageReceived("recreateviews", ""); if (host) { diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 03ca0d124b..ddd2bc8e3a 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -9,7 +9,7 @@ Disabled = Disabled DSound (compatible) = DSound (kompatibel) Enable Sound = Ljud Global volume = Global volym -Microphone = Microphone +Microphone = Mikrofon Microphone Device = Mikrofon-enhet Mute = Tysta Reverb volume = Volym på reverb-effekt @@ -541,7 +541,7 @@ Safe = Safe Screen Scaling Filter = Skärmskalningsfilter Show Debug Statistics = Visa debugstatistik Show FPS Counter = Visa FPS-räknare -Skip GPU Readbacks = Skip GPU Readbacks +Skip GPU Readbacks = Skippa dataläsningar från GPU:n Software Rendering = Mjukvarurendering (långsam men ofta mer korrekt) Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games @@ -1104,7 +1104,7 @@ Confirmation Button = Bekräftelseknapp Date Format = Datumformat Day Light Saving = Sommartid DDMMYYYY = DDMMYYYY -Decrease size = Decrease size +Decrease size = Minska storlek Developer Tools = Utvecklarverktyg Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid @@ -1120,33 +1120,34 @@ Fast (lag on slow storage) = Snabbt (lag on slow storage) Fast Memory = Snabbt minne (instabilt) Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) frames, 0:off = frames, 0 = avstängt -Games list settings = Games list settings +Games list settings = Inställningar för spel-listan General = Blandat -Grid icon size = Grid icon size +Grid icon size = Ikonstorlek i rutnät Help the PPSSPP team = Stöd PPSSPP-teamet Host (bugs, less lag) = Host (bugs, mindre lagg) Ignore bad memory accesses = Ignorera felaktiga minnesåtkomster -Increase size = Increase size +Increase size = Öka storlek Interpreter = Interpreter IO timing method = IO-timingsmetod IR Interpreter = IR interpreter -Memory Stick Folder = Memory Stick folder +Language = Språk +Memory Stick Folder = Memory Stick-mapp Memory Stick inserted = Memory Stick insatt MHz, 0:default = MHz, 0 = standard MMDDYYYY = MMDDYYYY -Moving background = Moving background -Newest Save = Newest save -No animation = No animation +Moving background = Rörlig bakgrund +Newest Save = Nyaste sparfilen +No animation = Ingen animation Not a PSP game = Inte ett PSP-spel Off = Off -Oldest Save = Oldest save +Oldest Save = Äldsta sparfilen Path does not exist! = Path does not exist! PSP Memory Stick = PSP Memory Stick PSP Model = PSP-modell PSP Settings = PSP-inställningar PSP-1000 = PSP-1000 PSP-2000/3000 = PSP-2000/3000 -Recent games = Recent games +Recent games = Tidigare spel Record Audio = Spela in audio till fil Record Display = Spela in video till fil Reset Recording on Save/Load State = Reset recording on Save/Load state @@ -1159,8 +1160,8 @@ Savestate slot backups = Savestate slot backups Screenshots as PNG = Skärmdumpar som PNG Set UI background... = Välj UI-bakgrund... Show ID = Show ID -Show Memory Stick folder = Show Memory Stick folder -Show region flag = Show region flag +Show Memory Stick folder = Visa Memory Stick-mappen +Show region flag = Visa region-flaggor Simulate UMD delays = Simulera UMD-fördröjningar Slot 1 = Slot 1 Slot 2 = Slot 2 @@ -1169,7 +1170,7 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Lagringsutrymme fullt Sustained performance mode = Sustained performance mode -Theme = Theme +Theme = Tema Time Format = Tidsformat UI = Användargränssnitt UI background animation = UI background animation From 6ef855bf316b1ca620a23689d3cccbc354c653f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 09:54:42 +0100 Subject: [PATCH 454/715] Put back the lost Language strings, now in the right category --- assets/lang/ar_AE.ini | 1 + assets/lang/az_AZ.ini | 1 + assets/lang/bg_BG.ini | 1 + assets/lang/ca_ES.ini | 1 + assets/lang/cz_CZ.ini | 1 + assets/lang/da_DK.ini | 1 + assets/lang/de_DE.ini | 1 + assets/lang/dr_ID.ini | 1 + assets/lang/es_ES.ini | 1 + assets/lang/es_LA.ini | 1 + assets/lang/fa_IR.ini | 1 + assets/lang/fi_FI.ini | 1 + assets/lang/fr_FR.ini | 1 + assets/lang/gl_ES.ini | 1 + assets/lang/gr_EL.ini | 1 + assets/lang/he_IL.ini | 1 + assets/lang/he_IL_invert.ini | 1 + assets/lang/hr_HR.ini | 1 + assets/lang/hu_HU.ini | 1 + assets/lang/id_ID.ini | 1 + assets/lang/it_IT.ini | 1 + assets/lang/ja_JP.ini | 1 + assets/lang/jv_ID.ini | 1 + assets/lang/ko_KR.ini | 1 + assets/lang/lo_LA.ini | 1 + assets/lang/lt-LT.ini | 1 + assets/lang/ms_MY.ini | 1 + assets/lang/nl_NL.ini | 1 + assets/lang/no_NO.ini | 1 + assets/lang/pl_PL.ini | 1 + assets/lang/pt_BR.ini | 1 + assets/lang/pt_PT.ini | 1 + assets/lang/ro_RO.ini | 1 + assets/lang/ru_RU.ini | 1 + assets/lang/tg_PH.ini | 1 + assets/lang/th_TH.ini | 1 + assets/lang/tr_TR.ini | 1 + assets/lang/uk_UA.ini | 1 + assets/lang/vi_VN.ini | 1 + assets/lang/zh_CN.ini | 1 + assets/lang/zh_TW.ini | 1 + 41 files changed, 41 insertions(+) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 8bdfcb940e..335d1768cd 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -1099,6 +1099,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = ‎اللغة Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = ‎تغيير الأسم المستعار diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 969a04f2d7..e77fd012e2 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Change nickname diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 7cc4685339..b7588b5cea 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Език Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Промени прякор diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index a983ab7a80..2d3de08e32 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Llengua Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Change nickname diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 6975e025f7..771be3b33b 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Jazyk Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Změnit přezdívku diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 461469846b..a30b204f77 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Sprog Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Ændre kaldenavn diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index e297baa7b5..e5dfc61dea 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Sprache Memory Stick folder = Memory Stick Ordner Memory Stick size = Memory Stick size Change Nickname = Spitznamen ändern diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index ff3c886a3d..ed73de7260 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Bahasa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Sullei Nickname diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 88057e48c2..a96a62bd96 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes +Language = Idioma Memory Stick folder = Directorio de Memory Stick Memory Stick size = Cambiar tamaño de Memory Stick (GB) Change Nickname = Cambiar apodo PSP diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index ddd6bbdb1c..10c0e35d70 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes +Language = Idioma Memory Stick folder = Carpeta del Memory Stick Memory Stick size = Tamaño del Memory Stick Change Nickname = Cambiar nombre de usuario diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 054602ab19..7b47740592 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = ‎زبان Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = ‎تغییر نام diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 4165daf4c7..06bc57cae7 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Vaihda nimimerkkiä diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 8fd76658ec..4c00779789 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -1082,6 +1082,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Langue Memory Stick folder = Changer le dossier de la Memory Stick Memory Stick size = Changer la taille de la Memory Stick (Go) Change Nickname = Changer de pseudo diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index ede4a3ef4f..eb1e7320fe 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Idioma Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Cambiar alcume PSP diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index a8b7fd0f95..00862fb7aa 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Γλώσσα Memory Stick folder = Αλλαγή φακέλου Memory Stick Memory Stick size = Memory Stick size Change Nickname = Αλλαγή Ψευδωνύμου diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 93d2c6431c..152a56d985 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = שפה Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = שנה כינוי diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 37757a38df..839f1f421f 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = הפש Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = יוניכ הנש diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 8f3b4ba77d..25b1cbd522 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Jezik Memory Stick folder = Promijeni mapu Memorijskoga sticka Memory Stick size = Memory Stick size Change Nickname = Promijeni nadimak diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 5a90a404a9..f6e2580399 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Nyelv Memory Stick folder = Memory Stick mappa megváltoztatása Memory Stick size = Memory Stick size Change Nickname = Becenév megváltoztatása diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 565e330e58..e687d2c8b5 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -1091,6 +1091,7 @@ Color Tint = Pewarnaan Error: load undo state is from a different game = Kesalahan: memuat status yang berasal dari permainan yang berbeda Failed to load state for load undo. Error in the file system. = Gagal memuat status untuk membatalkan pemuatan. Kesalahan dalam sistem berkas. Floating symbols = Simbol mengambang +Language = Bahasa Memory Stick folder = Berkas Memory Stick Memory Stick size = Ukuran Memory Stick Change Nickname = Ganti nama panggilan diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 4d6775d5ed..a00bcee019 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -1092,6 +1092,7 @@ Color Tint = Tonalità colore Error: load undo state is from a different game = Errore: lo stato annullato proviene da un gioco diverso. Failed to load state for load undo. Error in the file system. = Impossibile caricare lo stato da un caricamento annullato. Errore nel file system. Floating symbols = Simboli fluttuanti +Language = Lingua Memory Stick folder = Cartella della Memory Stick Memory Stick size = Cambia dimensioni Memory Stick Change Nickname = Cambia Nick diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 115eea7545..411b53e54b 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -1089,6 +1089,7 @@ Change CPU Clock = CPUクロックを変更する (不安定) Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = 言語 Memory Stick folder = メモリースティックフォルダを変更する Memory Stick size = メモリースティックの容量の変更 (GB) Change Nickname = ニックネームを変更する diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index c89ff8fc49..eb1e685986 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Basa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Ganti Jeneng diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 439d97f2e4..d21db63687 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -1099,6 +1099,7 @@ AVI Dump started. = AVI 덤프가 시작됨 AVI Dump stopped. = AVI 덤프가 중지됨 Cache ISO in RAM = RAM에 전체 ISO 캐시 Change CPU Clock = 에뮬레이트된 PSP의 CPU 클럭 변경 (불안정) +Language = 언어 Memory Stick folder = 메모리 스틱 폴더 Memory Stick size = 메모리 스틱 크기 Change Nickname = 별명 변경 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index e6706aab2b..36ff4ef15f 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = ພາສາ Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = ປ່ຽນຊື່ຫຼິ້ນ diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index d84ce08ed0..b3d7162f99 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Kalba Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Pakeisti slapyvardį diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index be200b4ad7..8dea0436f0 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Bahasa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Tukar nama samaran diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index da32d41b42..55e19838a6 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Taal Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Gebruikersnaam wijzigen diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 148359afed..bc3da4ee71 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Endre Kallenavn diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 6510d8222c..759bcaf066 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Język Memory Stick folder = Zmień folder Karty Pamięci Memory Stick size = Rozmiar Karty Pamięci Change Nickname = Zmień pseudonim diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 280e0dc0f2..0d026ef431 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -1104,6 +1104,7 @@ AVI Dump started. = Dump do AVI iniciado AVI Dump stopped. = Dump do AVI parado Cache ISO in RAM = Pôr a ISO inteira na RAM Change CPU Clock = Mudar o clock da CPU do PSP emulado (instável) +Language = Idioma Memory Stick folder = Pasta do cartão de memória Memory Stick size = Tamanho do cartão de memória Change Nickname = Mudar apelido diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index b56c82385b..6d9a2823d3 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -1104,6 +1104,7 @@ AVI Dump started. = Dump do AVI iniciado AVI Dump stopped. = Dump do AVI parado Cache ISO in RAM = Colocar a ISO inteira na RAM Change CPU Clock = Mudar o clock da CPU do PSP emulado (instável) +Language = Idioma Memory Stick folder = Pasta do Cartão de Memória Memory Stick size = Tamanho do Cartão de Memória Change Nickname = Mudar Nome diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index b80373a76a..f7a3da53a5 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Limbă Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Schimbă nume diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 8205c2bc4d..365dd76bd1 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -1090,6 +1090,7 @@ Cache ISO in RAM = Кэшировать ISO в ОЗУ Change CPU Clock = Эмулируемая частота ЦП PSP (нестабильно) Color Saturation = Насыщенность Color Tint = Оттенок цвета +Language = Язык Memory Stick folder = Изменить папку с картой памяти Memory Stick size = Изменить размер карты памяти (Гб) Change Nickname = Изменить ник diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index bd54f7cb92..2ca39ee971 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Lumulutang na simbolo +Language = Wika Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Baguhin ang palayaw diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 2d522a6cdb..069db90253 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -1136,6 +1136,7 @@ Increase size = เพิ่มขนาดไอคอน Interpreter = อินเตอร์พรีเตอร์ IO timing method = ทางเลือกคำนวณเวลา รับ/ส่ง ข้อมูล IR Interpreter = ไออาร์ อินเตอร์พรีเตอร์ +Language = ภาษา Memory Stick folder = เปลี่ยนแหล่งที่เก็บข้อมูล (เม็มโมรี่ สติ๊ก) Memory Stick Folder = โฟลเดอร์แหล่งที่เก็บข้อมูล (เม็มโมรี่ สติ๊ก) Memory Stick inserted = ใส่ที่บันทึกข้อมูล (เม็มโมรี่ สติ๊ก) diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 7b771b4c8d..0e22d1d76c 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1092,6 +1092,7 @@ Color Tint = Renk Tonu Error: load undo state is from a different game = Hata: yükleme geri alma durumu farklı bir oyundan Failed to load state for load undo. Error in the file system. = Yüklemeyi geri alma durumu yüklenemedi. Dosya sisteminde hata. Floating symbols = Kayan simgeler +Language = Dil Memory Stick folder = Hafıza Kartı klasörü Memory Stick size = Hafıza Kartı boyutu Change Nickname = Kullanıcı adını değiştir diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 2b35f5622e..dd243bc702 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Мова Memory Stick folder = Змінити папку для карти пам'яті Memory Stick size = Memory Stick size Change Nickname = Змінити ім'я diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index d5c697b261..60469d41d4 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -1091,6 +1091,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Language = Ngôn ngữ Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Đổi nickname diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 2087073bff..5a12fb15b9 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1085,6 +1085,7 @@ Color Saturation = 颜色饱和度 Error: load undo state is from a different game = 错误:撤回的即时存档是来自不同游戏的 Failed to load state for load undo. Error in the file system. = 无法撤回加载即时存档。文件系统有错误。 Floating symbols = 飘浮的按键 +Language = 语言设置 Memory Stick folder = 记忆棒文件夹 Memory Stick size = 记忆棒大小(GB) Change Nickname = 修改昵称 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 6b6400f9c3..34c762e3c2 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -1079,6 +1079,7 @@ AVI Dump started. = AVI 傾印已啟動 AVI Dump stopped. = AVI 傾印已停止 Cache ISO in RAM = 將完整 ISO 快取於 RAM Change CPU Clock = 變更模擬 PSP CPU 時脈 (不穩定) +Language = 語言 Memory Stick folder = 記憶棒資料夾 Memory Stick size = 記憶棒大小 Change Nickname = 變更暱稱 From 3ba37f4e7799ff7c2926d665b4fb29d3957d61fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 09:57:18 +0100 Subject: [PATCH 455/715] Langtool: Add --dry-run support --- Tools/langtool/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Tools/langtool/src/main.rs b/Tools/langtool/src/main.rs index f17aab1186..7b59706822 100644 --- a/Tools/langtool/src/main.rs +++ b/Tools/langtool/src/main.rs @@ -11,6 +11,8 @@ use structopt::StructOpt; struct Opt { #[structopt(subcommand)] cmd: Command, + #[structopt(short, long)] + dry_run: bool, } #[derive(StructOpt, Debug)] @@ -170,7 +172,9 @@ fn main() { } } - target_ini.write().unwrap(); + if !opt.dry_run { + target_ini.write().unwrap(); + } } println!("Langtool processing {}", reference_ini_filename); @@ -199,5 +203,7 @@ fn main() { _ => {} } - // println!("{:#?}", target_ini); + if !opt.dry_run { + reference_ini.write().unwrap(); + } } From 1358cf9b8f65578c60667f08ceb6a474c0bcf4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 10:04:09 +0100 Subject: [PATCH 456/715] Clean up "GPU log profiler" translation strings --- UI/GameSettingsScreen.cpp | 2 +- assets/lang/ar_AE.ini | 3 +-- assets/lang/az_AZ.ini | 3 +-- assets/lang/bg_BG.ini | 3 +-- assets/lang/ca_ES.ini | 3 +-- assets/lang/cz_CZ.ini | 3 +-- assets/lang/da_DK.ini | 3 +-- assets/lang/de_DE.ini | 3 +-- assets/lang/dr_ID.ini | 3 +-- assets/lang/en_US.ini | 7 +++---- assets/lang/es_ES.ini | 3 +-- assets/lang/es_LA.ini | 3 +-- assets/lang/fa_IR.ini | 3 +-- assets/lang/fi_FI.ini | 3 +-- assets/lang/fr_FR.ini | 3 +-- assets/lang/gl_ES.ini | 3 +-- assets/lang/gr_EL.ini | 3 +-- assets/lang/he_IL.ini | 3 +-- assets/lang/he_IL_invert.ini | 3 +-- assets/lang/hr_HR.ini | 3 +-- assets/lang/hu_HU.ini | 3 +-- assets/lang/id_ID.ini | 3 +-- assets/lang/it_IT.ini | 3 +-- assets/lang/ja_JP.ini | 3 +-- assets/lang/jv_ID.ini | 3 +-- assets/lang/ko_KR.ini | 3 +-- assets/lang/lo_LA.ini | 3 +-- assets/lang/lt-LT.ini | 3 +-- assets/lang/ms_MY.ini | 3 +-- assets/lang/nl_NL.ini | 3 +-- assets/lang/no_NO.ini | 3 +-- assets/lang/pl_PL.ini | 3 +-- assets/lang/pt_BR.ini | 3 +-- assets/lang/pt_PT.ini | 3 +-- assets/lang/ro_RO.ini | 3 +-- assets/lang/ru_RU.ini | 3 +-- assets/lang/sv_SE.ini | 10 +++++----- assets/lang/tg_PH.ini | 3 +-- assets/lang/th_TH.ini | 3 +-- assets/lang/tr_TR.ini | 3 +-- assets/lang/uk_UA.ini | 3 +-- assets/lang/vi_VN.ini | 3 +-- assets/lang/zh_CN.ini | 3 +-- assets/lang/zh_TW.ini | 3 +-- 44 files changed, 50 insertions(+), 92 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index b2552c10fd..02d975757e 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1756,7 +1756,7 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLogConfig); list->Add(new CheckBox(&g_Config.bLogFrameDrops, dev->T("Log Dropped Frame Statistics"))); if (GetGPUBackend() == GPUBackend::VULKAN) { - list->Add(new CheckBox(&g_Config.bGpuLogProfiler, gr->T("GPU log profiler"))); + list->Add(new CheckBox(&g_Config.bGpuLogProfiler, dev->T("GPU log profiler"))); } list->Add(new ItemHeader(dev->T("Texture Replacement"))); list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures"))); diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 335d1768cd..126cd55b67 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -248,7 +248,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -501,7 +501,6 @@ Frame Rate Control = ‎التحكم في معدل الإطارات Frame Skipping = ‎تخطي الإطارات Frame Skipping Type = Frame skipping type FullScreen = ‎الشاشة الكاملة -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index e77fd012e2..3bd1679316 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Framerate control Frame Skipping = Kvadrat Keçid et (Sürət) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index b7588b5cea..12d2beeefa 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Framerate control Frame Skipping = Прескачане на кадри Frame Skipping Type = Frame skipping type FullScreen = Цял екран -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 2d3de08e32..ceefe047c1 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Amideu el rendiment GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Comparació Jit JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Framerate control Frame Skipping = Saltar fotogrames (skip) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 771be3b33b..c350c3f093 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profilovač snímku GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Porovnání JIT JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Kontrola frekvence snímků Frame Skipping = Přeskakování snímků Frame Skipping Type = Frame skipping type FullScreen = Režim celé obrazovky -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Nastavení hacků (Mohou způsobit problémy) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index a30b204f77..9b961c2cd3 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit sammenlign JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Frameratekontrol Frame Skipping = Frameskipping Frame Skipping Type = Frame skipping type FullScreen = Fuldskærm -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack indstillinger (kan give fejl) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index e5dfc61dea..aef55f827c 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame Profiler GPU Driver Test = GPU Treibertest -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU Profil Jit Compare = JIT-Vergleich JIT debug tools = JIT Debug Werkzeuge @@ -493,7 +493,6 @@ Frame Rate Control = Frameratenkontrolle Frame Skipping = Bilder überspringen Frame Skipping Type = Typ für Bilder überspringen FullScreen = Vollbild -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hacks (kann zu Fehlern führen) Hardware Tessellation = Hardware Tessellation diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index ed73de7260..aa20527960 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Atoro'i FRna Frame Skipping = Frameskip Frame Skipping Type = Frame skipping type FullScreen = Layar pol -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index ebc732d9ca..e049ada474 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -173,7 +173,6 @@ File = &File Frame Skipping = &Frame skipping Frame Skipping Type = Frame skipping type Fullscreen = Fu&llscreen -Geometry shader culling = Geometry shader culling Game Settings = &Game settings GE Debugger... = GE debugge&r... GitHub = Git&Hub @@ -265,7 +264,7 @@ Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test GPU Profile = GPU profile -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler Jit Compare = JIT compare JIT debug tools = JIT debug tools Log Dropped Frame Statistics = Log dropped frame statistics @@ -517,6 +516,7 @@ Frame Rate Control = Framerate control Frame Skipping = Frame skipping Frame Skipping Type = Frame skipping type FullScreen = Fullscreen +Geometry shader culling = Geometry shader culling Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware transform @@ -590,7 +590,6 @@ VSync = VSync Vulkan = Vulkan Window Size = Window size xBRZ = xBRZ -GPU log profiler = GPU log profiler [InstallZip] Delete ZIP file = Delete ZIP file @@ -1242,4 +1241,4 @@ New version of PPSSPP available = New version of PPSSPP available Choices: = Choices: List: = List: Progress: %1% = Progress: %1% -Screen representation = Screen representation \ No newline at end of file +Screen representation = Screen representation diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index a96a62bd96..d957ee0eb2 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -240,7 +240,7 @@ FPU = FPU Frame Profiler = Medir rendimiento Framedump tests = Tests de volcado de cuadros GPU Driver Test = Test de controlador GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Perfil GPU Jit Compare = Comparación JIT JIT debug tools = Herramientas de depuración JIT @@ -493,7 +493,6 @@ Frame Rate Control = Control de tasa de cuadros (FPS) Frame Skipping = Saltar cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (causarán errores gráficos) Hardware Tessellation = Teselado por hardware diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 10c0e35d70..6f570cf71b 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Pruebas de volcado de frames Frame Profiler = Perfilado de frame GPU Driver Test = Probar controlador GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Perfil de GPU Jit Compare = Comparar JIT JIT debug tools = Herr. de depuración de JIT @@ -493,7 +493,6 @@ Frame Rate Control = Control de Framerate Frame Skipping = Salto de cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (puede causar glitches) Hardware Tessellation = Teselado por Hardware diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 7b47740592..775f1352f4 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = ‎کنترل سرعت فریم Frame Skipping = ‎ردکردن فریم Frame Skipping Type = Frame skipping type FullScreen = ‎تمام صفحه -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ‎تنظیمات هک ها (میتواند باعث باگ شود) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 06bc57cae7..c1ae6df728 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Framerate control Frame Skipping = Ruudun ohitus Frame Skipping Type = Frame skipping type FullScreen = Koko näyttö -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 4c00779789..568680d1ee 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profileur d'image GPU Driver Test = Test du pilote du GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Profilage du GPU Jit Compare = Comparaison JIT JIT debug tools = Outils de débogage JIT @@ -493,7 +493,6 @@ Frame Rate Control = Contrôle de la fréquence de rafraîchissement des images Frame Skipping = Saut d'images Frame Skipping Type = Type de saut d'images FullScreen = Plein écran -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Paramètres "hack" (crée des bugs graphiques) Hardware Tessellation = Tessellation matérielle diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index eb1e7320fe..322b5811b9 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Comparación JIT JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Control de tasa de cadros (FPS) Frame Skipping = Saltar cadros Frame Skipping Type = Frame skipping type FullScreen = Pantalla completa -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Axustes de hacks (causarán erros gráficos) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 00862fb7aa..7629b1fcf0 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profiler πλαισίου GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Σύγκριση Jit JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Ρυθμίσεις Ρυθμού Καρέ Frame Skipping = Παράκαμψη Καρέ Frame Skipping Type = Frame skipping type FullScreen = Πλήρης Οθόνη -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ρυθμίσεις Hack Hardware Tessellation = Tessellation Υλικού diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 152a56d985..bcf6ee3e7b 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = שליטה על קצב פריימים Frame Skipping = דלג על פריימים Frame Skipping Type = Frame skipping type FullScreen = מסך מלא -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 839f1f421f..196ad8c6b7 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = םימיירפ בצק לע הטילש Frame Skipping = םימיירפ לע גלד Frame Skipping Type = Frame skipping type FullScreen = אלמ ךסמ -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 25b1cbd522..a4ee6b93fb 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = Testiranje GPU drivera -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profil Jit Compare = JIT uspoređivanje JIT debug tools = JIT debug alati @@ -493,7 +493,6 @@ Frame Rate Control = Framerate kontrole Frame Skipping = Preskakanje sličica Frame Skipping Type = Vrsta preskakanja sličica FullScreen = Puni zaslon -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Opcije hakiranja (može uzrokovati glitcheve) Hardware Tessellation = Hardware tesselacija diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index f6e2580399..92d87c5766 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Képkocka profilozó GPU Driver Test = GPU driver teszt -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profil Jit Compare = JIT összehasonlítás JIT debug tools = JIT hibakereső eszközök @@ -493,7 +493,6 @@ Frame Rate Control = Képkocka sebesség szabályozása Frame Skipping = Képkocka kihagyás Frame Skipping Type = Képkocka kihagyás típusa FullScreen = Teljes képernyő -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack beállítások (ezek HIBÁKAT OKOZHATNAK) Hardware Tessellation = Hardveres tesszeláció diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index e687d2c8b5..6cd340b266 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Tes pembuangan laju bingkai Frame Profiler = Profil laju bingkai GPU Driver Test = Tes driver GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Profil GPU Jit Compare = Bandingkan Jit JIT debug tools = Alat awakutu JIT @@ -493,7 +493,6 @@ Frame Rate Control = Kontrol laju bingkai Frame Skipping = Lewati laju bingkai Frame Skipping Type = Jenis lewati laju bingkai FullScreen = Layar penuh -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas pengaturan (menyebabkan kecacatan) Hardware Tessellation = Pengujian perangkat keras diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index a00bcee019..d0fb006741 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Test del framedump Frame Profiler = Profilo Frame GPU Driver Test = Test dei driver GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Profilo GPU Jit Compare = Confronto Jit JIT debug tools = Strumenti di debug JIT @@ -494,7 +494,6 @@ Frame Rate Control = Controllo Framerate Frame Skipping = Salto frame Frame Skipping Type = Tipo di Salto frame FullScreen = Schermo Intero -GPU log profiler = Log profilo GPU GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Impostazioni Hack (causerà dei problemi, sicuramente) Hardware Tessellation = Tassellazione Hardware diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 411b53e54b..d54eeceac2 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -241,7 +241,7 @@ Framedump tests = フレームダンプのテスト Frame Profiler = フレームプロファイラ GPU Driver Test = GPUドライバをテスト GPU Profile = GPUプロファイル -GPU Log Profiler = GPUログプロファイラ +GPU log profiler = GPUログプロファイラ Jit Compare = JIT 比較 JIT debug tools = JITデバッグツール Log Dropped Frame Statistics = ドロップしたフレームの統計を記録する @@ -493,7 +493,6 @@ Frame Rate Control = フレームレートのコントロール Frame Skipping = フレームスキップ Frame Skipping Type = フレームスキップのタイプ FullScreen = フルスクリーン -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ハックの設定 (不具合あり) Hardware Tessellation = ハードウェアテッセレーション diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index eb1e685986..82dac80b9d 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Pigura Profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit mbandhingake JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Kontrol Frame-rate Frame Skipping = Frame-skip Frame Skipping Type = Frame skipping type FullScreen = Layar Penuh -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas setelsn (nyebabake glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index d21db63687..1d794783cf 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -241,7 +241,7 @@ Framedump tests = 프레임 덤프 테스트 Frame Profiler = 프레임 프로파일러 GPU Driver Test = GPU 드라이버 테스트 GPU Profile = GPU 프로파일 -GPU Log Profiler = GPU 로그 프로파일러 +GPU log profiler = GPU 로그 프로파일러 Jit Compare = JIT 비교 JIT debug tools = JIT 디버그 도구 Log Dropped Frame Statistics = 삭제된 프레임 통계 기록 @@ -565,7 +565,6 @@ VSync = 수직 동기화 Vulkan = Vulkan Window Size = 창 크기 xBRZ = xBRZ 필터 -GPU log profiler = GPU 로그 프로파일러 [InstallZip] Delete ZIP file = ZIP 파일 삭제 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 36ff4ef15f..7b0630a1e0 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = ລາຍລະອຽດຂອງເຟຣມ GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = ຄວບຄຸມເຟຣມເຣດ Frame Skipping = ຂ້າມເຟຣມ Frame Skipping Type = Frame skipping type FullScreen = ເຕັມໜ້າຈໍ -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ການຕັ້ງຄ່າແຮັກ Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index b3d7162f99..89f93a0027 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Kadrų kontrolė Frame Skipping = Kadrų praleidimas Frame Skipping Type = Frame skipping type FullScreen = Pilnas ekranas -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Modifikavimo parametrai (gali sukelti problemų) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 8dea0436f0..0b2067459d 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = Ujian driver GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = Alat pepijat JIT @@ -493,7 +493,6 @@ Frame Rate Control = Kawalan kadar Frame Frame Skipping = Pelompatan Frame Frame Skipping Type = Frame skipping type FullScreen = Skrin penuh -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Godam tetapan (mungkin menyebabkan gangguan) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 55e19838a6..ec56f9f198 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frameanalyse GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit vergelijken JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Framerateinstellingen Frame Skipping = Frames overslaan Frame Skipping Type = Frame skipping type FullScreen = Volledig scherm -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hackinstellingen (kan glitches veroorzaken) Hardware Tessellation = Hardwarebetegeling diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index bc3da4ee71..9958ee308a 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Framerate control Frame Skipping = Ramme Hoppe over Frame Skipping Type = Frame skipping type FullScreen = Fullskjerm -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 759bcaf066..ec3efdc9be 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profiler klatki GPU Driver Test = Test sterownika GPU -GPU Log Profiler = Profilowanie logów GPU +GPU log profiler = Profilowanie logów GPU GPU Profile = Profil GPU Jit Compare = Porównywanie JIT JIT debug tools = Narzędzia debugowania JIT @@ -493,7 +493,6 @@ Frame Rate Control = Kontrola klatek na sekundę Frame Skipping = Pomijanie klatek Frame Skipping Type = Tryb pomijania klatek FullScreen = Pełny ekran -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ustawienia specjalne (powodują problemy) Hardware Tessellation = Sprzętowa teselacja diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 0d026ef431..4f8ed95368 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -265,7 +265,7 @@ Framedump tests = Testes dos dumps dos frames Frame Profiler = Analista dos frames GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU -GPU Log Profiler = Criador do Perfil do Registro da GPU +GPU log profiler = Criador do Perfil do Registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de debug do JIT Log Dropped Frame Statistics = Pôr no log as estátisticas da queda dos frames @@ -589,7 +589,6 @@ VSync = VSync Vulkan = Vulkan Window Size = Tamanho da janela xBRZ = xBRZ -GPU log profiler = Criador de perfil da GPU [InstallZip] Delete ZIP file = Apagar arquivo ZIP diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 6d9a2823d3..51d3c75bd7 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -265,7 +265,7 @@ Framedump tests = Testes dos dumps dos quadros Frame Profiler = Analista dos quadros GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU -GPU Log Profiler = Criador do Perfil do Registro da GPU +GPU log profiler = Criador do Perfil do Registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de depuração do JIT Log Dropped Frame Statistics = Guardar no log as estátisticas da queda dos quadros @@ -589,7 +589,6 @@ VSync = VSync Vulkan = Vulkan Window Size = Tamanho da janela xBRZ = xBRZ -GPU log profiler = Criador de perfil da GPU [InstallZip] Delete ZIP file = Eliminar ficheiro .zip diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index f7a3da53a5..1b41ee4be5 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Control rată de cadre Frame Skipping = Cadre Omise Frame Skipping Type = Frame skipping type FullScreen = Ecran intreg -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Setări trișare (pot cauza stricăciuni) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 365dd76bd1..2ae349c8bf 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Тест дампов кадров Frame Profiler = Профайлер кадров GPU Driver Test = Проверка драйвера ГП -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Профиль ГП Jit Compare = Сравнение с JIT JIT debug tools = Инструменты отладки JIT @@ -494,7 +494,6 @@ Frame Rate Control = Управление частотой кадров Frame Skipping = Пропуск кадров Frame Skipping Type = Тип пропуска кадров FullScreen = Полноэкранный режим -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Параметры хаков (могут вызывать глюки) Hardware Tessellation = Аппаратная тесселяция diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index ddd2bc8e3a..fcc6e01296 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -237,10 +237,10 @@ Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Debugloggning Enter address = Address FPU = FPU -Framedump tests = Framedump tests +Framedump tests = Framedump-tester Frame Profiler = Frame-profiler -GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU Driver Test = GPU drivrutins-test +GPU log profiler = GPU logg-profiler GPU Profile = GPU profile Jit Compare = Jit-jämförare JIT debug tools = JIT debug tools @@ -253,7 +253,7 @@ No block = Inget block Prev = Föregående Random = Slump Replace textures = Ersätt texturer -Reset = Reset +Reset = Återställ Reset limited logging = Reset limited logging RestoreDefaultSettings = Are you sure you want to restore all settings back to their defaults?\nControl mapping settings are not changed.\n\nYou can't undo this.\nPlease restart PPSSPP for the changes to take effect. RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? @@ -493,7 +493,7 @@ Frame Rate Control = Framerate-kontroll Frame Skipping = Frameskipping Frame Skipping Type = Frame skipping type FullScreen = Fullskärm -GPU log profiler = GPU log profiler +Geometry shader culling = Geoshader-klippning GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack-inställningar (kan orsaka problem) Hardware Tessellation = Hårdvarutessellering diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 2ca39ee971..08ca41605b 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Ipagkumpara ang JIT JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Pag kontrol ng frame rate Frame Skipping = Frame Skipping Frame Skipping Type = Frame skipping type FullScreen = Isakto sa Sukat ng iyong Iskrin -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack Settings (maaring magdulot ng pagloloko sa laro) Hardware Tessellation = Hardware tessellation diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 069db90253..c287d70dd8 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = ทดสอบไฟล์เฟรมดั๊มพ์ Frame Profiler = รายละเอียดของเฟรม GPU Driver Test = ทดสอบไดรเวอร์ GPU -GPU Log Profiler = ตัวแสดงค่าโปรไฟล์ GPU +GPU log profiler = ตัวแสดงค่าโปรไฟล์ GPU GPU Profile = โปรไฟล์ GPU Jit Compare = เปรียบเทียบระบบ JIT JIT debug tools = เครื่องมือตรวจสอบระบบ JIT @@ -494,7 +494,6 @@ Frame Skipping = ข้ามเฟรม Frame Skipping Type = รูปแบบการข้ามเฟรม FullScreen = เต็มหน้าจอ Geometry shader culling = การคัดแยกเฉดสีเชิงเรขาคณิต -GPU log profiler = ตัวแสดงค่าโปรไฟล์ GPU GPUReadbackRequired = คำเตือน: เกมนี้จำเป็นต้องติ๊กตั้งค่า "ข้ามการอ่านข้อมูลส่งกลับไปยัง GPU" ออกด้วย Hack Settings = ตั้งค่าการปรับแฮ็ค (อาจแสดงผลผิดพลาด) Hardware Tessellation = ฮาร์ดแวร์ เทสเซลเลชั่น diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 0e22d1d76c..902af6b866 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -242,7 +242,7 @@ FPU = FPU Framedump tests = Framedump testleri Frame Profiler = Frame profiler GPU Driver Test = GPU sürücü testi -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profili Jit Compare = Jit karşılaştırma JIT debug tools = JIT hata ayıklama araçları @@ -495,7 +495,6 @@ Frame Rate Control = Kare hızı denetimi Frame Skipping = Kare atla Frame Skipping Type = Kare atlama türü FullScreen = Tam ekran -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack ayarları (Küçük teknik problemlere neden olabilir.) Hardware Tessellation = Donanım Mozaikleme diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index dd243bc702..3d9fd33c98 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Профілі кадрів GPU Driver Test = Перевірка драйверу GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Профіль GPU Jit Compare = Порівняння з Jit JIT debug tools = Інструменти налагодження JIT @@ -493,7 +493,6 @@ Frame Rate Control = Управління частотою кадрів Frame Skipping = Пропуск кадрів Frame Skipping Type = Тип пропуску кадрів FullScreen = Повноекранний режим -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Параметри хаків (можуть викликати глюки) Hardware Tessellation = Апаратна тесселляція diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 60469d41d4..bc09ec4eb2 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Khung hồ sơ GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = So sánh Jit JIT debug tools = JIT debug tools @@ -493,7 +493,6 @@ Frame Rate Control = Điều khiển tốc độ khung hình Frame Skipping = Nhảy khuôn hình Frame Skipping Type = Frame skipping type FullScreen = Toàn màn hình -GPU log profiler = GPU log profiler GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Thiết lập hack (sẽ bị lỗi) Hardware Tessellation = Lót phần cứng diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 5a12fb15b9..8d201ecd19 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -240,7 +240,7 @@ FPU = FPU Framedump tests = 帧转储测试 Frame Profiler = 帧分析器 GPU Driver Test = GPU驱动程序测试 -GPU Log Profiler = GPU日志分析器 +GPU log profiler = GPU日志分析器 GPU Profile = GPU分析器 Jit Compare = Jit比较 JIT debug tools = JIT调试工具 @@ -493,7 +493,6 @@ Frame Rate Control = 帧率控制 Frame Skipping = 跳帧 Frame Skipping Type = 跳帧方式 FullScreen = 全屏幕 -GPU log profiler = GPU日志分析器 GPUReadbackRequired = 警告: 此游戏需要"跳过GPU回读"设置为关闭 Hack Settings = 渲染修正(可能引发故障) Hardware Tessellation = 硬件曲面细分 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 34c762e3c2..ce51988185 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -241,7 +241,7 @@ Framedump tests = 影格傾印測試 Frame Profiler = 影格分析工具 GPU Driver Test = GPU 驅動程式測試 GPU Profile = GPU 設定檔 -GPU Log Profiler = GPU 記錄分析工具 +GPU log profiler = GPU 記錄分析工具 Jit Compare = JIT 比較 JIT debug tools = JIT 偵錯工具 Log Dropped Frame Statistics = 記錄捨棄影格統計資料 @@ -565,7 +565,6 @@ VSync = 垂直同步 Vulkan = Vulkan Window Size = 視窗大小 xBRZ = xBRZ -GPU log profiler = GPU 記錄分析工具 [InstallZip] Delete ZIP file = 刪除 ZIP 檔案 From 4a0dcfdb6947b53e066b513ebf486366c82092ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 10:10:34 +0100 Subject: [PATCH 457/715] Add missing strings to en_US.ini --- UI/GameSettingsScreen.cpp | 30 +++++++++++++++--------------- assets/lang/en_US.ini | 5 ++++- assets/lang/sv_SE.ini | 2 ++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 02d975757e..7ba8120ce9 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1762,6 +1762,21 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures"))); list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures"))); + Choice *createTextureIni = list->Add(new Choice(dev->T("Create/Open textures.ini file for current game"))); + createTextureIni->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile); + createTextureIni->SetEnabledFunc([&] { + if (!PSP_IsInited()) + return false; + + // Disable the choice to Open/Create if the textures.ini file already exists, and we can't open it due to platform support limitations. + if (!System_GetPropertyBool(SYSPROP_SUPPORTS_OPEN_FILE_IN_EDITOR)) { + if (hasTexturesIni_ == HasIni::MAYBE) + hasTexturesIni_ = TextureReplacer::IniExists(g_paramSFO.GetDiscID()) ? HasIni::YES : HasIni::NO; + return hasTexturesIni_ != HasIni::YES; + } + return true; + }); + Draw::DrawContext *draw = screenManager()->getDrawContext(); // Experimental, will move to main graphics settings later. @@ -1810,21 +1825,6 @@ void DeveloperToolsScreen::CreateViews() { // Reconsider whenever recreating views. hasTexturesIni_ = HasIni::MAYBE; - - Choice *createTextureIni = list->Add(new Choice(dev->T("Create/Open textures.ini file for current game"))); - createTextureIni->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile); - createTextureIni->SetEnabledFunc([&] { - if (!PSP_IsInited()) - return false; - - // Disable the choice to Open/Create if the textures.ini file already exists, and we can't open it due to platform support limitations. - if (!System_GetPropertyBool(SYSPROP_SUPPORTS_OPEN_FILE_IN_EDITOR)) { - if (hasTexturesIni_ == HasIni::MAYBE) - hasTexturesIni_ = TextureReplacer::IniExists(g_paramSFO.GetDiscID()) ? HasIni::YES : HasIni::NO; - return hasTexturesIni_ != HasIni::YES; - } - return true; - }); } void DeveloperToolsScreen::onFinish(DialogResult result) { diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index e049ada474..de41e305d8 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -256,6 +256,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -479,6 +480,7 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -839,7 +841,7 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color -RedBlue = Red/Blue +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen @@ -1150,6 +1152,7 @@ Increase size = Increase size Interpreter = Interpreter IO timing method = I/O timing method IR Interpreter = IR interpreter +Language = Language Memory Stick Folder = Memory Stick folder Memory Stick inserted = Memory Stick inserted MHz, 0:default = MHz, 0 = default diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index fcc6e01296..c7703e446d 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -547,6 +547,7 @@ Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet Speed Hacks = Speed-hacks (kan orsaka renderingsproblem) +Stereo rendering = Stereo-rendering Stretch = Stretch Texture Filter = Texturfilter Texture Filtering = Texturfiltrering @@ -816,6 +817,7 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Röd/Blå glasögon Saturation = Saturation Scanlines = Scanlines Sharpen = Sharpen From 39e835b320e22b24627ec43096c97fea189dcc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 10:10:52 +0100 Subject: [PATCH 458/715] Add missing lines to other languages --- assets/lang/ar_AE.ini | 8 ++++++++ assets/lang/az_AZ.ini | 8 ++++++++ assets/lang/bg_BG.ini | 8 ++++++++ assets/lang/ca_ES.ini | 8 ++++++++ assets/lang/cz_CZ.ini | 8 ++++++++ assets/lang/da_DK.ini | 8 ++++++++ assets/lang/de_DE.ini | 8 ++++++++ assets/lang/dr_ID.ini | 8 ++++++++ assets/lang/es_ES.ini | 8 ++++++++ assets/lang/es_LA.ini | 8 ++++++++ assets/lang/fa_IR.ini | 8 ++++++++ assets/lang/fi_FI.ini | 8 ++++++++ assets/lang/fr_FR.ini | 8 ++++++++ assets/lang/gl_ES.ini | 8 ++++++++ assets/lang/gr_EL.ini | 8 ++++++++ assets/lang/he_IL.ini | 8 ++++++++ assets/lang/he_IL_invert.ini | 8 ++++++++ assets/lang/hr_HR.ini | 8 ++++++++ assets/lang/hu_HU.ini | 8 ++++++++ assets/lang/id_ID.ini | 8 ++++++++ assets/lang/it_IT.ini | 8 ++++++++ assets/lang/ja_JP.ini | 8 ++++++++ assets/lang/jv_ID.ini | 8 ++++++++ assets/lang/ko_KR.ini | 8 ++++++++ assets/lang/lo_LA.ini | 8 ++++++++ assets/lang/lt-LT.ini | 8 ++++++++ assets/lang/ms_MY.ini | 8 ++++++++ assets/lang/nl_NL.ini | 8 ++++++++ assets/lang/no_NO.ini | 8 ++++++++ assets/lang/pl_PL.ini | 8 ++++++++ assets/lang/pt_BR.ini | 8 ++++++++ assets/lang/pt_PT.ini | 8 ++++++++ assets/lang/ro_RO.ini | 8 ++++++++ assets/lang/ru_RU.ini | 10 +++++++++- assets/lang/sv_SE.ini | 5 +++++ assets/lang/tg_PH.ini | 8 ++++++++ assets/lang/tr_TR.ini | 8 ++++++++ assets/lang/uk_UA.ini | 8 ++++++++ assets/lang/vi_VN.ini | 8 ++++++++ assets/lang/zh_CN.ini | 8 ++++++++ assets/lang/zh_TW.ini | 8 ++++++++ 41 files changed, 326 insertions(+), 1 deletion(-) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 126cd55b67..d862a5b530 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -501,6 +501,7 @@ Frame Rate Control = ‎التحكم في معدل الإطارات Frame Skipping = ‎تخطي الإطارات Frame Skipping Type = Frame skipping type FullScreen = ‎الشاشة الكاملة +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -554,6 +555,8 @@ Software Skinning = ‎طلاء برمجي SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = ‎السرعة Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = ‎المط Texture Filter = ‎منقي الرسوم Texture Filtering = ‎مفلتر الرسوم @@ -839,11 +842,13 @@ Brightness = Brightness Cartoon = ‎كرتوني CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = ‎CRT خطوط الفحص FXAA = ‎FXAA منعم الحواف Gamma = Gamma Grayscale = ‎التدرج الرمادي +GreenLevel = GreenLevel Intensity = Intensity InverseColors = ‎عكس الألوان MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -852,9 +857,11 @@ NaturalA = Natural Colors (no blur) Off = ‎مغلق Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = ‎تنعيم الحواف +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1098,6 +1105,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = ‎اللغة Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 3bd1679316..d7747c4d18 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -493,6 +493,7 @@ Frame Rate Control = Framerate control Frame Skipping = Kvadrat Keçid et (Sürət) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 12d2beeefa..2c3cda2d84 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -493,6 +493,7 @@ Frame Rate Control = Framerate control Frame Skipping = Прескачане на кадри Frame Skipping Type = Frame skipping type FullScreen = Цял екран +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Скорост Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Текстурно филтриране Texture Filtering = Текстурно филтриране @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Анимация CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Сива скала +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Противоположни цветове MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Изключено Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Изостряне +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Език Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index ceefe047c1..4c1a0f9ec6 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -493,6 +493,7 @@ Frame Rate Control = Framerate control Frame Skipping = Saltar fotogrames (skip) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Llengua Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index c350c3f093..dbb664fefa 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -493,6 +493,7 @@ Frame Rate Control = Kontrola frekvence snímků Frame Skipping = Přeskakování snímků Frame Skipping Type = Frame skipping type FullScreen = Režim celé obrazovky +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Nastavení hacků (Mohou způsobit problémy) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Textury aplikuje software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Rychlost Speed Hacks = Speed Hacks (Mohou způsobit problémy) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Roztažení Texture Filter = Filtr textur Texture Filtering = Filtrování textur @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Animák CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Skenovací řádky CRT FXAA = Vyhlazování hran FXAA Gamma = Gamma Grayscale = Stupně šedi +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverzní barvy MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Vypnuto Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Skenovací řádky (CRT) Sharpen = Zostřit +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Jazyk Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 9b961c2cd3..f55140f39b 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -493,6 +493,7 @@ Frame Rate Control = Frameratekontrol Frame Skipping = Frameskipping Frame Skipping Type = Frame skipping type FullScreen = Fuldskærm +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack indstillinger (kan give fejl) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Kombiner begrænset model tegning af CPU, hurtigere i fleste spil Speed = Hastighed Speed Hacks = Speed Hacks (kan give fejl) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Texturfilter Texture Filtering = Texturfiltrering @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Tegnefilm CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlinier FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Gråskala +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverterede farver MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Slukket Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlinier (CRT) Sharpen = Gør skarpere +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Sprog Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index aef55f827c..0e183a0dfb 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -493,6 +493,7 @@ Frame Rate Control = Frameratenkontrolle Frame Skipping = Bilder überspringen Frame Skipping Type = Typ für Bilder überspringen FullScreen = Vollbild +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hacks (kann zu Fehlern führen) Hardware Tessellation = Hardware Tessellation @@ -546,6 +547,8 @@ Software Skinning = Software Skinning SoftwareSkinning Tip = Reduziert Grafikbefehle und schneller in Spielen mit erweiterter Skinning-Technik, in anderen Spielen langsamer Speed = Geschwindigkeit Speed Hacks = Speed Hacks (kann zu Fehlern führen) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Strecken Texture Filter = Texturfilter Texture Filtering = Texturfilterung @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT Scanlines FXAA = FXAA Gamma = Gamma Grayscale = Graustufen +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Farben invertieren MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natürliche Farben (kein Blur) Off = Aus Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines Sharpen = Schärfen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Sprache Memory Stick folder = Memory Stick Ordner Memory Stick size = Memory Stick size diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index aa20527960..8f8340c886 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -493,6 +493,7 @@ Frame Rate Control = Atoro'i FRna Frame Skipping = Frameskip Frame Skipping Type = Frame skipping type FullScreen = Layar pol +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Lassinna Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Panyaring Texture Texture Filtering = Saring i Texture @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Bahasa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index d957ee0eb2..d41857869a 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -493,6 +493,7 @@ Frame Rate Control = Control de tasa de cuadros (FPS) Frame Skipping = Saltar cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (causarán errores gráficos) Hardware Tessellation = Teselado por hardware @@ -546,6 +547,8 @@ Software Skinning = "Skinning" por software SoftwareSkinning Tip = Reduce la carga de dibujado, rápido en juegos con técnicas de skinning avanzadas, pero lento en otros. Speed = Velocidad Speed Hacks = Speed Hacks (causarán errores gráficos) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas @@ -831,11 +834,13 @@ Brightness = Brillo Cartoon = Dibujos animados CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Corrección de color +ColorPreservation = Color preservation Contrast = Contraste CRT = Pantalla de tubo (CRT) FXAA = Antialiasing por FXAA Gamma = Gamma Grayscale = Escala de grises +GreenLevel = GreenLevel Intensity = Intensidad InverseColors = Invertir colores MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Colores naturales (sin difuminar) Off = No Power = Poder PSPColor = Paleta de colores PSP +RedBlue = Red/Blue glasses Saturation = Saturación Scanlines = Monitor con "scanlines" Sharpen = Afilado +SideBySide = Side by side (SBS) SSAA(Gauss) = Super muestreo AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes +Game crashed = Game crashed Language = Idioma Memory Stick folder = Directorio de Memory Stick Memory Stick size = Cambiar tamaño de Memory Stick (GB) diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 6f570cf71b..e36fd8c31c 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -493,6 +493,7 @@ Frame Rate Control = Control de Framerate Frame Skipping = Salto de cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (puede causar glitches) Hardware Tessellation = Teselado por Hardware @@ -546,6 +547,8 @@ Software Skinning = Skineado por software SoftwareSkinning Tip = Combina dibujados de modelo de skineado en la CPU. Acelera muchos juegos pero ralentiza otros. Speed = Velocidad Speed Hacks = Speed Hacks (puede causar glitches) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas @@ -831,11 +834,13 @@ Brightness = Brillo Cartoon = Caricaturas CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Corrección de color +ColorPreservation = Color preservation Contrast = Contraste CRT = Pantalla de tubo (CRT) FXAA = Antialiasing por FXAA Gamma = Gamma Grayscale = Escala de grises +GreenLevel = GreenLevel Intensity = Intensidad InverseColors = Invertir colores MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Colores naturales (sin desenfoques) Off = Apagado Power = Power PSPColor = Paleta de colores PSP +RedBlue = Red/Blue glasses Saturation = Saturación Scanlines = Líneas de escaneo (CRT) Sharpen = Afilado +SideBySide = Side by side (SBS) SSAA(Gauss) = Super muestreo AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes +Game crashed = Game crashed Language = Idioma Memory Stick folder = Carpeta del Memory Stick Memory Stick size = Tamaño del Memory Stick diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 775f1352f4..54e119c4f2 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -493,6 +493,7 @@ Frame Rate Control = ‎کنترل سرعت فریم Frame Skipping = ‎ردکردن فریم Frame Skipping Type = Frame skipping type FullScreen = ‎تمام صفحه +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ‎تنظیمات هک ها (میتواند باعث باگ شود) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = ‎در اکثر بازی ها سریع تر ،CPU دار در skin ترکیب رسم مدل های Speed = ‎سرعت Speed Hacks = Speed Hacks ‎(میتواند باعث باگ شود) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = ‎کشیدن Texture Filter = ‎فیلتر تکسچر Texture Filtering = ‎فیلتر کردن تکسچر @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = ‎زبان Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index c1ae6df728..260e4d30c7 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -493,6 +493,7 @@ Frame Rate Control = Framerate control Frame Skipping = Ruudun ohitus Frame Skipping Type = Frame skipping type FullScreen = Koko näyttö +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Nopeus Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Tekstuurisuodatin Texture Filtering = Tekstuurin suodatus @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 568680d1ee..89a4cde7ce 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -493,6 +493,7 @@ Frame Rate Control = Contrôle de la fréquence de rafraîchissement des images Frame Skipping = Saut d'images Frame Skipping Type = Type de saut d'images FullScreen = Plein écran +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Paramètres "hack" (crée des bugs graphiques) Hardware Tessellation = Tessellation matérielle @@ -546,6 +547,8 @@ Software Skinning = Enveloppe logicielle SoftwareSkinning Tip = Combine l'affichage des modèles enveloppés sur le CPU, plus rapide dans la plupart des jeux Speed = Vitesse Speed Hacks = Speed Hacks (crée des bugs graphiques) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Étirement Texture Filter = Filtre de textures Texture Filtering = Filtrage des textures @@ -831,11 +834,13 @@ Brightness = Luminosité Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Correction des couleurs +ColorPreservation = Color preservation Contrast = Contraste CRT = Lignes de balayage CRT FXAA = Anticrénelage FXAA Gamma = Gamma Grayscale = Niveaux de gris +GreenLevel = GreenLevel Intensity = Intensité InverseColors = Couleurs inversées MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Couleurs naturelles (sans flou) Off = Aucun Power = Puissance PSPColor = Couleurs PSP +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Lignes de balayage Sharpen = Plus net +SideBySide = Side by side (SBS) SSAA(Gauss) = Anticrénelage supersampling (Gauss) Tex4xBRZ = 4×BRZ TexMMPX = MMPX @@ -1081,6 +1088,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Langue Memory Stick folder = Changer le dossier de la Memory Stick Memory Stick size = Changer la taille de la Memory Stick (Go) diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 322b5811b9..4f301f1147 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -493,6 +493,7 @@ Frame Rate Control = Control de tasa de cadros (FPS) Frame Skipping = Saltar cadros Frame Skipping Type = Frame skipping type FullScreen = Pantalla completa +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Axustes de hacks (causarán erros gráficos) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = «Skinning» por software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Velocidade Speed Hacks = Speed Hacks (causarán erros gráficos) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Debuxos animados CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Monitor con «scanlines» (CRT) FXAA = Antialiasing FXAA Gamma = Gamma Grayscale = Escala de grises +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Invertir cores MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Non Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Afiado +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Idioma Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 7629b1fcf0..0fd4b4889b 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -493,6 +493,7 @@ Frame Rate Control = Ρυθμίσεις Ρυθμού Καρέ Frame Skipping = Παράκαμψη Καρέ Frame Skipping Type = Frame skipping type FullScreen = Πλήρης Οθόνη +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ρυθμίσεις Hack Hardware Tessellation = Tessellation Υλικού @@ -546,6 +547,8 @@ Software Skinning = Εκδορά Λογισμικού SoftwareSkinning Tip = Συνδυασμός μοντέλου στην CPU, γρηγορότερο στα περισσότερα παιχνίδια Speed = Ταχύτητα Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Επέκταση Texture Filter = Φίλτρο Υφών Texture Filtering = Φιλτράρισμα Υφών @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Καρτούν CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Γραμμές σάρωσης CRT FXAA = Εξομάλυνση κορυφών FXAA Gamma = Gamma Grayscale = Ασπρόμαυρο +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Αντιστροφή Χρωμάτων MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Ανενεργό Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Γραμμές Σάρωσης (CRT) Sharpen = Όξυνση +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Γλώσσα Memory Stick folder = Αλλαγή φακέλου Memory Stick Memory Stick size = Memory Stick size diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index bcf6ee3e7b..12d2b9dfd9 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -493,6 +493,7 @@ Frame Rate Control = שליטה על קצב פריימים Frame Skipping = דלג על פריימים Frame Skipping Type = Frame skipping type FullScreen = מסך מלא +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = מהירות Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = קידוד טקסטורה Texture Filtering = קידוד טקסטורה @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = שפה Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 196ad8c6b7..a455edd43d 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -493,6 +493,7 @@ Frame Rate Control = םימיירפ בצק לע הטילש Frame Skipping = םימיירפ לע גלד Frame Skipping Type = Frame skipping type FullScreen = אלמ ךסמ +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = תוריהמ Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = הרוטסקט דודיק Texture Filtering = הרוטסקט דודיק @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = הפש Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index a4ee6b93fb..dd275caed9 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -493,6 +493,7 @@ Frame Rate Control = Framerate kontrole Frame Skipping = Preskakanje sličica Frame Skipping Type = Vrsta preskakanja sličica FullScreen = Puni zaslon +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Opcije hakiranja (može uzrokovati glitcheve) Hardware Tessellation = Hardware tesselacija @@ -546,6 +547,8 @@ Software Skinning = Skiniranje softvera SoftwareSkinning Tip = Kombiniraj skinirane modele crteža na CPU, brže u većini igara Speed = Brzina Speed Hacks = Speed Hacks (može uzrokovati glitcheve) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Rastezanje Texture Filter = Filtar tekstura Texture Filtering = Filtriranje tekstura @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Izmijeni boje MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Prirodne boje (bez zamućivanja) Off = Isključeno Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Naoštriti +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Jezik Memory Stick folder = Promijeni mapu Memorijskoga sticka Memory Stick size = Memory Stick size diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 92d87c5766..09bf6c6476 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -493,6 +493,7 @@ Frame Rate Control = Képkocka sebesség szabályozása Frame Skipping = Képkocka kihagyás Frame Skipping Type = Képkocka kihagyás típusa FullScreen = Teljes képernyő +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack beállítások (ezek HIBÁKAT OKOZHATNAK) Hardware Tessellation = Hardveres tesszeláció @@ -546,6 +547,8 @@ Software Skinning = Szoftveres "skinning" SoftwareSkinning Tip = "Skinning" művelet elvégzése a processzoron. Sok játék esetében gyorsabb. Speed = Sebesség Speed Hacks = Speed Hacks (ezek HIBÁKAT OKOZHATNAK) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Nyújtás Texture Filter = Textúra szűrés Texture Filtering = Textúra szűrés @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Rajzfilm CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Színkorrekció +ColorPreservation = Color preservation Contrast = Kontraszt CRT = CRT FXAA = FXAA élsimítás Gamma = Gamma Grayscale = Szürkeárnyalatos +GreenLevel = GreenLevel Intensity = Erősség InverseColors = Színek megfordítása MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Természetes színek (elmosódás nélkül) Off = Ki Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Telítettség (szaturáció) Scanlines = Csíkozás Sharpen = Élesítés +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Nyelv Memory Stick folder = Memory Stick mappa megváltoztatása Memory Stick size = Memory Stick size diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 6cd340b266..ff777e4581 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -493,6 +493,7 @@ Frame Rate Control = Kontrol laju bingkai Frame Skipping = Lewati laju bingkai Frame Skipping Type = Jenis lewati laju bingkai FullScreen = Layar penuh +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas pengaturan (menyebabkan kecacatan) Hardware Tessellation = Pengujian perangkat keras @@ -546,6 +547,8 @@ Software Skinning = Pengkulitan perangkat lunak SoftwareSkinning Tip = Menggabungkan model berkulit pada CPU, lebih cepat di kebanyakan permainan Speed = Kecepatan Speed Hacks = Speed Hacks (menyebabkan kecacatan) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Peregangan Texture Filter = Filter tekstur Texture Filtering = Pemfilteran tekstur @@ -831,11 +834,13 @@ Brightness = Kecerahan Cartoon = Kartun CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Koreksi Warna +ColorPreservation = Color preservation Contrast = Kontras CRT = CRT FXAA = Mengurangi Artifak Distorsi (FXAA) Gamma = Gamma Grayscale = Abu-abu +GreenLevel = GreenLevel Intensity = Intensitas InverseColors = Warna Terbalik MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Warna Natural (tidak kabur) Off = Mati Power = Daya PSPColor = Warna PSP +RedBlue = Red/Blue glasses Saturation = Saturasi Scanlines = Pindai Garis (CRT) Sharpen = Pertajam +SideBySide = Side by side (SBS) SSAA(Gauss) = SSAA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Pewarnaan Error: load undo state is from a different game = Kesalahan: memuat status yang berasal dari permainan yang berbeda Failed to load state for load undo. Error in the file system. = Gagal memuat status untuk membatalkan pemuatan. Kesalahan dalam sistem berkas. Floating symbols = Simbol mengambang +Game crashed = Game crashed Language = Bahasa Memory Stick folder = Berkas Memory Stick Memory Stick size = Ukuran Memory Stick diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index d0fb006741..0af6c2d099 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -494,6 +494,7 @@ Frame Rate Control = Controllo Framerate Frame Skipping = Salto frame Frame Skipping Type = Tipo di Salto frame FullScreen = Schermo Intero +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Impostazioni Hack (causerà dei problemi, sicuramente) Hardware Tessellation = Tassellazione Hardware @@ -547,6 +548,8 @@ Software Skinning = Software Skinning SoftwareSkinning Tip = Combina la visualizzazione di modelli disegnati dalla CPU, più veloce nella maggior parte dei giochi Speed = Velocità Speed Hacks = Speed Hacks (causerà dei problemi) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Adatta al Display Texture Filter = Filtro delle texture Texture Filtering = Filtraggio delle texture @@ -803,11 +806,13 @@ Brightness = Luminosità Cartoon = Disegno CatmullRom = Upscaler Bicubico (Catmull-Rom) ColorCorrection = Correzione dei colori +ColorPreservation = Color preservation Contrast = Contrasto CRT = Linee di scansione CRT FXAA = Antialiasing FXAA Gamma = Gamma Grayscale = Scala di grigi +GreenLevel = GreenLevel Intensity = Intensità InverseColors = Colori invertiti MitchellNetravali = Upscaler Bicubico (Mitchell-Netravali) @@ -816,9 +821,11 @@ NaturalA = Colori naturali (nessuna sfocatura) Off = Nessuno Power = Potenza PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturazione Scanlines = Linee di scansione (CRT) Sharpen = Maggior nitidezza +SideBySide = Side by side (SBS) SSAA(Gauss) = Supercampionamento AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1091,6 +1098,7 @@ Color Tint = Tonalità colore Error: load undo state is from a different game = Errore: lo stato annullato proviene da un gioco diverso. Failed to load state for load undo. Error in the file system. = Impossibile caricare lo stato da un caricamento annullato. Errore nel file system. Floating symbols = Simboli fluttuanti +Game crashed = Game crashed Language = Lingua Memory Stick folder = Cartella della Memory Stick Memory Stick size = Cambia dimensioni Memory Stick diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index d54eeceac2..c340110427 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -493,6 +493,7 @@ Frame Rate Control = フレームレートのコントロール Frame Skipping = フレームスキップ Frame Skipping Type = フレームスキップのタイプ FullScreen = フルスクリーン +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ハックの設定 (不具合あり) Hardware Tessellation = ハードウェアテッセレーション @@ -546,6 +547,8 @@ Software Skinning = ソフトウェアスキニング SoftwareSkinning Tip = スキンモデルの描画をCPUでまとめて行う。ほとんどのゲームが高速化します Speed = 速度 Speed Hacks = Speed Hacks (不具合あり) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = 拡大 Texture Filter = テクスチャフィルタ Texture Filtering = テクスチャフィルタリング @@ -802,11 +805,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -815,9 +820,11 @@ NaturalA = Natural Colors (no blur) Off = オフ Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1088,6 +1095,7 @@ Change CPU Clock = CPUクロックを変更する (不安定) Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = 言語 Memory Stick folder = メモリースティックフォルダを変更する Memory Stick size = メモリースティックの容量の変更 (GB) diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 82dac80b9d..36b869e9f2 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -493,6 +493,7 @@ Frame Rate Control = Kontrol Frame-rate Frame Skipping = Frame-skip Frame Skipping Type = Frame skipping type FullScreen = Layar Penuh +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas setelsn (nyebabake glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Kacepetan Speed Hacks = Speed Hacks (nyebabake glitches) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Penyaring Tekstur Texture Filtering = Penyaring Tekstur @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Kartun CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Keabu-abuan +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Warna kebalik MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Ora Aktif Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Basa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 1d794783cf..f7cf4002ec 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -493,6 +493,7 @@ Frame Rate Control = 프레임속도 제어 Frame Skipping = 프레임 생략 Frame Skipping Type = 프레임 생략 유형 FullScreen = 전체화면 +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = 핵 설정 (결함을 일으킬 수 있음) Hardware Tessellation = 하드웨어 조각화 @@ -546,6 +547,8 @@ Software Skinning = 소프트웨어 스키닝 SoftwareSkinning Tip = 대부분의 게임에서 더 빠르게 CPU에서 스킨 모델 드로우를 결합합니다. Speed = 속도 Speed Hacks = Speed Hacks (결함을 일으킬 수 있음) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = 늘이기 Texture Filter = 텍스처 필터링 Texture Filtering = 텍스처 필터링 @@ -800,11 +803,13 @@ Bloom = 블룸 Brightness = 밝기 Cartoon = 카툰 ColorCorrection = 색상 교정 +ColorPreservation = Color preservation Contrast = 명암 CRT = CRT 스캔라인 FXAA = FXAA 안티 에일리어싱 Gamma = 감마 Grayscale = 그레이스케일 +GreenLevel = GreenLevel Intensity = 강도 InverseColors = 색 반전 Natural = 자연스러운 색상 @@ -812,9 +817,11 @@ NaturalA = 자연스러운 색상 (흐림 없음) Off = 끔 Power = 전원 PSPColor = PSP 색상 +RedBlue = Red/Blue glasses Saturation = 채도 Scanlines = 스캔라인 (CRT) Sharpen = 선명함 +SideBySide = Side by side (SBS) SSAA(Gauss) = 슈퍼샘플 AA (가우스) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1098,6 +1105,7 @@ AVI Dump started. = AVI 덤프가 시작됨 AVI Dump stopped. = AVI 덤프가 중지됨 Cache ISO in RAM = RAM에 전체 ISO 캐시 Change CPU Clock = 에뮬레이트된 PSP의 CPU 클럭 변경 (불안정) +Game crashed = Game crashed Language = 언어 Memory Stick folder = 메모리 스틱 폴더 Memory Stick size = 메모리 스틱 크기 diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 7b0630a1e0..2773dd95f1 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -493,6 +493,7 @@ Frame Rate Control = ຄວບຄຸມເຟຣມເຣດ Frame Skipping = ຂ້າມເຟຣມ Frame Skipping Type = Frame skipping type FullScreen = ເຕັມໜ້າຈໍ +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ການຕັ້ງຄ່າແຮັກ Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = ຊ໋ອບແວຣ໌ສກິນນິງ SoftwareSkinning Tip = ປະສານໂມເດລພື້ນຜິວໃຫ້ຂຽນຜ່ານ CPU, ເກມສ່ວນໃຫຍ່ໃຊ້ແລ້ວໄວຂຶ້ນ Speed = ຄວາມໄວ Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = ດຶງເຕັມຈໍ Texture Filter = ໂຕຕອງພື້ນຜິວ Texture Filtering = ຕອງພື້ນຜິວ @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT FXAA = FXAA Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = InverseColors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = ປິດ Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = ພາສາ Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 89f93a0027..d7f0439ec5 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -493,6 +493,7 @@ Frame Rate Control = Kadrų kontrolė Frame Skipping = Kadrų praleidimas Frame Skipping Type = Frame skipping type FullScreen = Pilnas ekranas +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Modifikavimo parametrai (gali sukelti problemų) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Programinės įrangos "nulupimas" SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Greitis Speed Hacks = Speed Hacks (gali sukelti problemų) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Tekstūrų filtravimas Texture Filtering = Tekstūrų filtravimas @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Animacinis filmas CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT skenavimo linjos FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Perkeisti spalvas MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Išjungti Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = CRT skenavimo linjos Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Kalba Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 0b2067459d..c0fcc500c2 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -493,6 +493,7 @@ Frame Rate Control = Kawalan kadar Frame Frame Skipping = Pelompatan Frame Frame Skipping Type = Frame skipping type FullScreen = Skrin penuh +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Godam tetapan (mungkin menyebabkan gangguan) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Pembalutan Perisian SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Laju Speed Hacks = Speed Hacks (mungkin menyebabkan gangguan) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Penapis Tekstur Texture Filtering = Penapisan Tekstur @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Kartun CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Anti aliasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Terbalikkan warna MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Tutup Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Ketajaman +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Bahasa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index ec56f9f198..4691e9eddd 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -493,6 +493,7 @@ Frame Rate Control = Framerateinstellingen Frame Skipping = Frames overslaan Frame Skipping Type = Frame skipping type FullScreen = Volledig scherm +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hackinstellingen (kan glitches veroorzaken) Hardware Tessellation = Hardwarebetegeling @@ -546,6 +547,8 @@ Software Skinning = Skinning via software SoftwareSkinning Tip = Vermindert aantal renders en is sneller in games die de geavanceerde skinningtechniek gebruiken, maar voor sommige games trager Speed = Snelheid Speed Hacks = Speed Hacks (kan glitches veroorzaken) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Uitrekken Texture Filter = Texturefilter Texture Filtering = Texturefilter @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT-scanlijnen FXAA = FXAA-antialiasing Gamma = Gamma Grayscale = Grijswaarden +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Omgekeerde kleuren MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Uit Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlijnen (CRT) Sharpen = Verscherpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Taal Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 9958ee308a..4835560145 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -493,6 +493,7 @@ Frame Rate Control = Framerate control Frame Skipping = Ramme Hoppe over Frame Skipping Type = Frame skipping type FullScreen = Fullskjerm +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Tekstur filtrering Texture Filtering = Tekstur filtrering @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Gråtoneskala +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index ec3efdc9be..8dd0476756 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -493,6 +493,7 @@ Frame Rate Control = Kontrola klatek na sekundę Frame Skipping = Pomijanie klatek Frame Skipping Type = Tryb pomijania klatek FullScreen = Pełny ekran +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ustawienia specjalne (powodują problemy) Hardware Tessellation = Sprzętowa teselacja @@ -546,6 +547,8 @@ Software Skinning = Programowy skinning SoftwareSkinning Tip = Łączy na CPU wywołania rysujące modele z animacjami, przyspieszenie w większości gier Speed = Prędkość (procentowo) Speed Hacks = Speed Hacks (powodują problemy) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Rozciąganie Texture Filter = Filtrowanie tekstur Texture Filtering = Filtrowanie tekstur @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Komiks CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Imitacja monitora CRT FXAA = Wygładzanie FXAA Gamma = Gamma Grayscale = Skala szarości +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Odwrócenie kolorów MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Naturalne kolory (bez rozmycia) Off = Wyłącz Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Linie skanowania Sharpen = Wyostrzenie +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Język Memory Stick folder = Zmień folder Karty Pamięci Memory Stick size = Rozmiar Karty Pamięci diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 4f8ed95368..0cbb4a0b42 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -517,6 +517,7 @@ Frame Rate Control = Controle da taxa dos frames Frame Skipping = Pulo dos frames Frame Skipping Type = Tipo de pulo dos frames FullScreen = Tela cheia +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Configurações dos hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por hardware @@ -570,6 +571,8 @@ Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade Speed Hacks = Speed Hacks (pode causar erros gráficos) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Esticamento Texture Filter = Filtragem das texturas Texture Filtering = Filtragem das texturas @@ -824,11 +827,13 @@ Bloom = Bloom Brightness = Brilho Cartoon = Cartoon ColorCorrection = Correção das cores +ColorPreservation = Color preservation Contrast = Contraste CRT = Scanlines do CRT FXAA = Anti-aliasing do FXAA Gamma = Gama Grayscale = Tons de cinza +GreenLevel = GreenLevel Intensity = Intensidade InverseColors = Cores invertidas Natural = Cores naturais @@ -836,9 +841,11 @@ NaturalA = Cores naturais (sem borrão) Off = Desligado Power = Energia PSPColor = Cor do PSP +RedBlue = Red/Blue glasses Saturation = Saturação Scanlines = Scanlines (CRT) Sharpen = Aprimorado +SideBySide = Side by side (SBS) SSAA(Gauss) = Super-amostragem do AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1103,6 +1110,7 @@ AVI Dump started. = Dump do AVI iniciado AVI Dump stopped. = Dump do AVI parado Cache ISO in RAM = Pôr a ISO inteira na RAM Change CPU Clock = Mudar o clock da CPU do PSP emulado (instável) +Game crashed = Game crashed Language = Idioma Memory Stick folder = Pasta do cartão de memória Memory Stick size = Tamanho do cartão de memória diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 51d3c75bd7..678779d5b1 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -517,6 +517,7 @@ Frame Rate Control = Controle da taxa dos quadros Frame Skipping = Pulo dos quadros Frame Skipping Type = Tipo de pulo dos quadros FullScreen = Tela Cheia +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Definições dos Hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por Hardware @@ -570,6 +571,8 @@ Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade Speed Hacks = Speed Hacks (pode causar erros gráficos) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Esticamento Texture Filter = Filtração das texturas Texture Filtering = Filtração das texturas @@ -824,11 +827,13 @@ Bloom = Bloom Brightness = Brilho Cartoon = Estilo Cartoon ColorCorrection = Correção das cores +ColorPreservation = Color preservation Contrast = Contraste CRT = Scanlines do CRT FXAA = Anti-aliasing do FXAA Gamma = Gama Grayscale = Tons de cinza +GreenLevel = GreenLevel Intensity = Intensidade InverseColors = Cores invertidas Natural = Cores naturais @@ -836,9 +841,11 @@ NaturalA = Cores naturais (sem borrão) Off = Desligado Power = Energia PSPColor = Cor do PSP +RedBlue = Red/Blue glasses Saturation = Saturação Scanlines = Scanlines (CRT) Sharpen = Aprimorado +SideBySide = Side by side (SBS) SSAA(Gauss) = Super-amostragem do AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1103,6 +1110,7 @@ AVI Dump started. = Dump do AVI iniciado AVI Dump stopped. = Dump do AVI parado Cache ISO in RAM = Colocar a ISO inteira na RAM Change CPU Clock = Mudar o clock da CPU do PSP emulado (instável) +Game crashed = Game crashed Language = Idioma Memory Stick folder = Pasta do Cartão de Memória Memory Stick size = Tamanho do Cartão de Memória diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 1b41ee4be5..95e3d6bb7f 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -493,6 +493,7 @@ Frame Rate Control = Control rată de cadre Frame Skipping = Cadre Omise Frame Skipping Type = Frame skipping type FullScreen = Ecran intreg +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Setări trișare (pot cauza stricăciuni) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Skinning cu software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Viteză Speed Hacks = Speed Hacks (pot cauza stricăciuni) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Filtru texturi Texture Filtering = Filtrare texturi @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Culori Inversate MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Oprit Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Limbă Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 2ae349c8bf..aced6ead7b 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -494,6 +494,7 @@ Frame Rate Control = Управление частотой кадров Frame Skipping = Пропуск кадров Frame Skipping Type = Тип пропуска кадров FullScreen = Полноэкранный режим +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Параметры хаков (могут вызывать глюки) Hardware Tessellation = Аппаратная тесселяция @@ -547,6 +548,8 @@ Software Skinning = Программная заливка SoftwareSkinning Tip = Объединяет вызовы отрисовки моделей с заливкой на ЦП, быстрее во многих играх Speed = Скорость Speed Hacks = Speed Hacks (могут вызывать глюки) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Растягивание Texture Filter = Текстурный фильтр Texture Filtering = Фильтрация текстур @@ -803,11 +806,13 @@ Brightness = Яркость Cartoon = Мультипликация CatmullRom = Бикубический (Catmull-Rom) Апскейлер ColorCorrection = Цветокоррекция +ColorPreservation = Color preservation Contrast = Контрастность CRT = ЭЛТ-развертка FXAA = Сглаживание FXAA Gamma = Gamma Grayscale = Оттенки серого +GreenLevel = GreenLevel Intensity = Интенсивность InverseColors = Инвертированные цвета MitchellNetravali = Бикубический (Mitchell-Netravali) Апскейлер @@ -816,9 +821,11 @@ NaturalA = Естественные цвета (без размытия) Off = Выключена Power = Сила PSPColor = Цвета PSP +RedBlue = Red/Blue glasses Saturation = Насыщенность Scanlines = Строки развертки (ЭЛТ) Sharpen = Резкость +SideBySide = Side by side (SBS) SSAA(Gauss) = SSAA (Гаусс) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1036,7 +1043,7 @@ CPU Name = Название D3DCompiler Version = Версия D3DCompiler Debug = Отладочная Debugger Present = Отладчик присутствует -Depth buffer format = Формат буфера глубины +#Depth buffer format = Формат буфера глубины Device Info = Устройство Directories = Директории Display Color Formats = Display Color Formats @@ -1089,6 +1096,7 @@ Cache ISO in RAM = Кэшировать ISO в ОЗУ Change CPU Clock = Эмулируемая частота ЦП PSP (нестабильно) Color Saturation = Насыщенность Color Tint = Оттенок цвета +Game crashed = Game crashed Language = Язык Memory Stick folder = Изменить папку с картой памяти Memory Stick size = Изменить размер карты памяти (Гб) diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index c7703e446d..8b0532f46e 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -547,6 +547,7 @@ Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet Speed Hacks = Speed-hacks (kan orsaka renderingsproblem) +Stereo display shader = Stereo display shader Stereo rendering = Stereo-rendering Stretch = Stretch Texture Filter = Texturfilter @@ -804,11 +805,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Gamma = Gamma Grayscale = Gråskala +GreenLevel = GreenLevel Intensity = Intensity InverseColors = InverseColors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -821,6 +824,7 @@ RedBlue = Röd/Blå glasögon Saturation = Saturation Scanlines = Scanlines Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1093,6 +1097,7 @@ Color Tint = Färgförskjutning Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Memory Stick folder = Memory Stick-mapp Memory Stick size = Memory Stick-storlek Change Nickname = Ändra nickname diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 08ca41605b..d649050859 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -493,6 +493,7 @@ Frame Rate Control = Pag kontrol ng frame rate Frame Skipping = Frame Skipping Frame Skipping Type = Frame skipping type FullScreen = Isakto sa Sukat ng iyong Iskrin +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack Settings (maaring magdulot ng pagloloko sa laro) Hardware Tessellation = Hardware tessellation @@ -546,6 +547,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Bilis Speed Hacks = Speed Hacks (maaring magdulot ng pagloloko sa laro) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Iunat Texture Filter = Panala ng Texture Texture Filtering = Pagsala sa Texture @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma Grayscale = Grayscale +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Inverse Colors MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Lumulutang na simbolo +Game crashed = Game crashed Language = Wika Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 902af6b866..415cbd1e91 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -495,6 +495,7 @@ Frame Rate Control = Kare hızı denetimi Frame Skipping = Kare atla Frame Skipping Type = Kare atlama türü FullScreen = Tam ekran +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack ayarları (Küçük teknik problemlere neden olabilir.) Hardware Tessellation = Donanım Mozaikleme @@ -548,6 +549,8 @@ Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hız Speed Hacks = Hız Hacks (Küçük teknik problemlere neden olabilir.) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Serbest tam ekran (sünme) Texture Filter = Doku filtreleme Texture Filtering = Doku filtreleme @@ -832,11 +835,13 @@ Brightness = Parlaklık Cartoon = Çizgi film CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Karşıtlık CRT = CRT tarama çizgileri FXAA = FXAA Kenar Yumuşatma Gamma = Gamma Grayscale = Gri tonlama +GreenLevel = GreenLevel Intensity = Yoğunluk InverseColors = Ters Renkler MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -845,9 +850,11 @@ NaturalA = Doğal Renkler (bulanıklık yok) Off = Kapalı Power = Güç PSPColor = PSP rengi +RedBlue = Red/Blue glasses Saturation = Doygunluk Scanlines = Tarama Çizgileri (CRT) Sharpen = Keskinleştir +SideBySide = Side by side (SBS) SSAA(Gauss) = Süper örneklemeli Kenar Yumuşatma (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1091,6 +1098,7 @@ Color Tint = Renk Tonu Error: load undo state is from a different game = Hata: yükleme geri alma durumu farklı bir oyundan Failed to load state for load undo. Error in the file system. = Yüklemeyi geri alma durumu yüklenemedi. Dosya sisteminde hata. Floating symbols = Kayan simgeler +Game crashed = Game crashed Language = Dil Memory Stick folder = Hafıza Kartı klasörü Memory Stick size = Hafıza Kartı boyutu diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 3d9fd33c98..1b6e6ec377 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -493,6 +493,7 @@ Frame Rate Control = Управління частотою кадрів Frame Skipping = Пропуск кадрів Frame Skipping Type = Тип пропуску кадрів FullScreen = Повноекранний режим +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Параметри хаків (можуть викликати глюки) Hardware Tessellation = Апаратна тесселляція @@ -546,6 +547,8 @@ Software Skinning = Програмна заливка SoftwareSkinning Tip = Комбінована модель розібраної моделі яка притягується до процесора, швидше в більшості ігор Speed = Швидкість Speed Hacks = Speed Hacks (можуть викликати глюки) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Розтягнення Texture Filter = Фільтр текстур Texture Filtering = Фільтрація текстур @@ -831,11 +834,13 @@ Brightness = Яскравість Cartoon = Мультиплікація CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Корекція кольорів +ColorPreservation = Color preservation Contrast = Контраст CRT = Кінескоп 1 FXAA = FXAA згладжування Gamma = Гамма Grayscale = Відтінки сірого +GreenLevel = GreenLevel Intensity = Інтенсивність InverseColors = Зворотні кольори MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Натуральні кольори (без розмиття) Off = Вимкнені Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Насиченість Scanlines = Кінескоп 2 Sharpen = Різкість +SideBySide = Side by side (SBS) SSAA(Gauss) = SSAA (Гаусс) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Мова Memory Stick folder = Змінити папку для карти пам'яті Memory Stick size = Memory Stick size diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index bc09ec4eb2..f459105a2f 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -493,6 +493,7 @@ Frame Rate Control = Điều khiển tốc độ khung hình Frame Skipping = Nhảy khuôn hình Frame Skipping Type = Frame skipping type FullScreen = Toàn màn hình +Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Thiết lập hack (sẽ bị lỗi) Hardware Tessellation = Lót phần cứng @@ -546,6 +547,8 @@ Software Skinning = phủ lớp bằng phần mềm SoftwareSkinning Tip = Mô hình kết hợp vẽ trên CPU, nhanh hơn trong hầu hết các trò chơi Speed = Tốc độ Speed Hacks = Tốc độ Hacks (sẽ bị lỗi) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Bộ lọc họa tiết Texture Filtering = Lọc texture @@ -831,11 +834,13 @@ Brightness = Brightness Cartoon = Hoạt họa CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT đường quét FXAA = Chống răng cưa FXAA Gamma = Gamma Grayscale = Đen trắng +GreenLevel = GreenLevel Intensity = Intensity InverseColors = Màu âm bản MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler @@ -844,9 +849,11 @@ NaturalA = Màu tự nhiên (không mờ) Off = Tắt Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Đường nét (CRT) Sharpen = Sắc nét +SideBySide = Side by side (SBS) SSAA(Gauss) = Siêu mẫu AA (cốt) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1090,6 +1097,7 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed Language = Ngôn ngữ Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 8d201ecd19..2628aa563f 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -493,6 +493,7 @@ Frame Rate Control = 帧率控制 Frame Skipping = 跳帧 Frame Skipping Type = 跳帧方式 FullScreen = 全屏幕 +Geometry shader culling = Geometry shader culling GPUReadbackRequired = 警告: 此游戏需要"跳过GPU回读"设置为关闭 Hack Settings = 渲染修正(可能引发故障) Hardware Tessellation = 硬件曲面细分 @@ -546,6 +547,8 @@ Software Skinning = 软件蒙皮 SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快 Speed = 运行速度 Speed Hacks = 提速修正 (引起不稳定性) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = 拉伸 Texture Filter = 纹理过滤方法 Texture Filtering = 纹理过滤 @@ -831,11 +834,13 @@ Bloom = 泛光 Brightness = 亮度 Cartoon = 卡通 ColorCorrection = 颜色修正 +ColorPreservation = Color preservation Contrast = 对比度 CRT = CRT 扫描线 FXAA = FXAA (快速近似抗锯齿) Gamma = 伽马值 Grayscale = 灰度图 +GreenLevel = GreenLevel Intensity = 强度 InverseColors = 反色 Natural = 自然色 @@ -843,9 +848,11 @@ NaturalA = 自然色(无模糊) Off = 关闭 Power = 效果强度 PSPColor = PSP色彩 +RedBlue = Red/Blue glasses Saturation = 色彩 Scanlines = 扫描线(CRT) Sharpen = 锐化 +SideBySide = Side by side (SBS) SSAA(Gauss) = 超级采样抗锯齿(高斯) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1084,6 +1091,7 @@ Color Saturation = 颜色饱和度 Error: load undo state is from a different game = 错误:撤回的即时存档是来自不同游戏的 Failed to load state for load undo. Error in the file system. = 无法撤回加载即时存档。文件系统有错误。 Floating symbols = 飘浮的按键 +Game crashed = Game crashed Language = 语言设置 Memory Stick folder = 记忆棒文件夹 Memory Stick size = 记忆棒大小(GB) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index ce51988185..b2ea88f4ba 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -493,6 +493,7 @@ Frame Rate Control = 影格速率控制 Frame Skipping = 影格跳過 Frame Skipping Type = 影格跳過類型 FullScreen = 全螢幕 +Geometry shader culling = Geometry shader culling GPUReadbackRequired = 警告:此遊戲需要關閉「跳過 GPU 讀回」 Hack Settings = 駭客設定 (可能會造成故障) Hardware Tessellation = 硬體鑲嵌 @@ -546,6 +547,8 @@ Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 Speed Hacks = 速度駭客 (可能會造成轉譯錯誤!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering Stretch = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 @@ -800,11 +803,13 @@ Bloom = 光圈 Brightness = 亮度 Cartoon = 卡通 ColorCorrection = 色彩修正 +ColorPreservation = Color preservation Contrast = 對比度 CRT = CRT 掃描線 FXAA = FXAA 消除鋸齒 Gamma = 色差補正 Grayscale = 灰階 +GreenLevel = GreenLevel Intensity = 濃度 InverseColors = 反轉色彩 Natural = 自然色彩 @@ -812,9 +817,11 @@ NaturalA = 自然色彩 (無模糊) Off = 關閉 Power = 強度 PSPColor = PSP 色彩 +RedBlue = Red/Blue glasses Saturation = 飽和度 Scanlines = 掃描線 (CRT) Sharpen = 銳利化 +SideBySide = Side by side (SBS) SSAA(Gauss) = 超級取樣 AA (高斯) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1078,6 +1085,7 @@ AVI Dump started. = AVI 傾印已啟動 AVI Dump stopped. = AVI 傾印已停止 Cache ISO in RAM = 將完整 ISO 快取於 RAM Change CPU Clock = 變更模擬 PSP CPU 時脈 (不穩定) +Game crashed = Game crashed Language = 語言 Memory Stick folder = 記憶棒資料夾 Memory Stick size = 記憶棒大小 From 390bf3e9129ae03fd7624e191628459a72c814e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 12:37:41 +0100 Subject: [PATCH 459/715] Fix Burnout Dominator lens flare on OpenGL ES Not the prettiest solution, but works: Use R8_UNORM as a fallback if R16_UNORM is not available. --- Common/GPU/OpenGL/thin3d_gl.cpp | 7 +++++++ GPU/Common/FramebufferManagerCommon.cpp | 28 +++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index ab3c92fa3e..0c9afd6869 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1516,6 +1516,13 @@ uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const { case DataFormat::R8_UNORM: return FMT_TEXTURE; + case DataFormat::R16_UNORM: + if (!gl_extensions.IsGLES) { + return FMT_TEXTURE; + } else { + return 0; + } + break; case DataFormat::BC1_RGBA_UNORM_BLOCK: case DataFormat::BC2_UNORM_BLOCK: diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 32a5156ffd..7a18fc127c 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1217,6 +1217,20 @@ void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer } Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) { + Draw::DataFormat depthFormat = Draw::DataFormat::UNDEFINED; + if (srcPixelFormat == GE_FORMAT_DEPTH16) { + if ((draw_->GetDataFormatSupport(Draw::DataFormat::R16_UNORM) & Draw::FMT_TEXTURE) != 0) { + depthFormat = Draw::DataFormat::R16_UNORM; + } else if ((draw_->GetDataFormatSupport(Draw::DataFormat::R8_UNORM) & Draw::FMT_TEXTURE) != 0) { + // This could be improved by using specific draw shaders to pack full precision in two channels. + // However, not really worth the trouble until we find a game that requires it. + depthFormat = Draw::DataFormat::R8_UNORM; + } else { + // No usable single channel format. Can't be bothered. + return nullptr; + } + } + // TODO: We can just change the texture format and flip some bits around instead of this. // Could share code with the texture cache perhaps. auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) { @@ -1225,6 +1239,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y; u32 *dst = (u32 *)(data + byteStride * y); u16 *dst16 = (u16 *)(data + byteStride * y); + u8 *dst8 = (u8 *)(data + byteStride * y); switch (srcPixelFormat) { case GE_FORMAT_565: if (preferredPixelsFormat_ == Draw::DataFormat::B8G8R8A8_UNORM) @@ -1263,7 +1278,16 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G // to do one of two different swizzle operations. However, for the only use of this so far, // the Burnout lens flare trickery, swizzle doesn't matter since it's just a 0, 7fff, 0, 7fff pattern // which comes out the same. - memcpy(dst16, src16, w * 2); + if (depthFormat == Draw::DataFormat::R16_UNORM) { + // We just use this format straight. + memcpy(dst16, src16, w * 2); + } else if (depthFormat == Draw::DataFormat::R8_UNORM) { + // We fall back to R8_UNORM. Precision is enough for most cases of depth clearing and initialization we've seen, + // but hardly ideal. + for (int i = 0; i < width; i++) { + dst8[i] = src16[i] >> 8; + } + } break; case GE_FORMAT_INVALID: @@ -1279,7 +1303,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G // and likely more efficient. Draw::TextureDesc desc{ Draw::TextureType::LINEAR2D, - srcPixelFormat == GE_FORMAT_DEPTH16 ? Draw::DataFormat::R16_UNORM : preferredPixelsFormat_, + srcPixelFormat == GE_FORMAT_DEPTH16 ? depthFormat : preferredPixelsFormat_, width, height, 1, From 3f0e53e60afe4417f183f0ff8108b621a317c83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 16:29:43 +0100 Subject: [PATCH 460/715] Let the running game show through the background of all the PromptScreen dialogs. --- UI/EmuScreen.cpp | 2 +- UI/GameScreen.cpp | 6 +++--- UI/GameSettingsScreen.cpp | 11 ++++++----- UI/MiscScreens.cpp | 4 ++-- UI/MiscScreens.h | 4 ++-- UI/PauseScreen.cpp | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 34375650b8..e3e8a6dcfa 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1058,7 +1058,7 @@ void EmuScreen::update() { errLoadingFile.append(" "); errLoadingFile.append(err->T(errorMessage_.c_str())); - screenManager()->push(new PromptScreen(errLoadingFile, "OK", "")); + screenManager()->push(new PromptScreen(gamePath_, errLoadingFile, "OK", "")); errorMessage_.clear(); quit_ = true; return; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 4486bbd9a3..33773e5adb 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -243,7 +243,7 @@ UI::EventReturn GameScreen::OnDeleteConfig(UI::EventParams &e) auto di = GetI18NCategory("Dialog"); auto ga = GetI18NCategory("Game"); screenManager()->push( - new PromptScreen(di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GameScreen::CallbackDeleteConfig, this, std::placeholders::_1))); return UI::EVENT_DONE; @@ -374,7 +374,7 @@ UI::EventReturn GameScreen::OnDeleteSaveData(UI::EventParams &e) { // Check that there's any savedata to delete if (saveDirs.size()) { screenManager()->push( - new PromptScreen(di->T("DeleteConfirmAll", "Do you really want to delete all\nyour save data for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmAll", "Do you really want to delete all\nyour save data for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GameScreen::CallbackDeleteSaveData, this, std::placeholders::_1))); } } @@ -398,7 +398,7 @@ UI::EventReturn GameScreen::OnDeleteGame(UI::EventParams &e) { std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); if (info) { screenManager()->push( - new PromptScreen(di->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GameScreen::CallbackDeleteGame, this, std::placeholders::_1))); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 7ba8120ce9..c85513f0e4 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1445,7 +1445,7 @@ UI::EventReturn GameSettingsScreen::OnRenderingBackend(UI::EventParams &e) { // It only makes sense to show the restart prompt if the backend was actually changed. if (g_Config.iGPUBackend != (int)GetGPUBackend()) { - screenManager()->push(new PromptScreen(di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), + screenManager()->push(new PromptScreen(gamePath_, di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackRenderingBackend, this, std::placeholders::_1))); } return UI::EVENT_DONE; @@ -1457,7 +1457,7 @@ UI::EventReturn GameSettingsScreen::OnRenderingDevice(UI::EventParams &e) { // It only makes sense to show the restart prompt if the device was actually changed. std::string *deviceNameSetting = GPUDeviceNameSetting(); if (deviceNameSetting && *deviceNameSetting != GetGPUBackendDevice()) { - screenManager()->push(new PromptScreen(di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), + screenManager()->push(new PromptScreen(gamePath_, di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackRenderingDevice, this, std::placeholders::_1))); } return UI::EVENT_DONE; @@ -1466,7 +1466,7 @@ UI::EventReturn GameSettingsScreen::OnRenderingDevice(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnInflightFramesChoice(UI::EventParams &e) { auto di = GetI18NCategory("Dialog"); if (g_Config.iInflightFrames != prevInflightFrames_) { - screenManager()->push(new PromptScreen(di->T("ChangingInflightFrames", "Changing graphics command buffering requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), + screenManager()->push(new PromptScreen(gamePath_, di->T("ChangingInflightFrames", "Changing graphics command buffering requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackInflightFrames, this, std::placeholders::_1))); } return UI::EVENT_DONE; @@ -1580,6 +1580,7 @@ UI::EventReturn GameSettingsScreen::OnChangeMacAddress(UI::EventParams &e) { std::string combined = std::string(confirmMessage) + "\n\n" + warningMessage; auto confirmScreen = new PromptScreen( + gamePath_, combined, di->T("Yes"), di->T("No"), [&](bool success) { if (success) { @@ -1844,13 +1845,13 @@ UI::EventReturn GameSettingsScreen::OnRestoreDefaultSettings(UI::EventParams &e) if (g_Config.bGameSpecific) { screenManager()->push( - new PromptScreen(dev->T("RestoreGameDefaultSettings", "Are you sure you want to restore the game-specific settings back to the ppsspp defaults?\n"), di->T("OK"), di->T("Cancel"), + new PromptScreen(gamePath_, dev->T("RestoreGameDefaultSettings", "Are you sure you want to restore the game-specific settings back to the ppsspp defaults?\n"), di->T("OK"), di->T("Cancel"), std::bind(&GameSettingsScreen::CallbackRestoreDefaults, this, std::placeholders::_1))); } else { screenManager()->push( - new PromptScreen(dev->T("RestoreDefaultSettings", "Are you sure you want to restore all settings(except control mapping)\nback to their defaults?\nYou can't undo this.\nPlease restart PPSSPP after restoring settings."), di->T("OK"), di->T("Cancel"), + new PromptScreen(gamePath_, dev->T("RestoreDefaultSettings", "Are you sure you want to restore all settings(except control mapping)\nback to their defaults?\nYou can't undo this.\nPlease restart PPSSPP after restoring settings."), di->T("OK"), di->T("Cancel"), std::bind(&GameSettingsScreen::CallbackRestoreDefaults, this, std::placeholders::_1))); } diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index d5d7ec5f85..85b04a4717 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -507,8 +507,8 @@ void UIDialogScreenWithBackground::sendMessage(const char *message, const char * HandleCommonMessages(message, value, screenManager(), this); } -PromptScreen::PromptScreen(std::string message, std::string yesButtonText, std::string noButtonText, std::function callback) - : message_(message), callback_(callback) { +PromptScreen::PromptScreen(const Path &gamePath, std::string message, std::string yesButtonText, std::string noButtonText, std::function callback) + : UIDialogScreenWithGameBackground(gamePath), message_(message), callback_(callback) { auto di = GetI18NCategory("Dialog"); yesButtonText_ = di->T(yesButtonText.c_str()); noButtonText_ = di->T(noButtonText.c_str()); diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 2790f85c37..341e3b7915 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -76,9 +76,9 @@ protected: bool darkenGameBackground_ = true; }; -class PromptScreen : public UIDialogScreenWithBackground { +class PromptScreen : public UIDialogScreenWithGameBackground { public: - PromptScreen(std::string message, std::string yesButtonText, std::string noButtonText, + PromptScreen(const Path& gamePath, std::string message, std::string yesButtonText, std::string noButtonText, std::function callback = &NoOpVoidBool); void CreateViews() override; diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 2ff43b61ab..85d60a480f 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -460,7 +460,7 @@ UI::EventReturn GamePauseScreen::OnDeleteConfig(UI::EventParams &e) auto di = GetI18NCategory("Dialog"); auto ga = GetI18NCategory("Game"); screenManager()->push( - new PromptScreen(di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GamePauseScreen::CallbackDeleteConfig, this, std::placeholders::_1))); return UI::EVENT_DONE; From 812c7d13aa880f47aa568f8bd59e38cf648f15a9 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 29 Nov 2022 21:25:13 +0100 Subject: [PATCH 461/715] OpenXR - HUD disappearing in Flatout fixed --- GPU/GLES/ShaderManagerGLES.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index d36a68fe7a..7c7463fc7a 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -364,6 +364,8 @@ static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { else if (!gstate.isAlphaBlendEnabled()) hud = false; //HUD cannot be rendered with clear color mask else if (gstate.isClearModeColorMask()) hud = false; + //HUD cannot be rendered with depth color mask + else if (gstate.isClearModeDepthMask()) hud = false; //HUD cannot be rendered with fog on else if (gstate.isFogEnabled()) hud = false; //HUD cannot be rendered with lights on @@ -374,8 +376,6 @@ static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { else if (gstate_c.textureFullAlpha) hud = false; //HUD cannot render FB screenshot else if (gstate_c.curTextureHeight == 272) hud = false; - //HUD cannot render far plane - else if ((fabs(gstate.viewMatrix[9]) > 100) || (fabs(gstate.viewMatrix[11]) > 100)) hud = false; return hud; } From 0682b7ba5441ece466161b9bfb3dc9a549418d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 22:05:56 +0100 Subject: [PATCH 462/715] Fix saving of the new Stretch setting --- Core/Config.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/Config.cpp b/Core/Config.cpp index 9870745c28..40e3478d3f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -915,6 +915,8 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("DisplayOffsetY", &g_Config.fDisplayOffsetY, 0.5f, true, true), ConfigSetting("DisplayScale", &g_Config.fDisplayScale, 1.0f, true, true), ConfigSetting("DisplayAspectRatio", &g_Config.fDisplayAspectRatio, 1.0f, true, true), + ConfigSetting("DisplayStretch", &g_Config.bDisplayStretch, false, true, true), + ConfigSetting("ImmersiveMode", &g_Config.bImmersiveMode, true, true, true), ConfigSetting("SustainedPerformanceMode", &g_Config.bSustainedPerformanceMode, false, true, true), ConfigSetting("IgnoreScreenInsets", &g_Config.bIgnoreScreenInsets, true, true, false), From de78007e66ad2c9c5b59d8f6ab8e3e0e1e93da60 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 29 Nov 2022 22:17:12 +0100 Subject: [PATCH 463/715] OpenXR - Enable HUD in a few more games --- GPU/GLES/ShaderManagerGLES.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 7c7463fc7a..0f730a3101 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -368,8 +368,6 @@ static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { else if (gstate.isClearModeDepthMask()) hud = false; //HUD cannot be rendered with fog on else if (gstate.isFogEnabled()) hud = false; - //HUD cannot be rendered with lights on - else if (gstate.isLightingEnabled()) hud = false; //HUD texture has to contain alpha channel else if (!gstate.isTextureAlphaUsed()) hud = false; //HUD cannot have full alpha From d72ad3b3f4517352dfb3c991f6818ccae4dc9819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Nov 2022 15:29:31 +0100 Subject: [PATCH 464/715] Fragment shader generator: Move the framebuffer fetch bit to the shader ID. Will resolve a future issue in the multisampling PR, where the GPU_USE_FRAMEBUFFER_FETCH flag changes at runtime if you switch between no AA and MSAA. Just figured I'd get it in separately for safety. --- GPU/Common/FragmentShaderGenerator.cpp | 9 +++++++-- GPU/Common/ShaderId.cpp | 9 +++++++++ GPU/Common/ShaderId.h | 1 + GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index dee1dfb431..eba7b966da 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -169,8 +169,13 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool needFramebufferRead = replaceBlend == REPLACE_BLEND_READ_FRAMEBUFFER || colorWriteMask || replaceLogicOp; - bool fetchFramebuffer = needFramebufferRead && gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH); - bool readFramebufferTex = needFramebufferRead && !gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH); + bool fetchFramebuffer = needFramebufferRead && id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); + bool readFramebufferTex = needFramebufferRead && !id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); + + if (fetchFramebuffer && (compat.shaderLanguage != GLSL_VULKAN || compat.shaderLanguage != GLSL_3xx)) { + *errorString = "framebuffer fetch requires GLSL: vulkan or 3xx"; + return false; + } bool needFragCoord = readFramebufferTex || gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); bool writeDepth = gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 705ce77cb9..e572f721de 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -259,6 +259,7 @@ std::string FragmentShaderDesc(const FShaderID &id) { if ((id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc << "ReplaceLogic "; if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc << "TexArray "; if (id.Bit(FS_BIT_STEREO)) desc << "Stereo "; + if (id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc << "(fetch)"; return desc.str(); } @@ -384,6 +385,14 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, stencilWithoutDepth); } } + + // In case the USE flag changes (for example, in multisampling we might disable input attachments), + // we don't want to accidentally use the wrong cached shader here. So moved it to a bit. + if (FragmentIdNeedsFramebufferRead(id)) { + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) { + id.SetBit(FS_BIT_USE_FRAMEBUFFER_FETCH); + } + } } *id_out = id; diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 06b252d87d..6c3a886669 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -100,6 +100,7 @@ enum FShaderBit : uint8_t { FS_BIT_SHADER_DEPAL_MODE = 55, // 2 bits (ShaderDepalMode) FS_BIT_SAMPLE_ARRAY_TEXTURE = 57, // For multiview, framebuffers are array textures and we need to sample the two layers correctly. FS_BIT_STEREO = 58, + FS_BIT_USE_FRAMEBUFFER_FETCH = 59, }; static inline FShaderBit operator +(FShaderBit bit, int i) { diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 076d317442..e895e21af6 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -484,7 +484,7 @@ VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 30 +#define CACHE_VERSION 31 struct VulkanCacheHeader { uint32_t magic; uint32_t version; From 874dba6731b0b445a5b41a8d1dac11554abb2d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Wed, 30 Nov 2022 16:37:02 +0800 Subject: [PATCH 465/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index a01e903294..82f3c571a0 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -493,7 +493,7 @@ Frame Rate Control = 影格速率控制 Frame Skipping = 影格跳過 Frame Skipping Type = 影格跳過類型 FullScreen = 全螢幕 -Geometry shader culling = Geometry shader culling +Geometry shader culling = 幾何著色器揀選 GPUReadbackRequired = 警告:此遊戲需要關閉「跳過 GPU 讀回」 Hack Settings = 駭客設定 (可能會造成故障) Hardware Tessellation = 硬體鑲嵌 @@ -547,8 +547,8 @@ Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 Speed Hacks = 速度駭客 (可能會造成轉譯錯誤!) -Stereo display shader = Stereo display shader -Stereo rendering = Stereo rendering +Stereo display shader = 立體聲顯示著色器 +Stereo rendering = 立體聲轉譯 Stretch = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 @@ -803,13 +803,13 @@ Bloom = 光圈 Brightness = 亮度 Cartoon = 卡通 ColorCorrection = 色彩修正 -ColorPreservation = Color preservation +ColorPreservation = 色彩保留 Contrast = 對比度 CRT = CRT 掃描線 FXAA = FXAA 消除鋸齒 Gamma = 色差補正 Grayscale = 灰階 -GreenLevel = GreenLevel +GreenLevel = 綠色色階 Intensity = 濃度 InverseColors = 反轉色彩 Natural = 自然色彩 @@ -817,11 +817,11 @@ NaturalA = 自然色彩 (無模糊) Off = 關閉 Power = 強度 PSPColor = PSP 色彩 -RedBlue = Red/Blue glasses +RedBlue = 紅藍眼鏡 Saturation = 飽和度 Scanlines = 掃描線 (CRT) Sharpen = 銳利化 -SideBySide = Side by side (SBS) +SideBySide = 並排 (SBS) SSAA(Gauss) = 超級取樣 AA (高斯) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1085,7 +1085,7 @@ AVI Dump started. = AVI 傾印已啟動 AVI Dump stopped. = AVI 傾印已停止 Cache ISO in RAM = 將完整 ISO 快取於 RAM Change CPU Clock = 變更模擬 PSP CPU 時脈 (不穩定) -Game crashed = Game crashed +Game crashed = 遊戲已當機 Language = 語言 Memory Stick folder = 記憶棒資料夾 Memory Stick size = 記憶棒大小 From 6b695ee5cdc7eef93a61f654e5ca457d0f09b93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=BA=E5=B7=A5=E7=9F=A5=E8=83=BD?= <42119227+Kaitul@users.noreply.github.com> Date: Wed, 30 Nov 2022 16:40:21 +0800 Subject: [PATCH 466/715] Update zh_TW.ini --- assets/lang/zh_TW.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 82f3c571a0..2c5bda9581 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -547,8 +547,8 @@ Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 Speed Hacks = 速度駭客 (可能會造成轉譯錯誤!) -Stereo display shader = 立體聲顯示著色器 -Stereo rendering = 立體聲轉譯 +Stereo display shader = 立體顯示著色器 +Stereo rendering = 立體轉譯 Stretch = 延伸 Texture Filter = 紋理濾鏡 Texture Filtering = 紋理濾鏡 From 0ff5e0a955e0f2583a579f07b6d257058c79e873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Nov 2022 09:40:38 +0100 Subject: [PATCH 467/715] Add checks preventing a number of "possible" divisions by 0 in layout --- Common/UI/ViewGroup.cpp | 34 ++++++++++++++++++++++----------- UI/TouchControlLayoutScreen.cpp | 2 +- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index e69f6865c8..b137697d94 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -31,13 +31,13 @@ void ApplyGravity(const Bounds outer, const Margins &margins, float w, float h, switch (gravity & G_HORIZMASK) { case G_LEFT: inner.x = outer.x + margins.left; break; case G_RIGHT: inner.x = outer.x + outer.w - w - margins.right; break; - case G_HCENTER: inner.x = outer.x + (outer.w - w) / 2; break; + case G_HCENTER: inner.x = outer.x + (outer.w - w) * 0.5f; break; } switch (gravity & G_VERTMASK) { case G_TOP: inner.y = outer.y + margins.top; break; case G_BOTTOM: inner.y = outer.y + outer.h - h - margins.bottom; break; - case G_VCENTER: inner.y = outer.y + (outer.h - h) / 2; break; + case G_VCENTER: inner.y = outer.y + (outer.h - h) * 0.5f; break; } } @@ -267,11 +267,12 @@ static float HorizontalOverlap(const Bounds &a, const Bounds &b) { // okay they do overlap. Let's clip. float maxMin = std::max(a.x, b.x); float minMax = std::min(a.x2(), b.x2()); + float minW = std::min(a.w, b.w); float overlap = minMax - maxMin; - if (overlap < 0.0f) + if (overlap < 0.0f || minW <= 0.0f) return 0.0f; else - return std::min(1.0f, overlap / std::min(a.w, b.w)); + return std::min(1.0f, overlap / minW); } // Returns the percentage the smaller one overlaps the bigger one. @@ -281,11 +282,12 @@ static float VerticalOverlap(const Bounds &a, const Bounds &b) { // okay they do overlap. Let's clip. float maxMin = std::max(a.y, b.y); float minMax = std::min(a.y2(), b.y2()); + float minH = std::min(a.h, b.h); float overlap = minMax - maxMin; - if (overlap < 0.0f) + if (overlap < 0.0f || minH <= 0.0f) return 0.0f; else - return std::min(1.0f, overlap / std::min(a.h, b.h)); + return std::min(1.0f, overlap / minH); } float GetTargetScore(const Point &originPos, int originIndex, View *origin, View *destination, FocusDirection direction) { @@ -303,6 +305,9 @@ float GetTargetScore(const Point &originPos, int originIndex, View *origin, View float dy = destPos.y - originPos.y; float distance = sqrtf(dx*dx + dy*dy); + if (distance == 0.0f) { + distance = 0.001f; + } float overlap = 0.0f; float dirX = dx / distance; float dirY = dy / distance; @@ -594,6 +599,10 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f) v = MeasureSpec(AT_MOST, measuredHeight_); float unit = (allowedWidth - weightZeroSum) / weightSum; + if (weightSum == 0.0f) { + // We must have gotten an inf. + unit = 1.0f; + } MeasureSpec h(AT_MOST, unit * linLayoutParams->weight - margins.horiz()); if (horiz.type == EXACTLY) { h.type = EXACTLY; @@ -635,6 +644,9 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f) h = MeasureSpec(AT_MOST, measuredWidth_); float unit = (allowedHeight - weightZeroSum) / weightSum; + if (weightSum == 0.0f) { + unit = 1.0f; + } MeasureSpec v(AT_MOST, unit * linLayoutParams->weight - margins.vert()); if (vert.type == EXACTLY) { v.type = EXACTLY; @@ -735,8 +747,8 @@ void FrameLayout::Layout() { bounds.w = w; bounds.h = h; - bounds.x = bounds_.x + (measuredWidth_ - w) / 2; - bounds.y = bounds_.y + (measuredWidth_ - h) / 2; + bounds.x = bounds_.x + (measuredWidth_ - w) * 0.5f; + bounds.y = bounds_.y + (measuredWidth_ - h) * 0.5f; views_[i]->SetBounds(bounds); } } @@ -912,7 +924,7 @@ void ScrollView::Draw(UIContext &dc) { float childHeight = views_[0]->GetBounds().h; float scrollMax = std::max(0.0f, childHeight - bounds_.h); - float ratio = bounds_.h / views_[0]->GetBounds().h; + float ratio = bounds_.h / std::max(0.01f, views_[0]->GetBounds().h); float bobWidth = 5; if (ratio < 1.0f && scrollMax > 0.0f) { @@ -1054,7 +1066,7 @@ void ScrollView::ScrollRelative(float distance) { } float ScrollView::ClampedScrollPos(float pos) { - if (!views_.size()) { + if (!views_.size() || bounds_.h == 0.0f) { return 0.0f; } @@ -1063,7 +1075,7 @@ float ScrollView::ClampedScrollPos(float pos) { Gesture gesture = orientation_ == ORIENT_VERTICAL ? GESTURE_DRAG_VERTICAL : GESTURE_DRAG_HORIZONTAL; - if (scrollTouchId_ >= 0 && gesture_.IsGestureActive(gesture, scrollTouchId_) && bounds_.h > 0) { + if (scrollTouchId_ >= 0 && gesture_.IsGestureActive(gesture, scrollTouchId_) && bounds_.h > 0.0f) { float maxPull = bounds_.h * 0.1f; if (pos < 0.0f) { float dist = std::min(-pos * (1.0f / bounds_.h), 1.0f); diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 12012332a1..53931db685 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -618,7 +618,7 @@ void TouchControlLayoutScreen::CreateViews() { InitPadLayout(bounds.w, bounds.h); const float leftColumnWidth = 170.0f; - layoutAreaScale = 1.0-(leftColumnWidth+10)/bounds.w; + layoutAreaScale = 1.0f - (leftColumnWidth + 10.0f) / std::max(bounds.w, 1.0f); auto co = GetI18NCategory("Controls"); auto di = GetI18NCategory("Dialog"); From 20a337f25bd227c865950668622ffd145eb6b315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Nov 2022 10:05:54 +0100 Subject: [PATCH 468/715] Initialization cleanup (no effect) --- Common/UI/ViewGroup.cpp | 4 ++-- Common/UI/ViewGroup.h | 25 +++++++++---------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index b137697d94..cb9666e951 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1287,7 +1287,7 @@ void AnchorLayout::Layout() { } GridLayout::GridLayout(GridLayoutSettings settings, LayoutParams *layoutParams) - : ViewGroup(layoutParams), settings_(settings), numColumns_(1) { + : ViewGroup(layoutParams), settings_(settings) { if (settings.orientation != ORIENT_HORIZONTAL) ERROR_LOG(SYSTEM, "GridLayout: Vertical layouts not yet supported"); } @@ -1468,7 +1468,7 @@ void TabHolder::PersistData(PersistStatus status, std::string anonId, PersistMap } ChoiceStrip::ChoiceStrip(Orientation orientation, LayoutParams *layoutParams) - : LinearLayout(orientation, layoutParams), selected_(0), topTabs_(false) { + : LinearLayout(orientation, layoutParams) { SetSpacing(0.0f); } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index c5ee4032dd..b789935592 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -113,9 +113,7 @@ const float NONE = -FLT_MAX; class AnchorLayoutParams : public LayoutParams { public: AnchorLayoutParams(Size w, Size h, float l, float t, float r, float b, bool c = false) - : LayoutParams(w, h, LP_ANCHOR), left(l), top(t), right(r), bottom(b), center(c) { - - } + : LayoutParams(w, h, LP_ANCHOR), left(l), top(t), right(r), bottom(b), center(c) {} // There's a small hack here to make this behave more intuitively - AnchorLayout ordinarily ignores FILL_PARENT. AnchorLayoutParams(Size w, Size h, bool c = false) : LayoutParams(w, h, LP_ANCHOR), left(0), top(0), right(w == FILL_PARENT ? 0 : NONE), bottom(h == FILL_PARENT ? 0 : NONE), center(c) { @@ -135,7 +133,7 @@ public: class AnchorLayout : public ViewGroup { public: - AnchorLayout(LayoutParams *layoutParams = 0) : ViewGroup(layoutParams), overflow_(true) {} + AnchorLayout(LayoutParams *layoutParams = 0) : ViewGroup(layoutParams) {} void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; void Overflow(bool allow) { @@ -145,7 +143,7 @@ public: private: void MeasureViews(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert); - bool overflow_; + bool overflow_ = true; }; class LinearLayoutParams : public LayoutParams { @@ -157,7 +155,7 @@ public: LinearLayoutParams(float wgt, const Margins &mgn) : LayoutParams(LP_LINEAR), weight(wgt), gravity(G_TOPLEFT), margins(mgn), hasMargins_(true) {} LinearLayoutParams(Size w, Size h, float wgt = 0.0f, Gravity grav = G_TOPLEFT) - : LayoutParams(w, h, LP_LINEAR), weight(wgt), gravity(grav), hasMargins_(false) {} + : LayoutParams(w, h, LP_LINEAR), weight(wgt), gravity(grav), margins(0), hasMargins_(false) {} LinearLayoutParams(Size w, Size h, float wgt, Gravity grav, const Margins &mgn) : LayoutParams(w, h, LP_LINEAR), weight(wgt), gravity(grav), margins(mgn), hasMargins_(true) {} LinearLayoutParams(Size w, Size h, const Margins &mgn) @@ -184,7 +182,7 @@ private: class LinearLayout : public ViewGroup { public: LinearLayout(Orientation orientation, LayoutParams *layoutParams = 0) - : ViewGroup(layoutParams), orientation_(orientation), defaultMargins_(0), spacing_(10) {} + : ViewGroup(layoutParams), orientation_(orientation), defaultMargins_(0) {} void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; @@ -197,7 +195,7 @@ protected: Orientation orientation_; private: Margins defaultMargins_; - float spacing_; + float spacing_ = 10.0f; }; class LinearLayoutList : public LinearLayout { @@ -249,7 +247,7 @@ public: private: GridLayoutSettings settings_; - int numColumns_; + int numColumns_ = 1; }; class GridLayoutList : public GridLayout { @@ -317,11 +315,6 @@ private: static float lastScrollPosY; }; -class ViewPager : public ScrollView { -public: -}; - - class ChoiceStrip : public LinearLayout { public: ChoiceStrip(Orientation orientation, LayoutParams *layoutParams = 0); @@ -348,8 +341,8 @@ private: StickyChoice *Choice(int index); EventReturn OnChoiceClick(EventParams &e); - int selected_; - bool topTabs_; // Can be controlled with L/R. + int selected_ = 0; // Can be controlled with L/R. + bool topTabs_ = false; }; From 25e8f8385e99af7220b4b738b73f5914a74facc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Nov 2022 10:56:29 +0100 Subject: [PATCH 469/715] Redo the control UI screen layout, slightly update the look --- Common/UI/ViewGroup.cpp | 7 +++++-- Common/UI/ViewGroup.h | 6 ++++++ UI/TouchControlLayoutScreen.cpp | 31 ++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index cb9666e951..9b7dac87bd 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1071,7 +1071,8 @@ float ScrollView::ClampedScrollPos(float pos) { } float childSize = orientation_ == ORIENT_VERTICAL ? views_[0]->GetBounds().h : views_[0]->GetBounds().w; - float scrollMax = std::max(0.0f, childSize - (orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w)); + float containerSize = (orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w); + float scrollMax = std::max(0.0f, childSize - containerSize); Gesture gesture = orientation_ == ORIENT_VERTICAL ? GESTURE_DRAG_VERTICAL : GESTURE_DRAG_HORIZONTAL; @@ -1094,7 +1095,9 @@ float ScrollView::ClampedScrollPos(float pos) { if (pos > scrollMax && pos > scrollMax + pull_) { pos = scrollMax + pull_; } - + if (childSize < containerSize && alignOpposite_) { + pos = -(containerSize - childSize); + } return pos; } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index b789935592..5a10704a23 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -293,6 +293,11 @@ public: void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) override; void SetVisibility(Visibility visibility) override; + // If the view is smaller than the scroll view, sets whether to align to the bottom/right instead of the left. + void SetAlignOpposite(bool alignOpposite) { + alignOpposite_ = alignOpposite; + } + NeighborResult FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) override; private: @@ -310,6 +315,7 @@ private: float pull_ = 0.0f; float lastViewSize_ = 0.0f; float *rememberPos_ = nullptr; + bool alignOpposite_ = false; static float lastScrollPosX; static float lastScrollPosY; diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 53931db685..729ee5ed1f 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -361,6 +361,7 @@ public: bool Touch(const TouchInput &input) override; void CreateViews(); + void Draw(UIContext& ui) override; bool HasCreatedViews() const { return !controls_.empty(); } @@ -455,6 +456,12 @@ bool ControlLayoutView::Touch(const TouchInput &touch) { return true; } +void ControlLayoutView::Draw(UIContext& dc) { + using namespace UI; + dc.FillRect(Drawable(0x80000000), bounds_); + UI::AnchorLayout::Draw(dc); +} + void ControlLayoutView::CreateViews() { using namespace CustomKey; const Bounds &bounds = GetBounds(); @@ -617,16 +624,19 @@ void TouchControlLayoutScreen::CreateViews() { const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); InitPadLayout(bounds.w, bounds.h); - const float leftColumnWidth = 170.0f; + const float leftColumnWidth = 200.0f; layoutAreaScale = 1.0f - (leftColumnWidth + 10.0f) / std::max(bounds.w, 1.0f); auto co = GetI18NCategory("Controls"); auto di = GetI18NCategory("Dialog"); - root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + auto rootLayout = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, FILL_PARENT)); + rootLayout->SetSpacing(0.0f); + root_ = rootLayout; - ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 84))); - LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); + ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(leftColumnWidth, FILL_PARENT))); + leftColumnScroll->SetAlignOpposite(true); + LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(Margins(12.0f, 0.0f)))); mode_ = new ChoiceStrip(ORIENT_VERTICAL); mode_->AddChoice(di->T("Move")); @@ -635,7 +645,7 @@ void TouchControlLayoutScreen::CreateViews() { mode_->OnChoice.Handle(this, &TouchControlLayoutScreen::OnMode); CheckBox *snap = new CheckBox(&g_Config.bTouchSnapToGrid, di->T("Snap")); - PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 2, 256, di->T("Grid"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158)); + PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 2, 256, di->T("Grid"), screenManager(), ""); gridSize->SetEnabledPtr(&g_Config.bTouchSnapToGrid); leftColumn->Add(mode_); @@ -643,9 +653,12 @@ void TouchControlLayoutScreen::CreateViews() { leftColumn->Add(snap); leftColumn->Add(gridSize); leftColumn->Add(new Choice(di->T("Reset")))->OnClick.Handle(this, &TouchControlLayoutScreen::OnReset); - AddStandardBack(root_); + leftColumn->Add(new Spacer(12.0f)); + leftColumn->Add(new Choice(di->T("Back"), "", false))->OnClick.Handle(this, &UIScreen::OnBack); + leftColumn->Add(new Spacer(0.0f)); - root_->Add(new BorderView(BORDER_BOTTOM, BorderStyle::ITEM_DOWN_BG, 4.0f, new AnchorLayoutParams(leftColumnWidth + 10, bounds.h * (1.0f - layoutAreaScale), 0.0f, NONE, false))); - root_->Add(new BorderView(BORDER_RIGHT, BorderStyle::ITEM_DOWN_BG, 4.0f, new AnchorLayoutParams(leftColumnWidth + 10, 0.0f, NONE, 0.0f, false))); - layoutView_ = root_->Add(new ControlLayoutView(new AnchorLayoutParams(leftColumnWidth + 10, bounds.h * (1.0 - layoutAreaScale), 0.0f, 0.0f, false))); + LinearLayout* rightColumn = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f, Margins(0.0f, 12.0f, 12.0f, 12.0f)))); + rightColumn->Add(new Spacer(new LinearLayoutParams(1.0))); + float previewHeight = bounds.h * layoutAreaScale; + layoutView_ = rightColumn->Add(new ControlLayoutView(new LinearLayoutParams(FILL_PARENT, previewHeight))); } From b51451d6720e2cabfba2709dc3c58941e987a3bb Mon Sep 17 00:00:00 2001 From: nassau-tk Date: Wed, 30 Nov 2022 22:11:44 +0900 Subject: [PATCH 470/715] Fix-jpn0.pgf --- assets/flash0/font/jpn0.pgf | Bin 4316452 -> 4316452 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/flash0/font/jpn0.pgf b/assets/flash0/font/jpn0.pgf index e0fba7621957c6f44ce85bf42af2a73baa594a87..e3acf4c62ac21c427e24315ff6db581a66663fa8 100644 GIT binary patch delta 223698 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.jxr>(!8VTM2-wb-JO;x= zl4J-*Dj`993dt-;R4sArhhX%QXOPzJJvo(OmgJ;{ZIaokw(*i9snJQ2H>r?ml778F zg%V~jOtHk#D?D3rvX^bXB;E^DA{pM>u%9S0rotHC&g3`hjjse)jX-m7vlgQOV?V`vXa3I_QbyX?ozf zq<4Q?y+q!>p;5BDzx|!$N`KoY32=bonN>@`8~kZR*Dn`m#$d)2i4YKu;t{xOklU^Uh=r8Rs7&cf+8QcJq&K}GdCOtB^ zX{7Ys;4oa835B4gI;cHMx)$mqNUuU&6lsSH7gfs1P%x#7GC*AEg$#&L`a44*k)mJ_ zg>(YUrj}O1AbROjSlB2{&vaR&icH&B=^967bb|D1CS!{9Z)RY+lrY3@m(CqxpDhgx z!OWL_8-gj3VuxZ}tv&I%Qa3gY@t)$X4lxVV)gQ*l>tf zY98LSTe@YqeZMq1yy=j%%ZTVPsbEB)M!I}N(<$lA5uS6>4kKZgq_mMuVd>nFHpeyT z@sXZe(x#D^yHdocrigUXsOSUf{!tB2q#s9xUr0xeZiq=IkM_Kg?ip?SAZ=__s!CyF z6bY$q4D5$==NQNz>60?+Dmkpa*!s*H+;F=Y$U z4IJ4Sv`--WjrFJE5z6}vXdBBo~#+;G0BKnpG`IsYa1^+j&)6zeaB*^%iviI zyR10NHCuKv%Qs)voMkJKp>R!3*<@VP64?^5 zAKob=5bQpgoxs>DJ3+7=lzk`IkIFDaOh7h;2s$Y{L=2yieIoiU$cB-kA=xBS^s4L# z33N*qCt>c&&}4g5HiHa%D61jcp3356*Gn0mVr!5UQ7~_1M<|ewvab}#SJ{~CXu=_z zknQ;)tIBr$ku_#x+Qh?~HblOb3K}85Lv0u>?@EK9d>glEzx*XPdRU&$gH+26JkSYwB@cE+{)(q?T##q-?IHPie)OvR2p@7w{*B*o zM~)IGqH?>y_fURH;CU+lCy2h3(}ea$xl@RFC%-IoeUf()MZd|#BFJ~SM`ZimTHr7( z@*ZLkKp_w}B`M0qu4Khyv9Ft=k0hF+Fi2p%6_pZ3KgAnKc%T9<#lRHPrI=v~$5AO` z)c;R2LP3y4F^X0h4qkCq2BRq2$rV%uOCDe~W=irez2P?4+%OBEtTRH<04z~~hB z6bz%Hk1}9U=#}BIiml4%M8#8ObgCj<)ljI=tD-X%J5-Q)iWe%zLd6iZ QAZd#%U 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